Version 2.7 luchezar, tomehlert, ericauer 2003/8/5

boot.asm modified to support non-512 byte sectors (e.g. 1.2 MB NEC diskettes)
  512 byte sector size check removed (although Eric's boot32ea.asm does require
    512-byte sectors, all LBA FAT32 volumes have 512-byte sectors anyway).
  boot.asm cleaned up and modified to support Metakern (by Tom, Eric and Lucho)
  bsDriveNumber updated by SYS even #ifndef STORE_BOOT_INFO (nothing in common)

Version 2.7beta, Luchezar Georgiev, 1 August 2003
  o  Now supports and includes the following new boot sectors:
       1) the combined CHS+LBA FAT12/FAT16 boot sector by Tom Ehlert (29 July)
       2) the CHS-only FAT32 boot sector -- as patched by Jon Gentle (08 July)
       3) the LBA-only FAT32 boot sector by Eric Auer and Jon Gentle (19 July)
  o  The old combined (CHS+LBA), no-CALCPARAMS, no-resizable, non-Ghostable,
     non-standard FAT32 boot sector and STORE_BOOT_INFO is no longer used.
  o  dump_sector() showed ASCII debug printout for the old sector only - fixed.
  o  Put a boot sector only if sector size = 512 (may it not be so in Japan?!).
     If non-512 byte sectors encountered, report to the fd-kernel mailing list.
  o  Now puts boot sector before copying kernel/shell so it works in WinNT now.
  o  check_space() now implemented at last (required significant modifications)
  o  New file system (FAT type) detection method according to a MS White Paper.
  o  Now BOOTONLY works even without a preceding boot sector image file name.
  o  Some minor code cleanups.

Bart: some cleanups to the above; replaced 386 code for CHS FAT32 by 8088 code.
use boot32lb.asm instead of boot32ea.asm


git-svn-id: https://svn.code.sf.net/p/freedos/svn/kernel/trunk@652 6ac86273-5f31-0410-b378-82cca8765d1b
This commit is contained in:
Bart Oldeman 2003-08-08 15:01:15 +00:00
parent 3229fe3fc4
commit 9a3da2b737
6 changed files with 755 additions and 438 deletions

View File

@ -26,31 +26,24 @@
; Cambridge, MA 02139, USA. ; Cambridge, MA 02139, USA.
; ;
; ;
; +--------+ ; +--------+ 1FE0:7E00
; | |
; | |
; |--------| 4000:0000
; | |
; | FAT |
; | |
; |--------| 2000:0000
; |BOOT SEC| ; |BOOT SEC|
; |RELOCATE| ; |RELOCATE|
; |--------| 1FE0:0000 ; |--------| 1FE0:7C00
; | |
; | | ; | |
; |--------| 1FE0:3000
; | CLUSTER|
; | LIST |
; |--------| 1FE0:2000
; | | ; | |
; |--------| 0000:7E00
; |BOOT SEC| overwritten by max 128k FAT buffer
; |ORIGIN | and later by max 134k loaded kernel
; |--------| 0000:7C00
; | | ; | |
; |--------| ; |--------|
; |BOOT SEC| ; |KERNEL | also used as max 128k FAT buffer
; |ORIGIN | 07C0:0000 ; |LOADED | before kernel loading starts
; |--------|
; | |
; | |
; | |
; |--------|
; |KERNEL |
; |LOADED |
; |--------| 0060:0000 ; |--------| 0060:0000
; | | ; | |
; +--------+ ; +--------+
@ -58,8 +51,6 @@
;%define ISFAT12 1 ;%define ISFAT12 1
;%define ISFAT16 1 ;%define ISFAT16 1
;%define CALCPARAMS 1
;%define MULTI_SEC_READ 1
segment .text segment .text
@ -118,7 +109,7 @@ Entry: jmp short real_start
mov word [fat_start+2], di mov word [fat_start+2], di
mov al, [bsFATs] mov al, [bsFATs]
xor ah, ah cbw
mul word [sectPerFat] ; DX:AX = total number of FAT sectors mul word [sectPerFat] ; DX:AX = total number of FAT sectors
add si, ax add si, ax
@ -148,49 +139,50 @@ Entry: jmp short real_start
times 0x3E-$+$$ db 0 times 0x3E-$+$$ db 0
%define tempbuf bp+0x3E %define loadsegoff_60 bp+0x3E
dw 0
%define loadseg_60 bp+0x40
dw LOADSEG dw LOADSEG
%ifdef CALCPARAMS ;%define LBA_PACKET bp+0x42
%define RootDirSecs bp+0x27 ; # of sectors root dir uses ; db 10h ; size of packet
; db 0 ; const
; dw 1 ; number of sectors to read
%define LBA_PACKET bp-0x40
%define LBA_SIZE word [LBA_PACKET]
%define LBA_SECNUM word [LBA_PACKET+2]
%define LBA_OFF LBA_PACKET+4
%define LBA_SEG LBA_PACKET+6
%define LBA_SECTOR_0 word [LBA_PACKET+8 ]
%define LBA_SECTOR_16 word [LBA_PACKET+10]
%define LBA_SECTOR_32 word [LBA_PACKET+12]
%define LBA_SECTOR_48 word [LBA_PACKET+14]
%define fat_start bp+0x29 ; first FAT sector
%define root_dir_start bp+0x2D ; first root directory sector
%define data_start bp+0x31 ; first data sector %define PARAMS LBA_PACKET+0x10
%define RootDirSecs PARAMS+0x0 ; # of sectors root dir uses
%else %define fat_start PARAMS+0x2 ; first FAT sector
%define RootDirSecs bp+0x40 ; # of sectors root dir uses
dw 0
%define fat_start bp+0x42 ; first FAT sector %define root_dir_start PARAMS+0x6 ; first root directory sector
dd 0
%define root_dir_start bp+0x46 ; first root directory sector %define data_start PARAMS+0x0a ; first data sector
dd 0
%define data_start bp+0x4A ; first data sector
dd 0
%endif
;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
; ENTRY ; ENTRY
;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
real_start: cli real_start:
cli
cld cld
xor ax, ax xor ax, ax
mov ss, ax ; initialize stack
mov ds, ax mov ds, ax
mov bp, 0x7c00 mov bp, 0x7c00
lea sp, [bp-0x20]
sti
cmp byte [drive], 0xff ; BIOS bug ?? ; a reset should not be needed here
jne dont_use_dl
mov [drive], dl ; BIOS passes drive number in DL
; a reset should not be needed here
dont_use_dl:
; int 0x13 ; reset drive ; int 0x13 ; reset drive
; int 0x12 ; get memory available in AX ; int 0x12 ; get memory available in AX
@ -207,15 +199,26 @@ dont_use_dl:
rep movsw rep movsw
jmp word 0x1FE0:cont jmp word 0x1FE0:cont
cont: mov ds, ax cont:
mov ds, ax
mov ss, ax mov ss, ax
lea sp, [bp-0x60]
sti
;
; Some BIOS don't pass drive number in DL, so don't use it if [drive] is known
;
cmp byte [drive], 0xff ; impossible number written by SYS
jne dont_use_dl ; was SYS drive: other than A or B?
mov [drive], dl ; yes, rely on BIOS drive number in DL
dont_use_dl: ; no, rely on [drive] written by SYS
mov LBA_SIZE, 10h
mov LBA_SECNUM,1 ; initialise LBA packet constants
call print call print
db "FreeDOS",0 db "FreeDOS",0
%ifdef CALCPARAMS
GETDRIVEPARMS GETDRIVEPARMS
%endif
; FINDFILE: Searches for the file in the root directory. ; FINDFILE: Searches for the file in the root directory.
@ -229,13 +232,12 @@ cont: mov ds, ax
mov ax, word [root_dir_start] mov ax, word [root_dir_start]
mov dx, word [root_dir_start+2] mov dx, word [root_dir_start+2]
mov di, word [RootDirSecs] mov di, word [RootDirSecs]
xor bx, bx les bx, [loadsegoff_60] ; es:bx = 60:0
mov word [tempbuf], LOADSEG
mov es, [tempbuf]
call readDisk call readDisk
jc jmp_boot_error jc jmp_boot_error
xor di, di les di, [loadsegoff_60] ; es:di = 60:0
; Search for KERNEL.SYS file name, and find start cluster. ; Search for KERNEL.SYS file name, and find start cluster.
@ -255,8 +257,8 @@ next_entry: mov cx, 11
ffDone: ffDone:
push ax ; store first cluster number push ax ; store first cluster number
call print ; call print
db " FAT",0 ; db " FAT",0
@ -275,8 +277,7 @@ ffDone:
; Load the complete FAT into memory. The FAT can't be larger ; Load the complete FAT into memory. The FAT can't be larger
; than 128 kb, so it should fit in the temporary buffer. ; than 128 kb, so it should fit in the temporary buffer.
mov es, [tempbuf] les bx, [loadsegoff_60] ; es:bx=60:0
xor bx, bx
mov di, [sectPerFat] mov di, [sectPerFat]
mov ax, word [fat_start] mov ax, word [fat_start]
mov dx, word [fat_start+2] mov dx, word [fat_start+2]
@ -286,9 +287,8 @@ jmp_boot_error: jc boot_error
; Set ES:DI to the temporary storage for the FAT chain. ; Set ES:DI to the temporary storage for the FAT chain.
push ds push ds
push es
pop ds
pop es pop es
mov ds, [loadseg_60]
mov di, FATBUF mov di, FATBUF
next_clust: stosw ; store cluster number next_clust: stosw ; store cluster number
@ -308,8 +308,7 @@ fat_12: add si, si ; multiply cluster number by 3...
; the number was odd, CF was set in the last shift instruction. ; the number was odd, CF was set in the last shift instruction.
jnc fat_even jnc fat_even
mov cl, 4 div word[LBA_PACKET]; luckily 16 !! -- divide the cluster number
shr ax, cl ; shift the cluster number
fat_even: and ah, 0x0f ; mask off the highest 4 bits fat_even: and ah, 0x0f ; mask off the highest 4 bits
cmp ax, 0x0ff8 ; check for EOF cmp ax, 0x0ff8 ; check for EOF
@ -320,7 +319,7 @@ fat_even: and ah, 0x0f ; mask off the highest 4 bits
; This is a FAT-16 disk. The maximal size of a 16-bit FAT ; This is a FAT-16 disk. The maximal size of a 16-bit FAT
; is 128 kb, so it may not fit within a single 64 kb segment. ; is 128 kb, so it may not fit within a single 64 kb segment.
fat_16: mov dx, [tempbuf] fat_16: mov dx, [loadseg_60]
add si, si ; multiply cluster number by two add si, si ; multiply cluster number by two
jnc first_half ; if overflow... jnc first_half ; if overflow...
add dh, 0x10 ; ...add 64 kb to segment value add dh, 0x10 ; ...add 64 kb to segment value
@ -341,14 +340,13 @@ finished: ; Mark end of FAT chain with 0, so we have a single
push cs push cs
pop ds pop ds
call print ;call print
db " Kernel",0 ; "KERNEL" ;db " Kernel",0 ; "KERNEL"
; loadFile: Loads the file into memory, one cluster at a time. ; loadFile: Loads the file into memory, one cluster at a time.
mov es, [tempbuf] ; set ES:BX to load address les bx, [loadsegoff_60] ; set ES:BX to load address 60:0
xor bx, bx
mov si, FATBUF ; set DS:SI to the FAT chain mov si, FATBUF ; set DS:SI to the FAT chain
@ -369,16 +367,17 @@ cluster_next: lodsw ; AX = next cluster to read
boot_error: call print boot_error: call print
db 13,10,"BOOT err!",0 db " err",0
xor ah,ah xor ah,ah
int 0x16 ; wait for a key int 0x16 ; wait for a key
int 0x19 ; reboot the machine int 0x19 ; reboot the machine
boot_success: call print boot_success:
db " GO! ",0 ;call print
;db " GO! ",0
mov bl, [drive] mov bl, [drive]
jmp word LOADSEG:0 jmp far [loadsegoff_60]
; prints text after call to this function. ; prints text after call to this function.
@ -406,13 +405,17 @@ print1: lodsb ; get token
; ES:BX points one byte after the last byte read. ; ES:BX points one byte after the last byte read.
readDisk: push si readDisk: push si
read_next: push dx
push ax mov LBA_SECTOR_0,ax
mov LBA_SECTOR_16,dx
mov word [LBA_SEG],es
mov word [LBA_OFF],bx
read_next:
;******************** LBA_READ ******************************* ;******************** LBA_READ *******************************
; check for LBA support ; check for LBA support
push bx
mov ah,041h ; mov ah,041h ;
mov bx,055aah ; mov bx,055aah ;
@ -424,51 +427,30 @@ read_next: push dx
int 0x13 int 0x13
jc read_normal_BIOS jc read_normal_BIOS
sub bx,0aa55h shr cx,1 ; CX must have 1 bit set
sbb bx,0aa55h - 1 ; tests for carry (from shr) too!
jne read_normal_BIOS jne read_normal_BIOS
shr cx,1 ; CX must have 1 bit set
jnc read_normal_BIOS
; OK, drive seems to support LBA addressing ; OK, drive seems to support LBA addressing
lea si,[LBA_DISK_PARAMETER_BLOCK] lea si,[LBA_PACKET]
; setup LBA disk block ; setup LBA disk block
mov [si+12],bx mov LBA_SECTOR_32,bx
mov [si+14],bx mov LBA_SECTOR_48,bx
pop bx
pop ax
pop dx
push dx
push ax
mov [si+ 8],ax
mov [si+10],dx
mov [si+4],bx
mov [si+6],es
mov ah,042h mov ah,042h
jmp short do_int13_read jmp short do_int13_read
LBA_DISK_PARAMETER_BLOCK:
db 10h ; constant size of block
db 0
dw 1 ; 1 sector read
; and overflow into code !!!
read_normal_BIOS: read_normal_BIOS:
pop bx
pop ax
pop dx
push dx
push ax
;******************** END OF LBA_READ ************************ ;******************** END OF LBA_READ ************************
mov ax,LBA_SECTOR_0
mov dx,LBA_SECTOR_16
; ;
@ -509,93 +491,37 @@ read_normal_BIOS:
inc ah ; sector offset from 1 inc ah ; sector offset from 1
or cl, ah ; merge sector into cylinder or cl, ah ; merge sector into cylinder
%ifdef MULTI_SEC_READ les bx,[LBA_OFF]
; Calculate how many sectors can be transfered in this read
; due to dma boundary conditions.
push dx
mov si, di ; temp register save
; this computes remaining bytes because of modulo 65536
; nature of dma boundary condition
mov ax, bx ; get offset pointer
neg ax ; and convert to bytes
jz ax_min_1 ; started at seg:0, skip ahead
xor dx, dx ; convert to sectors
div word [bsBytesPerSec]
cmp ax, di ; check remainder vs. asked
jb ax_min_1 ; less, skip ahead
mov si, ax ; transfer only what we can
ax_min_1: pop dx
; Check that request sectors do not exceed track boundary
mov si, [sectPerTrack]
inc si
mov ax, cx ; get the sector/cyl byte
and ax, 0x3f ; and mask out sector
sub si, ax ; si has how many we can read
mov ax, di
cmp si, di ; see if asked <= available
jge ax_min_2
mov ax, si ; get what can be xfered
ax_min_2: push ax
mov ah, 2
mov dl, [drive]
int 0x13
pop ax
%else
mov ax, 0x0201 mov ax, 0x0201
do_int13_read: do_int13_read:
mov dl, [drive] mov dl, [drive]
int 0x13 int 0x13
%endif
read_finished: read_finished:
jnc read_ok ; jump if no error jnc read_ok ; jump if no error
xor ah, ah ; else, reset floppy xor ah, ah ; else, reset floppy
int 0x13 int 0x13
pop ax
pop dx ; and...
read_next_chained: read_next_chained:
jmp short read_next ; read the same sector again jmp short read_next ; read the same sector again
read_ok: read_ok:
%ifdef MULTI_SEC_READ mov ax, word [bsBytesPerSec]
mul word [bsBytesPerSec] ; add number of bytes read to BX div byte[LBA_PACKET] ; luckily 16 !!
add bx, ax add word [LBA_SEG], ax
%else
add bx, word [bsBytesPerSec]
%endif
jnc no_incr_es ; if overflow...
mov ax, es add LBA_SECTOR_0, byte 1
add ah, 0x10 ; ...add 1000h to ES adc LBA_SECTOR_16, byte 0 ; DX:AX = next sector to read
mov es, ax
no_incr_es: pop ax
pop dx ; DX:AX = last sector number
%ifdef MULTI_SEC_READ
add ax, si
adc dx, byte 0 ; DX:AX = next sector to read
sub di,si ; if there is anything left to read,
jg read_next ; continue
%else
add ax, byte 1
adc dx, byte 0 ; DX:AX = next sector to read
dec di ; if there is anything left to read, dec di ; if there is anything left to read,
jnz read_next_chained ; continue jnz read_next_chained ; continue
%endif
clc mov es,word [LBA_SEG]
; clear carry: unnecessary since adc clears it
pop si pop si
ret ret
filename db "KERNEL SYS" filename db "KERNEL SYS"
times 0x01fe-$+$$ db 0 times 0x01fe-$+$$ db 0
sign dw 0xAA55 sign dw 0xAA55

View File

@ -57,34 +57,33 @@ Entry: jmp short real_start
%define xrootClst bp+0x2c ; Starting cluster of root directory %define xrootClst bp+0x2c ; Starting cluster of root directory
%define drive bp+0x40 ; Drive number %define drive bp+0x40 ; Drive number
times 0x5a-$+$$ db 0
%define LOADSEG 0x0060 %define LOADSEG 0x0060
%define FATSEG 0x2000 %define FATSEG 0x2000
%define fat_sector bp+0x48 ; last accessed sector of the FAT %define fat_sector bp+0x48 ; last accessed sector of the FAT
dd 0
times 0x5a-$+$$ db 0 %define loadsegoff_60 bp+0x5a ; FAR pointer = 60:0
%define fat_start bp+0x5a ; first FAT sector
dd 0
%define data_start bp+0x5e ; first data sector
dd 0
%define fat_secmask bp+0x62 ; number of clusters in a FAT sector - 1
dw 0
%define fat_secshift bp+0x64 ; fat_secmask+1 = 2^fat_secshift
dw 0 dw 0
%define loadseg_60 bp+0x5c
dw LOADSEG
%define fat_start bp+0x5e ; first FAT sector
%define data_start bp+0x62 ; first data sector
%define fat_secmask bp+0x66 ; number of clusters in a FAT sector - 1
%define fat_secshift bp+0x68 ; fat_secmask+1 = 2^fat_secshift
;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
; ENTRY ; ENTRY
;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
real_start: cld real_start: cld
cli
sub ax, ax sub ax, ax
mov ds, ax mov ds, ax
mov bp, 0x7c00 mov bp, 0x7c00
mov ss, ax ; initialize stack
lea sp, [bp-0x20]
int 0x13 ; reset drive
mov ax, 0x1FE0 mov ax, 0x1FE0
mov es, ax mov es, ax
@ -95,18 +94,59 @@ real_start: cld
jmp word 0x1FE0:cont jmp word 0x1FE0:cont
cont: mov ds, ax cont: mov ds, ax
mov ss, ax mov ss, ax
lea sp, [bp-0x20]
sti
mov [drive], dl ; BIOS passes drive number in DL mov [drive], dl ; BIOS passes drive number in DL
call print ; call print
db "Loading FreeDOS ",0 ; db "Loading ",0
; Calc Params
; Fat_Start
mov si, word [nHidden]
mov di, word [nHidden+2]
add si, word [bsResSectors]
adc di, byte 0
mov word [fat_start], si
mov word [fat_start+2], di
; Data_Start
mov al, [bsFATs]
cbw
push ax
mul word [xsectPerFat+2]
add di, ax
pop ax
mul word [xsectPerFat]
add ax, si
adc dx, di
mov word[data_start], ax
mov word[data_start+2], dx
; fat_secmask
mov ax, word[bsBytesPerSec]
shr ax, 1
shr ax, 1
dec ax
mov word [fat_secmask], ax
; fat_secshift
; cx = temp
; ax = fat_secshift
xchg ax, cx ; cx = 0 after movsw
inc cx
secshift: inc ax
shr cx, 1
cmp cx, 1
jne secshift
mov byte [fat_secshift], al
dec cx
; FINDFILE: Searches for the file in the root directory. ; FINDFILE: Searches for the file in the root directory.
; ;
; Returns: ; Returns:
; DX:AX = first cluster of file ; DX:AX = first cluster of file
mov word [fat_sector], cx ; CX is 0 after movsw mov word [fat_sector], cx ; CX is 0 after "dec"
mov word [fat_sector + 2], cx mov word [fat_sector + 2], cx
mov ax, word [xrootClst] mov ax, word [xrootClst]
@ -120,9 +160,7 @@ ff_next_cluster:
ff_next_sector: ff_next_sector:
push bx ; save sector count push bx ; save sector count
mov bx, LOADSEG les bx, [loadsegoff_60]
mov es, bx
sub bx, bx
call readDisk call readDisk
push dx ; save sector push dx ; save sector
push ax push ax
@ -171,10 +209,7 @@ c6:
call next_cluster call next_cluster
jmp c5 jmp c5
boot_error:
boot_error: call print
db 13,10,"BOOT error!",13,10,0
xor ah,ah xor ah,ah
int 0x16 ; wait for a key int 0x16 ; wait for a key
int 0x19 ; reboot the machine int 0x19 ; reboot the machine
@ -230,7 +265,7 @@ cn_exit:
boot_success: boot_success:
mov bl, [drive] mov bl, [drive]
jmp word LOADSEG:0 jmp far [loadsegoff_60]
; Convert cluster to the absolute sector ; Convert cluster to the absolute sector
;input: ;input:
@ -277,7 +312,6 @@ print1: lodsb ; get token
jne print_1char ; until done jne print_1char ; until done
ret ; and jump to it ret ; and jump to it
;input: ;input:
; DX:AX - 32-bit DOS sector number ; DX:AX - 32-bit DOS sector number
; ES:BX - destination buffer ; ES:BX - destination buffer

405
boot/boot32lb.asm Normal file
View File

@ -0,0 +1,405 @@
; This is an LBA-enabled FreeDOS FAT32 boot sector (single sector!).
; You can use and copy source code and binaries under the terms of the
; GNU Public License (GPL), version 2 or newer. See www.gnu.org for more.
; Based on earlier work by FreeDOS kernel hackers, modified heavily by
; Eric Auer and Jon Gentle in 7 / 2003.
;
; Features: Uses LBA and calculates all variables from BPB/EBPB data,
; thus making partition move / resize / image-restore easier. FreeDOS
; can boot from FAT32 partitions which start > 8 GB boundary with this
; boot sector. Disk geometry knowledge is not needed for booting.
;
; Windows uses 2-3 sectors for booting (sector stage, statistics sector,
; filesystem stage). Only using 1 sector for FreeDOS makes multi-booting
; of FreeDOS and Windows on the same filesystem easier.
;
; Requirements: LBA BIOS and 386 or better CPU. Use the older CHS-only
; boot sector if you want FAT32 on really old PCs (problems: you cannot
; boot from > 8 GB boundary, cannot move / resize / ... without applying
; SYS again if you use the CHS-only FAT32 boot sector).
;
; FAT12 / FAT16 hints: Use the older CHS-only boot sector unless you
; have to boot from > 8 GB. The LBA-and-CHS FAT12 / FAT16 boot sector
; needs applying SYS again after move / resize / ... a variant of that
; boot sector without CHS support but with better move / resize / ...
; support would be good for use on LBA harddisks.
; Memory layout for the FreeDOS FAT32 single stage boot process:
; ...
; |-------| 1FE0:7E00
; |BOOTSEC|
; |RELOC. |
; |-------| 1FE0:7C00
; ...
; |-------| 2000:0200
; | FAT | (only 1 sector buffered)
; |-------| 2000:0000
; ...
; |-------| 0000:7E00
; |BOOTSEC| overwritten by the kernel, so the
; |ORIGIN | bootsector relocates itself up...
; |-------| 0000:7C00
; ...
; |-------|
; |KERNEL | maximum size 134k (overwrites bootsec origin)
; |LOADED | (holds 1 sector directory buffer before kernel load)
; |-------| 0060:0000
; ...
segment .text
org 0x7c00 ; this is a boot sector
Entry: jmp short real_start
nop
; bp is initialized to 7c00h
; %define bsOemName bp+0x03 ; OEM label (8)
%define bsBytesPerSec bp+0x0b ; bytes/sector (dw)
%define bsSecPerClust bp+0x0d ; sectors/allocation unit (db)
%define bsResSectors bp+0x0e ; # reserved sectors (dw)
%define bsFATs bp+0x10 ; # of fats (db)
; %define bsRootDirEnts bp+0x11 ; # of root dir entries (dw, 0 for FAT32)
; (FAT32 has root dir in a cluster chain)
; %define bsSectors bp+0x13 ; # sectors total in image (dw, 0 for FAT32)
; (if 0 use nSectorHuge even if FAT16)
; %define bsMedia bp+0x15 ; media descriptor: fd=2side9sec, etc... (db)
; %define sectPerFat bp+0x16 ; # sectors in a fat (dw, 0 for FAT32)
; (FAT32 always uses xsectPerFat)
%define sectPerTrack bp+0x18 ; # sectors/track
; %define nHeads bp+0x1a ; # heads (dw)
%define nHidden bp+0x1c ; # hidden sectors (dd)
; %define nSectorHuge bp+0x20 ; # sectors if > 65536 (dd)
%define xsectPerFat bp+0x24 ; Sectors/Fat (dd)
; +0x28 dw flags (for fat mirroring)
; +0x2a dw filesystem version (usually 0)
%define xrootClst bp+0x2c ; Starting cluster of root directory (dd)
; +0x30 dw -1 or sector number of fs.-info sector
; +0x32 dw -1 or sector number of boot sector backup
; (+0x34 .. +0x3f reserved)
%define drive bp+0x40 ; Drive number
%define LOADSEG 0x0060
%define FATSEG 0x2000
%define fat_secshift fat_afterss-1 ; each fat sector describes 2^??
; clusters (db) (selfmodifying)
%define fat_sector bp+0x44 ; last accessed FAT sector (dd)
; (overwriting unused bytes)
%define fat_start bp+0x48 ; first FAT sector (dd)
; (overwriting unused bytes)
%define data_start bp+0x4c ; first data sector (dd)
; (overwriting unused bytes)
times 0x5a-$+$$ db 0
; not used: [0x42] = byte 0x29 (ext boot param flag)
; [0x43] = dword serial
; [0x47] = label (padded with 00, 11 bytes)
; [0x52] = "FAT32",32,32,32 (not used by Windows)
; ([0x5a] is where FreeDOS parts start)
;-----------------------------------------------------------------------
; ENTRY
;-----------------------------------------------------------------------
real_start: cld
sub ax, ax
mov ds, ax
lss sp, [mystack] ; initialize stack
int 0x13 ; reset drive
mov ax, 0x1FE0
mov es, ax
mov si, sp
mov di, sp
mov bp, sp ; bp-relative parameter addresses used
mov cx, 0x0100
rep movsw ; move boot code to the 0x1FE0:0x0000
jmp word 0x1FE0:cont
; -------------
cont: mov ds, ax
mov ss, ax ; stack and BP-relative moves up, too
mov [drive], dl ; BIOS passes drive number in DL
mov si, msg_LoadFreeDOS
call print ; modifies AX BX SI
; -------------
; CALCPARAMS: figure out where FAT and DATA area starts
; (modifies EAX EDX, sets fat_start and data_start variables)
calc_params: xor eax, eax
mov [fat_sector], eax ; init buffer status
; first, find fat_start:
mov ax, [bsResSectors] ; no movzx eax, word... needed
add eax, [nHidden]
mov [fat_start], eax ; first FAT sector
mov [data_start], eax ; (only first part of value)
; next, find data_start:
mov eax, [bsFATs] ; no movzx ... byte needed:
; the 2 dw after the bsFATs db are 0 by FAT32 definition :-).
imul dword [xsectPerFat] ; (also changes edx)
add [data_start], eax ; first DATA sector
; (adding in RAM is shorter!)
; finally, find fat_secshift:
mov ax, 512 ; default sector size (means default shift)
; shift = log2(secSize) - log2(fatEntrySize)
;--- mov cl, 9-2 ; shift is 7 for 512 bytes per sector
fatss_scan: cmp ax, [bsBytesPerSec]
jz fatss_found
add ax,ax
;--- inc cx
inc word [fat_secshift] ;XXX ; initially 9-2 (byte!)
jmp short fatss_scan ; try other sector sizes
fatss_found:
;--- mov [fat_secshift], cl
; -------------
; FINDFILE: Searches for the file in the root directory.
; Returns: EAX = first cluster of file
mov eax, [xrootClst] ; root dir cluster
ff_next_clust: push eax ; save cluster
call convert_cluster
jc boot_error ; EOC encountered
; EDX is clust/sector, EAX is sector
ff_next_sector: mov bx, LOADSEG
mov es, bx
sub bx, bx ; load to loadseg:0
call readDisk
;--- push eax ; save sector
;--- xor ax, ax ; first dir. entry in this sector
xor di, di ;XXX
; Search for KERNEL.SYS file name, and find start cluster.
ff_next_entry: mov cx, 11
mov si, filename
;--- mov di, ax
repe cmpsb
jz ff_done ; note that di now is at dirent+11
;--- add ax, 0x20 ; next directory entry
;--- cmp ax, [bsBytesPerSec] ; end of sector reached?
add di, byte 0x20 ;XXX
and di, byte -0x20 ; 0xffe0 ;XXX
cmp di, [bsBytesPerSec] ;XXX
jnz ff_next_entry
;--- pop eax ; restore sector
dec dx ; next sector in cluster
jnz ff_next_sector
ff_walk_fat: pop eax ; restore current cluster
call next_cluster ; find next cluster
jmp ff_next_clust
ff_done: push word [es:di+0x14-11] ; get cluster number HI
push word [es:di+0x1A-11] ; get cluster number LO
pop eax ; convert to 32bit
sub bx, bx ; ES points to LOADSEG
; (kernel -> ES:BX)
; -------------
read_kernel: push eax
call convert_cluster
jc boot_success ; EOC encountered - done
; EDX is sectors in cluster, EAX is sector
rk_in_cluster: call readDisk
dec dx
jnz rk_in_cluster ; loop over sect. in cluster
rk_walk_fat: pop eax
call next_cluster
jmp read_kernel
;-----------------------------------------------------------------------
boot_success: mov bl, [drive]
jmp word LOADSEG:0
;-----------------------------------------------------------------------
boot_error: mov si, msg_BootError
call print ; modifies AX BX SI
wait_key: xor ah,ah
int 0x16 ; wait for a key
reboot: int 0x19 ; reboot the machine
;-----------------------------------------------------------------------
; given a cluster number, find the number of the next cluster in
; the FAT chain. Needs fat_secshift and fat_start.
; input: EAX - cluster
; output: EAX - next cluster
next_cluster: push es
push di
push bx
mov di, ax
shl di, 2 ; 32bit FAT
push ax
mov ax, [bsBytesPerSec]
dec ax
and di, ax ; mask to sector size
pop ax
shr eax, 7 ; e.g. 9-2 for 512 by/sect.
fat_afterss: ; selfmodifying code: previous byte is patched!
; (to hold the fat_secshift value)
add eax, [fat_start] ; absolute sector number now
mov bx, FATSEG
mov es, bx
sub bx, bx
cmp eax, [fat_sector] ; already buffered?
jz cn_buffered
mov [fat_sector],eax ; number of buffered sector
call readDisk
cn_buffered: and byte [es:di+3],0x0f ; mask out top 4 bits
mov eax, [es:di] ; read next cluster number
pop bx
pop di
pop es
ret
;-----------------------------------------------------------------------
; Convert cluster number to the absolute sector number
; ... or return carry if EndOfChain! Needs data_start.
; input: EAX - target cluster
; output: EAX - absolute sector
; EDX - [bsSectPerClust] (byte)
; carry clear
; (if carry set, EAX/EDX unchanged, end of chain)
convert_cluster:
cmp eax, 0x0ffffff8 ; if end of cluster chain...
jnb end_of_chain
; sector = (cluster-2) * clustersize + data_start
dec eax
dec eax
movzx edx, byte [bsSecPerClust]
push edx
mul edx
pop edx
add eax, [data_start]
; here, carry is unset (unless parameters are wrong)
ret
end_of_chain: stc ; indicate EOC by carry
ret
;-----------------------------------------------------------------------
; PRINT - prints string DS:SI
; modifies AX BX SI
printchar: xor bx, bx ; video page 0
mov ah, 0x0e ; print it
int 0x10 ; via TTY mode
print: lodsb ; get token
cmp al, 0 ; end of string?
jne printchar ; until done
ret ; return to caller
;-----------------------------------------------------------------------
; Read a sector from disk, using LBA
; input: EAX - 32-bit DOS sector number
; ES:BX - destination buffer
; (will be filled with 1 sector of data)
; output: ES:BX points one byte after the last byte read.
; EAX - next sector
readDisk: push dx
push si
push di
read_next: push eax ; would ax be enough?
mov di, sp ; remember parameter block end
;--- db 0x66 ; operand size override (push dword)
push byte 0 ;XXX ; other half of the 32 bits at [C]
; (did not trust "o32 push byte 0" opcode)
push byte 0 ; [C] sector number high 32bit
push eax ; [8] sector number low 32bit
push es ; [6] buffer segment
push bx ; [4] buffer offset
push byte 1 ; [2] 1 sector (word)
push byte 16 ; [0] size of parameter block (word)
mov si, sp
mov dl, [drive]
mov ah, 42h ; disk read
int 0x13
mov sp, di ; remove parameter block from stack
; (without changing flags!)
pop eax ; would ax be enough?
jnc read_ok ; jump if no error
push ax ; !!
xor ah, ah ; else, reset and retry
int 0x13
pop ax ; !!
jmp read_next
read_ok: inc eax ; next sector
add bx, word [bsBytesPerSec]
jnc no_incr_es ; if overflow...
mov dx, es
add dh, 0x10 ; ...add 1000h to ES
mov es, dx
no_incr_es: pop di
pop si
pop dx
ret
;-----------------------------------------------------------------------
msg_LoadFreeDOS db "Loading FreeDOS ",0
msg_BootError db "No "
; currently, only "kernel.sys not found" gives a message,
; but read errors in data or root or fat sectors do not.
filename db "KERNEL SYS"
msg_BootErrorPart2:
db " ???",0
times 0x01fa-$+$$ db 0
mystack dw 0x7c00 ; the 0 for SS overlaps into sign!
; (so we can LSS SP to 0:7c00)
sign dw 0, 0xAA55
; Win9x uses all 4 bytes as magic value here.

View File

@ -7,19 +7,22 @@
!include "..\mkfiles\generic.mak" !include "..\mkfiles\generic.mak"
production: b_fat12.bin b_fat16.bin b_fat32.bin production: fat12com.bin fat16com.bin fat32chs.bin fat32lba.bin
b_fat12.bin: boot.asm fat12com.bin: boot.asm
$(NASM) -dISFAT12 boot.asm -ob_fat12.bin $(NASM) -dISFAT12 boot.asm -ofat12com.bin
b_fat16.bin: boot.asm fat16com.bin: boot.asm
$(NASM) -dISFAT16 boot.asm -ob_fat16.bin $(NASM) -dISFAT16 boot.asm -ofat16com.bin
b_fat32.bin: boot32.asm fat32chs.bin: boot32.asm
$(NASM) boot32.asm -ob_fat32.bin $(NASM) boot32.asm -ofat32chs.bin
fat32lba.bin: boot32lb.asm
$(NASM) boot32lb.asm -ofat32lba.bin
clobber: clean clobber: clean
-$(RM) b_fat12.bin b_fat16.bin b_fat32.bin status.me -$(RM) *.bin status.me
clean: clean:
-$(RM) *.lst *.map *.bak *.obj -$(RM) *.lst *.map *.bak *.obj

View File

@ -25,14 +25,17 @@ bin2c.com: bin2c.c
..\bin\sys.com: sys.com ..\bin\sys.com: sys.com
copy sys.com ..\bin copy sys.com ..\bin
b_fat12.h: ..\boot\b_fat12.bin bin2c.com fat12com.h: ..\boot\fat12com.bin bin2c.com
.\bin2c ..\boot\b_fat12.bin b_fat12.h b_fat12 .\bin2c ..\boot\fat12com.bin fat12com.h fat12com
b_fat16.h: ..\boot\b_fat16.bin bin2c.com fat16com.h: ..\boot\fat16com.bin bin2c.com
.\bin2c ..\boot\b_fat16.bin b_fat16.h b_fat16 .\bin2c ..\boot\fat16com.bin fat16com.h fat16com
b_fat32.h: ..\boot\b_fat32.bin bin2c.com fat32chs.h: ..\boot\fat32chs.bin bin2c.com
.\bin2c ..\boot\b_fat32.bin b_fat32.h b_fat32 .\bin2c ..\boot\fat32chs.bin fat32chs.h fat32chs
fat32lba.h: ..\boot\fat32lba.bin bin2c.com
.\bin2c ..\boot\fat32lba.bin fat32lba.h fat32lba
prf.obj: ..\kernel\prf.c prf.obj: ..\kernel\prf.c
$(CC) $(CFLAGS) ..\kernel\prf.c $(CC) $(CFLAGS) ..\kernel\prf.c
@ -43,12 +46,12 @@ sys.com: $(SYS_EXE_dependencies)
$(CL) $(CFLAGST) $(TINY) $(SYS_EXE_dependencies) $(CL) $(CFLAGST) $(TINY) $(SYS_EXE_dependencies)
clobber: clean clobber: clean
-$(RM) bin2c.com sys.com b_fat12.h b_fat16.h b_fat32.h -$(RM) bin2c.com sys.com fat*.h
clean: clean:
-$(RM) *.obj *.bak *.crf *.xrf *.map *.lst *.las *.cod *.err status.me -$(RM) *.obj *.bak *.crf *.xrf *.map *.lst *.las *.cod *.err status.me
# *Individual File Dependencies* # *Individual File Dependencies*
sys.obj: sys.c ..\hdr\portab.h ..\hdr\device.h b_fat12.h b_fat16.h b_fat32.h sys.obj: sys.c ..\hdr\portab.h ..\hdr\device.h fat12com.h fat16com.h fat32chs.h fat32lba.h
$(CC) $(CFLAGS) $*.c $(CC) $(CFLAGS) $*.c

398
sys/sys.c
View File

@ -26,16 +26,10 @@
***************************************************************/ ***************************************************************/
/*
TE thinks, that the boot info storage should be done by FORMAT, noone else
unfortunately, that doesn't work ???
*/
#define STORE_BOOT_INFO
#define DEBUG #define DEBUG
/* #define DDEBUG */ /* #define DDEBUG */
#define SYS_VERSION "v2.6" #define SYS_VERSION "v2.7"
#include <stdlib.h> #include <stdlib.h>
#include <dos.h> #include <dos.h>
@ -53,13 +47,25 @@
#endif #endif
#define SYS_MAXPATH 260 #define SYS_MAXPATH 260
#include "portab.h" #include "portab.h"
#include "algnbyte.h"
#include "device.h"
#include "dcb.h"
#include "xstructs.h"
#include "date.h"
#include "../hdr/time.h"
#include "fat.h"
/* These definitions deliberately put here instead of
* #including <stdio.h> to make executable MUCH smaller
*/
extern WORD CDECL printf(CONST BYTE * fmt, ...); extern WORD CDECL printf(CONST BYTE * fmt, ...);
extern WORD CDECL sprintf(BYTE * buff, CONST BYTE * fmt, ...); extern WORD CDECL sprintf(BYTE * buff, CONST BYTE * fmt, ...);
#include "b_fat12.h" #include "fat12com.h"
#include "b_fat16.h" #include "fat16com.h"
#ifdef WITHFAT32 #ifdef WITHFAT32
#include "b_fat32.h" #include "fat32chs.h"
#include "fat32lba.h"
#endif #endif
#ifndef __WATCOMC__ #ifndef __WATCOMC__
@ -68,7 +74,9 @@ extern WORD CDECL sprintf(BYTE * buff, CONST BYTE * fmt, ...);
#else #else
int unlink(const char *pathname); extern long filelength(int __handle);
extern int unlink(const char *pathname);
/* some non-conforming functions to make the executable smaller */ /* some non-conforming functions to make the executable smaller */
int open(const char *pathname, int flags, ...) int open(const char *pathname, int flags, ...)
{ {
@ -134,18 +142,12 @@ char *getenv(const char *name)
BYTE pgm[] = "SYS"; BYTE pgm[] = "SYS";
void put_boot(COUNT, BYTE *, BOOL); void put_boot(COUNT, BYTE *, BOOL);
BOOL check_space(COUNT, BYTE *); BOOL check_space(COUNT, ULONG);
BOOL copy(COUNT drive, BYTE * srcPath, BYTE * rootPath, BYTE * file); BOOL copy(COUNT drive, BYTE * srcPath, BYTE * rootPath, BYTE * file);
COUNT DiskRead(WORD, WORD, WORD, WORD, WORD, BYTE FAR *);
COUNT DiskWrite(WORD, WORD, WORD, WORD, WORD, BYTE FAR *);
#define SEC_SIZE 512 #define SEC_SIZE 512
#define COPY_SIZE 0x7e00 #define COPY_SIZE 0x7e00
#ifdef _MSC_VER
#pragma pack(1)
#endif
struct bootsectortype { struct bootsectortype {
UBYTE bsJump[3]; UBYTE bsJump[3];
char OemName[8]; char OemName[8];
@ -167,11 +169,6 @@ struct bootsectortype {
ULONG bsVolumeID; ULONG bsVolumeID;
char bsVolumeLabel[11]; char bsVolumeLabel[11];
char bsFileSysType[8]; char bsFileSysType[8];
char unused[2];
UWORD sysRootDirSecs; /* of sectors root dir uses */
ULONG sysFatStart; /* first FAT sector */
ULONG sysRootDirStart; /* first root directory sector */
ULONG sysDataStart; /* first data sector */
}; };
struct bootsectortype32 { struct bootsectortype32 {
@ -203,13 +200,14 @@ struct bootsectortype32 {
ULONG bsSerialNumber; ULONG bsSerialNumber;
char bsVolumeLabel[11]; char bsVolumeLabel[11];
char bsFileSystemID[8]; char bsFileSystemID[8];
ULONG sysFatStart;
ULONG sysDataStart;
UWORD sysFatSecMask;
UWORD sysFatSecShift;
}; };
UBYTE newboot[SEC_SIZE], oldboot[SEC_SIZE]; /*
* globals needed by put_boot & check_space
*/
enum {FAT12 = 12, FAT16 = 16, FAT32 = 32} fs; /* file system type */
/* static */ struct xfreespace x; /* we make this static to be 0 by default -
this avoids FAT misdetections */
#define SBOFFSET 11 #define SBOFFSET 11
#define SBSIZE (sizeof(struct bootsectortype) - SBOFFSET) #define SBSIZE (sizeof(struct bootsectortype) - SBOFFSET)
@ -217,8 +215,9 @@ UBYTE newboot[SEC_SIZE], oldboot[SEC_SIZE];
/* essentially - verify alignment on byte boundaries at compile time */ /* essentially - verify alignment on byte boundaries at compile time */
struct VerifyBootSectorSize { struct VerifyBootSectorSize {
char failure1[sizeof(struct bootsectortype) == 78 ? 1 : -1]; char failure1[sizeof(struct bootsectortype) == 62 ? 1 : -1];
char failure2[sizeof(struct bootsectortype) == 78 ? 1 : 0]; char failure2[sizeof(struct bootsectortype) == 62 ? 1 : 0];
/* (Watcom has a nice warning for this, by the way) */
}; };
int FDKrnConfigMain(int argc, char **argv); int FDKrnConfigMain(int argc, char **argv);
@ -233,7 +232,7 @@ int main(int argc, char **argv)
BYTE rootPath[4]; /* alternate source path to try if not '\0' */ BYTE rootPath[4]; /* alternate source path to try if not '\0' */
WORD slen; WORD slen;
printf("FreeDOS System Installer " SYS_VERSION "\n\n"); printf("FreeDOS System Installer " SYS_VERSION ", " __DATE__ "\n\n");
if (argc > 1 && memicmp(argv[1], "CONFIG", 6) == 0) if (argc > 1 && memicmp(argv[1], "CONFIG", 6) == 0)
{ {
@ -263,18 +262,15 @@ int main(int argc, char **argv)
if (drivearg == 0) if (drivearg == 0)
{ {
printf("Usage: %s [source] drive: [bootsect [BOTH|BOOTONLY]]\n", pgm); printf(
printf "Usage: %s [source] drive: [bootsect [BOTH]] [BOOTONLY]\n"
(" source = A:,B:,C:\\KERNEL\\BIN\\,etc., or current directory if not given\n"); " source = A:,B:,C:\\KERNEL\\BIN\\,etc., or current directory if not given\n"
printf(" drive = A,B,etc.\n"); " drive = A,B,etc.\n"
printf " bootsect = name of 512-byte boot sector file image for drive:\n"
(" bootsect = name of 512-byte boot sector file image for drive:\n"); " to write to *instead* of real boot sector\n"
printf(" to write to *instead* of real boot sector\n"); " BOTH : write to *both* the real boot sector and the image file\n"
printf " BOOTONLY : do *not* copy kernel / shell, only update boot sector or image\n"
(" BOTH : write to *both* the real boot sector and the image file\n"); "%s CONFIG /help\n", pgm, pgm);
printf
(" BOOTONLY : do *not* copy kernel / shell, only update boot sector or image\n");
printf("%s CONFIG /help\n", pgm);
exit(1); exit(1);
} }
drive = toupper(argv[drivearg][0]) - 'A'; drive = toupper(argv[drivearg][0]) - 'A';
@ -307,34 +303,25 @@ int main(int argc, char **argv)
else else
sprintf(rootPath, "%c:\\", 'A' + srcDrive); sprintf(rootPath, "%c:\\", 'A' + srcDrive);
if ((argc <= drivearg + 2) if (argc > drivearg + 1 && memicmp(argv[drivearg + 1], "BOOTONLY", 8) != 0)
|| (memicmp(argv[drivearg + 2], "BOOTONLY", 8) != 0)) bsFile = argv[drivearg + 1]; /* don't write to file "BOOTONLY" */
{
if (!check_space(drive, oldboot))
{
printf("%s: Not enough space to transfer system files\n", pgm);
exit(1);
}
printf("\nCopying KERNEL.SYS...\n");
if (!copy(drive, srcPath, rootPath, "KERNEL.SYS"))
{
printf("\n%s: cannot copy \"KERNEL.SYS\"\n", pgm);
exit(1);
}
} /* copy kernel */
if (argc > drivearg + 1)
bsFile = argv[drivearg + 1];
printf("\nWriting boot sector...\n"); printf("\nWriting boot sector...\n");
put_boot(drive, bsFile, put_boot(drive, bsFile,
(argc > drivearg + 2) (argc > drivearg + 2)
&& memicmp(argv[drivearg + 2], "BOTH", 4) == 0); && memicmp(argv[drivearg + 2], "BOTH", 4) == 0);
if ((argc <= drivearg + 2) if (argc <= drivearg + (bsFile ? 2 : 1)
|| (memicmp(argv[drivearg + 2], "BOOTONLY", 8) != 0)) || memicmp(argv[drivearg + (bsFile ? 2 : 1)], "BOOTONLY", 8) != 0
&& memicmp(argv[drivearg + (bsFile ? 3 : 2)], "BOOTONLY", 8) != 0)
{ {
printf("\nCopying KERNEL.SYS...\n");
if (!copy(drive, srcPath, rootPath, "KERNEL.SYS"))
{
printf("\n%s: cannot copy \"KERNEL.SYS\"\n", pgm);
exit(1);
} /* copy kernel */
printf("\nCopying COMMAND.COM...\n"); printf("\nCopying COMMAND.COM...\n");
if (!copy(drive, srcPath, rootPath, "COMMAND.COM")) if (!copy(drive, srcPath, rootPath, "COMMAND.COM"))
{ {
@ -350,8 +337,8 @@ int main(int argc, char **argv)
printf("\n%s: cannot copy \"COMMAND.COM\"\n", pgm); printf("\n%s: cannot copy \"COMMAND.COM\"\n", pgm);
exit(1); exit(1);
} }
} } /* copy shell */
} /* copy shell */ }
printf("\nSystem transferred.\n"); printf("\nSystem transferred.\n");
return 0; return 0;
@ -372,7 +359,7 @@ VOID dump_sector(unsigned char far * sec)
} }
for (y = 0; y < 16; y++) for (y = 0; y < 16; y++)
{ {
c = oldboot[x * 16 + y]; c = sec[x * 16 + y];
if (isprint(c)) if (isprint(c))
printf("%c", c); printf("%c", c);
else else
@ -523,16 +510,6 @@ int MyAbsReadWrite(int DosDrive, int count, ULONG sector, void *buffer,
#ifdef __WATCOMC__ #ifdef __WATCOMC__
unsigned getdrivespace(COUNT drive, unsigned *total_clusters);
#pragma aux getdrivespace = \
"mov ah, 0x36" \
"inc dx" \
"int 0x21" \
"mov [si], dx" \
parm [dx] [si] \
modify [bx cx dx] \
value [ax];
unsigned getextdrivespace(void far *drivename, void *buf, unsigned buf_size); unsigned getextdrivespace(void far *drivename, void *buf, unsigned buf_size);
#pragma aux getextdrivespace = \ #pragma aux getextdrivespace = \
"mov ax, 0x7303" \ "mov ax, 0x7303" \
@ -542,18 +519,7 @@ unsigned getextdrivespace(void far *drivename, void *buf, unsigned buf_size);
parm [es dx] [di] [cx] \ parm [es dx] [di] [cx] \
value [ax]; value [ax];
#else #else /* !defined __WATCOMC__ */
unsigned getdrivespace(COUNT drive, unsigned *total_clusters)
{
union REGS regs;
regs.h.ah = 0x36; /* get drive free space */
regs.h.dl = drive + 1; /* 1 = 'A',... */
intdos(&regs, &regs);
*total_clusters = regs.x.dx;
return regs.x.ax;
} /* getdrivespace */
unsigned getextdrivespace(void *drivename, void *buf, unsigned buf_size) unsigned getextdrivespace(void *drivename, void *buf, unsigned buf_size)
{ {
@ -573,20 +539,47 @@ unsigned getextdrivespace(void *drivename, void *buf, unsigned buf_size)
return regs.x.ax == 0x7300 || regs.x.cflag; return regs.x.ax == 0x7300 || regs.x.cflag;
} /* getextdrivespace */ } /* getextdrivespace */
#endif /* defined __WATCOMC__ */
#ifdef __WATCOMC__
/*
* If BIOS has got LBA extensions, after the Int 13h call BX will be 0xAA55.
* If extended disk access functions are supported, bit 0 of CX will be set.
*/
BOOL haveLBA(void); /* return TRUE if we have LBA BIOS, FALSE otherwise */
#pragma aux haveLBA = \
"mov ax, 0x4100" /* IBM/MS Int 13h Extensions - installation check */ \
"mov bx, 0x55AA" \
"mov dl, 0x80" \
"int 0x13" \
"xor ax, ax" \
"cmp bx, 0xAA55" \
"jne quit" \
"and cx, 1" \
"xchg cx, ax" \
"quit:" \
modify [bx cx] \
value [ax];
#else
BOOL haveLBA(void)
{
union REGS r;
r.x.ax = 0x4100;
r.x.bx = 0x55AA;
r.h.dl = 0x80;
int86(0x13, &r, &r);
return r.x.bx == 0xAA55 && r.x.cx & 1;
}
#endif #endif
VOID put_boot(COUNT drive, BYTE * bsFile, BOOL both) VOID put_boot(COUNT drive, BYTE * bsFile, BOOL both)
{ {
ULONG temp;
struct bootsectortype *bs;
#ifdef WITHFAT32 #ifdef WITHFAT32
struct bootsectortype32 *bs32; struct bootsectortype32 *bs32;
#endif #endif
int fs; struct bootsectortype *bs;
char *drivename = "A:\\"; static unsigned char oldboot[SEC_SIZE], newboot[SEC_SIZE];
static unsigned char x[0x40]; /* we make this static to be 0 by default -
this avoids FAT misdetections */
unsigned total_clusters;
#ifdef DEBUG #ifdef DEBUG
printf("Reading old bootsector from drive %c:\n", drive + 'A'); printf("Reading old bootsector from drive %c:\n", drive + 'A');
@ -606,87 +599,58 @@ VOID put_boot(COUNT drive, BYTE * bsFile, BOOL both)
#endif #endif
bs = (struct bootsectortype *)&oldboot; bs = (struct bootsectortype *)&oldboot;
if ((bs->bsFileSysType[4] == '6') && (bs->bsBootSignature == 0x29))
{ {
fs = 16; /* see "FAT: General Overview of On-Disk Format" v1.02, 5.V.1999
} * (http://www.nondot.org/sabre/os/files/FileSystems/FatFormat.pdf)
else */
{ ULONG fatSize, totalSectors, dataSectors, clusters;
fs = 12; UCOUNT rootDirSectors;
}
/* bs32 = (struct bootsectortype32 *)&oldboot;
the above code is not save enough for me (TE), so we change the rootDirSectors = (bs->bsRootDirEnts * DIRENT_SIZE /* 32 */
FS detection method to GetFreeDiskSpace(). + bs32->bsBytesPerSec - 1) / bs32->bsBytesPerSec;
this should work, as the disk was writeable, so GetFreeDiskSpace should work. fatSize = bs32->bsFATsecs ? bs32->bsFATsecs : bs32->bsBigFatSize;
*/ totalSectors = bs32->bsSectors ? bs32->bsSectors : bs32->bsHugeSectors;
dataSectors = totalSectors
- bs32->bsResSectors - (bs32->bsFATs * fatSize) - rootDirSectors;
clusters = dataSectors / bs32->bsSecPerClust;
/* would work different when reading from an image */ if (clusters < FAT_MAGIC) /* < 4085 */
if (getdrivespace(drive, &total_clusters) == 0xffff) fs = FAT12;
{ else if (clusters < FAT_MAGIC16) /* < 65525 */
printf("can't get free disk space for %c:\n", drive + 'A'); fs = FAT16;
exit(1);
}
if (total_clusters <= 0xff6)
{
if (fs != 12)
printf("warning : new detection overrides old detection\a\n");
fs = 12;
}
else
{
if (fs != 16)
printf("warning : new detection overrides old detection\a\n");
fs = 16;
/* fs = 16/32.
we don't want to crash a FAT32 drive
*/
drivename[0] = 'A' + drive;
/* would also work different when reading from an image */
if (getextdrivespace(drivename, x, sizeof(x)))
/* error --> no Win98 --> no FAT32 */
{
printf("get extended drive space not supported --> no FAT32\n");
}
else else
{ fs = FAT32;
if (*(unsigned long *)(x + 0x10) /* total number of clusters */
> (unsigned)65526l)
{
fs = 32;
}
}
} }
if (fs == 16) if (bs->bsBytesPerSec != SEC_SIZE)
{ {
memcpy(newboot, b_fat16, SEC_SIZE); /* copy FAT16 boot sector */ printf("Sector size is not 512 but %d bytes - not currently supported!\n",
printf("FAT type: FAT16\n"); bs->bsBytesPerSec);
exit(1); /* Japan?! */
} }
else if (fs == 12)
{ if (fs == FAT32)
memcpy(newboot, b_fat12, SEC_SIZE); /* copy FAT12 boot sector */
printf("FAT type: FAT12\n");
}
else
{ {
printf("FAT type: FAT32\n"); printf("FAT type: FAT32\n");
#ifdef WITHFAT32 #ifdef WITHFAT32 /* copy one of the FAT32 boot sectors */
memcpy(newboot, b_fat32, SEC_SIZE); /* copy FAT32 boot sector */ memcpy(newboot, haveLBA() ? fat32lba : fat32chs, SEC_SIZE);
#else #else
printf("SYS hasn't been compiled with FAT32 support."); printf("SYS hasn't been compiled with FAT32 support.\n"
printf("Consider using -DWITHFAT32 option.\n"); "Consider using -DWITHFAT32 option.\n");
exit(1); exit(1);
#endif #endif
} }
else
{ /* copy the FAT12/16 CHS+LBA boot sector */
printf("FAT type: FAT1%c\n", fs + '0' - 10);
memcpy(newboot, fs == FAT16 ? fat16com : fat12com, SEC_SIZE);
}
/* Copy disk parameter from old sector to new sector */ /* Copy disk parameter from old sector to new sector */
#ifdef WITHFAT32 #ifdef WITHFAT32
if (fs == 32) if (fs == FAT32)
memcpy(&newboot[SBOFFSET], &oldboot[SBOFFSET], SBSIZE32); memcpy(&newboot[SBOFFSET], &oldboot[SBOFFSET], SBSIZE32);
else else
#endif #endif
@ -697,70 +661,30 @@ VOID put_boot(COUNT drive, BYTE * bsFile, BOOL both)
memcpy(bs->OemName, "FreeDOS ", 8); memcpy(bs->OemName, "FreeDOS ", 8);
#ifdef WITHFAT32 #ifdef WITHFAT32
if (fs == 32) if (fs == FAT32)
{ {
bs32 = (struct bootsectortype32 *)&newboot; bs32 = (struct bootsectortype32 *)&newboot;
temp = bs32->bsHiddenSecs + bs32->bsResSectors;
bs32->sysFatStart = temp;
bs32->sysDataStart = temp + bs32->bsBigFatSize * bs32->bsFATs;
bs32->sysFatSecMask = bs32->bsBytesPerSec / 4 - 1;
temp = bs32->sysFatSecMask + 1;
for (bs32->sysFatSecShift = 0; temp != 1;
bs32->sysFatSecShift++, temp >>= 1) ;
/* put 0 for A: or B: (force booting from A:), otherwise use DL */ /* put 0 for A: or B: (force booting from A:), otherwise use DL */
bs32->bsDriveNumber = drive < 2 ? 0 : 0xff; bs32->bsDriveNumber = drive < 2 ? 0 : 0xff;
}
#ifdef DEBUG #ifdef DEBUG
if (fs == 32) printf(" FAT starts at sector %lx + %x\n",
{
printf("FAT starts at sector %lx = (%lx + %x)\n", bs32->sysFatStart,
bs32->bsHiddenSecs, bs32->bsResSectors); bs32->bsHiddenSecs, bs32->bsResSectors);
printf("DATA starts at sector %lx\n", bs32->sysDataStart);
}
#endif #endif
}
else else
#endif #endif
{ {
#ifdef STORE_BOOT_INFO
/* TE thinks : never, see above */
/* temporary HACK for the load segment (0x0060): it is in unused */
/* only needed for older kernels */
*((UWORD *) (bs->unused)) =
*((UWORD *) (((struct bootsectortype *)&b_fat16)->unused));
/* end of HACK */
/* root directory sectors */
bs->sysRootDirSecs = bs->bsRootDirEnts / 16;
/* sector FAT starts on */
temp = bs->bsHiddenSecs + bs->bsResSectors;
bs->sysFatStart = temp;
/* sector root directory starts on */
temp = temp + bs->bsFATsecs * bs->bsFATs;
bs->sysRootDirStart = temp;
/* sector data starts on */
temp = temp + bs->sysRootDirSecs;
bs->sysDataStart = temp;
/* put 0 for A: or B: (force booting from A:), otherwise use DL */ /* put 0 for A: or B: (force booting from A:), otherwise use DL */
bs->bsDriveNumber = drive < 2 ? 0 : 0xff; bs->bsDriveNumber = drive < 2 ? 0 : 0xff;
} }
#ifdef DEBUG /* add an option to display this on user request? */ #ifdef DEBUG /* add an option to display this on user request? */
printf("Root dir entries = %u\n", bs->bsRootDirEnts); printf("Root dir entries = %u\n", bs->bsRootDirEnts);
printf("Root dir sectors = %u\n", bs->sysRootDirSecs);
printf("FAT starts at sector %lu = (%lu + %u)\n", bs->sysFatStart, printf("FAT starts at sector (%lu + %u)\n",
bs->bsHiddenSecs, bs->bsResSectors); bs->bsHiddenSecs, bs->bsResSectors);
printf("Root directory starts at sector %lu = (PREVIOUS + %u * %u)\n", printf("Root directory starts at sector (PREVIOUS + %u * %u)\n",
bs->sysRootDirStart, bs->bsFATsecs, bs->bsFATs); bs->bsFATsecs, bs->bsFATs);
printf("DATA starts at sector %lu = (PREVIOUS + %u)\n", bs->sysDataStart,
bs->sysRootDirSecs);
#endif
#endif #endif
#ifdef DDEBUG #ifdef DDEBUG
@ -812,15 +736,34 @@ VOID put_boot(COUNT drive, BYTE * bsFile, BOOL both)
} /* put_boot */ } /* put_boot */
BOOL check_space(COUNT drive, BYTE * BlkBuffer) /*
* Returns TRUE if `drive` has at least `bytes` free space, FALSE otherwise.
* put_sector() must have been already called to determine file system type.
*/
BOOL check_space(COUNT drive, ULONG bytes)
{ {
/* this should check, if on destination is enough space #ifdef WITHFAT32
to hold command.com+ kernel.sys */ if (fs == FAT32)
{
UNREFERENCED_PARAMETER(drive); char *drivename = "A:\\";
UNREFERENCED_PARAMETER(BlkBuffer); drivename[0] = 'A' + drive;
getextdrivespace(drivename, &x, sizeof(x));
return TRUE; return x.xfs_freeclusters > (bytes / (x.xfs_clussize * x.xfs_secsize));
}
else
#endif
{
#ifdef __TURBOC__
struct dfree df;
getdfree(drive + 1, &df);
return (ULONG)df.df_avail * df.df_sclus * df.df_bsec >= bytes;
#else
struct _diskfree_t df;
_dos_getdiskfree(drive + 1, &df);
return (ULONG)df.avail_clusters * df.sectors_per_cluster
* df.bytes_per_sector >= bytes;
#endif
}
} /* check_space */ } /* check_space */
@ -859,7 +802,7 @@ BOOL copy(COUNT drive, BYTE * srcPath, BYTE * rootPath, BYTE * file)
truename(dest, source); truename(dest, source);
strcpy(source, dest); strcpy(source, dest);
sprintf(dest, "%c:\\%s", 'A' + drive, file); sprintf(dest, "%c:\\%s", 'A' + drive, file);
if (strcmp(source, dest) == 0) if (stricmp(source, dest) == 0)
{ {
printf("%s: source and destination are identical: skipping \"%s\"\n", printf("%s: source and destination are identical: skipping \"%s\"\n",
pgm, source); pgm, source);
@ -872,6 +815,13 @@ BOOL copy(COUNT drive, BYTE * srcPath, BYTE * rootPath, BYTE * file)
return FALSE; return FALSE;
} }
if (!check_space(drive, filelength(fdin)))
{
printf("%s: Not enough space to transfer %s\n", pgm, file);
close(fdin);
exit(1);
}
if ((fdout = if ((fdout =
open(dest, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, open(dest, O_RDWR | O_TRUNC | O_CREAT | O_BINARY,
S_IREAD | S_IWRITE)) < 0) S_IREAD | S_IWRITE)) < 0)
@ -893,25 +843,22 @@ BOOL copy(COUNT drive, BYTE * srcPath, BYTE * rootPath, BYTE * file)
copied += ret; copied += ret;
} }
#ifdef __TURBOC__
{
struct ftime ftime;
getftime(fdin, &ftime);
setftime(fdout, &ftime);
}
#endif
#ifdef __WATCOMC__
{ {
#if defined __WATCOMC__ || defined _MSC_VER /* || defined __BORLANDC__ */
unsigned short date, time; unsigned short date, time;
_dos_getftime(fdin, &date, &time); _dos_getftime(fdin, &date, &time);
_dos_setftime(fdout, date, time); _dos_setftime(fdout, date, time);
} #elif defined __TURBOC__
struct ftime ftime;
getftime(fdin, &ftime);
setftime(fdout, &ftime);
#endif #endif
}
close(fdin); close(fdin);
close(fdout); close(fdout);
#ifdef _MSV_VER #ifdef __SOME_OTHER_COMPILER__
{ {
#include <utime.h> #include <utime.h>
struct utimbuf utimb; struct utimbuf utimb;
@ -920,7 +867,6 @@ BOOL copy(COUNT drive, BYTE * srcPath, BYTE * rootPath, BYTE * file)
utimb.modtime = fstatbuf.st_mtime; /* modification time */ utimb.modtime = fstatbuf.st_mtime; /* modification time */
utime(dest, &utimb); utime(dest, &utimb);
}; };
#endif #endif
printf("%lu Bytes transferred", copied); printf("%lu Bytes transferred", copied);