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():
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:
do_wp_page(current, vma, address, error_code);
If, on the other hand, the fault was a page-not-present fault, invoke
do_no_page(current, vma, address, error_code);
error_code should be non-zero if the fault occured in user mode, and zero, if in kernel mode.
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:
intr_count++;
kstat.interrupts[irq]++;
add_interrupt_randomness(irq);
When all handlers have been executed, do the following:
intr_count--;
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:
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--;
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.