https://git.reactos.org/?p=reactos.git;a=commitdiff;h=065afd93fd35cb8a9717d901649bee97d71d1a35

commit 065afd93fd35cb8a9717d901649bee97d71d1a35
Author:     Dmitry Borisov <[email protected]>
AuthorDate: Sun Jan 19 00:16:23 2020 +0600
Commit:     Hermès BÉLUSCA - MAÏTO <[email protected]>
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 ([email protected])
+ */
+
+#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:

Reply via email to