📄 199.htm
字号:
} <br>
Starting the kernel <br>
Listing 4 contains the first few interesting lines of the start_kernel() fun <br>
ction, located in $(TOPDIR)/init/main.c. <br>
Listing 4: The beginning of the start_kernel function <br>
asmlinkage void __init start_kernel(void) <br>
{ <br>
{ <br>
char * command_line; <br>
/* <br>
* Interrupts are still disabled. Do necessary setups, then <br>
* enable them <br>
*/ <br>
lock_kernel(); <br>
printk(linux_banner); <br>
setup_arch(&command_line, &memory_start, &memory_end); <br>
memory_start = paging_init(memory_start, memory_end); <br>
trap_init(); <br>
init_IRQ(); <br>
sched_init(); <br>
time_init(); <br>
parse_options(command_line); <br>
. <br>
. <br>
. <br>
Listing 5 shows the setup_arch() function in $(TOPDIR)/arch/MY_ARCH/kernel/s <br>
etup.c. The board-specific setup function is called from here. The command l <br>
ine string and memory start and memory end are passed over to the caller of <br>
this function. The start and end addresses for the linked-in ramdisk image a <br>
re also updated here. <br>
Listing 5: Architecture setup function <br>
__initfunc(void setup_arch(char **cmdline_p, <br>
unsigned long * memory_start_p, <br>
unsigned long * memory_end_p)) <br>
{ <br>
#ifdef CONFIG_BLK_DEV_INITRD <br>
#if CONFIG_BLK_DEV_INITRD_OFILE <br>
extern void *__rd_start, *__rd_end; <br>
#endif <br>
#endif <br>
myplatform_setup(); <br>
strncpy(command_line, arcs_cmdline, CL_SIZE); <br>
*cmdline_p = command_line; <br>
*memory_start_p = (unsigned_long) &_end; <br>
*memory_end_p = mips_memory_upper; <br>
#ifdef CONFIG_BLK_DEV_INITRD <br>
#if CONFIG_BLK_DEV_INITRD_OFILE <br>
// Use the linked-in ramdisk <br>
// image located at __rd_start. <br>
initrd_start = (unsigned long)&__rd_start; <br>
initrd_end = (unsigned long)&__rd_end; <br>
initrd_below_start_ok = 1; <br>
if (initrd_end > memory_end) <br>
{ <br>
printk(*initrd extends beyond end of memory * <br>
*(0x%08lx > 0x%08lx)\ndisabling initrd\n*, <br>
initrd_end, memory_end); <br>
initrd_start = 0; <br>
} <br>
#endif <br>
#endif <br>
} <br>
$(TOPDIR)/arch/MY_ARCH/MY_PLATFORM/setup.c contains the platform-specific in <br>
itialization code (Listing 6). Here, the various base addresses and the plat <br>
form-specific RTC and PCI operations are set up. For PCI, the following seve <br>
n functions need to be implemented for the given platform: <br>
Listing 6: Platform-specific initialization code <br>
__initfunc(void myplatform_setup(void)) <br>
{ <br>
irq_setup = myplatform_irq_setup; <br>
/* <br>
* mips_io_port_base is the beginning <br>
*of the address space to which x86 <br>
* style I/O ports are mapped. <br>
*/ <br>
mips_io_port_base = 0xa0000000; <br>
/* <br>
* platform_io_mem_base is the <br>
*beginning of I/O bus memory space as <br>
* seen from the physical address bus. <br>
*This may or may not be ident- <br>
* ical to mips_io_port_base, e.g. the <br>
*former could point to the beginning of PCI <br>
*memory space while the latter might <br>
*indicate PCI I/O space. The two values are <br>
*used in different sets of macros. This <br>
* must be set to a correct value by the <br>
*platform setup code. <br>
*/ <br>
platform_io_mem_base=0x10000000; <br>
/* <br>
* platform_mem_iobus_base is the <br>
*beginning of main memory as seen <br>
* from the I/O bus, and must be set <br>
*by the platform setup code. <br>
*/ <br>
*/ <br>
platform_mem_iobus_base=0x0; <br>
#ifdef CONFIG_REMOTE_DEBUG <br>
/* <br>
* Do the minimum necessary to set up debugging <br>
*/ <br>
myplatform_kgdb_hook(0); <br>
remote_debug = 1; <br>
#endif <br>
#ifdef CONFIG_BLK_DEV_IDE <br>
ide_ops = &std_ide_ops; <br>
#endif <br>
#ifdef CONFIG_VT <br>
#if defined(CONFIG_DUMMY_CONSOLE) <br>
conswitchp = &dummy_con; <br>
#endif <br>
#endif <br>
/* <br>
* just set rtc_ops && pci_ops; forget the rest <br>
*/ <br>
rtc_ops = &myplatform_rtc_ops; <br>
pci_ops = &myplatform_pci_ops; <br>
} <br>
} <br>
myplatform_pcibios_fixup() <br>
myplatform_pcibios_read_config_byte() <br>
myplatform_pcibios_read_config_word() <br>
myplatform_pcibios_read_config_dword() <br>
myplatform_pcibios_write_config_byte() <br>
myplatform_pcibios_write_config_word() <br>
myplatform_pcibios_write_config_dword() <br>
Interrupt handling <br>
The trap_init() function copies the top-level exception handlers to the KSEG <br>
0 vector location based on the CPU type. The interrupt handling code is cont <br>
ained in $(TOPDIR)/arch/MY_ARCH/MY_PLATFORM/irq.c and int-handler.S. Most sy <br>
stems use a dedicated interrupt controller to handle the interrupts in the s <br>
ystem. The interrupt controller is hooked to one of the external interrupt l <br>
ines in the processor. The architecture-dependent code has to be modified to <br>
fit the interrupt controller into the kernel interrupt handling. <br>
Listing 7 shows the platform-specific interrupt initialization code. The top <br>
most interrupt handler has to be installed using set_except_vector(). The in <br>
terrupt controller that is used in the platform has to be initialized next. <br>
If remote debugging is enabled, a call to set_debug_traps() has to be made t <br>
o allow any breakpoints or error conditions to be properly intercepted and r <br>
eported to the debugger. In addition, a breakpoint needs to be generated to <br>
begin communication with the debugger running on the host. <br>
Listing 7: Platform-specific interrupt initialization <br>
static void __init myplatform_irq_setup (void) <br>
{ <br>
set_except_vector (0, myplatform_handle_int); <br>
// Initialize InterruptController <br>
InterruptController_Init(IsrTable); <br>
#ifdef CONFIG_REMOTE_DEBUG <br>
printk (*Setting debug traps - <br>
please connect the remote debugger.\n*); <br>
set_debug_traps (); <br>
breakpoint (); <br>
#endif <br>
} <br>
The top-level interrupt handler (Listing 8) first saves all the registers an <br>
d then disables further interrupts. The CAUSE register is examined to find t <br>
he source of the interrupt. If it is a timer interrupt, the corresponding IS <br>
R is called. In case it is not a timer interrupt, it checks whether an inter <br>
rupt has occurred on the line connected to the interrupt controller. The int <br>
errupt handler for the interrupt controller (Listing 9) has to get the pendi <br>
ng interrupt vector that caused the interrupt and then execute the handler f <br>
or the particular interrupt source. <br>
Listing 8: Top-level interrupt handler <br>
NESTED(myplatform_handle_int, PT_SIZE, ra) <br>
.set noat <br>
SAVE_ALL <br>
CLI <br>
.set at <br>
mfc0 s0, CP0_CAUSE # get irq mask <br>
/* First, we check for counter/timer IRQ. */ <br>
andi a0, s0, CAUSEF_IP5 <br>
beq a0, zero, 1f <br>
andi a0, s0, CAUSEF_IP2 <br>
# delay slot, check hw0 interrupt <br>
/* Wheee, a timer interrupt. */ <br>
move a0, sp <br>
jal timer_interrupt <br>
nop # delay slot <br>
j ret_from_irq <br>
nop # delay slot <br>
1: <br>
beq a0, zero, 1f <br>
nop <br>
/* Wheee, combined hardware <br>
level zero interrupt. */ <br>
jal InterruptController_InterruptHandler <br>
move a0, sp # delay slot <br>
j ret_from_irq <br>
nop # delay slot <br>
1: <br>
/* Here by mistake? This is possible, <br>
*what can happen is that by the time we <br>
*take the exception the IRQ pin goes low, so <br>
*just leave if this is the case. <br>
*/ <br>
j ret_from_irq <br>
nop <br>
END(myplatform_handle_int) <br>
Listing 9: Interrupt handler for the interrupt controller <br>
void <br>
InterruptController_InterruptHandler ( <br>
struct pt_regs *regs <br>
) <br>
{ <br>
IntVector intvector; <br>
struct irqaction *action; <br>
int irq, cpu = smp_processor_id(); <br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -