https://git.reactos.org/?p=reactos.git;a=commitdiff;h=065afd93fd35cb8a9717d…
commit 065afd93fd35cb8a9717d901649bee97d71d1a35
Author: Dmitry Borisov <di.sean(a)protonmail.com>
AuthorDate: Sun Jan 19 00:16:23 2020 +0600
Commit: Hermès BÉLUSCA - MAÏTO <hermes.belusca-maito(a)reactos.org>
CommitDate: Sat Jan 18 19:16:23 2020 +0100
[FREELDR] Add FAT12 file system boot sector for NEC PC-98 series (#2025)
The first part of PC-98 Port -
https://reactos.org/wiki/PC-98
- Add FAT12 file system boot sector for NEC PC-98 series.
- Add a new build target for a PC-98 bootable floppy disk.
- Add a new sub-architecture into config.cmake.
---
boot/freeldr/bootsect/CMakeLists.txt | 4 +
boot/freeldr/bootsect/pc98/fat12fdd.S | 501 ++++++++++++++++++++++++++++++++++
boot/freeldr/freeldr/CMakeLists.txt | 8 +
sdk/cmake/config.cmake | 2 +-
4 files changed, 514 insertions(+), 1 deletion(-)
diff --git a/boot/freeldr/bootsect/CMakeLists.txt b/boot/freeldr/bootsect/CMakeLists.txt
index 411750ac7a0..c847a998fa2 100644
--- a/boot/freeldr/bootsect/CMakeLists.txt
+++ b/boot/freeldr/bootsect/CMakeLists.txt
@@ -8,6 +8,10 @@ if(ARCH STREQUAL "i386" OR ARCH STREQUAL "amd64")
CreateBootSectorTarget(fat32 ${CMAKE_CURRENT_SOURCE_DIR}/fat32.S
${CMAKE_CURRENT_BINARY_DIR}/fat32.bin 7c00)
CreateBootSectorTarget(btrfsvbr ${CMAKE_CURRENT_SOURCE_DIR}/btrfs.S
${CMAKE_CURRENT_BINARY_DIR}/btrfs.bin 7c00)
+ if(SARCH STREQUAL "pc98")
+ CreateBootSectorTarget(fat12pc98 ${CMAKE_CURRENT_SOURCE_DIR}/pc98/fat12fdd.S
${CMAKE_CURRENT_BINARY_DIR}/pc98/fat12fdd.bin 7c00)
+ endif()
+
## New versions using FATY.S (experimental)
# add_definitions(-DFAT12)
# CreateBootSectorTarget(fat_new ${CMAKE_CURRENT_SOURCE_DIR}/faty.S
${CMAKE_CURRENT_BINARY_DIR}/fat_new.bin 7c00)
diff --git a/boot/freeldr/bootsect/pc98/fat12fdd.S
b/boot/freeldr/bootsect/pc98/fat12fdd.S
new file mode 100644
index 00000000000..51ebfec05c4
--- /dev/null
+++ b/boot/freeldr/bootsect/pc98/fat12fdd.S
@@ -0,0 +1,501 @@
+/*
+ * PROJECT: FreeLoader
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: FAT12 file system boot sector for NEC PC-98 series
+ * NOTES: The source code in this file is based on the Brian Palmer's work
+ * (boot/freeldr/bootsect/fat.S)
+ * COPYRIGHT: Copyright 2019 Dmitry Borisov (di.sean(a)protonmail.com)
+ */
+
+#include <asm.inc>
+#include <freeldr/include/arch/pc/x86common.h>
+
+#define BP_REL(x) [bp + x - offset start]
+#define VGA_WIDTH 80
+#define VGA_HEIGHT 25
+
+/*
+ * See
https://www.webtech.co.jp/company/doc/undocumented_mem/memsys.txt
+ * At segment 0000h
+ */
+#define BOOT_DAUA HEX(0584)
+
+DataAreaStartHigh = 2
+DataAreaStartLow = 4
+BiosCHSDriveSizeHigh = 6
+BiosCHSDriveSizeLow = 8
+BiosCHSDriveSize = 8
+ReadSectorsOffset = 10
+ReadClusterOffset = 12
+PutCharsOffset = 14
+BootSectorStackTop = HEX(7C00) - 16
+
+if 0
+.macro DEBUG_STOP
+ hlt
+ jmp short $ - 1
+.endm
+
+.macro DEBUG_STEP
+ push ax
+ xor ah, ah
+ int HEX(18) // Wait for a keypress
+ pop ax
+.endm
+endif
+
+// org 7C00h
+
+.code16
+
+start:
+ jmp main
+ nop
+
+// After running fatten tool it overwrites (BPB & EBPB)
+OEMName:
+ .ascii "FrLdr1.0"
+BytesPerSector:
+ .word 512
+SectsPerCluster:
+ .byte 1
+ReservedSectors:
+ .word 1
+NumberOfFats:
+ .byte 2
+MaxRootEntries:
+ .word 224
+TotalSectors:
+ .word 2880
+MediaDescriptor:
+ .byte HEX(0f0)
+SectorsPerFat:
+ .word 9
+SectorsPerTrack:
+ .word 18
+NumberOfHeads:
+ .word 2
+HiddenSectors:
+ .long 0
+TotalSectorsBig:
+ .long 0
+BootDrive:
+ .byte HEX(0ff)
+Reserved:
+ .byte 0
+ExtendSig:
+ .byte HEX(29)
+SerialNumber:
+ .long 00000000
+VolumeLabel:
+ .ascii "NO NAME "
+FileSystem:
+ .ascii "FAT12 "
+
+/*
+ * Real-mode entry point
+ */
+main:
+ xor ax, ax // Setup segment registers:
+ mov ds, ax // Make DS correct
+ mov es, ax // Make ES correct
+ mov ss, ax // Make SS correct
+ mov bp, HEX(7C00)
+ mov sp, BootSectorStackTop // Stack grows downwards from
BootSectorStackTop
+
+if 0 // It would have been nice to have had
this check...
+ mov ax, HEX(1000) // Detecting hardware
+
+ /*
+ * INSTALLATION CHECK interrupt
+ * See
http://www.ctyme.com/intr/rb-2293.htm
+ */
+ int HEX(1A)
+ cmp ax, HEX(1000)
+ je HardwareError // An IBM-compatible PC
+endif
+
+ /*
+ * IBM PC here: NEC PC-98 here:
+ * ESI = 000E:0000 ESI = 0000:0000
+ * EDI = 0000:070C EDI = 0000:0000
+ * EBP = 0000:7C00 EBP = 0000:7C00
+ * ESP = 0000:7BF0 ESP = 0000:7BF0
+ * CS:IP = 0000:7C4E CS:IP = 1FE0:004E
+ */
+ mov ax, word ptr ds:[BOOT_DAUA] // Get the Device Address/Unit Address
(DA/UA)
+ mov si, ax
+
+ push si
+ push cs
+ pop ds
+ xor si, si
+ mov ax, HEX(0000)
+ mov es, ax
+ mov di, HEX(7C00)
+ mov cx, 512
+ rep movsw // Move our 512 bytes boot sector to the
[0000:7C00]
+ pop si
+
+ ljmp16 0, relocated // Jump into relocated code
+
+relocated:
+ xor ax, ax // Clean-up segments
+ mov es, ax
+ mov ds, ax
+
+ test byte ptr ds:[HEX(501)], HEX(08) // High-resolution mode check
+ jz VideoTestNormalMode
+ mov ax, HEX(0E000)
+ jmp short VideoTestDone
+VideoTestNormalMode:
+ mov ax, HEX(0A000)
+VideoTestDone:
+ mov word ptr BP_REL(VramSegment), ax
+
+ mov ax, si
+ mov byte ptr BP_REL(BootDrive), al // Save the boot drive
+
+ /*
+ * Now we must find our way to the first sector of the root directory
+ *
+ * LBA = NumberOfFats * SectorsPerFat + HiddenSectors + ReservedSectors
+ */
+ xor ax, ax
+ xor cx, cx
+ mov al, byte ptr BP_REL(NumberOfFats) // Number of fats
+ mul word ptr BP_REL(SectorsPerFat) // Times sectors per fat
+ add ax, word ptr BP_REL(HiddenSectors)
+ adc dx, word ptr BP_REL(HiddenSectors + 2) // Add the number of hidden sectors
+ add ax, word ptr BP_REL(ReservedSectors) // Add the number of reserved sectors
+ adc dx, cx // Add carry bit
+ mov word ptr [bp - DataAreaStartLow], ax // Save the starting sector of the root
directory
+ mov word ptr [bp - DataAreaStartHigh], dx // Save it in the first 4 bytes before
the boot sector
+ mov si, word ptr BP_REL(MaxRootEntries) // Get number of root dir entries in SI
+ pusha // Save 32-bit logical start sector of
root dir
+ // DX:AX now has the number of the starting sector of the root directory
+
+ /*
+ * Now calculate the size of the root directory
+ *
+ * Root directory sectors = (MaxRootEntries * 32 + BytesPerSector - 1) /
BytesPerSector
+ */
+ xor dx, dx
+ mov ax, 32 // Size of dir entry
+ mul si // Times the number of entries
+ mov bx, word ptr BP_REL(BytesPerSector)
+ add ax, bx
+ dec ax
+ div bx // Divided by the size of a sector
+ // AX now has the number of root directory sectors
+
+ add word ptr [bp - DataAreaStartLow], ax // Add the number of sectors of the root
directory to our other value
+ adc word ptr [bp - DataAreaStartHigh], cx // Now the first 4 bytes before the boot
sector contain the starting sector of the data area
+ popa
+
+/*
+ * Reads root directory into [0000:7E00] and finds 'FREELDR SYS'
+ *
+ * Call with:
+ *
+ * DX:AX - LBA of the starting sector of the root directory
+ */
+LoadRootDirSector:
+ mov bx, HEX(7E0) // We will load the root directory
sector
+ mov es, bx // Right after the boot sector in memory
+ xor bx, bx // We will load it to [0000:7E00]
+ xor cx, cx // Zero out CX
+ inc cx // Now increment it to 1, we are reading
one sector
+ xor di, di // Zero out di
+ push es // Save ES because it will get
incremented by 20h
+ call ReadSectors // Read the first sector of the root
directory
+ pop es // Restore ES (ES:DI = 7E0:0000)
+
+SearchRootDirSector:
+ cmp byte ptr es:[di], ch // If the first byte of the directory
entry is zero then we have
+ jz PrintFileNotFound // reached the end of the directory and
FREELDR.SYS is not here so reboot
+ pusha // Save all registers
+ mov cl, 11 // Put 11 in cl (length of filename in
directory entry)
+ mov si, offset filename // Put offset of filename string in
DS:SI
+ repe cmpsb // Compare this directory entry against
'FREELDR SYS'
+ popa // Restore all the registers
+ jz FoundFreeLoader // If we found it then jump
+ dec si // SI holds MaxRootEntries, subtract one
+ jz PrintFileNotFound // If we are out of root dir entries then
reboot
+ add di, 32 // Increment DI by the size of a
directory entry
+ cmp di, HEX(0200) // Compare DI to 512 (DI has offset to
next dir entry, make sure we haven't gone over one sector)
+ jc SearchRootDirSector // If DI is less than 512 loop again
+ jmp short LoadRootDirSector // Didn't find FREELDR.SYS in this
directory sector, try again
+
+FoundFreeLoader:
+ /*
+ * We found freeldr.sys on the disk
+ * so we need to load the first 512 bytes of it to [0000:F800]
+ * ES:DI has dir entry (ES:DI == 07E0:XXXX)
+ */
+ mov ax, word ptr es:[di + HEX(1A)] // Get start cluster
+ push ax // Save start cluster
+ push FREELDR_BASE / 16 // Put load segment on the stack and load
it
+ pop es // Into ES so that we load the cluster at
[0000:F800]
+ call ReadCluster // Read the cluster
+ pop ax // Restore start cluster of FreeLoader
+
+ /*
+ * Save the addresses of needed functions so
+ * the helper code will know where to call them
+ */
+ mov word ptr [bp - ReadSectorsOffset], offset ReadSectors // Save the address of
ReadSectors
+ mov word ptr [bp - ReadClusterOffset], offset ReadCluster // Save the address of
ReadCluster
+ mov word ptr [bp - PutCharsOffset], offset PrintString // Save the address of
PrintString
+
+ /*
+ * Now AX has start cluster of FreeLoader and we
+ * have loaded the helper code in the first 512 bytes
+ * of FreeLoader to 0000:F800. Now transfer control
+ * to the helper code. Skip the first three bytes
+ * because they contain a jump instruction to skip
+ * over the helper code in the FreeLoader image
+ */
+ ljmp16 0, FREELDR_BASE + 3
+
+/*
+ * Reads cluster number in AX into [ES:BX]
+ *
+ * Call with:
+ *
+ * AX - cluster number
+ * ES:BX - buffer to read data into
+ */
+ReadCluster:
+ /*
+ * StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors +
HiddenSectors
+ */
+ dec ax // Adjust start cluster by 2
+ dec ax // Because the data area starts on
cluster 2
+ xor ch, ch
+ mov cl, byte ptr BP_REL(SectsPerCluster)
+ mul cx // Times sectors per cluster
+ add ax, [bp - DataAreaStartLow] // Add start of data area
+ adc dx, [bp - DataAreaStartHigh] // Now we have DX:AX with the logical
start sector of FREELDR.SYS
+ xor bx, bx // We will load it to [ES:0000], ES
loaded before function call
+
+/*
+ * Reads logical sectors into [ES:BX]
+ *
+ * Call with:
+ *
+ * DX:AX - logical sector number to read (LBA value)
+ * ES:BX - buffer to read data into
+ * CX - number of sectors to read
+ */
+ReadSectors:
+
+ .ReadSectorsLoop:
+ pusha
+
+ /*
+ * Converting LBA (Linear Block Address) into a format CHS
(Cylinder:Head:Sector)
+ *
+ * C = (LBA / SPT) / HPC
+ * H = (LBA / SPT) % HPC
+ * S = (LBA % SPT) + 1
+ */
+ xchg ax, cx
+ xchg ax, dx
+ xor dx, dx
+ div word ptr BP_REL(SectorsPerTrack)
+ xchg ax, cx
+ div word ptr BP_REL(SectorsPerTrack) // Divide logical by SectorsPerTrack
+ inc dx // Sectors numbering starts at 1 not 0
+ xchg cx, dx
+ div word ptr BP_REL(NumberOfHeads) // Number of heads
+
+ mov dh, dl // DH - head number (0-1)
+ mov dl, cl // DL - sector number (1-26)
+ mov cl, al // CL - cylinder number (0-76)
+
+ // TODO: This should be calculated using the equation: BytesPerSector = (CH + 1)
* 128
+ mov ch, 2 // CH - sector size (0-4): 0 (128), 1
(256), 2 (512), 3 (1024), 4 (2048)
+
+ mov al, byte ptr BP_REL(BootDrive) // AL - DA/UA
+ push bp
+ push bx
+ mov bx, word ptr BP_REL(BytesPerSector) // BX - bytes to read
+ pop bp // ES:BP - buffer to read data into
+ mov ah, HEX(56) // AH - read sectors from a floppy disk
with SEEK, and use double-density format (MFM)
+
+ /*
+ * Disk BIOS interrupt
+ * See
http://radioc.web.fc2.com/column/pc98bas/bios/int1b_06.htm
+ */
+ int HEX(1b)
+
+ pop bp
+ jc PrintDiskError // CF set on failure
+
+ popa
+
+ inc ax // Increment sector to read
+ jnz .NoCarryCHS
+ inc dx
+
+ .NoCarryCHS:
+ push bx
+ mov bx, es
+ add bx, HEX(20) // Add size of dir entry to the buffer
address for the next sector
+ mov es, bx
+ pop bx
+ loop .ReadSectorsLoop // Increment read buffer for next sector,
read next sector
+
+ ret
+
+/*
+ * Prints a character
+ *
+ * Call with:
+ *
+ * AL - ASCII code
+ */
+PutChar:
+ push di
+ push es
+
+ push word ptr BP_REL(VramSegment)
+ pop es
+ mov di, word ptr BP_REL(VramOffset) // ES:DI = VramSegment:VramOffset
+ .PutCharWrite:
+ xor ah, ah
+ stosw // Write ASCII directly to the VRAM
+
+ mov word ptr BP_REL(VramOffset), di
+ pop es
+ pop di
+
+ ret
+
+/*
+ * Prints a null-terminated string
+ *
+ * Call with:
+ *
+ * DS:SI - pointer to a string
+ */
+PrintString:
+ xor ah, ah
+ lodsb // Get a single char from a ptr
+
+ or al, al
+ jz short .PrintEnd // Found NULL
+
+ cmp al, HEX(0D)
+ jz short .PrintStringHandleCR // Found CR
+
+ call PutChar
+ jmp short PrintString
+
+ .PrintStringHandleCR:
+ mov ax, word ptr BP_REL(VramOffset)
+ mov dl, VGA_WIDTH * 2
+ div dl
+ inc ax
+ mul dl
+ mov word ptr BP_REL(VramOffset), ax
+ inc si // Skip the next LF character
+ jmp short PrintString
+
+.PrintEnd:
+ ret
+
+if 0
+/*
+ * Displays a hardware error message and reboots
+ */
+HardwareError:
+ mov si, offset msgHardwareError
+
+ .PrintStringVGA:
+ lodsb // Get a single char from a ptr
+
+ or al, al
+ jz short .HardwareErrorDone // Found NULL
+
+ mov ah, HEX(0E) // Teletype output
+ mov bx, 7 // BH - video page number, BL -
foreground color
+ int HEX(10) // Display a character via TTY mode
+ jmp short .PrintStringVGA
+
+.HardwareErrorDone:
+ xor ax, ax
+ int HEX(16) // Wait for a keypress
+ int HEX(19) // Reboot
+endif
+
+/*
+ * Displays a disk error message and reboots
+ */
+PrintDiskError:
+ mov si, offset msgDiskError // Disk error message
+ call PrintString // Display it
+
+ jmp short Reboot
+
+/*
+ * Displays a file not found error message and reboots
+ */
+PrintFileNotFound:
+ mov si, offset msgNotFoundError // FreeLdr not found message
+ call PrintString // Display it
+
+ jmp short Reboot
+
+/*
+ * Reboots the computer after keypress
+ */
+Reboot:
+ mov si, offset msgAnyKey // Press any key message
+ call PrintString // Display it
+
+ xor ax, ax
+ int HEX(18) // Wait for a keypress
+
+ /*
+ * Activate the CPU reset line
+ * See
https://people.freebsd.org/~kato/pc98-arch.html#cpureset
+ * and
http://www.webtech.co.jp/company/doc/undocumented_mem/io_cpu.txt
+ */
+ xor ax, ax
+ out HEX(0F0), al
+
+ hlt
+Halt:
+ jmp short Halt // Spin
+
+VramSegment:
+ .word 0
+VramOffset:
+ .word 0
+msgDiskError:
+ .ascii "ERR", CR, LF, NUL
+msgNotFoundError:
+ .ascii "NFE", CR, LF, NUL
+msgAnyKey:
+ .ascii "Press any key", NUL
+filename:
+ .ascii "FREELDR SYS"
+
+if 0 // So totally out of space here...
+msgHardwareError:
+ .ascii "It's not PC-98", NUL
+endif
+
+ .org 509 // Pad to 509 bytes
+
+BootPartition:
+ .byte 0
+
+BootSignature:
+ .word HEX(0AA55) // BootSector signature
+
+.endcode16
+
+END
diff --git a/boot/freeldr/freeldr/CMakeLists.txt b/boot/freeldr/freeldr/CMakeLists.txt
index 37f44004ef8..784febe1f43 100644
--- a/boot/freeldr/freeldr/CMakeLists.txt
+++ b/boot/freeldr/freeldr/CMakeLists.txt
@@ -292,6 +292,14 @@ endif()
add_dependencies(freeldr_pe asm)
add_dependencies(freeldr_pe_dbg asm)
+if(SARCH STREQUAL "pc98")
+ file(MAKE_DIRECTORY ${REACTOS_BINARY_DIR}/PC98)
+ add_custom_target(pc98bootfdd
+ COMMAND native-fatten ${REACTOS_BINARY_DIR}/PC98/ReactOS-98.IMG -format 2880
ROS98BOOT -boot ${CMAKE_BINARY_DIR}/boot/freeldr/bootsect/pc98/fat12fdd.bin -add
${CMAKE_CURRENT_BINARY_DIR}/freeldr.sys FREELDR.SYS -add
${CMAKE_SOURCE_DIR}/boot/bootdata/livecd.ini FREELDR.INI
+ DEPENDS native-fatten fat12pc98 freeldr
+ VERBATIM)
+endif()
+
if(NOT ARCH STREQUAL "arm")
concatenate_files(
${CMAKE_CURRENT_BINARY_DIR}/freeldr.sys
diff --git a/sdk/cmake/config.cmake b/sdk/cmake/config.cmake
index d3f596f3168..4c2305479ac 100644
--- a/sdk/cmake/config.cmake
+++ b/sdk/cmake/config.cmake
@@ -1,7 +1,7 @@
set(SARCH "pc" CACHE STRING
"Sub-architecture to build for. Specify one of:
- pc xbox")
+ pc pc98 xbox")
set(OARCH "pentium" CACHE STRING
"Generate instructions for this CPU type. Specify one of: