From 3662f1f7209f7f33a6e873f3c9947bce30451ab8 Mon Sep 17 00:00:00 2001 From: Brian Palmer Date: Thu, 15 Nov 2001 07:48:33 +0000 Subject: [PATCH] BIOS Int 13h Extensions Support New .ini file format (sort of) - changed some parameter names, etc. More efficient .ini file parsing code More efficient use of memory, smaller image file Total rewrite of file system code (the old stuff sucked) VFAT Long File Names now supported! ReactOS is the only boot type supported currently, disabled all others (temporarily) svn path=/trunk/; revision=2372 --- freeldr/FREELDR.INI | 34 +- freeldr/Makefile | 12 +- freeldr/bootsect/Makefile | 13 +- freeldr/bootsect/fat.asm | 33 +- freeldr/bootsect/fat32.asm | 443 ++++++++----- freeldr/freeldr/Makefile | 19 +- freeldr/freeldr/asmcode.S | 215 ++++++- freeldr/freeldr/asmcode.h | 15 +- freeldr/freeldr/debug.c | 121 ++-- freeldr/freeldr/debug.h | 49 +- freeldr/freeldr/fat.c | 1163 +++++++++++++++++++++++++++++++++++ freeldr/freeldr/fat.h | 179 ++++++ freeldr/freeldr/freeldr.c | 171 +++-- freeldr/freeldr/freeldr.h | 32 +- freeldr/freeldr/fs.c | 588 ++++++++++-------- freeldr/freeldr/fs.h | 221 +++---- freeldr/freeldr/fs_fat.c | 541 ---------------- freeldr/freeldr/linux.c | 4 +- freeldr/freeldr/memory.c | 80 ++- freeldr/freeldr/menu.c | 455 ++++++++++---- freeldr/freeldr/menu.h | 6 +- freeldr/freeldr/miscboot.c | 25 +- freeldr/freeldr/multiboot.c | 17 +- freeldr/freeldr/options.c | 21 +- freeldr/freeldr/oslist.c | 251 ++++++++ freeldr/freeldr/oslist.h | 28 + freeldr/freeldr/parseini.c | 220 ++++--- freeldr/freeldr/parseini.h | 11 +- freeldr/freeldr/reactos.c | 52 +- freeldr/freeldr/stdlib.c | 17 +- freeldr/freeldr/stdlib.h | 16 +- freeldr/freeldr/tui.c | 226 +++++-- freeldr/freeldr/tui.h | 24 +- freeldr/notes.txt | 27 +- 34 files changed, 3629 insertions(+), 1700 deletions(-) create mode 100644 freeldr/freeldr/fat.c create mode 100644 freeldr/freeldr/fat.h delete mode 100644 freeldr/freeldr/fs_fat.c create mode 100644 freeldr/freeldr/oslist.c create mode 100644 freeldr/freeldr/oslist.h diff --git a/freeldr/FREELDR.INI b/freeldr/FREELDR.INI index c54291dd8de..a10095effdd 100644 --- a/freeldr/FREELDR.INI +++ b/freeldr/FREELDR.INI @@ -71,9 +71,20 @@ [FREELOADER] MessageLine=Welcome to FreeLoader! -MessageLine=Copyright (c) 2000 by Brian Palmer +MessageLine=Copyright (c) 2001 by Brian Palmer MessageLine= MessageBox=Edit your FREELDR.INI file to change your boot settings. +OS=ReactOS (HD) +OS=ReactOS (Floppy) +#OS=ReactOS (Debug) +#OS=Linux +OS=3« Floppy (A:) +OS=Microsoft Windows (C:) +OS=Drive D: +DefaultOS=ReactOS (Floppy) +TimeOut=10 + +[Display] TitleText=Boot Menu StatusBarColor=Cyan StatusBarTextColor=Black @@ -89,18 +100,11 @@ MenuColor=Blue TextColor=Yellow SelectedTextColor=Black SelectedColor=Gray -OS=ReactOS (HD) -OS=ReactOS (Floppy) -#OS=ReactOS (Debug) -#OS=Linux -OS=3« Floppy (A:) -OS=Microsoft Windows (C:) -OS=Drive D: -#TimeOut=0 # Load ReactOS from harddisk (drive C:) # - does not work on large harddisks [ReactOS (HD)] +Name="ReactOS (HardDrive)" BootType=ReactOS SystemPath=multi(0)disk(0)rdisk(0)partition(1)\reactos Options=/DEBUGPORT=SCREEN @@ -110,14 +114,16 @@ Driver=VFATFS.SYS # Load ReactOS from floppy (drive A:) [ReactOS (Floppy)] +Name="ReactOS (Floppy)" BootType=ReactOS SystemPath=multi(0)disk(0)fdisk(0) Options=/DEBUGPORT=SCREEN -Kernel=NTOSKRNL.EXE -Driver=IDE.SYS -Driver=VFATFS.SYS +Kernel=\reactos\NTOSKRNL.EXE +Driver=\reactos\IDE.SYS +Driver=\reactos\VFATFS.SYS #[ReactOS (Debug)] +#Name="ReactOS (Debug)" #BootType=ReactOS #BootDrive=0 #Options=/DEBUG /DEBUGPORT=COM1 /BAUDRATE=19200 @@ -126,20 +132,24 @@ Driver=VFATFS.SYS #Driver=\DRIVERS\VFATFS.SYS #[Linux] +#Name="Linux" # Linux boot type not implemented yet #BootType=Partition #BootDrive=0x80 #BootPartition=2 [3« Floppy (A:)] +Name="3« Floppy (A:)" BootType=Drive BootDrive=0 [Microsoft Windows (C:)] +Name="Microsoft Windows (C:)" BootType=Drive BootDrive=0x80 [Drive D:] +Name="Drive D:" BootType=Partition BootDrive=0x81 BootPartition=1 diff --git a/freeldr/Makefile b/freeldr/Makefile index 63239b0613a..fa8a21a52b2 100644 --- a/freeldr/Makefile +++ b/freeldr/Makefile @@ -18,13 +18,13 @@ # -export CC = gcc -export LD = ld -export AR = ar -export RM = cmd /C del -export CP = cmd /C copy +export CC = gcc +export LD = ld +export AR = ar +export RM = cmd /C del +export CP = cmd /C copy export NASM_CMD = nasm -export MAKE = make +export MAKE = make .PHONY : bootsect freeldr install clean diff --git a/freeldr/bootsect/Makefile b/freeldr/bootsect/Makefile index a0c5f8dcbf6..ebde83fa865 100644 --- a/freeldr/bootsect/Makefile +++ b/freeldr/bootsect/Makefile @@ -17,13 +17,12 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # - -export CC = gcc -export LD = ld -export AR = ar -export RM = cmd /C del -export CP = cmd /C copy -export NASM_CMD = nasm +export CC = gcc +export LD = ld +export AR = ar +export RM = cmd /C del +export CP = cmd /C copy +export NASM_CMD = nasm .PHONY : clean diff --git a/freeldr/bootsect/fat.asm b/freeldr/bootsect/fat.asm index ce440069176..c541c935989 100644 --- a/freeldr/bootsect/fat.asm +++ b/freeldr/bootsect/fat.asm @@ -256,7 +256,7 @@ Done: msgDiskError db 'Disk error',0dh,0ah,0 msgFreeLdr db 'FREELDR.SYS not found',0dh,0ah,0 -msgAnyKey db 'Press any key to continue.',0dh,0ah,0 +msgAnyKey db 'Press any key to restart',0dh,0ah,0 filename db 'FREELDR SYS' times 510-($-$$) db 0 ; Pad to 510 bytes @@ -272,11 +272,34 @@ filename db 'FREELDR SYS' LoadFile: + + push ax ; First save AX - the start cluster of freeldr.sys + + + ; Lets save the contents of the screen + ; from B800:0000 to 9000:8000 + push ds + mov ax,0b800h + mov ds,ax + xor si,si + mov ax,9800h + mov es,ax + xor di,di + mov cx,2000 ; Copy 2000 characters [words] (screen is 80x25) + rep movsw ; 2 bytes a character (one is the attribute byte) + pop ds + + mov ah,03h ; AH = 03h + xor bx,bx ; BH = video page + int 10h ; BIOS Int 10h Func 3 - Read Cursor Position and Size + mov [es:di],dx ; DH = row, DL = column + ; Display "Loading FreeLoader..." message - push ax - mov si,msgLoading ; Loading message - call PutChars ; Display it - pop ax + mov si,msgLoading ; Loading message + call PutChars ; Display it + + + pop ax ; Restore AX ; AX has start cluster of freeldr.sys push ax diff --git a/freeldr/bootsect/fat32.asm b/freeldr/bootsect/fat32.asm index cdf935bc941..61264184ee7 100644 --- a/freeldr/bootsect/fat32.asm +++ b/freeldr/bootsect/fat32.asm @@ -2,7 +2,8 @@ ; FAT32 Boot Sector ; Copyright (c) 1998, 2000, 2001 Brian Palmer -org 7c00h +;org 7c00h +org 0 segment .text @@ -14,15 +15,15 @@ start: OEMName db 'FrLdr1.0' BytesPerSector dw 512 -SectsPerCluster db 1 +SectsPerCluster db 0 ReservedSectors dw 32 NumberOfFats db 2 MaxRootEntries dw 0 ; Always zero for FAT32 volumes TotalSectors dw 0 ; Always zero for FAT32 volumes MediaDescriptor db 0f8h SectorsPerFat dw 0 ; Always zero for FAT32 volumes -SectorsPerTrack dw 18 -NumberOfHeads dw 2 +SectorsPerTrack dw 0 +NumberOfHeads dw 0 HiddenSectors dd 0 TotalSectorsBig dd 0 ; FAT32 Inserted Info @@ -44,122 +45,209 @@ FileSystem db 'FAT32 ' main: cli cld + + ; Lets copy ourselves from 0000:7c00 to 9000:0000 + ; and transfer control to the new code + xor ax,ax + mov ds,ax + mov si,7c00h + mov ax,9000h + mov es,ax + xor di,di + mov cx,512 + rep movsb + jmp 0x9000:RealMain + + ; Now we are executing at 9000:xxxx + ; We are now free to load freeldr.sys at 0000:7e00 +RealMain: xor ax,ax - mov ss,ax - mov sp,7c00h ; Setup a stack + mov bp,ax + mov sp,ax ; Setup a stack mov ax,cs ; Setup segment registers mov ds,ax ; Make DS correct mov es,ax ; Make ES correct - - + mov ss,ax ; Make SS correct sti ; Enable ints now - mov [BootDrive],dl ; Save the boot drive - xor ax,ax ; Zero out AX - cmp word [TotalSectors],byte 0x00 ; Check the old 16-bit value of TotalSectors - jnz ErrBoot ; If it is non-zero then exit with an error - cmp word [FSVersion],byte 0x00 ; Check the file system version word - ja ErrBoot ; If it is not zero then exit with an error - ; Reset disk controller - int 13h - jnc LoadExtraBootCode - jmp BadBoot ; Reset failed... +CheckSectorsPerFat: + cmp WORD [BYTE bp+SectorsPerFat],byte 0x00 ; Check the old 16-bit value of SectorsPerFat + jnz CheckFailed ; If it is non-zero then exit with an error +CheckTotalSectors: ; Check the old 16-bit value of TotalSectors & MaxRootEntries + cmp DWORD [BYTE bp+MaxRootEntries],byte 0x00; by comparing the DWORD at offset MaxRootEntries to zero + jnz CheckFailed ; If it is non-zero then exit with an error +CheckFileSystemVersion: + cmp WORD [BYTE bp+FSVersion],byte 0x00 ; Check the file system version word + jna GetDriveParameters ; It is zero, so continue +CheckFailed: + jmp PrintFileSystemError ; If it is not zero then exit with an error + + +GetDriveParameters: + mov ax,0800h + mov dl,[BYTE bp+BootDrive] ; Get boot drive in dl + int 13h ; Request drive parameters from the bios + jnc CalcDriveSize ; If the call succeeded then calculate the drive size + + ; If we get here then the call to the BIOS failed + ; so just set CHS equal to the maximum addressable + ; size + mov cx,0ffffh + mov dh,cl + +CalcDriveSize: + ; Now that we have the drive geometry + ; lets calculate the drive size + mov bl,ch ; Put the low 8-bits of the cylinder count into BL + mov bh,cl ; Put the high 2-bits in BH + shr bh,6 ; Shift them into position, now BX contains the cylinder count + and cl,3fh ; Mask off cylinder bits from sector count + ; CL now contains sectors per track and DH contains head count + movzx eax,dh ; Move the heads into EAX + movzx ebx,bx ; Move the cylinders into EBX + movzx ecx,cl ; Move the sectors per track into ECX + inc eax ; Make it one based because the bios returns it zero based + inc ebx ; Make the cylinder count one based also + mul ecx ; Multiply heads with the sectors per track, result in edx:eax + mul ebx ; Multiply the cylinders with (heads * sectors) [stored in edx:eax already] + + ; We now have the total number of sectors as reported + ; by the bios in eax, so store it in our variable + mov [BiosCHSDriveSize],eax + LoadExtraBootCode: ; First we have to load our extra boot code at - ; sector 14 into memory at [0000:7e00h] - xor dx,dx - mov ax,0eh - add ax,WORD [HiddenSectors] - adc dx,WORD [HiddenSectors+2] ; Add the number of hidden sectors + ; sector 14 into memory at [9000:0200h] + mov eax,0eh + add eax,DWORD [BYTE bp+HiddenSectors] ; Add the number of hidden sectors mov cx,1 - mov bx,7e0h - mov es,bx ; Read sector to [0000:7e00h] - xor bx,bx + mov bx,9000h + mov es,bx ; Read sector to [9000:0200h] + mov bx,0200h call ReadSectors jmp StartSearch - ; Reads logical sectors into [ES:BX] -; DX:AX has logical sector number to read +; EAX has logical sector number to read ; CX has number of sectors to read -; CarryFlag set on error ReadSectors: - push ax - push dx - push cx - xchg ax,cx - xchg ax,dx - xor dx,dx - div WORD [SectorsPerTrack] - xchg ax,cx - div WORD [SectorsPerTrack] ; Divide logical by SectorsPerTrack - inc dx ; Sectors numbering starts at 1 not 0 - xchg cx,dx - div WORD [NumberOfHeads] ; Number of heads - mov dh,dl ; Head to DH, drive to DL - mov dl,[BootDrive] ; Drive number - mov ch,al ; Cylinder in CX - ror ah,1 ; Low 8 bits of cylinder in CH, high 2 bits - ror ah,1 ; in CL shifted to bits 6 & 7 - or cl,ah ; Or with sector number - mov ax,0201h - int 13h ; DISK - READ SECTORS INTO MEMORY + cmp eax,DWORD [BiosCHSDriveSize] ; Check if they are reading a sector within CHS range + jbe ReadSectorsCHS ; Yes - go to the old CHS routine + +ReadSectorsLBA: + pushad ; Save logical sector number & sector count + + o32 push byte 0 + push eax ; Put 64-bit logical block address on stack + push es ; Put transfer segment on stack + push bx ; Put transfer offset on stack + push byte 1 ; Set transfer count to 1 sector + push byte 0x10 ; Set size of packet to 10h + mov si,sp ; Setup disk address packet on stack + +CheckInt13hExtensions: ; Now make sure this computer supports extended reads + mov ah,0x41 ; AH = 41h + mov bx,0x55aa ; BX = 55AAh + mov dl,[BYTE bp+BootDrive] ; DL = drive (80h-FFh) + int 13h ; IBM/MS INT 13 Extensions - INSTALLATION CHECK + jc PrintDiskError ; CF set on error (extensions not supported) + cmp bx,0xaa55 ; BX = AA55h if installed + jne PrintDiskError + test cl,1 ; CX = API subset support bitmap + jz PrintDiskError ; Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported + + + ; Good, we're here so the computer supports LBA disk access + ; So finish the extended read + mov dl,[BYTE bp+BootDrive] ; Drive number + mov ah,42h ; Int 13h, AH = 42h - Extended Read + int 13h ; Call BIOS + jc PrintDiskError ; If the read failed then abort + + add sp,0x10 ; Remove disk address packet from stack + + popad ; Restore sector count & logical sector number + + inc eax ; Increment sector to read + mov dx,es + add dx,byte 20h ; Increment read buffer for next sector + mov es,dx + + loop ReadSectorsLBA ; Read next sector + + ret + + +; Reads logical sectors into [ES:BX] +; EAX has logical sector number to read +; CX has number of sectors to read +ReadSectorsCHS: + pushad + xor edx,edx + movzx ecx,WORD [BYTE bp+SectorsPerTrack] + div ecx ; Divide logical by SectorsPerTrack + inc dl ; Sectors numbering starts at 1 not 0 + mov cl,dl ; Sector in CL + mov edx,eax + shr edx,16 + div WORD [BYTE bp+NumberOfHeads] ; Divide logical by number of heads + mov dh,dl ; Head in DH + mov dl,[BYTE bp+BootDrive] ; Drive number in DL + mov ch,al ; Cylinder in CX + ror ah,1 ; Low 8 bits of cylinder in CH, high 2 bits + ror ah,1 ; in CL shifted to bits 6 & 7 + or cl,ah ; Or with sector number + mov ax,0201h + int 13h ; DISK - READ SECTORS INTO MEMORY ; AL = number of sectors to read, CH = track, CL = sector ; DH = head, DL = drive, ES:BX -> buffer to fill ; Return: CF set on error, AH = status (see AH=01h), AL = number of sectors read - jc BadBoot + jc PrintDiskError ; If the read failed then abort - pop cx - pop dx - pop ax - inc ax ;Increment Sector to Read - jnz NoCarry - inc dx + popad + inc eax ; Increment Sector to Read -NoCarry: - push bx - mov bx,es - add bx,byte 20h - mov es,bx - pop bx - ; Increment read buffer for next sector - loop ReadSectors ; Read next sector + mov dx,es + add dx,byte 20h ; Increment read buffer for next sector + mov es,dx + + loop ReadSectorsCHS ; Read next sector ret -; Displays a bad boot message +; Displays a disk error message ; And reboots -BadBoot: - mov si,msgDiskError ; Bad boot disk message - call PutChars ; Display it - mov si,msgAnyKey ; Press any key message - call PutChars ; Display it +PrintDiskError: + mov si,msgDiskError ; Bad boot disk message + call PutChars ; Display it + mov si,msgAnyKey ; Press any key message + call PutChars ; Display it jmp Reboot -; Displays an error message +; Displays a file system error message ; And reboots -ErrBoot: - mov si,msgFreeLdr ; FreeLdr not found message - call PutChars ; Display it - mov si,msgAnyKey ; Press any key message - call PutChars ; Display it +PrintFileSystemError: + mov si,msgFileSystemError ; FreeLdr not found message + call PutChars ; Display it + mov si,msgAnyKey ; Press any key message + call PutChars ; Display it Reboot: xor ax,ax - int 16h ; Wait for a keypress - int 19h ; Reboot + int 16h ; Wait for a keypress + int 19h ; Reboot PutChars: lodsb @@ -172,10 +260,13 @@ PutChars: Done: retn -msgDiskError db 'Disk error',0dh,0ah,0 -msgFreeLdr db 'FREELDR.SYS not found',0dh,0ah,0 -msgAnyKey db 'Press any key to continue.',0dh,0ah,0 -filename db 'FREELDR SYS' + + +BiosCHSDriveSize dd 0 + +msgDiskError db 'Disk error',0dh,0ah,0 +msgFileSystemError db 'File system error',0dh,0ah,0 +msgAnyKey db 'Press any key to restart',0dh,0ah,0 times 510-($-$$) db 0 ; Pad to 510 bytes dw 0aa55h ; BootSector signature @@ -190,29 +281,27 @@ filename db 'FREELDR SYS' ; systems we must not overwrite anything other than ; the bootsector which means we will have to use ; a different sector like 14 to store our extra boot code -; -; Note: Win2k uses sector 12 for this purpose StartSearch: ; Now we must get the first cluster of the root directory - mov eax,DWORD [RootDirStartCluster] + mov eax,DWORD [BYTE bp+RootDirStartCluster] cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain - jb ContinueSearch ; If not continue, if so BadBoot - jmp ErrBoot + jb ContinueSearch ; If not continue, if so then we didn't find freeldr.sys + jmp PrintFileNotFound ContinueSearch: - mov bx,800h - mov es,bx ; Read cluster to [0000:8000h] + mov bx,7e0h + mov es,bx ; Read cluster to [0000:7e00h] call ReadCluster ; Read the cluster ; Now we have to find our way through the root directory to ; The OSLOADER.SYS file xor bx,bx - mov bl,[SectsPerCluster] + mov bl,[BYTE bp+SectsPerCluster] shl bx,4 ; BX = BX * 512 / 32 - mov ax,800h ; We loaded at 0800:0000 + mov ax,7e0h ; We loaded at 07e0:0000 mov es,ax xor di,di mov si,filename @@ -221,7 +310,7 @@ ContinueSearch: jz FoundFile ; If same we found it dec bx jnz FindFile - jmp ErrBoot + jmp PrintFileNotFound FindFile: mov ax,es ; We didn't find it in the previous dir entry @@ -236,36 +325,67 @@ FindFile: jnz FindFile ; Last entry? ; Get the next root dir cluster and try again until we run out of clusters - mov eax,DWORD [RootDirStartCluster] + mov eax,DWORD [BYTE bp+RootDirStartCluster] call GetFatEntry - mov [RootDirStartCluster],eax + mov [BYTE bp+RootDirStartCluster],eax jmp StartSearch FoundFile: - ; Display "Loading FreeLoader..." message - mov si,msgLoading ; Loading message - call PutChars ; Display it - xor di,di ; ES:DI has dir entry + ; Lets save the contents of the screen + ; from B800:0000 to 9000:8000 + pushad + + mov ax,0b800h + mov ds,ax + xor si,si + mov ax,9800h + mov es,ax + xor di,di + mov cx,2000 ; Copy 2000 characters (screen is 80x25) + rep movsw ; 2 bytes a character (one is the attribute byte) + + mov ah,03h ; AH = 03h + xor bx,bx ; BH = video page + int 10h ; BIOS Int 10h Func 3 - Read Cursor Position and Size + mov [es:di],dx ; DH = row, DL = column + + ; Display "Loading FreeLoader..." message + mov si,msgLoading ; Loading message + call PutChars ; Display it + + popad + + xor di,di ; ES:DI has dir entry xor dx,dx mov ax,WORD [es:di+14h] ; Get start cluster high word shl eax,16 mov ax,WORD [es:di+1ah] ; Get start cluster low word - mov bx,800h +CheckStartCluster: + cmp eax,2 ; Check and see if the start cluster starts at cluster 2 or above + jnb CheckEndCluster ; If so then continue + jmp PrintFileSystemError ; If not exit with error +CheckEndCluster: + cmp eax,0ffffff8h ; Check and see if the start cluster is and end of cluster chain indicator + jb InitializeLoadSegment ; If not then continue + jmp PrintFileSystemError ; If so exit with error + +InitializeLoadSegment: + mov bx,7e0h mov es,bx -FoundFile2: +LoadFile: cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain - jae FoundFile3 ; If so continue, if not then read then next one + jae LoadFileDone ; If so continue, if not then read the next one push eax - xor bx,bx ; Load ROSLDR starting at 0000:8000h + xor bx,bx ; Load ROSLDR starting at 0000:7e00h push es call ReadCluster pop es xor bx,bx - mov bl,[SectsPerCluster] + mov bl,[BYTE bp+SectsPerCluster] shl bx,5 ; BX = BX * 512 / 16 mov ax,es ; Increment the load address by add ax,bx ; The size of a cluster @@ -276,14 +396,13 @@ FoundFile2: call GetFatEntry ; Get the next entry pop es - jmp FoundFile2 ; Load the next cluster (if any) + jmp LoadFile ; Load the next cluster (if any) -FoundFile3: - mov dl,[BootDrive] - xor ax,ax - push ax - mov ax,8000h - push ax ; We will do a far return to 0000:8000h +LoadFileDone: + mov dl,[BYTE bp+BootDrive] + xor ax,ax ; We loaded at 0000:7e00 but the entry point is 0000:8000 + push ax ; because the first 512 bytes is fat helper code + push WORD 8000h ; We will do a far return to 0000:8000h retf ; Transfer control to ROSLDR @@ -292,57 +411,52 @@ FoundFile3: ; On return EAX has FAT entry for that cluster GetFatEntry: - shl eax,2 ; EAX = EAX * 4 (since FAT32 entries are 4 bytes) - mov ecx,eax ; Save this for later in ECX + shl eax,2 ; EAX = EAX * 4 (since FAT32 entries are 4 bytes) + mov ecx,eax ; Save this for later in ECX xor edx,edx - movzx ebx,WORD [BytesPerSector] + movzx ebx,WORD [BYTE bp+BytesPerSector] push ebx - div ebx ; FAT Sector Number = EAX / BytesPerSector - movzx ebx,WORD [ReservedSectors] - add eax,ebx ; FAT Sector Number += ReservedSectors - mov ebx,DWORD [HiddenSectors] - add eax,ebx ; FAT Sector Number += HiddenSectors + div ebx ; FAT Sector Number = EAX / BytesPerSector + movzx ebx,WORD [BYTE bp+ReservedSectors] + add eax,ebx ; FAT Sector Number += ReservedSectors + mov ebx,DWORD [BYTE bp+HiddenSectors] + add eax,ebx ; FAT Sector Number += HiddenSectors pop ebx dec ebx - and ecx,ebx ; FAT Offset Within Sector = ECX % BytesPerSector - ; EAX holds logical FAT sector number - ; ECX holds FAT entry offset - - ; Now we have to check the extended flags - ; to see which FAT is the active one - ; and use it, or if they are mirrored then - ; no worries - movzx ebx,WORD [ExtendedFlags] ; Get extended flags and put into ebx - and bx,0x0f ; Mask off upper 8 bits - jz GetFatEntry2 ; If fat is mirrored then skip fat calcs - cmp bl,[NumberOfFats] ; Compare bl to number of fats - jc GetFatEntry1 - jmp ErrBoot ; If bl is bigger than numfats exit with error -GetFatEntry1: - mov edx,eax ; Put logical FAT sector number in edx - mov eax,[SectorsPerFatBig] ; Get the number of sectors occupied by one fat in eax - mul ebx ; Multiplied by the active FAT index we have in ebx - add eax,edx ; Add the current FAT sector offset - -GetFatEntry2: + and ecx,ebx ; FAT Offset Within Sector = ECX % BytesPerSector + ; EAX holds logical FAT sector number + ; ECX holds FAT entry offset + + ; Now we have to check the extended flags + ; to see which FAT is the active one + ; and use it, or if they are mirrored then + ; no worries + movzx ebx,WORD [BYTE bp+ExtendedFlags] ; Get extended flags and put into ebx + and bx,0x0f ; Mask off upper 8 bits, now we have active fat in bl + jz LoadFatSector ; If fat is mirrored then skip fat calcs + cmp bl,[BYTE bp+NumberOfFats] ; Compare bl to number of fats + jb GetActiveFatOffset + jmp PrintFileSystemError ; If bl is bigger than numfats exit with error +GetActiveFatOffset: + push eax ; Save logical FAT sector number + mov eax,[BYTE bp+SectorsPerFatBig] ; Get the number of sectors occupied by one fat in eax + mul ebx ; Multiplied by the active FAT index we have in ebx + pop edx ; Get logical FAT sector number + add eax,edx ; Add the current FAT sector offset + +LoadFatSector: push ecx - ror eax,16 - mov dx,ax - ror eax,16 - ; DX:AX holds logical FAT sector number + ; EAX holds logical FAT sector number mov bx,7000h mov es,bx - xor bx,bx ; We will load it to [7000:0000h] + xor bx,bx ; We will load it to [7000:0000h] mov cx,1 call ReadSectors - jnc GetFatEntry3 - jmp BadBoot -GetFatEntry3: mov bx,7000h mov es,bx pop ecx - mov eax,DWORD [es:ecx] ; Get FAT entry - and eax,0fffffffh ; Mask off reserved bits + mov eax,DWORD [es:ecx] ; Get FAT entry + and eax,0fffffffh ; Mask off reserved bits ret @@ -354,27 +468,38 @@ ReadCluster: dec eax dec eax xor edx,edx - movzx ebx,BYTE [SectsPerCluster] + movzx ebx,BYTE [BYTE bp+SectsPerCluster] mul ebx push eax xor edx,edx - movzx eax,BYTE [NumberOfFats] - mul DWORD [SectorsPerFatBig] - movzx ebx,WORD [ReservedSectors] + movzx eax,BYTE [BYTE bp+NumberOfFats] + mul DWORD [BYTE bp+SectorsPerFatBig] + movzx ebx,WORD [BYTE bp+ReservedSectors] add eax,ebx - add eax,DWORD [HiddenSectors] + add eax,DWORD [BYTE bp+HiddenSectors] pop ebx add eax,ebx ; EAX now contains the logical sector number of the cluster - ror eax,16 - mov dx,ax - ror eax,16 xor bx,bx ; We will load it to [ES:0000], ES loaded before function call - movzx cx,BYTE [SectsPerCluster] + movzx cx,BYTE [BYTE bp+SectsPerCluster] call ReadSectors ret - times 998-($-$$) db 0 ; Pad to 998 bytes +; Displays a file not found error message +; And reboots +PrintFileNotFound: + mov si,msgFreeLdr ; FreeLdr not found message + call PutChars ; Display it + mov si,msgAnyKey ; Press any key message + call PutChars ; Display it + + jmp Reboot + +msgFreeLdr db 'FREELDR.SYS not found',0dh,0ah,0 +filename db 'FREELDR SYS' msgLoading db 'Loading FreeLoader...',0dh,0ah,0 + + times 1022-($-$$) db 0 ; Pad to 1022 bytes + dw 0aa55h ; BootSector signature diff --git a/freeldr/freeldr/Makefile b/freeldr/freeldr/Makefile index 8823afacc9b..6ade1cad9be 100644 --- a/freeldr/freeldr/Makefile +++ b/freeldr/freeldr/Makefile @@ -25,17 +25,17 @@ export RM = cmd /C del export CP = cmd /C copy #FLAGS = -Wall -nostdinc -fno-builtin -#FLAGS = -Wall -fno-builtin -DDEBUG -FLAGS = -Wall -fno-builtin +FLAGS = -Wall -fno-builtin -DDEBUG +#FLAGS = -Wall -fno-builtin # asmcode.o has to be first in the link line because it contains the startup code -OBJS = asmcode.a asmcode.o mb.o boot.o freeldr.o stdlib.o fs.a fs.o fs_fat.o \ +OBJS = asmcode.a asmcode.o mb.o boot.o freeldr.o stdlib.o fs.a fs.o fat.o \ reactos.o tui.o menu.o miscboot.o options.o linux.o multiboot.o arcname.o \ mem.o memory.o debug.o parseini.o ASM_OBJS = asmcode.o mb.o boot.o mem.o C_OBJS = freeldr.o stdlib.o fs.a reactos.o tui.o menu.o miscboot.o options.o linux.o \ multiboot.o -C_OBJS2 = arcname.o memory.o debug.o parseini.o rs232.o portio.o +C_OBJS2 = arcname.o memory.o debug.o parseini.o rs232.o portio.o oslist.o .PHONY : clean @@ -66,14 +66,14 @@ freeldr.o: freeldr.c freeldr.h stdlib.h fs.h reactos.h tui.h asmcode.h menu.h mi stdlib.o: stdlib.c freeldr.h stdlib.h Makefile $(CC) $(FLAGS) -o stdlib.o -c stdlib.c -fs.a: fs.o fs_fat.o Makefile - $(LD) -r -o fs.a fs.o fs_fat.o +fs.a: fs.o fat.o Makefile + $(LD) -r -o fs.a fs.o fat.o fs.o: fs.c freeldr.h fs.h stdlib.h tui.h asmcode.h Makefile $(CC) $(FLAGS) -o fs.o -c fs.c -fs_fat.o: fs_fat.c freeldr.h fs.h stdlib.h tui.h Makefile - $(CC) $(FLAGS) -o fs_fat.o -c fs_fat.c +fat.o: fat.c fat.h freeldr.h fs.h stdlib.h tui.h Makefile + $(CC) $(FLAGS) -o fat.o -c fat.c reactos.o: reactos.c freeldr.h reactos.h stdlib.h fs.h tui.h multiboot.h Makefile $(CC) $(FLAGS) -o reactos.o -c reactos.c @@ -123,6 +123,9 @@ rs232.o: rs232.c rs232.h Makefile portio.o: portio.c portio.h Makefile $(CC) $(FLAGS) -o portio.o -c portio.c +oslist.o: oslist.c oslist.h Makefile + $(CC) $(FLAGS) -o oslist.o -c oslist.c + clean: $(RM) *.o $(RM) *.a diff --git a/freeldr/freeldr/asmcode.S b/freeldr/freeldr/asmcode.S index 440a233fe5f..f4d2913f70d 100644 --- a/freeldr/freeldr/asmcode.S +++ b/freeldr/freeldr/asmcode.S @@ -1,6 +1,6 @@ /* * FreeLoader - * Copyright (C) 1999, 2000 Brian Palmer + * Copyright (C) 1999, 2000, 2001 Brian Palmer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -376,10 +376,8 @@ EXTERN(_gotoxy) ret /* - * int biosdisk(int cmd, int drive, int head, int track, int sector, int nsects, void *buffer); + * BOOL BiosInt13Read(ULONG Drive, ULONG Head, ULONG Track, ULONG Sector, ULONG SectorCount, PVOID Buffer); */ -_biosdisk_cmd: - .long 0 _biosdisk_drive: .long 0 _biosdisk_head: @@ -396,7 +394,7 @@ _biosdisk_retval: .long 0 _biosdisk_retrycount: .byte 0 -EXTERN(_biosdisk) +EXTERN(_BiosInt13Read) .code32 push %ebp @@ -408,18 +406,16 @@ EXTERN(_biosdisk) /* Get parameters */ movl 0x1c(%esp),%eax - movl %eax,_biosdisk_cmd - movl 0x20(%esp),%eax movl %eax,_biosdisk_drive - movl 0x24(%esp),%eax + movl 0x20(%esp),%eax movl %eax,_biosdisk_head - movl 0x28(%esp),%eax + movl 0x24(%esp),%eax movl %eax,_biosdisk_track - movl 0x2c(%esp),%eax + movl 0x28(%esp),%eax movl %eax,_biosdisk_sector - movl 0x30(%esp),%eax + movl 0x2c(%esp),%eax movl %eax,_biosdisk_nsects - movl 0x34(%esp),%eax + movl 0x30(%esp),%eax movl %eax,_biosdisk_buffer call switch_to_real @@ -429,9 +425,11 @@ EXTERN(_biosdisk) movb $3,_biosdisk_retrycount // Set the retry count to 3 _biosdisk_read: - movw $SCRATCHSEG,%ax // Load ES with 7000 - movw %ax,%es // and BX with 0 - movw $SCRATCHOFF,%bx // so that the sector gets loaded to 7000:0000 + movl _biosdisk_buffer,%eax // Get buffer address in eax + shrl $4,%eax // Make linear address into segment + movw %ax,%es // Load ES with segment + movl _biosdisk_buffer,%ebx // and BX with offset + andl $0x0f,%ebx // so that data gets loaded to [ES:BX] movb _biosdisk_sector,%cl // Get the sector in CL movw _biosdisk_track,%ax // Cylinder in AX movb %al,%ch // Now put it in CH @@ -487,17 +485,6 @@ _biosdisk_done: .code32 - /* Copy the sector contents from 7000:0000 to the buffer */ - cld - movl $SCRATCHAREA,%esi - movl _biosdisk_buffer,%edi - movl _biosdisk_nsects,%eax - movl $0x100,%ebx - mull %ebx - movl %eax,%ecx - rep - movsw - movl _biosdisk_retval,%eax // Get return value //movl $1,%eax @@ -509,6 +496,176 @@ _biosdisk_done: pop %ebp ret +/* + * BOOL BiosInt13ReadExtended(ULONG Drive, ULONG Sector, ULONG SectorCount, PVOID Buffer); + */ +_disk_address_packet: +_packet_size: + .byte 0x10 +_packet_reserved: + .byte 0 +_packet_sector_count: + .word 0 +_packet_transfer_buffer_segment: + .word 0 +_packet_transfer_buffer_offset: + .word 0 +_packet_lba_sector_number: + .quad 0 +_packet_64bit_flat_address: + .quad 0 +_int13_extended_drive: + .long 0 +_int13_extended_sector_count: + .long 0 +_int13_extended_retval: + .long 0 +_int13_extended_retrycount: + .byte 0 +EXTERN(_BiosInt13ReadExtended) + .code32 + + push %ebp + push %esi + push %edi + push %ebx + push %ecx + push %edx + + /* Get parameters */ + movl 0x1c(%esp),%eax + movl %eax,_int13_extended_drive + movl 0x20(%esp),%eax + movl %eax,_packet_lba_sector_number + movl 0x24(%esp),%eax + movw %ax,_packet_sector_count + movl %eax,_int13_extended_sector_count + movl 0x28(%esp),%eax // Get buffer address in eax + shrl $4,%eax // Make linear address into segment + movw %ax,_packet_transfer_buffer_segment // Save segment + movl 0x28(%esp),%eax // Get buffer address in eax + andl $0x0f,%eax // Make linear address into offset + movw %ax,_packet_transfer_buffer_offset // Save offset + + call switch_to_real + + .code16 + pushw %es // Save this just in case + movb $3,_int13_extended_retrycount // Set the retry count to 3 + +_int13_extended_read: + movb _int13_extended_drive,%dl // Get the drive + movb $42,%ah // BIOS int 0x13, function 42h - IBM/MS INT 13 Extensions - EXTENDED READ + movw $_disk_address_packet,%si // DS:SI -> disk address packet + int $0x13 // Read sectors + + movb $1,%al // Set the return value to be one (will be set to zero later if needed) + jc _int13_extended_error // Jump if error (CF = 1 on error) + + movl _int13_extended_sector_count,%eax // Get the sector count in eax + cmpw _packet_sector_count,%ax // See how many sectors we actually read (returned in disk address packet sector count) + jne _int13_extended_error // Jump if not equal + + jmp _int13_extended_done + + +_int13_extended_error: + cmpb $0x11,%ah // Check and see if it was a corrected ECC error + je _int13_extended_done // If so then the data is still good, if not fail + + movb _int13_extended_retrycount,%al // Get the current retry count + decb %al // Decrement it + movb %al,_int13_extended_retrycount // Save it + cmpb $0,%al // Is it zero? + jz _int13_extended_zero // Yes, return zero + + movb $0,%ah // BIOS int 0x13, function 0 - Reset Disk System + movb _int13_extended_drive,%dl // Get the drive + int $0x13 // Reset the disk system + jmp _int13_extended_read // Try reading again + +_int13_extended_zero: + movb $0,%al // We will return zero + +_int13_extended_done: + movzbl %al,%eax // Put the number of sectors read into EAX + movl %eax,_int13_extended_retval // Save it as the return value + + popw %es // Restore ES + call switch_to_prot + + .code32 + + movl _int13_extended_retval,%eax // Get return value + //movl $1,%eax + + pop %edx + pop %ecx + pop %ebx + pop %edi + pop %esi + pop %ebp + ret + +/* + * BOOL BiosInt13ExtensionsSupported(ULONG Drive); + */ +_int13_extension_check_drive: + .long 0 +_int13_extension_check_retval: + .long 0 +EXTERN(_BiosInt13ExtensionsSupported) + .code32 + + push %ebp + push %esi + push %edi + push %ebx + push %ecx + push %edx + + /* Get parameters */ + movl 0x1c(%esp),%eax + movl %eax,_int13_extension_check_drive + + call switch_to_real + + .code16 + // Now make sure this computer supports extended reads + movb $0x41,%ah // AH = 41h + movw $0x55aa,%bx // BX = 55AAh + movb _int13_extension_check_drive,%dl // DL = drive (80h-FFh) + int $0x13 // IBM/MS INT 13 Extensions - INSTALLATION CHECK + jc _int13_extension_check_error // CF set on error (extensions not supported) + cmpw $0x55aa,%bx // BX = AA55h if installed + jne _int13_extension_check_error + testb $1,%cl // CX = API subset support bitmap + jz _int13_extension_check_error // Bit 0, extended disk access functions (AH=42h-44h,47h,48h) supported + + // If we get here then we passed all the int13 extension tests + movl $1,_int13_extension_check_retval // Set return value to TRUE + jmp _int13_extension_check_done + +_int13_extension_check_error: + + movl $0,_int13_extension_check_retval // The tests failed so return FALSE + +_int13_extension_check_done: + + call switch_to_prot + + .code32 + + movl _int13_extension_check_retval,%eax // Get return value + + pop %edx + pop %ecx + pop %ebx + pop %edi + pop %esi + pop %ebp + ret + /* * int getyear(void); */ @@ -996,7 +1153,7 @@ EXTERN(_get_heads) jmp _get_heads_done _get_heads_error: - movl $0x0e,_biosdisk_retval + movl $0xff,_biosdisk_retval _get_heads_done: @@ -1049,7 +1206,7 @@ EXTERN(_get_cylinders) jmp _get_cylinders_done _get_cylinders_error: - movl $0x00,_biosdisk_retval + movl $0xff,_biosdisk_retval _get_cylinders_done: @@ -1098,7 +1255,7 @@ EXTERN(_get_sectors) jmp _get_sectors_done _get_sectors_error: - movl $0x00,_biosdisk_retval + movl $0xff,_biosdisk_retval _get_sectors_done: diff --git a/freeldr/freeldr/asmcode.h b/freeldr/freeldr/asmcode.h index 11dd28a7318..7d7381a76ab 100644 --- a/freeldr/freeldr/asmcode.h +++ b/freeldr/freeldr/asmcode.h @@ -39,18 +39,13 @@ #define NR_TASKS 128 /* Space reserved in the GDT for TSS descriptors */ #define STACK16ADDR 0x7000 /* The 16-bit stack top will be at 0000:7000 */ -#define STACK32ADDR 0x60000 /* The 32-bit stack top will be at 6000:0000, or 0x60000 */ +#define STACK32ADDR 0xA0000 /* The 32-bit stack top will be at 9000:FFFF, or 0x9FFFF */ -#define FILESYSADDR 0x80000 /* The filesystem data address will be at 8000:0000, or 0x80000 */ +#define DISKREADBUFFER 0x90000 /* Buffer to store data read in from the disk via the BIOS */ -#define FATCLUSTERBUF 0x60000 /* The fat filesystem's cluster buffer */ - -#define SCREENBUFFER 0x68000 /* The screen contents will be saved here */ -#define FREELDRINIADDR 0x6C000 /* The freeldr.ini load address will be at 6000:C000, or 0x6C000 */ - -#define SCRATCHSEG 0x7000 /* The 512-byte fixed scratch area will be at 7000:0000, or 0x70000 */ -#define SCRATCHOFF 0x0000 /* The 512-byte fixed scratch area will be at 7000:0000, or 0x70000 */ -#define SCRATCHAREA 0x70000 /* The 512-byte fixed scratch area will be at 7000:0000, or 0x70000 */ +#define SCREENBUFFER 0x98000 /* The screen contents will be saved here */ +#define SCREENXCOORD 0x98FA0 /* Address of the byte that contains the current column of the cursor */ +#define SCREENYCOORD 0x98FA1 /* Address of the byte that contains the current row of the cursor */ /* Makes "x" a global variable or label */ #define EXTERN(x) .global x; x: diff --git a/freeldr/freeldr/debug.c b/freeldr/freeldr/debug.c index e65c12bdb4e..b8178c83636 100644 --- a/freeldr/freeldr/debug.c +++ b/freeldr/freeldr/debug.c @@ -22,20 +22,26 @@ #include "stdlib.h" #include "rs232.h" #include "parseini.h" +#include "portio.h" #ifdef DEBUG -ULONG DebugPrintMask = DPRINT_WARNING | DPRINT_MEMORY; +ULONG DebugPrintMask = DPRINT_WARNING | DPRINT_MEMORY | DPRINT_FILESYSTEM | DPRINT_UI; -#define SCREEN 0 -#define RS232 1 +#define SCREEN 0 +#define RS232 1 +#define BOCHS 2 -#define COM1 1 -#define COM2 2 -#define COM3 3 -#define COM4 4 +#define COM1 1 +#define COM2 2 +#define COM3 3 +#define COM4 4 -ULONG DebugPort = RS232; //SCREEN; +#define BOCHS_OUTPUT_PORT 0xe9 + +//ULONG DebugPort = RS232; +//ULONG DebugPort = SCREEN; +ULONG DebugPort = BOCHS; ULONG ComPort = COM1; ULONG BaudRate = 19200; @@ -47,13 +53,30 @@ VOID DebugInit(VOID) } } -void DebugPrint(ULONG Mask, char *format, ...) +VOID DebugPrintChar(UCHAR Character) +{ + if (DebugPort == RS232) + { + Rs232PortPutByte(Character); + if (Character == '\n') + { + Rs232PortPutByte('\r'); + } + } + else if (DebugPort == BOCHS) + { + WRITE_PORT_UCHAR((PUCHAR)BOCHS_OUTPUT_PORT, Character); + } + else + { + putchar(Character); + } +} + +VOID DebugPrint(ULONG Mask, char *format, ...) { int *dataptr = (int *) &format; char c, *ptr, str[16]; - char buffer[512]; - char *p = buffer; - int i; // Mask out unwanted debug messages if (!(Mask & DebugPrintMask)) @@ -65,60 +88,50 @@ void DebugPrint(ULONG Mask, char *format, ...) while ((c = *(format++))) { - if (c != '%') - { - *p = c; - p++; - } - else - switch (c = *(format++)) - { - case 'd': case 'u': case 'x': - *convert_to_ascii(str, c, *((unsigned long *) dataptr++)) = 0; - - ptr = str; - - while (*ptr) + if (c != '%') { - *p = *(ptr++); - p++; + DebugPrintChar(c); } - break; + else + { + switch (c = *(format++)) + { + case 'd': case 'u': case 'x': + + *convert_to_ascii(str, c, *((unsigned long *) dataptr++)) = 0; - case 'c': - *p = (*(dataptr++))&0xff; - p++; - break; + ptr = str; - case 's': - ptr = (char *)(*(dataptr++)); + while (*ptr) + { + DebugPrintChar(*(ptr++)); + } + break; - while ((c = *(ptr++))) - { - *p = c; - p++; - } - break; - } - } - *p=0; + case 'c': + DebugPrintChar((*(dataptr++))&0xff); + break; - if (DebugPort == RS232) - { - for (i=0; buffer[i] != 0; i++) - { - Rs232PortPutByte(buffer[i]); - if (buffer[i] == '\n') - { - Rs232PortPutByte('\r'); + case 's': + + ptr = (char *)(*(dataptr++)); + + while ((c = *(ptr++))) + { + DebugPrintChar(c); + } + break; } } } - else + + + if (DebugPort == SCREEN) { - print(buffer); + //getch(); } + } #endif // defined DEBUG diff --git a/freeldr/freeldr/debug.h b/freeldr/freeldr/debug.h index 7bade776994..57514cf1ab3 100644 --- a/freeldr/freeldr/debug.h +++ b/freeldr/freeldr/debug.h @@ -23,39 +23,22 @@ #ifdef DEBUG -#define DPRINT_WARNING 0x00000001 // OR this with DebugPrintMask to enable debugger messages and other misc stuff -#define DPRINT_MEMORY 0x00000002 // OR this with DebugPrintMask to enable memory management messages - -VOID DebugInit(VOID); -void DebugPrint(ULONG Mask, char *format, ...); - -#define BugCheck0(format) \ - { \ - DebugPrint(DPRINT_WARNING, "Fatal Error: %s:%d\n", __FILE__, __LINE__); \ - DebugPrint(DPRINT_WARNING, format); \ - for (;;); \ - } - -#define BugCheck1(format, arg1) \ - { \ - DebugPrint(DPRINT_WARNING, "Fatal Error: %s:%d\n", __FILE__, __LINE__); \ - DebugPrint(DPRINT_WARNING, format, arg1); \ - for (;;); \ - } - -#define BugCheck2(format, arg1, arg2) \ - { \ - DebugPrint(DPRINT_WARNING, "Fatal Error: %s:%d\n", __FILE__, __LINE__); \ - DebugPrint(DPRINT_WARNING, format, arg1, arg2); \ - for (;;); \ - } - -#define BugCheck3(format, arg1, arg2, arg3) \ - { \ - DebugPrint(DPRINT_WARNING, "Fatal Error: %s:%d\n", __FILE__, __LINE__); \ - DebugPrint(DPRINT_WARNING, format, arg1, arg2, arg3); \ - for (;;); \ - } + #define DPRINT_WARNING 0x00000001 // OR this with DebugPrintMask to enable debugger messages and other misc stuff + #define DPRINT_MEMORY 0x00000002 // OR this with DebugPrintMask to enable memory management messages + #define DPRINT_FILESYSTEM 0x00000004 // OR this with DebugPrintMask to enable file system messages + #define DPRINT_INIFILE 0x00000008 // OR this with DebugPrintMask to enable .ini file messages + #define DPRINT_UI 0x00000010 // OR this with DebugPrintMask to enable user interface messages + + VOID DebugInit(VOID); + VOID DebugPrint(ULONG Mask, char *format, ...); + + #define DbgPrint(_x_) DebugPrint _x_ + #define BugCheck(_x_) { DebugPrint(DPRINT_WARNING, "Fatal Error: %s:%d\n", __FILE__, __LINE__); DebugPrint _x_ ; for (;;); } + +#else + + #define DbgPrint(_x_) + #define BugCheck(_x_) #endif // defined DEBUG diff --git a/freeldr/freeldr/fat.c b/freeldr/freeldr/fat.c new file mode 100644 index 00000000000..6ef7ba59361 --- /dev/null +++ b/freeldr/freeldr/fat.c @@ -0,0 +1,1163 @@ +/* + * FreeLoader + * Copyright (C) 1999, 2000, 2001 Brian Palmer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "freeldr.h" +#include "fs.h" +#include "fat.h" +#include "stdlib.h" +#include "tui.h" +#include "asmcode.h" +#include "memory.h" +#include "debug.h" + + +PFAT_BOOTSECTOR FatVolumeBootSector = NULL; +PFAT32_BOOTSECTOR Fat32VolumeBootSector = NULL; + +ULONG RootDirSectorStart; // Starting sector of the root directory (fat12/16) +ULONG DataSectorStart; // Starting sector of the data area +ULONG SectorsPerFat; // Sectors per FAT table +ULONG RootDirSectors; // Number of sectors of the root directory (fat32) + +ULONG FatType = 0; // FAT12, FAT16, or FAT32 + + +BOOL FatOpenVolume(ULONG DriveNumber, ULONG VolumeStartHead, ULONG VolumeStartTrack, ULONG VolumeStartSector, ULONG FatFileSystemType) +{ + FatType = FatFileSystemType; + + // + // Free any memory previously allocated + // + if (FatVolumeBootSector != NULL) + { + FreeMemory(FatVolumeBootSector); + + FatVolumeBootSector = NULL; + Fat32VolumeBootSector = NULL; + } + + // + // Now allocate the memory to hold the boot sector + // + FatVolumeBootSector = (PFAT_BOOTSECTOR) AllocateMemory(512); + Fat32VolumeBootSector = (PFAT32_BOOTSECTOR) FatVolumeBootSector; + + // + // Make sure we got the memory + // + if (FatVolumeBootSector == NULL) + { + FileSystemError("Out of memory."); + return FALSE; + } + + // + // Now try to read the boot sector + // If this fails then abort + // + if (!BiosInt13Read(DriveNumber, VolumeStartHead, VolumeStartTrack, VolumeStartSector, 1, FatVolumeBootSector)) + { + return FALSE; + } + +#ifdef DEBUG + + DbgPrint((DPRINT_FILESYSTEM, "Dumping boot sector:\n")); + + if (FatFileSystemType == FAT32) + { + DbgPrint((DPRINT_FILESYSTEM, "sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR))); + + DbgPrint((DPRINT_FILESYSTEM, "JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector->JumpBoot[0], Fat32VolumeBootSector->JumpBoot[1], Fat32VolumeBootSector->JumpBoot[2])); + DbgPrint((DPRINT_FILESYSTEM, "OemName: %c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->OemName[0], Fat32VolumeBootSector->OemName[1], Fat32VolumeBootSector->OemName[2], Fat32VolumeBootSector->OemName[3], Fat32VolumeBootSector->OemName[4], Fat32VolumeBootSector->OemName[5], Fat32VolumeBootSector->OemName[6], Fat32VolumeBootSector->OemName[7])); + DbgPrint((DPRINT_FILESYSTEM, "BytesPerSector: %d\n", Fat32VolumeBootSector->BytesPerSector)); + DbgPrint((DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", Fat32VolumeBootSector->SectorsPerCluster)); + DbgPrint((DPRINT_FILESYSTEM, "ReservedSectors: %d\n", Fat32VolumeBootSector->ReservedSectors)); + DbgPrint((DPRINT_FILESYSTEM, "NumberOfFats: %d\n", Fat32VolumeBootSector->NumberOfFats)); + DbgPrint((DPRINT_FILESYSTEM, "RootDirEntries: %d\n", Fat32VolumeBootSector->RootDirEntries)); + DbgPrint((DPRINT_FILESYSTEM, "TotalSectors: %d\n", Fat32VolumeBootSector->TotalSectors)); + DbgPrint((DPRINT_FILESYSTEM, "MediaDescriptor: 0x%x\n", Fat32VolumeBootSector->MediaDescriptor)); + DbgPrint((DPRINT_FILESYSTEM, "SectorsPerFat: %d\n", Fat32VolumeBootSector->SectorsPerFat)); + DbgPrint((DPRINT_FILESYSTEM, "SectorsPerTrack: %d\n", Fat32VolumeBootSector->SectorsPerTrack)); + DbgPrint((DPRINT_FILESYSTEM, "NumberOfHeads: %d\n", Fat32VolumeBootSector->NumberOfHeads)); + DbgPrint((DPRINT_FILESYSTEM, "HiddenSectors: %d\n", Fat32VolumeBootSector->HiddenSectors)); + DbgPrint((DPRINT_FILESYSTEM, "TotalSectorsBig: %d\n", Fat32VolumeBootSector->TotalSectorsBig)); + DbgPrint((DPRINT_FILESYSTEM, "SectorsPerFatBig: %d\n", Fat32VolumeBootSector->SectorsPerFatBig)); + DbgPrint((DPRINT_FILESYSTEM, "ExtendedFlags: 0x%x\n", Fat32VolumeBootSector->ExtendedFlags)); + DbgPrint((DPRINT_FILESYSTEM, "FileSystemVersion: 0x%x\n", Fat32VolumeBootSector->FileSystemVersion)); + DbgPrint((DPRINT_FILESYSTEM, "RootDirStartCluster: %d\n", Fat32VolumeBootSector->RootDirStartCluster)); + DbgPrint((DPRINT_FILESYSTEM, "FsInfo: %d\n", Fat32VolumeBootSector->FsInfo)); + DbgPrint((DPRINT_FILESYSTEM, "BackupBootSector: %d\n", Fat32VolumeBootSector->BackupBootSector)); + DbgPrint((DPRINT_FILESYSTEM, "Reserved: 0x%x\n", Fat32VolumeBootSector->Reserved)); + DbgPrint((DPRINT_FILESYSTEM, "DriveNumber: 0x%x\n", Fat32VolumeBootSector->DriveNumber)); + DbgPrint((DPRINT_FILESYSTEM, "Reserved1: 0x%x\n", Fat32VolumeBootSector->Reserved1)); + DbgPrint((DPRINT_FILESYSTEM, "BootSignature: 0x%x\n", Fat32VolumeBootSector->BootSignature)); + DbgPrint((DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector->VolumeSerialNumber)); + DbgPrint((DPRINT_FILESYSTEM, "VolumeLabel: %c%c%c%c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->VolumeLabel[0], Fat32VolumeBootSector->VolumeLabel[1], Fat32VolumeBootSector->VolumeLabel[2], Fat32VolumeBootSector->VolumeLabel[3], Fat32VolumeBootSector->VolumeLabel[4], Fat32VolumeBootSector->VolumeLabel[5], Fat32VolumeBootSector->VolumeLabel[6], Fat32VolumeBootSector->VolumeLabel[7], Fat32VolumeBootSector->VolumeLabel[8], Fat32VolumeBootSector->VolumeLabel[9], Fat32VolumeBootSector->VolumeLabel[10])); + DbgPrint((DPRINT_FILESYSTEM, "FileSystemType: %c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->FileSystemType[0], Fat32VolumeBootSector->FileSystemType[1], Fat32VolumeBootSector->FileSystemType[2], Fat32VolumeBootSector->FileSystemType[3], Fat32VolumeBootSector->FileSystemType[4], Fat32VolumeBootSector->FileSystemType[5], Fat32VolumeBootSector->FileSystemType[6], Fat32VolumeBootSector->FileSystemType[7])); + DbgPrint((DPRINT_FILESYSTEM, "BootSectorMagic: 0x%x\n", Fat32VolumeBootSector->BootSectorMagic)); + } + else + { + DbgPrint((DPRINT_FILESYSTEM, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR))); + + DbgPrint((DPRINT_FILESYSTEM, "JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector->JumpBoot[0], FatVolumeBootSector->JumpBoot[1], FatVolumeBootSector->JumpBoot[2])); + DbgPrint((DPRINT_FILESYSTEM, "OemName: %c%c%c%c%c%c%c%c\n", FatVolumeBootSector->OemName[0], FatVolumeBootSector->OemName[1], FatVolumeBootSector->OemName[2], FatVolumeBootSector->OemName[3], FatVolumeBootSector->OemName[4], FatVolumeBootSector->OemName[5], FatVolumeBootSector->OemName[6], FatVolumeBootSector->OemName[7])); + DbgPrint((DPRINT_FILESYSTEM, "BytesPerSector: %d\n", FatVolumeBootSector->BytesPerSector)); + DbgPrint((DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", FatVolumeBootSector->SectorsPerCluster)); + DbgPrint((DPRINT_FILESYSTEM, "ReservedSectors: %d\n", FatVolumeBootSector->ReservedSectors)); + DbgPrint((DPRINT_FILESYSTEM, "NumberOfFats: %d\n", FatVolumeBootSector->NumberOfFats)); + DbgPrint((DPRINT_FILESYSTEM, "RootDirEntries: %d\n", FatVolumeBootSector->RootDirEntries)); + DbgPrint((DPRINT_FILESYSTEM, "TotalSectors: %d\n", FatVolumeBootSector->TotalSectors)); + DbgPrint((DPRINT_FILESYSTEM, "MediaDescriptor: 0x%x\n", FatVolumeBootSector->MediaDescriptor)); + DbgPrint((DPRINT_FILESYSTEM, "SectorsPerFat: %d\n", FatVolumeBootSector->SectorsPerFat)); + DbgPrint((DPRINT_FILESYSTEM, "SectorsPerTrack: %d\n", FatVolumeBootSector->SectorsPerTrack)); + DbgPrint((DPRINT_FILESYSTEM, "NumberOfHeads: %d\n", FatVolumeBootSector->NumberOfHeads)); + DbgPrint((DPRINT_FILESYSTEM, "HiddenSectors: %d\n", FatVolumeBootSector->HiddenSectors)); + DbgPrint((DPRINT_FILESYSTEM, "TotalSectorsBig: %d\n", FatVolumeBootSector->TotalSectorsBig)); + DbgPrint((DPRINT_FILESYSTEM, "DriveNumber: 0x%x\n", FatVolumeBootSector->DriveNumber)); + DbgPrint((DPRINT_FILESYSTEM, "Reserved1: 0x%x\n", FatVolumeBootSector->Reserved1)); + DbgPrint((DPRINT_FILESYSTEM, "BootSignature: 0x%x\n", FatVolumeBootSector->BootSignature)); + DbgPrint((DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", FatVolumeBootSector->VolumeSerialNumber)); + DbgPrint((DPRINT_FILESYSTEM, "VolumeLabel: %c%c%c%c%c%c%c%c%c%c%c\n", FatVolumeBootSector->VolumeLabel[0], FatVolumeBootSector->VolumeLabel[1], FatVolumeBootSector->VolumeLabel[2], FatVolumeBootSector->VolumeLabel[3], FatVolumeBootSector->VolumeLabel[4], FatVolumeBootSector->VolumeLabel[5], FatVolumeBootSector->VolumeLabel[6], FatVolumeBootSector->VolumeLabel[7], FatVolumeBootSector->VolumeLabel[8], FatVolumeBootSector->VolumeLabel[9], FatVolumeBootSector->VolumeLabel[10])); + DbgPrint((DPRINT_FILESYSTEM, "FileSystemType: %c%c%c%c%c%c%c%c\n", FatVolumeBootSector->FileSystemType[0], FatVolumeBootSector->FileSystemType[1], FatVolumeBootSector->FileSystemType[2], FatVolumeBootSector->FileSystemType[3], FatVolumeBootSector->FileSystemType[4], FatVolumeBootSector->FileSystemType[5], FatVolumeBootSector->FileSystemType[6], FatVolumeBootSector->FileSystemType[7])); + DbgPrint((DPRINT_FILESYSTEM, "BootSectorMagic: 0x%x\n", FatVolumeBootSector->BootSectorMagic)); + } + +#endif // defined DEBUG + + // + // Check the boot sector magic + // + if (FatVolumeBootSector->BootSectorMagic != 0xaa55) + { + FileSystemError("Invalid boot sector magic (0xaa55)"); + return FALSE; + } + + SetDriveGeometry(get_cylinders(DriveNumber), get_heads(DriveNumber), get_sectors(DriveNumber), FatVolumeBootSector->BytesPerSector); + SetVolumeProperties(FatVolumeBootSector->HiddenSectors); + + // + // Check the FAT cluster size + // We do not support clusters bigger than 64k + // + if ((FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector) > (64 * 1024)) + { + FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this."); + return FALSE; + } + + // + // Clear our variables + // + RootDirSectorStart = 0; + DataSectorStart = 0; + SectorsPerFat = 0; + RootDirSectors = 0; + + // + // Get the sectors per FAT, + // root directory starting sector, + // and data sector start + // + if (FatType != FAT32) + { + SectorsPerFat = FatVolumeBootSector->SectorsPerFat; + + RootDirSectorStart = (FatVolumeBootSector->NumberOfFats * SectorsPerFat) + FatVolumeBootSector->ReservedSectors; + RootDirSectors = ((FatVolumeBootSector->RootDirEntries * 32) + (FatVolumeBootSector->BytesPerSector - 1)) / FatVolumeBootSector->BytesPerSector; + + DataSectorStart = FatVolumeBootSector->ReservedSectors + (FatVolumeBootSector->NumberOfFats * FatVolumeBootSector->SectorsPerFat) + RootDirSectors; + } + else + { + SectorsPerFat = Fat32VolumeBootSector->SectorsPerFatBig; + + DataSectorStart = FatVolumeBootSector->ReservedSectors + (FatVolumeBootSector->NumberOfFats * Fat32VolumeBootSector->SectorsPerFatBig) + RootDirSectors; + + + // + // Check version + // we only work with version 0 + // + if (Fat32VolumeBootSector->FileSystemVersion != 0) + { + FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader."); + return FALSE; + } + } + + return TRUE; +} + +PVOID FatBufferDirectory(UINT32 DirectoryStartCluster, PUINT32 EntryCountPointer, BOOL RootDirectory) +{ + UINT32 RootDirectoryStartSector; + UINT32 RootDirectorySectorCount; + PVOID DirectoryBuffer; + UINT32 DirectorySize; + + DbgPrint((DPRINT_FILESYSTEM, "FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster, (RootDirectory ? "TRUE" : "FALSE"))); + + // + // Calculate the size of the directory + // + if ((RootDirectory) && (FatType != FAT32)) + { + DirectorySize = (FatVolumeBootSector->RootDirEntries / 32) * 512; + } + else + { + if (RootDirectory) + { + DirectorySize = (FatCountClustersInChain(Fat32VolumeBootSector->RootDirStartCluster) * Fat32VolumeBootSector->SectorsPerCluster) * Fat32VolumeBootSector->BytesPerSector; + } + else + { + DirectorySize = (FatCountClustersInChain(DirectoryStartCluster) * FatVolumeBootSector->SectorsPerCluster) * FatVolumeBootSector->BytesPerSector; + } + } + + // + // Attempt to allocate memory for directory buffer + // + DirectoryBuffer = AllocateMemory(DirectorySize); + + if (DirectoryBuffer == NULL) + { + return NULL; + } + + // + // Now read directory contents into DirectoryBuffer + // + if (RootDirectory) + { + if (FatType == FAT32) + { + if (!FatReadClusterChain(Fat32VolumeBootSector->RootDirStartCluster, 0xFFFFFFFF, DirectoryBuffer)) + { + FreeMemory(DirectoryBuffer); + return NULL; + } + } + else + { + // + // FAT type is not FAT32 so the root directory comes right after the fat table + // + RootDirectoryStartSector = FatVolumeBootSector->ReservedSectors + (FatVolumeBootSector->NumberOfFats * FatVolumeBootSector->SectorsPerFat); + RootDirectorySectorCount = FatVolumeBootSector->RootDirEntries / 32; + + if (!ReadMultipleLogicalSectors(RootDirectoryStartSector, RootDirectorySectorCount, DirectoryBuffer)) + { + FreeMemory(DirectoryBuffer); + return NULL; + } + } + } + else + { + if (!FatReadClusterChain(DirectoryStartCluster, 0xFFFFFFFF, DirectoryBuffer)) + { + FreeMemory(DirectoryBuffer); + return NULL; + } + } + + *EntryCountPointer = (DirectorySize / 32); + + return DirectoryBuffer; +} + +BOOL FatSearchDirectoryBufferForFile(PVOID DirectoryBuffer, UINT32 EntryCount, PUCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer) +{ + ULONG CurrentEntry; + PDIRENTRY DirEntry; + PLFN_DIRENTRY LfnDirEntry; + UCHAR LfnNameBuffer[261]; + UCHAR ShortNameBuffer[13]; + UINT32 StartCluster; + + DbgPrint((DPRINT_FILESYSTEM, "FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer, EntryCount, FileName)); + + memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR)); + memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR)); + + for (CurrentEntry=0; CurrentEntryFileName[0] == 0x00) + { + return FALSE; + } + + // + // Check if this is a deleted entry or not + // + if (DirEntry->FileName[0] == 0xE5) + { + memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR)); + memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR)); + continue; + } + + // + // Check if this is a LFN entry + // If so it needs special handling + // + if (DirEntry->Attr == ATTR_LONG_NAME) + { + // + // Check to see if this is a deleted LFN entry, if so continue + // + if (LfnDirEntry->SequenceNumber & 0x80) + { + continue; + } + + // + // Mask off high two bits of sequence number + // and make the sequence number zero-based + // + LfnDirEntry->SequenceNumber &= 0x3F; + LfnDirEntry->SequenceNumber--; + + // + // Get all 13 LFN entry characters + // + if (LfnDirEntry->Name0_4[0] != 0xFFFF) + { + LfnNameBuffer[0 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[0]; + } + if (LfnDirEntry->Name0_4[1] != 0xFFFF) + { + LfnNameBuffer[1 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[1]; + } + if (LfnDirEntry->Name0_4[2] != 0xFFFF) + { + LfnNameBuffer[2 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[2]; + } + if (LfnDirEntry->Name0_4[3] != 0xFFFF) + { + LfnNameBuffer[3 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[3]; + } + if (LfnDirEntry->Name0_4[4] != 0xFFFF) + { + LfnNameBuffer[4 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name0_4[4]; + } + if (LfnDirEntry->Name5_10[0] != 0xFFFF) + { + LfnNameBuffer[5 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[0]; + } + if (LfnDirEntry->Name5_10[1] != 0xFFFF) + { + LfnNameBuffer[6 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[1]; + } + if (LfnDirEntry->Name5_10[2] != 0xFFFF) + { + LfnNameBuffer[7 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[2]; + } + if (LfnDirEntry->Name5_10[3] != 0xFFFF) + { + LfnNameBuffer[8 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[3]; + } + if (LfnDirEntry->Name5_10[4] != 0xFFFF) + { + LfnNameBuffer[9 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[4]; + } + if (LfnDirEntry->Name5_10[5] != 0xFFFF) + { + LfnNameBuffer[10 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name5_10[5]; + } + if (LfnDirEntry->Name11_12[0] != 0xFFFF) + { + LfnNameBuffer[11 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name11_12[0]; + } + if (LfnDirEntry->Name11_12[1] != 0xFFFF) + { + LfnNameBuffer[12 + (LfnDirEntry->SequenceNumber * 13)] = (UCHAR)LfnDirEntry->Name11_12[1]; + } + + continue; + } + + // + // Check for the volume label attribute + // and skip over this entry if found + // + if (DirEntry->Attr & ATTR_VOLUMENAME) + { + memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR)); + memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR)); + continue; + } + + // + // If we get here then we've found a short file name + // entry and LfnNameBuffer contains the long file + // name or zeroes. All we have to do now is see if the + // file name matches either the short or long file name + // and fill in the FAT_FILE_INFO structure if it does + // or zero our buffers and continue looking. + // + + // + // Get short file name + // + FatParseShortFileName(ShortNameBuffer, DirEntry); + + DbgPrint((DPRINT_FILESYSTEM, "Entry: %d LFN = %s\n", CurrentEntry, LfnNameBuffer)); + DbgPrint((DPRINT_FILESYSTEM, "Entry: %d DOS name = %s\n", CurrentEntry, ShortNameBuffer)); + + // + // See if the file name matches either the short or long name + // + if (((strlen(FileName) == strlen(LfnNameBuffer)) && (stricmp(FileName, LfnNameBuffer) == 0)) || + ((strlen(FileName) == strlen(ShortNameBuffer)) && (stricmp(FileName, ShortNameBuffer) == 0))) + { + // + // We found the entry, now fill in the FAT_FILE_INFO struct + // + FatFileInfoPointer->FileSize = DirEntry->Size; + FatFileInfoPointer->FilePointer = 0; + + // + // Get the cluster chain + // + StartCluster = ((UINT32)DirEntry->ClusterHigh << 16) + DirEntry->ClusterLow; + FatFileInfoPointer->FileFatChain = FatGetClusterChainArray(StartCluster); + + // + // See if memory allocation failed + // + if (FatFileInfoPointer->FileFatChain == NULL) + { + return FALSE; + } + + return TRUE; + } + + // + // Nope, no match - zero buffers and continue looking + // + memset(ShortNameBuffer, 0, 13 * sizeof(UCHAR)); + memset(LfnNameBuffer, 0, 261 * sizeof(UCHAR)); + continue; + } + + return FALSE; +} + +/* + * FatLookupFile() + * This function searches the file system for the + * specified filename and fills in a FAT_STRUCT structure + * with info describing the file, etc. returns true + * if the file exists or false otherwise + */ +BOOL FatLookupFile(PUCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer) +{ + int i; + ULONG NumberOfPathParts; + UCHAR PathPart[261]; + PVOID DirectoryBuffer; + UINT32 DirectoryStartCluster = 0; + ULONG DirectoryEntryCount; + FAT_FILE_INFO FatFileInfo; + + DbgPrint((DPRINT_FILESYSTEM, "FatLookupFile() FileName = %s\n", FileName)); + + memset(FatFileInfoPointer, 0, sizeof(FAT_FILE_INFO)); + + // + // Check and see if the first character is '\' and remove it if so + // + while (*FileName == '\\') + { + FileName++; + } + + // + // Figure out how many sub-directories we are nested in + // + NumberOfPathParts = FatGetNumPathParts(FileName); + + // + // Loop once for each part + // + for (i=0; iFileName[0] == 0x05) + { + DirEntry->FileName[0] = 0xE5; + } + + // + // Get the file name + // + while (Idx < 8) + { + if (DirEntry->FileName[Idx] == ' ') + { + break; + } + + Buffer[Idx] = DirEntry->FileName[Idx]; + Idx++; + } + + // + // Get extension + // + if ((DirEntry->FileName[8] != ' ')) + { + Buffer[Idx++] = '.'; + Buffer[Idx++] = (DirEntry->FileName[8] == ' ') ? '\0' : DirEntry->FileName[8]; + Buffer[Idx++] = (DirEntry->FileName[9] == ' ') ? '\0' : DirEntry->FileName[9]; + Buffer[Idx++] = (DirEntry->FileName[10] == ' ') ? '\0' : DirEntry->FileName[10]; + } + + // + // Null-Terminate string + // + Buffer[Idx + 4] = '\0'; + + DbgPrint((DPRINT_FILESYSTEM, "FatParseShortFileName() ShortName = %s\n", Buffer)); +} + +/* + * FatGetFatEntry() + * returns the Fat entry for a given cluster number + */ +DWORD FatGetFatEntry(DWORD nCluster) +{ + DWORD fat = 0; + int FatOffset; + int ThisFatSecNum; + int ThisFatEntOffset; + + DbgPrint((DPRINT_FILESYSTEM, "FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", nCluster)); + + switch(FatType) + { + case FAT12: + + FatOffset = nCluster + (nCluster / 2); + ThisFatSecNum = FatVolumeBootSector->ReservedSectors + (FatOffset / FatVolumeBootSector->BytesPerSector); + ThisFatEntOffset = (FatOffset % FatVolumeBootSector->BytesPerSector); + + DbgPrint((DPRINT_FILESYSTEM, "FatOffset: %d\n", FatOffset)); + DbgPrint((DPRINT_FILESYSTEM, "ThisFatSecNum: %d\n", ThisFatSecNum)); + DbgPrint((DPRINT_FILESYSTEM, "ThisFatEntOffset: %d\n", ThisFatEntOffset)); + + if (ThisFatEntOffset == (FatVolumeBootSector->BytesPerSector - 1)) + { + if (!ReadMultipleLogicalSectors(ThisFatSecNum, 2, DISKREADBUFFER)) + { + return NULL; + } + } + else + { + if (!ReadLogicalSector(ThisFatSecNum, DISKREADBUFFER)) + { + return NULL; + } + } + + fat = *((WORD *) (DISKREADBUFFER + ThisFatEntOffset)); + if (nCluster & 0x0001) + fat = fat >> 4; /* Cluster number is ODD */ + else + fat = fat & 0x0FFF; /* Cluster number is EVEN */ + + break; + + case FAT16: + + FatOffset = (nCluster * 2); + ThisFatSecNum = FatVolumeBootSector->ReservedSectors + (FatOffset / FatVolumeBootSector->BytesPerSector); + ThisFatEntOffset = (FatOffset % FatVolumeBootSector->BytesPerSector); + + if (!ReadLogicalSector(ThisFatSecNum, DISKREADBUFFER)) + { + return NULL; + } + + fat = *((WORD *) (DISKREADBUFFER + ThisFatEntOffset)); + + break; + + case FAT32: + + FatOffset = (nCluster * 4); + ThisFatSecNum = FatVolumeBootSector->ReservedSectors + (FatOffset / FatVolumeBootSector->BytesPerSector); + ThisFatEntOffset = (FatOffset % FatVolumeBootSector->BytesPerSector); + + if (!ReadLogicalSector(ThisFatSecNum, DISKREADBUFFER)) + { + return NULL; + } + + // Get the fat entry + fat = (*((DWORD *) (DISKREADBUFFER + ThisFatEntOffset))) & 0x0FFFFFFF; + + break; + + } + + DbgPrint((DPRINT_FILESYSTEM, "FAT entry is 0x%x.\n", fat)); + + return fat; +} + +/* + * FatOpenFile() + * Tries to open the file 'name' and returns true or false + * for success and failure respectively + */ +FILE* FatOpenFile(PUCHAR FileName) +{ + FAT_FILE_INFO TempFatFileInfo; + PFAT_FILE_INFO FileHandle; + + DbgPrint((DPRINT_FILESYSTEM, "FatOpenFile() FileName = %s\n", FileName)); + + if (!FatLookupFile(FileName, &TempFatFileInfo)) + { + return NULL; + } + + FileHandle = AllocateMemory(sizeof(FAT_FILE_INFO)); + + if (FileHandle == NULL) + { + return NULL; + } + + memcpy(FileHandle, &TempFatFileInfo, sizeof(FAT_FILE_INFO)); + + return (FILE*)FileHandle; +} + +UINT32 FatCountClustersInChain(UINT32 StartCluster) +{ + UINT32 ClusterCount = 0; + + DbgPrint((DPRINT_FILESYSTEM, "FatCountClustersInChain() StartCluster = %d\n", StartCluster)); + + while (1) + { + // + // If end of chain then break out of our cluster counting loop + // + if (((FatType == FAT12) && (StartCluster >= 0xff8)) || + ((FatType == FAT16) && (StartCluster >= 0xfff8)) || + ((FatType == FAT32) && (StartCluster >= 0x0ffffff8))) + { + break; + } + + // + // Increment count + // + ClusterCount++; + + // + // Get next cluster + // + StartCluster = FatGetFatEntry(StartCluster); + } + + DbgPrint((DPRINT_FILESYSTEM, "FatCountClustersInChain() ClusterCount = %d\n", ClusterCount)); + + return ClusterCount; +} + +PUINT32 FatGetClusterChainArray(UINT32 StartCluster) +{ + UINT32 ClusterCount; + ULONG ArraySize; + PUINT32 ArrayPointer; + ULONG Idx; + + DbgPrint((DPRINT_FILESYSTEM, "FatGetClusterChainArray() StartCluster = %d\n", StartCluster)); + + ClusterCount = FatCountClustersInChain(StartCluster) + 1; // Lets get the 0x0ffffff8 on the end of the array + ArraySize = ClusterCount * sizeof(UINT32); + + // + // Allocate array memory + // + ArrayPointer = AllocateMemory(ArraySize); + + if (ArrayPointer == NULL) + { + return NULL; + } + + // + // Loop through and set array values + // + for (Idx=0; Idx= 0xff8)) || + ((FatType == FAT16) && (StartCluster >= 0xfff8)) || + ((FatType == FAT32) && (StartCluster >= 0x0ffffff8))) + { + Idx++; + break; + } + + // + // Get next cluster + // + StartCluster = FatGetFatEntry(StartCluster); + } + + return ArrayPointer; +} + +/* + * FatReadCluster() + * Reads the specified cluster into memory + * and returns the number of bytes read + */ +BOOL FatReadCluster(ULONG ClusterNumber, PVOID Buffer) +{ + ULONG ClusterStartSector; + + ClusterStartSector = ((ClusterNumber - 2) * FatVolumeBootSector->SectorsPerCluster) + DataSectorStart; + + DbgPrint((DPRINT_FILESYSTEM, "FatReadCluster() ClusterNumber = %d Buffer = 0x%x ClusterStartSector = %d\n", ClusterNumber, Buffer, ClusterStartSector)); + + if (!ReadMultipleLogicalSectors(ClusterStartSector, FatVolumeBootSector->SectorsPerCluster, DISKREADBUFFER)) + { + return FALSE; + } + + memcpy(Buffer, DISKREADBUFFER, FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector); + + return TRUE; +} + +/* + * FatReadClusterChain() + * Reads the specified clusters into memory + */ +BOOL FatReadClusterChain(ULONG StartClusterNumber, ULONG NumberOfClusters, PVOID Buffer) +{ + ULONG ClusterStartSector; + + DbgPrint((DPRINT_FILESYSTEM, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer)); + + while (NumberOfClusters > 0) + { + + DbgPrint((DPRINT_FILESYSTEM, "FatReadClusterChain() StartClusterNumber = %d NumberOfClusters = %d Buffer = 0x%x\n", StartClusterNumber, NumberOfClusters, Buffer)); + // + // Calculate starting sector for cluster + // + ClusterStartSector = ((StartClusterNumber - 2) * FatVolumeBootSector->SectorsPerCluster) + DataSectorStart; + + // + // Read cluster into memory + // + if (!ReadMultipleLogicalSectors(ClusterStartSector, FatVolumeBootSector->SectorsPerCluster, DISKREADBUFFER)) + { + return FALSE; + } + + memcpy(Buffer, DISKREADBUFFER, FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector); + + // + // Decrement count of clusters left to read + // + NumberOfClusters--; + + // + // Increment buffer address by cluster size + // + Buffer += (FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector); + + // + // Get next cluster + // + StartClusterNumber = FatGetFatEntry(StartClusterNumber); + + // + // If end of chain then break out of our cluster reading loop + // + if (((FatType == FAT12) && (StartClusterNumber >= 0xff8)) || + ((FatType == FAT16) && (StartClusterNumber >= 0xfff8)) || + ((FatType == FAT32) && (StartClusterNumber >= 0x0ffffff8))) + { + break; + } + } + + return TRUE; +} + +/* + * FatReadPartialCluster() + * Reads part of a cluster into memory + */ +BOOL FatReadPartialCluster(ULONG ClusterNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer) +{ + ULONG ClusterStartSector; + + DbgPrint((DPRINT_FILESYSTEM, "FatReadPartialCluster() ClusterNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", ClusterNumber, StartingOffset, Length, Buffer)); + + ClusterStartSector = ((ClusterNumber - 2) * FatVolumeBootSector->SectorsPerCluster) + DataSectorStart; + + if (!ReadMultipleLogicalSectors(ClusterStartSector, FatVolumeBootSector->SectorsPerCluster, DISKREADBUFFER)) + { + return FALSE; + } + + memcpy(Buffer, DISKREADBUFFER + StartingOffset, Length); + + return TRUE; +} + +/* + * FatReadFile() + * Reads BytesToRead from open file and + * returns the number of bytes read in BytesRead + */ +BOOL FatReadFile(FILE *FileHandle, ULONG BytesToRead, PULONG BytesRead, PVOID Buffer) +{ + PFAT_FILE_INFO FatFileInfo = (PFAT_FILE_INFO)FileHandle; + UINT32 ClusterNumber; + UINT32 OffsetInCluster; + UINT32 LengthInCluster; + UINT32 NumberOfClusters; + UINT32 BytesPerCluster; + + DbgPrint((DPRINT_FILESYSTEM, "FatReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead, Buffer)); + + if (BytesRead != NULL) + { + *BytesRead = 0; + } + + // + // If they are trying to read past the + // end of the file then return success + // with BytesRead == 0 + // + if (FatFileInfo->FilePointer >= FatFileInfo->FileSize) + { + return TRUE; + } + + // + // If they are trying to read more than there is to read + // then adjust the amount to read + // + if ((FatFileInfo->FilePointer + BytesToRead) > FatFileInfo->FileSize) + { + BytesToRead = (FatFileInfo->FileSize - FatFileInfo->FilePointer); + } + + // + // Ok, now we have to perform at most 3 calculations + // I'll draw you a picture (using nifty ASCII art): + // + // CurrentFilePointer -+ + // | + // +----------------+ + // | + // +-----------+-----------+-----------+-----------+ + // | Cluster 1 | Cluster 2 | Cluster 3 | Cluster 4 | + // +-----------+-----------+-----------+-----------+ + // | | + // +---------------+--------------------+ + // | + // BytesToRead -------+ + // + // 1 - The first calculation (and read) will align + // the file pointer with the next cluster. + // boundary (if we are supposed to read that much) + // 2 - The next calculation (and read) will read + // in all the full clusters that the requested + // amount of data would cover (in this case + // clusters 2 & 3). + // 3 - The last calculation (and read) would read + // in the remainder of the data requested out of + // the last cluster. + // + + BytesPerCluster = (FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector); + + // + // Only do the first read if we + // aren't aligned on a cluster boundary + // + if (FatFileInfo->FilePointer % BytesPerCluster) + { + // + // Do the math for our first read + // + ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster); + ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber]; + OffsetInCluster = (FatFileInfo->FilePointer % BytesPerCluster); + LengthInCluster = (BytesToRead > (BytesPerCluster - OffsetInCluster)) ? (BytesPerCluster - OffsetInCluster) : BytesToRead; + + // + // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer + // + if (!FatReadPartialCluster(ClusterNumber, OffsetInCluster, LengthInCluster, Buffer)) + { + return FALSE; + } + if (BytesRead != NULL) + { + *BytesRead += LengthInCluster; + } + BytesToRead -= LengthInCluster; + FatFileInfo->FilePointer += LengthInCluster; + Buffer += LengthInCluster; + } + + // + // Do the math for our second read (if any data left) + // + if (BytesToRead > 0) + { + // + // Determine how many full clusters we need to read + // + NumberOfClusters = (BytesToRead / BytesPerCluster); + + if (NumberOfClusters > 0) + { + ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster); + ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber]; + + // + // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer + // + if (!FatReadClusterChain(ClusterNumber, NumberOfClusters, Buffer)) + { + return FALSE; + } + if (BytesRead != NULL) + { + *BytesRead += (NumberOfClusters * BytesPerCluster); + } + BytesToRead -= (NumberOfClusters * BytesPerCluster); + FatFileInfo->FilePointer += (NumberOfClusters * BytesPerCluster); + Buffer += (NumberOfClusters * BytesPerCluster); + } + } + + // + // Do the math for our third read (if any data left) + // + if (BytesToRead > 0) + { + ClusterNumber = (FatFileInfo->FilePointer / BytesPerCluster); + ClusterNumber = FatFileInfo->FileFatChain[ClusterNumber]; + + // + // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer + // + if (!FatReadPartialCluster(ClusterNumber, 0, BytesToRead, Buffer)) + { + return FALSE; + } + if (BytesRead != NULL) + { + *BytesRead += BytesToRead; + } + BytesToRead -= BytesToRead; + FatFileInfo->FilePointer += BytesToRead; + Buffer += BytesToRead; + } + + return TRUE; +} + +ULONG FatGetFileSize(FILE *FileHandle) +{ + PFAT_FILE_INFO FatFileHandle = (PFAT_FILE_INFO)FileHandle; + + DbgPrint((DPRINT_FILESYSTEM, "FatGetFileSize() FileSize = %d\n", FatFileHandle->FileSize)); + + return FatFileHandle->FileSize; +} + +VOID FatSetFilePointer(FILE *FileHandle, ULONG NewFilePointer) +{ + PFAT_FILE_INFO FatFileHandle = (PFAT_FILE_INFO)FileHandle; + + DbgPrint((DPRINT_FILESYSTEM, "FatSetFilePointer() NewFilePointer = %d\n", NewFilePointer)); + + FatFileHandle->FilePointer = NewFilePointer; +} + +ULONG FatGetFilePointer(FILE *FileHandle) +{ + PFAT_FILE_INFO FatFileHandle = (PFAT_FILE_INFO)FileHandle; + + DbgPrint((DPRINT_FILESYSTEM, "FatGetFilePointer() FilePointer = %d\n", FatFileHandle->FilePointer)); + + return FatFileHandle->FilePointer; +} + diff --git a/freeldr/freeldr/fat.h b/freeldr/freeldr/fat.h new file mode 100644 index 00000000000..4444023075c --- /dev/null +++ b/freeldr/freeldr/fat.h @@ -0,0 +1,179 @@ +/* + * FreeLoader + * Copyright (C) 2001 Brian Palmer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __FAT_H +#define __FAT_H + +typedef struct _FAT_BOOTSECTOR +{ + BYTE JumpBoot[3]; // Jump instruction to boot code + UCHAR OemName[8]; // "MSWIN4.1" for MS formatted volumes + WORD BytesPerSector; // Bytes per sector + BYTE SectorsPerCluster; // Number of sectors in a cluster + WORD ReservedSectors; // Reserved sectors, usually 1 (the bootsector) + BYTE NumberOfFats; // Number of FAT tables + WORD RootDirEntries; // Number of root directory entries (fat12/16) + WORD TotalSectors; // Number of total sectors on the drive, 16-bit + BYTE MediaDescriptor; // Media descriptor byte + WORD SectorsPerFat; // Sectors per FAT table (fat12/16) + WORD SectorsPerTrack; // Number of sectors in a track + WORD NumberOfHeads; // Number of heads on the disk + DWORD HiddenSectors; // Hidden sectors (sectors before the partition start like the partition table) + DWORD TotalSectorsBig; // This field is the new 32-bit total count of sectors on the volume + BYTE DriveNumber; // Int 0x13 drive number (e.g. 0x80) + BYTE Reserved1; // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0. + BYTE BootSignature; // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present. + DWORD VolumeSerialNumber; // Volume serial number + UCHAR VolumeLabel[11]; // Volume label. This field matches the 11-byte volume label recorded in the root directory + UCHAR FileSystemType[8]; // One of the strings "FAT12 ", "FAT16 ", or "FAT " + + BYTE BootCodeAndData[448]; // The remainder of the boot sector + + WORD BootSectorMagic; // 0xAA55 + +} PACKED FAT_BOOTSECTOR, *PFAT_BOOTSECTOR; + +typedef struct _FAT32_BOOTSECTOR +{ + BYTE JumpBoot[3]; // Jump instruction to boot code + UCHAR OemName[8]; // "MSWIN4.1" for MS formatted volumes + WORD BytesPerSector; // Bytes per sector + BYTE SectorsPerCluster; // Number of sectors in a cluster + WORD ReservedSectors; // Reserved sectors, usually 1 (the bootsector) + BYTE NumberOfFats; // Number of FAT tables + WORD RootDirEntries; // Number of root directory entries (fat12/16) + WORD TotalSectors; // Number of total sectors on the drive, 16-bit + BYTE MediaDescriptor; // Media descriptor byte + WORD SectorsPerFat; // Sectors per FAT table (fat12/16) + WORD SectorsPerTrack; // Number of sectors in a track + WORD NumberOfHeads; // Number of heads on the disk + DWORD HiddenSectors; // Hidden sectors (sectors before the partition start like the partition table) + DWORD TotalSectorsBig; // This field is the new 32-bit total count of sectors on the volume + DWORD SectorsPerFatBig; // This field is the FAT32 32-bit count of sectors occupied by ONE FAT. BPB_FATSz16 must be 0 + WORD ExtendedFlags; // Extended flags (fat32) + WORD FileSystemVersion; // File system version (fat32) + DWORD RootDirStartCluster; // Starting cluster of the root directory (fat32) + WORD FsInfo; // Sector number of FSINFO structure in the reserved area of the FAT32 volume. Usually 1. + WORD BackupBootSector; // If non-zero, indicates the sector number in the reserved area of the volume of a copy of the boot record. Usually 6. + BYTE Reserved[12]; // Reserved for future expansion + BYTE DriveNumber; // Int 0x13 drive number (e.g. 0x80) + BYTE Reserved1; // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0. + BYTE BootSignature; // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present. + DWORD VolumeSerialNumber; // Volume serial number + UCHAR VolumeLabel[11]; // Volume label. This field matches the 11-byte volume label recorded in the root directory + UCHAR FileSystemType[8]; // Always set to the string "FAT32 " + + BYTE BootCodeAndData[420]; // The remainder of the boot sector + + WORD BootSectorMagic; // 0xAA55 + +} PACKED FAT32_BOOTSECTOR, *PFAT32_BOOTSECTOR; + +/* + * Structure of MSDOS directory entry + */ +typedef struct //_DIRENTRY +{ + UCHAR FileName[11]; /* Filename + extension */ + UINT8 Attr; /* File attributes */ + UINT8 ReservedNT; /* Reserved for use by Windows NT */ + UINT8 TimeInTenths; /* Millisecond stamp at file creation */ + UINT16 CreateTime; /* Time file was created */ + UINT16 CreateDate; /* Date file was created */ + UINT16 LastAccessDate; /* Date file was last accessed */ + UINT16 ClusterHigh; /* High word of this entry's start cluster */ + UINT16 Time; /* Time last modified */ + UINT16 Date; /* Date last modified */ + UINT16 ClusterLow; /* First cluster number low word */ + UINT32 Size; /* File size */ +} PACKED DIRENTRY, * PDIRENTRY; + +typedef struct +{ + UINT8 SequenceNumber; /* Sequence number for slot */ + WCHAR Name0_4[5]; /* First 5 characters in name */ + UINT8 EntryAttributes; /* Attribute byte */ + UINT8 Reserved; /* Always 0 */ + UINT8 AliasChecksum; /* Checksum for 8.3 alias */ + WCHAR Name5_10[6]; /* 6 more characters in name */ + UINT16 StartCluster; /* Starting cluster number */ + WCHAR Name11_12[2]; /* Last 2 characters in name */ +} PACKED LFN_DIRENTRY, * PLFN_DIRENTRY; + +typedef struct +{ + ULONG FileSize; // File size + ULONG FilePointer; // File pointer + PUINT32 FileFatChain; // File fat chain array +} FAT_FILE_INFO, * PFAT_FILE_INFO; + + + +BOOL FatOpenVolume(ULONG DriveNumber, ULONG VolumeStartHead, ULONG VolumeStartTrack, ULONG VolumeStartSector, ULONG FatFileSystemType); +PVOID FatBufferDirectory(UINT32 DirectoryStartCluster, PUINT32 EntryCountPointer, BOOL RootDirectory); +BOOL FatSearchDirectoryBufferForFile(PVOID DirectoryBuffer, UINT32 EntryCount, PUCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer); +BOOL FatLookupFile(PUCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer); +ULONG FatGetNumPathParts(PUCHAR Path); +VOID FatGetFirstNameFromPath(PUCHAR Buffer, PUCHAR Path); +void FatParseShortFileName(PUCHAR Buffer, PDIRENTRY DirEntry); +DWORD FatGetFatEntry(DWORD nCluster); +FILE* FatOpenFile(PUCHAR FileName); +UINT32 FatCountClustersInChain(UINT32 StartCluster); +PUINT32 FatGetClusterChainArray(UINT32 StartCluster); +BOOL FatReadCluster(ULONG ClusterNumber, PVOID Buffer); +BOOL FatReadClusterChain(ULONG StartClusterNumber, ULONG NumberOfClusters, PVOID Buffer); +BOOL FatReadPartialCluster(ULONG ClusterNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer); +BOOL FatReadFile(FILE *FileHandle, ULONG BytesToRead, PULONG BytesRead, PVOID Buffer); +ULONG FatGetFileSize(FILE *FileHandle); +VOID FatSetFilePointer(FILE *FileHandle, ULONG NewFilePointer); +ULONG FatGetFilePointer(FILE *FileHandle); + + +/*BOOL FatLookupFile(char *file, PFAT_STRUCT pFatStruct); +int FatGetNumPathParts(char *name); +BOOL FatGetFirstNameFromPath(char *buffer, char *name); +void FatParseFileName(char *buffer, char *name); +DWORD FatGetFatEntry(DWORD nCluster); +int FatReadCluster(DWORD nCluster, char *cBuffer); +int FatRead(PFAT_STRUCT pFatStruct, int nNumBytes, char *cBuffer); +int Fatfseek(PFAT_STRUCT pFatStruct, DWORD offset); + +FILE* FatOpenFile(PUCHAR FileName); +BOOL FatReadFile(FILE *FileHandle, ULONG BytesToRead, PULONG BytesRead, PVOID Buffer); +ULONG FatGetFileSize(FILE *FileHandle); +VOID FatSetFilePointer(FILE *FileHandle, ULONG NewFilePointer); +ULONG FatGetFilePointer(FILE *FileHandle);*/ + + +#define EOF -1 + +#define ATTR_NORMAL 0x00 +#define ATTR_READONLY 0x01 +#define ATTR_HIDDEN 0x02 +#define ATTR_SYSTEM 0x04 +#define ATTR_VOLUMENAME 0x08 +#define ATTR_DIRECTORY 0x10 +#define ATTR_ARCHIVE 0x20 +#define ATTR_LONG_NAME (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUMENAME) + +#define FAT12 1 +#define FAT16 2 +#define FAT32 3 + +#endif // #defined __FAT_H \ No newline at end of file diff --git a/freeldr/freeldr/freeldr.c b/freeldr/freeldr/freeldr.c index 3f45a279185..76541de1af6 100644 --- a/freeldr/freeldr/freeldr.c +++ b/freeldr/freeldr/freeldr.c @@ -1,6 +1,6 @@ /* * FreeLoader - * Copyright (C) 1999, 2000 Brian Palmer + * Copyright (C) 1999, 2000, 2001 Brian Palmer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,41 +29,42 @@ #include "memory.h" #include "parseini.h" #include "debug.h" +#include "oslist.h" // Variable BootDrive moved to asmcode.S -//ULONG BootDrive = 0; // BIOS boot drive, 0-A:, 1-B:, 0x80-C:, 0x81-D:, etc. -ULONG BootPartition = 0; // Boot Partition, 1-4 -BOOL UserInterfaceUp = FALSE; // Tells us if the user interface is displayed +//ULONG BootDrive = 0; // BIOS boot drive, 0-A:, 1-B:, 0x80-C:, 0x81-D:, etc. +ULONG BootPartition = 0; // Boot Partition, 1-4 -PUCHAR ScreenBuffer = (PUCHAR)(SCREENBUFFER); // Save buffer for screen contents -int CursorXPos = 0; // Cursor's X Position -int CursorYPos = 0; // Cursor's Y Position +PUCHAR ScreenBuffer = (PUCHAR)(SCREENBUFFER); // Save buffer for screen contents +ULONG CursorXPos = 0; // Cursor's X Position +ULONG CursorYPos = 0; // Cursor's Y Position -OSTYPE OSList[16]; -int nNumOS = 0; +ULONG GetDefaultOperatingSystem(PUCHAR OperatingSystemList[], ULONG OperatingSystemCount); +LONG GetTimeOut(VOID); -int nTimeOut = -1; // Time to wait for the user before booting - -void BootMain(void) +VOID BootMain(VOID) { - int i; - char name[1024]; - char value[1024]; - int nOSToBoot; + ULONG Idx; + UCHAR SettingName[80]; + UCHAR SettingValue[80]; + ULONG SectionId; + ULONG OperatingSystemCount; + PUCHAR *OperatingSystemSectionNames; + PUCHAR *OperatingSystemDisplayNames; + ULONG DefaultOperatingSystem; + LONG TimeOut; + ULONG SelectedOperatingSystem; enable_a20(); - SaveScreen(ScreenBuffer); - CursorXPos = wherex(); - CursorYPos = wherey(); - - printf("Loading FreeLoader...\n"); + CursorXPos = (ULONG) *((PUCHAR)(SCREENXCOORD)); + CursorYPos = (ULONG) *((PUCHAR)(SCREENYCOORD)); #ifdef DEBUG DebugInit(); #endif - InitMemoryManager((PVOID)0x100000, 0x20000); + InitMemoryManager( (PVOID) 0x20000 /* BaseAddress */, 0x70000 /* Length */); if (!ParseIniFile()) { @@ -72,39 +73,63 @@ void BootMain(void) return; } - clrscr(); - hidecursor(); - // Draw the backdrop and title box - DrawBackdrop(); - UserInterfaceUp = TRUE; + if (!OpenSection("FreeLoader", &SectionId)) + { + printf("Section [FreeLoader] not found in freeldr.ini.\n"); + getch(); + return; + } - if (nNumOS == 0) + if (!InitUserInterface()) { - DrawStatusText(" Press ENTER to reboot"); - MessageBox("Error: there were no operating systems listed in freeldr.ini.\nPress ENTER to reboot."); - clrscr(); - showcursor(); - RestoreScreen(ScreenBuffer); + printf("Press any key to reboot.\n"); + getch(); return; } + + if (!InitOperatingSystemList(&OperatingSystemSectionNames, &OperatingSystemDisplayNames, &OperatingSystemCount)) + { + MessageBox("Press ENTER to reboot.\n"); + goto reboot; + } + if (OperatingSystemCount == 0) + { + MessageBox("There were no operating systems listed in freeldr.ini.\nPress ENTER to reboot."); + goto reboot; + } - DrawStatusText(" Press ENTER to continue"); + DefaultOperatingSystem = GetDefaultOperatingSystem(OperatingSystemSectionNames, OperatingSystemCount); + TimeOut = GetTimeOut(); + + // // Find all the message box settings and run them - for (i=1; i<=GetNumSectionItems("FREELOADER"); i++) + // + for (Idx=0; Idx + * Copyright (C) 1999, 2000, 2001 Brian Palmer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,33 +54,27 @@ #define PWORD WORD * #define VOID void #define PVOID VOID* +#define INT8 char +#define UINT8 unsigned char +#define INT16 short +#define UINT16 unsigned short +#define INT32 long +#define UINT32 unsigned long +#define PUINT32 UINT32 * +#define INT64 long long +#define UINT64 unsigned long long #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S)) -#define OSTYPE_REACTOS 1 -#define OSTYPE_LINUX 2 -#define OSTYPE_BOOTSECTOR 3 -#define OSTYPE_PARTITION 4 -#define OSTYPE_DRIVE 5 - -typedef struct -{ - char name[260]; - int nOSType; // ReactOS or Linux or a bootsector, etc. -} OSTYPE, *POSTYPE; +#define PACKED __attribute__((packed)) extern ULONG BootDrive; // BIOS boot drive, 0-A:, 1-B:, 0x80-C:, 0x81-D:, etc. extern ULONG BootPartition; // Boot Partition, 1-4 extern BOOL UserInterfaceUp; // Tells us if the user interface is displayed extern PUCHAR ScreenBuffer; // Save buffer for screen contents -extern int CursorXPos; // Cursor's X Position -extern int CursorYPos; // Cursor's Y Position - -extern OSTYPE OSList[16]; // The OS list -extern int nNumOS; // Number of OSes listed - -extern int nTimeOut; // Time to wait for the user before booting +extern ULONG CursorXPos; // Cursor's X Position +extern ULONG CursorYPos; // Cursor's Y Position void BootMain(void); diff --git a/freeldr/freeldr/fs.c b/freeldr/freeldr/fs.c index 8fbd8112650..825030693d5 100644 --- a/freeldr/freeldr/fs.c +++ b/freeldr/freeldr/fs.c @@ -1,6 +1,6 @@ /* * FreeLoader - * Copyright (C) 1999, 2000 Brian Palmer + * Copyright (C) 1999, 2000, 2001 Brian Palmer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,251 +19,238 @@ #include "freeldr.h" #include "fs.h" +#include "fat.h" #include "stdlib.h" #include "tui.h" #include "asmcode.h" +#include "debug.h" -#define FS_DO_ERROR(s) \ - { \ - if (UserInterfaceUp) \ - MessageBox(s); \ - else \ - { \ - printf(s); \ - printf("\nPress any key\n"); \ - getch(); \ - } \ - } - - -int nSectorBuffered = -1; // Tells us which sector was read into SectorBuffer[] -BYTE SectorBuffer[512]; // 512 byte buffer space for read operations, ReadOneSector reads to here +///////////////////////////////////////////////////////////////////////////////////////////// +// DATA +///////////////////////////////////////////////////////////////////////////////////////////// -int FSType = NULL; // Type of filesystem on boot device, set by OpenDiskDrive() +GEOMETRY DriveGeometry; +ULONG VolumeHiddenSectors; +ULONG CurrentlyOpenDriveNumber; +ULONG FileSystemType = 0; // Type of filesystem on boot device, set by OpenDiskDrive() -char *pFileSysData = (char *)(FILESYSADDR); // Load address for filesystem data -char *pFat32FATCacheIndex = (char *)(FILESYSADDR); // Load address for filesystem data +///////////////////////////////////////////////////////////////////////////////////////////// +// FUNCTIONS +///////////////////////////////////////////////////////////////////////////////////////////// -BOOL OpenDiskDrive(int nDrive, int nPartition) +VOID FileSystemError(PUCHAR ErrorString) { - int num_bootable_partitions = 0; - int boot_partition = 0; - int partition_type = 0; - int head, sector, cylinder; - int offset; + DbgPrint((DPRINT_FILESYSTEM, "%s\n", ErrorString)); - // Check and see if it is a floppy drive - if (nDrive < 0x80) + if (UserInterfaceUp) { - // Read boot sector - if (!biosdisk(_DISK_READ, nDrive, 0, 0, 1, 1, SectorBuffer)) - { - FS_DO_ERROR("Disk Read Error"); - return FALSE; - } - - // Check for validity - if (*((WORD*)(SectorBuffer + 0x1fe)) != 0xaa55)//(SectorBuffer[0x1FE] != 0x55) || (SectorBuffer[0x1FF] != 0xAA)) - { - FS_DO_ERROR("Invalid boot sector magic (0xaa55)"); - return FALSE; - } + MessageBox(ErrorString); } else { - // Read master boot record - if (!biosdisk(_DISK_READ, nDrive, 0, 0, 1, 1, SectorBuffer)) - { - FS_DO_ERROR("Disk Read Error"); - return FALSE; - } - - // Check for validity - if (*((WORD*)(SectorBuffer + 0x1fe)) != 0xaa55)//(SectorBuffer[0x1FE] != 0x55) || (SectorBuffer[0x1FF] != 0xAA)) - { - FS_DO_ERROR("Invalid partition table magic (0xaa55)"); - return FALSE; - } - - if (nPartition == 0) - { - // Check for bootable partitions - if (SectorBuffer[0x1BE] == 0x80) - num_bootable_partitions++; - if (SectorBuffer[0x1CE] == 0x80) - { - num_bootable_partitions++; - boot_partition = 1; - } - if (SectorBuffer[0x1DE] == 0x80) - { - num_bootable_partitions++; - boot_partition = 2; - } - if (SectorBuffer[0x1EE] == 0x80) - { - num_bootable_partitions++; - boot_partition = 3; - } - - // Make sure there was only one bootable partition - if (num_bootable_partitions > 1) - { - FS_DO_ERROR("Too many boot partitions"); - return FALSE; - } - - offset = 0x1BE + (boot_partition * 0x10); - } - else - offset = 0x1BE + ((nPartition-1) * 0x10); + printf("%s", ErrorString); + printf("\nPress any key\n"); + getch(); + } +} - partition_type = SectorBuffer[offset + 4]; +/* + * + * BOOL OpenDiskDrive(ULONG DriveNumber, ULONG PartitionNumber); + * + * This function is called to open a disk drive for file access. + * It must be called before any of the file functions will work. + * It takes two parameters: + * + * Drive: The BIOS drive number of the disk to open + * Partition: This is zero for floppy drives. + * If the disk is a hard disk then this specifies + * The partition number to open (1 - 4) + * If it is zero then it opens the active (bootable) partition + * + */ +BOOL OpenDiskDrive(ULONG DriveNumber, ULONG PartitionNumber) +{ + ULONG BootablePartitionCount = 0; + ULONG BootPartition = 0; + ULONG PartitionStartHead; + ULONG PartitionStartSector; + ULONG PartitionStartCylinder; + MASTER_BOOT_RECORD DriveMasterBootRecord; - // Check for valid partition - if (partition_type == 0) - { - FS_DO_ERROR("Invalid boot partition"); - return FALSE; - } + DbgPrint((DPRINT_FILESYSTEM, "OpenDiskDrive() DriveNumber: 0x%x PartitionNumber: 0x%x\n", DriveNumber, PartitionNumber)); - head = SectorBuffer[offset + 1]; - sector = (SectorBuffer[offset + 2] & 0x3F); - cylinder = SectorBuffer[offset + 3]; - if (SectorBuffer[offset + 2] & 0x80) - cylinder += 0x200; - if (SectorBuffer[offset + 2] & 0x40) - cylinder += 0x100; + CurrentlyOpenDriveNumber = DriveNumber; - // Read partition boot sector - if (!biosdisk(_DISK_READ, nDrive, head, cylinder, sector, 1, SectorBuffer)) - { - FS_DO_ERROR("Disk Read Error"); - return FALSE; - } + // + // Check and see if it is a floppy drive + // If so then just assume FAT12 file system type + // + if (DriveNumber < 0x80) + { + DbgPrint((DPRINT_FILESYSTEM, "Drive is a floppy diskette drive. Assuming FAT12 file system.\n")); - // Check for validity - if (*((WORD*)(SectorBuffer + 0x1fe)) != 0xaa55)//(SectorBuffer[0x1FE] != 0x55) || (SectorBuffer[0x1FF] != 0xAA)) - { - FS_DO_ERROR("Invalid boot sector magic (0xaa55)"); - return FALSE; - } + FileSystemType = FS_FAT; + return FatOpenVolume(DriveNumber, 0, 0, 1, FAT12); } + // + // Read master boot record + // + if (!BiosInt13Read(DriveNumber, 0, 0, 1, 1, &DriveMasterBootRecord)) + { + FileSystemError("Disk read error."); + return FALSE; + } - // Reset data - nBytesPerSector = 0; - nSectorsPerCluster = 0; - nReservedSectors = 0; - nNumberOfFATs = 0; - nRootDirEntries = 0; - nTotalSectors16 = 0; - nSectorsPerFAT16 = 0; - nSectorsPerTrack = 0; - nNumberOfHeads = 0; - nHiddenSectors = 0; - nTotalSectors32 = 0; - - nSectorsPerFAT32 = 0; - nExtendedFlags = 0; - nFileSystemVersion = 0; - nRootDirStartCluster = 0; - - nRootDirSectorStart = 0; - nDataSectorStart = 0; - nSectorsPerFAT = 0; - nRootDirSectors = 0; - nTotalSectors = 0; - nNumberOfClusters = 0; - - // Get data - memcpy(&nBytesPerSector, SectorBuffer + BPB_BYTESPERSECTOR, 2); - memcpy(&nSectorsPerCluster, SectorBuffer + BPB_SECTORSPERCLUSTER, 1); - memcpy(&nReservedSectors, SectorBuffer + BPB_RESERVEDSECTORS, 2); - memcpy(&nNumberOfFATs, SectorBuffer + BPB_NUMBEROFFATS, 1); - memcpy(&nRootDirEntries, SectorBuffer + BPB_ROOTDIRENTRIES, 2); - memcpy(&nTotalSectors16, SectorBuffer + BPB_TOTALSECTORS16, 2); - memcpy(&nSectorsPerFAT16, SectorBuffer + BPB_SECTORSPERFAT16, 2); - memcpy(&nSectorsPerTrack, SectorBuffer + BPB_SECTORSPERTRACK, 2); - memcpy(&nNumberOfHeads, SectorBuffer + BPB_NUMBEROFHEADS, 2); - memcpy(&nHiddenSectors, SectorBuffer + BPB_HIDDENSECTORS, 4); - memcpy(&nTotalSectors32, SectorBuffer + BPB_TOTALSECTORS32, 4); - - memcpy(&nSectorsPerFAT32, SectorBuffer + BPB_SECTORSPERFAT32, 4); - memcpy(&nExtendedFlags, SectorBuffer + BPB_EXTENDEDFLAGS32, 2); - memcpy(&nFileSystemVersion, SectorBuffer + BPB_FILESYSTEMVERSION32, 2); - memcpy(&nRootDirStartCluster, SectorBuffer + BPB_ROOTDIRSTARTCLUSTER32, 4); - - // Calc some stuff - if (nTotalSectors16 != 0) - nTotalSectors = nTotalSectors16; - else - nTotalSectors = nTotalSectors32; - if (nSectorsPerFAT16 != 0) - nSectorsPerFAT = nSectorsPerFAT16; - else - nSectorsPerFAT = nSectorsPerFAT32; +#ifdef DEBUG - nRootDirSectorStart = (nNumberOfFATs * nSectorsPerFAT) + nReservedSectors; - nRootDirSectors = ((nRootDirEntries * 32) + (nBytesPerSector - 1)) / nBytesPerSector; - nDataSectorStart = nReservedSectors + (nNumberOfFATs * nSectorsPerFAT) + nRootDirSectors; - nNumberOfClusters = (nTotalSectors - nDataSectorStart) / nSectorsPerCluster; + DbgPrint((DPRINT_FILESYSTEM, "Drive is a hard disk, dumping partition table:\n")); + DbgPrint((DPRINT_FILESYSTEM, "sizeof(MASTER_BOOT_RECORD) = 0x%x.\n", sizeof(MASTER_BOOT_RECORD))); - // Determine FAT type - if (nNumberOfClusters < 4085) + for (BootPartition=0; BootPartition<4; BootPartition++) { - /* Volume is FAT12 */ - nFATType = FAT12; + DbgPrint((DPRINT_FILESYSTEM, "-------------------------------------------\n")); + DbgPrint((DPRINT_FILESYSTEM, "Partition %d\n", (BootPartition + 1))); + DbgPrint((DPRINT_FILESYSTEM, "BootIndicator: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].BootIndicator)); + DbgPrint((DPRINT_FILESYSTEM, "StartHead: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].StartHead)); + DbgPrint((DPRINT_FILESYSTEM, "StartSector (Plus 2 cylinder bits): 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].StartSector)); + DbgPrint((DPRINT_FILESYSTEM, "StartCylinder: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].StartCylinder)); + DbgPrint((DPRINT_FILESYSTEM, "SystemIndicator: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].SystemIndicator)); + DbgPrint((DPRINT_FILESYSTEM, "EndHead: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].EndHead)); + DbgPrint((DPRINT_FILESYSTEM, "EndSector (Plus 2 cylinder bits): 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].EndSector)); + DbgPrint((DPRINT_FILESYSTEM, "EndCylinder: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].EndCylinder)); + DbgPrint((DPRINT_FILESYSTEM, "SectorCountBeforePartition: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].SectorCountBeforePartition)); + DbgPrint((DPRINT_FILESYSTEM, "PartitionSectorCount: 0x%x\n", DriveMasterBootRecord.PartitionTable[BootPartition].PartitionSectorCount)); } - else if (nNumberOfClusters < 65525) + +#endif // defined DEBUG + + + // + // Check the partition table magic value + // + if (DriveMasterBootRecord.MasterBootRecordMagic != 0xaa55) { - /* Volume is FAT16 */ - nFATType = FAT16; + FileSystemError("Invalid partition table magic (0xaa55)"); + return FALSE; } - else + + if (PartitionNumber == 0) { - /* Volume is FAT32 */ - nFATType = FAT32; + // + // Count the bootable partitions + // + if (DriveMasterBootRecord.PartitionTable[0].BootIndicator == 0x80) + { + BootablePartitionCount++; + BootPartition = 1; + } + if (DriveMasterBootRecord.PartitionTable[1].BootIndicator == 0x80) + { + BootablePartitionCount++; + BootPartition = 2; + } + if (DriveMasterBootRecord.PartitionTable[2].BootIndicator == 0x80) + { + BootablePartitionCount++; + BootPartition = 3; + } + if (DriveMasterBootRecord.PartitionTable[3].BootIndicator == 0x80) + { + BootablePartitionCount++; + BootPartition = 4; + } - // Check version - // we only work with version 0 - if (*((WORD*)(SectorBuffer + BPB_FILESYSTEMVERSION32)) != 0) + // + // Make sure there was only one bootable partition + // + if (BootablePartitionCount != 1) { - FS_DO_ERROR("Error: FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader."); + FileSystemError("Too many bootable partitions or none found."); return FALSE; } + else + { + // + // We found the boot partition, so set the partition number + // + PartitionNumber = BootPartition; + } } - FSType = FS_FAT; + // + // Right now the partition number is one-based + // and we need zero based + // + PartitionNumber--; - // Buffer the FAT table if it is small enough - if ((FSType == FS_FAT) && (nFATType == FAT12)) - { - if (!ReadMultipleSectors(nReservedSectors, nSectorsPerFAT, pFileSysData)) - return FALSE; - } - else if ((FSType == FS_FAT) && (nFATType == FAT16)) + // + // Check for valid partition + // + if (DriveMasterBootRecord.PartitionTable[PartitionNumber].SystemIndicator == PARTITION_ENTRY_UNUSED) { - if (!ReadMultipleSectors(nReservedSectors, nSectorsPerFAT, pFileSysData)) - return FALSE; + FileSystemError("Invalid partition."); + return FALSE; } - else if ((FSType == FS_FAT) && (nFATType == FAT32)) + + PartitionStartHead = DriveMasterBootRecord.PartitionTable[PartitionNumber].StartHead; + PartitionStartSector = DriveMasterBootRecord.PartitionTable[PartitionNumber].StartSector & 0x3F; + PartitionStartCylinder = MAKE_CYLINDER( + DriveMasterBootRecord.PartitionTable[PartitionNumber].StartCylinder, + DriveMasterBootRecord.PartitionTable[PartitionNumber].StartSector); + + DbgPrint((DPRINT_FILESYSTEM, "PartitionStartHead: %d\n", PartitionStartHead)); + DbgPrint((DPRINT_FILESYSTEM, "PartitionStartSector: %d\n", PartitionStartSector)); + DbgPrint((DPRINT_FILESYSTEM, "PartitionStartCylinder: %d\n", PartitionStartCylinder)); + DbgPrint((DPRINT_FILESYSTEM, "PartitionNumber: %d\n", PartitionNumber)); + + switch (DriveMasterBootRecord.PartitionTable[PartitionNumber].SystemIndicator) { - // The FAT table is too big to be buffered so - // we will initialize our cache and cache it - // on demand - for (offset=0; offset<256; offset++) - ((int*)pFat32FATCacheIndex)[offset] = -1; + case PARTITION_FAT_12: + FileSystemType = FS_FAT; + return FatOpenVolume(DriveNumber, PartitionStartHead, PartitionStartCylinder, PartitionStartSector, FAT12); + case PARTITION_FAT_16: + case PARTITION_HUGE: + case PARTITION_XINT13: + FileSystemType = FS_FAT; + return FatOpenVolume(DriveNumber, PartitionStartHead, PartitionStartCylinder, PartitionStartSector, FAT16); + case PARTITION_FAT32: + case PARTITION_FAT32_XINT13: + FileSystemType = FS_FAT; + return FatOpenVolume(DriveNumber, PartitionStartHead, PartitionStartCylinder, PartitionStartSector, FAT32); + default: + FileSystemType = 0; + FileSystemError("Unsupported file system."); + return FALSE; } return TRUE; } -BOOL ReadMultipleSectors(int nSect, int nNumberOfSectors, void *pBuffer) +VOID SetDriveGeometry(ULONG Cylinders, ULONG Heads, ULONG Sectors, ULONG BytesPerSector) +{ + DriveGeometry.Cylinders = Cylinders; + DriveGeometry.Heads = Heads; + DriveGeometry.Sectors = Sectors; + DriveGeometry.BytesPerSector = BytesPerSector; + + DbgPrint((DPRINT_FILESYSTEM, "DriveGeometry.Cylinders: %d\n", DriveGeometry.Cylinders)); + DbgPrint((DPRINT_FILESYSTEM, "DriveGeometry.Heads: %d\n", DriveGeometry.Heads)); + DbgPrint((DPRINT_FILESYSTEM, "DriveGeometry.Sectors: %d\n", DriveGeometry.Sectors)); + DbgPrint((DPRINT_FILESYSTEM, "DriveGeometry.BytesPerSector: %d\n", DriveGeometry.BytesPerSector)); +} + +VOID SetVolumeProperties(ULONG HiddenSectors) { - BOOL bRetVal; + VolumeHiddenSectors = HiddenSectors; +} + +BOOL ReadMultipleLogicalSectors(ULONG SectorNumber, ULONG SectorCount, PVOID Buffer) +{ + /*BOOL bRetVal; int PhysicalSector; int PhysicalHead; int PhysicalTrack; @@ -292,7 +279,7 @@ BOOL ReadMultipleSectors(int nSect, int nNumberOfSectors, void *pBuffer) nNum = nNumberOfSectors; } - bRetVal = biosdisk(_DISK_READ, BootDrive, PhysicalHead, PhysicalTrack, PhysicalSector, nNum, pBuffer); + bRetVal = biosdisk(CurrentlyOpenDriveNumber, PhysicalHead, PhysicalTrack, PhysicalSector, nNum, pBuffer); if (!bRetVal) { @@ -303,124 +290,203 @@ BOOL ReadMultipleSectors(int nSect, int nNumberOfSectors, void *pBuffer) pBuffer += (nNum * 512); nNumberOfSectors -= nNum; nSect += nNum; + }*/ + + ULONG CurrentSector; + PVOID RealBuffer = Buffer; + + for (CurrentSector=SectorNumber; CurrentSector<(SectorNumber + SectorCount); CurrentSector++) + { + if (!ReadLogicalSector(CurrentSector, RealBuffer) ) + { + return FALSE; + } + + RealBuffer += DriveGeometry.BytesPerSector; } return TRUE; } -BOOL ReadOneSector(int nSect) +BOOL ReadLogicalSector(ULONG SectorNumber, PVOID Buffer) { - BOOL bRetVal; - int PhysicalSector; - int PhysicalHead; - int PhysicalTrack; + ULONG PhysicalSector; + ULONG PhysicalHead; + ULONG PhysicalTrack; - nSectorBuffered = nSect; - - nSect += nHiddenSectors; - PhysicalSector = 1 + (nSect % nSectorsPerTrack); - PhysicalHead = (nSect / nSectorsPerTrack) % nNumberOfHeads; - PhysicalTrack = nSect / (nSectorsPerTrack * nNumberOfHeads); + DbgPrint((DPRINT_FILESYSTEM, "ReadLogicalSector() SectorNumber: %d Buffer: 0x%x\n", SectorNumber, Buffer)); + SectorNumber += VolumeHiddenSectors; + PhysicalSector = 1 + (SectorNumber % DriveGeometry.Sectors); + PhysicalHead = (SectorNumber / DriveGeometry.Sectors) % DriveGeometry.Heads; + PhysicalTrack = (SectorNumber / DriveGeometry.Sectors) / DriveGeometry.Heads; - bRetVal = biosdisk(_DISK_READ, BootDrive, PhysicalHead, PhysicalTrack, PhysicalSector, 1, SectorBuffer); + //DbgPrint((DPRINT_FILESYSTEM, "Calling BiosInt13Read() with PhysicalHead: %d\n", PhysicalHead)); + //DbgPrint((DPRINT_FILESYSTEM, "Calling BiosInt13Read() with PhysicalTrack: %d\n", PhysicalTrack)); + //DbgPrint((DPRINT_FILESYSTEM, "Calling BiosInt13Read() with PhysicalSector: %d\n", PhysicalSector)); + if (PhysicalHead >= DriveGeometry.Heads) + { + BugCheck((DPRINT_FILESYSTEM, "PhysicalHead >= DriveGeometry.Heads\nPhysicalHead = %d\nDriveGeometry.Heads = %d\n", PhysicalHead, DriveGeometry.Heads)); + } + if (PhysicalTrack >= DriveGeometry.Cylinders) + { + BugCheck((DPRINT_FILESYSTEM, "PhysicalTrack >= DriveGeometry.Cylinders\nPhysicalTrack = %d\nDriveGeometry.Cylinders = %d\n", PhysicalTrack, DriveGeometry.Cylinders)); + } + if (PhysicalSector > DriveGeometry.Sectors) + { + BugCheck((DPRINT_FILESYSTEM, "PhysicalSector > DriveGeometry.Sectors\nPhysicalSector = %d\nDriveGeometry.Sectors = %d\n", PhysicalSector, DriveGeometry.Sectors)); + } - if (!bRetVal) + if ((CurrentlyOpenDriveNumber >= 0x80) && + (BiosInt13ExtensionsSupported(CurrentlyOpenDriveNumber)) && + (SectorNumber > (DriveGeometry.Cylinders * DriveGeometry.Heads * DriveGeometry.Sectors))) { - FS_DO_ERROR("Disk Error"); - return FALSE; + DbgPrint((DPRINT_FILESYSTEM, "Using Int 13 Extensions for read. BiosInt13ExtensionsSupported(%d) = %s\n", CurrentlyOpenDriveNumber, BiosInt13ExtensionsSupported(CurrentlyOpenDriveNumber) ? "TRUE" : "FALSE")); + if ( !BiosInt13ReadExtended(CurrentlyOpenDriveNumber, SectorNumber, 1, Buffer) ) + { + FileSystemError("Disk read error."); + return FALSE; + } + } + else + { + if ( !BiosInt13Read(CurrentlyOpenDriveNumber, PhysicalHead, PhysicalTrack, PhysicalSector, 1, Buffer) ) + { + FileSystemError("Disk read error."); + return FALSE; + } } return TRUE; } -BOOL OpenFile(char *filename, FILE *pFile) +PFILE OpenFile(PUCHAR FileName) { - switch(FSType) + PFILE FileHandle = NULL; + + // + // Print status message + // + DbgPrint((DPRINT_FILESYSTEM, "Opening file '%s'...\n", FileName)); + + // + // Check file system type and pass off to appropriate handler + // + if (FileSystemType == FS_FAT) { - case FS_FAT: - if(!FATOpenFile(filename, &(pFile->fat))) - return FALSE; - pFile->filesize = pFile->fat.dwSize; - break; - default: - FS_DO_ERROR("Error: Unknown filesystem."); - return FALSE; - break; + FileHandle = FatOpenFile(FileName); + } + else + { + FileSystemError("Error: Unknown filesystem."); } - return TRUE; +#ifdef DEBUG + // + // Check return value + // + if (FileHandle != NULL) + { + DbgPrint((DPRINT_FILESYSTEM, "OpenFile() succeeded. FileHandle: 0x%x\n", FileHandle)); + } + else + { + DbgPrint((DPRINT_FILESYSTEM, "OpenFile() failed.\n")); + } +#endif // defined DEBUG + + return FileHandle; +} + +VOID CloseFile(PFILE FileHandle) +{ } /* * ReadFile() * returns number of bytes read or EOF */ -int ReadFile(FILE *pFile, int count, void *buffer) +BOOL ReadFile(PFILE FileHandle, ULONG BytesToRead, PULONG BytesRead, PVOID Buffer) { - switch(FSType) + // + // Set the number of bytes read equal to zero + // + if (BytesRead !=NULL) + { + *BytesRead = 0; + } + + switch (FileSystemType) { case FS_FAT: - return FATRead(&(pFile->fat), count, buffer); + + return FatReadFile(FileHandle, BytesToRead, BytesRead, Buffer); + default: - FS_DO_ERROR("Error: Unknown filesystem."); - return EOF; - } - return 0; -} + FileSystemError("Unknown file system."); + return FALSE; + } -DWORD GetFileSize(FILE *pFile) -{ - return pFile->filesize; + return FALSE; } -DWORD Rewind(FILE *pFile) +ULONG GetFileSize(PFILE FileHandle) { - switch (FSType) + switch (FileSystemType) { case FS_FAT: - pFile->fat.dwCurrentCluster = pFile->fat.dwStartCluster; - pFile->fat.dwCurrentReadOffset = 0; - break; + + return FatGetFileSize(FileHandle); + default: - FS_DO_ERROR("Error: Unknown filesystem."); + FileSystemError("Unknown file system."); break; } - return pFile->filesize; + return 0; } -int feof(FILE *pFile) +VOID SetFilePointer(PFILE FileHandle, ULONG NewFilePointer) { - switch (FSType) + switch (FileSystemType) { case FS_FAT: - if (pFile->fat.dwCurrentReadOffset >= pFile->fat.dwSize) - return TRUE; - else - return FALSE; + + FatSetFilePointer(FileHandle, NewFilePointer); break; + default: - FS_DO_ERROR("Error: Unknown filesystem."); - return TRUE; + FileSystemError("Unknown file system."); break; } - - return TRUE; } -int fseek(FILE *pFile, DWORD offset) +ULONG GetFilePointer(PFILE FileHandle) { - switch (FSType) + switch (FileSystemType) { case FS_FAT: - return FATfseek(&(pFile->fat), offset); + + return FatGetFilePointer(FileHandle); break; + default: - FS_DO_ERROR("Error: Unknown filesystem."); + FileSystemError("Unknown file system."); break; } - return -1; + return 0; +} + +BOOL IsEndOfFile(PFILE FileHandle) +{ + if (GetFilePointer(FileHandle) >= GetFileSize(FileHandle)) + { + return TRUE; + } + else + { + return FALSE; + } } diff --git a/freeldr/freeldr/fs.h b/freeldr/freeldr/fs.h index e80dadb56c9..b8c133eb11b 100644 --- a/freeldr/freeldr/fs.h +++ b/freeldr/freeldr/fs.h @@ -1,6 +1,6 @@ /* * FreeLoader - * Copyright (C) 1999, 2000 Brian Palmer + * Copyright (C) 1999, 2000, 2001 Brian Palmer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,148 +17,89 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef __FS_FAT_H -#define __FS_FAT_H - -// Bootsector BPB defines -#define BPB_JMPBOOT 0 -#define BPB_OEMNAME 3 -#define BPB_BYTESPERSECTOR 11 -#define BPB_SECTORSPERCLUSTER 13 -#define BPB_RESERVEDSECTORS 14 -#define BPB_NUMBEROFFATS 16 -#define BPB_ROOTDIRENTRIES 17 -#define BPB_TOTALSECTORS16 19 -#define BPB_MEDIADESCRIPTOR 21 -#define BPB_SECTORSPERFAT16 22 -#define BPB_SECTORSPERTRACK 24 -#define BPB_NUMBEROFHEADS 26 -#define BPB_HIDDENSECTORS 28 -#define BPB_TOTALSECTORS32 32 - -// Fat12/16 extended BPB defines -#define BPB_DRIVENUMBER16 36 -#define BPB_RESERVED16_1 37 -#define BPB_BOOTSIGNATURE16 38 -#define BPB_VOLUMESERIAL16 39 -#define BPB_VOLUMELABEL16 43 -#define BPB_FILESYSTEMTYPE16 54 - -// Fat32 extended BPB defines -#define BPB_SECTORSPERFAT32 36 -#define BPB_EXTENDEDFLAGS32 40 -#define BPB_FILESYSTEMVERSION32 42 -#define BPB_ROOTDIRSTARTCLUSTER32 44 -#define BPB_FILESYSTEMINFOSECTOR32 48 -#define BPB_BACKUPBOOTSECTOR32 50 -#define BPB_RESERVED32_1 52 -#define BPB_DRIVENUMBER32 64 -#define BPB_RESERVED32_2 65 -#define BPB_BOOTSIGNATURE32 66 -#define BPB_VOLUMESERIAL32 67 -#define BPB_VOLUMELABEL32 71 -#define BPB_FILESYSTEMTYPE32 82 +#ifndef __FS_H +#define __FS_H -/* - * Structure of MSDOS directory entry - */ -typedef struct //_DIRENTRY +// +// Define the structure of a partition table entry +// +typedef struct _PARTITION_TABLE_ENTRY { - BYTE cFileName[11]; /* Filename + extension */ - BYTE cAttr; /* File attributes */ - BYTE cReserved[10]; /* Reserved area */ - WORD wTime; /* Time last modified */ - WORD wData; /* Date last modified */ - WORD wCluster; /* First cluster number */ - DWORD dwSize; /* File size */ -} DIRENTRY, * PDIRENTRY; - -/* - * Structure of internal file control block - */ -typedef struct //_FCB -{ - BYTE cAttr; /* Open attributes */ - BYTE cSector; /* Sector within cluster */ - PDIRENTRY pDirptr; /* Pointer to directory entry */ - WORD wDirSector; /* Directory sector */ - WORD wFirstCluster; /* First cluster in file */ - WORD wLastCluster; /* Last cluster read/written */ - WORD wNextCluster; /* Next cluster to read/write */ - WORD wOffset; /* Read/Write offset within sector */ - DWORD dwSize; /* File size */ - BYTE cBuffer[512]; /* Data transfer buffer */ -} FCB, * PFCB; - -typedef struct //_FAT_STRUCT + BYTE BootIndicator; // 0x00 - non-bootable partition, 0x80 - bootable partition (one partition only) + BYTE StartHead; // Beginning head number + BYTE StartSector; // Beginning sector (2 high bits of cylinder #) + BYTE StartCylinder; // Beginning cylinder# (low order bits of cylinder #) + BYTE SystemIndicator; // System indicator + BYTE EndHead; // Ending head number + BYTE EndSector; // Ending sector (2 high bits of cylinder #) + BYTE EndCylinder; // Ending cylinder# (low order bits of cylinder #) + DWORD SectorCountBeforePartition; // Number of sectors preceding the partition + DWORD PartitionSectorCount; // Number of sectors in the partition + +} PACKED PARTITION_TABLE_ENTRY, *PPARTITION_TABLE_ENTRY; + +// +// This macro will return the cylinder when you pass it a cylinder/sector +// pair where the high 2 bits of the cylinder are stored in the sector byte +// +#define MAKE_CYLINDER(cylinder, sector) ( cylinder + ((((WORD)sector) & 0xC0) << 2) ) + +// +// Define the structure of the master boot record +// +typedef struct _MASTER_BOOT_RECORD { - DWORD dwStartCluster; // File's starting cluster - DWORD dwCurrentCluster; // Current read cluster number - DWORD dwSize; // File size - DWORD dwCurrentReadOffset;// Amount of data already read -} FAT_STRUCT, * PFAT_STRUCT; - -typedef struct //_FILE + BYTE MasterBootRecordCodeAndData[0x1be]; + PARTITION_TABLE_ENTRY PartitionTable[4]; + WORD MasterBootRecordMagic; + +} PACKED MASTER_BOOT_RECORD, *PMASTER_BOOT_RECORD; + +// +// Partition type defines +// +#define PARTITION_ENTRY_UNUSED 0x00 // Entry unused +#define PARTITION_FAT_12 0x01 // 12-bit FAT entries +#define PARTITION_XENIX_1 0x02 // Xenix +#define PARTITION_XENIX_2 0x03 // Xenix +#define PARTITION_FAT_16 0x04 // 16-bit FAT entries +#define PARTITION_EXTENDED 0x05 // Extended partition entry +#define PARTITION_HUGE 0x06 // Huge partition MS-DOS V4 +#define PARTITION_IFS 0x07 // IFS Partition +#define PARTITION_OS2BOOTMGR 0x0A // OS/2 Boot Manager/OPUS/Coherent swap +#define PARTITION_FAT32 0x0B // FAT32 +#define PARTITION_FAT32_XINT13 0x0C // FAT32 using extended int13 services +#define PARTITION_XINT13 0x0E // Win95 partition using extended int13 services +#define PARTITION_XINT13_EXTENDED 0x0F // Same as type 5 but uses extended int13 services +#define PARTITION_PREP 0x41 // PowerPC Reference Platform (PReP) Boot Partition +#define PARTITION_LDM 0x42 // Logical Disk Manager partition +#define PARTITION_UNIX 0x63 // Unix + +typedef struct _GEOMETRY { - //DIRENTRY de; - //FCB fcb; - FAT_STRUCT fat; - unsigned long filesize; -} FILE; - -extern int nSectorBuffered; // Tells us which sector was read into SectorBuffer[] -extern BYTE SectorBuffer[512]; // 512 byte buffer space for read operations, ReadOneSector reads to here - -extern int nFATType; - -extern DWORD nBytesPerSector; // Bytes per sector -extern DWORD nSectorsPerCluster; // Number of sectors in a cluster -extern DWORD nReservedSectors; // Reserved sectors, usually 1 (the bootsector) -extern DWORD nNumberOfFATs; // Number of FAT tables -extern DWORD nRootDirEntries; // Number of root directory entries (fat12/16) -extern DWORD nTotalSectors16; // Number of total sectors on the drive, 16-bit -extern DWORD nSectorsPerFAT16; // Sectors per FAT table (fat12/16) -extern DWORD nSectorsPerTrack; // Number of sectors in a track -extern DWORD nNumberOfHeads; // Number of heads on the disk -extern DWORD nHiddenSectors; // Hidden sectors (sectors before the partition start like the partition table) -extern DWORD nTotalSectors32; // Number of total sectors on the drive, 32-bit - -extern DWORD nSectorsPerFAT32; // Sectors per FAT table (fat32) -extern DWORD nExtendedFlags; // Extended flags (fat32) -extern DWORD nFileSystemVersion; // File system version (fat32) -extern DWORD nRootDirStartCluster; // Starting cluster of the root directory (fat32) - -extern DWORD nRootDirSectorStart; // Starting sector of the root directory (fat12/16) -extern DWORD nDataSectorStart; // Starting sector of the data area -extern DWORD nSectorsPerFAT; // Sectors per FAT table -extern DWORD nRootDirSectors; // Number of sectors of the root directory (fat32) -extern DWORD nTotalSectors; // Total sectors on the drive -extern DWORD nNumberOfClusters; // Number of clusters on the drive - -extern int FSType; // Type of filesystem on boot device, set by OpenDiskDrive() - -extern char *pFileSysData; // Load address for filesystem data -extern char *pFat32FATCacheIndex; // Load address for filesystem data - -BOOL OpenDiskDrive(int nDrive, int nPartition); // Opens the disk drive device for reading -BOOL ReadMultipleSectors(int nSect, int nNumberOfSectors, void *pBuffer);// Reads a sector from the open device -BOOL ReadOneSector(int nSect); // Reads one sector from the open device -BOOL OpenFile(char *filename, FILE *pFile); // Opens a file -int ReadFile(FILE *pFile, int count, void *buffer); // Reads count bytes from pFile into buffer -DWORD GetFileSize(FILE *pFile); -DWORD Rewind(FILE *pFile); // Rewinds a file and returns it's size -int feof(FILE *pFile); -int fseek(FILE *pFILE, DWORD offset); - -BOOL FATLookupFile(char *file, PFAT_STRUCT pFatStruct); -int FATGetNumPathParts(char *name); -BOOL FATGetFirstNameFromPath(char *buffer, char *name); -void FATParseFileName(char *buffer, char *name); -DWORD FATGetFATEntry(DWORD nCluster); -BOOL FATOpenFile(char *szFileName, PFAT_STRUCT pFatStruct); -int FATReadCluster(DWORD nCluster, char *cBuffer); -int FATRead(PFAT_STRUCT pFatStruct, int nNumBytes, char *cBuffer); -int FATfseek(PFAT_STRUCT pFatStruct, DWORD offset); + ULONG Cylinders; + ULONG Heads; + ULONG Sectors; + ULONG BytesPerSector; + +} GEOMETRY, *PGEOMETRY; + +#define FILE VOID +#define PFILE FILE * + +VOID FileSystemError(PUCHAR ErrorString); +BOOL OpenDiskDrive(ULONG DriveNumber, ULONG PartitionNumber); +VOID SetDriveGeometry(ULONG Cylinders, ULONG Heads, ULONG Sectors, ULONG BytesPerSector); +VOID SetVolumeProperties(ULONG HiddenSectors); +BOOL ReadMultipleLogicalSectors(ULONG SectorNumber, ULONG SectorCount, PVOID Buffer); +BOOL ReadLogicalSector(ULONG SectorNumber, PVOID Buffer); +PFILE OpenFile(PUCHAR FileName); +VOID CloseFile(PFILE FileHandle); +BOOL ReadFile(PFILE FileHandle, ULONG BytesToRead, PULONG BytesRead, PVOID Buffer); +ULONG GetFileSize(PFILE FileHandle); +VOID SetFilePointer(PFILE FileHandle, ULONG NewFilePointer); +ULONG GetFilePointer(PFILE FileHandle); +BOOL IsEndOfFile(PFILE FileHandle); #define EOF -1 @@ -179,4 +120,4 @@ int FATfseek(PFAT_STRUCT pFatStruct, DWORD offset); #define FAT16 2 #define FAT32 3 -#endif // #defined __FS_FAT_H \ No newline at end of file +#endif // #defined __FS_H \ No newline at end of file diff --git a/freeldr/freeldr/fs_fat.c b/freeldr/freeldr/fs_fat.c deleted file mode 100644 index 828d1dc828c..00000000000 --- a/freeldr/freeldr/fs_fat.c +++ /dev/null @@ -1,541 +0,0 @@ -/* - * FreeLoader - * Copyright (C) 1999, 2000 Brian Palmer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "freeldr.h" -#include "fs.h" -#include "stdlib.h" -#include "tui.h" -#include "asmcode.h" - -int nFATType = FAT12; - -DWORD nBytesPerSector; // Bytes per sector -DWORD nSectorsPerCluster; // Number of sectors in a cluster -DWORD nReservedSectors; // Reserved sectors, usually 1 (the bootsector) -DWORD nNumberOfFATs; // Number of FAT tables -DWORD nRootDirEntries; // Number of root directory entries (fat12/16) -DWORD nTotalSectors16; // Number of total sectors on the drive, 16-bit -DWORD nSectorsPerFAT16; // Sectors per FAT table (fat12/16) -DWORD nSectorsPerTrack; // Number of sectors in a track -DWORD nNumberOfHeads; // Number of heads on the disk -DWORD nHiddenSectors; // Hidden sectors (sectors before the partition start like the partition table) -DWORD nTotalSectors32; // Number of total sectors on the drive, 32-bit - -DWORD nSectorsPerFAT32; // Sectors per FAT table (fat32) -DWORD nExtendedFlags; // Extended flags (fat32) -DWORD nFileSystemVersion; // File system version (fat32) -DWORD nRootDirStartCluster; // Starting cluster of the root directory (fat32) - -DWORD nRootDirSectorStart; // Starting sector of the root directory (fat12/16) -DWORD nDataSectorStart; // Starting sector of the data area -DWORD nSectorsPerFAT; // Sectors per FAT table -DWORD nRootDirSectors; // Number of sectors of the root directory (fat32) -DWORD nTotalSectors; // Total sectors on the drive -DWORD nNumberOfClusters; // Number of clusters on the drive - -BOOL FATReadRootDirectoryEntry(int nDirEntry, void *pDirEntryBuf) -{ - DWORD nDirEntrySector; - int nOffsetWithinSector; - - nDirEntrySector = nRootDirSectorStart + ((nDirEntry * 32) / nBytesPerSector); - - if (!ReadOneSector(nDirEntrySector)) - return FALSE; - - nOffsetWithinSector = (nDirEntry * 32) % nBytesPerSector; - - memcpy(pDirEntryBuf, SectorBuffer + nOffsetWithinSector, 32); - - if (*((char *)pDirEntryBuf) == 0x05) - *((char *)pDirEntryBuf) = 0xE5; - - return TRUE; -} - -BOOL FATReadDirectoryEntry(DWORD nDirStartCluster, int nDirEntry, void *pDirEntryBuf) -{ - DWORD nRealDirCluster; - int nSectorWithinCluster; - int nOffsetWithinSector; - int nSectorToRead; - int i; - - i = (nDirEntry * 32) / (nSectorsPerCluster * nBytesPerSector); - //if ((nDirEntry * 32) % (nSectorsPerCluster * nBytesPerSector)) - // i++; - - for (nRealDirCluster = nDirStartCluster; i; i--) - nRealDirCluster = FATGetFATEntry(nRealDirCluster); - - nSectorWithinCluster = ((nDirEntry * 32) % (nSectorsPerCluster * nBytesPerSector)) / nBytesPerSector; - - nSectorToRead = ((nRealDirCluster - 2) * nSectorsPerCluster) + nDataSectorStart + nSectorWithinCluster; - - if (!ReadOneSector(nSectorToRead)) - return FALSE; - - nOffsetWithinSector = (nDirEntry * 32) % nBytesPerSector; - - memcpy(pDirEntryBuf, SectorBuffer + nOffsetWithinSector, 32); - - if (*((char *)pDirEntryBuf) == 0x05) - *((char *)pDirEntryBuf) = 0xE5; - - return TRUE; -} - -/* - * FATLookupFile() - * This function searches the file system for the - * specified filename and fills in a FAT_STRUCT structure - * with info describing the file, etc. returns true - * if the file exists or false otherwise - */ -BOOL FATLookupFile(char *file, PFAT_STRUCT pFatStruct) -{ - int i, j; - int numparts; - char filename[12]; - BYTE direntry[32]; - int nNumDirEntries; - FAT_STRUCT fatstruct; - BOOL bFound; - DWORD cluster; - - memset(pFatStruct, 0, sizeof(FAT_STRUCT)); - - // Check and see if the first character is '\' and remove it if so - if (*file == '\\') - file++; - - // Figure out how many sub-directories we are nested in - numparts = FATGetNumPathParts(file); - - // Loop once for each part - for (i=0; idwStartCluster, direntry + 26, sizeof(WORD)); - memcpy(&pFatStruct->dwCurrentCluster, direntry + 20, sizeof(WORD)); - pFatStruct->dwStartCluster += (pFatStruct->dwCurrentCluster * 0x10000); - pFatStruct->dwCurrentCluster = pFatStruct->dwStartCluster; - - memcpy(&pFatStruct->dwSize, direntry + 28, sizeof(DWORD)); - pFatStruct->dwCurrentReadOffset = 0; - - return TRUE; -} - -/* - * FATGetNumPathParts() - * This function parses a path in the form of dir1\dir2\file1.ext - * and returns the number of parts it has (i.e. 3 - dir1,dir2,file1.ext) - */ -int FATGetNumPathParts(char *name) -{ - int i, num; - - for(i=0,num=0; i<(int)strlen(name); i++) - { - if(name[i] == '\\') - num++; - } - num++; - - return num; -} - -/* - * FATGetFirstNameFromPath() - * This function parses a path in the form of dir1\dir2\file1.ext - * and puts the first name of the path (e.g. "dir1") in buffer - * compatible with the MSDOS directory structure - */ -BOOL FATGetFirstNameFromPath(char *buffer, char *name) -{ - int i; - char temp[260]; - - // Copy all the characters up to the end of the - // string or until we hit a '\' character - // and put them in temp - for(i=0; i<(int)strlen(name); i++) - { - if(name[i] == '\\') - break; - else - temp[i] = name[i]; - } - temp[i] = 0; - - // If the filename is too long then fail - if(strlen(temp) > 12) - return FALSE; - - FATParseFileName(buffer, temp); - - return TRUE; -} - -/* - * FATParseFileName() - * This function parses "name" which is in the form of file.ext - * and puts it in "buffer" in the form of "FILE EXT" which - * is compatible with the MSDOS directory structure - */ -void FATParseFileName(char *buffer, char *name) -{ - int i, j; - - i = 0; - j = 0; - - while(i < 8) - buffer[i++] = (name[j] && (name[j] != '.')) ? toupper(name[j++]) : ' '; - - if(name[j] == '.') - j++; - - while(i < 11) - buffer[i++] = name[j] ? toupper(name[j++]) : ' '; - - buffer[i] = 0; -} - -/* - * FATGetFATEntry() - * returns the FAT entry for a given cluster number - */ -DWORD FATGetFATEntry(DWORD nCluster) -{ - DWORD fat; - int FATOffset; - int ThisFATSecNum; - int ThisFATEntOffset; - int Idx; - BOOL bEntryFound; - - switch(nFATType) - { - case FAT12: - FATOffset = nCluster + (nCluster / 2); - ThisFATSecNum = (FATOffset / nBytesPerSector); - ThisFATEntOffset = (FATOffset % nBytesPerSector); - fat = *((WORD *) (pFileSysData + (ThisFATSecNum * nBytesPerSector) + ThisFATEntOffset)); - if (nCluster & 0x0001) - fat = fat >> 4; /* Cluster number is ODD */ - else - fat = fat & 0x0FFF; /* Cluster number is EVEN */ - - return fat; - break; - case FAT16: - FATOffset = (nCluster * 2); - //ThisFATSecNum = nReservedSectors + (FATOffset / nBytesPerSector); - //ThisFATEntOffset = (FATOffset % nBytesPerSector); - - //if (!ReadOneSector(ThisFATSecNum)) - // return NULL; - - //fat = *((WORD *) &SectorBuffer[ThisFATEntOffset]); - fat = *((WORD *) (pFileSysData + FATOffset)); - - return fat; - break; - case FAT32: - //if (!ReadOneSector(ThisFATSecNum)) - // return NULL; - - //fat = *((DWORD *) &SectorBuffer[ThisFATEntOffset]) & 0x0FFFFFFF; - //return fat; - - // This code manages the fat32 fat table entry cache - // The cache is at address FILESYSADDR which is 128k in size - // The first two sectors will contain an array of DWORDs that - // Specify what fat sector is cached. The first two DWORDs - // should be zero. - FATOffset = (nCluster * 4); - ThisFATSecNum = nReservedSectors + (FATOffset / nBytesPerSector); - ThisFATEntOffset = (FATOffset % nBytesPerSector); - - // Now we go through our cache and see if we already have the sector cached - bEntryFound = FALSE; - for (Idx=2; Idx<256; Idx++) - { - if (((int*)pFat32FATCacheIndex)[Idx] == ThisFATSecNum) - { - bEntryFound = TRUE; - break; - } - } - - if (bEntryFound) - { - // Get the fat entry - fat = (*((DWORD *) (pFat32FATCacheIndex + - (Idx * nBytesPerSector) + ThisFATEntOffset))) & 0x0FFFFFFF; - } - else - { - if (!ReadOneSector(ThisFATSecNum)) - return NULL; - - // Move each sector down in the cache to make room for new sector - for (Idx=255; Idx>2; Idx--) - { - memcpy(pFat32FATCacheIndex + (Idx * nBytesPerSector), pFat32FATCacheIndex + ((Idx - 1) * nBytesPerSector), nBytesPerSector); - ((int*)pFat32FATCacheIndex)[Idx] = ((int*)pFat32FATCacheIndex)[Idx - 1]; - } - - // Insert it into the cache - memcpy(pFat32FATCacheIndex + (2 * nBytesPerSector), SectorBuffer, nBytesPerSector); - ((int*)pFat32FATCacheIndex)[2] = ThisFATSecNum; - - // Get the fat entry - fat = (*((DWORD *) (pFat32FATCacheIndex + - (2 * nBytesPerSector) + ThisFATEntOffset))) & 0x0FFFFFFF; - } - - return fat; - break; - } - - return NULL; -} - -/* - * FATOpenFile() - * Tries to open the file 'name' and returns true or false - * for success and failure respectively - */ -BOOL FATOpenFile(char *szFileName, PFAT_STRUCT pFatStruct) -{ - if(!FATLookupFile(szFileName, pFatStruct)) - return FALSE; - - /* Fill in file control information */ - pFatStruct->dwCurrentCluster = pFatStruct->dwStartCluster; - pFatStruct->dwCurrentReadOffset = 0; - - return TRUE; -} - -/* - * FATReadCluster() - * Reads the specified cluster into memory - * and returns the number of bytes read - */ -int FATReadCluster(DWORD nCluster, char *cBuffer) -{ - int nStartSector; - - nStartSector = ((nCluster - 2) * nSectorsPerCluster) + nDataSectorStart; - - ReadMultipleSectors(nStartSector, nSectorsPerCluster, cBuffer); - - return (nSectorsPerCluster * nBytesPerSector); -} - -/* - * FATRead() - * Reads nNumBytes from open file and - * returns the number of bytes read - */ -int FATRead(PFAT_STRUCT pFatStruct, int nNumBytes, char *cBuffer) -{ - int nSectorWithinCluster; - int nOffsetWithinSector; - int nOffsetWithinCluster; - int nNum; - int nBytesRead = 0; - - // If all the data is read return zero - if (pFatStruct->dwCurrentReadOffset >= pFatStruct->dwSize) - return 0; - - // If they are trying to read more than there is to read - // then adjust the amount to read - if ((pFatStruct->dwCurrentReadOffset + nNumBytes) > pFatStruct->dwSize) - nNumBytes = pFatStruct->dwSize - pFatStruct->dwCurrentReadOffset; - - while (nNumBytes) - { - // Check and see if the read offset is aligned to a cluster boundary - // if so great, if not then read the rest of the current cluster - if ((pFatStruct->dwCurrentReadOffset % (nSectorsPerCluster * nBytesPerSector)) != 0) - { - nSectorWithinCluster = ((pFatStruct->dwCurrentReadOffset / nBytesPerSector) % nSectorsPerCluster); - nOffsetWithinSector = (pFatStruct->dwCurrentReadOffset % nBytesPerSector); - nOffsetWithinCluster = (pFatStruct->dwCurrentReadOffset % (nSectorsPerCluster * nBytesPerSector)); - - // Read the cluster into the scratch area - FATReadCluster(pFatStruct->dwCurrentCluster, (char *)FATCLUSTERBUF); - - nNum = (nSectorsPerCluster * nBytesPerSector) - (pFatStruct->dwCurrentReadOffset % (nSectorsPerCluster * nBytesPerSector)); - if (nNumBytes >= nNum) - { - memcpy(cBuffer, (char *)(FATCLUSTERBUF + nOffsetWithinCluster), nNum); - nBytesRead += nNum; - cBuffer += nNum; - pFatStruct->dwCurrentReadOffset += nNum; - pFatStruct->dwCurrentCluster = FATGetFATEntry(pFatStruct->dwCurrentCluster); - nNumBytes -= nNum; - } - else - { - memcpy(cBuffer, (char *)(FATCLUSTERBUF + nOffsetWithinCluster), nNumBytes); - nBytesRead += nNumBytes; - cBuffer += nNumBytes; - pFatStruct->dwCurrentReadOffset += nNumBytes; - nNumBytes -= nNumBytes; - } - } - else - { - // Read the cluster into the scratch area - FATReadCluster(pFatStruct->dwCurrentCluster, (char *)FATCLUSTERBUF); - - nNum = (nSectorsPerCluster * nBytesPerSector); - if (nNumBytes >= nNum) - { - memcpy(cBuffer, (char *)(FATCLUSTERBUF), nNum); - nBytesRead += nNum; - cBuffer += nNum; - pFatStruct->dwCurrentReadOffset += nNum; - pFatStruct->dwCurrentCluster = FATGetFATEntry(pFatStruct->dwCurrentCluster); - nNumBytes -= nNum; - } - else - { - memcpy(cBuffer, (char *)(FATCLUSTERBUF), nNumBytes); - nBytesRead += nNumBytes; - cBuffer += nNumBytes; - pFatStruct->dwCurrentReadOffset += nNumBytes; - nNumBytes -= nNumBytes; - } - } - } - - return nBytesRead; -} - -int FATfseek(PFAT_STRUCT pFatStruct, DWORD offset) -{ - DWORD cluster; - int numclusters; - - numclusters = offset / (nSectorsPerCluster * nBytesPerSector); - for (cluster=pFatStruct->dwStartCluster; numclusters > 0; numclusters--) - cluster = FATGetFATEntry(cluster); - - pFatStruct->dwCurrentCluster = cluster; - pFatStruct->dwCurrentReadOffset = offset; - - return 0; -} diff --git a/freeldr/freeldr/linux.c b/freeldr/freeldr/linux.c index 448d86d6fdd..6eedb47b9ed 100644 --- a/freeldr/freeldr/linux.c +++ b/freeldr/freeldr/linux.c @@ -28,7 +28,7 @@ void LoadAndBootLinux(int DriveNum, int Partition, char *vmlinuz, char *cmd_line) { - FILE file; + /*FILE file; char temp[260]; char bootsector[512]; char setup[2048]; @@ -97,5 +97,5 @@ void LoadAndBootLinux(int DriveNum, int Partition, char *vmlinuz, char *cmd_line gotoxy(CursorXPos, CursorYPos); stop_floppy(); - JumpToLinuxBootCode(); + JumpToLinuxBootCode();*/ } diff --git a/freeldr/freeldr/memory.c b/freeldr/freeldr/memory.c index 6dfcb02e12a..9f40d1dcfa2 100644 --- a/freeldr/freeldr/memory.c +++ b/freeldr/freeldr/memory.c @@ -21,6 +21,15 @@ #include "memory.h" #include "stdlib.h" #include "debug.h" +#include "tui.h" + + +// +// Define this to 1 if you want the entire contents +// of the memory allocation bitmap displayed +// when a chunk is allocated or freed +// +#define DUMP_MEM_MAP_ON_VERIFY 0 #define MEM_BLOCK_SIZE 256 @@ -39,6 +48,7 @@ PMEMBLOCK HeapMemBlockArray = NULL; ULONG AllocationCount = 0; VOID VerifyHeap(VOID); +VOID DumpMemoryAllocMap(VOID); VOID IncrementAllocationCount(VOID); VOID DecrementAllocationCount(VOID); VOID MemAllocTest(VOID); @@ -66,7 +76,7 @@ VOID InitMemoryManager(PVOID BaseAddress, ULONG Length) ZeroMemory(HeapMemBlockArray, (HeapMemBlockCount * sizeof(MEMBLOCK))); #ifdef DEBUG - DebugPrint(DPRINT_MEMORY, "Memory Manager initialized. BaseAddress = 0x%x Length = 0x%x. %d blocks in heap.\n", BaseAddress, Length, HeapMemBlockCount); + DbgPrint((DPRINT_MEMORY, "Memory Manager initialized. BaseAddress = 0x%x Length = 0x%x. %d blocks in heap.\n", BaseAddress, Length, HeapMemBlockCount)); //MemAllocTest(); #endif } @@ -78,9 +88,11 @@ PVOID AllocateMemory(ULONG NumberOfBytes) ULONG NumFree; PVOID MemPointer; -#ifdef DEBUG - VerifyHeap(); -#endif DEBUG + if (NumberOfBytes == 0) + { + DbgPrint((DPRINT_MEMORY, "AllocateMemory() called for 0 bytes. Returning NULL.\n")); + return NULL; + } // Find out how many blocks it will take to // satisfy this allocation @@ -116,6 +128,8 @@ PVOID AllocateMemory(ULONG NumberOfBytes) // then return NULL if (NumFree < BlocksNeeded) { + DbgPrint((DPRINT_MEMORY, "Memory allocation failed. Not enough free memory to allocate %d bytes. AllocationCount: %d\n", NumberOfBytes, AllocationCount)); + MessageBox("Memory allocation failed: out of memory."); return NULL; } @@ -135,7 +149,8 @@ PVOID AllocateMemory(ULONG NumberOfBytes) #ifdef DEBUG IncrementAllocationCount(); - DebugPrint(DPRINT_MEMORY, "Allocated %d bytes (%d blocks) of memory starting at block %d. AllocationCount: %d\n", NumberOfBytes, BlocksNeeded, Idx, AllocationCount); + DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d blocks) of memory starting at block %d. AllocCount: %d\n", NumberOfBytes, BlocksNeeded, Idx, AllocationCount)); + VerifyHeap(); #endif DEBUG // Now return the pointer @@ -149,12 +164,11 @@ VOID FreeMemory(PVOID MemBlock) ULONG Idx; #ifdef DEBUG - VerifyHeap(); // Make sure we didn't get a bogus pointer if ((MemBlock < HeapBaseAddress) || (MemBlock > (HeapBaseAddress + HeapLengthInBytes))) { - BugCheck1("Bogus memory pointer (0x%x) passed to FreeMemory()\n", MemBlock); + BugCheck((DPRINT_MEMORY, "Bogus memory pointer (0x%x) passed to FreeMemory()\n", MemBlock)); } #endif DEBUG @@ -167,7 +181,7 @@ VOID FreeMemory(PVOID MemBlock) // Make sure we didn't get a bogus pointer if ((BlockCount < 1) || (BlockCount > HeapMemBlockCount)) { - BugCheck1("Invalid block count in heap page header. HeapMemBlockArray[BlockNumber].BlocksAllocated = %d\n", HeapMemBlockArray[BlockNumber].BlocksAllocated); + BugCheck((DPRINT_MEMORY, "Invalid block count in heap page header. HeapMemBlockArray[BlockNumber].BlocksAllocated = %d\n", HeapMemBlockArray[BlockNumber].BlocksAllocated)); } #endif @@ -181,7 +195,8 @@ VOID FreeMemory(PVOID MemBlock) #ifdef DEBUG DecrementAllocationCount(); - DebugPrint(DPRINT_MEMORY, "Freed %d blocks of memory starting at block %d. AllocationCount: %d\n", BlockCount, BlockNumber, AllocationCount); + DbgPrint((DPRINT_MEMORY, "Freed %d blocks of memory starting at block %d. AllocationCount: %d\n", BlockCount, BlockNumber, AllocationCount)); + VerifyHeap(); #endif DEBUG } @@ -192,6 +207,11 @@ VOID VerifyHeap(VOID) ULONG Idx2; ULONG Count; + if (DUMP_MEM_MAP_ON_VERIFY) + { + DumpMemoryAllocMap(); + } + // Loop through the array and verify that // everything is kosher for (Idx=0; Idx (HeapMemBlockCount - Idx))) { - BugCheck1("Allocation length out of range in heap table. HeapMemBlockArray[Idx].BlocksAllocated = %d\n", HeapMemBlockArray[Idx].BlocksAllocated); + BugCheck((DPRINT_MEMORY, "Allocation length out of range in heap table. HeapMemBlockArray[Idx].BlocksAllocated = %d\n", HeapMemBlockArray[Idx].BlocksAllocated)); } // Now go through and verify that the rest of @@ -216,30 +236,60 @@ VOID VerifyHeap(VOID) // Make sure it's allocated if (HeapMemBlockArray[Idx + Idx2].MemBlockAllocated != TRUE) { - BugCheck0("Heap table indicates hole in memory allocation. HeapMemBlockArray[Idx + Idx2].MemBlockAllocated != TRUE\n"); + BugCheck((DPRINT_MEMORY, "Heap table indicates hole in memory allocation. HeapMemBlockArray[Idx + Idx2].MemBlockAllocated != TRUE\n")); } // Make sure the length is zero if (HeapMemBlockArray[Idx + Idx2].BlocksAllocated != 0) { - BugCheck0("Allocation chain has non-zero value in non-first block in heap table. HeapMemBlockArray[Idx + Idx2].BlocksAllocated != 0\n"); + BugCheck((DPRINT_MEMORY, "Allocation chain has non-zero value in non-first block in heap table. HeapMemBlockArray[Idx + Idx2].BlocksAllocated != 0\n")); } } // Move on to the next run - Idx += Count; + Idx += (Count - 1); } else { // Nope, not allocated so make sure the length is zero if (HeapMemBlockArray[Idx].BlocksAllocated != 0) { - BugCheck0("Free block is start of memory allocation. HeapMemBlockArray[Idx].BlocksAllocated != 0\n"); + BugCheck((DPRINT_MEMORY, "Free block is start of memory allocation. HeapMemBlockArray[Idx].BlocksAllocated != 0\n")); } } } } +VOID DumpMemoryAllocMap(VOID) +{ + ULONG Idx; + + DbgPrint((DPRINT_MEMORY, "----------- Memory Allocation Bitmap -----------\n")); + + for (Idx=0; Idx + * Copyright (C) 1999, 2000, 2001 Brian Palmer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,171 +22,384 @@ #include "tui.h" #include "menu.h" #include "options.h" +#include "memory.h" -static int nOSListBoxLeft; -static int nOSListBoxRight; -static int nOSListBoxTop; -static int nOSListBoxBottom; -static int nOSSelected = 0; // Currently selected OS (zero based) - -int RunMenu(void) +typedef struct { - int key; - int second; - BOOL bDone = FALSE; + PUCHAR *MenuItemList; + ULONG MenuItemCount; + LONG MenuTimeRemaining; + ULONG SelectedMenuItem; + + ULONG Left; + ULONG Top; + ULONG Right; + ULONG Bottom; - if (nTimeOut > 0) - nTimeOut++; // Increment the timeout since 0 doesn't count for a second +} MENU_INFO, *PMENU_INFO; - // Initialise the menu - InitMenu(); +VOID CalcMenuBoxSize(PMENU_INFO MenuInfo); +VOID DrawMenu(PMENU_INFO MenuInfo); +VOID DrawMenuBox(PMENU_INFO MenuInfo); +VOID DrawMenuItem(PMENU_INFO MenuInfo, ULONG MenuItemNumber); +ULONG ProcessMenuKeyboardEvent(PMENU_INFO MenuInfo); - // Update the menu - DrawMenu(); +extern ULONG nScreenWidth; // Screen Width +extern ULONG nScreenHeight; // Screen Height - second = getsecond(); +extern CHAR cStatusBarFgColor; // Status bar foreground color +extern CHAR cStatusBarBgColor; // Status bar background color +extern CHAR cBackdropFgColor; // Backdrop foreground color +extern CHAR cBackdropBgColor; // Backdrop background color +extern CHAR cBackdropFillStyle; // Backdrop fill style +extern CHAR cTitleBoxFgColor; // Title box foreground color +extern CHAR cTitleBoxBgColor; // Title box background color +extern CHAR cMessageBoxFgColor; // Message box foreground color +extern CHAR cMessageBoxBgColor; // Message box background color +extern CHAR cMenuFgColor; // Menu foreground color +extern CHAR cMenuBgColor; // Menu background color +extern CHAR cTextColor; // Normal text color +extern CHAR cSelectedTextColor; // Selected text color +extern CHAR cSelectedTextBgColor; // Selected text background color - // Loop - do +BOOL DisplayMenu(PUCHAR MenuItemList[], ULONG MenuItemCount, ULONG DefaultMenuItem, LONG MenuTimeOut, PULONG SelectedMenuItem) +{ + PUCHAR ScreenBuffer; + MENU_INFO MenuInformation; + ULONG CurrentClockSecond; + + // + // The first thing we need to check is the timeout + // If it's zero then don't bother with anything, + // just return the default item + // + if (MenuTimeOut == 0) { - // Check for a keypress - if (kbhit()) + if (SelectedMenuItem != NULL) { - // Cancel the timeout - if (nTimeOut != -1) - { - nTimeOut = -1; - DrawMenu(); - } + *SelectedMenuItem = DefaultMenuItem; + } + + return TRUE; + } + + // + // Allocate memory to hold screen contents before menu is drawn + // + ScreenBuffer = AllocateMemory(4000); + if (ScreenBuffer == NULL) + { + return FALSE; + } - // Get the key - key = getch(); + // + // Save screen contents to our buffer + // + SaveScreen(ScreenBuffer); - // Is it extended? - if (key == 0) - key = getch(); // Yes - so get the extended key + // + // Setup the MENU_INFO structure + // + MenuInformation.MenuItemList = MenuItemList; + MenuInformation.MenuItemCount = MenuItemCount; + MenuInformation.MenuTimeRemaining = MenuTimeOut; + MenuInformation.SelectedMenuItem = DefaultMenuItem; - // Process the key - switch (key) - { - case KEY_UP: - if (nOSSelected) - { - nOSSelected--; - - // Update the menu - DrawMenu(); - } - break; - case KEY_DOWN: - if (nOSSelected < (nNumOS-1)) - { - nOSSelected++; - - // Update the menu - DrawMenu(); - } - break; - case KEY_ENTER: - bDone = TRUE; - break; - case KEY_F8: - DoOptionsMenu(); - DrawBackdrop(); - DrawMenu(); - break; - } + // + // Calculate the size of the menu box + // + CalcMenuBoxSize(&MenuInformation); + + // + // Draw the menu + // + DrawMenu(&MenuInformation); + + // + // Get the current second of time + // + CurrentClockSecond = getsecond(); + + // + // Process keys + // + while (1) + { + // + // Process key presses + // + if (ProcessMenuKeyboardEvent(&MenuInformation) == KEY_ENTER) + { + // + // If they pressed enter then exit this loop + // + break; } + // // Update the date & time + // UpdateDateTime(); - if (nTimeOut > 0) + if (MenuInformation.MenuTimeRemaining > 0) { - if (getsecond() != second) + if (getsecond() != CurrentClockSecond) { - second = getsecond(); - nTimeOut--; + // + // Update the time information + // + CurrentClockSecond = getsecond(); + MenuInformation.MenuTimeRemaining--; + // // Update the menu - DrawMenu(); + // + DrawMenuBox(&MenuInformation); } } - - if (nTimeOut == 0) - bDone = TRUE; + else if (MenuInformation.MenuTimeRemaining == 0) + { + // + // A time out occurred, exit this loop and return default OS + // + break; + } } - while (!bDone); - return nOSSelected; + // + // Update the selected menu item information + // + if (SelectedMenuItem != NULL) + { + *SelectedMenuItem = MenuInformation.SelectedMenuItem; + } + + return TRUE; } -void InitMenu(void) +VOID CalcMenuBoxSize(PMENU_INFO MenuInfo) { - int i; - int height = 1; // Allow room for top & bottom borders - int width = 0; + ULONG Idx; + ULONG Width; + ULONG Height; + ULONG Length; - for(i=0; iMenuItemCount + 2; + Height -= 1; // Height is zero-based + + // + // Find the length of the longest string in the menu + // + Width = 0; + for(Idx=0; IdxMenuItemCount; Idx++) { - height++; - if(strlen(OSList[i].name) > width) - width = strlen(OSList[i].name); + Length = strlen(MenuInfo->MenuItemList[Idx]); + + if (Length > Width) + { + Width = Length; + } } - width += 18; // Allow room for left & right borders, plus 8 spaces on each side - // Calculate the OS list box area - nOSListBoxLeft = (nScreenWidth - width) / 2; - nOSListBoxRight = nOSListBoxLeft + width; - nOSListBoxTop = (nScreenHeight - height) / 2 + 1; - nOSListBoxBottom = nOSListBoxTop + height; + // + // Allow room for left & right borders, plus 8 spaces on each side + // + Width += 18; - nOSSelected = 0; + // + // Calculate the menu box area + // + MenuInfo->Left = (nScreenWidth - Width) / 2; + MenuInfo->Right = (MenuInfo->Left) + Width; + MenuInfo->Top = (( (nScreenHeight - TITLE_BOX_HEIGHT) - Height) / 2 + 1) + (TITLE_BOX_HEIGHT / 2); + MenuInfo->Bottom = (MenuInfo->Top) + Height; } -void DrawMenu(void) +VOID DrawMenu(PMENU_INFO MenuInfo) { - int i, j; - char text[260]; - char temp[260]; - int space, space_left, space_right; + ULONG Idx; + + // + // Draw the menu box + // + DrawMenuBox(MenuInfo); + // + // Draw each line of the menu + // + for (Idx=0; IdxMenuItemCount; Idx++) + { + DrawMenuItem(MenuInfo, Idx); + } +} + +VOID DrawMenuBox(PMENU_INFO MenuInfo) +{ + UCHAR MenuLineText[80]; + UCHAR TempString[80]; + + // // Update the status bar - DrawStatusText(" Use \x18\x19 to select, ENTER to boot. Press F8 for advanced options."); + // + DrawStatusText(" Use \x18\x19 to select, ENTER to boot."); + + // + // Draw the menu box + // + DrawBox(MenuInfo->Left, + MenuInfo->Top, + MenuInfo->Right, + MenuInfo->Bottom, + D_VERT, + D_HORZ, + FALSE, // Filled + TRUE, // Shadow + ATTR(cMenuFgColor, cMenuBgColor)); + + // + // If there is a timeout draw the time remaining + // + if (MenuInfo->MenuTimeRemaining >= 0) + { + strcpy(MenuLineText, "[ Time Remaining: "); + itoa(MenuInfo->MenuTimeRemaining, TempString, 10); + strcat(MenuLineText, TempString); + strcat(MenuLineText, " ]"); - DrawBox(nOSListBoxLeft, nOSListBoxTop, nOSListBoxRight, nOSListBoxBottom, D_VERT, D_HORZ, TRUE, TRUE, ATTR(cMenuFgColor, cMenuBgColor)); + DrawText(MenuInfo->Right - strlen(MenuLineText) - 1, + MenuInfo->Bottom, + MenuLineText, + ATTR(cMenuFgColor, cMenuBgColor)); + } +} + +VOID DrawMenuItem(PMENU_INFO MenuInfo, ULONG MenuItemNumber) +{ + ULONG Idx; + UCHAR MenuLineText[80]; + ULONG SpaceTotal; + ULONG SpaceLeft; + ULONG SpaceRight; + + // + // We will want the string centered so calculate + // how many spaces will be to the left and right + // + SpaceTotal = (MenuInfo->Right - MenuInfo->Left - 2) - strlen(MenuInfo->MenuItemList[MenuItemNumber]); + SpaceLeft = (SpaceTotal / 2) + 1; + SpaceRight = (SpaceTotal - SpaceLeft) + 1; + + // + // Insert the spaces on the left + // + for (Idx=0; IdxMenuItemList[MenuItemNumber]); + + // + // Now append the spaces on the right + // + for (Idx=0; IdxSelectedMenuItem) + { + DrawText(MenuInfo->Left + 1, + MenuInfo->Top + 1 + MenuItemNumber, + MenuLineText, + ATTR(cSelectedTextColor, cSelectedTextBgColor)); + } + else + { + DrawText(MenuInfo->Left + 1, + MenuInfo->Top + 1 + MenuItemNumber, + MenuLineText, + ATTR(cTextColor, cMenuBgColor)); + } +} + +ULONG ProcessMenuKeyboardEvent(PMENU_INFO MenuInfo) +{ + ULONG KeyEvent = 0; - for(i=0; iMenuTimeRemaining != -1) { - DrawText(nOSListBoxLeft+1, nOSListBoxTop+1+i, text, ATTR(cSelectedTextColor, cSelectedTextBgColor)); + MenuInfo->MenuTimeRemaining = -1; + DrawMenuBox(MenuInfo); } - else + + // + // Get the key + // + KeyEvent = getch(); + + // + // Is it extended? + // + if (KeyEvent == 0) + KeyEvent = getch(); // Yes - so get the extended key + + // + // Process the key + // + switch (KeyEvent) { - DrawText(nOSListBoxLeft+1, nOSListBoxTop+1+i, text, ATTR(cTextColor, cMenuBgColor)); - } - } + case KEY_UP: + + if (MenuInfo->SelectedMenuItem > 0) + { + MenuInfo->SelectedMenuItem--; - if (nTimeOut >= 0) - { - strcpy(text, "[ Time Remaining: "); - itoa(nTimeOut, temp, 10); - strcat(text, temp); - strcat(text, " ]"); + // + // Update the menu + // + DrawMenuItem(MenuInfo, MenuInfo->SelectedMenuItem + 1); // Deselect previous item + DrawMenuItem(MenuInfo, MenuInfo->SelectedMenuItem); // Select new item + } + + break; - DrawText(nOSListBoxRight - strlen(text) - 1, nOSListBoxBottom, text, ATTR(cMenuFgColor, cMenuBgColor)); + case KEY_DOWN: + + if (MenuInfo->SelectedMenuItem < (MenuInfo->MenuItemCount - 1)) + { + MenuInfo->SelectedMenuItem++; + + // + // Update the menu + // + DrawMenuItem(MenuInfo, MenuInfo->SelectedMenuItem - 1); // Deselect previous item + DrawMenuItem(MenuInfo, MenuInfo->SelectedMenuItem); // Select new item + } + + break; + } } -} \ No newline at end of file + + return KeyEvent; +} diff --git a/freeldr/freeldr/menu.h b/freeldr/freeldr/menu.h index ebf085ff534..b30d0b6f26d 100644 --- a/freeldr/freeldr/menu.h +++ b/freeldr/freeldr/menu.h @@ -1,6 +1,6 @@ /* * FreeLoader - * Copyright (C) 1999, 2000 Brian Palmer + * Copyright (C) 1999, 2000, 2001 Brian Palmer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,8 +20,6 @@ #ifndef __MENU_H #define __MENU_H -int RunMenu(void); -void InitMenu(void); -void DrawMenu(void); +BOOL DisplayMenu(PUCHAR MenuItemList[], ULONG MenuItemCount, ULONG DefaultMenuItem, LONG MenuTimeOut, PULONG SelectedMenuItem); #endif // #defined __MENU_H \ No newline at end of file diff --git a/freeldr/freeldr/miscboot.c b/freeldr/freeldr/miscboot.c index 43a76b7b748..c084cc77ae8 100644 --- a/freeldr/freeldr/miscboot.c +++ b/freeldr/freeldr/miscboot.c @@ -28,14 +28,15 @@ void LoadAndBootBootSector(int nOSToBoot) { - FILE file; + FILE* FilePointer; char name[260]; char value[260]; char szFileName[1024]; int i; + ULONG BytesRead; // Find all the message box settings and run them - for (i=1; i<=GetNumSectionItems(OSList[nOSToBoot].name); i++) + /*for (i=1; i<=GetNumSectionItems(OSList[nOSToBoot].name); i++) { ReadSectionSettingByNumber(OSList[nOSToBoot].name, i, name, value); if (stricmp(name, "MessageBox") == 0) @@ -69,7 +70,9 @@ void LoadAndBootBootSector(int nOSToBoot) } strcpy(szFileName, value); - if (!OpenFile(szFileName, &file)) + + FilePointer = OpenFile(szFileName); + if (FilePointer == NULL) { strcat(value, " not found."); MessageBox(value); @@ -77,7 +80,7 @@ void LoadAndBootBootSector(int nOSToBoot) } // Read boot sector - if (ReadFile(&file, 512, (void*)0x7c00) != 512) + if (!ReadFile(FilePointer, 512, &BytesRead, (void*)0x7c00) || (BytesRead != 512)) { MessageBox("Disk Read Error"); return; @@ -95,7 +98,7 @@ void LoadAndBootBootSector(int nOSToBoot) gotoxy(CursorXPos, CursorYPos); stop_floppy(); - JumpToBootCode(); + JumpToBootCode();*/ } void LoadAndBootPartition(int nOSToBoot) @@ -107,7 +110,7 @@ void LoadAndBootPartition(int nOSToBoot) int i; // Find all the message box settings and run them - for (i=1; i<=GetNumSectionItems(OSList[nOSToBoot].name); i++) + /*for (i=1; i<=GetNumSectionItems(OSList[nOSToBoot].name); i++) { ReadSectionSettingByNumber(OSList[nOSToBoot].name, i, name, value); if (stricmp(name, "MessageBox") == 0) @@ -132,14 +135,14 @@ void LoadAndBootPartition(int nOSToBoot) BootPartition = atoi(value); - if (!biosdisk(_DISK_READ, BootDrive, 0, 0, 1, 1, SectorBuffer)) + if (!BiosInt13Read(BootDrive, 0, 0, 1, 1, DISKREADBUFFER)) { MessageBox("Disk Read Error"); return; } // Check for validity - if (*((WORD*)(SectorBuffer + 0x1fe)) != 0xaa55) + if (*((WORD*)(DISKREADBUFFER + 0x1fe)) != 0xaa55) { MessageBox("Invalid partition table magic (0xaa55)"); return; @@ -181,7 +184,7 @@ void LoadAndBootPartition(int nOSToBoot) gotoxy(CursorXPos, CursorYPos); stop_floppy(); - JumpToBootCode(); + JumpToBootCode();*/ } void LoadAndBootDrive(int nOSToBoot) @@ -191,7 +194,7 @@ void LoadAndBootDrive(int nOSToBoot) int i; // Find all the message box settings and run them - for (i=1; i<=GetNumSectionItems(OSList[nOSToBoot].name); i++) + /*for (i=1; i<=GetNumSectionItems(OSList[nOSToBoot].name); i++) { ReadSectionSettingByNumber(OSList[nOSToBoot].name, i, name, value); if (stricmp(name, "MessageBox") == 0) @@ -226,5 +229,5 @@ void LoadAndBootDrive(int nOSToBoot) gotoxy(CursorXPos, CursorYPos); stop_floppy(); - JumpToBootCode(); + JumpToBootCode();*/ } diff --git a/freeldr/freeldr/multiboot.c b/freeldr/freeldr/multiboot.c index 8bac0bcceb6..78b11a83028 100644 --- a/freeldr/freeldr/multiboot.c +++ b/freeldr/freeldr/multiboot.c @@ -36,12 +36,13 @@ BOOL MultiBootLoadKernel(FILE *KernelImage) DWORD dwFileLoadOffset; DWORD dwDataSize; DWORD dwBssSize; + ULONG BytesRead; /* * Load the first 8192 bytes of the kernel image * so we can search for the multiboot header */ - ReadFile(KernelImage, 8192, ImageHeaders); + ReadFile(KernelImage, 8192, NULL, ImageHeaders); /* * Now find the multiboot header and copy it @@ -95,13 +96,13 @@ BOOL MultiBootLoadKernel(FILE *KernelImage) * Get the file offset, this should be 0, and move the file pointer */ dwFileLoadOffset = (Idx * sizeof(DWORD)) - (mb_header.header_addr - mb_header.load_addr); - fseek(KernelImage, dwFileLoadOffset); + SetFilePointer(KernelImage, dwFileLoadOffset); /* * Load the file image */ dwDataSize = (mb_header.load_end_addr - mb_header.load_addr); - ReadFile(KernelImage, dwDataSize, (void*)mb_header.load_addr); + ReadFile(KernelImage, dwDataSize, NULL, (void*)mb_header.load_addr); /* * Initialize bss area @@ -142,7 +143,7 @@ BOOL MultiBootLoadModule(FILE *ModuleImage, char *ModuleName) /* * Load the file image */ - ReadFile(ModuleImage, dwModuleSize, (void*)next_module_load_base); + ReadFile(ModuleImage, dwModuleSize, NULL, (void*)next_module_load_base); next_module_load_base = ROUND_UP(pModule->mod_end, /*PAGE_SIZE*/4096); mb_info.mods_count++; @@ -154,10 +155,14 @@ int GetBootPartition(char *OperatingSystemName) { int BootPartitionNumber = -1; char value[1024]; + ULONG SectionId; - if (ReadSectionSettingByName(OperatingSystemName, "BootPartition", value)) + if (OpenSection(OperatingSystemName, &SectionId)) { - BootPartitionNumber = atoi(value); + if (ReadSectionSettingByName(SectionId, "BootPartition", value, 1024)) + { + BootPartitionNumber = atoi(value); + } } return BootPartitionNumber; diff --git a/freeldr/freeldr/options.c b/freeldr/freeldr/options.c index 3a0e92db956..e779d0f6da7 100644 --- a/freeldr/freeldr/options.c +++ b/freeldr/freeldr/options.c @@ -23,7 +23,7 @@ #include "options.h" #include "miscboot.h" - +#if 0 void DoOptionsMenu(void) { int OptionsMenuItemCount = 1; // Count is 1 because we don't show the "Set ReactOS Boot Flags" menu item yet @@ -101,7 +101,7 @@ void DoBootOptionsMenu(int BootDriveNum, char *BootDriveText) char BootOptionsMenuItems[2][80] = { "Boot To ", "Pick A Boot Partition" }; int BootOptionsMenuItemSelected = 0; - strcat(BootOptionsMenuItems[0], BootDriveText); + /*strcat(BootOptionsMenuItems[0], BootDriveText); while (BootOptionsMenuItemSelected != -1) { @@ -144,7 +144,7 @@ void DoBootOptionsMenu(int BootDriveNum, char *BootDriveText) break; } - } + }*/ } void DoBootPartitionOptionsMenu(int BootDriveNum) @@ -164,7 +164,7 @@ void DoBootPartitionOptionsMenu(int BootDriveNum) char temp[25]; - BootDrive = BootDriveNum; + /*BootDrive = BootDriveNum; if (!biosdisk(_DISK_READ, BootDrive, 0, 0, 1, 1, SectorBuffer)) { @@ -244,7 +244,7 @@ void DoBootPartitionOptionsMenu(int BootDriveNum) stop_floppy(); JumpToBootCode(); } - } + }*/ } int RunOptionsMenu(char OptionsMenuItems[][80], int OptionsMenuItemCount, int nOptionSelected, char *OptionsMenuTitle) @@ -345,7 +345,7 @@ int RunOptionsMenu(char OptionsMenuItems[][80], int OptionsMenuItemCount, int nO void InitOptionsMenu(int *nOptionsMenuBoxLeft, int *nOptionsMenuBoxTop, int *nOptionsMenuBoxRight, int *nOptionsMenuBoxBottom, int OptionsMenuItemCount) { - int height = OptionsMenuItemCount; + /*int height = OptionsMenuItemCount; int width = 20; height += 1; // Allow room for top & bottom borders @@ -355,7 +355,7 @@ void InitOptionsMenu(int *nOptionsMenuBoxLeft, int *nOptionsMenuBoxTop, int *nOp *nOptionsMenuBoxLeft = (nScreenWidth - width) / 2; *nOptionsMenuBoxRight = *nOptionsMenuBoxLeft + width; *nOptionsMenuBoxTop = (nScreenHeight - height) / 2 + 1; - *nOptionsMenuBoxBottom = *nOptionsMenuBoxTop + height; + *nOptionsMenuBoxBottom = *nOptionsMenuBoxTop + height;*/ } void DrawOptionsMenu(char OptionsMenuItems[][80], int OptionsMenuItemCount, int nOptionSelected, char *OptionsMenuTitle, int nOptionsMenuBoxLeft, int nOptionsMenuBoxTop, int nOptionsMenuBoxRight, int nOptionsMenuBoxBottom) @@ -365,7 +365,7 @@ void DrawOptionsMenu(char OptionsMenuItems[][80], int OptionsMenuItemCount, int int space, space_left, space_right; // Update the status bar - DrawStatusText(" Use \x18\x19 to select, then press ENTER. Press ESC to go back."); + /*DrawStatusText(" Use \x18\x19 to select, then press ENTER. Press ESC to go back."); DrawBox(nOptionsMenuBoxLeft, nOptionsMenuBoxTop, nOptionsMenuBoxRight, nOptionsMenuBoxBottom, D_VERT, D_HORZ, TRUE, TRUE, ATTR(cMenuFgColor, cMenuBgColor)); DrawText(nOptionsMenuBoxLeft + (((nOptionsMenuBoxRight - nOptionsMenuBoxLeft) - strlen(OptionsMenuTitle)) / 2) + 1, nOptionsMenuBoxTop, OptionsMenuTitle, ATTR(cMenuFgColor, cMenuBgColor)); @@ -391,5 +391,6 @@ void DrawOptionsMenu(char OptionsMenuItems[][80], int OptionsMenuItemCount, int { DrawText(nOptionsMenuBoxLeft+1, nOptionsMenuBoxTop+1+i, text, ATTR(cTextColor, cMenuBgColor)); } - } -} \ No newline at end of file + }*/ +} +#endif \ No newline at end of file diff --git a/freeldr/freeldr/oslist.c b/freeldr/freeldr/oslist.c new file mode 100644 index 00000000000..34d67df2a07 --- /dev/null +++ b/freeldr/freeldr/oslist.c @@ -0,0 +1,251 @@ +/* + * FreeLoader + * Copyright (C) 1999, 2000, 2001 Brian Palmer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "freeldr.h" +#include "parseini.h" +#include "oslist.h" + +BOOL InitOperatingSystemList(PUCHAR **SectionNamesPointer, PUCHAR **DisplayNamesPointer, PULONG OperatingSystemCountPointer) +{ + ULONG Idx; + ULONG CurrentOperatingSystemIndex; + UCHAR SettingName[80]; + UCHAR SettingValue[80]; + ULONG OperatingSystemCount; + ULONG SectionId; + ULONG OperatingSystemSectionId; + ULONG SectionSettingCount; + PUCHAR *OperatingSystemSectionNames; + PUCHAR *OperatingSystemDisplayNames; + + // + // Open the [FreeLoader] section + // + if (!OpenSection("FreeLoader", &SectionId)) + { + MessageBox("Section [FreeLoader] not found in freeldr.ini."); + return FALSE; + } + + SectionSettingCount = GetNumSectionItems(SectionId); + OperatingSystemCount = CountOperatingSystems(SectionId); + + // + // Allocate memory to hold operating system lists + // + if (!AllocateListMemory(&OperatingSystemSectionNames, &OperatingSystemDisplayNames, OperatingSystemCount)) + { + return FALSE; + } + + // + // Now loop through and read the operating system section names + // + CurrentOperatingSystemIndex = 0; + for (Idx=0; Idx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __OSLIST_H +#define __OSLIST_H + +BOOL InitOperatingSystemList(PUCHAR **SectionNamesPointer, PUCHAR **DisplayNamesPointer, PULONG OperatingSystemCountPointer); +ULONG CountOperatingSystems(ULONG SectionId); +BOOL AllocateListMemory(PUCHAR **SectionNamesPointer, PUCHAR **DisplayNamesPointer, ULONG OperatingSystemCount); +BOOL RemoveQuotes(PUCHAR QuotedString); + +#endif // #defined __OSLIST_H diff --git a/freeldr/freeldr/parseini.c b/freeldr/freeldr/parseini.c index 1bb2615d44d..681c1eba98c 100644 --- a/freeldr/freeldr/parseini.c +++ b/freeldr/freeldr/parseini.c @@ -23,16 +23,17 @@ #include "fs.h" #include "stdlib.h" #include "memory.h" +#include "debug.h" PUCHAR FreeLoaderIniFileData = NULL; ULONG FreeLoaderIniFileSize = 0; -BOOL ParseIniFile(void) +BOOL ParseIniFile(VOID) { - int i; - char name[1024]; - char value[1024]; - FILE Freeldr_Ini; // File handle for freeldr.ini + //int i; + //char name[1024]; + //char value[1024]; + PFILE Freeldr_Ini; // File handle for freeldr.ini // Open the boot drive for file access if (!OpenDiskDrive(BootDrive, 0)) @@ -42,28 +43,31 @@ BOOL ParseIniFile(void) } // Try to open freeldr.ini or fail - if (!OpenFile("freeldr.ini", &Freeldr_Ini)) + Freeldr_Ini = OpenFile("freeldr.ini"); + if (Freeldr_Ini == NULL) { printf("FREELDR.INI not found.\nYou need to re-install FreeLoader.\n"); return FALSE; } // Get the file size & allocate enough memory for it - FreeLoaderIniFileSize = GetFileSize(&Freeldr_Ini); + FreeLoaderIniFileSize = GetFileSize(Freeldr_Ini); FreeLoaderIniFileData = AllocateMemory(FreeLoaderIniFileSize); // If we are out of memory then return FALSE if (FreeLoaderIniFileData == NULL) { printf("Out of memory while loading FREELDR.INI.\n"); + CloseFile(Freeldr_Ini); return FALSE; } // Read freeldr.ini off the disk - ReadFile(&Freeldr_Ini, FreeLoaderIniFileSize, FreeLoaderIniFileData); + ReadFile(Freeldr_Ini, FreeLoaderIniFileSize, NULL, FreeLoaderIniFileData); + CloseFile(Freeldr_Ini); // Make sure the [FREELOADER] section exists - if (!GetNumSectionItems("FREELOADER")) + /*if (OpenSection("FREELOADER", NULL)) { printf("Section [FREELOADER] not found in FREELDR.INI.\nYou need to re-install FreeLoader.\n"); return FALSE; @@ -81,7 +85,7 @@ BOOL ParseIniFile(void) } else SetSetting(name, value); - } + }*/ return TRUE; } @@ -122,208 +126,202 @@ ULONG GetNextLineOfFileData(PUCHAR Buffer, ULONG BufferSize, ULONG CurrentOffset return CurrentOffset; } -ULONG GetOffsetOfFirstLineOfSection(PUCHAR SectionName) +BOOL OpenSection(PUCHAR SectionName, PULONG SectionId) { - char str[1024]; - char real_section[1024]; - ULONG freeldr_ini_offset; + UCHAR TempString[80]; + UCHAR RealSectionName[80]; + ULONG FileOffset; BOOL SectionFound = FALSE; + // // Get the real section name - strcpy(real_section, "["); - strcat(real_section, SectionName); - strcat(real_section, "]"); + // + strcpy(RealSectionName, "["); + strcat(RealSectionName, SectionName); + strcat(RealSectionName, "]"); + // // Get to the beginning of the file - freeldr_ini_offset = 0; + // + FileOffset = 0; + // // Find the section - while (freeldr_ini_offset < FreeLoaderIniFileSize) + // + while (FileOffset < FreeLoaderIniFileSize) { + // // Read a line - freeldr_ini_offset = GetNextLineOfFileData(str, 1024, freeldr_ini_offset); - - // Skip comments - if (str[0] == '#') - continue; - - // Skip blank lines - if (!strlen(str)) - continue; + // + FileOffset = GetNextLineOfFileData(TempString, 80, FileOffset); + // // If it isn't a section header then continue on - if (str[0] != '[') + // + if (TempString[0] != '[') continue; + // // Check and see if we found it - if (stricmp(str, real_section) == 0) + // + if (stricmp(TempString, RealSectionName) == 0) { SectionFound = TRUE; break; } } - // If we didn't find the section then we're outta here - if (!SectionFound) - return 0; + if (SectionId) + { + *SectionId = FileOffset; + } - return freeldr_ini_offset; + return SectionFound; } -ULONG GetNumSectionItems(PUCHAR SectionName) +ULONG GetNumSectionItems(ULONG SectionId) { - UCHAR str[1024]; - ULONG num_items = 0; - ULONG freeldr_ini_offset; - - // Get to the beginning of the section - freeldr_ini_offset = GetOffsetOfFirstLineOfSection(SectionName); - - // If the section wasn't found then exit - if (freeldr_ini_offset == 0) - { - return 0; - } + UCHAR TempString[80]; + ULONG SectionItemCount = 0; // Now count how many settings are in this section - while (freeldr_ini_offset < FreeLoaderIniFileSize) + while (SectionId < FreeLoaderIniFileSize) { // Read a line - freeldr_ini_offset = GetNextLineOfFileData(str, 1024, freeldr_ini_offset); + SectionId = GetNextLineOfFileData(TempString, 80, SectionId); + + // If we hit a new section then we're done + if (TempString[0] == '[') + break; // Skip comments - if (str[0] == '#') + if (TempString[0] == '#') continue; // Skip blank lines - if (!strlen(str)) + if (!strlen(TempString)) continue; - // If we hit a new section then we're done - if (str[0] == '[') - break; - - num_items++; + SectionItemCount++; } - return num_items; + return SectionItemCount; } -BOOL ReadSectionSettingByNumber(PUCHAR SectionName, ULONG SettingNumber, PUCHAR SettingName, PUCHAR SettingValue) +BOOL ReadSectionSettingByNumber(ULONG SectionId, ULONG SettingNumber, PUCHAR SettingName, ULONG NameSize, PUCHAR SettingValue, ULONG ValueSize) { - UCHAR str[1024]; - ULONG num_items = 0; - ULONG i; - ULONG freeldr_ini_offset; + UCHAR TempString[1024]; + ULONG SectionItemCount = 0; + ULONG Idx; + ULONG FileOffset; + // // Get to the beginning of the section - freeldr_ini_offset = GetOffsetOfFirstLineOfSection(SectionName); - - // If the section wasn't found then exit - if (freeldr_ini_offset == 0) - { - return 0; - } + // + FileOffset = SectionId; + // // Now find the setting we are looking for - while (freeldr_ini_offset < FreeLoaderIniFileSize) + // + do { // Read a line - freeldr_ini_offset = GetNextLineOfFileData(str, 1024, freeldr_ini_offset); + FileOffset = GetNextLineOfFileData(TempString, 1024, FileOffset); // Skip comments - if (str[0] == '#') + if (TempString[0] == '#') continue; // Skip blank lines - if (!strlen(str)) + if (!strlen(TempString)) continue; // If we hit a new section then we're done - if (str[0] == '[') + if (TempString[0] == '[') break; - // Increment setting number - num_items++; - // Check and see if we found the setting - if (num_items == SettingNumber) + if (SectionItemCount == SettingNumber) { - for (i=0; i", ATTR(cTitleBoxFgColor, cTitleBoxBgColor)); - + // + DrawText(3, + 3, + "by Brian Palmer", + ATTR(cTitleBoxFgColor, cTitleBoxBgColor)); + DrawText(3, + 4, + "", + ATTR(cTitleBoxFgColor, cTitleBoxBgColor)); + + // // Draw help text + // //DrawText(nScreenWidth-15, 4, /*"F1 for Help"*/"F8 for Options", ATTR(cTitleBoxFgColor, cTitleBoxBgColor)); - // Draw title - DrawText((nScreenWidth/2)-(strlen(szTitleBoxTitleText)/2), 3, szTitleBoxTitleText, ATTR(cTitleBoxFgColor, cTitleBoxBgColor)); - - // Draw date - DrawText(nScreenWidth-9, 2, "01/02/03", ATTR(cTitleBoxFgColor, cTitleBoxBgColor)); - // Draw time - DrawText(nScreenWidth-9, 3, "10:12:34", ATTR(cTitleBoxFgColor, cTitleBoxBgColor)); + // + // Draw title text + // + DrawText( (nScreenWidth / 2) - (strlen(szTitleBoxTitleText)/2), + 3, + szTitleBoxTitleText, + ATTR(cTitleBoxFgColor, cTitleBoxBgColor)); + // // Draw status bar + // DrawStatusText(""); + // // Update the date & time + // UpdateDateTime(); } @@ -234,8 +370,8 @@ void DrawStatusText(char *text) void UpdateDateTime(void) { - char date[260]; - char time[260]; + char date[40]; + char time[40]; char temp[20]; int hour, minute, second, bPM=FALSE; @@ -353,10 +489,19 @@ void MessageBox(char *text) int curline = 0; int i , j, k; int x1, x2, y1, y2; - char savebuffer[8000]; + PVOID savebuffer; char temp[260]; char key; + if (!UserInterfaceUp) + { + printf("%s", text); + printf("Press any key.\n"); + getch(); + return; + } + + savebuffer = AllocateMemory(8000); SaveScreen(savebuffer); strcat(szMessageBoxLineText, text); @@ -428,6 +573,7 @@ void MessageBox(char *text) } RestoreScreen(savebuffer); + FreeMemory(savebuffer); UpdateDateTime(); strcpy(szMessageBoxLineText, ""); } diff --git a/freeldr/freeldr/tui.h b/freeldr/freeldr/tui.h index 8dc6cf0914f..072ac5c7942 100644 --- a/freeldr/freeldr/tui.h +++ b/freeldr/freeldr/tui.h @@ -20,27 +20,11 @@ #ifndef __TUI_H #define __TUI_H -#define SCREEN_MEM 0xB8000 - -extern int nScreenWidth; // Screen Width -extern int nScreenHeight; // Screen Height - -extern char cStatusBarFgColor; // Status bar foreground color -extern char cStatusBarBgColor; // Status bar background color -extern char cBackdropFgColor; // Backdrop foreground color -extern char cBackdropBgColor; // Backdrop background color -extern char cBackdropFillStyle; // Backdrop fill style -extern char cTitleBoxFgColor; // Title box foreground color -extern char cTitleBoxBgColor; // Title box background color -extern char cMessageBoxFgColor; // Message box foreground color -extern char cMessageBoxBgColor; // Message box background color -extern char cMenuFgColor; // Menu foreground color -extern char cMenuBgColor; // Menu background color -extern char cTextColor; // Normal text color -extern char cSelectedTextColor; // Selected text color -extern char cSelectedTextBgColor; // Selected text background color -extern char szTitleBoxTitleText[260]; // Title box's title text +#define SCREEN_MEM 0xB8000 +#define TITLE_BOX_HEIGHT 5 +// Initialize Textual-User-Interface +BOOL InitUserInterface(VOID); // Fills the entire screen with a backdrop void DrawBackdrop(void); // Fills the area specified with cFillChar and cAttr diff --git a/freeldr/notes.txt b/freeldr/notes.txt index 8dcc68e76a8..489ee79ac72 100644 --- a/freeldr/notes.txt +++ b/freeldr/notes.txt @@ -4,8 +4,9 @@ To build FreeLoader you will need DJGPP because Mingw32 doesn't support 16-bit c FreeLoader does not currently work with extended partitions. Linux booting support needs to be added. ext2 filesystem support needs to be added. +The MessageBox() function needs to not allocate memory. Because it gets called when memory allocation fails. -Current memory layout: +Old memory layout: 0000:0000 - 0000:0FFF: Interrupt vector table & BIOS data 0000:1000 - 0000:6FFF: Real mode stack area @@ -16,3 +17,27 @@ xxxx:xxxx - 6000:0000: Protected mode stack area & heap 7000:0000 - 7000:FFFF: scratch area for any function's use (ie sector buffer for biosdisk()) - can be overwritten by any function 8000:0000 - 9000:FFFF: fat table entry buffer A000:0000 - FFFF:FFFF: reserved + + +New memory layout: + +0000:0000 - 0000:0FFF: Interrupt vector table & BIOS data +0000:1000 - 0000:6FFF: Real mode stack area +0000:7000 - 0000:7FFF: Unused +0000:8000 - xxxx:xxxx: FreeLoader program & data area +xxxx:xxxx - 8000:FFFF: Random memory allocation heap +9000:0000 - 9000:7FFF: Disk read buffer for BIOS Int 13h +9000:8000 - 9000:8FFF: Screen save buffer passed in from boot sector +9000:9000 - 9000:FFFF: Protected mode stack area +A000:0000 - FFFF:FFFF: reserved + + +FreeLoader Boot Process + +Boot Sector + + The BIOS loads the boot sector at 0000:7C00. The FAT32 boot sector relocates itself higher in memory at 9000:0000 and loads it's extra sector at 9000:0200 and then looks for freeldr.sys on the file system. Once found it loads freeldr.sys to 0000:7E00 and then jumps to it's entry point at 0000:8000. The FAT12/16 boot sector does no relocation, it just searches for the freeldr.sys and loads the first 512 bytes to 0000:7E00. This extra code enables it to fully navigate the file allocation table. Then it loads freeldr.sys to 0000:7E00 and jumps to it's entry point at 0000:8000. Before FreeLoader gets control the boot sector saves the screen contents to a buffer at 9000:8000 and the cursor x & y position to bytes at 9000:8FA0 & 9000:8FA1 respectively. + +FreeLoader Initialization + + When FreeLoader gets control it saves the boot drive, passed to it in the DL register, and sets up the stack, enables protected mode, and calls BootMain(). \ No newline at end of file -- 2.17.1