📄 first-dos.s
字号:
; first.S - primary boot loader for DOS;; Copyright (C) 1996-1998 Gero Kuhlmann <gero@gkminix.han.de>; Modifications for booting FreeDOS by Ken Yap <ken_yap@users.sourceforge.net>;; 2003.04.28 Robb Main; Tweaks & bugfixes to allow use with much larger disk images, remove; '2 head assumption', use 32-bit GDT, and other 'stuff'.;; This program is free software; you can redistribute it and/or modify; it under the terms of the GNU General Public License as published by; the Free Software Foundation; either version 2 of the License, or; any later version.;; This program is distributed in the hope that it will be useful,; but WITHOUT ANY WARRANTY; without even the implied warranty of; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the; GNU General Public License for more details.;; You should have received a copy of the GNU General Public License; along with this program; if not, write to the Free Software; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.#if !defined(USE_NASM) && !defined(USE_AS86)#define USE_AS86#endif#ifdef USE_AS86#define CON(x) *x#define BCON(x) *x#define LOC(x) x#define BLOC(x) byte ptr x#define WLOC(x) word ptr x#define JMP(x) jmp x#define STRDECL(s) .ascii s#define SEGCS seg cs#define SEGES seg es#define ALIGN(x) .align x#define SPACE(x) .space x#endif#ifdef USE_NASM#define CON(x) x#define BCON(x) byte x#define LOC(x) [x]#define BLOC(x) byte [x]#define WLOC(x) word [x]#define JMP(x) jmp short x#define STRDECL(s) db s#define SEGCS cs#define SEGES es#define ALIGN(x) align x, db 0#define SPACE(x) times x db 0#endif#ifndef ASM_DEBUG#undef ASM_DEBUG#endif#include "first-dos.h"#include "version-dos.h"#ifdef USE_AS86 .text .org 0#endif#ifdef USE_NASM text#endif_start: mov dx,ds mov ax,cs ; set DS mov ds,ax mov LOC(oldES),es mov LOC(oldDS),dx ; save old register values in case mov LOC(oldBP),bp ; we have to return to the boot rom mov LOC(oldSI),si mov LOC(oldDI),di mov bp,sp mov ax,[bp+4] mov LOC(header+0),ax ; load the address of the boot header mov ax,[bp+6] mov LOC(header+2),ax mov ax,[bp+8] mov LOC(bootp+0),ax ; load the address of the bootp block mov ax,[bp+10] mov LOC(bootp+2),ax; Tell the user who we are and that we started running mov si,CON(sigmsg) call prnstr; Check if the boot image header is correct. les bx,LOC(header) mov si,CON(bmerr) ; prepare for correct error message SEGES mov ax,[bx+BOOT_HD_MAGIC+0] cmp ax,LOC(bmagic+0) ; compare boot rom magic numbers jne doerr1 SEGES mov ax,[bx+BOOT_HD_MAGIC+2] cmp ax,LOC(bmagic+2) jne doerr1 mov si,CON(vmerr) ; prepare for correct error message SEGES mov al,[bx+BOOT_HD_LENGTH] mov cl,CON(4) shr al,cl and al,CON(0x0F) cmp al,CON(VENDOR_SIZE) ; check vendor ID size jne doerr1 xor di,didovmag: mov al,[di+vmagic] ; check vendor ID or al,al jz getrd ; vendor ID ok, continue SEGES cmp al,[bx+di+BOOT_HD_VENDOR] jne doerr1 inc di JMP(dovmag)doerr1: call prnstr ; in case of error return to the mov si,LOC(oldSI) ; boot rom with registers set mov di,LOC(oldDI) ; correctly mov bp,LOC(oldBP) mov es,LOC(oldES) mov ds,LOC(oldDS) retf; Next get the address of the ramdisk and its size.getrd: mov si,CON(recerr) mov al,CON(VENDOR_RAMDISK) call fndldr ; find load record for ramdisk mov ax,es or ax,di jz doerr1 SEGES mov al,[di+BOOT_LD_FLAGS] ; get load record flags test al,CON(BOOT_FLAG_B0 + BOOT_FLAG_B1) ; check that it has a jnz doerr1 ; correct flag SEGES mov ax,[di+BOOT_LD_ADDR+0] ; get base adress of ramdisk SEGES mov bx,[di+BOOT_LD_ADDR+2] mov LOC(rdaddr+0),ax mov LOC(rdaddr+2),bx SEGES mov ax,[di+BOOT_LD_MLENGTH+0] ; get ramdisk size SEGES mov bx,[di+BOOT_LD_MLENGTH+2] add ax,CON(0x03ff) ; round to nearest kb adc bx,BCON(0) mov cl,CON(10) shr ax,cl ; convert into kb mov cl,CON(6) shl bx,cl or ax,bx mov LOC(rdsize),ax; Get the disk geometry out of the vendor information block in the; load record SEGES mov bl,[di+BOOT_LD_LENGTH] and bl,CON(0x0f) xor bh,bh ; compute pointer to shl bx,CON(1) ; vendor block shl bx,CON(1) SEGES mov ax,[di+bx+BOOT_LD_SECNUM] ; get number of sectors mov LOC(secnumlo),ax SEGES mov ax,[di+bx+BOOT_LD_SECNUM+2] ; get number of sectors mov LOC(secnumhi),ax SEGES mov ax,[di+bx+BOOT_LD_HEADS] ; get head count mov LOC(heads),al SEGES mov ax,[di+bx+BOOT_LD_SPT] ; get sectors per track mov LOC(secptk),al SEGES mov ax,[di+bx+BOOT_LD_CYL] ; get number of cylinders mov LOC(cylnum),ax SEGES mov al,[di+bx+BOOT_LD_NOHD] ; get no-hard-disk flag mov LOC(nohd),al SEGES mov al,[di+bx+BOOT_LD_DRIVE] ; get ram disk drive id mov LOC(drvid),al; Set the address of the BIOS disk status byte mov bx,CON(BIOS_FDSTAT) cmp al,CON(0x80) jb setsts mov bx,CON(BIOS_HDSTAT)setsts: mov LOC(statof),bx; Get system configuration from BIOS push ax int 0x11 mov LOC(syscnf),ax pop ax; Get the number of floppy or hard disk drives in the system and set; the DOS disk parameter block cmp al,BCON(0x80) jae getnm2 mov ah,CON(0x08) xor dl,dl int 0x13 ; get the number of floppy disk jc getnm1 ; drives from the BIOS or dl,dl jnz gotnum inc dl ; indicate at least one drive JMP(gotnum)getnm1: mov dx,LOC(syscnf) ; if int 13h didnt work try it with test dl,CON(0x01) ; the mainboard dip switch config jz getnm3 mov cl,CON(6) shr dl,cl and dl,CON(0x03) ; determine number of floppy disk inc dl ; drives JMP(gotnum)getnm2: mov ah,CON(0x08) mov dl,CON(0x80) int 0x13 ; get the number of hard disk jc getnm3 ; drives from the BIOS inc dl JMP(gotnum); The next line was mov dl,1 in netboot-0.8.1. This was probably an error.getnm3: mov dl,CON(1) ; we have at least one drivegotnum: mov LOC(drvnum),dl ; save number of disk drives call setdpb ; set disk parameter block; Now get the boot sector of the ramdisk and check that its correct. If; we are simulating a hard disk the boot sector contains the partition; table, which we have to analyze. Then load the partitions boot sector. mov ax,CON(TEMP_SEGMENT) mov es,ax ; pointer to temporary buffer xor bx,bx xor dx,dx ; first sector xor ax,ax xor ch,ch ; indicate read mov cl,1 ; one sector call rwsect ; read boot sector mov si,CON(rderr) jc doerr2 cmp BLOC(drvid),CON(0x80) ; if the ram disk is simulates a jb chkbot ; floppy, there is no partition table mov si,CON(dskerr) ; prepare for correct error message SEGES cmp BLOC(PART_STATUS),CON(PART_ACTIVE) jne doerr2 SEGES cmp BLOC(PART_TYPE),CON(PART_FAT16) je partok SEGES cmp BLOC(PART_TYPE),CON(PART_FAT12) jne doerr2partok: SEGES mov dx,[PART_ABS_SECT+2] ; get number of first sector SEGES mov ax,[PART_ABS_SECT+0] xor ch,ch ; indicate read mov cl,1 ; one sector call rwsect ; read boot sector mov si,CON(rderr) jc doerr2#ifndef HD_PARM_CHECK JMP(dobotp)#endifchkbot: mov si,CON(dskerr) ; prepare for correct error message mov al,LOC(drvid) SEGES cmp BLOC(DISK_BOOT),al ; check boot disk number jne doerr2 SEGES cmp WLOC(DISK_BPS),CON(SECT_SIZE) ; check sector size jne doerr2 SEGES cmp WLOC(DISK_HEADS),BCON(16) ; check number of heads jg doerr2 SEGES mov ax,LOC(DISK_SPT) ; check number of sectors per track cmp al,LOC(secptk) je dobotpdoerr2: call prnstr ; in case of error return to the#if 1 push ax mov ah,0 ; wait for a keypress, so user int 0x16 ; can read the error message pop ax#endif mov si,LOC(oldSI) ; boot rom with registers set mov di,LOC(oldDI) ; correctly mov bp,LOC(oldBP) mov es,LOC(oldES) mov ds,LOC(oldDS) retf; Save the BOOTP record for later retrieval by a DOS program.dobotp: cld xor dx,dx les di,LOC(bootp) mov ax,es or ax,di jz dobot9 SEGES mov al,[di+BOOTP_OP] ; op code must indicate reply cmp al,CON(BOOTP_REPLY) jne dobot9 ; it isnt add di,CON(BOOTP_VEND) mov bx,di mov si,CON(pmagic) ; compare vendor IDdobot1: mov di,bx mov cx,CON(BOOTP_MAGIC_LEN) repe cmpsb jz dobot2 ; vendor ID is valid add si,cx#ifdef USE_AS86 cmp byte ptr[si],CON(0) ; check next vendor ID#endif#ifdef USE_NASM cmp byte [si],CON(0) ; check next vendor ID#endif jne dobot1dobot9: JMP(nobot2) ; vendor ID not founddoerr6: JMP(doerr2)dobot2: sub si,BCON(BOOTP_MAGIC_LEN) sub si,CON(pmagic) mov ax,si push ds mov bx,ds mov es,bx mov di,CON(btpnew) lds si,LOC(bootp) mov bx,si mov dx,CON(BOOTP_SIZE) or ax,ax ; if not RFC vendor ID the bootp jnz dobot7 ; record has fixed length xor cx,cx add si,CON(BOOTP_VEND + BOOTP_MAGIC_LEN)dobot3: lodsb cmp al,CON(BOOTP_RFC_NOP) ; handle NOP tag jnz dobot4 inc cx cmp cx,BCON(16) ; more than 16 NOP tags is VERY unusual jae dobot7 ; so the bootp record maybe broken JMP(dobot3) ; loop to next tagnobot2: JMP(nobotp)dobot4: cmp al,CON(BOOTP_RFC_END) ; handle END tag jnz dobot6 mov dx,si sub dx,bx ; compute length of bootp record cmp dx,CON(BOOTP_SIZE) jae dobot7 mov dx,CON(BOOTP_SIZE) ; use minimum size JMP(dobot7)dobot6: lodsb ; handle all other tags mov cl,al xor ch,ch add si,cx ; jump to next tag xor cx,cx ; reset NOP counter JMP(dobot3) ; proceed with next tagdobot7: mov si,CON(btperr) mov ax,CON(btpnew) ; bootp record cannot be larger add ax,dx ; than the current segment jc doerr6 mov cx,dx mov si,bx ; restore source pointer rep movsb ; save the bootp record pop dsnobotp: mov LOC(btplen),dx ; set length of bootp record; Everything is right, so we can now move the resident section to the; end of the conventional memory, thus overwriting the bootrom data; area. Therefore there is no chance of returning to the bootrom from; now on.; Note that the resident section doesnt start at offset 0, so we have; to set the segment address to somewhere lower.#ifdef ASM_DEBUG mov si,CON(debug1) call prnstr#endif cli mov ax,CON(TEMP_SEGMENT) ; set new stack mov ss,ax mov sp,CON(0xFFF0) cld int 0x12 ; get memory size in kB#ifdef FREEDOS push ax ; save mem size in kB#endif /* FREEDOS */ mov cl,CON(6) shl ax,cl ; compute last usable segment mov bx,CON(btpnew) add bx,LOC(btplen) mov dx,bx mov cl,CON(4) shr bx,cl ; compute size of code segment in inc bx ; paragraphs#ifdef FREEDOS push bx ; save size in paragraphs#endif /* FREEDOS */ sub ax,bx ; compute new code segment mov LOC(resseg),ax mov es,ax ; set source and destination ptrs mov si,CON(start_resident) mov di,si mov cx,dx sub cx,si ; compute size of resident area rep movsb ; move it#ifdef FREEDOS; New code for FreeDOS, adjust the value of the top of memory returned by; int 0x12. Currently there is no code to restore the original size pop bx ; restore size in paragraphs add bx,BCON(63) ; round up to next kB mov cl,CON(6) ; divide by 64 shr bx,cl pop ax ; restore size in kB sub ax,bx mov bx,CON(0x40) mov es,bx SEGES mov LOC(0x13),ax ; store at 0x40:0x13 for int 12h; End of new code#endif /* FREEDOS */; Setup all interrupt vectors mov bx,LOC(resseg) push ds mov ds,bx xor ax,ax mov es,ax SEGES mov ax,LOC(I13_INT+0) mov LOC(old13h+0),ax SEGES mov ax,LOC(I13_INT+2) mov LOC(old13h+2),ax SEGES mov ax,LOC(I2F_INT+0) mov LOC(old2Fh+0),ax SEGES mov ax,LOC(I2F_INT+2) mov LOC(old2Fh+2),ax SEGES mov ax,LOC(IF1_INT+0) mov LOC(oldF1h+0),ax SEGES mov ax,LOC(IF1_INT+2) mov LOC(oldF1h+2),ax SEGES mov ax,LOC(IF8_INT+0) mov LOC(oldF8h+0),ax SEGES mov ax,LOC(IF8_INT+2) mov LOC(oldF8h+2),ax pop ds SEGES mov LOC(I13_INT+2),bx ; interrupt vector 13h SEGES mov WLOC(I13_INT+0),CON(int13) SEGES mov LOC(I2F_INT+2),bx ; interrupt vector 2Fh SEGES mov WLOC(I2F_INT+0),CON(int2F) SEGES mov LOC(IF8_INT+2),bx ; interrupt vector F8h SEGES mov WLOC(IF8_INT+0),CON(intF8) mov di,CON(IF1_INT) mov si,CON(if1sig) ; interrupt vector F1h mov cx,CON(4) ; contains the string "NetB" rep ; to provide as an installation
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -