Skip to content

Intra Kernel Initialization and Dependencies

Claudio Fontana edited this page Jun 23, 2014 · 3 revisions

List of Kernel Core Dependencies

this should eventually be more structured, but lets start from somewhere.

Early Console Output

early console output can be obtained with debug_early, debug_early_entry, debug_early_u64. These APIs provide non-buffered, straight to the device output, and are and should remain callable very early (as in directly from the pre-C assembly in boot.S and similar).

These APIs rely on the arch_early_console class instance, which is provided by each architecture in arch/$(arch)/early-console.hh arch/$(arch)/early-console.cc

Those classes need to provide a "write" method, which should do nothing else than writing the input on the console, and should require no prior dependencies on other classes construction.

Later Console Output

Console output initialization occurs in 3 stages currently.

First we have the arch_early_console mentioned above and the debug_early APIs, which are used for things that really need to go out on the console early and immediately.

Then we have the initialization priority "console", whose constructor is run inside premain, and that priority initializes the console-multiplexer.

Then we have the main_cont call of arch_setup_console, which sorts out the kernel console options to choose which console/s to initialize and use, and immediately afterwards we have console_init(), which creates the character tty console device and starts the console multiplexer, which starts polling the console for input as well via the dedicated thread.

APIs providing console output at this later stages include debug_ll, debug_write, and of course libc functions writing to stdout, and these can buffer the output as well.

Lockless mutexes

mutexes require threads to be available (locking uses sched::thread::current()) Attempts to lock before s_current is set by the cpu[0] when initializing the first thread (thread::thread()) will cause random behavior if called before TLS initialization (as s_current is a __thread variable), and will instead potentially loop forever on AArch64 (x64 probably not?) if called after setup_tls but before threads are available.

Backtrace functionality

Backtraces use mutexes in ELF (so needs threads (s_current)) and also need s_program to be initialized. They are therefore available in main_cont just after new program::program().

Construction order

The constructors of static C++ objects in the kernel are not run before the kernel starts (as one might expect in a C++ program), but rather in the premain() function (loader.cc), where the code runs these static constructors one by one:

    for (auto init = inittab.start; init < inittab.start + inittab.count; ++init) {
        (*init)();
    }

The order in which these constructors are run is determined by the "init_priority" attribute of the object, or "constructor" attribute for an object-less function. These priorities should symbolic names from include/osv/prio.hh. For example, in that file, "cpus" comes before "sched". This means the "cpus" vector is constructed (as an empty vector, but still requires construction), before the smp_init(), which is a constructor function with priority "sched", is called to add more cpus to this list.

Clone this wiki locally