|
Size: 712
Comment:
|
← Revision 3 as of 2017-12-30 01:30:31 ⇥
Size: 4089
Comment: converted to 1.6 markup
|
| Deletions are marked like this. | Additions are marked like this. |
| Line 6: | Line 6: |
| static void __init do_initcalls(void) |
static void __init do_initcalls(void) |
| Line 9: | Line 8: |
| initcall_t *call; | initcall_t *call; int count = preempt_count(); |
| Line 11: | Line 11: |
| call = &__initcall_start; do { (*call)(); call++; } while (call < &__initcall_end); |
for (call = __initcall_start; call < __initcall_end; call++) { char *msg = NULL; char msgbuf[40]; int result; |
| Line 17: | Line 16: |
| /* Make sure there is no pending stuff from the initcall sequence */ flush_scheduled_tasks(); |
if (initcall_debug) { printk("Calling initcall 0x%p", *call); print_fn_descriptor_symbol(": %s()", (unsigned long) *call); printk("\n"); } result = (*call)(); if (result && result != -ENODEV && initcall_debug) { sprintf(msgbuf, "error code %d", result); msg = msgbuf; } if (preempt_count() != count) { msg = "preemption imbalance"; preempt_count() = count; } if (irqs_disabled()) { msg = "disabled interrupts"; local_irq_enable(); } if (msg) { printk(KERN_WARNING "initcall at 0x%p", *call); print_fn_descriptor_symbol(": %s()", (unsigned long) *call); printk(": returned with %s\n", msg); } } /* Make sure there is no pending stuff from the initcall sequence */ flush_scheduled_work(); |
| Line 21: | Line 49: |
Searching hi and low for `__initcall_start` reveals that it doesn't appear in any *.c source files anywhere, it only appears in the linker scripts (*.lds) for the various architectures. {{{ [trevor@trevor linux-2.6.18]$ grep -r __initcall_start * arch/alpha/kernel/vmlinux.lds.S: __initcall_start = .; arch/arm/kernel/vmlinux.lds.S: __initcall_start = .; arch/arm26/kernel/vmlinux-arm26-xip.lds.in: __initcall_start = .; arch/arm26/kernel/vmlinux-arm26.lds.in: __initcall_start = .; arch/cris/arch-v10/vmlinux.lds.S: __initcall_start = .; arch/cris/arch-v32/vmlinux.lds.S: __initcall_start = .; arch/frv/kernel/vmlinux.lds.S: __initcall_start = .; arch/h8300/kernel/vmlinux.lds.S: ___initcall_start = .; arch/i386/kernel/vmlinux.lds.S: __initcall_start = .; arch/ia64/kernel/vmlinux.lds.S: __initcall_start = .; arch/m32r/kernel/vmlinux.lds.S: __initcall_start = .; arch/m68k/kernel/vmlinux-std.lds: __initcall_start = .; arch/m68k/kernel/vmlinux-sun3.lds: __initcall_start = .; arch/m68knommu/kernel/vmlinux.lds.S: __initcall_start = .; arch/mips/kernel/vmlinux.lds.S: __initcall_start = .; arch/parisc/kernel/vmlinux.lds.S: __initcall_start = .; arch/powerpc/kernel/vmlinux.lds.S: __initcall_start = .; arch/ppc/kernel/vmlinux.lds.S: __initcall_start = .; arch/s390/kernel/vmlinux.lds.S: __initcall_start = .; arch/sh/kernel/vmlinux.lds.S: __initcall_start = .; arch/sh64/kernel/vmlinux.lds.S: __initcall_start = .; arch/sparc/kernel/vmlinux.lds.S: __initcall_start = .; arch/sparc64/kernel/vmlinux.lds.S: __initcall_start = .; arch/v850/kernel/vmlinux.lds.S: ___initcall_start = . ; \ arch/x86_64/kernel/vmlinux.lds.S: __initcall_start = .; arch/xtensa/kernel/vmlinux.lds.S: __initcall_start = .; include/asm-um/common.lds.S: __initcall_start = .; init/main.c:extern initcall_t __initcall_start[], __initcall_end[]; init/main.c: for (call = __initcall_start; call < __initcall_end; call++) { }}} |
What motivated me to explore this item? I was looking through the source code of the Linux kernel, trying to get my head around the exact steps and workings of how the kernel boots. Partway through the code I came across some code I just couldn't figure out, it just didn't make sense to me how the code was working.
In init/main.c:do_basic_setup() is a call to do_initcalls() which is defined as:
static void __init do_initcalls(void)
{
initcall_t *call;
int count = preempt_count();
for (call = __initcall_start; call < __initcall_end; call++) {
char *msg = NULL;
char msgbuf[40];
int result;
if (initcall_debug) {
printk("Calling initcall 0x%p", *call);
print_fn_descriptor_symbol(": %s()",
(unsigned long) *call);
printk("\n");
}
result = (*call)();
if (result && result != -ENODEV && initcall_debug) {
sprintf(msgbuf, "error code %d", result);
msg = msgbuf;
}
if (preempt_count() != count) {
msg = "preemption imbalance";
preempt_count() = count;
}
if (irqs_disabled()) {
msg = "disabled interrupts";
local_irq_enable();
}
if (msg) {
printk(KERN_WARNING "initcall at 0x%p", *call);
print_fn_descriptor_symbol(": %s()",
(unsigned long) *call);
printk(": returned with %s\n", msg);
}
}
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}Searching hi and low for __initcall_start reveals that it doesn't appear in any *.c source files anywhere, it only appears in the linker scripts (*.lds) for the various architectures.
[trevor@trevor linux-2.6.18]$ grep -r __initcall_start *
arch/alpha/kernel/vmlinux.lds.S: __initcall_start = .;
arch/arm/kernel/vmlinux.lds.S: __initcall_start = .;
arch/arm26/kernel/vmlinux-arm26-xip.lds.in: __initcall_start = .;
arch/arm26/kernel/vmlinux-arm26.lds.in: __initcall_start = .;
arch/cris/arch-v10/vmlinux.lds.S: __initcall_start = .;
arch/cris/arch-v32/vmlinux.lds.S: __initcall_start = .;
arch/frv/kernel/vmlinux.lds.S: __initcall_start = .;
arch/h8300/kernel/vmlinux.lds.S: ___initcall_start = .;
arch/i386/kernel/vmlinux.lds.S: __initcall_start = .;
arch/ia64/kernel/vmlinux.lds.S: __initcall_start = .;
arch/m32r/kernel/vmlinux.lds.S: __initcall_start = .;
arch/m68k/kernel/vmlinux-std.lds: __initcall_start = .;
arch/m68k/kernel/vmlinux-sun3.lds: __initcall_start = .;
arch/m68knommu/kernel/vmlinux.lds.S: __initcall_start = .;
arch/mips/kernel/vmlinux.lds.S: __initcall_start = .;
arch/parisc/kernel/vmlinux.lds.S: __initcall_start = .;
arch/powerpc/kernel/vmlinux.lds.S: __initcall_start = .;
arch/ppc/kernel/vmlinux.lds.S: __initcall_start = .;
arch/s390/kernel/vmlinux.lds.S: __initcall_start = .;
arch/sh/kernel/vmlinux.lds.S: __initcall_start = .;
arch/sh64/kernel/vmlinux.lds.S: __initcall_start = .;
arch/sparc/kernel/vmlinux.lds.S: __initcall_start = .;
arch/sparc64/kernel/vmlinux.lds.S: __initcall_start = .;
arch/v850/kernel/vmlinux.lds.S: ___initcall_start = . ; \
arch/x86_64/kernel/vmlinux.lds.S: __initcall_start = .;
arch/xtensa/kernel/vmlinux.lds.S: __initcall_start = .;
include/asm-um/common.lds.S: __initcall_start = .;
init/main.c:extern initcall_t __initcall_start[], __initcall_end[];
init/main.c: for (call = __initcall_start; call < __initcall_end; call++) {