mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 17:44:45 +00:00
[FREELDR] Add ARC-emulation support for NEC PC-98 series
- Add ARC-emulation support for NEC PC-98 series - Add global definition for PC-98 port into CMakeLists.txt - Add floppy verison of freeldr.ini for PC-98 CD boot
This commit is contained in:
parent
9ccd179e4a
commit
c14cc22bfd
22 changed files with 3853 additions and 29 deletions
|
@ -161,6 +161,8 @@ else()
|
|||
add_definitions(-D_X86_ -D__i386__ -Di386)
|
||||
if(SARCH STREQUAL "xbox")
|
||||
add_definitions(-DSARCH_XBOX)
|
||||
elseif(SARCH STREQUAL "pc98")
|
||||
add_definitions(-DSARCH_PC98)
|
||||
endif()
|
||||
elseif(ARCH STREQUAL "amd64")
|
||||
add_definitions(-D_M_AMD64 -D_AMD64_ -D__x86_64__ -D_WIN64)
|
||||
|
|
56
boot/bootdata/floppy_pc98.ini
Normal file
56
boot/bootdata/floppy_pc98.ini
Normal file
|
@ -0,0 +1,56 @@
|
|||
[FREELOADER]
|
||||
DefaultOS=LiveCD_Debug
|
||||
TimeOut=5
|
||||
|
||||
[Display]
|
||||
TitleText=ReactOS CD boot
|
||||
StatusBarColor=Cyan
|
||||
StatusBarTextColor=Black
|
||||
BackdropTextColor=White
|
||||
BackdropColor=Blue
|
||||
BackdropFillStyle=Medium
|
||||
TitleBoxTextColor=White
|
||||
TitleBoxColor=Red
|
||||
MessageBoxTextColor=White
|
||||
MessageBoxColor=Blue
|
||||
MenuTextColor=Gray
|
||||
MenuColor=Black
|
||||
TextColor=Gray
|
||||
SelectedTextColor=Black
|
||||
SelectedColor=Gray
|
||||
ShowTime=No
|
||||
MenuBox=No
|
||||
CenterMenu=No
|
||||
MinimalUI=Yes
|
||||
TimeText=Seconds until highlighted choice will be started automatically:
|
||||
|
||||
[Operating Systems]
|
||||
LiveCD="LiveCD"
|
||||
LiveCD_Debug="LiveCD (Debug)"
|
||||
LiveCD_Screen="LiveCD (Screen)"
|
||||
LiveCD_LogFile="LiveCD (Log file)"
|
||||
Setup="Setup"
|
||||
|
||||
[LiveCD]
|
||||
BootType=Windows2003
|
||||
SystemPath=multi(0)disk(0)cdrom(0)\reactos
|
||||
Options=/MININT
|
||||
|
||||
[LiveCD_Debug]
|
||||
BootType=Windows2003
|
||||
SystemPath=multi(0)disk(0)cdrom(0)\reactos
|
||||
Options=/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS /MININT
|
||||
|
||||
[LiveCD_Screen]
|
||||
BootType=Windows2003
|
||||
SystemPath=multi(0)disk(0)cdrom(0)\reactos
|
||||
Options=/DEBUG /DEBUGPORT=SCREEN /SOS /MININT
|
||||
|
||||
[LiveCD_LogFile]
|
||||
BootType=Windows2003
|
||||
SystemPath=multi(0)disk(0)cdrom(0)\reactos
|
||||
Options=/DEBUG /DEBUGPORT=FILE:\Device\HarddiskX\PartitionY\debug.log /SOS /MININT
|
||||
|
||||
[Setup]
|
||||
BootType=ReactOSSetup
|
||||
SystemPath=multi(0)disk(0)cdrom(0)\reactos
|
|
@ -139,6 +139,18 @@ if(ARCH STREQUAL "i386")
|
|||
arch/i386/xbox/xboxmem.c
|
||||
arch/i386/xbox/xboxrtc.c
|
||||
arch/i386/xbox/xboxvideo.c)
|
||||
elseif(SARCH STREQUAL "pc98")
|
||||
list(APPEND FREELDR_ARC_SOURCE
|
||||
arch/i386/pc/pcmem.c
|
||||
arch/i386/pc98/machpc98.c
|
||||
arch/i386/pc98/pc98beep.c
|
||||
arch/i386/pc98/pc98cons.c
|
||||
arch/i386/pc98/pc98disk.c
|
||||
arch/i386/pc98/pc98hw.c
|
||||
arch/i386/pc98/pc98mem.c
|
||||
arch/i386/pc98/pc98rtc.c
|
||||
arch/i386/pc98/pc98video.c
|
||||
arch/i386/xbox/xboxfont.c)
|
||||
else()
|
||||
list(APPEND FREELDR_ARC_SOURCE
|
||||
arch/i386/pc/machpc.c
|
||||
|
@ -307,7 +319,7 @@ 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
|
||||
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/floppy_pc98.ini FREELDR.INI
|
||||
DEPENDS native-fatten fat12pc98 freeldr
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
|
|
@ -180,6 +180,11 @@ VOID DriveMapInstallInt13Handler(PDRIVE_MAP_LIST DriveMap)
|
|||
ULONG* RealModeIVT = (ULONG*)UlongToPtr(0x00000000);
|
||||
USHORT* BiosLowMemorySize = (USHORT*)ULongToPtr(0x00000413);
|
||||
|
||||
#if defined(SARCH_PC98)
|
||||
/* FIXME */
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!DriveMapInstalled)
|
||||
{
|
||||
// Get the old INT 13h handler address from the vector table
|
||||
|
@ -218,6 +223,11 @@ VOID DriveMapRemoveInt13Handler(VOID)
|
|||
ULONG* RealModeIVT = (ULONG*)0x00000000;
|
||||
USHORT* BiosLowMemorySize = (USHORT*)0x00000413;
|
||||
|
||||
#if defined(SARCH_PC98)
|
||||
/* FIXME */
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (DriveMapInstalled)
|
||||
{
|
||||
// Get the old INT 13h handler address from the vector table
|
||||
|
|
|
@ -29,12 +29,15 @@ FindApmBios(VOID)
|
|||
REGS RegsIn;
|
||||
REGS RegsOut;
|
||||
|
||||
RegsIn.b.ah = 0x53;
|
||||
RegsIn.b.al = 0x00;
|
||||
#if defined(SARCH_PC98)
|
||||
RegsIn.w.ax = 0x9A00;
|
||||
RegsIn.w.bx = 0x0000;
|
||||
Int386(0x1F, &RegsIn, &RegsOut);
|
||||
#else
|
||||
RegsIn.w.ax = 0x5300;
|
||||
RegsIn.w.bx = 0x0000;
|
||||
|
||||
Int386(0x15, &RegsIn, &RegsOut);
|
||||
|
||||
#endif
|
||||
if (INT386_SUCCESS(RegsOut))
|
||||
{
|
||||
TRACE("Found APM BIOS\n");
|
||||
|
|
162
boot/freeldr/freeldr/arch/i386/pc98/machpc98.c
Normal file
162
boot/freeldr/freeldr/arch/i386/pc98/machpc98.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Hardware-specific routines for NEC PC-98 series
|
||||
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <freeldr.h>
|
||||
|
||||
#include <debug.h>
|
||||
DBG_DEFAULT_CHANNEL(HWDETECT);
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
BOOLEAN HiResoMachine;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID
|
||||
Pc98GetExtendedBIOSData(PULONG ExtendedBIOSDataArea, PULONG ExtendedBIOSDataSize)
|
||||
{
|
||||
*ExtendedBIOSDataArea = HiResoMachine ? MEM_EXTENDED_HIGH_RESO : MEM_EXTENDED_NORMAL;
|
||||
*ExtendedBIOSDataSize = 64;
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98HwIdle(VOID)
|
||||
{
|
||||
/* Unimplemented */
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98PrepareForReactOS(VOID)
|
||||
{
|
||||
Pc98DiskPrepareForReactOS();
|
||||
Pc98VideoPrepareForReactOS();
|
||||
DiskStopFloppyMotor();
|
||||
}
|
||||
|
||||
ULONG
|
||||
Pc98GetBootSectorLoadAddress(IN UCHAR DriveNumber)
|
||||
{
|
||||
PPC98_DISK_DRIVE DiskDrive;
|
||||
|
||||
DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
|
||||
if (!DiskDrive)
|
||||
{
|
||||
ERR("Failed to get drive 0x%x\n", DriveNumber);
|
||||
return 0x1FC00;
|
||||
}
|
||||
|
||||
if (((DiskDrive->DaUa & 0xF0) == 0x30) ||
|
||||
((DiskDrive->DaUa & 0xF0) == 0xB0))
|
||||
{
|
||||
/* 1.44 MB floppy */
|
||||
return 0x1FE00;
|
||||
}
|
||||
else if (DiskDrive->Type & DRIVE_FDD)
|
||||
{
|
||||
return 0x1FC00;
|
||||
}
|
||||
|
||||
return 0x1F800;
|
||||
}
|
||||
|
||||
VOID __cdecl ChainLoadBiosBootSectorCode(
|
||||
IN UCHAR BootDrive OPTIONAL,
|
||||
IN ULONG BootPartition OPTIONAL)
|
||||
{
|
||||
REGS Regs;
|
||||
PPC98_DISK_DRIVE DiskDrive;
|
||||
USHORT LoadAddress;
|
||||
UCHAR DriveNumber = BootDrive ? BootDrive : FrldrBootDrive;
|
||||
|
||||
DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
|
||||
if (!DiskDrive)
|
||||
{
|
||||
ERR("Failed to get drive 0x%x\n", DriveNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
LoadAddress = (USHORT)(Pc98GetBootSectorLoadAddress(DriveNumber) >> 4);
|
||||
|
||||
RtlZeroMemory(&Regs, sizeof(Regs));
|
||||
Regs.w.ax = DiskDrive->DaUa;
|
||||
Regs.w.si = LoadAddress;
|
||||
Regs.w.es = LoadAddress;
|
||||
*(PUCHAR)MEM_DISK_BOOT = DiskDrive->DaUa;
|
||||
|
||||
Pc98VideoClearScreen(ATTR(COLOR_WHITE, COLOR_BLACK));
|
||||
|
||||
Relocator16Boot(&Regs,
|
||||
/* Stack segment:pointer */
|
||||
0x0020, 0x00FF,
|
||||
/* Code segment:pointer */
|
||||
LoadAddress, 0x0000);
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
Pc98ArchTest(VOID)
|
||||
{
|
||||
REGS RegsIn, RegsOut;
|
||||
|
||||
/* Int 1Ah AX=1000h
|
||||
* NEC PC-9800 series - Installation check
|
||||
*/
|
||||
RegsIn.w.ax = 0x1000;
|
||||
Int386(0x1A, &RegsIn, &RegsOut);
|
||||
|
||||
return RegsOut.w.ax != 0x1000;
|
||||
}
|
||||
|
||||
VOID
|
||||
MachInit(const char *CmdLine)
|
||||
{
|
||||
if (!Pc98ArchTest())
|
||||
{
|
||||
_disable();
|
||||
__halt();
|
||||
|
||||
while (TRUE)
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
/* Setup vtbl */
|
||||
RtlZeroMemory(&MachVtbl, sizeof(MACHVTBL));
|
||||
MachVtbl.ConsPutChar = Pc98ConsPutChar;
|
||||
MachVtbl.ConsKbHit = Pc98ConsKbHit;
|
||||
MachVtbl.ConsGetCh = Pc98ConsGetCh;
|
||||
MachVtbl.VideoClearScreen = Pc98VideoClearScreen;
|
||||
MachVtbl.VideoSetDisplayMode = Pc98VideoSetDisplayMode;
|
||||
MachVtbl.VideoGetDisplaySize = Pc98VideoGetDisplaySize;
|
||||
MachVtbl.VideoGetBufferSize = Pc98VideoGetBufferSize;
|
||||
MachVtbl.VideoGetFontsFromFirmware = Pc98VideoGetFontsFromFirmware;
|
||||
MachVtbl.VideoSetTextCursorPosition = Pc98VideoSetTextCursorPosition;
|
||||
MachVtbl.VideoHideShowTextCursor = Pc98VideoHideShowTextCursor;
|
||||
MachVtbl.VideoPutChar = Pc98VideoPutChar;
|
||||
MachVtbl.VideoCopyOffScreenBufferToVRAM = Pc98VideoCopyOffScreenBufferToVRAM;
|
||||
MachVtbl.VideoIsPaletteFixed = Pc98VideoIsPaletteFixed;
|
||||
MachVtbl.VideoSetPaletteColor = Pc98VideoSetPaletteColor;
|
||||
MachVtbl.VideoGetPaletteColor = Pc98VideoGetPaletteColor;
|
||||
MachVtbl.VideoSync = Pc98VideoSync;
|
||||
MachVtbl.Beep = Pc98Beep;
|
||||
MachVtbl.PrepareForReactOS = Pc98PrepareForReactOS;
|
||||
MachVtbl.GetMemoryMap = Pc98MemGetMemoryMap;
|
||||
MachVtbl.GetExtendedBIOSData = Pc98GetExtendedBIOSData;
|
||||
MachVtbl.GetFloppyCount = Pc98GetFloppyCount;
|
||||
MachVtbl.DiskReadLogicalSectors = Pc98DiskReadLogicalSectors;
|
||||
MachVtbl.DiskGetDriveGeometry = Pc98DiskGetDriveGeometry;
|
||||
MachVtbl.DiskGetCacheableBlockCount = Pc98DiskGetCacheableBlockCount;
|
||||
MachVtbl.GetTime = Pc98GetTime;
|
||||
MachVtbl.InitializeBootDevices = Pc98InitializeBootDevices;
|
||||
MachVtbl.HwDetect = Pc98HwDetect;
|
||||
MachVtbl.HwIdle = Pc98HwIdle;
|
||||
|
||||
HiResoMachine = *(PUCHAR)MEM_BIOS_FLAG1 & HIGH_RESOLUTION_FLAG;
|
||||
|
||||
HalpCalibrateStallExecution();
|
||||
Pc98VideoInit();
|
||||
}
|
27
boot/freeldr/freeldr/arch/i386/pc98/pc98beep.c
Normal file
27
boot/freeldr/freeldr/arch/i386/pc98/pc98beep.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Beep routine for NEC PC-98 series
|
||||
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
#include <freeldr.h>
|
||||
|
||||
VOID Pc98Beep(VOID)
|
||||
{
|
||||
REGS Regs;
|
||||
|
||||
/* Int 18h AH=17h
|
||||
* CRT BIOS - Beep on
|
||||
*/
|
||||
Regs.b.ah = 0x17;
|
||||
Int386(0x18, &Regs, &Regs);
|
||||
|
||||
StallExecutionProcessor(100000);
|
||||
|
||||
/* Int 18h AH=18h
|
||||
* CRT BIOS - Beep off
|
||||
*/
|
||||
Regs.b.ah = 0x18;
|
||||
Int386(0x18, &Regs, &Regs);
|
||||
}
|
122
boot/freeldr/freeldr/arch/i386/pc98/pc98cons.c
Normal file
122
boot/freeldr/freeldr/arch/i386/pc98/pc98cons.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Console routines for NEC PC-98 series
|
||||
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <freeldr.h>
|
||||
|
||||
extern ULONG VramText;
|
||||
extern UCHAR TextCols;
|
||||
extern UCHAR TextLines;
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define TEXT_CHAR_SIZE 2
|
||||
|
||||
static USHORT CursorPosition = 0;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID
|
||||
Pc98ConsPutChar(int Ch)
|
||||
{
|
||||
/* If scrolling is needed */
|
||||
if (CursorPosition >= TextCols * TextLines)
|
||||
{
|
||||
RtlCopyMemory((PUSHORT)VramText,
|
||||
(PUSHORT)(VramText + TextCols * TEXT_CHAR_SIZE),
|
||||
TextCols * TextLines * TEXT_CHAR_SIZE);
|
||||
|
||||
CursorPosition -= TextCols;
|
||||
}
|
||||
|
||||
if (Ch == '\n')
|
||||
{
|
||||
if (CursorPosition % TextCols != 0)
|
||||
CursorPosition += TextCols - (CursorPosition % TextCols);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Ch == '\t')
|
||||
{
|
||||
Pc98ConsPutChar(' ');
|
||||
Pc98ConsPutChar(' ');
|
||||
Pc98ConsPutChar(' ');
|
||||
Pc98ConsPutChar(' ');
|
||||
Pc98ConsPutChar(' ');
|
||||
Pc98ConsPutChar(' ');
|
||||
Pc98ConsPutChar(' ');
|
||||
Pc98ConsPutChar(' ');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
*(PUSHORT)(VramText + CursorPosition * TEXT_CHAR_SIZE) = Ch;
|
||||
++CursorPosition;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
Pc98ConsKbHit(VOID)
|
||||
{
|
||||
REGS Regs;
|
||||
|
||||
/* Int 18h AH=01h
|
||||
* KEYBOARD - CHECK FOR KEYSTROKE
|
||||
*
|
||||
* Return:
|
||||
* BH - status
|
||||
* 00h - if no keystroke available
|
||||
* 01h - if keystroke available
|
||||
* AH - BIOS scan code
|
||||
* AL - ASCII character
|
||||
*/
|
||||
Regs.b.ah = 0x01;
|
||||
Int386(0x18, &Regs, &Regs);
|
||||
|
||||
return Regs.b.bh == 1;
|
||||
}
|
||||
|
||||
int
|
||||
Pc98ConsGetCh(VOID)
|
||||
{
|
||||
static BOOLEAN ExtendedKey = FALSE;
|
||||
static UCHAR ExtendedScanCode = 0;
|
||||
REGS Regs;
|
||||
|
||||
/*
|
||||
* If the last time we were called an
|
||||
* extended key was pressed then return
|
||||
* that keys scan code.
|
||||
*/
|
||||
if (ExtendedKey)
|
||||
{
|
||||
ExtendedKey = FALSE;
|
||||
|
||||
return ExtendedScanCode;
|
||||
}
|
||||
|
||||
/* Int 18h AH=00h
|
||||
* KEYBOARD - GET KEYSTROKE
|
||||
*
|
||||
* Return:
|
||||
* AH - BIOS scan code
|
||||
* AL - ASCII character
|
||||
*/
|
||||
Regs.b.ah = 0x00;
|
||||
Int386(0x18, &Regs, &Regs);
|
||||
|
||||
/* Check for an extended keystroke */
|
||||
if (Regs.b.al == 0)
|
||||
{
|
||||
ExtendedKey = TRUE;
|
||||
ExtendedScanCode = Regs.b.ah;
|
||||
}
|
||||
|
||||
/* Return keystroke */
|
||||
return Regs.b.al;
|
||||
}
|
902
boot/freeldr/freeldr/arch/i386/pc98/pc98disk.c
Normal file
902
boot/freeldr/freeldr/arch/i386/pc98/pc98disk.c
Normal file
|
@ -0,0 +1,902 @@
|
|||
/*
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Drive access routines for NEC PC-98 series
|
||||
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <freeldr.h>
|
||||
#include <hwide.h>
|
||||
|
||||
#include <debug.h>
|
||||
DBG_DEFAULT_CHANNEL(DISK);
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
/* Maximum number of disks, indexed from 0x00 to 0xFF */
|
||||
#define MAX_DRIVES 0x100
|
||||
|
||||
/* Cache of all possible PC disk drives */
|
||||
PC98_DISK_DRIVE Pc98DiskDrive[MAX_DRIVES];
|
||||
|
||||
/* DISK IO ERROR SUPPORT ******************************************************/
|
||||
|
||||
static LONG lReportError = 0; /* >= 0: display errors; < 0: hide errors */
|
||||
|
||||
LONG
|
||||
DiskReportError(BOOLEAN bShowError)
|
||||
{
|
||||
/* Set the reference count */
|
||||
if (bShowError)
|
||||
++lReportError;
|
||||
else
|
||||
--lReportError;
|
||||
return lReportError;
|
||||
}
|
||||
|
||||
static PCSTR
|
||||
DiskGetErrorCodeString(ULONG ErrorCode)
|
||||
{
|
||||
switch (ErrorCode & 0xF0)
|
||||
{
|
||||
case 0x00: return "No error";
|
||||
case 0x10: return "Drive write protection error";
|
||||
case 0x20: return "DMA access across 64 kB boundary";
|
||||
case 0x30: return "End of cylinder";
|
||||
case 0x40: return "The drive name is invalid or the device have low health";
|
||||
case 0x50: return "Time out, data not written";
|
||||
case 0x60: return "Time out, drive not ready";
|
||||
case 0x70:
|
||||
if (ErrorCode == 0x78)
|
||||
return "Illegal disk address";
|
||||
else
|
||||
return "Drive write protection error";
|
||||
case 0x80: return "Undefined error";
|
||||
case 0x90: return "Time out error";
|
||||
case 0xA0: return "CRC error in the ID section";
|
||||
case 0xB0: return "CRC error in the DATA section";
|
||||
case 0xC0:
|
||||
if (ErrorCode == 0xC8)
|
||||
return "Seek failure";
|
||||
else
|
||||
return "No data (Sector not found)";
|
||||
case 0xD0: return "Bad cylinder";
|
||||
case 0xE0: return "No ID address mark was found";
|
||||
case 0xF0: return "No DATA address mark was found";
|
||||
|
||||
default: return "Unknown error code";
|
||||
}
|
||||
}
|
||||
|
||||
static VOID
|
||||
DiskError(PCSTR ErrorString, ULONG ErrorCode)
|
||||
{
|
||||
CHAR ErrorCodeString[200];
|
||||
|
||||
if (lReportError < 0)
|
||||
return;
|
||||
|
||||
RtlStringCbPrintfA(ErrorCodeString, sizeof(ErrorCodeString), "%s\n\nError Code: 0x%lx\nError: %s",
|
||||
ErrorString, ErrorCode, DiskGetErrorCodeString(ErrorCode));
|
||||
|
||||
ERR("%s\n", ErrorCodeString);
|
||||
|
||||
UiMessageBox(ErrorCodeString);
|
||||
}
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOLEAN DiskResetController(IN PPC98_DISK_DRIVE DiskDrive)
|
||||
{
|
||||
REGS Regs;
|
||||
|
||||
if (DiskDrive->Type & DRIVE_FDD)
|
||||
{
|
||||
/* Int 1Bh AH=07h
|
||||
* DISK BIOS - Recalibrate
|
||||
*
|
||||
* Call with:
|
||||
* AL - drive number
|
||||
*
|
||||
* Return:
|
||||
* CF - set on error, clear if successful
|
||||
* AH - status
|
||||
*/
|
||||
Regs.b.ah = 0x07;
|
||||
}
|
||||
else if (DiskDrive->Type != (DRIVE_IDE | DRIVE_CDROM))
|
||||
{
|
||||
/* Int 1Bh AH=03h
|
||||
* DISK BIOS - Initialize
|
||||
*
|
||||
* Call with:
|
||||
* AL - drive number
|
||||
*
|
||||
* Return:
|
||||
* CF - set on error, clear if successful
|
||||
* AH - status
|
||||
*/
|
||||
Regs.b.ah = 0x03;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WARN("DiskResetController(0x%x) DISK OPERATION FAILED -- RESETTING CONTROLLER\n", DiskDrive->DaUa);
|
||||
|
||||
Regs.b.al = DiskDrive->DaUa;
|
||||
Int386(0x1B, &Regs, &Regs);
|
||||
return INT386_SUCCESS(Regs);
|
||||
}
|
||||
|
||||
VOID Pc98DiskPrepareForReactOS(VOID)
|
||||
{
|
||||
AtaFree();
|
||||
}
|
||||
|
||||
PPC98_DISK_DRIVE
|
||||
Pc98DiskDriveNumberToDrive(IN UCHAR DriveNumber)
|
||||
{
|
||||
PPC98_DISK_DRIVE DiskDrive;
|
||||
|
||||
ASSERT((0 <= DriveNumber) && (DriveNumber < RTL_NUMBER_OF(Pc98DiskDrive)));
|
||||
|
||||
/* Retrieve a slot */
|
||||
DiskDrive = &Pc98DiskDrive[DriveNumber];
|
||||
|
||||
/* The pre-initialization of the BIOS disks was already done in Pc98InitializeBootDevices() */
|
||||
if (DiskDrive->Initialized)
|
||||
return DiskDrive;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline
|
||||
UCHAR
|
||||
BytesPerSectorToSectorLengthCode(IN ULONG BytesPerSector)
|
||||
{
|
||||
switch (BytesPerSector)
|
||||
{
|
||||
case 128:
|
||||
return 0;
|
||||
case 256:
|
||||
return 1;
|
||||
case 512:
|
||||
return 2;
|
||||
case 1024:
|
||||
return 3;
|
||||
case 2048:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
Pc98DiskReadLogicalSectorsLBA(
|
||||
IN PPC98_DISK_DRIVE DiskDrive,
|
||||
IN ULONGLONG SectorNumber,
|
||||
IN ULONG SectorCount,
|
||||
OUT PVOID Buffer)
|
||||
{
|
||||
REGS RegsIn, RegsOut;
|
||||
ULONG RetryCount;
|
||||
|
||||
if (DiskDrive->Type & DRIVE_IDE && DiskDrive->Type & DRIVE_CDROM)
|
||||
{
|
||||
return AtaAtapiReadLogicalSectorsLBA(AtaGetDevice(DiskDrive->IdeUnitNumber), SectorNumber, SectorCount, Buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Int 1Bh AH=06h
|
||||
* DISK BIOS - Read data
|
||||
*
|
||||
* Call with:
|
||||
* AL - drive number
|
||||
* BX - bytes to read
|
||||
* CX - cylinder number
|
||||
* DH - head number
|
||||
* DL - sector number
|
||||
* ES:BP -> buffer to read data into
|
||||
*
|
||||
* Return:
|
||||
* CF - set on error, clear if successful
|
||||
* AH - status
|
||||
*/
|
||||
RegsIn.b.al = DiskDrive->DaUa;
|
||||
RegsIn.b.ah = 0x06;
|
||||
RegsIn.w.bx = DiskDrive->Geometry.BytesPerSector * SectorCount;
|
||||
RegsIn.w.cx = SectorNumber & 0xFFFF;
|
||||
RegsIn.w.dx = (SectorNumber >> 16) & 0xFFFF;
|
||||
RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
|
||||
RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
|
||||
|
||||
/* Retry 3 times */
|
||||
for (RetryCount = 0; RetryCount < 3; RetryCount++)
|
||||
{
|
||||
Int386(0x1B, &RegsIn, &RegsOut);
|
||||
|
||||
/* If it worked return TRUE */
|
||||
if (INT386_SUCCESS(RegsOut))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
/* If it was a corrected ECC error then the data is still good */
|
||||
else if (RegsOut.b.ah == 0x08)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
/* If it failed the do the next retry */
|
||||
else
|
||||
{
|
||||
DiskResetController(DiskDrive);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we get here then the read failed */
|
||||
DiskError("Disk Read Failed in LBA mode", RegsOut.b.ah);
|
||||
ERR("Disk Read Failed in LBA mode: %x (%s) (DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d)\n",
|
||||
RegsOut.b.ah, DiskGetErrorCodeString(RegsOut.b.ah),
|
||||
DiskDrive->DaUa, SectorNumber, SectorCount);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
Pc98DiskReadLogicalSectorsCHS(
|
||||
IN PPC98_DISK_DRIVE DiskDrive,
|
||||
IN ULONGLONG SectorNumber,
|
||||
IN ULONG SectorCount,
|
||||
OUT PVOID Buffer)
|
||||
{
|
||||
UCHAR PhysicalSector;
|
||||
UCHAR PhysicalHead;
|
||||
ULONG PhysicalTrack;
|
||||
GEOMETRY DriveGeometry;
|
||||
ULONG NumberOfSectorsToRead;
|
||||
REGS RegsIn, RegsOut;
|
||||
ULONG RetryCount;
|
||||
|
||||
DriveGeometry = DiskDrive->Geometry;
|
||||
|
||||
while (SectorCount > 0)
|
||||
{
|
||||
/*
|
||||
* Calculate the physical disk offsets.
|
||||
* Note: DriveGeometry.Sectors < 64
|
||||
*/
|
||||
PhysicalSector = (UCHAR)(SectorNumber % DriveGeometry.Sectors);
|
||||
PhysicalHead = (UCHAR)((SectorNumber / DriveGeometry.Sectors) % DriveGeometry.Heads);
|
||||
PhysicalTrack = (ULONG)((SectorNumber / DriveGeometry.Sectors) / DriveGeometry.Heads);
|
||||
|
||||
/* Floppy sectors value always start at 1 */
|
||||
if (DiskDrive->Type & DRIVE_FDD)
|
||||
++PhysicalSector;
|
||||
|
||||
/* Calculate how many sectors we need to read this round */
|
||||
if (PhysicalSector > 1)
|
||||
{
|
||||
if (SectorCount >= (DriveGeometry.Sectors - (PhysicalSector - 1)))
|
||||
NumberOfSectorsToRead = (DriveGeometry.Sectors - (PhysicalSector - 1));
|
||||
else
|
||||
NumberOfSectorsToRead = SectorCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SectorCount >= DriveGeometry.Sectors)
|
||||
NumberOfSectorsToRead = DriveGeometry.Sectors;
|
||||
else
|
||||
NumberOfSectorsToRead = SectorCount;
|
||||
}
|
||||
|
||||
/* Make sure the read is within the geometry boundaries */
|
||||
if ((PhysicalHead >= DriveGeometry.Heads) ||
|
||||
(PhysicalTrack >= DriveGeometry.Cylinders) ||
|
||||
((NumberOfSectorsToRead + PhysicalSector) > (DriveGeometry.Sectors + 1)) ||
|
||||
(PhysicalSector > DriveGeometry.Sectors))
|
||||
{
|
||||
DiskError("Disk read exceeds drive geometry limits.", 0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (DiskDrive->Type & DRIVE_FDD)
|
||||
{
|
||||
/* Int 1Bh AH=x6h
|
||||
* DISK BIOS - Read data
|
||||
*
|
||||
* Call with:
|
||||
* AL - drive number
|
||||
* BX - bytes to read
|
||||
* CH - sector length code
|
||||
* CL - cylinder number
|
||||
* DH - head number
|
||||
* DL - sector number
|
||||
* ES:BP -> buffer to read data into
|
||||
*
|
||||
* Return:
|
||||
* CF - set on error, clear if successful
|
||||
* AH - status
|
||||
*/
|
||||
RegsIn.b.al = DiskDrive->DaUa;
|
||||
RegsIn.b.ah = 0x56; /* With SEEK, and use double-density format (MFM) */
|
||||
RegsIn.w.bx = DriveGeometry.BytesPerSector * (UCHAR)NumberOfSectorsToRead;
|
||||
RegsIn.b.cl = PhysicalTrack & 0xFFFF;
|
||||
RegsIn.b.ch = BytesPerSectorToSectorLengthCode(DriveGeometry.BytesPerSector);
|
||||
RegsIn.b.dl = PhysicalSector;
|
||||
RegsIn.b.dh = PhysicalHead;
|
||||
RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
|
||||
RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Int 1Bh AH=06h
|
||||
* DISK BIOS - Read data
|
||||
*
|
||||
* Call with:
|
||||
* AL - drive number
|
||||
* BX - bytes to read
|
||||
* CX - cylinder number
|
||||
* DH - head number
|
||||
* DL - sector number
|
||||
* ES:BP -> buffer to read data into
|
||||
*
|
||||
* Return:
|
||||
* CF - set on error, clear if successful
|
||||
* AH - status
|
||||
*/
|
||||
RegsIn.b.al = DiskDrive->DaUa;
|
||||
RegsIn.b.ah = 0x06;
|
||||
RegsIn.w.bx = DriveGeometry.BytesPerSector * (UCHAR)NumberOfSectorsToRead;
|
||||
RegsIn.w.cx = PhysicalTrack & 0xFFFF;
|
||||
RegsIn.b.dl = PhysicalSector;
|
||||
RegsIn.b.dh = PhysicalHead;
|
||||
RegsIn.w.es = (USHORT)(((ULONG_PTR)Buffer) >> 4);
|
||||
RegsIn.w.bp = ((ULONG_PTR)Buffer) & 0x0F;
|
||||
}
|
||||
|
||||
/* Perform the read. Retry 3 times. */
|
||||
for (RetryCount = 0; RetryCount < 3; RetryCount++)
|
||||
{
|
||||
Int386(0x1B, &RegsIn, &RegsOut);
|
||||
|
||||
/* If it worked break out */
|
||||
if (INT386_SUCCESS(RegsOut))
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* If it was a corrected ECC error then the data is still good */
|
||||
else if (RegsOut.b.ah == 0x08)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* If it failed then do the next retry */
|
||||
else
|
||||
{
|
||||
DiskResetController(DiskDrive);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we retried 3 times then fail */
|
||||
if (RetryCount >= 3)
|
||||
{
|
||||
DiskError("Disk Read Failed in CHS mode, after retrying 3 times", RegsOut.b.ah);
|
||||
ERR("Disk Read Failed in CHS mode, after retrying 3 times: %x (%s) (DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d)\n",
|
||||
RegsOut.b.ah, DiskGetErrorCodeString(RegsOut.b.ah),
|
||||
DiskDrive->DaUa, SectorNumber, SectorCount);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Buffer = (PVOID)((ULONG_PTR)Buffer + (NumberOfSectorsToRead * DriveGeometry.BytesPerSector));
|
||||
SectorCount -= NumberOfSectorsToRead;
|
||||
SectorNumber += NumberOfSectorsToRead;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
InitScsiDrive(
|
||||
IN UCHAR DaUa,
|
||||
IN OUT PPC98_DISK_DRIVE DiskDrive)
|
||||
{
|
||||
REGS RegsIn, RegsOut;
|
||||
UCHAR UnitAddress = DaUa & 0x0F;
|
||||
USHORT DiskEquipment = *(PUCHAR)MEM_DISK_EQUIPS;
|
||||
ULONG ScsiParameters = *(PULONG)(MEM_SCSI_TABLE + UnitAddress * sizeof(ULONG));
|
||||
UCHAR DeviceType;
|
||||
|
||||
/* Hard drives */
|
||||
if (DiskEquipment & (1 << UnitAddress))
|
||||
{
|
||||
/* Int 1Bh AH=84h
|
||||
* DISK BIOS - Sense
|
||||
*
|
||||
* Call with:
|
||||
* AL - drive number
|
||||
*
|
||||
* Return:
|
||||
* BX - bytes per sector
|
||||
* CX - cylinders number
|
||||
* DH - heads number
|
||||
* DL - sectors number
|
||||
* CF - set on error, clear if successful
|
||||
* AH - status
|
||||
*/
|
||||
RegsIn.b.al = DaUa;
|
||||
RegsIn.b.ah = 0x84;
|
||||
Int386(0x1B, &RegsIn, &RegsOut);
|
||||
if (!INT386_SUCCESS(RegsOut) || RegsOut.w.cx == 0)
|
||||
{
|
||||
DiskDrive->Initialized = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DiskDrive->Geometry.Cylinders = RegsOut.w.cx;
|
||||
DiskDrive->Geometry.Heads = RegsOut.b.dh;
|
||||
DiskDrive->Geometry.Sectors = RegsOut.b.dl;
|
||||
DiskDrive->Geometry.BytesPerSector = RegsOut.w.bx;
|
||||
DiskDrive->LBASupported = FALSE;
|
||||
DiskDrive->IsRemovable = FALSE;
|
||||
}
|
||||
/* Other devices */
|
||||
else if (ScsiParameters)
|
||||
{
|
||||
DeviceType = ScsiParameters & 0x1F;
|
||||
switch (DeviceType)
|
||||
{
|
||||
case 0x05:
|
||||
/* CD-ROM */
|
||||
DiskDrive->Geometry.Cylinders = 0xFFFF;
|
||||
DiskDrive->Geometry.Heads = 0xFFFF;
|
||||
DiskDrive->Geometry.Sectors = 0xFFFF;
|
||||
DiskDrive->Geometry.BytesPerSector = 2048;
|
||||
DiskDrive->Type = DRIVE_CDROM;
|
||||
DiskDrive->LBASupported = TRUE;
|
||||
DiskDrive->IsRemovable = TRUE;
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
/* Magneto-optical drive */
|
||||
DiskDrive->Geometry.Cylinders = 0xFFFF;
|
||||
DiskDrive->Geometry.Heads = 8;
|
||||
DiskDrive->Geometry.Sectors = 32;
|
||||
DiskDrive->Geometry.BytesPerSector = 512;
|
||||
DiskDrive->Type = DRIVE_MO;
|
||||
DiskDrive->LBASupported = TRUE;
|
||||
DiskDrive->IsRemovable = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
DiskDrive->Initialized = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DiskDrive->Initialized = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DiskDrive->DaUa = DaUa;
|
||||
DiskDrive->Type |= DRIVE_SCSI;
|
||||
DiskDrive->Initialized = TRUE;
|
||||
|
||||
TRACE("InitScsiDrive(0x%x) returned:\n"
|
||||
"Cylinders : 0x%x\n"
|
||||
"Heads : 0x%x\n"
|
||||
"Sects/Track: 0x%x\n"
|
||||
"Bytes/Sect : 0x%x\n",
|
||||
DaUa,
|
||||
DiskDrive->Geometry.Cylinders,
|
||||
DiskDrive->Geometry.Heads,
|
||||
DiskDrive->Geometry.Sectors,
|
||||
DiskDrive->Geometry.BytesPerSector);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
InitIdeDrive(
|
||||
IN UCHAR UnitNumber,
|
||||
IN OUT PPC98_DISK_DRIVE DiskDrive)
|
||||
{
|
||||
PDEVICE_UNIT DeviceUnit = AtaGetDevice(UnitNumber);
|
||||
|
||||
/* We work directly only with ATAPI drives because BIOS has ATA support */
|
||||
if (DeviceUnit && DeviceUnit->Flags & ATA_DEVICE_ATAPI)
|
||||
{
|
||||
DiskDrive->Geometry.Cylinders = DeviceUnit->Cylinders;
|
||||
DiskDrive->Geometry.Heads = DeviceUnit->Heads;
|
||||
DiskDrive->Geometry.Sectors = DeviceUnit->Sectors;
|
||||
DiskDrive->Geometry.BytesPerSector = DeviceUnit->SectorSize;
|
||||
DiskDrive->DaUa = 0xFF;
|
||||
DiskDrive->IdeUnitNumber = UnitNumber;
|
||||
DiskDrive->Type = DRIVE_IDE | DRIVE_CDROM;
|
||||
DiskDrive->LBASupported = TRUE;
|
||||
DiskDrive->IsRemovable = TRUE;
|
||||
DiskDrive->Initialized = TRUE;
|
||||
|
||||
TRACE("InitIdeDrive(0x%x) returned:\n"
|
||||
"Cylinders : 0x%x\n"
|
||||
"Heads : 0x%x\n"
|
||||
"Sects/Track: 0x%x\n"
|
||||
"Bytes/Sect : 0x%x\n",
|
||||
UnitNumber,
|
||||
DiskDrive->Geometry.Cylinders,
|
||||
DiskDrive->Geometry.Heads,
|
||||
DiskDrive->Geometry.Sectors,
|
||||
DiskDrive->Geometry.BytesPerSector);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DiskDrive->Initialized = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
InitHardDrive(
|
||||
IN UCHAR DaUa,
|
||||
IN OUT PPC98_DISK_DRIVE DiskDrive)
|
||||
{
|
||||
REGS RegsIn, RegsOut;
|
||||
|
||||
/* Int 1Bh AH=8Eh
|
||||
* DISK BIOS - Set half-height operation mode
|
||||
*
|
||||
* Call with:
|
||||
* AL - drive number
|
||||
*/
|
||||
RegsIn.b.al = DaUa;
|
||||
RegsIn.b.ah = 0x8E;
|
||||
Int386(0x1B, &RegsIn, &RegsOut);
|
||||
|
||||
/* Int 1Bh AH=84h
|
||||
* DISK BIOS - Sense
|
||||
*
|
||||
* Call with:
|
||||
* AL - drive number
|
||||
*
|
||||
* Return:
|
||||
* BX - bytes per sector
|
||||
* CX - cylinders number
|
||||
* DH - heads number
|
||||
* DL - sectors number
|
||||
* CF - set on error, clear if successful
|
||||
* AH - status
|
||||
*/
|
||||
RegsIn.b.al = DaUa;
|
||||
RegsIn.b.ah = 0x84;
|
||||
Int386(0x1B, &RegsIn, &RegsOut);
|
||||
if (!INT386_SUCCESS(RegsOut) || RegsOut.w.cx == 0)
|
||||
{
|
||||
DiskDrive->Initialized = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DiskDrive->Geometry.Cylinders = RegsOut.w.cx;
|
||||
DiskDrive->Geometry.Heads = RegsOut.b.dh;
|
||||
DiskDrive->Geometry.Sectors = RegsOut.b.dl;
|
||||
DiskDrive->Geometry.BytesPerSector = RegsOut.w.bx;
|
||||
DiskDrive->DaUa = DaUa;
|
||||
DiskDrive->Type = DRIVE_IDE;
|
||||
DiskDrive->LBASupported = FALSE;
|
||||
DiskDrive->IsRemovable = FALSE;
|
||||
DiskDrive->Initialized = TRUE;
|
||||
|
||||
TRACE("InitHardDrive(0x%x) returned:\n"
|
||||
"Cylinders : 0x%x\n"
|
||||
"Heads : 0x%x\n"
|
||||
"Sects/Track: 0x%x\n"
|
||||
"Bytes/Sect : 0x%x\n",
|
||||
DaUa,
|
||||
DiskDrive->Geometry.Cylinders,
|
||||
DiskDrive->Geometry.Heads,
|
||||
DiskDrive->Geometry.Sectors,
|
||||
DiskDrive->Geometry.BytesPerSector);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
InitFloppyDrive(
|
||||
IN UCHAR DaUa,
|
||||
IN OUT PPC98_DISK_DRIVE DiskDrive)
|
||||
{
|
||||
REGS RegsIn, RegsOut;
|
||||
USHORT BytesPerSector;
|
||||
UCHAR DeviceAddress = DaUa & 0xF0;
|
||||
|
||||
/* There's no way to obtain floppy disk geometry in BIOS */
|
||||
|
||||
/* Int 1Bh AH=4Ah
|
||||
* DISK BIOS - Read ID
|
||||
*
|
||||
* Call with:
|
||||
* AL - drive number
|
||||
*
|
||||
* Return:
|
||||
* CH - sector size
|
||||
* CL - cylinder
|
||||
* DH - head
|
||||
* DL - sector
|
||||
* CF - set on error, clear if successful
|
||||
* AH - status
|
||||
*/
|
||||
RegsIn.b.ah = 0x4A;
|
||||
RegsIn.b.al = DaUa;
|
||||
Int386(0x1B, &RegsIn, &RegsOut);
|
||||
if (!INT386_SUCCESS(RegsOut))
|
||||
{
|
||||
DiskDrive->Initialized = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BytesPerSector = 128 << RegsOut.b.ch;
|
||||
switch (BytesPerSector)
|
||||
{
|
||||
case 256:
|
||||
if (DeviceAddress == 0x50)
|
||||
{
|
||||
/* 320 kB 2DD */
|
||||
DiskDrive->Geometry.Cylinders = 80;
|
||||
DiskDrive->Geometry.Heads = 2;
|
||||
DiskDrive->Geometry.Sectors = 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 1 MB 2HD */
|
||||
DiskDrive->Geometry.Cylinders = 77;
|
||||
DiskDrive->Geometry.Heads = 2;
|
||||
DiskDrive->Geometry.Sectors = 26;
|
||||
}
|
||||
break;
|
||||
|
||||
case 512:
|
||||
if (DeviceAddress == 0x30 || DeviceAddress == 0xB0)
|
||||
{
|
||||
/* 1.44 MB 2HD */
|
||||
DiskDrive->Geometry.Cylinders = 80;
|
||||
DiskDrive->Geometry.Heads = 2;
|
||||
DiskDrive->Geometry.Sectors = 18;
|
||||
}
|
||||
else if (DeviceAddress == 0x70 || DeviceAddress == 0xF0)
|
||||
{
|
||||
/* 720/640 kB 2DD */
|
||||
DiskDrive->Geometry.Cylinders = 80;
|
||||
DiskDrive->Geometry.Heads = 2;
|
||||
DiskDrive->Geometry.Sectors = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 1.2 MB 2HC */
|
||||
DiskDrive->Geometry.Cylinders = 80;
|
||||
DiskDrive->Geometry.Heads = 2;
|
||||
DiskDrive->Geometry.Sectors = 15;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1024:
|
||||
/* 1.25 MB 2HD */
|
||||
DiskDrive->Geometry.Cylinders = 77;
|
||||
DiskDrive->Geometry.Heads = 2;
|
||||
DiskDrive->Geometry.Sectors = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
DiskDrive->Initialized = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DiskDrive->Geometry.BytesPerSector = BytesPerSector;
|
||||
DiskDrive->DaUa = DaUa;
|
||||
DiskDrive->Type = DRIVE_FDD;
|
||||
DiskDrive->LBASupported = FALSE;
|
||||
DiskDrive->IsRemovable = TRUE;
|
||||
DiskDrive->Initialized = TRUE;
|
||||
|
||||
TRACE("InitFloppyDrive(0x%x) returned:\n"
|
||||
"Cylinders : 0x%x\n"
|
||||
"Heads : 0x%x\n"
|
||||
"Sects/Track: 0x%x\n"
|
||||
"Bytes/Sect : 0x%x\n",
|
||||
DaUa,
|
||||
DiskDrive->Geometry.Cylinders,
|
||||
DiskDrive->Geometry.Heads,
|
||||
DiskDrive->Geometry.Sectors,
|
||||
DiskDrive->Geometry.BytesPerSector);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* We emulate PC BIOS drive numbers here */
|
||||
BOOLEAN
|
||||
Pc98InitializeBootDevices(VOID)
|
||||
{
|
||||
PPC98_DISK_DRIVE DiskDrive;
|
||||
UCHAR FakeFloppyDriveNumber = 0x30;
|
||||
UCHAR FakeHardDriveDriveNumber = 0x80;
|
||||
UCHAR FakeCdRomDriveNumber = 0xE0;
|
||||
USHORT DiskEquipment = *(PUSHORT)MEM_DISK_EQUIP & ~(*(PUCHAR)MEM_RDISK_EQUIP);
|
||||
UCHAR IdeDetectedCount;
|
||||
UCHAR i;
|
||||
|
||||
TRACE("Pc98InitializeBootDevices()\n");
|
||||
|
||||
RtlZeroMemory(&Pc98DiskDrive, sizeof(Pc98DiskDrive));
|
||||
|
||||
/*
|
||||
* Map DA/UA to drive number, i.e.
|
||||
* 0x90 -> 0x30
|
||||
* 0x80 -> 0x80
|
||||
* 0xA0 -> 0x81, etc.
|
||||
*/
|
||||
|
||||
/* Map floppies */
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
DiskDrive = &Pc98DiskDrive[FakeFloppyDriveNumber];
|
||||
if (FIRSTBYTE(DiskEquipment) & (1 << i))
|
||||
{
|
||||
if (InitFloppyDrive(0x30 + i, DiskDrive) || InitFloppyDrive(0xB0 + i, DiskDrive) ||
|
||||
InitFloppyDrive(0x90 + i, DiskDrive) || InitFloppyDrive(0x10 + i, DiskDrive))
|
||||
++FakeFloppyDriveNumber;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
DiskDrive = &Pc98DiskDrive[FakeFloppyDriveNumber];
|
||||
if (FIRSTBYTE(DiskEquipment) & (16 << i))
|
||||
{
|
||||
if (InitFloppyDrive(0x50 + i, DiskDrive))
|
||||
++FakeFloppyDriveNumber;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
DiskDrive = &Pc98DiskDrive[FakeFloppyDriveNumber];
|
||||
if (SECONDBYTE(DiskEquipment) & (16 << i))
|
||||
{
|
||||
if (InitFloppyDrive(0x70 + i, DiskDrive) || InitFloppyDrive(0xF0 + i, DiskDrive))
|
||||
++FakeFloppyDriveNumber;
|
||||
}
|
||||
}
|
||||
|
||||
/* Map IDE/SASI drives */
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
DiskDrive = &Pc98DiskDrive[FakeHardDriveDriveNumber];
|
||||
if (InitHardDrive(0x80 + i, DiskDrive) || InitHardDrive(0x00 + i, DiskDrive))
|
||||
++FakeHardDriveDriveNumber;
|
||||
}
|
||||
|
||||
AtaInit(&IdeDetectedCount);
|
||||
for (i = 0; i <= IdeDetectedCount; i++)
|
||||
{
|
||||
DiskDrive = &Pc98DiskDrive[FakeCdRomDriveNumber];
|
||||
if (InitIdeDrive(i, DiskDrive))
|
||||
++FakeCdRomDriveNumber;
|
||||
}
|
||||
|
||||
/* Map SCSI drives */
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
DiskDrive = &Pc98DiskDrive[FakeHardDriveDriveNumber];
|
||||
if (InitScsiDrive(0xA0 + i, DiskDrive) || InitScsiDrive(0x20 + i, DiskDrive))
|
||||
{
|
||||
if (DiskDrive->Type & DRIVE_CDROM || DiskDrive->Type & DRIVE_MO)
|
||||
{
|
||||
/* Move to CD-ROM area */
|
||||
Pc98DiskDrive[FakeCdRomDriveNumber] = *DiskDrive;
|
||||
RtlZeroMemory(DiskDrive, sizeof(PC98_DISK_DRIVE));
|
||||
++FakeCdRomDriveNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
++FakeHardDriveDriveNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
// Ugly HACK: Force ISO boot
|
||||
// FIXME: Fill ARC disk blocks completely
|
||||
// to allow usage of CD-ROM root path (See floppy_pc98.ini).
|
||||
FrldrBootDrive = 0xE0;
|
||||
FrldrBootPartition = 0xFF;
|
||||
#else
|
||||
/* Reassign boot drive */
|
||||
for (i = 0; i < MAX_DRIVES - 1; i++)
|
||||
{
|
||||
DiskDrive = &Pc98DiskDrive[i];
|
||||
if (DiskDrive->Initialized && DiskDrive->DaUa == FrldrBootDrive)
|
||||
{
|
||||
TRACE("Boot drive: old 0x%x, new 0x%x\n", FrldrBootDrive, i);
|
||||
FrldrBootDrive = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Call PC version */
|
||||
return PcInitializeBootDevices();
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
Pc98DiskReadLogicalSectors(
|
||||
IN UCHAR DriveNumber,
|
||||
IN ULONGLONG SectorNumber,
|
||||
IN ULONG SectorCount,
|
||||
OUT PVOID Buffer)
|
||||
{
|
||||
PPC98_DISK_DRIVE DiskDrive;
|
||||
|
||||
TRACE("Pc98DiskReadLogicalSectors() DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d Buffer: 0x%x\n",
|
||||
DriveNumber, SectorNumber, SectorCount, Buffer);
|
||||
|
||||
/* 16-bit BIOS addressing limitation */
|
||||
ASSERT(((ULONG_PTR)Buffer) <= 0xFFFFF);
|
||||
|
||||
DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
|
||||
if (!DiskDrive)
|
||||
return FALSE;
|
||||
|
||||
if (DiskDrive->LBASupported)
|
||||
{
|
||||
/* LBA is easy, nothing to calculate. Just do the read. */
|
||||
TRACE("--> Using LBA\n");
|
||||
return Pc98DiskReadLogicalSectorsLBA(DiskDrive, SectorNumber, SectorCount, Buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* LBA is not supported, default to CHS */
|
||||
TRACE("--> Using CHS\n");
|
||||
return Pc98DiskReadLogicalSectorsCHS(DiskDrive, SectorNumber, SectorCount, Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
Pc98DiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
|
||||
{
|
||||
PPC98_DISK_DRIVE DiskDrive;
|
||||
|
||||
TRACE("Pc98DiskGetDriveGeometry(0x%x)\n", DriveNumber);
|
||||
|
||||
DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
|
||||
if (!DiskDrive)
|
||||
return FALSE;
|
||||
|
||||
*Geometry = DiskDrive->Geometry;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ULONG
|
||||
Pc98DiskGetCacheableBlockCount(UCHAR DriveNumber)
|
||||
{
|
||||
PPC98_DISK_DRIVE DiskDrive;
|
||||
|
||||
DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
|
||||
if (!DiskDrive)
|
||||
return 1; // Unknown count.
|
||||
|
||||
/*
|
||||
* If LBA is supported then the block size will be 64 sectors (32k).
|
||||
* If not then the block size is the size of one track.
|
||||
*/
|
||||
if (DiskDrive->LBASupported)
|
||||
return 64;
|
||||
else
|
||||
return DiskDrive->Geometry.Sectors;
|
||||
}
|
1292
boot/freeldr/freeldr/arch/i386/pc98/pc98hw.c
Normal file
1292
boot/freeldr/freeldr/arch/i386/pc98/pc98hw.c
Normal file
File diff suppressed because it is too large
Load diff
105
boot/freeldr/freeldr/arch/i386/pc98/pc98mem.c
Normal file
105
boot/freeldr/freeldr/arch/i386/pc98/pc98mem.c
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Hardware-specific creating a memory map routine for NEC PC-98 series
|
||||
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <freeldr.h>
|
||||
|
||||
#include <debug.h>
|
||||
DBG_DEFAULT_CHANNEL(MEMORY);
|
||||
|
||||
/* pcmem.c */
|
||||
extern VOID
|
||||
SetMemory(
|
||||
PFREELDR_MEMORY_DESCRIPTOR MemoryMap,
|
||||
ULONG_PTR BaseAddress,
|
||||
SIZE_T Size,
|
||||
TYPE_OF_MEMORY MemoryType);
|
||||
|
||||
/* pcmem.c */
|
||||
extern VOID
|
||||
ReserveMemory(
|
||||
PFREELDR_MEMORY_DESCRIPTOR MemoryMap,
|
||||
ULONG_PTR BaseAddress,
|
||||
SIZE_T Size,
|
||||
TYPE_OF_MEMORY MemoryType,
|
||||
PCHAR Usage);
|
||||
|
||||
/* pcmem.c */
|
||||
extern ULONG
|
||||
PcMemFinalizeMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap);
|
||||
|
||||
extern BOOLEAN HiResoMachine;
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define KB 1024
|
||||
#define MB (KB * KB)
|
||||
|
||||
static FREELDR_MEMORY_DESCRIPTOR Pc98MemoryMap[MAX_BIOS_DESCRIPTORS + 1];
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
PFREELDR_MEMORY_DESCRIPTOR
|
||||
Pc98MemGetMemoryMap(ULONG *MemoryMapSize)
|
||||
{
|
||||
USHORT ConventionalMemory, ExtendedMemory;
|
||||
ULONG ExtendedMemory16;
|
||||
|
||||
TRACE("Pc98MemGetMemoryMap()\n");
|
||||
|
||||
RtlZeroMemory(&PcBiosMemoryMap, sizeof(BIOS_MEMORY_MAP) * MAX_BIOS_DESCRIPTORS);
|
||||
PcBiosMapCount = 0;
|
||||
|
||||
ConventionalMemory = ((*(PUCHAR)MEM_BIOS_FLAG1 & CONVENTIONAL_MEMORY_SIZE) + 1) * 128;
|
||||
ExtendedMemory = *(PUCHAR)MEM_EXPMMSZ * 128;
|
||||
ExtendedMemory16 = (*(PUCHAR)MEM_EXPMMSZ16M_LOW + (*(PUCHAR)MEM_EXPMMSZ16M_HIGH << 8)) * 1024;
|
||||
|
||||
if (ConventionalMemory > 640 && !HiResoMachine)
|
||||
ConventionalMemory = 640;
|
||||
|
||||
TRACE("Total conventional memory %d kB available.\n", ConventionalMemory);
|
||||
TRACE("Total extended memory %d kB available.\n", ExtendedMemory);
|
||||
TRACE("Total extended high memory %d kB available.\n", ExtendedMemory16);
|
||||
TRACE("Installed physical memory %d kB.\n", ConventionalMemory + ExtendedMemory + ExtendedMemory16);
|
||||
|
||||
/* First, setup allowed ranges */
|
||||
SetMemory(Pc98MemoryMap, 0x0000600, ConventionalMemory * KB, LoaderFree);
|
||||
SetMemory(Pc98MemoryMap, 0x0100000, ExtendedMemory * KB, LoaderFree);
|
||||
SetMemory(Pc98MemoryMap, 0x1000000, ExtendedMemory16 * KB, LoaderFree);
|
||||
|
||||
/* Next, setup some protected ranges */
|
||||
if (HiResoMachine)
|
||||
{
|
||||
SetMemory(Pc98MemoryMap, 0x000000, 1 * KB, LoaderFirmwarePermanent); /* Real mode IVT */
|
||||
SetMemory(Pc98MemoryMap, 0x000400, 512, LoaderFirmwarePermanent); /* Real mode BDA */
|
||||
SetMemory(Pc98MemoryMap, 0x080000, 256 * KB, LoaderFirmwarePermanent);/* Memory Window */
|
||||
SetMemory(Pc98MemoryMap, 0x0C0000, 128 * KB, LoaderFirmwarePermanent);/* VRAM */
|
||||
SetMemory(Pc98MemoryMap, 0x0E0000, 16 * KB, LoaderFirmwarePermanent); /* Text VRAM */
|
||||
SetMemory(Pc98MemoryMap, 0x0E4000, 4 * KB, LoaderFirmwarePermanent); /* CG Window */
|
||||
SetMemory(Pc98MemoryMap, 0x0E5000, 103 * KB, LoaderSpecialMemory); /* BIOS ROM */
|
||||
SetMemory(Pc98MemoryMap, 0xF00000, 640 * KB, LoaderSpecialMemory); /* Reserved */
|
||||
}
|
||||
else
|
||||
{
|
||||
SetMemory(Pc98MemoryMap, 0x000000, 1 * KB, LoaderFirmwarePermanent); /* Real mode IVT */
|
||||
SetMemory(Pc98MemoryMap, 0x000400, 512, LoaderFirmwarePermanent); /* Real mode BDA */
|
||||
SetMemory(Pc98MemoryMap, 0x000600 + ConventionalMemory * KB,
|
||||
(640 - ConventionalMemory) * KB, LoaderSpecialMemory); /* External bus */
|
||||
SetMemory(Pc98MemoryMap, 0x0A0000, 16 * KB, LoaderFirmwarePermanent); /* Text VRAM */
|
||||
SetMemory(Pc98MemoryMap, 0x0A4000, 4 * KB, LoaderFirmwarePermanent); /* CG Window */
|
||||
SetMemory(Pc98MemoryMap, 0x0A5000, 12 * KB, LoaderFirmwarePermanent); /* Reserved */
|
||||
SetMemory(Pc98MemoryMap, 0x0A8000, 96 * KB, LoaderFirmwarePermanent); /* VRAM (Plane B, R, G) */
|
||||
SetMemory(Pc98MemoryMap, 0x0C0000, 128 * KB, LoaderSpecialMemory); /* BIOS ROM (Peripherals) */
|
||||
SetMemory(Pc98MemoryMap, 0x0E0000, 32 * KB, LoaderFirmwarePermanent); /* VRAM (Plane I) */
|
||||
SetMemory(Pc98MemoryMap, 0x0E8000, 96 * KB, LoaderSpecialMemory); /* BIOS ROM */
|
||||
SetMemory(Pc98MemoryMap, 0xF00000, 640 * KB, LoaderSpecialMemory); /* Reserved */
|
||||
}
|
||||
|
||||
*MemoryMapSize = PcMemFinalizeMemoryMap(Pc98MemoryMap);
|
||||
return Pc98MemoryMap;
|
||||
}
|
42
boot/freeldr/freeldr/arch/i386/pc98/pc98rtc.c
Normal file
42
boot/freeldr/freeldr/arch/i386/pc98/pc98rtc.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Real-time clock access routine for NEC PC-98 series
|
||||
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
#include <freeldr.h>
|
||||
|
||||
#define BCD_INT(bcd) (((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F))
|
||||
|
||||
TIMEINFO*
|
||||
Pc98GetTime(VOID)
|
||||
{
|
||||
static TIMEINFO TimeInfo;
|
||||
REGS Regs;
|
||||
UCHAR SysTime[6];
|
||||
|
||||
/* Int 1Ch AH=00h
|
||||
* TIMER BIOS - Read system time
|
||||
*
|
||||
* Call with:
|
||||
* ES:BX -> data buffer
|
||||
*/
|
||||
Regs.b.ah = 0x00;
|
||||
Regs.w.es = ((ULONG_PTR)SysTime) >> 4;
|
||||
Regs.w.bx = ((ULONG_PTR)SysTime) & 0x0F;
|
||||
Int386(0x1C, &Regs, &Regs);
|
||||
|
||||
TimeInfo.Year = BCD_INT(SysTime[0]);
|
||||
TimeInfo.Month = BCD_INT(SysTime[1] >> 4);
|
||||
TimeInfo.Day = BCD_INT(SysTime[2]);
|
||||
TimeInfo.Hour = BCD_INT(SysTime[3]);
|
||||
TimeInfo.Minute = BCD_INT(SysTime[4]);
|
||||
TimeInfo.Second = BCD_INT(SysTime[5]);
|
||||
if (TimeInfo.Year >= 80)
|
||||
TimeInfo.Year += 1900;
|
||||
else
|
||||
TimeInfo.Year += 2000;
|
||||
|
||||
return &TimeInfo;
|
||||
}
|
339
boot/freeldr/freeldr/arch/i386/pc98/pc98video.c
Normal file
339
boot/freeldr/freeldr/arch/i386/pc98/pc98video.c
Normal file
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Video support for NEC PC-98 series
|
||||
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <freeldr.h>
|
||||
#include <drivers/pc98/video.h>
|
||||
|
||||
extern UCHAR XboxFont8x16[];
|
||||
extern BOOLEAN HiResoMachine;
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define VGA_CHAR_SIZE 2
|
||||
|
||||
#define TEXT_CHAR_SIZE 2
|
||||
UCHAR TextCols;
|
||||
UCHAR TextLines;
|
||||
|
||||
#define CHAR_WIDTH 8
|
||||
#define CHAR_HEIGHT 16
|
||||
|
||||
#define SCREEN_WIDTH 640
|
||||
#define SCREEN_HEIGHT 400
|
||||
#define BYTES_PER_SCANLINE (SCREEN_WIDTH / 8)
|
||||
|
||||
ULONG VramText;
|
||||
static ULONG VramPlaneB;
|
||||
static ULONG VramPlaneG;
|
||||
static ULONG VramPlaneR;
|
||||
static ULONG VramPlaneI;
|
||||
|
||||
static const PALETTE_ENTRY CgaPalette[] =
|
||||
{
|
||||
{0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x0A},
|
||||
{0x00, 0x0A, 0x00},
|
||||
{0x00, 0x0A, 0x0A},
|
||||
{0x0A, 0x00, 0x00},
|
||||
{0x0A, 0x00, 0x0A},
|
||||
{0x0A, 0x05, 0x00},
|
||||
{0x0A, 0x0A, 0x0A},
|
||||
{0x05, 0x05, 0x05},
|
||||
{0x05, 0x05, 0x0F},
|
||||
{0x05, 0x0F, 0x05},
|
||||
{0x05, 0x0F, 0x0F},
|
||||
{0x0F, 0x05, 0x05},
|
||||
{0x0F, 0x05, 0x0F},
|
||||
{0x0F, 0x0F, 0x05},
|
||||
{0x0F, 0x0F, 0x0F}
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID
|
||||
Pc98VideoInit(VOID)
|
||||
{
|
||||
REGS Regs;
|
||||
USHORT i;
|
||||
|
||||
if (HiResoMachine)
|
||||
{
|
||||
VramPlaneB = VRAM_HI_RESO_PLANE_B;
|
||||
VramPlaneG = VRAM_HI_RESO_PLANE_G;
|
||||
VramPlaneR = VRAM_HI_RESO_PLANE_R;
|
||||
VramPlaneI = VRAM_HI_RESO_PLANE_I;
|
||||
VramText = VRAM_HI_RESO_TEXT;
|
||||
TextCols = 80;
|
||||
TextLines = 31;
|
||||
}
|
||||
else
|
||||
{
|
||||
VramPlaneB = VRAM_NORMAL_PLANE_B;
|
||||
VramPlaneG = VRAM_NORMAL_PLANE_G;
|
||||
VramPlaneR = VRAM_NORMAL_PLANE_R;
|
||||
VramPlaneI = VRAM_NORMAL_PLANE_I;
|
||||
VramText = VRAM_NORMAL_TEXT;
|
||||
TextCols = 80;
|
||||
TextLines = 25;
|
||||
}
|
||||
|
||||
for (i = 0; i < VRAM_ATTR_SIZE; i += TEXT_CHAR_SIZE)
|
||||
*(PUCHAR)(VramText + VRAM_TEXT_ATTR_OFFSET + i) = GDC_ATTR_WHITE | GDC_ATTR_VISIBLE;
|
||||
|
||||
/* Int 18h AH=41h
|
||||
* CRT BIOS - Stop displaying graphics
|
||||
*/
|
||||
Regs.b.ah = 0x41;
|
||||
Int386(0x18, &Regs, &Regs);
|
||||
|
||||
/* Int 18h AH=42h
|
||||
* CRT BIOS - Set display area
|
||||
*
|
||||
* CH0-CH3 - always zero
|
||||
* CH4 - video page
|
||||
* CH5 - CRT display mode
|
||||
* 0 - color
|
||||
* 1 - monochrome
|
||||
* CH6-CH7 - VRAM area
|
||||
* 01 - Upper-half (16-32 kB), 640x200
|
||||
* 10 - Lower-half (0-16 kB), 640x200
|
||||
* 11 - All (0-32 kB), 640x400
|
||||
*/
|
||||
Regs.b.ah = 0x42;
|
||||
Regs.b.ch = 0xC0;
|
||||
Int386(0x18, &Regs, &Regs); /* 640x400 */
|
||||
|
||||
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_COLORS_16);
|
||||
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_VIDEO_PAGE, 0);
|
||||
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_VIDEO_PAGE_ACCESS, 0);
|
||||
|
||||
Pc98VideoSync();
|
||||
for (i = 0; i < RTL_NUMBER_OF(CgaPalette); i++)
|
||||
Pc98VideoSetPaletteColor(i, CgaPalette[i].Red, CgaPalette[i].Green, CgaPalette[i].Blue);
|
||||
|
||||
/* Int 18h AH=A0h
|
||||
* CRT BIOS - Set text screen mode
|
||||
*
|
||||
* AL0 - text rows
|
||||
* 0 - 25
|
||||
* 1 - 20
|
||||
* AL1 - text cols
|
||||
* 0 - 80
|
||||
* 1 - 40
|
||||
* AL2 - text attribute
|
||||
* 0 - with vertical line
|
||||
* 1 - normal
|
||||
* AL3 - KCG access mode
|
||||
* 0 - code
|
||||
* 1 - bitmap
|
||||
* AL4-AL7 - always zero
|
||||
*
|
||||
* High-resolution machine:
|
||||
* AL4 - text rows, AL3 - KCG access mode
|
||||
*/
|
||||
Regs.b.ah = 0xA0;
|
||||
Regs.b.al = HiResoMachine ? 0x10 : 0x00;
|
||||
Int386(0x18, &Regs, &Regs); /* 80x25(31) */
|
||||
|
||||
/* Int 18h AH=0Ch
|
||||
* CRT BIOS - Start displaying text
|
||||
*/
|
||||
Regs.b.ah = 0x0C;
|
||||
Int386(0x18, &Regs, &Regs);
|
||||
|
||||
/* Int 18h AH=40h
|
||||
* CRT BIOS - Start displaying graphics
|
||||
*/
|
||||
Regs.b.ah = 0x40;
|
||||
Int386(0x18, &Regs, &Regs);
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98VideoClearScreen(UCHAR Attr)
|
||||
{
|
||||
USHORT i;
|
||||
USHORT B = (Attr & 0x10) ? 0xFFFF : 0;
|
||||
USHORT G = (Attr & 0x20) ? 0xFFFF : 0;
|
||||
USHORT R = (Attr & 0x40) ? 0xFFFF : 0;
|
||||
USHORT I = (Attr & 0x80) ? 0xFFFF : 0;
|
||||
|
||||
for (i = 0; i < VRAM_TEXT_SIZE; i += TEXT_CHAR_SIZE)
|
||||
*(PUSHORT)(VramText + i) = ' ';
|
||||
|
||||
for (i = 0; i < BYTES_PER_SCANLINE * SCREEN_HEIGHT; i += sizeof(USHORT))
|
||||
{
|
||||
*(PUSHORT)(VramPlaneB + i) = B;
|
||||
*(PUSHORT)(VramPlaneG + i) = G;
|
||||
*(PUSHORT)(VramPlaneR + i) = R;
|
||||
*(PUSHORT)(VramPlaneI + i) = I;
|
||||
}
|
||||
}
|
||||
|
||||
VIDEODISPLAYMODE
|
||||
Pc98VideoSetDisplayMode(char *DisplayModeName, BOOLEAN Init)
|
||||
{
|
||||
/* Not supported by hardware */
|
||||
return VideoTextMode;
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98VideoGetDisplaySize(PULONG Width, PULONG Height, PULONG Depth)
|
||||
{
|
||||
*Width = SCREEN_WIDTH / CHAR_WIDTH;
|
||||
*Height = SCREEN_HEIGHT / CHAR_HEIGHT;
|
||||
*Depth = 0;
|
||||
}
|
||||
|
||||
ULONG
|
||||
Pc98VideoGetBufferSize(VOID)
|
||||
{
|
||||
return (SCREEN_WIDTH / CHAR_WIDTH) * (SCREEN_HEIGHT / CHAR_HEIGHT) * VGA_CHAR_SIZE;
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98VideoGetFontsFromFirmware(PULONG RomFontPointers)
|
||||
{
|
||||
*RomFontPointers = VramText + 0x4000;
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98VideoSetTextCursorPosition(UCHAR X, UCHAR Y)
|
||||
{
|
||||
CSRWPARAM CursorParameters;
|
||||
|
||||
RtlZeroMemory(&CursorParameters, sizeof(CSRWPARAM));
|
||||
CursorParameters.CursorAdress = X + Y * TextCols;
|
||||
CursorParameters.DotAddress = 0;
|
||||
|
||||
WRITE_PORT_UCHAR((PUCHAR)GDC1_IO_o_COMMAND, GDC_COMMAND_CSRW);
|
||||
WRITE_GDC_CSRW((PUCHAR)GDC1_IO_o_PARAM, &CursorParameters);
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98VideoHideShowTextCursor(BOOLEAN Show)
|
||||
{
|
||||
CSRFORMPARAM CursorParameters;
|
||||
|
||||
RtlZeroMemory(&CursorParameters, sizeof(CSRFORMPARAM));
|
||||
CursorParameters.Show = Show;
|
||||
CursorParameters.Blink = TRUE;
|
||||
CursorParameters.BlinkRate = 12;
|
||||
CursorParameters.LinesPerRow = 16;
|
||||
CursorParameters.StartScanLine = 12;
|
||||
CursorParameters.EndScanLine = 15;
|
||||
|
||||
WRITE_PORT_UCHAR((PUCHAR)GDC1_IO_o_COMMAND, GDC_COMMAND_CSRFORM);
|
||||
WRITE_GDC_CSRFORM((PUCHAR)GDC1_IO_o_PARAM, &CursorParameters);
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98VideoPutChar(int Ch, UCHAR Attr, unsigned X, unsigned Y)
|
||||
{
|
||||
UCHAR Line;
|
||||
UCHAR B = (Attr & 0x10) ? 0xFF : 0;
|
||||
UCHAR G = (Attr & 0x20) ? 0xFF : 0;
|
||||
UCHAR R = (Attr & 0x40) ? 0xFF : 0;
|
||||
UCHAR I = (Attr & 0x80) ? 0xFF : 0;
|
||||
ULONG VramOffset = X + (Y * CHAR_HEIGHT) * BYTES_PER_SCANLINE;
|
||||
PUCHAR FontPtr = XboxFont8x16 + Ch * 16;
|
||||
|
||||
for (Line = 0; Line < CHAR_HEIGHT; Line++)
|
||||
{
|
||||
if (Attr & 0x0F)
|
||||
{
|
||||
*(PUCHAR)(VramPlaneB + VramOffset + Line * BYTES_PER_SCANLINE) = B | ((Attr & 0x01) ? FontPtr[Line] : 0);
|
||||
*(PUCHAR)(VramPlaneG + VramOffset + Line * BYTES_PER_SCANLINE) = G | ((Attr & 0x02) ? FontPtr[Line] : 0);
|
||||
*(PUCHAR)(VramPlaneR + VramOffset + Line * BYTES_PER_SCANLINE) = R | ((Attr & 0x04) ? FontPtr[Line] : 0);
|
||||
*(PUCHAR)(VramPlaneI + VramOffset + Line * BYTES_PER_SCANLINE) = I | ((Attr & 0x08) ? FontPtr[Line] : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
*(PUCHAR)(VramPlaneB + VramOffset + Line * BYTES_PER_SCANLINE) = B & ~FontPtr[Line];
|
||||
*(PUCHAR)(VramPlaneG + VramOffset + Line * BYTES_PER_SCANLINE) = G & ~FontPtr[Line];
|
||||
*(PUCHAR)(VramPlaneR + VramOffset + Line * BYTES_PER_SCANLINE) = R & ~FontPtr[Line];
|
||||
*(PUCHAR)(VramPlaneI + VramOffset + Line * BYTES_PER_SCANLINE) = I & ~FontPtr[Line];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98VideoCopyOffScreenBufferToVRAM(PVOID Buffer)
|
||||
{
|
||||
PUCHAR OffScreenBuffer = (PUCHAR)Buffer;
|
||||
USHORT X, Y;
|
||||
|
||||
for (Y = 0; Y < SCREEN_HEIGHT / CHAR_HEIGHT; Y++)
|
||||
{
|
||||
for (X = 0; X < SCREEN_WIDTH / CHAR_WIDTH; X++)
|
||||
{
|
||||
Pc98VideoPutChar(OffScreenBuffer[0], OffScreenBuffer[1], X, Y);
|
||||
OffScreenBuffer += VGA_CHAR_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
Pc98VideoIsPaletteFixed(VOID)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98VideoSetPaletteColor(UCHAR Color, UCHAR Red, UCHAR Green, UCHAR Blue)
|
||||
{
|
||||
if (Color < 16)
|
||||
{
|
||||
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_PALETTE_INDEX, Color);
|
||||
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_RED, Red);
|
||||
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_GREEN, Green);
|
||||
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_BLUE, Blue);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98VideoGetPaletteColor(UCHAR Color, UCHAR* Red, UCHAR* Green, UCHAR* Blue)
|
||||
{
|
||||
if (Color < 16)
|
||||
{
|
||||
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_PALETTE_INDEX, Color);
|
||||
*Red = READ_PORT_UCHAR((PUCHAR)GDC2_IO_i_RED);
|
||||
*Green = READ_PORT_UCHAR((PUCHAR)GDC2_IO_i_GREEN);
|
||||
*Blue = READ_PORT_UCHAR((PUCHAR)GDC2_IO_i_BLUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
*Red = 0;
|
||||
*Green = 0;
|
||||
*Blue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98VideoSync(VOID)
|
||||
{
|
||||
while (READ_PORT_UCHAR((PUCHAR)GDC2_IO_i_STATUS) & GDC_STATUS_VSYNC)
|
||||
NOTHING;
|
||||
|
||||
while (!(READ_PORT_UCHAR((PUCHAR)GDC2_IO_i_STATUS) & GDC_STATUS_VSYNC))
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
VOID
|
||||
Pc98VideoPrepareForReactOS(VOID)
|
||||
{
|
||||
REGS Regs;
|
||||
|
||||
/* Int 18h AH=41h
|
||||
* CRT BIOS - Stop displaying graphics
|
||||
*/
|
||||
Regs.b.ah = 0x41;
|
||||
Int386(0x18, &Regs, &Regs);
|
||||
|
||||
Pc98VideoHideShowTextCursor(FALSE);
|
||||
}
|
245
boot/freeldr/freeldr/arch/realmode/helpers_pc98.inc
Normal file
245
boot/freeldr/freeldr/arch/realmode/helpers_pc98.inc
Normal file
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Real mode helper code for NEC PC-98 series
|
||||
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enable the A20 address line
|
||||
*/
|
||||
EnableA20:
|
||||
push ax
|
||||
|
||||
/* Unmask A20 line */
|
||||
xor ax, ax
|
||||
out HEX(0F2), al
|
||||
mov al, HEX(02)
|
||||
out HEX(0F6), al
|
||||
|
||||
pop ax
|
||||
ret
|
||||
|
||||
/*
|
||||
* Disable the A20 address line
|
||||
*/
|
||||
DisableA20:
|
||||
push ax
|
||||
|
||||
/* Mask A20 line */
|
||||
mov al, HEX(03)
|
||||
out HEX(0F6), al
|
||||
|
||||
pop ax
|
||||
ret
|
||||
|
||||
/*
|
||||
* Prints a string
|
||||
* SI = pointer to zero terminated string
|
||||
*/
|
||||
writestr:
|
||||
pushfd
|
||||
pushad
|
||||
|
||||
.writestr_loop:
|
||||
lodsb
|
||||
|
||||
/* Null test */
|
||||
or al, al
|
||||
jz short .writestr_end
|
||||
|
||||
/* CR test */
|
||||
cmp al, HEX(0D)
|
||||
jz short .writestr_cr
|
||||
|
||||
call writechr
|
||||
jmp short .writestr_loop
|
||||
|
||||
.writestr_cr:
|
||||
mov ax, word ptr VramOffset
|
||||
mov dl, 80 * 2
|
||||
div dl
|
||||
inc ax
|
||||
mul dl
|
||||
mov word ptr VramOffset, ax
|
||||
|
||||
/* Skip the next LF character */
|
||||
inc si
|
||||
jmp short .writestr_loop
|
||||
|
||||
.writestr_end:
|
||||
popad
|
||||
popfd
|
||||
ret
|
||||
|
||||
/*
|
||||
* writechr
|
||||
* AL = character to output
|
||||
*/
|
||||
writechr:
|
||||
pushf
|
||||
pusha
|
||||
|
||||
/* High-resolution mode check */
|
||||
test byte ptr ds:[HEX(501)], HEX(08)
|
||||
jz .writechr_normal
|
||||
push HEX(0E000)
|
||||
jmp short .writechr_test_done
|
||||
.writechr_normal:
|
||||
push HEX(0A000)
|
||||
|
||||
.writechr_test_done:
|
||||
pop es
|
||||
mov di, word ptr VramOffset
|
||||
xor ah, ah
|
||||
stosw
|
||||
mov word ptr VramOffset, di
|
||||
|
||||
popa
|
||||
popf
|
||||
ret
|
||||
|
||||
VramOffset:
|
||||
.word 0
|
||||
|
||||
/*
|
||||
* Writes a hex number in (AL, AX, EAX) to the console
|
||||
*/
|
||||
writehex2:
|
||||
pushfd
|
||||
pushad
|
||||
shl eax, 24
|
||||
mov cx, 2
|
||||
jmp short writehex_common
|
||||
writehex4:
|
||||
pushfd
|
||||
pushad
|
||||
shl eax, 16
|
||||
mov cx, 4
|
||||
jmp short writehex_common
|
||||
writehex8:
|
||||
pushfd
|
||||
pushad
|
||||
mov cx, 8
|
||||
writehex_common:
|
||||
.loop:
|
||||
rol eax, 4
|
||||
push eax
|
||||
and al, HEX(0F)
|
||||
cmp al, 10
|
||||
jae .high
|
||||
.low:
|
||||
add al, '0'
|
||||
jmp short .ischar
|
||||
.high:
|
||||
add al, 'A'-10
|
||||
.ischar:
|
||||
call writechr
|
||||
pop eax
|
||||
loop .loop
|
||||
popad
|
||||
popfd
|
||||
ret
|
||||
|
||||
/*
|
||||
* Reboots the computer
|
||||
*/
|
||||
Reboot:
|
||||
cli
|
||||
|
||||
/* Disable A20 address line */
|
||||
call DisableA20
|
||||
|
||||
/* Enable SHUT0 */
|
||||
mov al, HEX(0F)
|
||||
out HEX(37), al
|
||||
|
||||
/* Enable SHUT1 */
|
||||
mov al, HEX(0B)
|
||||
out HEX(37), al
|
||||
|
||||
/* Activate the CPU reset line */
|
||||
xor ax, ax
|
||||
out HEX(0F0), al
|
||||
|
||||
.RebootLoop:
|
||||
hlt
|
||||
jmp short .RebootLoop
|
||||
|
||||
/*
|
||||
* Jumps to the bootsector code
|
||||
*/
|
||||
Relocator16Boot:
|
||||
cli
|
||||
|
||||
/* Disable A20 address line */
|
||||
call DisableA20
|
||||
|
||||
/* Stop displaying graphics */
|
||||
mov ax, HEX(4100)
|
||||
int HEX(18)
|
||||
|
||||
/* Cursor off */
|
||||
mov ax, HEX(1200)
|
||||
int HEX(18)
|
||||
|
||||
/* Clear text screen */
|
||||
mov ax, HEX(1600)
|
||||
mov dx, HEX(0E120)
|
||||
int HEX(18)
|
||||
|
||||
/* Start displaying text */
|
||||
mov ax, HEX(0C00)
|
||||
int HEX(18)
|
||||
|
||||
/* Get current EFLAGS and mask CF, ZF and SF */
|
||||
pushf
|
||||
pop cx
|
||||
and cx, not (EFLAGS_CF or EFLAGS_ZF or EFLAGS_SF)
|
||||
|
||||
/* Get flags CF, ZF and SF from the REGS structure */
|
||||
mov ax, word ptr cs:[BSS_RegisterSet + REGS_EFLAGS]
|
||||
and ax, (EFLAGS_CF or EFLAGS_ZF or EFLAGS_SF)
|
||||
|
||||
/* Combine flags and set them */
|
||||
or ax, cx
|
||||
push ax
|
||||
popf
|
||||
|
||||
/* Setup the segment registers */
|
||||
mov ax, word ptr cs:[BSS_RegisterSet + REGS_DS]
|
||||
mov ds, ax
|
||||
mov ax, word ptr cs:[BSS_RegisterSet + REGS_ES]
|
||||
mov es, ax
|
||||
mov ax, word ptr cs:[BSS_RegisterSet + REGS_FS]
|
||||
mov fs, ax
|
||||
mov ax, word ptr cs:[BSS_RegisterSet + REGS_GS]
|
||||
mov gs, ax
|
||||
|
||||
/* Patch the jump address (segment:offset) */
|
||||
mov eax, dword ptr cs:[BSS_RealModeEntry]
|
||||
mov dword ptr cs:[Relocator16Address], eax
|
||||
|
||||
/* Switch the stack (segment:offset) */
|
||||
mov eax, dword ptr cs:[BSS_CallbackReturn]
|
||||
shr eax, 16
|
||||
mov ss, ax
|
||||
mov eax, dword ptr cs:[BSS_CallbackReturn]
|
||||
and eax, HEX(0FFFF)
|
||||
mov esp, eax
|
||||
|
||||
/* Setup the registers */
|
||||
mov eax, dword ptr cs:[BSS_RegisterSet + REGS_EAX]
|
||||
mov ebx, dword ptr cs:[BSS_RegisterSet + REGS_EBX]
|
||||
mov ecx, dword ptr cs:[BSS_RegisterSet + REGS_ECX]
|
||||
mov edx, dword ptr cs:[BSS_RegisterSet + REGS_EDX]
|
||||
mov esi, dword ptr cs:[BSS_RegisterSet + REGS_ESI]
|
||||
mov edi, dword ptr cs:[BSS_RegisterSet + REGS_EDI]
|
||||
mov ebp, dword ptr cs:[BSS_RegisterSet + REGS_EBP]
|
||||
|
||||
/* Jump to the new CS:IP */
|
||||
.byte HEX(0EA) /* ljmp16 segment:offset */
|
||||
Relocator16Address:
|
||||
.word HEX(0000) /* Default offset */
|
||||
.word HEX(1FC0) /* Default segment */
|
||||
nop
|
|
@ -197,7 +197,11 @@ rmode_idtptr:
|
|||
.long 0 /* Base Address */
|
||||
|
||||
#include "int386.inc"
|
||||
#if defined(SARCH_PC98)
|
||||
#include "helpers_pc98.inc"
|
||||
#else
|
||||
#include "helpers.inc"
|
||||
#endif
|
||||
#include "pxe.inc"
|
||||
#include "pnp.inc"
|
||||
|
||||
|
|
|
@ -50,6 +50,12 @@ Int386_set_registers:
|
|||
mov edx, dword ptr cs:[BSS_RegisterSet + REGS_EDX]
|
||||
mov esi, dword ptr cs:[BSS_RegisterSet + REGS_ESI]
|
||||
mov edi, dword ptr cs:[BSS_RegisterSet + REGS_EDI]
|
||||
#if defined(SARCH_PC98)
|
||||
/* Always set EBP register even if its equals zero.
|
||||
* Otherwise the DISK BIOS calls will store garbage data in a output buffer.
|
||||
*/
|
||||
mov ebp, dword ptr cs:[BSS_RegisterSet + REGS_EBP]
|
||||
#endif
|
||||
|
||||
/* Call the interrupt vector */
|
||||
/*int Int386_vector*/
|
||||
|
|
153
boot/freeldr/freeldr/include/arch/i386/machpc98.h
Normal file
153
boot/freeldr/freeldr/include/arch/i386/machpc98.h
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Header file for NEC PC-98 series
|
||||
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __MEMORY_H
|
||||
#include "mm.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* BIOS work area memory
|
||||
*/
|
||||
|
||||
/* Extended RAM between 0x100000 and 0xFFFFFF in 128 kB */
|
||||
#define MEM_EXPMMSZ 0x401
|
||||
|
||||
#define MEM_BIOS_FLAG5 0x458
|
||||
#define NESA_BUS_FLAG 0x80
|
||||
|
||||
#define MEM_SCSI_TABLE 0x460
|
||||
|
||||
/* Bit 3 and bit 6 - keyboard type */
|
||||
#define MEM_KEYB_TYPE 0x481
|
||||
|
||||
/* Status about connected SCSI hard drives */
|
||||
#define MEM_DISK_EQUIPS 0x482
|
||||
|
||||
/* Status about RAM drives */
|
||||
#define MEM_RDISK_EQUIP 0x488
|
||||
|
||||
#define MEM_BIOS_FLAG1 0x501
|
||||
#define CONVENTIONAL_MEMORY_SIZE 0x07 /* In 128 kB */
|
||||
#define HIGH_RESOLUTION_FLAG 0x08
|
||||
#define SYSTEM_CLOCK_8MHZ_FLAG 0x80 /* 0 = PIT runs at 2.4576 MHz, 1 = at 1.9968 MHz */
|
||||
|
||||
/* Status about connected floppies */
|
||||
#define MEM_DISK_EQUIP 0x55C
|
||||
|
||||
/* Device Address/Unit Address (DA/UA) */
|
||||
#define MEM_DISK_BOOT 0x584
|
||||
|
||||
/* Extended RAM after 0x1000000, low part, in 1 MB */
|
||||
#define MEM_EXPMMSZ16M_LOW 0x594
|
||||
|
||||
/* Extended RAM after 0x1000000, high part, in 1 MB */
|
||||
#define MEM_EXPMMSZ16M_HIGH 0x595
|
||||
|
||||
/* Status about connected 1.44 MB floppies */
|
||||
#define MEM_F144_SUPPORT 0x5AE
|
||||
|
||||
#define MEM_EXTENDED_NORMAL 0xF8E80
|
||||
#define MEM_EXTENDED_HIGH_RESO 0xFFE80
|
||||
|
||||
VOID Pc98Beep(VOID);
|
||||
|
||||
VOID Pc98ConsPutChar(int Ch);
|
||||
BOOLEAN Pc98ConsKbHit(VOID);
|
||||
int Pc98ConsGetCh(VOID);
|
||||
|
||||
VOID Pc98VideoInit(VOID);
|
||||
VOID Pc98VideoClearScreen(UCHAR Attr);
|
||||
VIDEODISPLAYMODE Pc98VideoSetDisplayMode(char *DisplayMode, BOOLEAN Init);
|
||||
VOID Pc98VideoGetDisplaySize(PULONG Width, PULONG Height, PULONG Depth);
|
||||
ULONG Pc98VideoGetBufferSize(VOID);
|
||||
VOID Pc98VideoGetFontsFromFirmware(PULONG RomFontPointers);
|
||||
VOID Pc98VideoSetTextCursorPosition(UCHAR X, UCHAR Y);
|
||||
VOID Pc98VideoHideShowTextCursor(BOOLEAN Show);
|
||||
VOID Pc98VideoPutChar(int Ch, UCHAR Attr, unsigned X, unsigned Y);
|
||||
VOID Pc98VideoCopyOffScreenBufferToVRAM(PVOID Buffer);
|
||||
BOOLEAN Pc98VideoIsPaletteFixed(VOID);
|
||||
VOID Pc98VideoSetPaletteColor(UCHAR Color, UCHAR Red, UCHAR Green, UCHAR Blue);
|
||||
VOID Pc98VideoGetPaletteColor(UCHAR Color, UCHAR* Red, UCHAR* Green, UCHAR* Blue);
|
||||
VOID Pc98VideoSync(VOID);
|
||||
VOID Pc98VideoPrepareForReactOS(VOID);
|
||||
|
||||
VOID Pc98PrepareForReactOS(VOID);
|
||||
TIMEINFO* Pc98GetTime(VOID);
|
||||
BOOLEAN Pc98InitializeBootDevices(VOID);
|
||||
PCONFIGURATION_COMPONENT_DATA Pc98HwDetect(VOID);
|
||||
VOID Pc98HwIdle(VOID);
|
||||
|
||||
/* pcmem.c */
|
||||
extern BIOS_MEMORY_MAP PcBiosMemoryMap[];
|
||||
extern ULONG PcBiosMapCount;
|
||||
|
||||
PFREELDR_MEMORY_DESCRIPTOR Pc98MemGetMemoryMap(ULONG *MemoryMapSize);
|
||||
|
||||
/* hwpci.c */
|
||||
BOOLEAN PcFindPciBios(PPCI_REGISTRY_INFO BusData);
|
||||
|
||||
/*
|
||||
* Disk Variables and Functions
|
||||
*/
|
||||
|
||||
typedef struct _PC98_DISK_DRIVE
|
||||
{
|
||||
/* Disk geometry */
|
||||
GEOMETRY Geometry;
|
||||
|
||||
/* BIOS drive number */
|
||||
UCHAR DaUa;
|
||||
|
||||
/* IDE driver drive number */
|
||||
UCHAR IdeUnitNumber;
|
||||
|
||||
/* Drive type flags */
|
||||
UCHAR Type;
|
||||
#define DRIVE_SASI 0x00
|
||||
#define DRIVE_IDE 0x01
|
||||
#define DRIVE_SCSI 0x02
|
||||
#define DRIVE_CDROM 0x04
|
||||
#define DRIVE_FDD 0x08
|
||||
#define DRIVE_MO 0x10
|
||||
#define DRIVE_RAM 0x20
|
||||
|
||||
/* TRUE when LBA access are supported */
|
||||
BOOLEAN LBASupported;
|
||||
|
||||
/*
|
||||
* 'IsRemovable' flag: TRUE when the drive is removable (e.g. floppy, CD-ROM...).
|
||||
* In that case some of the cached information might need to be refreshed regularly.
|
||||
*/
|
||||
BOOLEAN IsRemovable;
|
||||
|
||||
/*
|
||||
* 'Initialized' flag: if TRUE then the drive has been initialized;
|
||||
* if FALSE then the disk isn't detected by BIOS/FreeLoader.
|
||||
*/
|
||||
BOOLEAN Initialized;
|
||||
} PC98_DISK_DRIVE, *PPC98_DISK_DRIVE;
|
||||
|
||||
/* Platform-specific boot drive and partition numbers */
|
||||
extern UCHAR FrldrBootDrive;
|
||||
extern ULONG FrldrBootPartition;
|
||||
|
||||
LONG DiskReportError(BOOLEAN bShowError);
|
||||
BOOLEAN DiskResetController(IN PPC98_DISK_DRIVE DiskDrive);
|
||||
|
||||
BOOLEAN Pc98DiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer);
|
||||
BOOLEAN Pc98DiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY DriveGeometry);
|
||||
ULONG Pc98DiskGetCacheableBlockCount(UCHAR DriveNumber);
|
||||
UCHAR Pc98GetFloppyCount(VOID);
|
||||
PPC98_DISK_DRIVE Pc98DiskDriveNumberToDrive(IN UCHAR DriveNumber);
|
||||
|
||||
ULONG Pc98GetBootSectorLoadAddress(IN UCHAR DriveNumber);
|
||||
VOID Pc98DiskPrepareForReactOS(VOID);
|
||||
|
||||
/* hwdisk.c */
|
||||
BOOLEAN PcInitializeBootDevices(VOID);
|
|
@ -104,16 +104,23 @@
|
|||
#if defined(_M_IX86) || defined(_M_AMD64)
|
||||
#include <arch/pc/hardware.h>
|
||||
#include <arch/pc/pcbios.h>
|
||||
#include <arch/pc/machpc.h>
|
||||
#include <arch/pc/x86common.h>
|
||||
#include <arch/pc/pxe.h>
|
||||
#include <arch/i386/drivemap.h>
|
||||
#endif
|
||||
#if defined(_M_IX86)
|
||||
#include <arch/i386/i386.h>
|
||||
#if defined(SARCH_PC98)
|
||||
#include <arch/i386/machpc98.h>
|
||||
#elif defined(SARCH_XBOX)
|
||||
#include <arch/pc/machpc.h>
|
||||
#include <arch/i386/machxbox.h>
|
||||
#else
|
||||
#include <arch/pc/machpc.h>
|
||||
#endif
|
||||
#include <arch/i386/i386.h>
|
||||
#include <internal/i386/intrin_i.h>
|
||||
#elif defined(_M_AMD64)
|
||||
#include <arch/pc/machpc.h>
|
||||
#include <arch/amd64/amd64.h>
|
||||
#include <internal/amd64/intrin_i.h>
|
||||
#elif defined(_M_PPC)
|
||||
|
|
|
@ -1,25 +1,40 @@
|
|||
/*
|
||||
* FreeLoader
|
||||
* Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Key codes header file
|
||||
* COPYRIGHT: Copyright 1998-2003 Brian Palmer (brianp@reactos.org)
|
||||
* Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Key codes
|
||||
#if defined(SARCH_PC98)
|
||||
#define KEY_EXTENDED 0x00
|
||||
#define KEY_ENTER 0x0D
|
||||
#define KEY_BACKSPACE 0x08
|
||||
#define KEY_DELETE 0x39
|
||||
#define KEY_SPACE 0x20
|
||||
#define KEY_LEFTSHIFT 0x70
|
||||
#define KEY_HOME 0x3E
|
||||
#define KEY_UP 0x3A
|
||||
#define KEY_DOWN 0x3D
|
||||
#define KEY_LEFT 0x3B
|
||||
#define KEY_RIGHT 0x3C
|
||||
#define KEY_ESC 0x1B
|
||||
#define KEY_CAPS_LOCK 0x71
|
||||
#define KEY_F1 0x62
|
||||
#define KEY_F2 0x63
|
||||
#define KEY_F3 0x64
|
||||
#define KEY_F4 0x65
|
||||
#define KEY_F5 0x66
|
||||
#define KEY_F6 0x67
|
||||
#define KEY_F7 0x68
|
||||
#define KEY_F8 0x69
|
||||
#define KEY_F9 0x6A
|
||||
#define KEY_F10 0x6B
|
||||
#define KEY_KEYPAD_PLUS 0x2B
|
||||
#define KEY_END 0x3F
|
||||
#else /* SARCH_PC98 */
|
||||
#define KEY_EXTENDED 0x00
|
||||
#define KEY_ENTER 0x0D
|
||||
#define KEY_BACKSPACE 0x08
|
||||
|
@ -48,3 +63,4 @@
|
|||
#define KEY_KEYPAD_PLUS 0x4E
|
||||
#define KEY_END 0x4F
|
||||
#define KEY_SEND 0xE7
|
||||
#endif
|
||||
|
|
|
@ -39,6 +39,7 @@ LoadBootSector(
|
|||
ULONG FileId;
|
||||
ULONG BytesRead;
|
||||
CHAR ArcPath[MAX_PATH];
|
||||
ULONG LoadAddress;
|
||||
|
||||
*DriveNumber = 0;
|
||||
*PartitionNumber = 0;
|
||||
|
@ -98,8 +99,14 @@ LoadBootSector(
|
|||
return Status;
|
||||
}
|
||||
|
||||
#if defined(SARCH_PC98)
|
||||
LoadAddress = Pc98GetBootSectorLoadAddress(*DriveNumber);
|
||||
#else
|
||||
LoadAddress = 0x7C00;
|
||||
#endif
|
||||
|
||||
/* Now try to load the boot sector. If this fails then abort. */
|
||||
Status = ArcRead(FileId, (PVOID)0x7c00, 512, &BytesRead);
|
||||
Status = ArcRead(FileId, UlongToPtr(LoadAddress), 512, &BytesRead);
|
||||
ArcClose(FileId);
|
||||
if ((Status != ESUCCESS) || (BytesRead != 512))
|
||||
{
|
||||
|
@ -108,7 +115,7 @@ LoadBootSector(
|
|||
}
|
||||
|
||||
/* Check for validity */
|
||||
if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
|
||||
if (*(USHORT*)UlongToPtr(LoadAddress + 0x1FE) != 0xAA55)
|
||||
{
|
||||
UiMessageBox("Invalid boot sector magic (0xaa55)");
|
||||
return ENOEXEC;
|
||||
|
@ -131,6 +138,7 @@ LoadPartitionOrDrive(
|
|||
ULONG FileId;
|
||||
ULONG BytesRead;
|
||||
CHAR ArcPath[MAX_PATH];
|
||||
ULONG LoadAddress;
|
||||
|
||||
/*
|
||||
* The ARC "BootPath" value takes precedence over
|
||||
|
@ -167,11 +175,17 @@ LoadPartitionOrDrive(
|
|||
return Status;
|
||||
}
|
||||
|
||||
#if defined(SARCH_PC98)
|
||||
LoadAddress = Pc98GetBootSectorLoadAddress(*DriveNumber);
|
||||
#else
|
||||
LoadAddress = 0x7C00;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now try to load the partition boot sector or the MBR (when PartitionNumber == 0).
|
||||
* If this fails then abort.
|
||||
*/
|
||||
Status = ArcRead(FileId, (PVOID)0x7c00, 512, &BytesRead);
|
||||
Status = ArcRead(FileId, UlongToPtr(LoadAddress), 512, &BytesRead);
|
||||
ArcClose(FileId);
|
||||
if ((Status != ESUCCESS) || (BytesRead != 512))
|
||||
{
|
||||
|
@ -183,7 +197,7 @@ LoadPartitionOrDrive(
|
|||
}
|
||||
|
||||
/* Check for validity */
|
||||
if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
|
||||
if (*(USHORT*)UlongToPtr(LoadAddress + 0x1FE) != 0xAA55)
|
||||
{
|
||||
UiMessageBox("Invalid boot sector magic (0xaa55)");
|
||||
return ENOEXEC;
|
||||
|
@ -325,7 +339,7 @@ LoadAndBootDevice(
|
|||
UiUnInitialize("Booting...");
|
||||
IniCleanup();
|
||||
|
||||
/* Boot the loaded sector code at 0x7C00 */
|
||||
/* Boot the loaded sector code */
|
||||
ChainLoadBiosBootSectorCode(DriveNumber, PartitionNumber);
|
||||
/* Must not return! */
|
||||
return ESUCCESS;
|
||||
|
|
26
sdk/include/reactos/drivers/pc98/fdc.h
Normal file
26
sdk/include/reactos/drivers/pc98/fdc.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* PROJECT: NEC PC-98 series onboard hardware
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: NEC uPD765A FDC header file
|
||||
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define FDC1_IO_BASE 0x90
|
||||
#define FDC2_IO_BASE 0xC8
|
||||
|
||||
#define FDC_IO_o_MODE_SWITCH 0xBE
|
||||
#define FDC_IO_o_EMODE_SWITCH 0x4BE
|
||||
#define FDC_IO_i_MODE 0xBE
|
||||
#define FDC_IO_i_EMODE 0x4BE
|
||||
|
||||
/*
|
||||
* FDC registers offsets
|
||||
*/
|
||||
#define FDC_o_DATA 0x02
|
||||
#define FDC_o_CONTROL 0x04
|
||||
|
||||
#define FDC_i_STATUS 0x00
|
||||
#define FDC_i_DATA 0x02
|
||||
#define FDC_i_READ_SWITCH 0x04
|
279
sdk/include/reactos/drivers/pc98/video.h
Normal file
279
sdk/include/reactos/drivers/pc98/video.h
Normal file
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* PROJECT: NEC PC-98 series onboard hardware
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Graphics system header file
|
||||
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Video memory ***************************************************************/
|
||||
|
||||
#define VRAM_NORMAL_PLANE_B 0xA8000
|
||||
#define VRAM_NORMAL_PLANE_G 0xB0000
|
||||
#define VRAM_NORMAL_PLANE_R 0xB8000
|
||||
#define VRAM_NORMAL_PLANE_I 0xE0000
|
||||
#define VRAM_PLANE_SIZE 0x08000
|
||||
#define VRAM_NORMAL_TEXT 0xA0000
|
||||
#define VRAM_TEXT_ATTR_OFFSET 0x02000
|
||||
#define VRAM_TEXT_SIZE 0x02000
|
||||
#define VRAM_ATTR_SIZE 0x02000
|
||||
|
||||
/* High-resolution machine */
|
||||
#define VRAM_HI_RESO_PLANE_B 0xC0000
|
||||
#define VRAM_HI_RESO_PLANE_G 0xC8000
|
||||
#define VRAM_HI_RESO_PLANE_R 0xD0000
|
||||
#define VRAM_HI_RESO_PLANE_I 0xD8000
|
||||
#define VRAM_HI_RESO_TEXT 0xE0000
|
||||
|
||||
/* GDC definitions ************************************************************/
|
||||
|
||||
#define GDC_STATUS_DRDY 0x01
|
||||
#define GDC_STATUS_FIFO_FULL 0x02
|
||||
#define GDC_STATUS_FIFO_EMPTY 0x04
|
||||
#define GDC_STATUS_DRAWING 0x08
|
||||
#define GDC_STATUS_DMA_EXECUTE 0x10
|
||||
#define GDC_STATUS_VSYNC 0x20
|
||||
#define GDC_STATUS_HBLANK 0x40
|
||||
#define GDC_STATUS_LPEN 0x80
|
||||
|
||||
#define GDC_ATTR_VISIBLE 0x01
|
||||
#define GDC_ATTR_BLINK 0x02
|
||||
#define GDC_ATTR_REVERSE 0x04
|
||||
#define GDC_ATTR_UNDERLINE 0x08
|
||||
#define GDC_ATTR_VERTICAL_LINE 0x10
|
||||
|
||||
#define GDC_ATTR_BLACK 0x00
|
||||
#define GDC_ATTR_BLUE 0x20
|
||||
#define GDC_ATTR_RED 0x40
|
||||
#define GDC_ATTR_PURPLE 0x60
|
||||
#define GDC_ATTR_GREEN 0x80
|
||||
#define GDC_ATTR_LIGHTBLUE 0xA0
|
||||
#define GDC_ATTR_YELLOW 0xC0
|
||||
#define GDC_ATTR_WHITE 0xE0
|
||||
|
||||
#define GDC_COMMAND_RESET 0x00
|
||||
#define GDC_COMMAND_BCTRL_STOP 0x0C
|
||||
#define GDC_COMMAND_BCTRL_START 0x0D
|
||||
#define GDC_COMMAND_SYNC_ON 0x0E
|
||||
#define GDC_COMMAND_SYNC_OFF 0x0F
|
||||
#define GDC_COMMAND_WRITE 0x20
|
||||
#define GDC_COMMAND_SLAVE 0x6E
|
||||
#define GDC_COMMAND_MASTER 0x6F
|
||||
|
||||
#define GDC_COMMAND_CSRFORM 0x4B
|
||||
typedef struct _CSRFORMPARAM
|
||||
{
|
||||
BOOLEAN Show;
|
||||
BOOLEAN Blink;
|
||||
UCHAR BlinkRate;
|
||||
UCHAR LinesPerRow;
|
||||
UCHAR StartScanLine;
|
||||
UCHAR EndScanLine;
|
||||
} CSRFORMPARAM, *PCSRFORMPARAM;
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
WRITE_GDC_CSRFORM(PUCHAR Port, PCSRFORMPARAM CursorParameters)
|
||||
{
|
||||
WRITE_PORT_UCHAR(Port, ((CursorParameters->Show & 0x01) << 7) |
|
||||
(CursorParameters->LinesPerRow - 1));
|
||||
WRITE_PORT_UCHAR(Port, ((CursorParameters->BlinkRate & 0x03) << 6) |
|
||||
((!CursorParameters->Blink & 0x01) << 5) | CursorParameters->StartScanLine);
|
||||
WRITE_PORT_UCHAR(Port, (CursorParameters->EndScanLine << 3) | ((CursorParameters->BlinkRate & 0x1C) >> 2));
|
||||
}
|
||||
|
||||
#define GDC_COMMAND_START 0x6B
|
||||
#define GDC_COMMAND_ZOOM 0x46
|
||||
|
||||
#define GDC_COMMAND_CSRW 0x49
|
||||
typedef struct _CSRWPARAM
|
||||
{
|
||||
ULONG CursorAdress;
|
||||
UCHAR DotAddress;
|
||||
} CSRWPARAM, *PCSRWPARAM;
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
WRITE_GDC_CSRW(PUCHAR Port, PCSRWPARAM CursorParameters)
|
||||
{
|
||||
ASSERT(CursorParameters->CursorAdress < 0xF00000);
|
||||
ASSERT(CursorParameters->DotAddress < 0x10);
|
||||
|
||||
WRITE_PORT_UCHAR(Port, CursorParameters->CursorAdress & 0xFF);
|
||||
WRITE_PORT_UCHAR(Port, (CursorParameters->CursorAdress >> 8) & 0xFF);
|
||||
WRITE_PORT_UCHAR(Port, (CursorParameters->DotAddress << 4) |
|
||||
((CursorParameters->CursorAdress >> 16) & 0x03));
|
||||
}
|
||||
|
||||
#define GDC_COMMAND_PRAM 0x70
|
||||
#define GDC_COMMAND_PITCH 0x47
|
||||
#define GDC_COMMAND_MASK 0x4A
|
||||
#define GDC_COMMAND_FIGS 0x4C
|
||||
#define GDC_COMMAND_FIGD 0x6C
|
||||
#define GDC_COMMAND_GCHRD 0x68
|
||||
#define GDC_COMMAND_READ 0xA0
|
||||
#define GDC_COMMAND_CURD 0xE0
|
||||
#define GDC_COMMAND_LPRD 0xC0
|
||||
#define GDC_COMMAND_DMAR 0xA4
|
||||
#define GDC_COMMAND_DMAW 0x24
|
||||
|
||||
/* Master GDC *****************************************************************/
|
||||
|
||||
#define GDC1_IO_i_STATUS 0x60
|
||||
#define GDC1_IO_i_DATA 0x62
|
||||
#define GDC1_IO_i_MODE_FLIPFLOP1 0x68
|
||||
|
||||
#define GDC1_IO_o_PARAM 0x60
|
||||
#define GDC1_IO_o_COMMAND 0x62
|
||||
#define GDC1_IO_o_VSYNC 0x64 /* CRT interrupt reset */
|
||||
|
||||
#define GDC1_IO_o_MODE_FLIPFLOP1 0x68
|
||||
#define GDC1_MODE_VERTICAL_LINE 0x00 /* Character attribute */
|
||||
#define GDC1_MODE_SIMPLE_GRAPHICS 0x01
|
||||
#define GDC1_MODE_COLORED 0x02
|
||||
#define GDC1_MODE_MONOCHROME 0x03
|
||||
#define GDC1_MODE_COLS_80 0x04
|
||||
#define GDC1_MODE_COLS_40 0x05
|
||||
#define GDC1_MODE_ANK_6_8 0x06
|
||||
#define GDC1_MODE_ANK_7_13 0x07
|
||||
#define GDC1_MODE_LINES_400 0x08
|
||||
#define GDC1_MODE_LINES_200 0x09 /* Hide odd raster line */
|
||||
#define GDC1_MODE_KCG_CODE 0x0A /* CG access during V-SYNC */
|
||||
#define GDC1_MODE_KCG_BITMAP 0x0B
|
||||
#define GDC1_NVMW_PROTECT 0x0C
|
||||
#define GDC1_NVMW_UNPROTECT 0x0D /* Memory at TextVramSegment:(3FE2-3FFEh) */
|
||||
#define GDC1_MODE_DISPLAY_DISABLE 0x0E
|
||||
#define GDC1_MODE_DISPLAY_ENABLE 0x0F
|
||||
|
||||
#define GDC1_IO_o_BORDER_COLOR 0x6C /* PC-H98 */
|
||||
|
||||
/* Slave GDC ******************************************************************/
|
||||
|
||||
#define GDC2_IO_i_STATUS 0xA0
|
||||
#define GDC2_IO_i_DATA 0xA2
|
||||
#define GDC2_IO_i_VIDEO_PAGE 0xA4
|
||||
#define GDC2_IO_i_VIDEO_PAGE_ACCESS 0xA6
|
||||
#define GDC2_IO_i_PALETTE_INDEX 0xA8
|
||||
#define GDC2_IO_i_GREEN 0xAA
|
||||
#define GDC2_IO_i_RED 0xAC
|
||||
#define GDC2_IO_i_BLUE 0xAE
|
||||
#define GDC2_IO_i_MODE_FLIPFLOP2 0x6A
|
||||
#define GDC2_IO_i_MODE_FLIPFLOP3 0x6E
|
||||
|
||||
#define GDC2_IO_o_PARAM 0xA0
|
||||
#define GDC2_IO_o_COMMAND 0xA2
|
||||
#define GDC2_IO_o_VIDEO_PAGE 0xA4 /* Video page to display (invalid in 480 height mode) */
|
||||
#define GDC2_IO_o_VIDEO_PAGE_ACCESS 0xA6 /* Video page to CPU access */
|
||||
#define GDC2_IO_o_PALETTE_INDEX 0xA8
|
||||
#define GDC2_IO_o_GREEN 0xAA
|
||||
#define GDC2_IO_o_RED 0xAC
|
||||
#define GDC2_IO_o_BLUE 0xAE
|
||||
|
||||
#define GDC2_IO_o_MODE_FLIPFLOP2 0x6A
|
||||
#define GDC2_MODE_COLORS_8 0x00
|
||||
#define GDC2_MODE_COLORS_16 0x01
|
||||
#define GDC2_MODE_GRCG 0x04
|
||||
#define GDC2_MODE_EGC 0x05
|
||||
#define GDC2_EGC_FF_PROTECT 0x06
|
||||
#define GDC2_EGC_FF_UNPROTECT 0x07 /* Unprotect the EGC F/F registers */
|
||||
#define GDC2_MODE_PEGS_DISABLE 0x20
|
||||
#define GDC2_MODE_PEGC_ENABLE 0x21
|
||||
// #define GDC2_MODE_ 0x26
|
||||
// #define GDC2_MODE_ 0x27
|
||||
// #define GDC2_MODE_ 0x28
|
||||
// #define GDC2_MODE_ 0x29
|
||||
// #define GDC2_MODE_ 0x2A
|
||||
// #define GDC2_MODE_ 0x2B
|
||||
// #define GDC2_MODE_ 0x2C
|
||||
// #define GDC2_MODE_ 0x2D
|
||||
#define GDC2_MODE_CRT 0x40
|
||||
#define GDC2_MODE_LCD 0x41
|
||||
// #define GDC2_MODE_VRAM_PLAIN 0x62 /* PC-H98 */
|
||||
// #define GDC2_MODE_VRAM_PACKED 0x63
|
||||
#define GDC2_MODE_LINES_400 0x68 /* 128 kB VRAM boundary */
|
||||
#define GDC2_MODE_LINES_800 0x69 /* 256 kB VRAM boundary */
|
||||
// #define GDC2_MODE_ 0x6C
|
||||
// #define GDC2_MODE_ 0x6D
|
||||
#define GDC2_CLOCK1_2_5MHZ 0x82
|
||||
#define GDC2_CLOCK1_5MHZ 0x83
|
||||
#define GDC2_CLOCK2_2_5MHZ 0x84
|
||||
#define GDC2_CLOCK2_5MHZ 0x85
|
||||
|
||||
#define GDC2_IO_o_MODE_FLIPFLOP3 0x6E
|
||||
// #define GDC2_MODE_ 0x02
|
||||
// #define GDC2_MODE_ 0x03
|
||||
// #define GDC2_MODE_ 0x08
|
||||
// #define GDC2_MODE_ 0x09
|
||||
// #define GDC2_MODE_ 0x0A
|
||||
// #define GDC2_MODE_ 0x0B
|
||||
// #define GDC2_MODE_ 0x0C
|
||||
// #define GDC2_MODE_ 0x0D
|
||||
// #define GDC2_MODE_ 0x0E
|
||||
// #define GDC2_MODE_ 0x0F
|
||||
// #define GDC2_MODE_ 0x14
|
||||
// #define GDC2_MODE_ 0x15
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
WRITE_GDC1_COMMAND(UCHAR Command)
|
||||
{
|
||||
while (!(READ_PORT_UCHAR((PUCHAR)GDC1_IO_i_STATUS) & GDC_STATUS_FIFO_EMPTY))
|
||||
NOTHING;
|
||||
|
||||
WRITE_PORT_UCHAR((PUCHAR)GDC1_IO_o_COMMAND, Command);
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
WRITE_GDC2_COMMAND(UCHAR Command)
|
||||
{
|
||||
while (!(READ_PORT_UCHAR((PUCHAR)GDC2_IO_i_STATUS) & GDC_STATUS_FIFO_EMPTY))
|
||||
NOTHING;
|
||||
|
||||
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_COMMAND, Command);
|
||||
}
|
||||
|
||||
/* CRT Controller *************************************************************/
|
||||
|
||||
#define CRTC_IO_o_SCANLINE_START 0x70
|
||||
#define CRTC_IO_o_SCANLINE_END 0x72
|
||||
#define CRTC_IO_o_SCANLINE_BLANK_AT 0x74
|
||||
#define CRTC_IO_o_SCANLINES 0x76
|
||||
#define CRTC_IO_o_SUR 0x78
|
||||
#define CRTC_IO_o_SDR 0x7A
|
||||
|
||||
/* GRCG (Graphic Charger) *****************************************************/
|
||||
|
||||
#define GRCG_IO_i_MODE 0x7C
|
||||
#define GRCG_IO_o_MODE 0x7C
|
||||
typedef union _GRCG_MODE_REGISTER
|
||||
{
|
||||
struct
|
||||
{
|
||||
UCHAR DisablePlaneB:1;
|
||||
UCHAR DisablePlaneR:1;
|
||||
UCHAR DisablePlaneG:1;
|
||||
UCHAR DisablePlaneI:1;
|
||||
UCHAR Unused:2;
|
||||
|
||||
UCHAR Mode:1;
|
||||
#define GRCG_MODE_TILE_DIRECT_WRITE 0
|
||||
#define GRCG_MODE_TILE_COMPARE_READ 0
|
||||
#define GRCG_MODE_READ_MODIFY_WRITE 1
|
||||
|
||||
UCHAR Enable:1;
|
||||
};
|
||||
UCHAR Bits;
|
||||
} GRCG_MODE_REGISTER, *PGRCG_MODE_REGISTER;
|
||||
|
||||
#define GRCG_IO_o_TILE_PATTERN 0x7E
|
||||
|
||||
/* CG Window ******************************************************************/
|
||||
|
||||
#define KCG_IO_o_CHARCODE_HIGH 0xA1
|
||||
#define KCG_IO_o_CHARCODE_LOW 0xA3
|
||||
#define KCG_IO_o_LINE 0xA5
|
||||
#define KCG_IO_o_PATTERN 0xA9
|
||||
|
||||
#define KCG_IO_i_PATTERN 0xA9
|
Loading…
Reference in a new issue