📄 chain.s
字号:
; chain.S - LILO boot chainer ;; Copyright 1992-1998 Werner Almesberger.; Copyright 1999-2004 John Coffman.; All rights reserved.;; Licensed under the terms contained in the file 'COPYING' in the ; source directory.;#define LILO_ASM#include "lilo.h"get common.s /* as86 "include" will bypass the CPP */; for debugging, set the EBDA size in Kilobytes; e.g., 64#define EBDA 0#define REVERSE_DL 1#if defined(LCF_SOLO_CHAIN) && !defined(DOS_D)#ifndef DOS_D#define DOS_D#endif#ifndef CHECK#define CHECK#endif#endif /* LCF_SOLO_CHAIN */#if VERSION_MINOR >= 50#define DEBUG_NEW#endif .text .globl _main .org 0_main: cld ! make sure !!! jmp start .org 6 .ascii "LILO" ! signature .word STAGE_CHAIN .word VERSIONoffset: .word 0! the byte "drive" is filled in by the installer & updated by the second stage drive: .byte 0 ! drive, 0x80, 0x81 .byte 0 ! head, always zerohint: .word drvmap ! pointer to drive mapptable: .blkw 0x20 ! partition table to preloaddevmap: .word 0,0 ! device map filled in by second.Scmd: .word 0,0 ! command line to pass on; ES:DI contains a pointer to the command line passed from second-stagestart: xor bx,bx ! set SS:SP to 0:7C00 mov ss,bx mov sp,#BOOTSEG*16 ! #0x7C00 mov bp,sp ! address from BP#if EBDA push #0x40 pop ds mov word ptr [0x13],#640-EBDA ; simulate EBDA in Kilobytes#endif push cs pop ds#ifdef DEBUG_NEW push bp push es pop ds mov si,di call say push cs pop ds mov si,#crlf call say call bd1 .ascii "Boot drive 0x" .byte 0bd1: pop si call say mov al,drive call bout mov si,#crlf call say pop bp#endif mov al,#0x3D ! '=' sign mov cx,#-1 repne scasb ! scan for =srch: seg es mov al,(di) inc di cmp al,#0x20 ! test for space ja srch; real command line if AL==space, no command line if NUL jb nocmd mov [cmd],di mov [cmd+2],esnocmd:;; Account for any drive mappings being used by the Second Stage; les di,[parC_devmap] ! second stage translate table ! this was set by the second stage loader#if defined DEBUG_NEW mov ax,es call wout mov al,#0x20 call cout mov ax,di call wout mov si,#crlf call say mov bx,di call dump_drvmap#endif call install_map ! install it; ; but first, process the two 0xFFFF drive-map records for "master-boot"; mov si,#drvmap ! our created drive map cmp WORD (si),#-1 ! test for "master-boot" jne noswap mov ah,[drive] ! boot drive mov al,(si+3) ! possible "boot-as=" cmp al,#-1 ! test for master jne boot_as! make AL the master drive (0 or 80) mov al,ah and al,#0x80 ! AL is master drive 0 or 80boot_as: mov (si),ax ! 80 -> boot xchg ah,al mov (si+2),ax ! boot -> 80 cmp ah,al ! are they the same jne domerge add si,#4 ! skip a "no-translation" mov byte (si-1),#-1 ! clear any boot-asnoswap:domerge: mov [devmap],si ! save updated value;************************************** push ss pop es mov cx,#SECTOR_SIZE/2mtmp = SETUPSECS-1 ! broken math ... mov si,#mtmp*SECTOR_SIZE#ifdef DEBUG_NEW mov di,#boot_sector cmp si,di ja use_setupsecs_m_1 mov si,diuse_setupsecs_m_1:#endif mov di,bp ! #0x7C00 rep movsw#ifdef DOS_D#ifdef CHECK mov si,#BOOTSEG*16+0x24 ; address of first byte to test cmp byte (bp+0x15),#0xf8 ; check media descriptor jne ck_failed seg es lodsb cmp al,#0x80 ; check range of device codes jb ck_failed cmp al,#0x8f ja ck_failed seg es lodsb or al,al ; check hi-byte is empty jnz ck_failed seg es lodsb cmp al,#0x29 ; I do not know what this byte means je ck_okay cmp al,#0x28 ; HPFS marker jne ck_failedck_okay: lea si,(si+4) ; address of vol label & fs type mov cx,#11 ; volume label (11)ck_next: seg es lodsb or al,al js ck_failed ; not alphabetic if >= 0x80 jz ck_loop ; NUL allowed for HPFS cmp al,#0x20 jb ck_failed ; not alphabetic if < SPACEck_loop: loop ck_next mov cx,#8 ; check Filesystem typeck_fstype: seg es lodsb or al,al ; not alphabetic if >= 0x80 js ck_failed cmp al,#0x20 ; not alphabetic if < SPACE jb ck_failed loop ck_fstype#endifdos4: call revmap1 mov (bp+0x24),dx ! fill in 0x24 and 0x25 mov si,offset mov edx,ptable+8(si) mov (bp+0x1C),edx#ifdef DEBUG_NEW mov si,#update jmp ck_say ck_failed: mov si,#no_updateck_say: call say#elseck_failed:#endif#endif mov cx,#0x20 ! move partition table mov si,#ptable mov di,#PART_TABLE rep movsw ! mess with the partition table#if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY) mov si,#prtmap ! get partition table change rulesprtclp: lodsw ! bios == 0 indicates end or al,al jz pmend ! at end -> quit cmp al,cache ! already in cache ? je incache ! yes -> no loading required push ax ! save table data call flush ! flush the cache pop ax push ax mov cache,al ! remember drive in cache#if 0 cmp al,drive ! boot drive ?#else call revmap1 cmp al,dl#endif jne noc ! no -> load into scratch area xor ax,ax ! load at 0000:0600 mov bx,#PARTS_LOAD jmp loaditpmend: call flush ! flush table br nopp ! and proceednoc: mov ax,ds mov bx,#PARTS_SCR ! scratch area 0000:0800loadit: mov es,ax ! set up pointers and remember them mov ces,ax mov cbx,bx mov ax,#0x201 ! load partition table, one sector mov dx,cache ! drive from cache (DH = 0) mov cx,#1#ifdef DEBUG_NEW pusha mov al,dl ! dump device code call bout mov si,#msg_load ! say loading call say popa#endif int 0x13 ! load it jc wrfail ! error -> abort pop ax ! get BIOS and offsetincache:les bx,cbx ! load pointer add bx,#PART_TABLE_OFFSET ! move to partition table add bl,ah ! offset is always in [0x1be,0x1fd] lodsw ! see what we need to do seg es ! match ? cmp byte ptr (bx),al jne nocng ! no -> do not change seg es ! change mov byte ptr (bx),ah mov byte ptr dirty,#1 ! mark as dirtynocng: br prtclp ! next oneflush: test byte ptr dirty,#1 ! dirty ? jz noflush ! no -> do not write mov ax,#0x301 ! write one sector mov dx,cache ! get the drive or dl,dl ! nothing cached ? jz noflush ! no -> do not flush les bx,cbx ! reload pointer#ifdef DEBUG_NEW pusha mov al,dl ! dump device code call bout mov si,#msg_write ! say writing call say popa#endif int 0x13 ! write ... jc wrfail ! arglnoflush:retwrfail: mov si,#failmsg ! complain call say#if 0 mov ax,#FIRSTSEG ! try to restart LILO jmpi #GO,FIRSTSEG#else xor dx,dx ! zap the device code jmpi FIRSTSEG*16,0 ! try to restart at 0000:7c00#endifcache: .byte 0 ! drive, 0 means not cached .byte 0 ! head, always 0cbx: .blkw 1ces: .blkw 1dirty: .byte 0#endif; reverse drive mapping; uses AX; updates DL;revmap1: push si mov dx,drive ; get drive/head pair mov si,#drvmaprev0: lodsw ; get to, from pair or ax,ax ; test for end jz rev9 ; done cmp ah,dl ; booting from "to" jne rev0 ; loop if not mov dl,al ; substitute the "from"rev9: pop si ; restore SI retnopp:#if 0 mov ax,drvmap ! need to install mapper ? or ax,ax jz noimap ! no -> go on call swap13noimap:#else mov di,[devmap] ! get drive map pointer cmp word (di),#0 je noimap push cs pop es ; ES:DI points at the current map call install_mapnoimap:#endif#if REVERSE_DL call revmap1#else mov dx,drive ! initialize DX (drive and head)#endif mov si,offset ! DS:SI and ES:SI point to the partition add si,#PART_TABLE#ifdef DEBUG_NEW pusha mov cx,# 4<<4 ; delay 4 seconds xor dx,dx mov ah,# 0x86 int 0x15 ! Delay 6 seconds#ifdef DEBUG_CONTINUE jnc delayed mov si,#msg_cont ! Hit any key ... call say xor ax,ax int 0x16 ! AH==0, get keydelayed:#endif popa#endif xor ax,ax ! set DS and ES to zero mov ds,ax mov es,ax mov bx,#BOOTSEG*16 ;;;; mov ss,ax ! on all processors since the 186 mov sp,bx ! these instructions are locked #ifdef LCF_COHERENT mov (si),dl ! yes, put it in the partition table#endif mov bp,si ! BP==SI flags hard disk boot push ax push bx seg ss cmp byte ptr (bx+par1_cli),#0xFA ! first.S starts with CLI je try_sig cmp byte ptr (bx+par1_cli),#0xEB ! short jump? jne gotoit push ax mov al,(bx+par1_cli+1) ! get offset cbw inc ax inc ax add bx,ax ! test relocated record pop ax cmp byte ptr (bx+par1_cli),#0xFA ! first.S starts with CLI jne gotoit ! not LILO if no CLItry_sig: seg ss cmp dword ptr (bx+par1_signature),#EX_MAG_HL jne gotoit ! LILO signature required for command line seg cs cmp dword ptr [cmd],#0 je gotoit; pass on a command line seg cs les bx,[cmd] lea si,(bx-4) seg es mov dword ptr (si),#EX_MAG_HL mov dh,dl mov dl,#EX_DL_MAGgotoit: retf#if defined(LCF_REWRITE_TABLE) || defined(DEBUG_NEW)! Display a NUL-terminated string on the console! DS:SI points at the string!say: push ax push bx ! save BXsay_2: lodsb ! get byte or al,al ! NUL ? jz aret ! yes -> done mov ah,#14 ! display, tty-style mov bx,#0007 int 0x10 jmp say_2 ! next onearet: pop bx ! restore pop ax ret ! donefailmsg:.ascii "Rewrite error." .byte 13,10,0#endif;**************************************; Merge the contents of two drive maps;; First drive map encountered: DS:SI; Second drive map encountered: ES:DI; Output drive map: DS:BX;; The output drive coincides with the First drive map;; Enter with DS != CS;;; drive_map_merge: pusha ! save all the registers;; this is the guts of the loop to merge the records;process: lodsw ! get drive mapping or ax,ax jz copy push di jmp nextone1nextone: inc di inc dinextone1: seg es cmp word (di),#0 je atend seg es cmp (di),ah jne nextone seg es mov ah,(di+1) ! do the translation seg es mov word (di),#-1 ! wipe out entryatend: cmp ah,al ! remove null translation je nostore mov (bx),ax inc bx inc bxnostore: pop di jmp process; finished merge, copy the rest from the sourcecopy: seg es mov ax,(di) ! inc di inc di inc ax jz copy ! it was -1, skip it dec ax mov (bx),ax ! store value or end marker jz alldone ! it was 0, end marker inc bx inc bx jmp copyalldone: popa ! restore all that we saved ret; end of drive_map_merge;**************************************; Install a drive swapper with a null drive map;; Enter with:; DS == CS, SS == 0000;; Exit with:; ES:DI points at the null device map;; EAX is trashed; All other registers preserved;;swap13_null: push cx push si#ifdef DEBUG_NEW call sn11 .asciz "Installing Drive Swapper\r\n"sn11: pop si call say#endif seg ss dec word [0x413] ; allocate 1k int 0x12#if EBDA_EXTRA sub ax,#EBDA_EXTRA ! allocate extra EBDA#endif shl ax,#10-4 ; convert to paragraphs mov es,ax ; xor di,di ; DI = 0 shl eax,#16 ; EAX is ES:DI seg ss xchg eax,[4*0x13] ; set new int 0x13 vector; get old mov [old13of],eax mov cx,#NEW13B/2 ; count of words to move mov si,#new13 ; source is DS:SI rep movsw ; move in the new drive mapper seg es mov (di),cx ; CX is zero from the move pop si pop cx ret; Install drive mapper map;; The map to use is at ES:DI; If there is an existing drive mapper, the two are merged.; If there is no drive mapper, then one is installed.;; Enter with ES:DI set to point at the map to install; DS == CS;; Exit with DS=CX; All registers are preserved;install_map: push es pusha ; save all the regs mov bp,sp ; save stack location#ifdef DEBUG_NEW call im111 .asciz "Install Map\r\n"im111: pop si call say#endif seg es cmp word (di),#0 je install_ret ; nothing to doCOUNT = DRVMAP_SIZE*2 mov cx,#COUNT ; count of words sub sp,#COUNT*2 ; now allocate words mov si,di ; ES:SI is now source mov di,sp ; SS:DI is now destination push ds push es pop ds push ss pop esinstall_move1: lodsw ; get part of a map stosw ; store it or ax,ax ; test for null jz install_done1 loop install_move1 jmp fatalinstall_done1: ; the map is at SS:SP pop ds#ifdef DEBUG_NEW mov bx,sp ; ES==SS call dump_drvmap#endif call is_prev_mapper ; is there a previous drive swapper ; sets ES:DI jnz install_skip call swap13_null ; install a new, null drive mapper ; sets ES:DI to point at drvmap in swapper ; which must be NULL terminatedinstall_skip: mov si,sp ; SS:SI is place to do the map merge push ss pop ds ; DS:SI is primary map mov bx,si ; DS:BX receives the new map ; and ES:DI points at the existing map call drive_map_merge#ifdef DEBUG_NEW mov bx,sp push es push ss pop es call dump_drvmap pop es#endif mov si,sp ; DS:SI is the source mov cx,#COUNT rep movsw push cs pop ds ; restore the DSinstall_ret: mov sp,bp ; get ready for pop popa pop es retfatal: hlt jmp fatal#ifdef DEBUG_NEWwout: push ax xchg ah,al call bout ! write hi-byte pop axbout: push ax ! save byte shr al,#4 ! display upper nibble call nout pop axnout: and al,#0x0F ! lower nible only daa ! smaller conversion routine add al,#0xF0 adc al,#0x40 ! AL is hex char [0..9A..F]cout: push bx mov ah,#14 ! display, tty-style mov bx,#0007 int 0x10 pop bx retmsg_new: .ascii "Found v.22 drive swapper" .byte 13,10,0msg_old: .ascii "Found v.21 drive swapper" .byte 13,10,0msg_swap13: .ascii "Drive Mapping" .byte 13,10,0msg_load: .ascii " - PT loaded" .byte 13,10,0msg_write: .ascii " - PT written" .byte 13,10,0no_update: .ascii "NO "update: .ascii "24-25 update has occurred"crlf: .byte 13,10,0#ifdef DEBUG_CONTINUEmsg_cont: .ascii "\r\nHit any key to continue ..." .byte 0#endif#endif /* DEBUG_NEW */#if 0/* LILO version 21 (and maybe earlier) drive map header signature code */new13_old: push ax ! save AX (contains function code in AH) push bp ! need BP to mess with stack mov bp,sp pushf ! push flags (to act like interrupt) push si mov si,#drvmap-new13new13_old_drvmap_offs = * - new13_old - 2new13_old_length = new13_old_drvmap_offsnew13_old_min_offs = 0x46 ; min seen in old code is 0x49new13_old_max_offs = 0x50 ; maxed out at 21.7.5 at 0x4d#endif#ifdef DEBUG_NEW; dump the drive map pointed to by ES:BX; Beware: DS != CS on some calls;dump_drvmap: pusha push ds push cs pop dssw13b: seg es mov ax,(bx) ; get drvmap entry or ax,ax jz sw13z call bout mov si,#sw13p inc bx call say seg es mov al,(bx) call bout inc bx mov si,#crlf call say jmp sw13bsw13z: mov si,#msg_swap13 call say pop ds popa retsw13p: .asciz " -> "#endif#define CHAIN_LOADER#include "mapper.S"NEW13B = drvmap-new13#if defined(LCF_REWRITE_TABLE)prtmap: .blkw PRTMAP_SIZE*2+1 ! only first word of last entry is read#endif#ifdef CHAIN .org *+4#endiftheend:#ifdef CHAINthe_end1 = theend+511theends = the_end1/512 .org theends*512-4 .long CHAIN ! boot signature check#endif .align 512boot_sector:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -