VirtualBox

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

Last change on this file since 72117 was 72083, checked in by vboxsync, 7 years ago

Devices/Serial: Updates to the new emulation

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.0 KB
Line 
1/* $Id: DevSerialNew.cpp 72083 2018-05-02 18:04:29Z 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 <iprt/assert.h>
28#include <iprt/uuid.h>
29#include <iprt/string.h>
30#include <iprt/semaphore.h>
31#include <iprt/critsect.h>
32
33#include "VBoxDD.h"
34
35
36/*********************************************************************************************************************************
37* Defined Constants And Macros *
38*********************************************************************************************************************************/
39
40/** The RBR/DLL register index (from the base of the port range). */
41#define UART_REG_RBR_DLL_INDEX 0
42
43/** The THR/DLL register index (from the base of the port range). */
44#define UART_REG_THR_DLL_INDEX 0
45
46/** The IER/DLM register index (from the base of the port range). */
47#define UART_REG_IER_DLM_INDEX 1
48/** Enable received data available interrupt */
49# define UART_REG_IER_ERBFI RT_BIT(0)
50/** Enable transmitter holding register empty interrupt */
51# define UART_REG_IER_ETBEI RT_BIT(1)
52/** Enable receiver line status interrupt */
53# define UART_REG_IER_ELSI RT_BIT(2)
54/** Enable modem status interrupt. */
55# define UART_REG_IER_EDSSI RT_BIT(3)
56/** Mask of writeable bits. */
57# define UART_REG_IER_MASK_WR 0x0f
58
59/** The IIR register index (from the base of the port range). */
60#define UART_REG_IIR_INDEX 2
61/** Interrupt Pending - high means no interrupt pending. */
62# define UART_REG_IIR_IP_NO_INT RT_BIT(0)
63/** Interrupt identification mask. */
64# define UART_REG_IIR_ID_MASK 0x0e
65/** Sets the interrupt identification to the given value. */
66# define UART_REG_IIR_ID_SET(a_Val) (((a_Val) & UART_REG_IIR_ID_MASK) << 1)
67/** Receiver Line Status interrupt. */
68# define UART_REG_IIR_ID_RCL 0x3
69/** Received Data Avalable interrupt. */
70# define UART_REG_IIR_ID_RDA 0x2
71/** Character Timeou Indicator interrupt. */
72# define UART_REG_IIR_ID_CTI 0x6
73/** Transmitter Holding Register Empty interrupt. */
74# define UART_REG_IIR_ID_THRE 0x1
75/** Modem Status interrupt. */
76# define UART_REG_IIR_ID_MS 0x0
77/** FIFOs enabled. */
78# define UART_REG_IIR_FIFOS_EN 0xc0
79
80/** The FCR register index (from the base of the port range). */
81#define UART_REG_FCR_INDEX 2
82/** Enable the TX/RX FIFOs. */
83# define UART_REG_FCR_FIFO_EN RT_BIT(0)
84/** Reset the receive FIFO. */
85# define UART_REG_FCR_RCV_FIFO_RST RT_BIT(1)
86/** Reset the transmit FIFO. */
87# define UART_REG_FCR_XMIT_FIFO_RST RT_BIT(2)
88/** DMA Mode Select. */
89# define UART_REG_FCR_DMA_MODE_SEL RT_BIT(3)
90/** Receiver level interrupt trigger. */
91# define UART_REG_FCR_RCV_LVL_IRQ_MASK 0xc0
92/** Returns the receive level trigger value from the given FCR register. */
93# define UART_REG_FCR_RCV_LVL_IRQ_GET(a_Fcr) (((a_Fcr) & UART_REG_FCR_RCV_LVL_IRQ_MASK) >> 6)
94/** Mask of writeable bits. */
95# define UART_REG_FCR_MASK_WR 0xcf
96
97/** The LCR register index (from the base of the port range). */
98#define UART_REG_LCR_INDEX 3
99/** Word Length Select Mask. */
100# define UART_REG_LCR_WLS_MASK 0x3
101/** Returns the WLS value form the given LCR register value. */
102# define UART_REG_LCR_WLS_GET(a_Lcr) ((a_Lcr) & UART_REG_LCR_WLS_MASK)
103/** Number of stop bits. */
104# define UART_REG_LCR_STB RT_BIT(2)
105/** Parity Enable. */
106# define UART_REG_LCR_PEN RT_BIT(3)
107/** Even Parity. */
108# define UART_REG_LCR_EPS RT_BIT(4)
109/** Stick parity. */
110# define UART_REG_LCR_PAR_STICK RT_BIT(5)
111/** Set Break. */
112# define UART_REG_LCR_BRK_SET RT_BIT(6)
113/** Divisor Latch Access Bit. */
114# define UART_REG_LCR_DLAB RT_BIT(7)
115
116/** The MCR register index (from the base of the port range). */
117#define UART_REG_MCR_INDEX 4
118/** Data Terminal Ready. */
119# define UART_REG_MCR_DTR RT_BIT(0)
120/** Request To Send. */
121# define UART_REG_MCR_RTS RT_BIT(1)
122/** Out1. */
123# define UART_REG_MCR_OUT1 RT_BIT(2)
124/** Out2. */
125# define UART_REG_MCR_OUT2 RT_BIT(3)
126/** Loopback connection. */
127# define UART_REG_MCR_LOOP RT_BIT(4)
128/** Mask of writeable bits. */
129# define UART_REG_MCR_MASK_WR 0x1f
130
131/** The LSR register index (from the base of the port range). */
132#define UART_REG_LSR_INDEX 5
133/** Data Ready. */
134# define UART_REG_LSR_DR RT_BIT(0)
135/** Overrun Error. */
136# define UART_REG_LSR_OE RT_BIT(1)
137/** Parity Error. */
138# define UART_REG_LSR_PE RT_BIT(2)
139/** Framing Error. */
140# define UART_REG_LSR_FE RT_BIT(3)
141/** Break Interrupt. */
142# define UART_REG_LSR_BI RT_BIT(4)
143/** Transmitter Holding Register. */
144# define UART_REG_LSR_THRE RT_BIT(5)
145/** Transmitter Empty. */
146# define UART_REG_LSR_TEMT RT_BIT(6)
147/** Error in receiver FIFO. */
148# define UART_REG_LSR_RCV_FIFO_ERR RT_BIT(7)
149
150/** The MSR register index (from the base of the port range). */
151#define UART_REG_MSR_INDEX 6
152/** Delta Clear to Send. */
153# define UART_REG_MSR_DCTS RT_BIT(0)
154/** Delta Data Set Ready. */
155# define UART_REG_MSR_DDSR RT_BIT(1)
156/** Trailing Edge Ring Indicator. */
157# define UART_REG_MSR_TERI RT_BIT(2)
158/** Delta Data Carrier Detect. */
159# define UART_REG_MSR_DDCD RT_BIT(3)
160/** Clear to Send. */
161# define UART_REG_MSR_CTS RT_BIT(4)
162/** Data Set Ready. */
163# define UART_REG_MSR_DSR RT_BIT(5)
164/** Ring Indicator. */
165# define UART_REG_MSR_RI RT_BIT(6)
166/** Data Carrier Detect. */
167# define UART_REG_MSR_DCD RT_BIT(7)
168
169/** The SCR register index (from the base of the port range). */
170#define UART_REG_SCR_INDEX 7
171
172
173/*********************************************************************************************************************************
174* Structures and Typedefs *
175*********************************************************************************************************************************/
176
177/**
178 * Serial device.
179 *
180 * @implements PDMIBASE
181 * @implements PDMISERIALPORT
182 */
183typedef struct DEVSERIAL
184{
185 /** Access critical section. */
186 PDMCRITSECT CritSect;
187 /** Pointer to the device instance - R3 Ptr. */
188 PPDMDEVINSR3 pDevInsR3;
189 /** Pointer to the device instance - R0 Ptr. */
190 PPDMDEVINSR0 pDevInsR0;
191 /** Pointer to the device instance - RC Ptr. */
192 PPDMDEVINSRC pDevInsRC;
193 /** Alignment. */
194 RTRCPTR Alignment0;
195 /** LUN\#0: The base interface. */
196 PDMIBASE IBase;
197 /** LUN\#0: The serial port interface. */
198 PDMISERIALPORT ISerialPort;
199 /** Pointer to the attached base driver. */
200 R3PTRTYPE(PPDMIBASE) pDrvBase;
201 /** Pointer to the attached serial driver. */
202 R3PTRTYPE(PPDMISERIALCONNECTOR) pDrvSerial;
203 /** Flag whether the R0 portion of this device is enabled. */
204 bool fR0Enabled;
205 /** Flag whether the RC portion of this device is enabled. */
206 bool fRCEnabled;
207 /** Flag whether an 16550A (with FIFO) or a plain 16450 is emulated. */
208 bool f16550AEnabled;
209 /** Flag whether to yield on an guest LSR read. */
210 bool fYieldOnLSRRead;
211 /** The IRQ value. */
212 uint8_t uIrq;
213 /** The base I/O port the device is registered at. */
214 RTIOPORT PortBase;
215
216 /** The divisor register (DLAB = 1). */
217 uint16_t uRegDivisor;
218 /** The Receiver Buffer Register (RBR, DLAB = 0). */
219 uint8_t uRegRbr;
220 /** The Transmitter Holding Register (THR, DLAB = 0). */
221 uint8_t uRegThr;
222 /** The Interrupt Enable Register (IER). */
223 uint8_t uRegIer;
224 /** The Interrupt Identification Register (IIR). */
225 uint8_t uRegIir;
226 /** The FIFO Control Register (FCR). */
227 uint8_t uRegFcr;
228 /** The Line Control Register (LCR). */
229 uint8_t uRegLcr;
230 /** The Modem Control Register (MCR). */
231 uint8_t uRegMcr;
232 /** The Line Status Register (LSR). */
233 uint8_t uRegLsr;
234 /** The Modem Status Register (MSR). */
235 uint8_t uRegMsr;
236 /** The Scratch Register (SCR). */
237 uint8_t uRegScr;
238
239} DEVSERIAL;
240/** Pointer to the serial device state. */
241typedef DEVSERIAL *PDEVSERIAL;
242
243#ifndef VBOX_DEVICE_STRUCT_TESTCASE
244
245
246/*********************************************************************************************************************************
247* Global Variables *
248*********************************************************************************************************************************/
249#ifdef IN_RING3
250/**
251 * String versions of the parity enum.
252 */
253static const char *s_aszParity[] =
254{
255 "INVALID",
256 "NONE",
257 "EVEN",
258 "ODD",
259 "MARK",
260 "SPACE",
261 "INVALID"
262};
263
264
265/**
266 * String versions of the stop bits enum.
267 */
268static const char *s_aszStopBits[] =
269{
270 "INVALID",
271 "1",
272 "1.5",
273 "2",
274 "INVALID"
275};
276#endif
277
278
279/*********************************************************************************************************************************
280* Internal Functions *
281*********************************************************************************************************************************/
282
283
284/**
285 * Updates the IRQ state based on the current device state.
286 *
287 * @returns nothing.
288 * @param pThis The serial port instance.
289 */
290static void serialIrqUpdate(PDEVSERIAL pThis)
291{
292 RT_NOREF(pThis);
293}
294
295
296#ifdef IN_RING3
297/**
298 * Updates the serial port parameters of the attached driver with the current configuration.
299 *
300 * @returns nothing.
301 * @param pThis The serial port instance.
302 */
303static void serialParamsUpdate(PDEVSERIAL pThis)
304{
305 if ( pThis->uRegDivisor != 0
306 && pThis->pDrvSerial)
307 {
308 uint32_t uBps = 115200 / pThis->uRegDivisor; /* This is for PC compatible serial port with a 1.8432 MHz crystal. */
309 unsigned cDataBits = UART_REG_LCR_WLS_GET(pThis->uRegLcr) + 5;
310 PDMSERIALSTOPBITS enmStopBits = PDMSERIALSTOPBITS_ONE;
311 PDMSERIALPARITY enmParity = PDMSERIALPARITY_NONE;
312
313 if (pThis->uRegLcr & UART_REG_LCR_STB)
314 {
315 enmStopBits = cDataBits == 5 ? PDMSERIALSTOPBITS_ONEPOINTFIVE : PDMSERIALSTOPBITS_TWO;
316 }
317
318 if (pThis->uRegLcr & UART_REG_LCR_PEN)
319 {
320 /* Select the correct parity mode based on the even and stick parity bits. */
321 switch (pThis->uRegLcr & (UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK))
322 {
323 case 0:
324 enmParity = PDMSERIALPARITY_ODD;
325 break;
326 case UART_REG_LCR_EPS:
327 enmParity = PDMSERIALPARITY_EVEN;
328 break;
329 case UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK:
330 enmParity = PDMSERIALPARITY_SPACE;
331 break;
332 case UART_REG_LCR_PAR_STICK:
333 enmParity = PDMSERIALPARITY_MARK;
334 break;
335 default:
336 /* We should never get here as all cases where caught earlier. */
337 AssertMsgFailed(("This shouldn't happen at all: %#x\n",
338 pThis->uRegLcr & (UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK)));
339 }
340 }
341
342 LogFlowFunc(("Changing parameters to: %u,%s,%u,%s\n",
343 uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits]));
344
345 int rc = pThis->pDrvSerial->pfnChgParams(pThis->pDrvSerial, uBps, enmParity, cDataBits, enmStopBits);
346 if (RT_FAILURE(rc))
347 LogRelMax(10, ("Serial#%d: Failed to change parameters to %u,%s,%u,%s -> %Rrc\n",
348 pThis->pDevInsR3->iInstance, uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits], rc));
349 }
350}
351
352
353/**
354 * Updates the internal device state with the given PDM status line states.
355 *
356 * @returns nothing.
357 * @param pThis The serial port instance.
358 * @param fStsLines The PDM status line states.
359 */
360static void serialStsLinesUpdate(PDEVSERIAL pThis, uint32_t fStsLines)
361{
362 uint8_t uRegMsrNew = 0; /* The new MSR value. */
363
364 if (fStsLines & PDMISERIALPORT_STS_LINE_DCD)
365 uRegMsrNew |= UART_REG_MSR_DCD;
366 if (fStsLines & PDMISERIALPORT_STS_LINE_RI)
367 uRegMsrNew |= UART_REG_MSR_RI;
368 if (fStsLines & PDMISERIALPORT_STS_LINE_DSR)
369 uRegMsrNew |= UART_REG_MSR_DSR;
370 if (fStsLines & PDMISERIALPORT_STS_LINE_CTS)
371 uRegMsrNew |= UART_REG_MSR_CTS;
372
373 /* Compare current and new states and set remaining bits accordingly. */
374 if ((uRegMsrNew & UART_REG_MSR_CTS) != (pThis->uRegMsr & UART_REG_MSR_CTS))
375 uRegMsrNew |= UART_REG_MSR_DCTS;
376 if ((uRegMsrNew & UART_REG_MSR_DSR) != (pThis->uRegMsr & UART_REG_MSR_DSR))
377 uRegMsrNew |= UART_REG_MSR_DDSR;
378 if ((uRegMsrNew & UART_REG_MSR_RI) != 0 && (pThis->uRegMsr & UART_REG_MSR_RI) == 0)
379 uRegMsrNew |= UART_REG_MSR_TERI;
380 if ((uRegMsrNew & UART_REG_MSR_DCD) != (pThis->uRegMsr & UART_REG_MSR_DCD))
381 uRegMsrNew |= UART_REG_MSR_DDCD;
382
383 pThis->uRegMsr = uRegMsrNew;
384
385 serialIrqUpdate(pThis);
386}
387#endif
388
389
390/**
391 * Write handler for the THR/DLL register (depending on the DLAB bit in LCR).
392 *
393 * @returns VBox status code.
394 * @param pThis The serial port instance.
395 * @param uVal The value to write.
396 */
397DECLINLINE(int) serialRegThrDllWrite(PDEVSERIAL pThis, uint8_t uVal)
398{
399 int rc = VINF_SUCCESS;
400
401 /* A set DLAB causes a write to the lower 8bits of the divisor latch. */
402 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
403 {
404 if (uVal != (pThis->uRegDivisor & 0xff))
405 {
406#ifndef IN_RING3
407 rc = VINF_IOM_R3_IOPORT_WRITE;
408#else
409 pThis->uRegDivisor = (pThis->uRegDivisor & 0xff00) | uVal;
410 serialParamsUpdate(pThis);
411#endif
412 }
413 }
414 else
415 {
416 /** @todo Data transfer (depending on FIFO). */
417 }
418
419 return rc;
420}
421
422
423/**
424 * Write handler for the IER/DLM register (depending on the DLAB bit in LCR).
425 *
426 * @returns VBox status code.
427 * @param pThis The serial port instance.
428 * @param uVal The value to write.
429 */
430DECLINLINE(int) serialRegIerDlmWrite(PDEVSERIAL pThis, uint8_t uVal)
431{
432 int rc = VINF_SUCCESS;
433
434 /* A set DLAB causes a write to the higher 8bits of the divisor latch. */
435 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
436 {
437 if (uVal != (pThis->uRegDivisor & 0xff00) >> 8)
438 {
439#ifndef IN_RING3
440 rc = VINF_IOM_R3_IOPORT_WRITE;
441#else
442 pThis->uRegDivisor = (pThis->uRegDivisor & 0xff) | (uVal << 8);
443 serialParamsUpdate(pThis);
444#endif
445 }
446 }
447 else
448 {
449 pThis->uRegIer = uVal & UART_REG_IER_MASK_WR;
450 serialIrqUpdate(pThis);
451 }
452
453 return rc;
454}
455
456
457/**
458 * Write handler for the FCR register.
459 *
460 * @returns VBox status code.
461 * @param pThis The serial port instance.
462 * @param uVal The value to write.
463 */
464DECLINLINE(int) serialRegFcrWrite(PDEVSERIAL pThis, uint8_t uVal)
465{
466 int rc = VINF_SUCCESS;
467
468 RT_NOREF(uVal);
469 if (pThis->f16550AEnabled)
470 {
471 /** @todo */
472 }
473
474 return rc;
475}
476
477
478/**
479 * Write handler for the LCR register.
480 *
481 * @returns VBox status code.
482 * @param pThis The serial port instance.
483 * @param uVal The value to write.
484 */
485DECLINLINE(int) serialRegLcrWrite(PDEVSERIAL pThis, uint8_t uVal)
486{
487 int rc = VINF_SUCCESS;
488
489 /* Any change except the DLAB bit causes a switch to R3. */
490 if ((pThis->uRegLcr & ~UART_REG_LCR_DLAB) != (uVal & ~UART_REG_LCR_DLAB))
491 {
492#ifndef IN_RING3
493 rc = VINF_IOM_R3_IOPORT_WRITE;
494#else
495 /* Check whether the BREAK bit changed before updating the LCR value. */
496 bool fBrkEn = RT_BOOL(uVal & UART_REG_LCR_BRK_SET);
497 bool fBrkChg = fBrkEn != RT_BOOL(pThis->uRegLcr & UART_REG_LCR_BRK_SET);
498 pThis->uRegLcr = uVal;
499 serialParamsUpdate(pThis);
500
501 if ( fBrkChg
502 && pThis->pDrvSerial)
503 pThis->pDrvSerial->pfnChgBrk(pThis->pDrvSerial, fBrkEn);
504#endif
505 }
506 else
507 pThis->uRegLcr = uVal;
508
509 return rc;
510}
511
512
513/**
514 * Write handler for the MCR register.
515 *
516 * @returns VBox status code.
517 * @param pThis The serial port instance.
518 * @param uVal The value to write.
519 */
520DECLINLINE(int) serialRegMcrWrite(PDEVSERIAL pThis, uint8_t uVal)
521{
522 int rc = VINF_SUCCESS;
523
524 uVal &= UART_REG_MCR_MASK_WR;
525 if (pThis->uRegMcr != uVal)
526 {
527#ifndef IN_RING3
528 rc = VINF_IOM_R3_IOPORT_WRITE;
529#else
530 /** @todo Loopback mode handling (setting RTS, DTR to high looping everything to MSR). */
531 pThis->uRegMcr = uVal;
532 if (pThis->pDrvSerial)
533 pThis->pDrvSerial->pfnChgModemLines(pThis->pDrvSerial,
534 RT_BOOL(uVal & UART_REG_MCR_RTS),
535 RT_BOOL(uVal & UART_REG_MCR_DTR));
536#endif
537 }
538
539 return rc;
540}
541
542
543/**
544 * Read handler for the RBR/DLL register (depending on the DLAB bit in LCR).
545 *
546 * @returns VBox status code.
547 * @param pThis The serial port instance.
548 * @param puVal Where to store the read value on success.
549 */
550DECLINLINE(int) serialRegRbrDllRead(PDEVSERIAL pThis, uint32_t *puVal)
551{
552 int rc = VINF_SUCCESS;
553
554 /* A set DLAB causes a read from the lower 8bits of the divisor latch. */
555 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
556 *puVal = pThis->uRegDivisor & 0xff;
557 else
558 {
559 /** @todo Data transfer (depending on FIFO). */
560 }
561
562 return rc;
563}
564
565
566/**
567 * Read handler for the IER/DLM register (depending on the DLAB bit in LCR).
568 *
569 * @returns VBox status code.
570 * @param pThis The serial port instance.
571 * @param puVal Where to store the read value on success.
572 */
573DECLINLINE(int) serialRegIerDlmRead(PDEVSERIAL pThis, uint32_t *puVal)
574{
575 int rc = VINF_SUCCESS;
576
577 /* A set DLAB causes a read from the upper 8bits of the divisor latch. */
578 if (pThis->uRegLcr & UART_REG_LCR_DLAB)
579 *puVal = (pThis->uRegDivisor & 0xff00) >> 8;
580 else
581 *puVal = pThis->uRegIer;
582
583 return rc;
584}
585
586
587/**
588 * Read handler for the IIR register.
589 *
590 * @returns VBox status code.
591 * @param pThis The serial port instance.
592 * @param puVal Where to store the read value on success.
593 */
594DECLINLINE(int) serialRegIirRead(PDEVSERIAL pThis, uint32_t *puVal)
595{
596 int rc = VINF_SUCCESS;
597
598 RT_NOREF(pThis, puVal);
599
600 return rc;
601}
602
603
604/**
605 * Read handler for the LSR register.
606 *
607 * @returns VBox status code.
608 * @param pThis The serial port instance.
609 * @param puVal Where to store the read value on success.
610 */
611DECLINLINE(int) serialRegLsrRead(PDEVSERIAL pThis, uint32_t *puVal)
612{
613 int rc = VINF_SUCCESS;
614
615 RT_NOREF(pThis, puVal);
616
617 return rc;
618}
619
620
621/**
622 * Read handler for the MSR register.
623 *
624 * @returns VBox status code.
625 * @param pThis The serial port instance.
626 * @param puVal Where to store the read value on success.
627 */
628DECLINLINE(int) serialRegMsrRead(PDEVSERIAL pThis, uint32_t *puVal)
629{
630 int rc = VINF_SUCCESS;
631
632 RT_NOREF(pThis, puVal);
633
634 return rc;
635}
636
637
638/* -=-=-=-=-=-=-=-=- I/O Port Access Handlers -=-=-=-=-=-=-=-=- */
639
640/**
641 * @callback_method_impl{FNIOMIOPORTOUT}
642 */
643PDMBOTHCBDECL(int) serialIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
644{
645 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
646 Assert(PDMCritSectIsOwner(&pThis->CritSect));
647 RT_NOREF_PV(pvUser);
648
649 AssertMsgReturn(cb == 1, ("uPort=%#x cb=%d u32=%#x\n", uPort, cb, u32), VINF_SUCCESS);
650
651 int rc = VINF_SUCCESS;
652 uint8_t uVal = (uint8_t)u32;
653 switch (uPort & 0x7)
654 {
655 case UART_REG_THR_DLL_INDEX:
656 rc = serialRegThrDllWrite(pThis, uVal);
657 break;
658 case UART_REG_IER_DLM_INDEX:
659 rc = serialRegIerDlmWrite(pThis, uVal);
660 break;
661 case UART_REG_FCR_INDEX:
662 rc = serialRegFcrWrite(pThis, uVal);
663 break;
664 case UART_REG_LCR_INDEX:
665 rc = serialRegLcrWrite(pThis, uVal);
666 break;
667 case UART_REG_MCR_INDEX:
668 rc = serialRegMcrWrite(pThis, uVal);
669 break;
670 case UART_REG_SCR_INDEX:
671 pThis->uRegScr = u32;
672 break;
673 default:
674 break;
675 }
676
677 return rc;
678}
679
680
681/**
682 * @callback_method_impl{FNIOMIOPORTIN}
683 */
684PDMBOTHCBDECL(int) serialIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
685{
686 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
687 Assert(PDMCritSectIsOwner(&pThis->CritSect));
688 RT_NOREF_PV(pvUser);
689
690 if (cb != 1)
691 return VERR_IOM_IOPORT_UNUSED;
692
693 int rc = VINF_SUCCESS;
694 switch (uPort & 0x7)
695 {
696 case UART_REG_RBR_DLL_INDEX:
697 rc = serialRegRbrDllRead(pThis, pu32);
698 break;
699 case UART_REG_IER_DLM_INDEX:
700 rc = serialRegIerDlmRead(pThis, pu32);
701 break;
702 case UART_REG_IIR_INDEX:
703 rc = serialRegIirRead(pThis, pu32);
704 break;
705 case UART_REG_LCR_INDEX:
706 *pu32 = pThis->uRegLcr;
707 break;
708 case UART_REG_MCR_INDEX:
709 *pu32 = pThis->uRegMcr;
710 break;
711 case UART_REG_LSR_INDEX:
712 rc = serialRegLsrRead(pThis, pu32);
713 break;
714 case UART_REG_MSR_INDEX:
715 rc = serialRegMsrRead(pThis, pu32);
716 break;
717 case UART_REG_SCR_INDEX:
718 *pu32 = pThis->uRegScr;
719 break;
720 default:
721 rc = VERR_IOM_IOPORT_UNUSED;
722 }
723
724 return rc;
725}
726
727
728#ifdef IN_RING3
729
730/* -=-=-=-=-=-=-=-=- PDMISERIALPORT on LUN#0 -=-=-=-=-=-=-=-=- */
731
732static DECLCALLBACK(int) serialDataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
733{
734 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
735
736 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
737 RT_NOREF(cbAvail);
738 PDMCritSectLeave(&pThis->CritSect);
739 return VERR_NOT_IMPLEMENTED;
740}
741
742static DECLCALLBACK(int) serialReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
743{
744 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
745
746 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
747 /** @todo */
748 RT_NOREF(pvBuf, cbRead, pcbRead);
749 PDMCritSectLeave(&pThis->CritSect);
750 return VERR_NOT_IMPLEMENTED;
751}
752
753static DECLCALLBACK(int) serialNotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
754{
755 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
756
757 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
758 serialStsLinesUpdate(pThis, fNewStatusLines);
759 PDMCritSectLeave(&pThis->CritSect);
760 return VINF_SUCCESS;
761}
762
763static DECLCALLBACK(int) serialNotifyBrk(PPDMISERIALPORT pInterface)
764{
765 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
766
767 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
768 /** @todo */
769 PDMCritSectLeave(&pThis->CritSect);
770 return VERR_NOT_IMPLEMENTED;
771}
772
773
774/* -=-=-=-=-=-=-=-=- PDMIBASE on LUN#0 -=-=-=-=-=-=-=-=- */
775
776/**
777 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
778 */
779static DECLCALLBACK(void *) serialR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
780{
781 PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, IBase);
782 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
783 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALPORT, &pThis->ISerialPort);
784 return NULL;
785}
786
787
788/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
789
790/**
791 * @interface_method_impl{PDMDEVREG,pfnRelocate}
792 */
793static DECLCALLBACK(void) serialR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
794{
795 RT_NOREF(offDelta);
796 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
797
798 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
799}
800
801
802/**
803 * @interface_method_impl{PDMDEVREG,pfnReset}
804 */
805static DECLCALLBACK(void) serialR3Reset(PPDMDEVINS pDevIns)
806{
807 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
808
809 pThis->uRegDivisor = 0x0c; /* Default to 9600 Baud. */
810 pThis->uRegRbr = 0;
811 pThis->uRegThr = 0;
812 pThis->uRegIer = 0;
813 pThis->uRegIir = UART_REG_IIR_IP_NO_INT;
814 pThis->uRegFcr = 0;
815 pThis->uRegLcr = 0; /* 5 data bits, no parity, 1 stop bit. */
816 pThis->uRegMcr = 0;
817 pThis->uRegLsr = UART_REG_LSR_THRE | UART_REG_LSR_TEMT;
818 pThis->uRegMsr = 0; /* Updated below. */
819 pThis->uRegScr = 0;
820
821 /** @todo Clear FIFOs. */
822 serialParamsUpdate(pThis);
823 serialIrqUpdate(pThis);
824
825 if (pThis->pDrvSerial)
826 {
827 uint32_t fStsLines = 0;
828 int rc = pThis->pDrvSerial->pfnQueryStsLines(pThis->pDrvSerial, &fStsLines);
829 if (RT_SUCCESS(rc))
830 serialStsLinesUpdate(pThis, fStsLines);
831 else
832 LogRel(("Serial#%d: Failed to query status line status with %Rrc during reset\n",
833 pThis->pDevInsR3->iInstance, rc));
834 }
835}
836
837
838/**
839 * @interface_method_impl{PDMDEVREG,pfnAttach}
840 */
841static DECLCALLBACK(int) serialR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
842{
843 RT_NOREF(iLUN, fFlags);
844 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
845
846 int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
847 if (RT_SUCCESS(rc))
848 {
849 pThis->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMISERIALCONNECTOR);
850 if (!pThis->pDrvSerial)
851 {
852 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", pDevIns->iInstance));
853 return VERR_PDM_MISSING_INTERFACE;
854 }
855 }
856 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
857 {
858 pThis->pDrvBase = NULL;
859 pThis->pDrvSerial = NULL;
860 rc = VINF_SUCCESS;
861 LogRel(("Serial#%d: no unit\n", pDevIns->iInstance));
862 }
863 else /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
864 LogRel(("Serial#%d: Failed to attach to serial driver. rc=%Rrc\n", pDevIns->iInstance, rc));
865
866 return rc;
867}
868
869
870/**
871 * @interface_method_impl{PDMDEVREG,pfnDetach}
872 */
873static DECLCALLBACK(void) serialR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
874{
875 RT_NOREF(iLUN, fFlags);
876 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
877
878 /* Zero out important members. */
879 pThis->pDrvBase = NULL;
880 pThis->pDrvSerial = NULL;
881}
882
883
884/**
885 * @interface_method_impl{PDMDEVREG,pfnDestruct}
886 */
887static DECLCALLBACK(int) serialR3Destruct(PPDMDEVINS pDevIns)
888{
889 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
890 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
891
892 PDMR3CritSectDelete(&pThis->CritSect);
893 return VINF_SUCCESS;
894}
895
896
897/**
898 * @interface_method_impl{PDMDEVREG,pfnConstruct}
899 */
900static DECLCALLBACK(int) serialR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
901{
902 PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
903 int rc = VINF_SUCCESS;
904
905 Assert(iInstance < 4);
906 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
907
908 /*
909 * Initialize the instance data.
910 * (Do this early or the destructor might choke on something!)
911 */
912 pThis->pDevInsR3 = pDevIns;
913 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
914 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
915
916 /* IBase */
917 pThis->IBase.pfnQueryInterface = serialR3QueryInterface;
918
919 /* ISerialPort */
920 pThis->ISerialPort.pfnDataAvailRdrNotify = serialDataAvailRdrNotify;
921 pThis->ISerialPort.pfnReadWr = serialReadWr;
922 pThis->ISerialPort.pfnNotifyStsLinesChanged = serialNotifyStsLinesChanged;
923 pThis->ISerialPort.pfnNotifyBrk = serialNotifyBrk;
924
925 /*
926 * Validate and read the configuration.
927 */
928 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0"
929 "IOBase\0"
930 "GCEnabled\0"
931 "R0Enabled\0"
932 "YieldOnLSRRead\0"
933 "Enable16550A\0"
934 ))
935 {
936 AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
937 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
938 }
939
940 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fRCEnabled, true);
941 if (RT_FAILURE(rc))
942 return PDMDEV_SET_ERROR(pDevIns, rc,
943 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
944
945 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
946 if (RT_FAILURE(rc))
947 return PDMDEV_SET_ERROR(pDevIns, rc,
948 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
949
950 rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &pThis->fYieldOnLSRRead, false);
951 if (RT_FAILURE(rc))
952 return PDMDEV_SET_ERROR(pDevIns, rc,
953 N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
954
955 uint8_t uIrq = 0;
956 rc = CFGMR3QueryU8(pCfg, "IRQ", &uIrq);
957 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
958 {
959 /* Provide sensible defaults. */
960 if (iInstance == 0)
961 uIrq = 4;
962 else if (iInstance == 1)
963 uIrq = 3;
964 else
965 AssertReleaseFailed(); /* irq_lvl is undefined. */
966 }
967 else if (RT_FAILURE(rc))
968 return PDMDEV_SET_ERROR(pDevIns, rc,
969 N_("Configuration error: Failed to get the \"IRQ\" value"));
970
971 uint16_t uIoBase = 0;
972 rc = CFGMR3QueryU16(pCfg, "IOBase", &uIoBase);
973 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
974 {
975 if (iInstance == 0)
976 uIoBase = 0x3f8;
977 else if (iInstance == 1)
978 uIoBase = 0x2f8;
979 else
980 AssertReleaseFailed(); /* uIoBase is undefined */
981 }
982 else if (RT_FAILURE(rc))
983 return PDMDEV_SET_ERROR(pDevIns, rc,
984 N_("Configuration error: Failed to get the \"IOBase\" value"));
985
986 rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &pThis->f16550AEnabled, true);
987 if (RT_FAILURE(rc))
988 return PDMDEV_SET_ERROR(pDevIns, rc,
989 N_("Configuration error: Failed to get the \"Enable16550A\" value"));
990
991 pThis->uIrq = uIrq;
992 pThis->PortBase = uIoBase;
993
994 LogRel(("Serial#%d: emulating %s (IOBase: %04x IRQ: %u)\n",
995 pDevIns->iInstance, pThis->f16550AEnabled ? "16550A" : "16450", uIoBase, uIrq));
996
997 /*
998 * Initialize critical section and the semaphore. Change the default
999 * critical section to ours so that TM and IOM will enter it before
1000 * calling us.
1001 *
1002 * Note! This must of be done BEFORE creating timers, registering I/O ports
1003 * and other things which might pick up the default CS or end up
1004 * calling back into the device.
1005 */
1006 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%d", iInstance);
1007 AssertRCReturn(rc, rc);
1008
1009 rc = PDMDevHlpSetDeviceCritSect(pDevIns, &pThis->CritSect);
1010 AssertRCReturn(rc, rc);
1011
1012 /*
1013 * Register the I/O ports.
1014 */
1015 rc = PDMDevHlpIOPortRegister(pDevIns, uIoBase, 8, 0,
1016 serialIoPortWrite, serialIoPortRead,
1017 NULL, NULL, "SERIAL");
1018 if (RT_FAILURE(rc))
1019 return rc;
1020
1021 if (pThis->fRCEnabled)
1022 {
1023 rc = PDMDevHlpIOPortRegisterRC(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
1024 "serialIoPortRead", NULL, NULL, "SERIAL");
1025 if (RT_FAILURE(rc))
1026 return rc;
1027 }
1028
1029 if (pThis->fR0Enabled)
1030 {
1031 rc = PDMDevHlpIOPortRegisterR0(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
1032 "serialIoPortRead", NULL, NULL, "SERIAL");
1033 if (RT_FAILURE(rc))
1034 return rc;
1035 }
1036
1037#if 0 /** @todo Later */
1038 /*
1039 * Saved state.
1040 */
1041 rc = PDMDevHlpSSMRegister3(pDevIns, SERIAL_SAVED_STATE_VERSION, sizeof (*pThis),
1042 serialR3LiveExec, serialR3SaveExec, serialR3LoadExec);
1043 if (RT_FAILURE(rc))
1044 return rc;
1045#endif
1046
1047 /*
1048 * Attach the char driver and get the interfaces.
1049 */
1050 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial");
1051 if (RT_SUCCESS(rc))
1052 {
1053 pThis->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMISERIALCONNECTOR);
1054 if (!pThis->pDrvSerial)
1055 {
1056 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", iInstance));
1057 return VERR_PDM_MISSING_INTERFACE;
1058 }
1059 }
1060 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1061 {
1062 pThis->pDrvBase = NULL;
1063 pThis->pDrvSerial = NULL;
1064 LogRel(("Serial#%d: no unit\n", iInstance));
1065 }
1066 else
1067 {
1068 AssertLogRelMsgFailed(("Serial#%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
1069 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1070 return rc;
1071 }
1072
1073 return VINF_SUCCESS;
1074}
1075
1076
1077/**
1078 * The device registration structure.
1079 */
1080const PDMDEVREG g_DeviceSerialPort =
1081{
1082 /* u32Version */
1083 PDM_DEVREG_VERSION,
1084 /* szName */
1085 "serial",
1086 /* szRCMod */
1087 "VBoxDDRC.rc",
1088 /* szR0Mod */
1089 "VBoxDDR0.r0",
1090 /* pszDescription */
1091 "Serial Communication Port",
1092 /* fFlags */
1093 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1094 /* fClass */
1095 PDM_DEVREG_CLASS_SERIAL,
1096 /* cMaxInstances */
1097 UINT32_MAX,
1098 /* cbInstance */
1099 sizeof(DEVSERIAL),
1100 /* pfnConstruct */
1101 serialR3Construct,
1102 /* pfnDestruct */
1103 serialR3Destruct,
1104 /* pfnRelocate */
1105 serialR3Relocate,
1106 /* pfnMemSetup */
1107 NULL,
1108 /* pfnPowerOn */
1109 NULL,
1110 /* pfnReset */
1111 serialR3Reset,
1112 /* pfnSuspend */
1113 NULL,
1114 /* pfnResume */
1115 NULL,
1116 /* pfnAttach */
1117 serialR3Attach,
1118 /* pfnDetach */
1119 serialR3Detach,
1120 /* pfnQueryInterface. */
1121 NULL,
1122 /* pfnInitComplete */
1123 NULL,
1124 /* pfnPowerOff */
1125 NULL,
1126 /* pfnSoftReset */
1127 NULL,
1128 /* u32VersionEnd */
1129 PDM_DEVREG_VERSION
1130};
1131#endif /* IN_RING3 */
1132
1133#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
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