📄 first-dos.s
字号:
movsb ; check sti; Output some debugging messages by simply calling the interrupt vectors; which we just created.#ifdef DRV_DEBUG mov ax,CON(0x4A06) int 0x2F mov si,CON(consz) call prnstr ; print out amount of conventional mov ax,dx ; memory mov cl,CON(12) shr ax,cl call prnwrd mov ax,dx mov cl,CON(4) shl ax,cl call prnwrd mov si,CON(bytes) call prnstr mov ax,CON(0x8800) int 0x15 push ax mov si,CON(extsz) call prnstr ; print out amount of extended memory mov cl,CON(6) shr ax,cl call prnwrd pop ax mov cl,CON(10) shl ax,cl call prnwrd mov si,CON(bytes) call prnstr#endif#ifndef FREEDOS; The boot sector had to be placed into a temporary memory area to; avoid overwriting any bootrom structures. However, a call back; to the bootrom is no longer possible, so we can move the bootblock; where it belongs. push ds mov ax,CON(TEMP_SEGMENT) mov ds,ax xor ax,ax mov es,ax xor si,si mov di,CON(BOOT_OFFSET) mov cx,CON(SECT_SIZE) rep movsb ; move it pop ds; Finally call the boot sector#else; Finally call kernel.sys#endif /* FREEDOS */#ifdef ASM_DEBUG mov si,CON(debug2) call prnstr#endif#ifdef FREEDOS mov bl,LOC(drvid) ; FreeDOS gets boot drive from bl, 0=A#else mov dl,LOC(drvid) ; boot block may expect this#endif#ifdef ASM_FREEZE_AFTER_INITlop: JMP(lop)#else#ifdef FREEDOS jmp FDKSEG:0 ; FreeDOS kernel.sys entry point#else jmp 0:BOOT_OFFSET#endif /* FREEDOS */#endif;====================================================================;; Setup DOS drive parameter block (DPB) for floppy disk drive. The; DPB is required to activate the floppy disk drive after the ramdisk; has been turned off.; Input: none; Output: none; Registers changed: AX, BX, CX, DXsetdpb: push es push si push di mov dl,LOC(drvid) cmp dl,CON(0x80) ; can only restore floppy drives jae setdp8; First get the drive parameters from the BIOS mov LOC(dpb_phys),dl ; set physical drive ID mov ah,CON(0x08) ; get drive parameters from BIOS int 0x13 jc setdp8 xor ah,ah mov al,ch ; set max number of cylinders inc ax mov LOC(dpb_cyls),ax mov si,CON(dpb_bpb_cur) mov al,cl ; set max number of sectors per track mov [si+BPB_SPT],ax mov al,dh inc ax ; set max number of heads mov [si+BPB_HEADS],ax; Determine DOS disk parameters by drive type cmp bl,CON(5) jb setdp1 ; check for invalid drive type mov bl,CON(4)setdp1: xor bh,bh dec bx push bx shl bx,CON(1) shl bx,CON(1) ; compute address into drive para- add bx,CON(drvtab) ; meter table xor ah,ah mov al,[bx+0] ; get # of entries in root dir mov [si+BPB_DIR],al mov al,[bx+1] ; get # of sectors per FAT mov [si+BPB_SPF],ax mov al,[bx+2] ; get # of sectors per cluster mov [si+BPB_SPC],al mov al,[bx+3] ; get media ID mov [si+BPB_MEDIA_ID],al pop bx mov al,[bx+typtab] ; get drive type mov LOC(dpb_type),al; Determine number of bytes per sector SEGES mov cl,[di+3] ; get shift value from BIOS media mov ax,CON(128) ; parameter table shl ax,cl ; shift base value mov [si+BPB_BPS],ax JMP(setdp4)setdp8: JMP(setdp9) ; needed for short jumps; Determine total number of sectorssetdp4: mov ax,[si+BPB_SPT] mul WLOC(dpb_cyls) or dx,dx ; should not overflow jnz setdp8#ifdef USE_AS86 cmp [si+BPB_HEADS],BCON(2)#endif#ifdef USE_NASM cmp word [si+BPB_HEADS],BCON(2)#endif jb setdp3 shl ax,CON(1) jc setdp8setdp3: mov [si+BPB_TOT_SECTS],ax; Determine if the drive can detect disk changes mov ah,CON(0x15) mov dl,LOC(drvid) int 0x13 ; get DASD type from BIOS mov bl,ah mov ax,CON(DPB_F_DEFAULT) jc setdp2 cmp bl,CON(0x02) ; check if drive detects disk changes jne setdp2 or ax,CON(DPB_F_DOOR)setdp2: mov LOC(dpb_flags),ax ; set flags; Thats it inc BLOC(dpb_valid) ; increment valid flagsetdp9: pop di pop si pop es ret;====================================================================;; Find a load record in the boot header. The ID number of the load; record is in AL, and ES:DI points to requested load record, or is; the NULL pointer if load record not found.;; Changed registers: AX, DI, ESfndldr: push cx mov ch,al les di,LOC(header) ; examine boot image header SEGES mov al,[di+BOOT_HD_LENGTH] ; get length of image header call getlen add di,ax ; get the pointer to first load recordfndl1: SEGES cmp ch,[di+BOOT_LD_TAG1] ; is it the desired one ? je fndl3 SEGES mov al,[di+BOOT_LD_FLAGS] ; no, so check if its the last record test al,CON(BOOT_FLAG_EOF) jnz fndl2 SEGES mov al,[di+BOOT_LD_LENGTH] ; no, get the address of the next one call getlen add di,ax JMP(fndl1)fndl2: xor ax,ax ; couldnt find the desired record mov es,ax mov di,axfndl3: pop cx ret;====================================================================;; Compute the length of a load record address from a length byte; in AL. Return the offset in AX.;; Changed registers: AXgetlen: push cx mov ah,al mov cl,CON(4) shr ah,cl and ax,CON(0x0f0f) ; compute the total length in add al,ah ; bytes from the length of the xor ah,ah ; record and that of the vendor shl ax,1 ; information. shl ax,1 pop cx ret;====================================================================; Print a string in DS:SI onto the console;; Changed registers: ALprnstr: push si cldprns1: lodsb ; loop over all characters of or al,al ; string jz prns2 push bx mov ah,CON(0x0E) ; print it mov bl,CON(0x07) xor bh,bh int 0x10 pop bx JMP(prns1)prns2: pop si ret#ifdef DRV_DEBUG;====================================================================;; Print hexadecimal values (in AX or AL) or characters onto the console;; Changed registers: AXprnwrd: push ax mov al,ah call prnbyt ; print the upper byte pop axprnbyt: push ax shr al,1 ; prepare upper nibble shr al,1 shr al,1 shr al,1 call prnnib ; print it pop axprnnib: and al,CON(0x0F) ; prepare lower nibble add al,CON(0x30) cmp al,CON(0x39) ; convert it into hex jle prnchr add al,CON(7)prnchr: push bx mov ah,CON(0x0E) ; print it mov bl,CON(0x07) xor bh,bh int 0x10 pop bx ret#endif;====================================================================;; String and constants definitions; Startup signaturesigmsg: db 0x0D, 0x0A STRDECL('DOS Net Boot Image Loader ') STRDECL(VERSION) db ' ' STRDECL(VENDOR_MAGIC) db 0x0D, 0x0A STRDECL(COPYRIGHT) db 0x0D, 0x0Acrlf: db 0x0D, 0x0A db 0; Magic numbers for boot record and bootp entrybmagic: dd BOOT_MAGIC ; boot image magic numbervmagic: STRDECL(VENDOR_MAGIC) ; vendor magic ID db 0 ; end of vendor magic IDpmagic: db BOOTP_MAGIC_RFC ; bootp magic ID for RFC 1048 db BOOTP_MAGIC_CMU ; bootp magic ID for CMU db BOOTP_MAGIC_STA ; bootp magic ID for Stanford db 0; Specifications for different types of disk drives. The order is:; # dir entries, # sects per FAT, # sects per cluster, media IDdrvtab: db 112, 2, 2, 0xfd ; 360kB disk db 224, 7, 1, 0xf9 ; 1.2MB disk db 112, 3, 2, 0xf9 ; 720kB disk db 224, 9, 1, 0xf0 ; 1.44 MB disktyptab: db DPB_T_360 ; type values for drive parameter block db DPB_T_1200 db DPB_T_720 db DPB_T_1440; Error messagesrecerr: STRDECL('Error in load record data') db 0x0D, 0x0A db 0bmerr: STRDECL('Invalid boot header magic number') db 0x0D, 0x0A db 0vmerr: STRDECL('Invalid vendor magic ID') db 0x0D, 0x0A db 0rderr: STRDECL('Error while accessing ramdisk') db 0x0D, 0x0A db 0dskerr: STRDECL('Wrong ramdisk image') db 0x0D, 0x0A db 0btperr: STRDECL('BOOTP record invalid') db 0x0D, 0x0A db 0; Debug messages#ifdef ASM_DEBUGdebug1: STRDECL('Making driver resident') db 0x0D, 0x0A db 0debug2:#ifdef ASM_FREEZE_AFTER_INIT STRDECL('Freezing;')#else STRDECL('Calling boot block')#endif db 0x0D, 0x0A db 0#endif#ifdef DRV_DEBUGconsz: STRDECL('RAMDISK: reporting conventional memory size: ') db 0extsz: STRDECL('RAMDISK: reporting extended memory size: ') db 0bytes: STRDECL(' bytes') db 0x0D,0x0A db 0#endif;====================================================================;; Variable definitionsheader: dd 0 ; pointer to boot header from boot rombootp: dd 0 ; pointer to bootp block from boot romresseg: dw 0 ; segment of resident sectionoldDS: dw 0 ; old DS from boot romoldES: dw 0 ; old ES from boot romoldBP: dw 0 ; old BP from boot romoldSI: dw 0 ; old SI from boot romoldDI: dw 0 ; old DI from boot rom;====================================================================;; Start of resident section. This will be placed at the end of the; low 640kB RAM area.;;====================================================================; ALIGN(16) ; has to be paragraph alignedstart_resident: ; indicate start of resident section;====================================================================;; New interrupt 2Fh routine. This routine gets called by IO.SYS; in order to determine the maximum amount of memory usable to; DOS. This only works with DOS versions 5.0 and higher. The DOS; function which gets installed into the interrupt 2Fh vector; does not call the old vector (i.e. it does not daisy-chain),; and therefore we can redirect 2Fh without a problem even when; considering to remove the ram disk lateron.;; NOTE THAT THIS INTERRUPT HAS TO BE THE FIRST ROUTINE IN THE; RESIDENT SECTION!;; Input: AX - Magic ID; DX - segment following last usable byte; Output: DX - new segment following last usable byte; Registers changed: DXint2F: JMP(int2F1) ; this has to be a relative jump nop STRDECL('RPL') ; magic ID string for DOSint2F1: cmp ax,CON(0x4A06) ; check for magic ID jne int2F9 push cx mov dx,CON(start_resident) ; determine last usable segment mov cl,CON(4) ; from segment and offset of shr dx,cl ; the resident section pop cx push ax push cs pop ax add dx,ax ; add offset to segment dec dx pop ax iretint2F9: SEGCS jmp far [old2Fh] ; jump to old interrupt routine;====================================================================;; New interrupt F8h routine. It can be used to retrieve several; values from the resident driver.; Input: AX - function code; Output: depends on function:;; Installation check (AX = 0x9C00); AX - contains 0x009C;; Return ramdisk size and address (AX = 0x9C01); BX:DX - address of ramdisk; CX - size of ramdisk in kb;; Return size and address of BOOTP block (AX = 0x9C02); BX:DX - address of BOOTP block; CX - size of BOOTP block;; Return miscellaneous values for handling the ramdisk (AX = 0x9C03); AX - XMS handle for ram disk; BX:DX - address of old interrupt vector table; CL - ramdisk id;; Remove ramdisk (AX = 0x9C04); AL - non-zero if error;; Registers changed: depends on functionintF8: cmp ah,CON(0x9C) ; check for magic ID jne intF89 cmp al,CON(01) ; check for function number jne intF81 SEGCS mov bx,LOC(rdaddr+2) ; return ramdisk address SEGCS mov dx,LOC(rdaddr+0) SEGCS mov cx,LOC(rdsize) ; return ramdisk size iretintF81: cmp al,CON(0x02) jne intF82
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -