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 ??
jne dont_use_dl
mov [drive], dl ; BIOS passes drive number in DL
; a reset should not be needed here ; 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
@ -96,17 +95,58 @@ real_start: cld
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

394
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;
}
else
{
fs = 12;
}
/*
the above code is not save enough for me (TE), so we change the
FS detection method to GetFreeDiskSpace().
this should work, as the disk was writeable, so GetFreeDiskSpace should work.
*/
/* would work different when reading from an image */
if (getdrivespace(drive, &total_clusters) == 0xffff)
{ {
printf("can't get free disk space for %c:\n", drive + 'A'); /* see "FAT: General Overview of On-Disk Format" v1.02, 5.V.1999
exit(1); * (http://www.nondot.org/sabre/os/files/FileSystems/FatFormat.pdf)
}
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
*/ */
ULONG fatSize, totalSectors, dataSectors, clusters;
UCOUNT rootDirSectors;
drivename[0] = 'A' + drive; bs32 = (struct bootsectortype32 *)&oldboot;
/* would also work different when reading from an image */ rootDirSectors = (bs->bsRootDirEnts * DIRENT_SIZE /* 32 */
if (getextdrivespace(drivename, x, sizeof(x))) + bs32->bsBytesPerSec - 1) / bs32->bsBytesPerSec;
/* error --> no Win98 --> no FAT32 */ fatSize = bs32->bsFATsecs ? bs32->bsFATsecs : bs32->bsBigFatSize;
{ totalSectors = bs32->bsSectors ? bs32->bsSectors : bs32->bsHugeSectors;
printf("get extended drive space not supported --> no FAT32\n"); dataSectors = totalSectors
} - bs32->bsResSectors - (bs32->bsFATs * fatSize) - rootDirSectors;
clusters = dataSectors / bs32->bsSecPerClust;
if (clusters < FAT_MAGIC) /* < 4085 */
fs = FAT12;
else if (clusters < FAT_MAGIC16) /* < 65525 */
fs = FAT16;
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);