CS452 - Real-Time Programming - Winter 2018
Lecture 8a - Initialization of the Kernel
Public Service Annoucements
-
Due date for kernel 1: 26 January, 2018
Creating a Task
In creating a task you have to do two things
-
Allocate the resources needed by the task
-
Make the task look as if it had just entered the kernel
Initializing the task descriptor (TD)
When a task is not executing, either the kernel or another task
might be executing its TD holds some of the task's state; the
stack holds the rest.
Must also initialize the stack
Initializing the Kernel
Set up the Hardware
RedBoot gives you the processor with
-
caching turned off,
-
slow cpu and bus clock,
-
memory mapped into a single block starting at 0x0, (32 Mbytes
is 2^25 bytes.)
-
the interrupt control unit turned off,
-
interrupts disabled in the CPSR, and
-
MMU turned on to get the memory map above.
There is a subtlety here. There are actually three ways that you
can get into RedBoot and the state of the hardware is slightly
different.
-
You can cycle the power. In this case RedBoot initializes
some memory, and the remainder of the memory is garbage. The
I/O devices should be in their reset state, but it's safer
if you assume they are in a random state.
-
You can press the reset button. Then Redboot reinitializes
the memory it uses, including low memory, but the remainder
of the memory, including the code and data, but not I/O
devices, remains as it was when the reset button was pressed.
(The memory controllers are not turned off by the reset
button.)
-
You can unwind the kernel's stack to its top level, then
put RedBoot's link register into the program counter.
The memory of the processor, including low memory, is entact.
Then there are a few things you need to do. While
RedBoot gives you the system as described above, there may be
things done by a previous student that changed what RedBoot thinks
it is giving you.
-
Initialize busy-wait I/O. You will over-write this state when
the tasks that handle interrupt-driven I/O initialize themselves
in k4.
-
Initialize low memory.
-
How do you find the kernel entry?
-
To test whether or not you have done this correctly
-
Find the hex value of the first instruction executed on
kernel entry.
-
Read the number in 0x28 using Redboot.
-
Read what's in the word it points to, which should be the
same as the first instruction. (Hint. RedBoot and gcc don't
agree about endedness.)
-
Turn off interrupts in the ICU and in the CPSR.
-
This should be unnecessary, but what if the previous kernel turned
them on?
-
Later you will initialize the ICU differently.
-
As a debugging aid I sometimes put distinct bit patterns in the
registers in order to get some easy information about what is going
where.
Prepare the Kernel Data Structures
Where is the kernel's stack pointer, right now? What is on
the bottom of the stack?
-
Do you want it there? Would you rather have it somewhere else?
-
This is your last chance to change it. (If you decide to
change it you might want to keep what you are replacing around.
Why?)
The kernel data structures. At the very least you need
-
an array of empty ready queues
-
a pointer to the TD of the active task
-
an array of TDs
-
a free list of pointers to free TDs. This might take the form
of bits set in a couple of words.
-
a structure for keeping the request currently being serviced,
including its arguments.
Prepare the Memory to be Used by Tasks
Some of the state of a task on creation is task-independent. You
can, if you want to, initialize it in every TD and every block
of memory right now.
Create the First User Task
Run with hardware interrupts turned off for now. But
hardware interrupts in user tasks are turned on in kernel 3
though they stay off in the kernel.
What you do in creating the First User Task is exactly what you
do creating any other task. This task will have simpler code than
most other tasks you create, but getting it running correctly may
be hard.
Reminder. The place where the kernel starts executing has the
global name main, which cannot be re-used.
Other Primitives
These primitives exist mostly so that we, which includes you, can
ensure that task creation and scheduling are working when there
is not much else implemented.
Tid MyTid( )
Self-explanatory
-
Doesn't block, but does reschedule.
A question, to which there is a correct answer, or more specifically,
a correct (answer, reason) pair.
- Should the Tid be stored in user space?
Tid MyParentTid( )
Self-explanatory
- Doesn't block, but does reschedule.
Where is the parent Tid, and how does the kernel find it?
void Pass( )
Doesn't block: task calling Pass( )
makes a state
transition from ACTIVE
to READY
.
Does reschedule.
When is Pass( )
a NOP
?
void Exit( )
Calling task is removed from all queues, but its resources are
not reclaimed or reused.
That is, the task goes into a zombie state, and will never become
active or ready, but continues to own all its resources.
Return to: