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 }
41 
42 ULONG
43 Pc98GetBootSectorLoadAddress(IN UCHAR DriveNumber)
44 {
45     PPC98_DISK_DRIVE DiskDrive;
46 
47     DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
48     if (!DiskDrive)
49     {
50         ERR("Failed to get drive 0x%x\n", DriveNumber);
51         return 0x1FC00;
52     }
53 
54     if (((DiskDrive->DaUa & 0xF0) == 0x30) ||
55         ((DiskDrive->DaUa & 0xF0) == 0xB0))
56     {
57         /* 1.44 MB floppy */
58         return 0x1FE00;
59     }
60     else if (DiskDrive->Type & DRIVE_FDD)
61     {
62         return 0x1FC00;
63     }
64 
65     return 0x1F800;
66 }
67 
68 VOID __cdecl ChainLoadBiosBootSectorCode(
69     IN UCHAR BootDrive OPTIONAL,
70     IN ULONG BootPartition OPTIONAL)
71 {
72     REGS Regs;
73     PPC98_DISK_DRIVE DiskDrive;
74     USHORT LoadAddress;
75     UCHAR DriveNumber = BootDrive ? BootDrive : FrldrBootDrive;
76 
77     DiskDrive = Pc98DiskDriveNumberToDrive(DriveNumber);
78     if (!DiskDrive)
79     {
80         ERR("Failed to get drive 0x%x\n", DriveNumber);
81         return;
82     }
83 
84     LoadAddress = (USHORT)(Pc98GetBootSectorLoadAddress(DriveNumber) >> 4);
85 
86     RtlZeroMemory(&Regs, sizeof(Regs));
87     Regs.w.ax = DiskDrive->DaUa;
88     Regs.w.si = LoadAddress;
89     Regs.w.es = LoadAddress;
90     *(PUCHAR)MEM_DISK_BOOT = DiskDrive->DaUa;
91 
92     Pc98VideoClearScreen(ATTR(COLOR_WHITE, COLOR_BLACK));
93 
94     Relocator16Boot(&Regs,
95                     /* Stack segment:pointer */
96                     0x0020, 0x00FF,
97                     /* Code segment:pointer */
98                     LoadAddress, 0x0000);
99 }
100 
101 static BOOLEAN
102 Pc98ArchTest(VOID)
103 {
104     REGS RegsIn, RegsOut;
105 
106     /* Int 1Ah AX=1000h
107      * NEC PC-9800 series - Installation check
108      */
109     RegsIn.w.ax = 0x1000;
110     Int386(0x1A, &RegsIn, &RegsOut);
111 
112     return RegsOut.w.ax != 0x1000;
113 }
114 
115 VOID
116 MachInit(const char *CmdLine)
117 {
118     if (!Pc98ArchTest())
119     {
120         _disable();
121         __halt();
122 
123         while (TRUE)
124             NOTHING;
125     }
126 
127     /* Setup vtbl */
128     RtlZeroMemory(&MachVtbl, sizeof(MACHVTBL));
129     MachVtbl.ConsPutChar = Pc98ConsPutChar;
130     MachVtbl.ConsKbHit = Pc98ConsKbHit;
131     MachVtbl.ConsGetCh = Pc98ConsGetCh;
132     MachVtbl.VideoClearScreen = Pc98VideoClearScreen;
133     MachVtbl.VideoSetDisplayMode = Pc98VideoSetDisplayMode;
134     MachVtbl.VideoGetDisplaySize = Pc98VideoGetDisplaySize;
135     MachVtbl.VideoGetBufferSize = Pc98VideoGetBufferSize;
136     MachVtbl.VideoGetFontsFromFirmware = Pc98VideoGetFontsFromFirmware;
137     MachVtbl.VideoSetTextCursorPosition = Pc98VideoSetTextCursorPosition;
138     MachVtbl.VideoHideShowTextCursor = Pc98VideoHideShowTextCursor;
139     MachVtbl.VideoPutChar = Pc98VideoPutChar;
140     MachVtbl.VideoCopyOffScreenBufferToVRAM = Pc98VideoCopyOffScreenBufferToVRAM;
141     MachVtbl.VideoIsPaletteFixed = Pc98VideoIsPaletteFixed;
142     MachVtbl.VideoSetPaletteColor = Pc98VideoSetPaletteColor;
143     MachVtbl.VideoGetPaletteColor = Pc98VideoGetPaletteColor;
144     MachVtbl.VideoSync = Pc98VideoSync;
145     MachVtbl.Beep = Pc98Beep;
146     MachVtbl.PrepareForReactOS = Pc98PrepareForReactOS;
147     MachVtbl.GetMemoryMap = Pc98MemGetMemoryMap;
148     MachVtbl.GetExtendedBIOSData = Pc98GetExtendedBIOSData;
149     MachVtbl.GetFloppyCount = Pc98GetFloppyCount;
150     MachVtbl.DiskReadLogicalSectors = Pc98DiskReadLogicalSectors;
151     MachVtbl.DiskGetDriveGeometry = Pc98DiskGetDriveGeometry;
152     MachVtbl.DiskGetCacheableBlockCount = Pc98DiskGetCacheableBlockCount;
153     MachVtbl.GetTime = Pc98GetTime;
154     MachVtbl.InitializeBootDevices = Pc98InitializeBootDevices;
155     MachVtbl.HwDetect = Pc98HwDetect;
156     MachVtbl.HwIdle = Pc98HwIdle;
157 
158     HiResoMachine = *(PUCHAR)MEM_BIOS_FLAG1 & HIGH_RESOLUTION_FLAG;
159 
160     HalpCalibrateStallExecution();
161     Pc98VideoInit();
162 }
163