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

Upload page content

You can upload content for the page named below. If you change the page name, you can also upload content for another page. If the page name is empty, we derive the page name from the file name.

File to load page content from
Page name
Comment

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