4 Kernel Interface to Architecture Support

This chapter documents interfaces of the architecture-independent parts of the Linux kernel which are relevant to the architecture support.

4.1 Booting

asmlinkage void start_kernel(void);

The kernel's initialization/boot routine. The following steps should have been taken before calling start_kernel():

4.2 Kernel Entry/Exit

System call and fault handlers expect that current is a pointer to the invoker's struct task_struct (declared in <linux/sched.h>):

(Actually, current is #defined to be current_set[smp_processor_id()], but exception handlers don't care about that.)

4.2.1 System Calls

System calls expect a stack layout as defined by struct pt_regs (see section ptrace.h). This also makes sure that system calls find their parameters on the stack.

extern struct task_struct *current;

The architecture support must identify the appropriate system call handler to invoke. There is no architecture-independent system call dispatch facility.

When a system call returns, the architecture must perform housekeeping (see section Housekeeping).

4.2.2 Page Fault Handling

The page fault handler has available the following general kernel interfaces (declared in <linux/mm.h>):

static inline struct vm_area_struct * find_vma (struct task_struct * task,
        unsigned long addr);
static inline int expand_stack(struct vm_area_struct * vma, 
        unsigned long address);
extern void do_wp_page(struct task_struct * tsk, 
        struct vm_area_struct * vma, unsigned long address, 
        int write_access);
extern void do_no_page(struct task_struct * tsk, 
        struct vm_area_struct * vma, unsigned long address, 
        int write_access);

It should do approximately the following:

4.2.3 Other Faults

Other faults should be handled as appropriate, often by just sending signals to the process. All exceptions should invoke kernel housekeeping after having been handled (see section Kernel Housekeeping).

4.2.4 Interrupts

The kernel exports the following interfaces relevant to interrupt entry and exit:

extern unsigned long intr_count;    /* in <linux/sched.h> */

(In <linux/sched.h>.) The number of nested interrupts the kernel is processing: Must be incremented at every interrupt kernel entry, and decremented at exit. The scheduler (schedule()) must only be called if intr_count == 0. See section [here] for more information on how this flag is used.

extern struct kernel_stat kstat;

(In <linux/kernel_stat.h>.)

void add_interrupt_randomness(int irq);

(In <linux/random.h>.)

Before invoking the interrupt handlers, the architecture support should do the following:

When all handlers have been executed, do the following:

For information on registering interrupts see section sched.h. For information on interrupt handler implementation, see the Kernel Hacker's Guide.

4.3 Kernel Housekeeping

The architecture support must do some housekeeping. This is usually implemented in a routine called ret_from_system_call(). This housekeeping routine should be invoked every time a system call or a slow interrupt handler (see section [here]) returns.

It should do the following:

  1. Check if it is being called from a nested interrupt (intr_count != 0). If so, return immediately to the interrupted process.
  2. Check if any interrupt bottom halfs need to be executed ((bh_mask & bh_active) != 0). If so, handle bottom halfs (see section [here]). Then restart this step.
  3. Was the code segment we're returning to supervisor (i.e., system call from supervisor mode, or interrupted system call)? If so, return at this point.
  4. Check if the need_resched flag has been set. If so, call schedule() (see section [here]), then restart the whole housekeeping routine.
  5. Check if the process we're going to return to has any signals pending. If so, handle the signals now (see section [here]).

4.3.1 Bottom Half Handling

The bottom halfs are handled by this kernel routine (declared in <linux/interrupt.h>):

extern unsigned long bh_active;
extern unsigned long bh_mask;

asmlinkage void do_bottom_half(void);

As long as (bh_mask & bh_active) != 0, the housekeeping routine should execute code along the following lines:

intr_count++;
save_flags(flags);
sti();
do_bottom_half();
restore_flags(flags);
intr_count--;

4.3.2 Scheduling

The kernel exports its scheduling routine to the architecture support (declared in <linux/sched.h>):

extern /* volatile */ int need_resched;

asmlinkage void schedule(void);

The housekeeping routine should call the schedule() routine whenever the need_resched flag is true (this flag is set by the timer interrupt routine). schedule() will select some process which should be executed next, calls switch_to() (see section system.h) to switch to it, and returns.

The schedule() routine can also be called from system calls in order to block the current process. It must only be called if the intr_count flag (see section [here]) is zero, i.e., it can not be used from interrupt handlers (neither top nor bottom half).

4.3.3 Signal Handling

If (current->signal & ~(current->blocked)) != 0, the housekeeping routine must handle signals before returning to the task. The logic of doing this is actually quite complex and is best copied from the do_signal() routine in arch/i386/kernel/signal.c.

The architecture-dependant part is posting signals not handled kernel-internally, that is, actually invoking signal handlers in the process by pushing signal frames on the process' stack.


Michael Hohmuth
March 21, 1996