Excuses and exercises

List of excuses:

  1. Kernel don't use RSE (stacked registers, because of an idea of "efficiency" and optimization,  potential problems). See exercises.

  2. Using a flag with do_fork (poor programming practice)

  3. The programming style is not always very good, too much harry in many places, definitions in the include files and variable definitions not carefully structured

  4. Ugly inline assembly (well, Itanium gcc don't support gnu style inline assembly)

  5. Spilling/filling is not complete (I found gcc uses only b0!), easy to fix-exercise

  6. The system is "tried" to work with some tests, far from the proper full testing (exercise)

  7. I left semaphore implementation not so nice, it works but...(exercise)

  8. The disc simulation is not very good even we build up physical data pages reading from image  (exercise)

About excuse 1:

First: We have two kind of system calls , about half can't cause context switch
(epc- gate implemented) and do not need heavy register
saving/restoring operation- for ex. "close shared memory".
Half of the calls can cause context switch sometimes- sometimes not.
For example a low priority task can send a message to a waiting higher
priority task or to a waiting lower priority task-cw in the first case only.

We have the cases:

(1) return from the idle_loop to the idle_loop            "Zero" load (no spill/fill RSE handling)
(2) return from the idle_loop to a real task                Half load
(3) return from a real task to the idle_loop                Half load
(4) return from a real task to the same real task      "Zero" load (see below why)
(5) return from a real task to another real task         Full load -register saving/
                                                                                    restoring and backing store switch

Short kernel routines do not use RSE and regs r2-r15 (fixed gcc flag), so saving/restoring
can be postponed to the time point when we return to a task and we can do the optimal state
saving/restoring.
(Of course kernel could use RSE- because backing store switch is implemented for task it would not be
problem to implement it for kernel short routines too)

This is the case with gcc- compiler and binutils. The same code can be invalid with different
tools without minor changes (gcc needs -O3 flag!).


Because of some odd reason gcc voluntary generates the code not using r16-r31 (and can be asked to use)
(if and when r1-r15 are available-not fixed for tasks).

This makes the context switch more efficient.(The kernel uses r1,r16- r31, an user task uses r1-r15 and RSE r32- r128.)
A trick to  get gcc to generate the code not using RSE was to make kernel service routines is

NOT to call subroutines inside system call service routines, parameters AND USE gcc flag -O3!


---- example:

*********************************
void send(void){// Sychronous message passing send handler (system call service routine)

 register long _task_to  __asm__("r30")//The parameter 1  - normally r32
 register long _message  __asm__("r31")//The parameter 2  - normally r33
 // The "normal" way to do it -void send(int _task_to_, long _message)
 register struct TCB_type *ptr_current__
 register struct TCB_type *ptr_to__
 ptr_current__= TCB_ptr[current_task_nr]
 
  if((_task_to < 1) || ( _task_to  > MAXTASK)){
              message  = SEM_INDEX_ERROR_ACK
              _return_same_()
          }

  ptr_current__= TCB_ptr[current_task_nr]
  ptr_to__     = TCB_ptr[_task_to]
   if(  ptr_to__->STATE       ==   WAITING_SENDER ) { ..................

*********************************

Spill and fill routines include backing store switch support (flushrs ,loadrs).
Only regs r1-r15 need to be spilled/filled as well as some system regs (CRs), also user regs r16- r31 could be
spilled/filled different (not optimized) way or kernel could use bank.0 onlt.

Implementation: Only one context_switch proc with entries spill and fill, but in the beginning of the
fill and spill the "idle_loop situation" is evaluated and handled

Exercises:

  1. Implement semaphore operations with better system calls (easy)

  2. Implement spill/fill of all registers as b1-b7 (easy)

  3. Reorganize tests so that you find system error. Sure possible. Fix it. (more difficult)

  4. Most important. Implement kernel backing storage use and get rid of many complicated things. Pretty hard work even it is at some extent straightforward, because the backing store switch is already implement for the context switch of tasks (hard). Of course, task/kernel backing store switch do not use flushrs/loadrs but changes ar.bspstore address, see manuals.

  5. Get rig of fork_flag, easy now when kernel uses RSE.

  6. Study epc-gate system call's backing store usage (kernel can use users's backing store because of security)

  7. Make better interface which looks exactly as reading from disc (call simulated disc read). (Very hard)

  8. Implement smp version (very hard)

  9. Implement version where part of tasks are round robin (not too hard)(DONE IN THE NEWEST VERSION)

  10. Test fork call at a general level, now it is tested only initialization and forked task is created always as lowest priority. Works fine with initialization but.....

  11. Port the system for Intel's more popular processors (very hard)


  Exercise 4 is good because if we don't want to use RSE, gcc do not know it AND CAN USE RSE, IF SOME C-code is very long and complicated. We can see this only looking with objdump if a new  module starts with "alloc".