Thanks, Shudong, this is very useful document. BTW, can we (community) get access to other documentation, like writing nexus driver, for example. Provided that such documentation exists...
Cyril On 1/11/06, Shudong Zhou <szhou at billybob.sfbay.sun.com> wrote: > I made some notes for the S10 boot code while working on GRUB boot. > You might find the sparc portion useful for understanding ufsboot, > krtld, etc. The notes describes kadb as a standalone, which was > changed to kmdb (as a kernel module) before S10 was shipped. > > Shudong > > > #ident "@(#)bootcode.txt 1.4 04/05/13 SMI" > > Taking stock of Solaris 10 boot code (S10_53) > > Shudong Zhou > > > bootblk: installed on disk starting from 2nd block > (equivalent to GRUB stage2) > > realmode/dos/bootblk > bootblk understands ufs > strap.com understands pcfs > > psm/stand/bootblk > ufs > This looks like the only relevant code. The only > thing useful is in sparc/sun4u (forth code). > Hardcoded to read ufsboot/alternate-booter. > hsfs > Looks unused, doesn't install anything > obp-c > These are used to build bootblk for sun4c/4d/4m. > XXX Why are we still doing that in s10? > > secondary booter: loaded by bootblk > (This thing should be much simpler after boot-rearch) > > wanboot: > sparc/common/wanboot.c wbfsconf.c wbcli.c > (wanboot specific) > (common part) > sparc/common/sun4u_srt0.s (where it all starts...) > sparcv9/sun4u/machdep.c > sparc/common/sparcv9_subr.s get.c boot_plat.c > bootops.c bootprop.c boot_services.c bootflags.c > sun4u_memlist.c sun4x_standalloc.c ramdisk.c > common/heap_kmem.c readfile.c > usr/src/common/util/getoptstr.c (XXX should be in lib?) > + stand/lib libraries > > ufsboot: sparc/common/boot.c fsconf.c (ufsboot) > (ditto common part) > > hsfsboot: sparc/common/boot.c hsfsconf.c (hsfsboot) > (ditto common part) > > inetboot: sparc/common/boot.c fsconf.c (a.out format) > (ditto common part) > > boot.bin (x86): i386/i86pc/srt0.s > cpu_id.s cache.s endsrt0.s idttab.s intr.s machdep.c > i386/common/a20enable.c arg.c ata.c boot_plat.c bootflags.c > bootops.c i386_bootprop.c bsetup.c bsh.c bus_probe.c > cbus.c chario.c cmds.c cmdtbl.c compatboot.c debug.c > delayed.c i386_devtree.c disk.c dosbootop.c dosdirs.c > dosemul.c dosmem.c env.c expr.c gets.c help.c > i386_memlist.c i386_standalloc.c if.c initsrc.c > ix_alts.c keyboard.c keyboard_table.c load.c map.c > memory.c misc_utls.c net.c net_pxe.c probe.c > prom.c prop.c setcolor.c src.c var.c vga.c acpi_pm.c > exprgram.y fsconf.c > intel/bootprop.c devtree.c > common/heap_kmem.c readfile.c > uts/intel/os/acpi_intp/acpi_boot.c acpi_inf.c acpi_bad.c > acpi_decl.c acpi_exe.c acpi_gram.c acpi_io.c > acpi_lex.c acpi_name.c acpi_ns.c acpi_op1.c acpi_op2.c > acpi_rule.c acpi_tab.c acpi_thr.c acpi_val.c acpi_exc.c > acpi_bst.c acpi_node.c acpi_stk.c acpi_par.c acpi_ml.c > usr/src/common/util/getoptstr.c (XXX should be in lib?) > > inetboot (x86): ditto boot.bin > > Others: alternative loaders > > kadb(sparc): kadb/common/main.c kadb.c > debug.o: sparcv9/sun4u/locore.s savestate.s physmem.s invoke.s > machstate.c machdep.c > sparcv9/common/stubs_sparcv9.c readfile_sparcv9.c > support_sparcv9.c fiximp.c > pf.c: macros > sun4u-kadb.o: cmd/adb/sparc/kadb/* > > kadb(x86): kadb/common/main.c kadb.c > debug.o: i386/i86pc/locore.s intr.s tables.s ttrap.s prom.c > machdep.c, stubs_i386.c readfile_i386.c support_i386.c > machstate.c > pf.c: macros > i86pc-kadb.o: cmd/adb/i386/kadb/* > > cprboot: cpr/sparcv9/sun4u/cb_srt0.s cprboot.c machdep.c pages.c > bitmap.c util.c > cpr/sparcv9/common/support.c > uts/common/os/compress.c > > psm/promif > sparc/sun4u specific libprom.a (see psm/stand/lib) > > psm/stand/boot > common/heap_kmem.c memory allocator > common/readfile.c read elf & elf64 > common/stripalign.c > > psm/stand/lib > libboot.a: uts/sparc/os/bootops.c (why compile v8?) > boot/i386/common/bootops.c > libprom.a: psm/promif/ieee1275 > uts/intel/promif/*.c > libnames.a: names/ (uname directory stuff) > > stand/lib > Filesystem support > libcachefs.a > libhsfs.a > libufs.a > libnfs.a > libcompfs.a (x86 only) > libpcfs.a (x86 only) > Common services (shared source with kernel) > libcrypto.a > libscrypt.a > libmd5.a > libssl.a > libnvpair.a > Boot specific services > libsa.a (what's this for?) > libinet.a > libtcpstubs.a > libwanboot.a > libsock.a > libxdr.a (why not share code?) > libtcp.a (stubs) > libboot.a (bootops) > > > Boot timeline: SPARC > ==================== > > bootblk->kadb|xxxboot->krtld->unix > bootblk->cprboot->kernel > > kadb > ---- > locore.s > debug stack 0x8000 (32K) > debug vector, etc > _start() > .enterkadb // setup trap > .xword ... // setup callbacks > > early_startup() // setup kadb_bootops, etc > startup() // machdep > initialize_console() > main() // enter debugger > > kadb/common/main.c > load_it() // read obp defined file name > exitto() // jump to kernel/kobj > > > sun4u_srt0.s (ufsboot/inetboot/wanboot on sparc) > ------------ > stack 0x14000 (80K) > _start() > %o4 contains p1275cif address > call main(prom-cookie) > > exitto() > exitto64() > client_handler() > > boot_plat.c -- main() > prom_init() > fiximp() (align = 1) > system_check() (prom version, CPU) > > init_memlists() > set_default_filename() -> kernel/sparcv9/unix > init_bootargs() // parse boot arges > prom_bootpath() > setup_bootops() // strip : from network device > retain_nvram_page() > > bootprog(path, args, filename) > set_fstype() cachefs, ufs, nfs > mountroot() > <redirection stuff> > post_mountroot(filename, NULL) > interactive boot stuff > readfile() // boot file > exitto64() // jump to _kobj_boot() > > kernel > ------ > common/krtld/kobj_boot.c > _kobj_boot() // kernel/sparcv9/unix list krtld as the > // interpretor; this is the entry point of > // krtld returned by readfile() in the boot > // loader (xxxboot or kadb) > kobj_init() > load dependent modules of unix: > genunix, misc/platform, cpu/$CPU, dtracestubs > bind and relocate the modules > exitto() > unix entry point (_start) > > ml/mach_locore.s > _start() > init CPU registers > register windows stuff > kadb stuff > init thread 0 stack > mlsetup // lots of cpu/thread/proc/boot flags > > common/os/main.c > main (kernel's main) > startup() > segkmem_gc() > callb_init() > callout_init() > cbe_init() > clock_init() > call all init_tbl[] > vm_init() > physio_bufs_init() > spl0() // allow interrupts > vfs_mountroot() // can happen earlier? > errorq_init() > cpu_kstat_init() > post_startup() > strplumb() > init_mstate() > consconfig() // XXX move to earlier... > forceattach_drivers() // XXX still needed? > process init > exacct_init > sysevent_evc_thrinit > start_other_cpus() // do it earlier? > lgrp_root_init() > kmem_mp_init() > vmem_update() > run everything in mp_init_tbl[] > create init process > create pageout > create fsflush > cluster hooks > ... > sched() > // switch root in init? > > > cprboot > ------- > cb_srt0.s > initialization > call main() > first stage: > prom_init() > get_bootargs() > cb_drive(first_worklist) > cb_intro, > cb_startup, > cb_get_props > cb_usb_setup > cb_open_sf > cb_read_statefile > cb_close_sf > cb_check_machdep > cb_interpret > cb_get_physavail > cb_set_bitmap > cb_get_newstack > return to "cb_srt0.s", switch to new stack > second stage > cb_drive(second_worklist) > cb_relocate > cb_tracking_setup > cb_restore_kpages > cb_terminator > cb_ksetup > cb_mpsetup > exit_to_kernel() > > Boot timeline: x86 > ================== > > mboot->pboot->bootblk[->strap.com] > bootblk->boot.bin->krtld->unix > bootblk->boot.bin->kadb->krtld->unix > > mboot (realmode/dos/hd/mboot) > master boot record (can be replaced by other mboot progs) > reside on the first physical sector of the hard drive > looks at fdisk partitions and read the active one (pboot) > > pboot (realmode/doc/hd/pboot) > partition boot record > installed on the first logical sector of solaris partition > Search the fdisk table, read bootlk from the the active > partition and jump to it. > > bootblk (realmode/dos/bootblk) > asm.s init + call boot_blk > bootblk.c > fs_init() ufs or fat > if not floppy > reboot() > allows user to select bootable partition > This is the blue screen > If selected, jump to 0x7c00 (strap.com?) > read boot.bin to 0x8000 and above > jump to 0x8000 > > i386/i86pc/srt0.s (boot.bin/inetboot) > ----------------- > call doint (compatibility for xpcimach module -- what's that?) > setup idt (defined in idttab.s) > call bsetup > call main > > i386/common/bsetup.c--bsetup(): > doint() // cursor to 0,0 > doint() // write black-on-white to screen > enable_cpuid() > pxe_check() // PXE boot? > setup boot scratch mem // end of text to 1MB > kmem_init() > setup_devtree() > setup "standard" nodes: root, +boot, memory, > aliases, chosen, i86pc-memory, i86pc-mmu > openprom, options, packages, delayed-writes > itu-props > set root to "i86pc" > add hard-coded properties > if (use_serial) ... // dead code? > if pxe_boot > pxe_early_setup() > // handle int15 in protected mode > tftpbootenv() // read some kind of env file? > clear screen > probe() > get ega font pointer locations > gather memory size info form CMOS and BIOS ram > is_MC() check for micro-channel and panic > is_EISA() // didn't we just EOL this thing? > is_ISA() // seems to be the only thing left > cpu-type is486() else 386 > // no 586, Opteron, etc... > setup btep->memrng[] (memory range) > memtest() // get memory size > check_hdbios(); > check_ata() // check presence of controllers > // and drives. > acpi_enum(); > acpi_init() > acpi_rootobj() // disable if no root obj > acpi_trans_dev() // walk acpi tree > acpi_setprop(); > set acpi-memory prop > setup_memlists() > setup MEM_INSTALLED > setup MEM_AVAIL > setup MEM_VIRTUAL > init_paging() > allocate page table and turn on MMU > probe_eisa() // why is this still here? > if PXE pxe_setup() > > boot_plat.c > fiximp() cpu level, largepage support, global pages? > init_bootpath() > set_client_bootpath() > setup_bootops(); > create boot-args property > set_fstype() // get fs type, default fsw set to compfs... > // extendfs set to pcfs, origfs set to nfs/ufs > mountroot() // always compfs mountroot, which ref other > // fs'es via extendfs and origfs > dosemul() // setup dos emulation: int21 hooks > bsh_init() > source bootenv.rc > bsh() // hand control over to boot shell > getsrcchar() reads > /boot/solaris/boot.rc > /etc/bootrc > console input > > > source boot.rc > source /boot/solaris/bootenv.rc > source /boot/solaris/bootargs.rc > run /boot/solaris/bootconf.exe ${confflags} > XXX What flags are taken? > > surce /etc/bootrc > process args > run $bootfile (successful boot doesn't return) > source /etc/bootrc (recurse) > > $bootfile is either kadb or kernel/unix > > > run $bootfile > ------------- > > i386/common/load.c > loadnrun_x() the dos "run" command maps to this function > look for well-known dos extensions .bef, .sys, .com, .exe > For booting kernel, call loadnrun_elf() > loadnrun_elf() > openfile() > readfile() // load kadb or kernel/unix > p0_mapin() // map in page 0 > exitto() // kadb or kernel > > kadb > ---- > > kadb/i386/i86pc/locore.s > _start() > switch from boot stack to new stack > create/load idt gdt > call main() > > kadb/common/main.c > init_bootops() // on x86 only > load_it() // read kernel/unix or whatever specific in bsh() > it returns the entry point to interpreter (_kobj_boot) > lookup() a bunch of symbols > if interactive boot, setbp() > exitto() // jump to kernel/kobj > > args pass to kernel: > struct boot_syscalls *sysp /* not used by kernel */ > dvec /* debug vector; kadb only */ > struct bootops *bop (bootops.c) > Elf32_Boot *elfbootvec /* from krtld */ > > kernel > ------ > common/krtld/kobj_boot.c > _kobj_boot() // kernel/unix list krtld as the interpretor; > // this is the entry point of krtld returned > // by readfile() in kadb > kobj_init() > load dependent modules of unix: > genunix, mmu/$MMU, dtracestubs > bind and relocate the modules > exitto() > unix entry point (_start) > > i86pc/ml/locore.s > _start() > check for kadb support > builds kernel IDT, GDT, LDT > eflags > cpuid > perform 5/2 to detect Cyrix?? > Cyrix stuff > patch_tsc > mlsetup // lots of cpu/thread/proc/bootflags > main > > common/os/main.c > main (kernel's main) > startup() > segkmem_gc() > callb_init() > callout_init() > cbe_init() > clock_init() > call all init_tbl[] > vm_init() > physio_bufs_init() > spl0() // allow interrupts > vfs_mountroot() // can happen earlier? > errorq_init() > cpu_kstat_init() > post_startup() > strplumb() > init_mstate() > consconfig() // XXX move to earlier... > forceattach_drivers() // XXX still needed? > process init > exacct_init > sysevent_evc_thrinit > start_other_cpus() // do it earlier? > lgrp_root_init() > kmem_mp_init() > vmem_update() > run everything in mp_init_tbl[] > create init process > create pageout > create fsflush > cluster hooks > ... > sched() > // switch root in init? > > > cprboot > ------- > not applicable to x86 > > > > Network booting > > sparc > ----- > > OBP retrieves inetboot or wanboot over the network. > > Boot server is configured to know the MAC address of > clients and place a file in /tftpboot named after the > hex digits of the ethernet address. > > WANBOOT: > > wanboot diverges from ufsboot/inetboot at bootprog() > > wanboot.c > bootprog() > init_netdev() > bootinfo_init() > wanboot_init_interface(wanboot_args) > init_encryption() > init_hashing() > > get_url() http://host[:port]/abspath > get_wanbootfs(&server_url) > bootconf_init() > init_boot_time() > want_boot_verify_config() // check wanboot.conf > get_miniroot(&miniroot_path) > estalish_http_connection() > process_miniroot() > fd = create_ramdisk() > create_ramdisk_node() > // send forth code down > prom_interpret() > prom_open(/<name>:size=0x,0x) > write_msg_to_ramdisk() > prom_close(fd) > verify_digests() > unmountroot() // unmount wanboot fs > > determine_fstype_and_mountroot() // mounts miniroot > v2path = "/ramdisk-rootfs:a" // set bootpath > handle boot args > cleanup bootconf_end() > bootinfo_end() > > x86 > --- > > The traditional netboot requires a floppy or cd to > kickstart the process. Once the system is in bootconf, > a menu with all bootable interfaces will be displayed. > If user picks a network interface, boot.bin will attempt > to retrieve inetboot over the network, just like the > way sparc OBP does it. > > PXE boot: > > BIOS will send out a DHCP request for boot service. > Upon getting an answer from the boot server, it will > download a problem and place it at 0x7C00 and jump > to it. For Solaris, this is a realmode program. > > realmode/dos/nbp/asm.s > init NBP environment > save PXE stack and !PXE pointer arg > setup NPB stack > call pxe_nbp() > > nbp.c > pxe_nbp() > ping Solaris boot message > wait 2 seconds for keystroke (for debug) > pxe_boot() /* doesn't return if successful */ > download inetboot and place it between > end of NBP and start of realmode memory for PXE > > Check UNDI state > net_addr(ether) // get mac address > pxe_call(PXENV_UNDI_GET_INFORMATION) > dhcp_config() // get boot server and file > pxe_UDP_open() > dhcp_send() > dhcp_receive() > pxe_UDP_close() > read_file() > pxe_call(...) > call_boot_bin() // jump to 0x8000 > > x86 bootconf > ------------ > > usr/src/realmode/dos/bootconf/ > > init_main() > if autoboot > run_enum(ENUM_ALL) > auto_boot() > get_bootpath() > sanitise_devices() > assign_prog_probe() > program_enum() // wakeup devices > program_pnp() > or > program_pci() > order_devices() > load bef drivers? > find_PXE_dev() > load bef for boot path > write_escd() > build_tree() > output_biosprim() > used_resources_node_ur() > set_prop_version() > set_stdin() > try_mount() > set_boot_control_prop() > done(0) > > run_enum(ENUM_ALL) > MotherBoard() > memory resource > irq 0 (nmi), 2 (2nd pic), 8 (clock), 13 (fpu) > port 0-0x59, 0x61-63, 0x65-9b > (0x60, 0x64 kb/mouse) > dma 4 (cascaded dma) > enumerator_acpi(ACPI_INIT) > loop acpi_copy() > compare with motherboard device > if already exists or conflict > resolve the difference > else > acpi_translate_devdb() > TranslateDevice_devdb() > if real driver > TranslateDriver_devdb() > acpi_add_board() > enumerator_pnp(); > isa+ PNP enumeration > enumnerator_pnpbios(LPT_COM_PNPBIOS) > get irq + io port from > pnpbios_hdr_t 0xf0000000 - ffff0000 > for serial and parallel ports only > device_probe(DPROBE_ALWAYS) > load isa.000-099 > com, joyst, logi, msm, fdc, key, lpt, ps2ms > > enumerator_pci > check pciide > get interrupt routing table from BIOS > int > create_config_ports_board_pci() > get_configured_dev_resources(0) > loop through func, get vid and conf header > loop through peer busses > get_configured_dev_resources(i) > > enumerator_eisa > _int86() read eisa slots > ReadEISAid(slot) > for each function > GetEisaFctnTab() > > enumerator_pnpbios(REST_PNPBIOS) > extract_resources_pnpbios() non-com/lpt devices > > enumerator_vgaprobe() > find_vga_bios() > 0xc0000 > int 10h -> get type > if xga > create_xga_node() > find_video_board() > query 0xb0000 + 64k > get_vga_properties() > VESA stuff > > enumerator_bios() > look for un-enumerated resourece btw 0xc0000000-0xf0000000 > add them with "SUNFFFE1" > > read_escd() > read configuration info saved from last boot > > enumerator_acpi(ACPI_COMPLETE) > acpi_add_rest() > if no conflict, add it > else > resolve non self-identifying bus devices > else > shouldn't happen, but add anyway > MakeAliases() > MakeComAlias("com1", 0x3f8); alias for ports > MakeComAlias("com2", 0x2f8); > MakeComAlias("com3", 0x3e8); > MakeComAlias("com4", 0x2e8); > MakeComAlias("ttya", 0x3f8); > MakeComAlias("ttyb", 0x2f8); > MakeComAlias("ttyc", 0x3e8); > MakeComAlias("ttyd", 0x2e8); > "screen" for video > "key" for "keyboard" (driver) > > > build_tree() > loop through Head_board > if conflict for weak resources, skip > call bus specific code to build node > add property from database > add_boot_interface() > > > _______________________________________________ > powerpc-discuss mailing list > powerpc-discuss at opensolaris.org > > -- Regards, Cyril