OpenBSD內核之引導PBR

  OpenBSD引導的第二部PBR,也是活動分區的一個扇區的代碼,由第一步的MBR加載到0x7C00處,manpage裏詳細的講解了過程和大體實現 biosboot(8) http://man.openbsd.org/OpenBSD-6.0/man8/i386/biosboot.8),代碼在sys/arch/i386/stand/biosboot/目錄下,主要就是其中的biosboot.S;和mbr.S同樣,在代碼的開頭清晰的介紹了該代碼要作的事情:node

 

/*
 * Memory layout:
 *
 * 0x00000 -> 0x07BFF    our stack        (to  31k)
 * 0x07A00 -> 0x07BFF    typical MBR loc        (at  30k5)
 * 0x07C00 -> 0x07DFF    our code        (at  31k)
 * 0x07E00 -> ...        /boot inode block    (at  31k5)
 * 0x07E00 -> ...        (indirect block if nec)
 * 0x40000 -> ...    /boot            (at 256k)
 *
 * The BIOS loads the MBR at physical address 0x07C00.  It then relocates
 * itself to (typically) 0x07A00.
 *
 * The MBR then loads us at physical address 0x07C00.
 *
 * We use a long jmp to normalise our address to seg:offset 07C0:0000.
 * (In real mode on x86, segment registers contain a base address in
 * paragraphs (16 bytes).  0000:00010 is the same as 0001:0000.)
 *
 * We set the stack to start at 0000:7BFC (grows down on i386)
 *
 * We then read the inode for /boot into memory just above us at
 * 07E0:0000, and run through the direct block table (and the first
 * indirect block table, if necessary).
 *
 * We load /boot at seg:offset 4000:0000.
 *
 * Previous versions limited the size of /boot to 64k (loaded in a single
 * segment).  This version does not have this limitation.
 */

 

  註釋內容包含了mbr.S開頭的內容,仍是講解了大體引導過程:BIOS MBR0x7C00處,而後MBR將自身重定位到0x7A00MBR加載PBR也就是biosboot.S0x7C00,而後jmp0x7C00處的biosboot.S執行。ios

  biosboot.S的特殊之處在於不像mbr.S裏那樣直接從磁盤扇區的第1扇區這種「物理」定位信息加載後續代碼,也就是說biosboot須要能直接操做文件系統了,由於它後續加載的是/boot,要直接從根分區加載boot!對比其餘的bootloader,好比GRUBGRUB能直接讀各類各樣的文件系統,其代碼複雜度可想而知,OpenBSDbiosboot實際上並不能讀文件系統,由於它只有512字節啊,這點空間不可能能放下文件系統驅動!biosboot採起的方法是在最終的二進制內容裏直接保存/boot所在的磁盤扇區位置信息,固然不可能直接寫死在biosboot.S代碼裏,採起的辦法是打二進制patch,也就是直接修改編譯後的二進制文件裏的,經過用戶態程序/usr/sbin/installboot/boot的物理位置信息寫到編譯後的biosboot中,而後將修改後的biosboot寫到分區第一個扇區;這裏涉及到ELF文件相關知識,在biosboot.S中有幾個導出的符號,installboot/boot物理位置信息寫到這幾個符號所指的位置處,代碼的註釋裏清晰的講解了這幾個導出符號:ui

 

/*
 * The data passed by installboot is:
 *
 * inodeblk    uint32    the filesystem block that holds /boot's inode
 * inodedbl    uint32    the memory offset to the beginning of the
 *            direct block list (di_db[]).  (This is the
 *            offset within the block + $INODEOFF, which is
 *            where we load the block to.)
 * fs_bsize_p    uint16    the filesystem block size _in paragraphs_
 *            (i.e. fs_bsize / 16)
 * fs_bsize_s    uint16    the number of disk sectors in a filesystem
 *            block (i.e. fs_bsize / d_secsize). Directly written
 *            into the LBA command block, at lba_count.
 *            XXX LIMITED TO 127 BY PHOENIX EDD SPEC.
 * fsbtodb    uint8    shift count to convert filesystem blocks to
 *            disk blocks (sectors).  Note that this is NOT
 *            log2 fs_bsize, since fragmentation allows
 *            the trailing part of a file to use part of a
 *            filesystem block.  In other words, filesystem
 *            block numbers can point into the middle of
 *            filesystem blocks.
 * p_offset    uint32    the starting disk block (sector) of the
 *            filesystem
 * nblocks    uint16    the number of filesystem blocks to read.
 *            While this can be calculated as
 *            howmany(di_size, fs_bsize) it takes us too
 *            many code bytes to do it.
 *
 * All of these are patched directly into the code where they are used
 * (once only, each), to save space.
 *
 * One more symbol is exported, in anticipation of a "-c" flag in
 * installboot to force CHS reads:
 *
 * force_chs    uint8    set to the value 1 to force biosboot to use CHS
 *            reads (this will of course cause the boot sequence
 *            to fail if /boot is above 8 GB).
 */

 

  這幾個值使biosboot能直接定位到磁盤上的bootbiosboot中和mbr同樣也有CHSLBA相關的代碼,按住shift鍵強制使用CHS模式。加載boot到0x40000,也就是256KB處,而後jmp到其中繼續執行/bootthis

  OK,終於看完這些實模式的鬼東西了……後面空了再繼續寫boot後面的東西吧。spa

相關文章
相關標籤/搜索