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

Reply via email to