KernelNewbies
  • Comments
  • Immutable Page
  • Menu
    • Navigation
    • RecentChanges
    • FindPage
    • Local Site Map
    • Help
    • HelpContents
    • HelpOnMoinWikiSyntax
    • Display
    • Attachments
    • Info
    • Raw Text
    • Print View
    • Edit
    • Load
    • Save
  • Login

Kernel Hacking

  • Frontpage

  • Kernel Hacking

  • Kernel Documentation

  • Kernel Glossary

  • FAQ

  • Found a bug?

  • Kernel Changelog

  • Upstream Merge Guide

Projects

  • KernelJanitors

  • KernelMentors

  • KernelProjects

Community

  • Why a community?

  • Regional Kernelnewbies

  • Personal Pages

  • Upcoming Events

References

  • Mailing Lists

  • Related Sites

  • Programming Links

Wiki

  • Recent Changes

  • Site Editors

  • Side Bar

  • Tips for Editors

  • Hosted by WikiWall

Navigation

  • RecentChanges
  • FindPage
  • HelpContents
Revision 2 as of 2006-10-11 15:47:10
KernelNewbies:
  • InitcallMechanism
  • Motivation

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++) {
  • MoinMoin Powered
  • Python Powered
  • GPL licensed
  • Valid HTML 4.01