Solaris main():
1. High level boot sequence
===========================
-> lgrp_setup() // Setup the first lgroup, and home t0
-> startup() // Machine-dependent startup code
// In a 32-bit OS, boot loads the kernel text at 0xfe800000 and kernel data
// at 0xfec00000. On a 64-bit OS, kernel text and data are loaded at
// 0xffffffff.fe800000 and 0xffffffff.fec00000 respectively. Those
// addresses are fixed in the binary at link time.
--> progressbar_init() // Initialize a rectangle area for progress bar
--> startup_init()
--> startup_xen_version()
--> startup_memlist() // Build the memlists and other kernel essential memory system data structures
--> startup_kmem() // Layout the kernel's part of address space and initialize kmem allocator
--> startup_vm() // Finish initializing the VM system, now that we are no longer relying on the boot time memory allocators.
--> startup_pci_bios() // Retrieve information from the bios needed for system configuration early during startup.
--> startup_modules() // setup_ddi() is called at this point to create a kernel device tree.
// First, create rootnex and then invoke bus specific code to probe devices.
--> startup_bios_disk() // ???
--> startup_end() // configure() is called at this point to set up devices.
// setx86isalist() is called to set the isa_list string to the defined instruction sets we support.
// psm_install() is called to call the prober() of each psm module
// (*picinitf)() is called to enabling interrupt. picinitf is set to mach_picinit() in ./i86pc/os/mp_machdep.c. Reading here, I am thinking about the IOMMU code. The best place to initialization and enable Intel IOMMU is here. We shouldn't put this range of code between the first and second pass of pci_enumerate(), since the pci device tree could be changes during the second pass (phantom, subtractive ppb and so on).
--> progressbar_start() // process bar related, ignore it.
-> segkmem_gc() // kernel memory segment driver related
-> callb_init() // Init all callb tables in the system
-> callout_init() // Initialize all callout tables. Called at boot time just before clkstart().
-> timer_init() // timer_init() allocates the internal data structures used by i_timeout(), i_untimeout() and the timer. Timer must be initialized before cyclic starts
-> cbe_init() // initialize cyclic back end
-> clock_tick_init_pre() // Clock tick initialization
-> clock_init() // initialize clock system
-> init_mstate()
-> init_cpu_mstate() //On some platforms, clkinitf() changes the timing source that gethrtime_unscaled() uses to generate timestamps. cbe_init() calls clkinitf(), so re-initialize the microstate counters after the timesource has been chosen.
-> lgrp_plat_probe()
-> (**initptr)() // Call all system initialization functions. Initialization functions are saved in init_tbl[]. For each initptr, call the function.
-> vm_init() // vm subsystem related initialization
-> physio_bufs_init() // initialize buffer pool for raw I/O requests
-> XXX // Drop the interrupt level and allow interrupts. At this point the DDI guarantees that interrupts are enabled
-> vfs_mountroot() // Mount the root file system. errorq_init(), cpu_kstat_init(CPU), and ddi_walk_devs(ddi_root_node(), pm_adjust_timestamps, NULL) are called after the root file system is mounted.
-> post_startup()
2. setup_ddi
============
invoking stack:
main()
->startup()
-->startup_modules()
--->setup_ddi()
(1) impl_ddi_init_nodeid()
Keep a sorted free list of available nodeids. Allocating a nodeid won't cause memory allocation. Freeing a nodeid does cause memory allocation. The list node is defined as
struct available {
uint32_t nodeid;
uint32_t count;
struct available *next;
struct available *prev;
};
Mutex lock, nodeid_lock ,is defined to protect the nodeid list. The list head is pointed by nhead. impl_ddi_init_nodeid() is called to initialize the list and mutex lock.
(2) impl_create_root_class()
Create classes and major number bindings for the name of my root. Called immediately before 'loadrootmodules'. rootname = 'i86pc', platform = 'i86pc'
(3) create_devinfo_tree()
init the dev_info mem cache
alloc a dev_info for root and hold it
add the root dip into devimap list, the list is defined as,
struct devi_nodeid_list {
kmutex_t dno_lock; /* Protects other fields */
struct devi_nodeid *dno_head;
1. High level boot sequence
===========================
-> lgrp_setup() // Setup the first lgroup, and home t0
-> startup() // Machine-dependent startup code
// In a 32-bit OS, boot loads the kernel text at 0xfe800000 and kernel data
// at 0xfec00000. On a 64-bit OS, kernel text and data are loaded at
// 0xffffffff.fe800000 and 0xffffffff.fec00000 respectively. Those
// addresses are fixed in the binary at link time.
--> progressbar_init() // Initialize a rectangle area for progress bar
--> startup_init()
--> startup_xen_version()
--> startup_memlist() // Build the memlists and other kernel essential memory system data structures
--> startup_kmem() // Layout the kernel's part of address space and initialize kmem allocator
--> startup_vm() // Finish initializing the VM system, now that we are no longer relying on the boot time memory allocators.
--> startup_pci_bios() // Retrieve information from the bios needed for system configuration early during startup.
--> startup_modules() // setup_ddi() is called at this point to create a kernel device tree.
// First, create rootnex and then invoke bus specific code to probe devices.
--> startup_bios_disk() // ???
--> startup_end() // configure() is called at this point to set up devices.
// setx86isalist() is called to set the isa_list string to the defined instruction sets we support.
// psm_install() is called to call the prober() of each psm module
// (*picinitf)() is called to enabling interrupt. picinitf is set to mach_picinit() in ./i86pc/os/mp_machdep.c. Reading here, I am thinking about the IOMMU code. The best place to initialization and enable Intel IOMMU is here. We shouldn't put this range of code between the first and second pass of pci_enumerate(), since the pci device tree could be changes during the second pass (phantom, subtractive ppb and so on).
--> progressbar_start() // process bar related, ignore it.
-> segkmem_gc() // kernel memory segment driver related
-> callb_init() // Init all callb tables in the system
-> callout_init() // Initialize all callout tables. Called at boot time just before clkstart().
-> timer_init() // timer_init() allocates the internal data structures used by i_timeout(), i_untimeout() and the timer. Timer must be initialized before cyclic starts
-> cbe_init() // initialize cyclic back end
-> clock_tick_init_pre() // Clock tick initialization
-> clock_init() // initialize clock system
-> init_mstate()
-> init_cpu_mstate() //On some platforms, clkinitf() changes the timing source that gethrtime_unscaled() uses to generate timestamps. cbe_init() calls clkinitf(), so re-initialize the microstate counters after the timesource has been chosen.
-> lgrp_plat_probe()
-> (**initptr)() // Call all system initialization functions. Initialization functions are saved in init_tbl[]. For each initptr, call the function.
-> vm_init() // vm subsystem related initialization
-> physio_bufs_init() // initialize buffer pool for raw I/O requests
-> XXX // Drop the interrupt level and allow interrupts. At this point the DDI guarantees that interrupts are enabled
-> vfs_mountroot() // Mount the root file system. errorq_init(), cpu_kstat_init(CPU), and ddi_walk_devs(ddi_root_node(), pm_adjust_timestamps, NULL) are called after the root file system is mounted.
-> post_startup()
2. setup_ddi
============
invoking stack:
main()
->startup()
-->startup_modules()
--->setup_ddi()
(1) impl_ddi_init_nodeid()
Keep a sorted free list of available nodeids. Allocating a nodeid won't cause memory allocation. Freeing a nodeid does cause memory allocation. The list node is defined as
struct available {
uint32_t nodeid;
uint32_t count;
struct available *next;
struct available *prev;
};
Mutex lock, nodeid_lock ,is defined to protect the nodeid list. The list head is pointed by nhead. impl_ddi_init_nodeid() is called to initialize the list and mutex lock.
(2) impl_create_root_class()
Create classes and major number bindings for the name of my root. Called immediately before 'loadrootmodules'. rootname = 'i86pc', platform = 'i86pc'
(3) create_devinfo_tree()
init the dev_info mem cache
alloc a dev_info for root and hold it
add the root dip into devimap list, the list is defined as,
struct devi_nodeid_list {
kmutex_t dno_lock; /* Protects other fields */
struct devi_nodeid *dno_head;