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
22 Pc98GetExtendedBIOSData(PULONG ExtendedBIOSDataArea, PULONG ExtendedBIOSDataSize)
23 {
24     *ExtendedBIOSDataArea = HiResoMachine ? MEM_EXTENDED_HIGH_RESO : MEM_EXTENDED_NORMAL;
25     *ExtendedBIOSDataSize = 64;
26 }
27 
28 VOID
29 Pc98HwIdle(VOID)
30 {
31     /* Unimplemented */
32 }
33 
34 VOID
35 Pc98PrepareForReactOS(VOID)
36 {
37     Pc98DiskPrepareForReactOS();
38     Pc98VideoPrepareForReactOS();
39     DiskStopFloppyMotor();
40     DebugDisableScreenPort();
41 }
42 
43 ULONG
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 
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
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
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