From 2d04cacc5322951f187bb17e017c12920ac8ebe2 Mon Sep 17 00:00:00 2001 From: Mark Zbikowski Date: Thu, 25 Apr 2024 21:24:10 +0100 Subject: MZ is back! --- v4.0/src/BIOS/MSLOAD.ASM | 1090 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1090 insertions(+) create mode 100644 v4.0/src/BIOS/MSLOAD.ASM (limited to 'v4.0/src/BIOS/MSLOAD.ASM') diff --git a/v4.0/src/BIOS/MSLOAD.ASM b/v4.0/src/BIOS/MSLOAD.ASM new file mode 100644 index 0000000..859a318 --- /dev/null +++ b/v4.0/src/BIOS/MSLOAD.ASM @@ -0,0 +1,1090 @@ + +page ,132; +title Non-Contiguous IBMBIO Loader (MSLOAD) +;============================================================================== +;REVISION HISTORY: +;AN000 - New for DOS Version 4.00 - J.K. +;AC000 - Changed for DOS Version 4.00 - J.K. +;AN00x - PTMs for DOS Version 4.00 - J.K. +;============================================================================== +;AN001; - P1820 New Message SKL file 10/20/87 J.K. +;AN002; - D381 For SYS.COM, put the version number 01/06/88 J.K. +;============================================================================== +;JK, 1987 - +; For DOS 4.00, MSLOAD program has been changed to allow: +; 1. 32 bit calculation, +; 2. Reading a FAT sector when needed, instead of reading the whole FAT +; sectors at once. This will make the Boot time faster, and eliminate +; the memory size limitation problem, +; 3. Solving the limitation of the file size (29 KB) of IBMBIO.COM, +; 4. Adding the boot error message. Show the same boot error message +; and do the same behavior when the read operation of IBMBIO.COM +; failes as the MSBOOT program, since MSLOAD program is the +; extention of MSBOOT program. +; + +IF1 + %OUT ASSEMBLING: Non-Contiguous IBMBIO Loader (MSLOAD) + %OUT + +ENDIF + + +DSKADR = 1Eh * 4 ;ROM bios diskette table vector position + +bootseg segment at 0h + + + org 7C00h +Boot_Sector label byte +bootseg ends + + +dosloadseg segment at 70h + org 00h +IBMBIO_Address label byte + +dosloadseg ends + + +cseg segment public para 'code' + assume cs:cseg,ds:nothing,es:nothing,ss:nothing + +include MSload.inc +include Bootform.inc ;AN000; Extended bpb, boot record defintion. +include versiona.inc ;AN001; Version number for SYS.COM + +sec9 equ 522h ;;** 8/3/87 DCL + +BIOOFF equ 700h +; +org 0h + +start: + jmp Save_Input_Values +SYS_Version dw EXPECTED_VERSION ;AN001; From VERSIONA.INC file +Mystacks dw 64 dup (0) ;AN000; local stack +MyStack_ptr label word + +;local data +Number_Of_Heads dw 0 +Size_Cluster dw 0 +Start_Sector_L dw 0 +Start_Sector_H dw 0 ;J.K. +Temp_H dw 0 ;J.K. For 32 bit calculation +Temp_Cluster dw 0 ;J.K. Temporary place for cluster number +Last_Fat_SecNum dw -1 ;Fat sector number starting from the first fat entry. +Sector_Count dw 0 +Number_Of_FAT_Sectors dw 0 +Hidden_Sectors_L dw 0 +Hidden_Sectors_H dw 0 ;J.K. +Sector_Size dw 0 +Reserved_Sectors dw 0 +Last_Found_Cluster dw 0 +Next_BIO_Location dw 0 +First_Sector_L dw 0 +First_Sector_H dw 0 ;J.K. +Drive_Lim_L dw 0 ;J.K. Max. number of sectors +Drive_Lim_H dw 0 ;J.K. +Sectors_Per_Track dw 0 +Drive_Number db 0 +FAT_Size db 0 +Media_Byte db 0 +EOF db 0 +Org_Rom_Disktable dd 0 +FAT_Segment dw 0 +Sectors_Per_Cluster db 0 + +subttl Save Input Values +page +;*********************************************************************** +; Save_Input_Values +;*********************************************************************** +; +; Input: none +; +; DL = INT 13 drive number we booted from +; CH = media byte +; BX = First data sector (low) on disk (0-based) +; DS:SI = Original ROM BIOS DISKETTE Parameter table. +;J.K. 6/2/87 If an extended Boot Record, then AX will be the First data sector +;J.K. high word. Save AX and set First_Sector_H according to AX if it is an +;J.K. extended boot record. +; AX = First data sector (High) on disk ; +; Output: +; +; BX = first data sector on disk +; +; Media_Byte = input CH +; Drive_Number = input DL +; First_Sector_L = input BX +; First_Sector_H = input AX, if an extended Boot record.;J.K. +; Drive_Lim_L = maximum sector number in this media ;J.K. +; Drive_Lim_H = high word of the above +; Hidden_Sectors_L = hidden secotrs +; Hidden_Sectors_H +; Reserved_Sectors = reserved sectors +; Sectors_Per_Track = Sectors/track +; Number_Of_Heads = heads/cylinder +; +; DS = 0 +; AX,DX,SI destroyed +; +; Calls: none +;----------------------------------------------------------------------- +;Function: +; Save input information and BPB informations from the boot record. +; +;---------------------------------------------------------------------- +Save_Input_Values: + + + mov First_Sector_L,bx ;AC000; + mov media_Byte,ch + mov Drive_Number,dl + mov word ptr Org_Rom_Disktable, si + push ds + pop word ptr Org_Rom_Disktable+2 + xor cx,cx ;Segment 0 + mov ds,cx + assume ds:Bootseg + + push es ;;** DCL 8/3/87 + mov es,cx ;;** DCL 8/3/87 + assume es:Bootseg ;;** DCL 8/3/87 + + MOV SI,WORD PTR DS:DSKADR ; ARR 2.41 + MOV DS,WORD PTR DS:DSKADR+2 ; DS:SI -> CURRENT TABLE ARR 2.41 + + MOV DI,SEC9 ; ES:DI -> NEW TABLE ARR 2.41 + MOV CX,11 ; taken from ibmboot.asm ARR 2.41 + CLD ; + REP MOVSB ; COPY TABLE ARR 2.41 + PUSH ES ; ARR 2.41 + POP DS ; DS = 0 ARR 2.41 + + MOV WORD PTR DS:DSKADR,SEC9 ; ARR 2.41 + MOV WORD PTR DS:DSKADR+2,DS ; POINT DISK PARM VECTOR TO NEW TABLE + pop es ;;** DCL 8/3/87 + assume es:nothing + + mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_BYTESPERSECTOR ;AN000; + mov cs:Sector_Size, cx ;AN000; + mov cl,Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERCLUSTER ;AN000; + mov cs:Sectors_Per_Cluster, cl ;AN000; + mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERTRACK ;Get Sectors per track + mov cs:Sectors_Per_Track,cx + mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_HEADS ;Get BPB heads per cylinder + mov cs:Number_Of_Heads,cx + mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERFAT ;Get sectors per FAT + mov cs:Number_Of_FAT_Sectors,cx + mov cx,Boot_Sector.EXT_BOOT_BPB.EBPB_RESERVEDSECTORS ;Get Reserved Sectors + mov cs:Reserved_Sectors,cx + mov cx,word ptr Boot_Sector.EXT_BOOT_BPB.EBPB_HIDDENSECTOR ;Get hidden sectors + mov cs:Hidden_Sectors_L,cx + mov cx, Boot_Sector.EXT_BOOT_BPB.EBPB_TOTALSECTORS ;AN000; + mov cs:Drive_Lim_L, cx ;AN000; + +;J.K. First of all, check if it the boot record is an extended one. +;J.K. This is just a safe guard in case some user just "copy" the 4.00 IBMBIO.COM +;J.K. to a media with a conventional boot record. + + cmp Boot_Sector.EXT_BOOT_SIG, EXT_BOOT_SIGNATURE ;AN000; + jne Relocate ;AN000; + mov cs:First_Sector_H, AX ;AN000; start data sector (high) + mov ax,word ptr Boot_Sector.EXT_BOOT_BPB.EBPB_HIDDENSECTOR+2 ;AN000; + mov cs:Hidden_Sectors_H,ax ;AN000; + cmp cx, 0 ;AN000; CX set already before (=Totalsectors) + jne Relocate ;AN000; + mov ax, word ptr Boot_Sector.EXT_BOOT_BPB.EBPB_BIGTOTALSECTORS ;AN000; + mov cs:Drive_Lim_L, ax ;AN000; + mov ax, word ptr Boot_Sector.EXT_BOOT_BPB.EBPB_BIGTOTALSECTORS+2 ;AN000; + mov cs:Drive_Lim_H, ax ;AN000; +subttl Relocate +page +; +;*********************************************************************** +; RELOCATE +;*********************************************************************** +; +; Notes: +; +; Relocate the loader code to top-of-memory. +; +; Input: none +; +; Output: Code and data relocated. +; ax,cx,si,di destroyed +; +; Calls: none +;----------------------------------------------------------------------- +; Copy code from Start to Top of memory. +; +; The length to copy is Total_length +; +; Jump to relocated code +;----------------------------------------------------------------------- +; +Relocate: + assume ds:nothing + cld ;AN000; + xor si,si ;AN000; + mov di,si ;AN000; +;SB34LOAD000**************************************************************** +;SB Determine the number of paragraphs (16 byte blocks) of memory. +;SB This involves invoking the memory size determination interrupt, +;SB which returns the number of 1K blocks of memory, and then +;SB converting this to the number of paragraphs. +;SB Leave the number of paragraphs of memory in AX. + + int 12h ;get system memory size in Kbytes + mov cl,6 ; + shl ax,cl ;memory size in paragraphs +;SB34LOAD000**************************************************************** + mov cl,4 ;AN000; + mov dx, cs:Sector_Size ;AN000; + shr dx,cl ;AN000; + inc dx ;AN000; + sub ax, dx ;AN000; + mov cs:Fat_Segment, ax ;AN000;This will be used for FAT sector + mov dx, offset total_length ;AN000; + shr dx, cl ;AN000; + inc dx ;AN000; + sub ax, dx ;AN000; + mov es, ax ;AN000;es:di -> place be relocated. + push cs ;AN000; + pop ds ;AN000;ds:si -> source + mov cx, offset total_length ;AN000; + rep movsb ;AN000; + + push es ;AN000; + mov ax, offset Setup_stack ;AN000; + push ax ;AN000;massage stack for destination of cs:ip +Dumbbb proc far ;AN000; + ret ;AN000; +Dumbbb endp ;AN000; + + +; push cs ;Set up ds segreg +; pop ds +; xor ax,ax ;Set up ES segreg +; mov es,ax +; +; assume es:bootseg,ds:cseg +; +; mov si,offset Start ;Source +; mov di,offset Relocate_Start ;Target +; mov cx,Relocate_Length ;Length +; rep movsb ;Go do it +; jmp far ptr Relocate_Start + + + +subttl Setup Stack +page +;*********************************************************************** +; Setup_Stack +;*********************************************************************** +; +; Input: none +; +; Output: +; +; SS:SP set +; AX destroyed +;----------------------------------------------------------------------- +; First thing is to reset the stack to a better and more known place. +; +; Move the stack to just under the boot record and relocation area (0:7C00h) +; +; Preserve all other registers +;---------------------------------------------------------------------- + +Setup_Stack: + assume ds:nothing, es:nothing, ss:nothing +; CLI ;Stop interrupts till stack ok + mov ax,cs + MOV SS,AX ;Set up the stack to the known area. + mov sp, offset MyStack_Ptr +; MOV SP,7C00h - 50 ;Leave room for stack frame +; MOV BP,7C00h - 50 ;Point BP as stack index pointer +; STI + +subttl Find_Cluster_Size +page +;*********************************************************************** +; Find_Cluster_Size +;*********************************************************************** +; +; Input: BPB information in loaded boot record at 0:7C00h +; +; Output: +; +; DS = 0 +; AX = Bytes/Cluster +; BX = Sectors/Cluster +; SI destroyed +; Calls: none +;----------------------------------------------------------------------- +; +; Get Bytes/sector from BPB +; +; Get sectors/cluster from BPB +; +; Bytes/cluster = Bytes/sector * sector/cluster +;---------------------------------------------------------------------- +Find_Cluster_Size: + +;For the time being just assume the boot record is valid and the BPB +;is there. + + xor ax,ax ;Segment 0 + mov ds,ax + + assume ds:bootseg + + mov ax,Boot_Sector.EXT_BOOT_BPB.EBPB_BYTESPERSECTOR ;AC000;Get BPB bytes/sector + xor bx,bx + mov bl,Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERCLUSTER ;AC000;Get sectors/cluster + mul bx ;Bytes/cluster + mov cs:Size_Cluster,ax ;Save it + + +subttl Determine FAT size +page +;*********************************************************************** +; Determine_FAT_Size +;*********************************************************************** +; +; Notes: +; +; Determine if FAT is 12 or 16 bit FAT. 12 bit FAT if floppy, read MBR +; to find out what system id byte is. +; +; Input: +; +; Output: +; +; cs:Fat_Size = FAT12_bit or FAT16_bit +; All other registers destroyed +; +;---------------------------------------------------------------------- +Determine_FAT_Size: + mov cs:FAT_Size,FAT12_bit ;AN000;Assume 12 bit fat + mov dx, cs:Drive_Lim_H ;AN000; + mov ax, cs:Drive_Lim_L ;AN000; + sub ax, cs:Reserved_Sectors ;AN000; + sbb dx, 0 ;AN000;now, dx;ax = available total sectors + mov bx, cs:Number_Of_FAT_Sectors ;AN000; + shl bx, 1 ;AN000;2 FATs + sub ax, bx ;AN000; + sbb dx, 0 ;AN000;now, dx;ax = tatal sectors - fat sectors + mov bx, Boot_Sector.EXT_BOOT_BPB.EBPB_ROOTENTRIES ;AN000; + mov cl, 4 ;AN000; + shr bx, cl ;AN000;Sectors for dir entries = dir entries / Num_DIR_Sector + sub ax, bx ;AN000; + sbb dx, 0 ;AN000; + xor cx, cx ;AN000; + mov cl, Boot_Sector.EXT_BOOT_BPB.EBPB_SECTORSPERCLUSTER ;AN000; + push ax ;AN000; + mov ax, dx ;AN000; + xor dx, dx ;AN000; + div cx ;AN000; + mov cs:Temp_H, ax ;AN000; + pop ax ;AN000; +;J.K. We assume that cx > dx. + div cx ;AN000; + cmp ax, 4096-10 ;AN000; +; jb Determine_First_Cluster ;AN000; + jb Read_In_FirstClusters + mov cs:FAT_Size, FAT16_Bit ;AN000;16 bit fat + +; cmp cs:Media_Byte,0F8h ;Is it floppy +; jne FAT_Size_Found ;Yep, all set +; mov cs:Logical_Sector,0 ;Got hardfile, go get MBR +; xor ax,ax +; mov es,ax +; mov di,offset Relocate_Start +; mov cs:Sector_Count,1 +; call Disk_Read +; mov si,offset Relocate_Start+1C2h +; mov cx,4 +; xor ax,ax +; mov ds,ax +;Find_Sys_Id: +; mov cs:FAT_Size,FAT12_bit ;Assume 12 bit fat +; cmp byte ptr [si],1 +; je FAT_Size_Found +; mov cs:FAT_Size,FAT16_bit ;Assume 12 bit fat +; cmp byte ptr [si],4 +; je Fat_Size_Found +; add si,16 +; loop Find_Sys_Id +; ;xxxxxxxxxxxxxxxxxxxxxxxxxx error +;FAT_Size_Found: + + +subttl Read_In_FirstClusters +page +;*********************************************************************** +; Read_In_FirstClusters +;*********************************************************************** +; +; Notes: Read the start of the clusters that covers at least IBMLOADSIZE +; fully. For example, if sector/cluster = 2, and IBMLOADSIZE=3 +; then we are going to re-read the second cluster to fully cover +; MSLOAD program in the cluster boundary. +; +; Input: +; IBMLOADSIZE - Make sure this value is the same as the one in +; MSBOOT program when you build the new version!!!!! +; +; Sectors_Per_Cluster +; Size_Cluster +; First_Sector_L +; First_Sector_H +; +; Output: MSLOAD program is fully covered in a cluster boundary. +; AX = # of clusters we read in so far. +; +; Calls: Disk_Read +; Logic: +; AX; DX = IBMLOADSIZE / # of sector in a cluster. +; if DX = 0 then Ok. (MSLOAD is in a cluster boundary.) +; else (Has to read (AX+1)th cluster to cover MSLOAD) +; read (AX+1)th cluster into the address after the clusters we +; read in so far. +;----------------------------------------------------------------------- + +Read_In_FirstClusters: + mov ax, IBMLOADSIZE ;AN000; + div cs:Sectors_Per_Cluster ;AN000; + cmp ah, 0 ;AN000; + je Set_Next_Cluster_Number ;AN000; + xor ah, ah ;AN000; + push ax ;AN000; + mov cx, cs:First_Sector_L ;AN000; + mov cs:Start_Sector_L, cx ;AN000; + mov cx, cs:First_Sector_H ;AN000; + mov cs:Start_Sector_H, cx ;AN000; + mul cs:Sectors_Per_Cluster ;AN000; Now, AX=# of sectors + add cs:Start_Sector_L, ax ;AN000; + adc cs:Start_Sector_H, 0 ;AN000; + pop ax ;AN000; + push ax ;AN000; + mov di, BIOOFF ;AN000; + mul cs:Size_Cluster ;AN000;AX = # of bytes read in before this cluster + add di, ax ;AN000; + xor ax, ax ;AN000; + mov es, ax ;AN000; + mov al, cs:Sectors_Per_Cluster ;AN000; + mov cs:Sector_Count, ax ;AN000; + call Disk_Read ;AN000; + pop ax ;AN000; + inc ax ;AN000;# of clusters read in so far. + +subttl Set_Next_Cluster_Number +page +;*********************************************************************** +; Set_Next_Cluster_Number +;*********************************************************************** +; +; Notes: Set LAST_Found_Cluster for the next use. +; Last_Found_Cluster is the cluster number we are in now. +; Since cluster number is 0 based and there are 2 clusters int +; the beginning of FAT table used by the system, we just add +; 1 to set Last_Found_Cluster. +; +; Input: +; AX = # of clusters read in so far. +; +; Output: +; +; cs:Last_Found_Cluster +; +; Calls: none +;------------------------------------------------------------------ +Set_Next_Cluster_Number: + inc ax ;AN000; For Last_Found_Cluster + mov cs:Last_Found_Cluster,ax ;2 is the first data cluster number(0 based) + +subttl Read In FAT +page +;*********************************************************************** +; Read_In_FAT +;*********************************************************************** +; +; Notes: +; +; Reads in the entire FAT at 800:0. This gives the relocated portion +; of this loader a maximum size of 768 bytes (8000 - 7D00). +; With 64 KB memory system, this can support maximum size of FAT to +; be 32 KB. We assumes that the system memory size be 128 KB, if +; the system has a big media with the total fat size bigger than +; 32 KB. +; +; Input: none +; +; Output: +; +; ES = 0 +; All sectors destroyed +; +; Calls: READ DISK +;----------------------------------------------------------------------- +; Get number of sectors in FAT +; +; Set ES:DI to 800:0 +; +; Read in the sectors +; +;---------------------------------------------------------------------- +;Read_In_FAT: +; mov ax,cs:Number_Of_FAT_Sectors ;Get sectors/FAT +; mov cs:Sector_Count,ax ;Number of sectors to read +; mov ax,cs:Hidden_Sectors_L ;Hidden+Reserved = start of FAT sector +; mov dx,cs:Hidden_Sectors_H ;AN000; +; add ax,cs:Reserved_Sectors +; adc dx, 0 +; mov cs:Start_Sector_L,ax ;AC000;Save it, setup for disk read +; mov cs:Start_Sector_H,dx ;AN000; +; mov di, 800h ;AC000; +; mov es, di ;AC000; +; xor di, di ;AC000; +; assume es:nothing +; call Disk_Read +; +subttl Keep Loaded BIO +page +;*********************************************************************** +; KEEP LOADED BIO +;*********************************************************************** +; +; Notes: +; +; Determine how much of IBMBIO was loaded in when the loader was loaded +; by the boot record (only the portion that is guaranteed to be contiguous) +; +; Input: +; +; cs:Last_Found_Cluster = number of clusters used for loader+2 +; +; Output: +; ES=70h +; DI = Next offset to load IBMBIO code +; AX,BX,CX,DX,SI destroyed +; +; cs:Next_BIO_Location = DI on output +; cs:Last_Cluster = last cluster loaded +; +; Calls: none +;----------------------------------------------------------------------- +;Number of clusters loaded+2 is in cs:Last_Found_Cluster +; +;Multiply cluster * cluster size in bytes to get total loaded for MSLOAD +; +;Subtract TOTAL_LOADED - LOADBIO_SIZE to get loaded IBMBIO in last cluster +; +;Relocate this piece of IBMBIO down to 70:0 +; +;---------------------------------------------------------------------- +Keep_Loaded_BIO: + push ds + mov ax,cs:Last_Found_Cluster ;Point to last cluster loaded + sub ax,1 ;Get number of clusters loaded + mul cs:Size_Cluster ;Get total bytes loaded by + ;This is always < 64k, so + ;lower 16 bits ok + sub ax,LoadBio_Size ;Get portion of IBMBIO loaded + mov cx,ax ;Save length to move + mov ax,70h ;Segment at 70h + mov ds,ax + mov es,ax + mov si,offset Total_Length ;Point at IBMBIO + mov di,0 ;Point at 70:0 + rep movsb ;Relocate this code + mov cs:Next_Bio_Location,di ;Save where to load next + pop ds + +subttl Get Contiguous Clusters +page +;*********************************************************************** +; Get_Contiguous_Clusters +;*********************************************************************** +; +; Notes: Go find clusters as long as they are contiguous +; +; +; Input: +; +; cs:Next_BIO_Location +; cs: +; +; +; Output: +; +; +; Calls: Get_Next_FAT_Entry +;----------------------------------------------------------------------- +; +;Set cs:Sector_Count to Sectors per cluster +; +;Call Get_Next_FAT_Entry to get next cluster in file +; +;Call Check_for_EOF +; +;IF (NC returned) +; +; {Call Get_Next_FAT_Entry +; +; IF (New cluster is contig to old cluster) +; {Add sectors per cluster to cs:Sector_Count +; +; Call Check_For_EOF +; +; IF (NC returned) +; +; +;---------------------------------------------------------------------- +Get_Contiguous_Cluster: + xor ah,ah + mov al,cs:Sectors_Per_Cluster ;Assume we will get one cluster + mov cs:Sector_Count,ax + push cs:Sector_Count + call Get_Next_Fat_Entry ;Go get it in AX + pop cs:Sector_Count + mov cs:Last_Found_Cluster,ax ;Update the last one found + cmp cs:EOF,END_OF_FILE + je GO_IBMBIO + +; je GOTO_IBMBIO +;Got_Contig_Clusters: + + xor dx,dx ;AN000; + sub ax,2 ;Zero base the cluster + xor ch,ch + mov cl,cs:Sectors_Per_Cluster ;Get sectors per cluster + mul cx ;Get how many + add ax,cs:First_Sector_L ;AC000;See where the data sector starts + adc dx,cs:First_Sector_H ;AN000; + mov cs:Start_Sector_L,ax ;AC000;Save it + mov cs:Start_Sector_H,dx ;AN000; + mov di,cs:Next_Bio_Location ;Get where to put code + push cs:Sector_Count ;Save how many sectors + mov ax,dosloadseg ;Get area to load code + mov es,ax + call Disk_Read + pop ax ;Get back total sectors read in +; jc ########## + mul cs:Sector_Size ;AC000;Get number of bytes we loaded +; mul Boot_Sector.ByteSec + add cs:Next_Bio_Location,ax ;Point to where to load next + jmp Get_Contiguous_Cluster + +subttl GOTO IBMBIO +page +;*********************************************************************** +; GOTO_IBMBIO +;*********************************************************************** +; +; Notes: +; +; Set up required registers for IBMBIO, then jump to it (70:0) +; +; Input: none +; +; cs:Media_Byte = media byte +; cs:Drive_Number = INT 13 drive number we booted from +; cs:First_Sector_L = First data sector on disk (Low) (0-based) +; cs:First_Sector_H = First data sector on disk (High) +; +; Output: +; +; Required by MSINIT +; DL = INT 13 drive number we booted from +; CH = media byte +; BX = First data sector on disk (0-based) +; AX = First data sector on disk (High) +; DI = Sectors/FAT for the boot media. +; +; Calls: none +;----------------------------------------------------------------------- +; +; Set up registers for MSINIT then do Far Jmp +; +;---------------------------------------------------------------------- +GO_IBMBIO: + mov ch,cs:Media_Byte ;Restore regs required for MSINT + mov dl,cs:Drive_Number ;Physical Drive number we booted from. + mov bx,cs:First_Sector_L ;AC000; + mov ax,cs:First_Sector_H ;AN000; AX will be the First data sector (High) +;J.K. Don't need this information any more. +; mov di,cs:Number_Of_FAT_Sectors ;AN000 + jmp far ptr IBMBIO_Address + + +subttl Disk Read +page +;*********************************************************************** +; Disk_Read +;*********************************************************************** +; +; Notes: +; +; Read in the cs:Sector_Count number of sectors at ES:DI +; +; +; Input: none +; +; DI = Offset of start of read +; ES = Segment of read +; cs:Sector_Count = number of sectors to read +; cs:Start_sector_L = starting sector (Low) +; cs:Start_sector_H = starting sector (High) +; Following is BPB info that must be setup prior to call +; cs:Number_Of_Heads +; cs:Number_Of_Sectors +; cs:Drive_Number +; cs:Sectors_Per_Track +; +; Output: +; +; AX,BX,CX,DX,SI,DI destroyed +;----------------------------------------------------------------------- +; Divide start sector by sectors per track +; The remainder is the actual sector number, 0 based +; +; Increment actual sector number to get 1 based +; +; The quotient is the number of tracks - divide by heads to get the cyl +; +; The remainder is actual head, the quotient is cylinder +; +; Figure the number of sectors in that track, set AL to this +; +; Do the read +; +; If Error, Do RESET, then redo the INT 13h +; +; If successful read, Subtract # sectors read from Sector_Count, Add to Logical +; Sector, add #sectors read * Sector_Size to BX; +; +; If Sector_Count <> 0 Do next read +;---------------------------------------------------------------------- +Disk_Read: + +; +; convert a logical sector into Track/sector/head. AX has the logical +; sector number +; +DODIV: + MOV cx,5 ;5 retries + +Try_Read: + PUSH cx ;Save it + MOV AX,cs:Start_Sector_L ;AC000; Get starting sector + mov dx, cs:Start_Sector_H ;AN000; +; XOR DX,DX + push ax ;AN000; + mov ax, dx ;AN000; + xor dx, dx ;AN000; + DIV word ptr cs:Sectors_Per_Track + mov cs:Temp_H, ax ;AN000; + pop ax ;AN000; + div word ptr cs:Sectors_Per_Track ;AN000;[temp_h];AX = track, DX = sector number + MOV bx,cs:Sectors_Per_Track ;Get number of sectors we can read in + sub bx,dx ;this track + mov si,bx + cmp cs:Sector_Count,si ;Is possible sectors in track more + jae Got_Length ;than what we need to read? + mov si,cs:Sector_Count ;Yes, only read what we need to +Got_Length: + INC DL ; sector numbers are 1-based + MOV bl,dl ;Start sector in DL + mov dx, cs:Temp_H ;AN000;now, dx;ax = track +; XOR DX, DX + push ax ;AN000; + mov ax, dx ;AN000; + xor dx, dx ;AN000; + DIV word ptr cs:Number_Of_Heads ;Start cyl in ax,head in DL + mov cs:Temp_h, ax ;AN000; + pop ax ;AN000; + div word ptr cs:Number_of_Heads ;AN000;now [temp_h];AX = cyliner, dx = head +;J.K. At this moment, we assume that Temp_h = 0, AX <= 1024, DX <= 255 + MOV DH,DL +; +; Issue one read request. ES:BX have the transfer address, AL is the number +; of sectors. +; + MOV CL,6 + SHL AH,CL ;Shift cyl high bits up + OR AH,BL ;Mix in with sector bits + MOV CH,AL ;Setup Cyl low + MOV CL,AH ;Setup Cyl/high - Sector + mov bx,di ;Get back offset + MOV DL,cs:Drive_Number ;Get drive + mov ax,si ;Get number of sectors to read (AL) + + MOV AH,2 ;Read + push ax ;Save length of read + push di +; Issue one read request. ES:BX have the transfer address, AL is the number +; of sectors. + INT 13H + pop di + pop ax + pop cx ;Get retry count back + jnc Read_OK + mov bx,di ;Get offset + xor ah,ah + push cx + mov dl,cs:Drive_Number + push di + int 13h + pop di + pop cx +; loop Try_Read ;AC000; + ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx error + dec cx ;AN000; + jz Read_Error ;AN000; + jmp Try_Read ;AN000; +Read_Error: ;AN000; + jmp ErrorOut ;AN000; + +Read_OK: + xor ah,ah ;Mask out read command, just get # read + sub cs:Sector_Count,ax ;Bump number down + jz Read_Finished + add cs:Start_Sector_L,ax ;AC000;Where to start next time + adc cs:Start_Sector_H, 0 ;AN000; + xor bx,bx ;Get number sectors read + mov bl,al + mov ax,cs:Sector_Size ;Bytes per sector + mul bx ;Get total bytes read + add di,ax ;Add it to offset + jmp DODIV +Read_Finished: + RET + +subttl GET NEXT FAT ENTRY +page +;*********************************************************************** +; GET_NEXT_FAT_ENTRY +;*********************************************************************** +; +; Notes: +; +; Given the last cluster found, this will return the next cluster of +; IBMBIO. If the last cluster is (F)FF8 - (F)FFF, then the final cluster +; of IBMBIO has been loaded, and control is passed to GOTO_IBMBIO +; MSLOAD can handle maximum FAT area size of 64 KB. +; +; Input: +; +; cs:Last_Found_Cluster +; cs:Fat_Size +; +; Output: +; +; cs:Last_Found_Cluster (updated) +; +; Calls: Get_Fat_Sector +;----------------------------------------------------------------------- +; Get Last_Found_Cluster +; +; IF (16 bit FAT) +; {IF (Last_Found_Cluster = FFF8 - FFFF) +; {JMP GOTO_IBMBIO} +; ELSE +; {Get offset by multiply cluster by 2} +; +; ELSE +; {IF (Last_Found_Cluster = FF8 - FFF) +; {JMP GOTO_IBMBIO} +; ELSE +; {Get offset by - multiply cluster by 3 +; +; Rotate right to divide by 2 +; +; IF (CY set - means odd number) +; {SHR 4 times to keep high twelve bits} +; +; ELSE +; {AND with 0FFFh to keep low 12 bits} +; } +; } +; +; +;---------------------------------------------------------------------- +Get_Next_FAT_Entry: + + push es ;AN000; + mov ax, cs:FAT_Segment ;AN000; + mov es, ax ;AN000; es-> Fat area segment + assume es:nothing + + mov cs:EOF,End_Of_File ;Assume last cluster + mov ax,cs:Last_Found_Cluster ;Get last cluster + cmp cs:Fat_Size,FAT12_bit + jne Got_16_Bit + mov si, ax ;AN000; + shr ax, 1 ;AN000; + add si, ax ;AN000; si = ax*1.5 = ax+ax/2 + call Get_Fat_Sector ;AN000; + jne Ok_cluster ;AN000; + mov al, byte ptr es:[bx] ;AN000; + mov byte ptr cs:Temp_cluster, al ;AN000; + inc si ;AN000; + call Get_Fat_Sector ;AN000;read next FAT sector + mov al, byte ptr es:[0] ;AN000; + mov byte ptr cs:Temp_cluster+1, al ;AN000; + mov ax, cs:Temp_cluster ;AN000; + jmp short Even_Odd ;AN000; +Ok_cluster: ;AN000; + mov ax, es:[bx] ;AN000; +Even_Odd: ;AN000; + +; xor bx,bx +; mov bl,3 ;Mult by 3 +; mul bx +; shr ax,1 ;Div by 2 to get 1.5 +; mov si,ax ;Get the final buffer offset +; mov ax,[si]+8000h ;Get new cluster + + test cs:Last_Found_Cluster,1 ;Was last cluster odd? + jnz Odd_Result ;If Carry set it was odd + and ax,0FFFh ;Keep low 12 bits + jmp short Test_EOF ; + +Odd_Result: + mov cl,4 ;AN000;Keep high 12 bits for odd + shr ax,cl +Test_EOF: + cmp ax,0FF8h ;Is it last cluster? + jae Got_Cluster_Done ;Yep, all done here + jmp short Not_Last_CLuster + +Got_16_Bit: + shl ax,1 ;Multiply cluster by 2 + mov si,ax ;Get the final buffer offset + call Get_Fat_Sector ;AN000; + mov ax, es:[bx] ;AN000; +; mov ax,[si]+8000h ;Get new cluster + cmp ax,0FFF8h + jae Got_Cluster_Done + +Not_Last_Cluster: + mov cs:EOF,not END_OF_FILE ;Assume last cluster + +Got_Cluster_Done: + pop es + ret + + +Get_Fat_Sector proc near +;Function: Find and read the corresponding FAT sector into ES:0 +;In). SI = offset value (starting from FAT entry 0) of FAT entry to find. +; ES = FAT sector segment +; cs:Sector_Size +;Out). Corresponding FAT sector read in. +; BX = offset value of the corresponding FAT entry in the FAT sector. +; CX destroyed. +; Zero flag set if the FAT entry is splitted, i.e. when 12 bit FAT entry +; starts at the last byte of the FAT sector. In this case, the caller +; should save this byte, and read the next FAT sector to get the rest +; of the FAT entry value. (This will only happen with the 12 bit fat). + + push ax ;AN000; + push si ;AN000; + push di ;AN000; + push dx ;AN000; + xor dx, dx ;AN000; + mov ax, si ;AN000; + mov cx, cs:Sector_Size ;AN000; + div cx ;AN000;ax = sector number, dx = offset + cmp ax, cs:Last_Fat_SecNum ;AN000;the same fat sector? + je GFS_Split_Chk ;AN000;don't need to read it again. + mov cs:Last_Fat_SecNum, ax ;AN000; + push dx ;AN000; + xor dx, dx ;AN000; + add ax, cs:Hidden_Sectors_L ;AN000; + adc dx, cs:Hidden_Sectors_H ;AN000; + add ax, cs:Reserved_Sectors ;AN000; + adc dx, 0 ;AN000; + mov cs:Start_Sector_L, ax ;AN000; + mov cs:Start_Sector_H, dx ;AN000;set up for Disk_Read + mov cs:Sector_Count, 1 ;AN000;1 sector + xor di, di ;AN000; + call Disk_Read ;AN000; + pop dx ;AN000; + mov cx, cs:Sector_Size ;AN000; +GFS_Split_Chk: ;AN000; + dec cx ;AN000;now, cx= sector size - 1 + cmp dx, cx ;AN000;if the last byte of the sector, then splitted entry. + mov bx, dx ;AN000;Set BX to DX + pop dx ;AN000; + pop di ;AN000; + pop si ;AN000; + pop ax ;AN000; + ret ;AN000; +Get_Fat_Sector endp ;AN000; + + +Errorout: ;AN000; + push cs ;AN000; + pop ds ;AN000; + mov si, offset Sysmsg ;AN000; + call write ;AN000; +;SB34LOAD001**************************************************************** +;SB Wait for a keypress on the keyboard. Use the BIOS keyboard interrupt. +;SB 2 LOCS + + xor ah,ah + int 16h ;read keyboard +;SB34LOAD001**************************************************************** + +;SB34LOAD002**************************************************************** +;SB We have to restore the address of the original rom Disk parameter table +;SB to the location at [0:DSKADR]. The address of this original table has been +;SB saved previously in 0:Org_Rom_DiskTable and 0:Org_Rom_Disktable+2. +;SB After this table address has been restored we can reboot by +;SB invoking the bootstrap loader BIOS interrupt. + + xor bx, bx + mov ds, bx + les bx, dword ptr ds:Org_Rom_DiskTable + mov si, DSKADR + mov word ptr ds:[si], bx ;restore offset + mov word ptr ds:[si+2], es ;restore segment + int 19h ;reboot +;SB34LOAD002**************************************************************** + +Write proc near ;show error messages +;In) DS:SI -> ASCIIZ string. + + lodsb ;AN000; + or al, al ;AN000; + jz Endwr ;AN000; +;SB34LOAD003**************************************************************** +;SB Write the character in al to the screen. +;SB Use Video service 'Write teletype to active page' (ROM_TELETYPE) +;SB Use normal character attribute + mov ah, ROM_TELETYPE + mov bl, 7 ;"normal" attribute ? + int 10h ;video write +;SB34LOAD003**************************************************************** + jmp Write ;AN000; +Endwr: ;AN000; + ret ;AN000; +Write endp +; + +;include MSbtmes.inc ;AN000; +include MSbio.cl1 ;AN001; + +Relocate_Length equ $ - start +Total_Length label byte +LoadBIO_Size equ $ - Start + +cseg ends + end start -- cgit v1.2.3