VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevPcArch.cpp@ 81876

Last change on this file since 81876 was 81591, checked in by vboxsync, 5 years ago

Devices: Use PDMDEVINS_2_DATA and PDMDEVINS_2_DATA. bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 12.4 KB
Line 
1/* $Id: DevPcArch.cpp 81591 2019-10-30 14:14:10Z vboxsync $ */
2/** @file
3 * DevPcArch - PC Architecture Device.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_PC_ARCH
23#include <VBox/vmm/pdmdev.h>
24#include <VBox/vmm/mm.h>
25#include <VBox/vmm/pgm.h>
26#include <VBox/log.h>
27#include <VBox/err.h>
28#include <iprt/assert.h>
29#include <iprt/string.h>
30
31#include "VBoxDD.h"
32
33
34/*********************************************************************************************************************************
35* Structures and Typedefs *
36*********************************************************************************************************************************/
37
38/**
39 * PC Bios instance data structure.
40 */
41typedef struct DEVPCARCH
42{
43 /** Pointer back to the device instance. */
44 PPDMDEVINS pDevIns;
45} DEVPCARCH, *PDEVPCARCH;
46
47
48
49/**
50 * @callback_method_impl{FNIOMIOPORTIN, Math coprocessor.}
51 */
52static DECLCALLBACK(int) pcarchIOPortFPURead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
53{
54 int rc;
55 NOREF(pvUser); NOREF(pDevIns); NOREF(pu32);
56 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Port=%#x cb=%d\n", Port, cb);
57 if (rc == VINF_SUCCESS)
58 rc = VERR_IOM_IOPORT_UNUSED;
59 return rc;
60}
61
62/**
63 * @callback_method_impl{FNIOMIOPORTOUT, Math coprocessor.}
64 * @todo Add IGNNE support.
65 */
66static DECLCALLBACK(int) pcarchIOPortFPUWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
67{
68 int rc = VINF_SUCCESS;
69 NOREF(pvUser);
70 if (cb == 1)
71 {
72 switch (Port)
73 {
74 /*
75 * Clear busy latch.
76 */
77 case 0xf0:
78 Log2(("PCARCH: FPU Clear busy latch u32=%#x\n", u32));
79/* This is triggered when booting Knoppix (3.7) */
80#if 0
81 if (!u32)
82 rc = PDMDeviceDBGFStop(pDevIns, RT_SRC_POS, "Port=%#x cb=%d u32=%#x\n", Port, cb, u32);
83#endif
84 /* pDevIns->pHlp->pfnPICSetIrq(pDevIns, 13, 0); */
85 break;
86
87 /* Reset. */
88 case 0xf1:
89 Log2(("PCARCH: FPU Reset cb=%d u32=%#x\n", cb, u32));
90 /** @todo figure out what the difference between FPU ports 0xf0 and 0xf1 are... */
91 /* pDevIns->pHlp->pfnPICSetIrq(pDevIns, 13, 0); */
92 break;
93
94 /* opcode transfers */
95 case 0xf8:
96 case 0xfa:
97 case 0xfc:
98 default:
99 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Port=%#x cb=%d u32=%#x\n", Port, cb, u32);
100 break;
101 }
102 /* this works better, but probably not entirely correct. */
103 PDMDevHlpISASetIrq(pDevIns, 13, 0);
104 }
105 else
106 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Port=%#x cb=%d u32=%#x\n", Port, cb, u32);
107 return rc;
108}
109
110
111/**
112 * @callback_method_impl{FNIOMIOPORTIN, PS/2 system control port A.}
113 *
114 * @todo Check if the A20 enable/disable method implemented here in any way
115 * should cooperate with the one implemented in the PS/2 keyboard device.
116 * This probably belongs together in the PS/2 keyboard device (since that
117 * is where the "port B" mentioned by Ralph Brown is implemented).
118 *
119 * @remark Ralph Brown and friends have this to say about this port:
120 *
121 * @verbatim
1220092 RW PS/2 system control port A (port B is at PORT 0061h) (see #P0415)
123
124Bitfields for PS/2 system control port A:
125Bit(s) Description (Table P0415)
126 7-6 any bit set to 1 turns activity light on
127 5 unused
128 4 watchdog timout occurred
129 3 =0 RTC/CMOS security lock (on password area) unlocked
130 =1 CMOS locked (done by POST)
131 2 unused
132 1 A20 is active
133 0 =0 system reset or write
134 =1 pulse alternate reset pin (high-speed alternate CPU reset)
135Notes: once set, bit 3 may only be cleared by a power-on reset
136 on at least the C&T 82C235, bit 0 remains set through a CPU reset to
137 allow the BIOS to determine the reset method
138 on the PS/2 30-286 & "Tortuga" the INT 15h/87h memory copy does
139 not use this port for A20 control, but instead uses the keyboard
140 controller (8042). Reportedly this may cause the system to crash
141 when access to the 8042 is disabled in password server mode
142 (see #P0398).
143SeeAlso: #P0416,#P0417,MSR 00001000h
144 * @endverbatim
145 */
146static DECLCALLBACK(int)
147pcarchIOPortPS2SysControlPortARead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
148{
149 RT_NOREF1(pvUser);
150 if (cb == 1)
151 {
152 *pu32 = PDMDevHlpA20IsEnabled(pDevIns) << 1;
153 return VINF_SUCCESS;
154 }
155 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Port=%#x cb=%d\n", Port, cb);
156}
157
158
159/**
160 * @callback_method_impl{FNIOMIOPORTOUT, PS/2 system control port A.}
161 * @see Remark and todo of pcarchIOPortPS2SysControlPortARead().
162 */
163static DECLCALLBACK(int)
164pcarchIOPortPS2SysControlPortAWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
165{
166 NOREF(pvUser);
167 if (cb == 1)
168 {
169 /*
170 * Fast reset?
171 */
172 if (u32 & 1)
173 {
174 LogRel(("Reset initiated by system port A\n"));
175 return PDMDevHlpVMReset(pDevIns, PDMVMRESET_F_PORT_A);
176 }
177
178 /*
179 * A20 is the only thing we care about of the other stuff.
180 */
181 PDMDevHlpA20Set(pDevIns, !!(u32 & 2));
182 return VINF_SUCCESS;
183 }
184 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Port=%#x cb=%d u32=%#x\n", Port, cb, u32);
185}
186
187
188/**
189 * @callback_method_impl{FNIOMMMIOWRITE, Ignores writes to the reserved memory.}
190 */
191static DECLCALLBACK(int) pcarchReservedMemoryWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr,
192 void const *pv, unsigned cb)
193{
194 Log2(("pcarchReservedMemoryRead: %#RGp LB %#x %.*Rhxs\n", GCPhysAddr, cb, RT_MIN(cb, 16), pv));
195 NOREF(pDevIns); NOREF(pvUser); NOREF(GCPhysAddr); NOREF(pv); NOREF(cb);
196 return VINF_SUCCESS;
197}
198
199
200/**
201 * @callback_method_impl{FNIOMMMIOREAD, The reserved memory reads as 0xff.}
202 */
203static DECLCALLBACK(int) pcarchReservedMemoryRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
204{
205 Log2(("pcarchReservedMemoryRead: %#RGp LB %#x\n", GCPhysAddr, cb));
206 NOREF(pDevIns); NOREF(pvUser); NOREF(GCPhysAddr);
207 memset(pv, 0xff, cb);
208 return VINF_SUCCESS;
209}
210
211
212/**
213 * @interface_method_impl{PDMDEVREG,pfnInitComplete,
214 * Turn RAM pages between 0xa0000 and 0xfffff into reserved memory.}
215 */
216static DECLCALLBACK(int) pcarchInitComplete(PPDMDEVINS pDevIns)
217{
218 PVM pVM = PDMDevHlpGetVM(pDevIns);
219 int iRegion = 0;
220 RTGCPHYS const GCPhysEnd = 0x100000;
221 RTGCPHYS GCPhysCur = 0x0a0000;
222 do
223 {
224 if (!PGMPhysIsGCPhysNormal(pVM, GCPhysCur))
225 GCPhysCur += X86_PAGE_SIZE;
226 else
227 {
228 RTGCPHYS const GCPhysStart = GCPhysCur;
229 do
230 GCPhysCur += X86_PAGE_SIZE;
231 while (GCPhysCur < GCPhysEnd && PGMPhysIsGCPhysNormal(pVM, GCPhysCur));
232
233 int rc = PDMDevHlpMMIORegister(pDevIns, GCPhysStart, GCPhysCur - GCPhysStart, NULL /*pvUser*/,
234 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
235 pcarchReservedMemoryWrite, pcarchReservedMemoryRead,
236 MMR3HeapAPrintf(pVM, MM_TAG_PGM_PHYS /* bad bird*/, "PC Arch Reserved #%u", iRegion));
237 AssertLogRelRCReturn(rc, rc);
238 iRegion++;
239 }
240 } while (GCPhysCur < GCPhysEnd);
241
242 return VINF_SUCCESS;
243}
244
245
246/**
247 * @interface_method_impl{PDMDEVREG,pfnConstruct}
248 */
249static DECLCALLBACK(int) pcarchConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
250{
251 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
252 PDEVPCARCH pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCARCH);
253 int rc;
254 Assert(iInstance == 0); RT_NOREF(iInstance);
255
256 /*
257 * Validate configuration.
258 */
259 if (!CFGMR3AreValuesValid(pCfg, "\0"))
260 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
261
262 /*
263 * Init the data.
264 */
265 pThis->pDevIns = pDevIns;
266
267 /*
268 * Register I/O Ports
269 */
270 rc = PDMDevHlpIOPortRegister(pDevIns, 0xF0, 0x10, NULL,
271 pcarchIOPortFPUWrite, pcarchIOPortFPURead,
272 NULL, NULL, "Math Co-Processor (DOS/OS2 mode)");
273 if (RT_FAILURE(rc))
274 return rc;
275 rc = PDMDevHlpIOPortRegister(pDevIns, 0x92, 1, NULL,
276 pcarchIOPortPS2SysControlPortAWrite, pcarchIOPortPS2SysControlPortARead,
277 NULL, NULL, "PS/2 system control port A (A20 and more)");
278 if (RT_FAILURE(rc))
279 return rc;
280
281 return VINF_SUCCESS;
282}
283
284
285/**
286 * The device registration structure.
287 */
288const PDMDEVREG g_DevicePcArch =
289{
290 /* .u32Version = */ PDM_DEVREG_VERSION,
291 /* .uReserved0 = */ 0,
292 /* .szName = */ "pcarch",
293 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS,
294 /* .fClass = */ PDM_DEVREG_CLASS_ARCH,
295 /* .cMaxInstances = */ 1,
296 /* .uSharedVersion = */ 42,
297 /* .cbInstanceShared = */ sizeof(DEVPCARCH),
298 /* .cbInstanceCC = */ 0,
299 /* .cbInstanceRC = */ 0,
300 /* .cMaxPciDevices = */ 0,
301 /* .cMaxMsixVectors = */ 0,
302 /* .pszDescription = */ "PC Architecture Device",
303#if defined(IN_RING3)
304 /* .pszRCMod = */ "",
305 /* .pszR0Mod = */ "",
306 /* .pfnConstruct = */ pcarchConstruct,
307 /* .pfnDestruct = */ NULL,
308 /* .pfnRelocate = */ NULL,
309 /* .pfnMemSetup = */ NULL,
310 /* .pfnPowerOn = */ NULL,
311 /* .pfnReset = */ NULL,
312 /* .pfnSuspend = */ NULL,
313 /* .pfnResume = */ NULL,
314 /* .pfnAttach = */ NULL,
315 /* .pfnDetach = */ NULL,
316 /* .pfnQueryInterface = */ NULL,
317 /* .pfnInitComplete = */ pcarchInitComplete,
318 /* .pfnPowerOff = */ NULL,
319 /* .pfnSoftReset = */ NULL,
320 /* .pfnReserved0 = */ NULL,
321 /* .pfnReserved1 = */ NULL,
322 /* .pfnReserved2 = */ NULL,
323 /* .pfnReserved3 = */ NULL,
324 /* .pfnReserved4 = */ NULL,
325 /* .pfnReserved5 = */ NULL,
326 /* .pfnReserved6 = */ NULL,
327 /* .pfnReserved7 = */ NULL,
328#elif defined(IN_RING0)
329 /* .pfnEarlyConstruct = */ NULL,
330 /* .pfnConstruct = */ NULL,
331 /* .pfnDestruct = */ NULL,
332 /* .pfnFinalDestruct = */ NULL,
333 /* .pfnRequest = */ NULL,
334 /* .pfnReserved0 = */ NULL,
335 /* .pfnReserved1 = */ NULL,
336 /* .pfnReserved2 = */ NULL,
337 /* .pfnReserved3 = */ NULL,
338 /* .pfnReserved4 = */ NULL,
339 /* .pfnReserved5 = */ NULL,
340 /* .pfnReserved6 = */ NULL,
341 /* .pfnReserved7 = */ NULL,
342#elif defined(IN_RC)
343 /* .pfnConstruct = */ NULL,
344 /* .pfnReserved0 = */ NULL,
345 /* .pfnReserved1 = */ NULL,
346 /* .pfnReserved2 = */ NULL,
347 /* .pfnReserved3 = */ NULL,
348 /* .pfnReserved4 = */ NULL,
349 /* .pfnReserved5 = */ NULL,
350 /* .pfnReserved6 = */ NULL,
351 /* .pfnReserved7 = */ NULL,
352#else
353# error "Not in IN_RING3, IN_RING0 or IN_RC!"
354#endif
355 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
356};
357
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette