1.簡介
本文主要介紹三個文件bootsect.s、setup.s、head.s,主要是做了些從軟盤加載內核和設置32位保護模式的操作。
2.程序分析
當PC電源打開后,BIOS自檢后將bootsect讀入內存絕對地址0x7c00處,因為bootsect.s的結尾是:
.word 0xAA55
然后跳轉到0x7c00處並把執行權交給此處的代碼,從start:處開始執行。
BOOTSEG = 0x07c0 INITSEG = 0x9000 start: mov ax,#BOOTSEG mov ds,ax mov ax,#INITSEG mov es,ax mov cx,#256 sub si,si sub di,di rep movw jmpi go,INITSEG
BOOTSEG是當前程序的起始內存地址的段地址,INITSEG表示是bootsect將要移動要的內存地址的段地址,這段代碼的意思是重復執行movw指令256次,每次從BOOTSEG(0x7c0段地址)+si的地址處移動一個字(2個字節)的數據到INITSEG(0x9000段地址)+di地址處,挨個移動256次,所以總共就是256字(512字節),bootsect.s編譯出來也就是512字節的大小。所以這段代碼執行完之后就是把自己拷貝到0x90000地址處,然后jmpi跳轉到0x9000的偏移地址為go的地方執行。
所以接下來程序執行到go:處,但是整個程序的起始段地址變成了0x9000,go處的代碼設置了下堆棧,接着是load_setup:
SETUPLEN = 4 load_setup: mov dx,#0x0000 ! drive 0, head 0 mov cx,#0x0002 ! sector 2, track 0 mov bx,#0x0200 ! address = 512, in INITSEG mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors int 0x13 ! read it jnc ok_load_setup ! ok - continue mov dx,#0x0000 mov ax,#0x0000 ! reset the diskette int 0x13 j load_setup
利用BIOS中斷int 0x13將setup從磁盤第2個扇區開始讀到0x90200開始處,共SETUPLEN(setup 程序的扇區數)讀4個扇區。成功后跳轉到ok_load_setup。
SETUPSEG = 0x9020 ok_load_setup: ... mov ax,#SYSSEG mov es,ax ! segment of 0x010000 call read_it call kill_motor ... jmpi 0,SETUPSEG
省略的代碼都是一些讀硬盤和驅動器的數據。這里比較關鍵的是call read_it,調用read_it:
SYSSIZE = 0x3000 SYSSEG = 0x1000 ENDSEG = SYSSEG + SYSSIZE read_it: mov ax,es test ax,#0x0fff die: jne die ! es must be at 64kB boundary xor bx,bx ! bx is starting address within segment rp_read: mov ax,es cmp ax,#ENDSEG ! have we loaded all yet? jb ok1_read ret ok1_read: ...
SYSSIZE是編譯后system模塊的大小,SYSSEG是system模塊將加載到的內存段地址處,所以ENDSEG的值就是system模塊停止加載的段地址。那么read_it的作用就是先判斷一下es是不是到了system模塊停止加載的段地址處,如果沒有則跳轉去讀取system模塊到這個地址。加載完成后就ret返回。然后關閉馬達后讀一些驅動器的信息,最后jmpi 0,SETUPSEG跳轉到0x9020:0000也就是setup.s程序的開始處。
bootsect.s就此結束,到現在為止內核各個模塊在內存中的位置如下圖的第3步:
接下來進入setup.s。
未完待續