1 /*
2 * PROJECT: FreeLoader
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Hardware-specific routines for NEC PC-98 series
5 * COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
6 */
7
8 /* INCLUDES *******************************************************************/
9
10 #include <freeldr.h>
11
12 #include <debug.h>
13 DBG_DEFAULT_CHANNEL(HWDETECT);
14
15 /* GLOBALS ********************************************************************/
16
17 BOOLEAN HiResoMachine;
18
19 /* FUNCTIONS ******************************************************************/
20
21 VOID
Pc98GetExtendedBIOSData(PULONG ExtendedBIOSDataArea,PULONG ExtendedBIOSDataSize)22 Pc98GetExtendedBIOSData(PULONG ExtendedBIOSDataArea, PULONG ExtendedBIOSDataSize)
23 {
24 *ExtendedBIOSDataArea = HiResoMachine ? MEM_EXTENDED_HIGH_RESO : MEM_EXTENDED_NORMAL;
25 *ExtendedBIOSDataSize = 64;
26 }
27
28 VOID
Pc98HwIdle(VOID)29 Pc98HwIdle(VOID)
30 {
31 /* Unimplemented */
32 }
33
34 VOID
Pc98PrepareForReactOS(VOID)35 Pc98PrepareForReactOS(VOID)
36 {
37 Pc98DiskPrepareForReactOS();
38 Pc98VideoPrepareForReactOS();
39 DiskStopFloppyMotor();
40 DebugDisableScreenPort();
41 }
42
43 ULONG
Pc98GetBootSectorLoadAddress(IN UCHAR DriveNumber)44 Pc98GetBootSectorLoadAddress(IN UCHAR DriveNumber)
45 {
46 PPC98_DISK_DRIVE DiskDrive;
47
48 DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
49 if (!DiskDrive)
50 {
51 ERR("Failed to get drive 0x%x\n", DriveNumber);
52 return 0x1FC00;
53 }
54
55 if (((DiskDrive->DaUa & 0xF0) == 0x30) ||
56 ((DiskDrive->DaUa & 0xF0) == 0xB0))
57 {
58 /* 1.44 MB floppy */
59 return 0x1FE00;
60 }
61 else if (DiskDrive->Type & DRIVE_FDD)
62 {
63 return 0x1FC00;
64 }
65
66 return 0x1F800;
67 }
68
ChainLoadBiosBootSectorCode(IN UCHAR BootDrive OPTIONAL,IN ULONG BootPartition OPTIONAL)69 VOID __cdecl ChainLoadBiosBootSectorCode(
70 IN UCHAR BootDrive OPTIONAL,
71 IN ULONG BootPartition OPTIONAL)
72 {
73 REGS Regs;
74 PPC98_DISK_DRIVE DiskDrive;
75 USHORT LoadAddress;
76 UCHAR DriveNumber = BootDrive ? BootDrive : FrldrBootDrive;
77
78 DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
79 if (!DiskDrive)
80 {
81 ERR("Failed to get drive 0x%x\n", DriveNumber);
82 return;
83 }
84
85 LoadAddress = (USHORT)(Pc98GetBootSectorLoadAddress(DriveNumber) >> 4);
86
87 RtlZeroMemory(&Regs, sizeof(Regs));
88 Regs.w.ax = DiskDrive->DaUa;
89 Regs.w.si = LoadAddress;
90 Regs.w.es = LoadAddress;
91 *(PUCHAR)MEM_DISK_BOOT = DiskDrive->DaUa;
92
93 Pc98VideoClearScreen(ATTR(COLOR_WHITE, COLOR_BLACK));
94
95 Relocator16Boot(&Regs,
96 /* Stack segment:pointer */
97 0x0020, 0x00FF,
98 /* Code segment:pointer */
99 LoadAddress, 0x0000);
100 }
101
102 static BOOLEAN
Pc98ArchTest(VOID)103 Pc98ArchTest(VOID)
104 {
105 REGS RegsIn, RegsOut;
106
107 /* Int 1Ah AX=1000h
108 * NEC PC-9800 series - Installation check
109 */
110 RegsIn.w.ax = 0x1000;
111 Int386(0x1A, &RegsIn, &RegsOut);
112
113 return RegsOut.w.ax != 0x1000;
114 }
115
116 VOID
MachInit(const char * CmdLine)117 MachInit(const char *CmdLine)
118 {
119 if (!Pc98ArchTest())
120 {
121 ERR("This is not a supported PC98!\n");
122
123 /* Disable and halt the CPU */
124 _disable();
125 __halt();
126
127 while (TRUE)
128 NOTHING;
129 }
130
131 /* Setup vtbl */
132 RtlZeroMemory(&MachVtbl, sizeof(MachVtbl));
133 MachVtbl.ConsPutChar = Pc98ConsPutChar;
134 MachVtbl.ConsKbHit = Pc98ConsKbHit;
135 MachVtbl.ConsGetCh = Pc98ConsGetCh;
136 MachVtbl.VideoClearScreen = Pc98VideoClearScreen;
137 MachVtbl.VideoSetDisplayMode = Pc98VideoSetDisplayMode;
138 MachVtbl.VideoGetDisplaySize = Pc98VideoGetDisplaySize;
139 MachVtbl.VideoGetBufferSize = Pc98VideoGetBufferSize;
140 MachVtbl.VideoGetFontsFromFirmware = Pc98VideoGetFontsFromFirmware;
141 MachVtbl.VideoSetTextCursorPosition = Pc98VideoSetTextCursorPosition;
142 MachVtbl.VideoHideShowTextCursor = Pc98VideoHideShowTextCursor;
143 MachVtbl.VideoPutChar = Pc98VideoPutChar;
144 MachVtbl.VideoCopyOffScreenBufferToVRAM = Pc98VideoCopyOffScreenBufferToVRAM;
145 MachVtbl.VideoIsPaletteFixed = Pc98VideoIsPaletteFixed;
146 MachVtbl.VideoSetPaletteColor = Pc98VideoSetPaletteColor;
147 MachVtbl.VideoGetPaletteColor = Pc98VideoGetPaletteColor;
148 MachVtbl.VideoSync = Pc98VideoSync;
149 MachVtbl.Beep = Pc98Beep;
150 MachVtbl.PrepareForReactOS = Pc98PrepareForReactOS;
151 MachVtbl.GetMemoryMap = Pc98MemGetMemoryMap;
152 MachVtbl.GetExtendedBIOSData = Pc98GetExtendedBIOSData;
153 MachVtbl.GetFloppyCount = Pc98GetFloppyCount;
154 MachVtbl.DiskReadLogicalSectors = Pc98DiskReadLogicalSectors;
155 MachVtbl.DiskGetDriveGeometry = Pc98DiskGetDriveGeometry;
156 MachVtbl.DiskGetCacheableBlockCount = Pc98DiskGetCacheableBlockCount;
157 MachVtbl.GetTime = Pc98GetTime;
158 MachVtbl.InitializeBootDevices = Pc98InitializeBootDevices;
159 MachVtbl.HwDetect = Pc98HwDetect;
160 MachVtbl.HwIdle = Pc98HwIdle;
161
162 HiResoMachine = *(PUCHAR)MEM_BIOS_FLAG1 & HIGH_RESOLUTION_FLAG;
163
164 HalpCalibrateStallExecution();
165 Pc98VideoInit();
166 }
167