First a picture, then the same as text:
1) An user task X makes receive system_call:
…..............
RETVAL=receive_call(taskY);
…................
(2) We have a library stub in the shared library:
long receive_call (long task) {
register long r8 __asm__("r8");
__asm__ ("break 0x1;");
//INTERRUPT
return r8;
(3) We enter to break handler:
rsm psr.i | psr.ic
mov r30 = cr.iip
add r30 = 16,r30// Incrementing is needed, otherwise we return to break not
mov r17 = cr.iim //BREAK NR
….................
cmp.eq (p1),(p0) = 1,r17 // Allowed break system calls 1,2,.....9
cmp.eq (p2),(p0) = 2,r17 // Could be also array of addresses (big system)
cmp.eq (p3),(p0) = 3,r17
…...................................
mov r30 = r32// Service routines use register variables as parameters r30 and r31
mov r31= r33// Service routines use register variables as parameters r30 and r31
…..............
(p1) add r16 = @gprel(receive),gp
(p2)add r16 = @gprel(send),gp
(p3)add r16 = @gprel(shm_open),gp
(p5)add r16 = @gprel(sem_post),gp
…......
mov b0 = r16
br.sptk.few b0 //TO THE C-LANGUAGE SERVICE ROUTINE in directory kernel.
(4) We enter c-languge function receive:
void receive(void) { // Sychronous message massing receive handler (called from break interrupt)
struct TCB_type * ptr_current_;
struct TCB_type *ptr_from_ ;
register long _task_from __asm__("r30");
if((_task_from < 0) || ( _task_from >= MAXTASK)){
message = SEM_INDEX_ERROR_ACK;
_return_same_();// Return to the same context, wrong task index in sys call
}
ptr_current_ = TCB_ptr[current_task_nr];
ptr_from_ = TCB_ptr[_task_from];
if(ptr_from_->STATE == WAITING_RECEIVER ) {
// If the task we are receiving from is already waiting us
_ready_ = _ready_ | (1 << _task_from)| (1 << current_task_nr) ;
// Both are now ready to run
ptr_current_->message = ptr_from_->message ;
ptr_from_->message = RECEIVER_ACK;
ptr_from_->timeout = MAX_TIMEOUT;
…...............................
ptr_current_->timeout = MAX_TIMEOUT;
}
else {
ptr_current_->STATE = WAITING_SENDER;//If the task we are receiving from is not waiting….........................
_schedule()_ // WE go to find out next highest priority task
(5) We enter flash()
This "flash-scheduling" finds out highest priority process from the set of 63 processes with about 25 clock cycles.Looping bit by bit would take max 10 times more. We find out first right 32- bits then 16-bits then 8-bits-....If max number of the processes would be 127, addition to the seek time would be about 2-3 clocks.The scheduling policy is pre- emptive priority based. Implementing (an) additional round robin queue(s) is easywith the same bit mask technique, if need be.
(6) ) We enter schedule() to set up some variables for context switch assembly
…............................................................
if(found==current_task_nr) flag=1;
tr_ptr = tcb_ptr[found];//For context switch assembly!//Reg save area
….........................
_context_switch_();
(7) We enter to context switch assembly:
Here is register spilling/ filling as well as backing store TLB translation for the new task.Other translations done by TLB fault handler. RSE can' cause this fault(?)
PROC context_switch:
ENTRY spill()
{ if(exiting task/"task" was kernel idle loop)
call fill()
else {
save exiting task register state and RSE
call fill():
}
}
ENTRY fill()
{
if (task to enter is idle loop) {
enable ints,
while(TRUE)//Loop waiting int
}
else
{
build up TBL entries for the new task
restore task register state and RSE and return address
rfi (return from interruption (break or timer) to the new running task
}
}
ENTRY build_up_tlb_tr()
{Set shm protection key
return_same()
}
ENTRY return_same()// For the cases, context switch did not happen even sometimes possible
{
restore minimal state
rfi (return the same task we just were running)
}
….....................
SPILL code snippets
…..............
.macro set_TLB_tr PTR INDEX_REG INDEX RSE_ITIR RSE_IFA RSE_IDRT TRANSL
//Insert new translation for RSE - can' work by fault as the rest of the system (appications)!
add \PTR = @gprel(\TRANSL),gp// Pointer to pointer of itir ifa ... save area
ld8 \PTR = [\PTR]
ld8 \RSE_ITIR = [\PTR],8
ld8 \RSE_IFA = [\PTR],16 //Skip one long in tcb--->16
ld8 \RSE_IDRT = [\PTR],8
mov \INDEX_REG = \INDEX
mov cr.itir= \RSE_ITIR// Pkr key register takes care of protection, even translation exsists with a task not
cr.ifa = \RSE_IFA
itr.i itr[\INDEX_REG] = \RSE_IDRT
itr.d dtr[\INDEX_REG] = \RSE_IDRT
srlz.d
srlz.i
.endm
…......................
/*
ar.rsc <-- 0
d <--- difference (ar.bsp- ar.bspstrore), saved to tcb
*/
....................
cover // This MUST be before set_TLB_tr uses old TLB transalation as RSE backing store area!
flushrs
…...............
.irp REG, cr.ifs, ar.bspstore, cr.iip, cr.ipsr, ar.rnat, ar.k0, b1, ar.k1, sp, ar.k3, ar.k2,ar.k6
mov r26 = \REG
st8.spill [r27] = r26,8
.endr
…..........................
FILL code snippts
.irp REG,r16, r20, r30, r17, ar.bspstore, cr.iip, cr.ipsr, ar.rnat, b0, b1, gp, sp, ar.lc,pr,ar.ec
ld8.fill r27 = [r26],8
mov \REG = r27
.endr
/* rsc.mode <--- 0
rsc.loadrs <--- d (from tcb----old value of subtraction: bsp-bspstore, the number of loader regs)
loadrs
*/
::::::::::::::::::::..
rfi //ENTER THE NEXT TASK Y TO RUN
(8) we go back to the lib- this time objdumb
00000000000303c0 <receive_call>:
303c0: 01 08 00 00 00 00 [MII] break.m 0x1
303c6: 00 00 00 02 00 00 nop.i 0x0
303cc: 00 00 04 00 nop.i 0x0;;
303d0: 11 00 00 00 01 00 [MIB] nop.m 0x0<-----Here
303d6: 00 00 00 02 00 80 nop.i 0x0
303dc: 08 00 84 00 br.ret.sptk.many b0;;
(9) We return to the task Y sending and waiting receiver X
We suppose here, that sending task has higher priority, and it continues when receiver found.
ret_val=send_call(TaskX,TY_message);
…......................................................... <-----------------return
How the assembly looks like by objdump.
5035c: 78 01 fe 58 br.call.sptk.many b0=304c0 <send_call>;;
50360: 01 00 00 00 01 00 [MII] nop.m 0x0
50366: 80 00 20 2c 00 00 sxt4 r8=r8 <------return
5036c: 00 00 04 00 nop.i 0x0;;
50370: 09 00 00 00 01 00 [MMI] nop.m 0x0
50376: 00 40 9c 30 23 00 st8 [r39]=r8
// ret val in r8
5037c: 00 00 04 00 nop.i 0x0;;