The file locore.s contains all of the assembly-language code for the port. This includes the interrupt and exception handlers, the bootstrapping code, the task-switching code, and any routines that are small and used often enough that they should be written in assembly ( e.g., routines to copy blocks of memory). As little as possible should be written in assembly, since it is not portable or easily maintained. Several ports have broken parts of locore.s out into Locore.c.
The object file for locore is linked first in the kernel executable and usually includes the vector table for the interrupts. All of these vectors point to stubs in locore that clean up the stack and call the C routine to handle the interrupt or trap properly. Depending on the architecture, the assembly language code might also have to determine the cause of the interrupt. For example, a page fault produces different actions if it was caused by kernel code or user code, or if the accessed memory refers to a swapped-out page or an invalid location.
The code at the label start: is jumped to directly from either the booter or the stand-along kernel. It usually turns off interrupts, disables caches, sets up the MMU tables, enables the MMU, enables the interrupts, and jumps to main(), the C routine responsible for initializing the machine-independent code.
Most architectures can call a C routine to setup the MMU routines instead of doing it in assembly. On some architectures, however, this code must be in assembly because of the memory layout. For example, on HP 300 machines, RAM is mapped at the end of the physical address space. That is, the last addressable byte is at address . This means that when the kernel is loaded at the bottom of physical memory, the lowest address (and therefore the address of all variables and routines in the kernel) is dependent on the amount of memory installed in the machine. Since this is not known at link time, the kernel must use the MMU to map itself to virtual address 0. Setting up the MMU tables happens before the MMU is enabled, so all references to variables and routines must explicitly take into account the physical location at which the kernel was loaded. This is not easily done in C, so the code is written in assembly.
The assembly language part of the task-switching code saves and restores machine state (including that of the MMU and floating-point unit). The rest is done in C in the machine-independent code.