VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DevSerialNew.cpp@ 73136

Last change on this file since 73136 was 73135, checked in by vboxsync, 7 years ago

Serial: Split out the generic UART functionality into a separate module so it can be reused.

Add a PCI Express 16 port UART controller emulation based on the Oxford Semiconductor OXPCIe958
PCI Express to octa UART controller (supports chaining two of those together in a single device
to get up to 16 UARTs). This somewhat revives the incomplete and never enabled PCI UART controller
in the old code. Linux detects the device and apparently configures all 16 UARTs but data transfers
were not tested and the code is pretty incomplete still.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.7 KB
Line 
1/* $Id: DevSerialNew.cpp 73135 2018-07-15 16:43:16Z vboxsync $ */
2/** @file
3 * DevSerial - 16550A UART emulation.
4 *
5 * The documentation for this device was taken from the PC16550D spec from TI.
6 */
7
8/*
9 * Copyright (C) 2018 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#define LOG_GROUP LOG_GROUP_DEV_SERIAL
25#include <VBox/vmm/pdmdev.h>
26#include <VBox/vmm/pdmserialifs.h>
27#include <VBox/vmm/vm.h>
28#include <iprt/assert.h>
29#include <iprt/uuid.h>
30#include <iprt/string.h>
31#include <iprt/semaphore.h>
32#include <iprt/critsect.h>
33
34#include "VBoxDD.h"
35#include "UartCore.h"
36
37
38/*********************************************************************************************************************************
39* Defined Constants And Macros *
40*********************************************************************************************************************************/
41
42
43/*********************************************************************************************************************************
44* Structures and Typedefs *
45*********************************************************************************************************************************/
46
47/**
48 * Serial device.
49 */
50typedef struct DEVSERIAL
51{
52 /** Pointer to the device instance - R3 Ptr. */
53 PPDMDEVINSR3 pDevInsR3;
54 /** Pointer to the device instance - R0 Ptr. */
55 PPDMDEVINSR0 pDevInsR0;
56 /** Pointer to the device instance - RC Ptr. */
57 PPDMDEVINSRC pDevInsRC;
58 /** Alignment. */
59 RTRCPTR Alignment0;
60 /** Flag whether the R0 portion of this device is enabled. */
61 bool fR0Enabled;
62 /** Flag whether the RC portion of this device is enabled. */
63 bool fRCEnabled;
64 /** Alignment. */
65 bool afAlignment1[2];
66 /** The IRQ value. */
67 uint8_t uIrq;
68 /** The base I/O port the device is registered at. */
69 RTIOPORT PortBase;
70
71 /** The UART core. */
72 UARTCORE UartCore;
73} DEVSERIAL;
74/** Pointer to the serial device state. */
75typedef DEVSERIAL *PDEVSERIAL;
76
77#ifndef VBOX_DEVICE_STRUCT_TESTCASE
78
79
80/*********************************************************************************************************************************
81* Global Variables *
82*********************************************************************************************************************************/
83
84
85/*********************************************************************************************************************************
86* Internal Functions *
87*********************************************************************************************************************************/
88
89
90PDMBOTHCBDECL(void) serialIrqReq(PPDMDEVINS pDevIns, PUARTCORE pUart, unsigned iLUN, int iLvl)
91{
92 RT_NOREF(pUart, iLUN);
93 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
94 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->uIrq, iLvl);
95}
96
97
98/* -=-=-=-=-=-=-=-=- I/O Port Access Handlers -=-=-=-=-=-=-=-=- */
99
100/**
101 * @callback_method_impl{FNIOMIOPORTOUT}
102 */
103PDMBOTHCBDECL(int) serialIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
104{
105 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
106 RT_NOREF_PV(pvUser);
107
108 return uartRegWrite(&pThis->UartCore, uPort - pThis->PortBase, u32, cb);
109}
110
111
112/**
113 * @callback_method_impl{FNIOMIOPORTIN}
114 */
115PDMBOTHCBDECL(int) serialIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
116{
117 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
118 RT_NOREF_PV(pvUser);
119
120 return uartRegRead(&pThis->UartCore, uPort - pThis->PortBase, pu32, cb);
121}
122
123
124#ifdef IN_RING3
125
126
127/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
128
129/**
130 * @interface_method_impl{PDMDEVREG,pfnRelocate}
131 */
132static DECLCALLBACK(void) serialR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
133{
134 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
135 uartR3Relocate(&pThis->UartCore, offDelta);
136}
137
138
139/**
140 * @interface_method_impl{PDMDEVREG,pfnReset}
141 */
142static DECLCALLBACK(void) serialR3Reset(PPDMDEVINS pDevIns)
143{
144 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
145 uartR3Reset(&pThis->UartCore);
146}
147
148
149/**
150 * @interface_method_impl{PDMDEVREG,pfnAttach}
151 */
152static DECLCALLBACK(int) serialR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
153{
154 RT_NOREF(fFlags);
155 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
156 return uartR3Attach(&pThis->UartCore, iLUN);
157}
158
159
160/**
161 * @interface_method_impl{PDMDEVREG,pfnDetach}
162 */
163static DECLCALLBACK(void) serialR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
164{
165 RT_NOREF(iLUN, fFlags);
166 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
167 uartR3Detach(&pThis->UartCore);
168}
169
170
171/**
172 * @interface_method_impl{PDMDEVREG,pfnDestruct}
173 */
174static DECLCALLBACK(int) serialR3Destruct(PPDMDEVINS pDevIns)
175{
176 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
177 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
178
179 uartR3Destruct(&pThis->UartCore);
180 return VINF_SUCCESS;
181}
182
183
184/**
185 * @interface_method_impl{PDMDEVREG,pfnConstruct}
186 */
187static DECLCALLBACK(int) serialR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
188{
189 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
190 int rc = VINF_SUCCESS;
191
192 Assert(iInstance < 4);
193 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
194
195 /*
196 * Initialize the instance data.
197 * (Do this early or the destructor might choke on something!)
198 */
199 pThis->pDevInsR3 = pDevIns;
200 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
201 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
202
203 /*
204 * Validate and read the configuration.
205 */
206 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0"
207 "IOBase\0"
208 "GCEnabled\0"
209 "R0Enabled\0"
210 "YieldOnLSRRead\0"
211 "Enable16550A\0"
212 ))
213 {
214 AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
215 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
216 }
217
218 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fRCEnabled, true);
219 if (RT_FAILURE(rc))
220 return PDMDEV_SET_ERROR(pDevIns, rc,
221 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
222
223 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
224 if (RT_FAILURE(rc))
225 return PDMDEV_SET_ERROR(pDevIns, rc,
226 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
227
228 bool fYieldOnLSRRead = false;
229 rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &fYieldOnLSRRead, false);
230 if (RT_FAILURE(rc))
231 return PDMDEV_SET_ERROR(pDevIns, rc,
232 N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
233
234 uint8_t uIrq = 0;
235 rc = CFGMR3QueryU8(pCfg, "IRQ", &uIrq);
236 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
237 {
238 /* Provide sensible defaults. */
239 if (iInstance == 0)
240 uIrq = 4;
241 else if (iInstance == 1)
242 uIrq = 3;
243 else
244 AssertReleaseFailed(); /* irq_lvl is undefined. */
245 }
246 else if (RT_FAILURE(rc))
247 return PDMDEV_SET_ERROR(pDevIns, rc,
248 N_("Configuration error: Failed to get the \"IRQ\" value"));
249
250 uint16_t uIoBase = 0;
251 rc = CFGMR3QueryU16(pCfg, "IOBase", &uIoBase);
252 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
253 {
254 if (iInstance == 0)
255 uIoBase = 0x3f8;
256 else if (iInstance == 1)
257 uIoBase = 0x2f8;
258 else
259 AssertReleaseFailed(); /* uIoBase is undefined */
260 }
261 else if (RT_FAILURE(rc))
262 return PDMDEV_SET_ERROR(pDevIns, rc,
263 N_("Configuration error: Failed to get the \"IOBase\" value"));
264
265 bool f16550AEnabled = true;
266 rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &f16550AEnabled, true);
267 if (RT_FAILURE(rc))
268 return PDMDEV_SET_ERROR(pDevIns, rc,
269 N_("Configuration error: Failed to get the \"Enable16550A\" value"));
270
271 pThis->uIrq = uIrq;
272 pThis->PortBase = uIoBase;
273
274 LogRel(("Serial#%d: emulating %s (IOBase: %04x IRQ: %u)\n",
275 pDevIns->iInstance, f16550AEnabled ? "16550A" : "16450", uIoBase, uIrq));
276
277 /*
278 * Init locks, using explicit locking where necessary.
279 */
280 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
281 if (RT_FAILURE(rc))
282 return rc;
283
284 /*
285 * Register the I/O ports.
286 */
287 rc = PDMDevHlpIOPortRegister(pDevIns, uIoBase, 8, 0,
288 serialIoPortWrite, serialIoPortRead,
289 NULL, NULL, "SERIAL");
290 if (RT_FAILURE(rc))
291 return rc;
292
293 PVM pVM = PDMDevHlpGetVM(pDevIns);
294 RTR0PTR pfnSerialIrqReqR0 = NIL_RTR0PTR;
295 RTRCPTR pfnSerialIrqReqRC = NIL_RTRCPTR;
296
297 if (pThis->fRCEnabled)
298 {
299 rc = PDMDevHlpIOPortRegisterRC(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
300 "serialIoPortRead", NULL, NULL, "SERIAL");
301 if ( RT_SUCCESS(rc)
302 && VM_IS_RAW_MODE_ENABLED(pVM))
303 rc = PDMR3LdrGetSymbolRC(pVM, pDevIns->pReg->szRCMod, "serialIrqReq", &pfnSerialIrqReqRC);
304
305 if (RT_FAILURE(rc))
306 return rc;
307 }
308
309 if (pThis->fR0Enabled)
310 {
311 rc = PDMDevHlpIOPortRegisterR0(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
312 "serialIoPortRead", NULL, NULL, "SERIAL");
313 if (RT_SUCCESS(rc))
314 rc = PDMR3LdrGetSymbolR0(pVM, pDevIns->pReg->szR0Mod, "serialIrqReq", &pfnSerialIrqReqR0);
315
316 if (RT_FAILURE(rc))
317 return rc;
318 }
319
320#if 0 /** @todo Later */
321 /*
322 * Saved state.
323 */
324 rc = PDMDevHlpSSMRegister3(pDevIns, SERIAL_SAVED_STATE_VERSION, sizeof (*pThis),
325 serialR3LiveExec, serialR3SaveExec, serialR3LoadExec);
326 if (RT_FAILURE(rc))
327 return rc;
328#endif
329
330
331 /* Init the UART core structure. */
332 rc = uartR3Init(&pThis->UartCore, pDevIns, f16550AEnabled ? UARTTYPE_16550A : UARTTYPE_16450, 0,
333 fYieldOnLSRRead ? UART_CORE_YIELD_ON_LSR_READ : 0, serialIrqReq, pfnSerialIrqReqR0, pfnSerialIrqReqRC);
334
335 serialR3Reset(pDevIns);
336 return VINF_SUCCESS;
337}
338
339
340/**
341 * The device registration structure.
342 */
343const PDMDEVREG g_DeviceSerialPort =
344{
345 /* u32Version */
346 PDM_DEVREG_VERSION,
347 /* szName */
348 "serial",
349 /* szRCMod */
350 "VBoxDDRC.rc",
351 /* szR0Mod */
352 "VBoxDDR0.r0",
353 /* pszDescription */
354 "Serial Communication Port",
355 /* fFlags */
356 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
357 /* fClass */
358 PDM_DEVREG_CLASS_SERIAL,
359 /* cMaxInstances */
360 UINT32_MAX,
361 /* cbInstance */
362 sizeof(DEVSERIAL),
363 /* pfnConstruct */
364 serialR3Construct,
365 /* pfnDestruct */
366 serialR3Destruct,
367 /* pfnRelocate */
368 serialR3Relocate,
369 /* pfnMemSetup */
370 NULL,
371 /* pfnPowerOn */
372 NULL,
373 /* pfnReset */
374 serialR3Reset,
375 /* pfnSuspend */
376 NULL,
377 /* pfnResume */
378 NULL,
379 /* pfnAttach */
380 serialR3Attach,
381 /* pfnDetach */
382 serialR3Detach,
383 /* pfnQueryInterface. */
384 NULL,
385 /* pfnInitComplete */
386 NULL,
387 /* pfnPowerOff */
388 NULL,
389 /* pfnSoftReset */
390 NULL,
391 /* u32VersionEnd */
392 PDM_DEVREG_VERSION
393};
394#endif /* IN_RING3 */
395
396#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

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