VirtualBox

Changeset 73135 in vbox for trunk/src/VBox/Devices/Serial


Ignore:
Timestamp:
Jul 15, 2018 4:43:16 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
123723
Message:

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.

Location:
trunk/src/VBox/Devices/Serial
Files:
2 added
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Serial/DevSerialNew.cpp

    r72203 r73135  
    2525#include <VBox/vmm/pdmdev.h>
    2626#include <VBox/vmm/pdmserialifs.h>
     27#include <VBox/vmm/vm.h>
    2728#include <iprt/assert.h>
    2829#include <iprt/uuid.h>
     
    3233
    3334#include "VBoxDD.h"
     35#include "UartCore.h"
    3436
    3537
     
    3840*********************************************************************************************************************************/
    3941
    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) << 1) & UART_REG_IIR_ID_MASK)
    67 /** Receiver Line Status interrupt. */
    68 #  define UART_REG_IIR_ID_RCL                0x3
    69 /** Received Data Available 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 /** Bits relevant for checking whether the interrupt status has changed. */
    80 # define UART_REG_IIR_CHANGED_MASK           0x0f
    81 
    82 /** The FCR register index (from the base of the port range). */
    83 #define UART_REG_FCR_INDEX                   2
    84 /** Enable the TX/RX FIFOs. */
    85 # define UART_REG_FCR_FIFO_EN                RT_BIT(0)
    86 /** Reset the receive FIFO. */
    87 # define UART_REG_FCR_RCV_FIFO_RST           RT_BIT(1)
    88 /** Reset the transmit FIFO. */
    89 # define UART_REG_FCR_XMIT_FIFO_RST          RT_BIT(2)
    90 /** DMA Mode Select. */
    91 # define UART_REG_FCR_DMA_MODE_SEL           RT_BIT(3)
    92 /** Receiver level interrupt trigger. */
    93 # define UART_REG_FCR_RCV_LVL_IRQ_MASK       0xc0
    94 /** Returns the receive level trigger value from the given FCR register. */
    95 # define UART_REG_FCR_RCV_LVL_IRQ_GET(a_Fcr) (((a_Fcr) & UART_REG_FCR_RCV_LVL_IRQ_MASK) >> 6)
    96 /** RCV Interrupt trigger level - 1 byte. */
    97 # define UART_REG_FCR_RCV_LVL_IRQ_1          0x0
    98 /** RCV Interrupt trigger level - 4 bytes. */
    99 # define UART_REG_FCR_RCV_LVL_IRQ_4          0x1
    100 /** RCV Interrupt trigger level - 8 bytes. */
    101 # define UART_REG_FCR_RCV_LVL_IRQ_8          0x2
    102 /** RCV Interrupt trigger level - 14 bytes. */
    103 # define UART_REG_FCR_RCV_LVL_IRQ_14         0x3
    104 /** Mask of writeable bits. */
    105 # define UART_REG_FCR_MASK_WR                0xcf
    106 /** Mask of sticky bits. */
    107 # define UART_REG_FCR_MASK_STICKY            0xc9
    108 
    109 /** The LCR register index (from the base of the port range). */
    110 #define UART_REG_LCR_INDEX                   3
    111 /** Word Length Select Mask. */
    112 # define UART_REG_LCR_WLS_MASK               0x3
    113 /** Returns the WLS value form the given LCR register value. */
    114 # define UART_REG_LCR_WLS_GET(a_Lcr)         ((a_Lcr) & UART_REG_LCR_WLS_MASK)
    115 /** Number of stop bits. */
    116 # define UART_REG_LCR_STB                    RT_BIT(2)
    117 /** Parity Enable. */
    118 # define UART_REG_LCR_PEN                    RT_BIT(3)
    119 /** Even Parity. */
    120 # define UART_REG_LCR_EPS                    RT_BIT(4)
    121 /** Stick parity. */
    122 # define UART_REG_LCR_PAR_STICK              RT_BIT(5)
    123 /** Set Break. */
    124 # define UART_REG_LCR_BRK_SET                RT_BIT(6)
    125 /** Divisor Latch Access Bit. */
    126 # define UART_REG_LCR_DLAB                   RT_BIT(7)
    127 
    128 /** The MCR register index (from the base of the port range). */
    129 #define UART_REG_MCR_INDEX                   4
    130 /** Data Terminal Ready. */
    131 # define UART_REG_MCR_DTR                    RT_BIT(0)
    132 /** Request To Send. */
    133 # define UART_REG_MCR_RTS                    RT_BIT(1)
    134 /** Out1. */
    135 # define UART_REG_MCR_OUT1                   RT_BIT(2)
    136 /** Out2. */
    137 # define UART_REG_MCR_OUT2                   RT_BIT(3)
    138 /** Loopback connection. */
    139 # define UART_REG_MCR_LOOP                   RT_BIT(4)
    140 /** Mask of writeable bits. */
    141 # define UART_REG_MCR_MASK_WR                0x1f
    142 
    143 /** The LSR register index (from the base of the port range). */
    144 #define UART_REG_LSR_INDEX                   5
    145 /** Data Ready. */
    146 # define UART_REG_LSR_DR                     RT_BIT(0)
    147 /** Overrun Error. */
    148 # define UART_REG_LSR_OE                     RT_BIT(1)
    149 /** Parity Error. */
    150 # define UART_REG_LSR_PE                     RT_BIT(2)
    151 /** Framing Error. */
    152 # define UART_REG_LSR_FE                     RT_BIT(3)
    153 /** Break Interrupt. */
    154 # define UART_REG_LSR_BI                     RT_BIT(4)
    155 /** Transmitter Holding Register. */
    156 # define UART_REG_LSR_THRE                   RT_BIT(5)
    157 /** Transmitter Empty. */
    158 # define UART_REG_LSR_TEMT                   RT_BIT(6)
    159 /** Error in receiver FIFO. */
    160 # define UART_REG_LSR_RCV_FIFO_ERR           RT_BIT(7)
    161 /** The bits to check in this register when checking for the RCL interrupt. */
    162 # define UART_REG_LSR_BITS_IIR_RCL           0x1e
    163 
    164 /** The MSR register index (from the base of the port range). */
    165 #define UART_REG_MSR_INDEX                   6
    166 /** Delta Clear to Send. */
    167 # define UART_REG_MSR_DCTS                   RT_BIT(0)
    168 /** Delta Data Set Ready. */
    169 # define UART_REG_MSR_DDSR                   RT_BIT(1)
    170 /** Trailing Edge Ring Indicator. */
    171 # define UART_REG_MSR_TERI                   RT_BIT(2)
    172 /** Delta Data Carrier Detect. */
    173 # define UART_REG_MSR_DDCD                   RT_BIT(3)
    174 /** Clear to Send. */
    175 # define UART_REG_MSR_CTS                    RT_BIT(4)
    176 /** Data Set Ready. */
    177 # define UART_REG_MSR_DSR                    RT_BIT(5)
    178 /** Ring Indicator. */
    179 # define UART_REG_MSR_RI                     RT_BIT(6)
    180 /** Data Carrier Detect. */
    181 # define UART_REG_MSR_DCD                    RT_BIT(7)
    182 /** The bits to check in this register when checking for the MS interrupt. */
    183 # define UART_REG_MSR_BITS_IIR_MS            0x0f
    184 
    185 /** The SCR register index (from the base of the port range). */
    186 #define UART_REG_SCR_INDEX                   7
    187 
    188 /** Set the specified bits in the given register. */
    189 #define UART_REG_SET(a_Reg, a_Set)           ((a_Reg) |= (a_Set))
    190 /** Clear the specified bits in the given register. */
    191 #define UART_REG_CLR(a_Reg, a_Clr)           ((a_Reg) &= ~(a_Clr))
    192 
    193 /** Size of a FIFO. */
    194 #define UART_FIFO_LENGTH                     16
    195 
    19642
    19743/*********************************************************************************************************************************
     
    20046
    20147/**
    202  * Serial FIFO.
    203  */
    204 typedef struct SERIALFIFO
    205 {
    206     /** Current amount of bytes used. */
    207     uint8_t                         cbUsed;
    208     /** Next index to write to. */
    209     uint8_t                         offWrite;
    210     /** Next index to read from. */
    211     uint8_t                         offRead;
    212     /** The interrupt trigger level (only used for the receive FIFO). */
    213     uint8_t                         cbItl;
    214     /** The data in the FIFO. */
    215     uint8_t                         abBuf[UART_FIFO_LENGTH];
    216 } SERIALFIFO;
    217 /** Pointer to a FIFO. */
    218 typedef SERIALFIFO *PSERIALFIFO;
    219 
    220 
    221 /**
    22248 * Serial device.
    223  *
    224  * @implements  PDMIBASE
    225  * @implements  PDMISERIALPORT
    22649 */
    22750typedef struct DEVSERIAL
    22851{
    229     /** Access critical section. */
    230     PDMCRITSECT                     CritSect;
    23152    /** Pointer to the device instance - R3 Ptr. */
    23253    PPDMDEVINSR3                    pDevInsR3;
     
    23758    /** Alignment. */
    23859    RTRCPTR                         Alignment0;
    239     /** LUN\#0: The base interface. */
    240     PDMIBASE                        IBase;
    241     /** LUN\#0: The serial port interface. */
    242     PDMISERIALPORT                  ISerialPort;
    243     /** Pointer to the attached base driver. */
    244     R3PTRTYPE(PPDMIBASE)            pDrvBase;
    245     /** Pointer to the attached serial driver. */
    246     R3PTRTYPE(PPDMISERIALCONNECTOR) pDrvSerial;
    24760    /** Flag whether the R0 portion of this device is enabled. */
    24861    bool                            fR0Enabled;
    24962    /** Flag whether the RC portion of this device is enabled. */
    25063    bool                            fRCEnabled;
    251     /** Flag whether an 16550A (with FIFO) or a plain 16450 is emulated. */
    252     bool                            f16550AEnabled;
    253     /** Flag whether to yield on an guest LSR read. */
    254     bool                            fYieldOnLSRRead;
     64    /** Alignment. */
     65    bool                            afAlignment1[2];
    25566    /** The IRQ value. */
    25667    uint8_t                         uIrq;
     
    25869    RTIOPORT                        PortBase;
    25970
    260     /** The divisor register (DLAB = 1). */
    261     uint16_t                        uRegDivisor;
    262     /** The Receiver Buffer Register (RBR, DLAB = 0). */
    263     uint8_t                         uRegRbr;
    264     /** The Transmitter Holding Register (THR, DLAB = 0). */
    265     uint8_t                         uRegThr;
    266     /** The Interrupt Enable Register (IER, DLAB = 0). */
    267     uint8_t                         uRegIer;
    268     /** The Interrupt Identification Register (IIR). */
    269     uint8_t                         uRegIir;
    270     /** The FIFO Control Register (FCR). */
    271     uint8_t                         uRegFcr;
    272     /** The Line Control Register (LCR). */
    273     uint8_t                         uRegLcr;
    274     /** The Modem Control Register (MCR). */
    275     uint8_t                         uRegMcr;
    276     /** The Line Status Register (LSR). */
    277     uint8_t                         uRegLsr;
    278     /** The Modem Status Register (MSR). */
    279     uint8_t                         uRegMsr;
    280     /** The Scratch Register (SCR). */
    281     uint8_t                         uRegScr;
    282 
    283     /** The transmit FIFO. */
    284     SERIALFIFO                      FifoXmit;
    285     /** The receive FIFO. */
    286     SERIALFIFO                      FifoRecv;
    287 
    288     /** Number of bytes available for reading from the layer below. */
    289     volatile uint32_t               cbAvailRdr;
    290 
     71    /** The UART core. */
     72    UARTCORE                        UartCore;
    29173} DEVSERIAL;
    29274/** Pointer to the serial device state. */
     
    29981*   Global Variables                                                                                                             *
    30082*********************************************************************************************************************************/
     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
    301124#ifdef IN_RING3
    302 /**
    303  * String versions of the parity enum.
    304  */
    305 static const char *s_aszParity[] =
    306 {
    307     "INVALID",
    308     "NONE",
    309     "EVEN",
    310     "ODD",
    311     "MARK",
    312     "SPACE",
    313     "INVALID"
    314 };
    315 
    316 
    317 /**
    318  * String versions of the stop bits enum.
    319  */
    320 static const char *s_aszStopBits[] =
    321 {
    322     "INVALID",
    323     "1",
    324     "1.5",
    325     "2",
    326     "INVALID"
    327 };
    328 #endif
    329 
    330 
    331 /*********************************************************************************************************************************
    332 *   Internal Functions                                                                                                           *
    333 *********************************************************************************************************************************/
    334 
    335 
    336 /**
    337  * Updates the IRQ state based on the current device state.
    338  *
    339  * @returns nothing.
    340  * @param   pThis               The serial port instance.
    341  */
    342 static void serialIrqUpdate(PDEVSERIAL pThis)
    343 {
    344     LogFlowFunc(("pThis=%#p\n", pThis));
    345 
    346     /*
    347      * The interrupt uses a priority scheme, only the interrupt with the
    348      * highest priority is indicated in the interrupt identification register.
    349      *
    350      * The priorities are as follows (high to low):
    351      *      * Receiver line status
    352      *      * Received data available
    353      *      * Character timeout indication (only in FIFO mode).
    354      *      * Transmitter holding register empty
    355      *      * Modem status change.
    356      */
    357     uint8_t uRegIirNew = UART_REG_IIR_IP_NO_INT;
    358     if (   (pThis->uRegLsr & UART_REG_LSR_BITS_IIR_RCL)
    359         && (pThis->uRegIer & UART_REG_IER_ELSI))
    360         uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_RCL);
    361     else if (   (pThis->uRegLsr & UART_REG_LSR_DR)
    362              && (pThis->uRegIer & UART_REG_IER_ERBFI)
    363              && (   !(pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
    364                  || pThis->FifoRecv.cbUsed >= pThis->FifoRecv.cbItl))
    365         uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_RDA);
    366     else if (   (pThis->uRegLsr & UART_REG_LSR_THRE)
    367              && (pThis->uRegIer & UART_REG_IER_ETBEI))
    368         uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_THRE);
    369     else if (   (pThis->uRegMsr & UART_REG_MSR_BITS_IIR_MS)
    370              && (pThis->uRegIer & UART_REG_IER_EDSSI))
    371         uRegIirNew = UART_REG_IIR_ID_SET(UART_REG_IIR_ID_MS);
    372 
    373     /** @todo Character timeout indication for FIFO mode. */
    374 
    375     LogFlowFunc(("    uRegIirNew=%#x uRegIir=%#x\n", uRegIirNew, pThis->uRegIir));
    376 
    377     /* Change interrupt only if the interrupt status really changed from the previous value. */
    378     if (uRegIirNew != (pThis->uRegIir & UART_REG_IIR_CHANGED_MASK))
    379     {
    380         LogFlow(("    Interrupt source changed from %#x -> %#x (IRQ %d -> %d)\n",
    381                  pThis->uRegIir, uRegIirNew,
    382                  pThis->uRegIir == UART_REG_IIR_IP_NO_INT ? 0 : 1,
    383                  uRegIirNew == UART_REG_IIR_IP_NO_INT ? 0 : 1));
    384         if (uRegIirNew == UART_REG_IIR_IP_NO_INT)
    385             PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->uIrq, 0);
    386         else
    387             PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->uIrq, 1);
    388     }
    389     else
    390         LogFlow(("    No change in interrupt source\n"));
    391 
    392     if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
    393         uRegIirNew |= UART_REG_IIR_FIFOS_EN;
    394 
    395     pThis->uRegIir = uRegIirNew;
    396 }
    397 
    398 
    399 /**
    400  * Clears the given FIFO.
    401  *
    402  * @returns nothing.
    403  * @param   pFifo               The FIFO to clear.
    404  */
    405 DECLINLINE(void) serialFifoClear(PSERIALFIFO pFifo)
    406 {
    407     memset(&pFifo->abBuf[0], 0, sizeof(pFifo->abBuf));
    408     pFifo->cbUsed   = 0;
    409     pFifo->offWrite = 0;
    410     pFifo->offRead  = 0;
    411 }
    412 
    413 
    414 /**
    415  * Returns the amount of free bytes in the given FIFO.
    416  *
    417  * @returns The amount of bytes free in the given FIFO.
    418  * @param   pFifo               The FIFO.
    419  */
    420 DECLINLINE(size_t) serialFifoFreeGet(PSERIALFIFO pFifo)
    421 {
    422     return UART_FIFO_LENGTH - pFifo->cbUsed;
    423 }
    424 
    425 
    426 /**
    427  * Puts a new character into the given FIFO.
    428  *
    429  * @returns Flag whether the FIFO overflowed.
    430  * @param   pFifo               The FIFO to put the data into.
    431  * @param   fOvrWr              Flag whether to overwrite data if the FIFO is full.
    432  * @param   bData               The data to add.
    433  */
    434 DECLINLINE(bool) serialFifoPut(PSERIALFIFO pFifo, bool fOvrWr, uint8_t bData)
    435 {
    436     if (fOvrWr || pFifo->cbUsed < UART_FIFO_LENGTH)
    437     {
    438         pFifo->abBuf[pFifo->offWrite] = bData;
    439         pFifo->offWrite = (pFifo->offWrite + 1) % UART_FIFO_LENGTH;
    440     }
    441 
    442     bool fOverFlow = false;
    443     if (pFifo->cbUsed < UART_FIFO_LENGTH)
    444         pFifo->cbUsed++;
    445     else
    446     {
    447         fOverFlow = true;
    448         if (fOvrWr) /* Advance the read position to account for the lost character. */
    449            pFifo->offRead = (pFifo->offRead + 1) % UART_FIFO_LENGTH;
    450     }
    451 
    452     return fOverFlow;
    453 }
    454 
    455 
    456 /**
    457  * Returns the next character in the FIFO.
    458  *
    459  * @return Next byte in the FIFO.
    460  * @param   pFifo               The FIFO to get data from.
    461  */
    462 DECLINLINE(uint8_t) serialFifoGet(PSERIALFIFO pFifo)
    463 {
    464     uint8_t bRet = 0;
    465 
    466     if (pFifo->cbUsed)
    467     {
    468         bRet = pFifo->abBuf[pFifo->offRead];
    469         pFifo->offRead = (pFifo->offRead + 1) % UART_FIFO_LENGTH;
    470         pFifo->cbUsed--;
    471     }
    472 
    473     return bRet;
    474 }
    475 
    476 
    477 /**
    478  * Tries to copy the requested amount of data from the given FIFO into the provided buffer.
    479  *
    480  * @returns Amount of bytes actually copied.
    481  * @param   pFifo               The FIFO to copy data from.
    482  * @param   pvDst               Where to copy the data to.
    483  * @param   cbCopy              How much to copy.
    484  */
    485 DECLINLINE(size_t) serialFifoCopyTo(PSERIALFIFO pFifo, void *pvDst, size_t cbCopy)
    486 {
    487     size_t cbCopied = 0;
    488     uint8_t *pbDst = (uint8_t *)pvDst;
    489 
    490     cbCopy = RT_MIN(cbCopy, pFifo->cbUsed);
    491     while (cbCopy)
    492     {
    493         size_t cbThisCopy = RT_MIN(cbCopy, (uint8_t)(UART_FIFO_LENGTH - pFifo->offRead));
    494         memcpy(pbDst, &pFifo->abBuf[pFifo->offRead], cbThisCopy);
    495 
    496         pFifo->offRead = (pFifo->offRead + cbThisCopy) % UART_FIFO_LENGTH;
    497         pFifo->cbUsed -= cbThisCopy;
    498         pbDst    += cbThisCopy;
    499         cbCopied += cbThisCopy;
    500         cbCopy   -= cbThisCopy;
    501     }
    502 
    503     return cbCopied;
    504 }
    505 
    506 
    507 /**
    508  * Tries to copy the requested amount of data from the provided buffer into the given FIFO.
    509  *
    510  * @returns Amount of bytes actually copied.
    511  * @param   pFifo               The FIFO to copy data to.
    512  * @param   pvSrc               Where to copy the data from.
    513  * @param   cbCopy              How much to copy.
    514  */
    515 DECLINLINE(size_t) serialFifoCopyFrom(PSERIALFIFO pFifo, void *pvSrc, size_t cbCopy)
    516 {
    517     size_t cbCopied = 0;
    518     uint8_t *pbSrc = (uint8_t *)pvSrc;
    519 
    520     cbCopy = RT_MIN(cbCopy, serialFifoFreeGet(pFifo));
    521     while (cbCopy)
    522     {
    523         size_t cbThisCopy = RT_MIN(cbCopy, (uint8_t)(UART_FIFO_LENGTH - pFifo->offWrite));
    524         memcpy(&pFifo->abBuf[pFifo->offWrite], pbSrc, cbThisCopy);
    525 
    526         pFifo->offWrite = (pFifo->offWrite + cbThisCopy) % UART_FIFO_LENGTH;
    527         pFifo->cbUsed += cbThisCopy;
    528         pbSrc    += cbThisCopy;
    529         cbCopied += cbThisCopy;
    530         cbCopy   -= cbThisCopy;
    531     }
    532 
    533     return cbCopied;
    534 }
    535 
    536 
    537 #ifdef IN_RING3
    538 /**
    539  * Updates the delta bits for the given MSR register value which has the status line
    540  * bits set.
    541  *
    542  * @returns nothing.
    543  * @param   pThis               The serial port instance.
    544  * @param   uMsrSts             MSR value with the appropriate status bits set.
    545  */
    546 static void serialR3MsrUpdate(PDEVSERIAL pThis, uint8_t uMsrSts)
    547 {
    548     /* Compare current and new states and set remaining bits accordingly. */
    549     if ((uMsrSts & UART_REG_MSR_CTS) != (pThis->uRegMsr & UART_REG_MSR_CTS))
    550         uMsrSts |= UART_REG_MSR_DCTS;
    551     if ((uMsrSts & UART_REG_MSR_DSR) != (pThis->uRegMsr & UART_REG_MSR_DSR))
    552         uMsrSts |= UART_REG_MSR_DDSR;
    553     if ((uMsrSts & UART_REG_MSR_RI) != 0 && (pThis->uRegMsr & UART_REG_MSR_RI) == 0)
    554         uMsrSts |= UART_REG_MSR_TERI;
    555     if ((uMsrSts & UART_REG_MSR_DCD) != (pThis->uRegMsr & UART_REG_MSR_DCD))
    556         uMsrSts |= UART_REG_MSR_DDCD;
    557 
    558     pThis->uRegMsr = uMsrSts;
    559 
    560     serialIrqUpdate(pThis);
    561 }
    562 
    563 
    564 /**
    565  * Updates the serial port parameters of the attached driver with the current configuration.
    566  *
    567  * @returns nothing.
    568  * @param   pThis               The serial port instance.
    569  */
    570 static void serialR3ParamsUpdate(PDEVSERIAL pThis)
    571 {
    572     if (   pThis->uRegDivisor != 0
    573         && pThis->pDrvSerial)
    574     {
    575         uint32_t uBps = 115200 / pThis->uRegDivisor; /* This is for PC compatible serial port with a 1.8432 MHz crystal. */
    576         unsigned cDataBits = UART_REG_LCR_WLS_GET(pThis->uRegLcr) + 5;
    577         PDMSERIALSTOPBITS enmStopBits = PDMSERIALSTOPBITS_ONE;
    578         PDMSERIALPARITY enmParity = PDMSERIALPARITY_NONE;
    579 
    580         if (pThis->uRegLcr & UART_REG_LCR_STB)
    581         {
    582             enmStopBits = cDataBits == 5 ? PDMSERIALSTOPBITS_ONEPOINTFIVE : PDMSERIALSTOPBITS_TWO;
    583         }
    584 
    585         if (pThis->uRegLcr & UART_REG_LCR_PEN)
    586         {
    587             /* Select the correct parity mode based on the even and stick parity bits. */
    588             switch (pThis->uRegLcr & (UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK))
    589             {
    590                 case 0:
    591                     enmParity = PDMSERIALPARITY_ODD;
    592                     break;
    593                 case UART_REG_LCR_EPS:
    594                     enmParity = PDMSERIALPARITY_EVEN;
    595                     break;
    596                 case UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK:
    597                     enmParity = PDMSERIALPARITY_SPACE;
    598                     break;
    599                 case UART_REG_LCR_PAR_STICK:
    600                     enmParity = PDMSERIALPARITY_MARK;
    601                     break;
    602                 default:
    603                     /* We should never get here as all cases where caught earlier. */
    604                     AssertMsgFailed(("This shouldn't happen at all: %#x\n",
    605                                      pThis->uRegLcr & (UART_REG_LCR_EPS | UART_REG_LCR_PAR_STICK)));
    606             }
    607         }
    608 
    609         LogFlowFunc(("Changing parameters to: %u,%s,%u,%s\n",
    610                      uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits]));
    611 
    612         int rc = pThis->pDrvSerial->pfnChgParams(pThis->pDrvSerial, uBps, enmParity, cDataBits, enmStopBits);
    613         if (RT_FAILURE(rc))
    614             LogRelMax(10, ("Serial#%d: Failed to change parameters to %u,%s,%u,%s -> %Rrc\n",
    615                            pThis->pDevInsR3->iInstance, uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits], rc));
    616     }
    617 }
    618 
    619 
    620 /**
    621  * Updates the internal device state with the given PDM status line states.
    622  *
    623  * @returns nothing.
    624  * @param   pThis               The serial port instance.
    625  * @param   fStsLines           The PDM status line states.
    626  */
    627 static void serialR3StsLinesUpdate(PDEVSERIAL pThis, uint32_t fStsLines)
    628 {
    629     uint8_t uRegMsrNew = 0; /* The new MSR value. */
    630 
    631     if (fStsLines & PDMISERIALPORT_STS_LINE_DCD)
    632         uRegMsrNew |= UART_REG_MSR_DCD;
    633     if (fStsLines & PDMISERIALPORT_STS_LINE_RI)
    634         uRegMsrNew |= UART_REG_MSR_RI;
    635     if (fStsLines & PDMISERIALPORT_STS_LINE_DSR)
    636         uRegMsrNew |= UART_REG_MSR_DSR;
    637     if (fStsLines & PDMISERIALPORT_STS_LINE_CTS)
    638         uRegMsrNew |= UART_REG_MSR_CTS;
    639 
    640     serialR3MsrUpdate(pThis, uRegMsrNew);
    641 }
    642 
    643 
    644 /**
    645  * Fills up the receive FIFO with as much data as possible.
    646  *
    647  * @returns nothing.
    648  * @param   pThis               The serial port instance.
    649  */
    650 static void serialR3RecvFifoFill(PDEVSERIAL pThis)
    651 {
    652     LogFlowFunc(("pThis=%#p\n", pThis));
    653 
    654     PSERIALFIFO pFifo = &pThis->FifoRecv;
    655     size_t cbFill = RT_MIN(serialFifoFreeGet(pFifo),
    656                            ASMAtomicReadU32(&pThis->cbAvailRdr));
    657     size_t cbFilled = 0;
    658 
    659     while (cbFilled < cbFill)
    660     {
    661         size_t cbThisRead = RT_MIN(cbFill, (uint8_t)(UART_FIFO_LENGTH - pFifo->offWrite));
    662         size_t cbRead = 0;
    663         int rc = pThis->pDrvSerial->pfnReadRdr(pThis->pDrvSerial, &pFifo->abBuf[pFifo->offWrite], cbThisRead, &cbRead);
    664         /*Assert(RT_SUCCESS(rc) && cbRead == cbThisRead);*/ RT_NOREF(rc);
    665 
    666         pFifo->offWrite = (pFifo->offWrite + cbRead) % UART_FIFO_LENGTH;
    667         pFifo->cbUsed   += cbRead;
    668         cbFilled        += cbRead;
    669 
    670         if (cbRead < cbThisRead)
    671             break;
    672     }
    673 
    674     if (cbFilled)
    675     {
    676         UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
    677         serialIrqUpdate(pThis);
    678     }
    679 
    680     ASMAtomicSubU32(&pThis->cbAvailRdr, cbFilled);
    681 }
    682 
    683 
    684 /**
    685  * Fetches a single byte and writes it to RBR.
    686  *
    687  * @returns nothing.
    688  * @param   pThis               The serial port instance.
    689  */
    690 static void serialR3ByteFetch(PDEVSERIAL pThis)
    691 {
    692     if (ASMAtomicReadU32(&pThis->cbAvailRdr))
    693     {
    694         AssertPtr(pThis->pDrvSerial);
    695         size_t cbRead = 0;
    696         int rc2 = pThis->pDrvSerial->pfnReadRdr(pThis->pDrvSerial, &pThis->uRegRbr, 1, &cbRead);
    697         AssertMsg(RT_SUCCESS(rc2) && cbRead == 1, ("This shouldn't fail and always return one byte!\n"));
    698         UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
    699         serialIrqUpdate(pThis);
    700     }
    701 }
    702 
    703 
    704 /**
    705  * Fetches a ready data based on the FIFO setting.
    706  *
    707  * @returns nothing.
    708  * @param   pThis               The serial port instance.
    709  */
    710 static void serialR3DataFetch(PDEVSERIAL pThis)
    711 {
    712     if (pThis->uRegFcr % UART_REG_FCR_FIFO_EN)
    713         serialR3RecvFifoFill(pThis);
    714     else
    715         serialR3ByteFetch(pThis);
    716 }
    717 #endif
    718 
    719 
    720 /**
    721  * Write handler for the THR/DLL register (depending on the DLAB bit in LCR).
    722  *
    723  * @returns VBox status code.
    724  * @param   pThis               The serial port instance.
    725  * @param   uVal                The value to write.
    726  */
    727 DECLINLINE(int) serialRegThrDllWrite(PDEVSERIAL pThis, uint8_t uVal)
    728 {
    729     int rc = VINF_SUCCESS;
    730 
    731     /* A set DLAB causes a write to the lower 8bits of the divisor latch. */
    732     if (pThis->uRegLcr & UART_REG_LCR_DLAB)
    733     {
    734         if (uVal != (pThis->uRegDivisor & 0xff))
    735         {
    736 #ifndef IN_RING3
    737             rc = VINF_IOM_R3_IOPORT_WRITE;
    738 #else
    739             pThis->uRegDivisor = (pThis->uRegDivisor & 0xff00) | uVal;
    740             serialR3ParamsUpdate(pThis);
    741 #endif
    742         }
    743     }
    744     else
    745     {
    746         if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
    747         {
    748 #ifndef IN_RING3
    749             rc = VINF_IOM_R3_IOPORT_WRITE;
    750 #else
    751             serialFifoPut(&pThis->FifoXmit, true /*fOvrWr*/, uVal);
    752             UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
    753             serialIrqUpdate(pThis);
    754             if (pThis->pDrvSerial)
    755             {
    756                 int rc2 = pThis->pDrvSerial->pfnDataAvailWrNotify(pThis->pDrvSerial, 1);
    757                 if (RT_FAILURE(rc2))
    758                     LogRelMax(10, ("Serial#%d: Failed to send data with %Rrc\n", rc2));
    759             }
    760 #endif
    761         }
    762         else
    763         {
    764             /* Notify the lower driver about available data only if the register was empty before. */
    765             if (pThis->uRegLsr & UART_REG_LSR_THRE)
    766             {
    767 #ifndef IN_RING3
    768                 rc = VINF_IOM_R3_IOPORT_WRITE;
    769 #else
    770                 pThis->uRegThr = uVal;
    771                 UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
    772                 serialIrqUpdate(pThis);
    773                 if (pThis->pDrvSerial)
    774                 {
    775                     int rc2 = pThis->pDrvSerial->pfnDataAvailWrNotify(pThis->pDrvSerial, 1);
    776                     if (RT_FAILURE(rc2))
    777                         LogRelMax(10, ("Serial#%d: Failed to send data with %Rrc\n", rc2));
    778                 }
    779 #endif
    780             }
    781             else
    782                 pThis->uRegThr = uVal;
    783         }
    784     }
    785 
    786     return rc;
    787 }
    788 
    789 
    790 /**
    791  * Write handler for the IER/DLM register (depending on the DLAB bit in LCR).
    792  *
    793  * @returns VBox status code.
    794  * @param   pThis               The serial port instance.
    795  * @param   uVal                The value to write.
    796  */
    797 DECLINLINE(int) serialRegIerDlmWrite(PDEVSERIAL pThis, uint8_t uVal)
    798 {
    799     int rc = VINF_SUCCESS;
    800 
    801     /* A set DLAB causes a write to the higher 8bits of the divisor latch. */
    802     if (pThis->uRegLcr & UART_REG_LCR_DLAB)
    803     {
    804         if (uVal != (pThis->uRegDivisor & 0xff00) >> 8)
    805         {
    806 #ifndef IN_RING3
    807             rc = VINF_IOM_R3_IOPORT_WRITE;
    808 #else
    809             pThis->uRegDivisor = (pThis->uRegDivisor & 0xff) | (uVal << 8);
    810             serialR3ParamsUpdate(pThis);
    811 #endif
    812         }
    813     }
    814     else
    815     {
    816         pThis->uRegIer = uVal & UART_REG_IER_MASK_WR;
    817         serialIrqUpdate(pThis);
    818     }
    819 
    820     return rc;
    821 }
    822 
    823 
    824 /**
    825  * Write handler for the FCR register.
    826  *
    827  * @returns VBox status code.
    828  * @param   pThis               The serial port instance.
    829  * @param   uVal                The value to write.
    830  */
    831 DECLINLINE(int) serialRegFcrWrite(PDEVSERIAL pThis, uint8_t uVal)
    832 {
    833     int rc = VINF_SUCCESS;
    834 
    835     if (   pThis->f16550AEnabled
    836         && uVal != pThis->uRegFcr)
    837     {
    838         /* A change in the FIFO enable bit clears both FIFOs automatically. */
    839         if ((uVal ^ pThis->uRegFcr) & UART_REG_FCR_FIFO_EN)
    840         {
    841             serialFifoClear(&pThis->FifoXmit);
    842             serialFifoClear(&pThis->FifoRecv);
    843 
    844             /* Fill in the next data. */
    845             if (ASMAtomicReadU32(&pThis->cbAvailRdr))
    846             {
    847 #ifndef IN_RING3
    848                 rc = VINF_IOM_R3_IOPORT_WRITE;
    849 #else
    850                 serialR3DataFetch(pThis);
    851 #endif
    852             }
    853         }
    854 
    855         if (rc == VINF_SUCCESS)
    856         {
    857             if (uVal & UART_REG_FCR_RCV_FIFO_RST)
    858                 serialFifoClear(&pThis->FifoRecv);
    859             if (uVal & UART_REG_FCR_XMIT_FIFO_RST)
    860                 serialFifoClear(&pThis->FifoXmit);
    861 
    862             if (uVal & UART_REG_FCR_FIFO_EN)
    863             {
    864                 switch (UART_REG_FCR_RCV_LVL_IRQ_GET(uVal))
    865                 {
    866                     case UART_REG_FCR_RCV_LVL_IRQ_1:
    867                         pThis->FifoRecv.cbItl = 1;
    868                         break;
    869                     case UART_REG_FCR_RCV_LVL_IRQ_4:
    870                         pThis->FifoRecv.cbItl = 4;
    871                         break;
    872                     case UART_REG_FCR_RCV_LVL_IRQ_8:
    873                         pThis->FifoRecv.cbItl = 8;
    874                         break;
    875                     case UART_REG_FCR_RCV_LVL_IRQ_14:
    876                         pThis->FifoRecv.cbItl = 14;
    877                         break;
    878                     default:
    879                         /* Should never occur as all cases are handled earlier. */
    880                         AssertMsgFailed(("Impossible to hit!\n"));
    881                 }
    882             }
    883 
    884             /* The FIFO reset bits are self clearing. */
    885             pThis->uRegFcr = uVal & UART_REG_FCR_MASK_STICKY;
    886             serialIrqUpdate(pThis);
    887         }
    888     }
    889 
    890     return rc;
    891 }
    892 
    893 
    894 /**
    895  * Write handler for the LCR register.
    896  *
    897  * @returns VBox status code.
    898  * @param   pThis               The serial port instance.
    899  * @param   uVal                The value to write.
    900  */
    901 DECLINLINE(int) serialRegLcrWrite(PDEVSERIAL pThis, uint8_t uVal)
    902 {
    903     int rc = VINF_SUCCESS;
    904 
    905     /* Any change except the DLAB bit causes a switch to R3. */
    906     if ((pThis->uRegLcr & ~UART_REG_LCR_DLAB) != (uVal & ~UART_REG_LCR_DLAB))
    907     {
    908 #ifndef IN_RING3
    909         rc = VINF_IOM_R3_IOPORT_WRITE;
    910 #else
    911         /* Check whether the BREAK bit changed before updating the LCR value. */
    912         bool fBrkEn = RT_BOOL(uVal & UART_REG_LCR_BRK_SET);
    913         bool fBrkChg = fBrkEn != RT_BOOL(pThis->uRegLcr & UART_REG_LCR_BRK_SET);
    914         pThis->uRegLcr = uVal;
    915         serialR3ParamsUpdate(pThis);
    916 
    917         if (   fBrkChg
    918             && pThis->pDrvSerial)
    919             pThis->pDrvSerial->pfnChgBrk(pThis->pDrvSerial, fBrkEn);
    920 #endif
    921     }
    922     else
    923         pThis->uRegLcr = uVal;
    924 
    925     return rc;
    926 }
    927 
    928 
    929 /**
    930  * Write handler for the MCR register.
    931  *
    932  * @returns VBox status code.
    933  * @param   pThis               The serial port instance.
    934  * @param   uVal                The value to write.
    935  */
    936 DECLINLINE(int) serialRegMcrWrite(PDEVSERIAL pThis, uint8_t uVal)
    937 {
    938     int rc = VINF_SUCCESS;
    939 
    940     uVal &= UART_REG_MCR_MASK_WR;
    941     if (pThis->uRegMcr != uVal)
    942     {
    943 #ifndef IN_RING3
    944         rc = VINF_IOM_R3_IOPORT_WRITE;
    945 #else
    946         /*
    947          * When loopback mode is activated the RTS, DTR, OUT1 and OUT2 lines are
    948          * disconnected and looped back to MSR.
    949          */
    950         if (   (uVal & UART_REG_MCR_LOOP)
    951             && !(pThis->uRegMcr & UART_REG_MCR_LOOP)
    952             && pThis->pDrvSerial)
    953             pThis->pDrvSerial->pfnChgModemLines(pThis->pDrvSerial, false /*fRts*/, false /*fDtr*/);
    954 
    955         pThis->uRegMcr = uVal;
    956         if (uVal & UART_REG_MCR_LOOP)
    957         {
    958             uint8_t uRegMsrSts = 0;
    959 
    960             if (uVal & UART_REG_MCR_RTS)
    961                 uRegMsrSts |= UART_REG_MSR_CTS;
    962             if (uVal & UART_REG_MCR_DTR)
    963                 uRegMsrSts |= UART_REG_MSR_DSR;
    964             if (uVal & UART_REG_MCR_OUT1)
    965                 uRegMsrSts |= UART_REG_MSR_RI;
    966             if (uVal & UART_REG_MCR_OUT2)
    967                 uRegMsrSts |= UART_REG_MSR_DCD;
    968             serialR3MsrUpdate(pThis, uRegMsrSts);
    969         }
    970         else if (pThis->pDrvSerial)
    971             pThis->pDrvSerial->pfnChgModemLines(pThis->pDrvSerial,
    972                                                 RT_BOOL(uVal & UART_REG_MCR_RTS),
    973                                                 RT_BOOL(uVal & UART_REG_MCR_DTR));
    974 #endif
    975     }
    976 
    977     return rc;
    978 }
    979 
    980 
    981 /**
    982  * Read handler for the RBR/DLL register (depending on the DLAB bit in LCR).
    983  *
    984  * @returns VBox status code.
    985  * @param   pThis               The serial port instance.
    986  * @param   puVal               Where to store the read value on success.
    987  */
    988 DECLINLINE(int) serialRegRbrDllRead(PDEVSERIAL pThis, uint32_t *puVal)
    989 {
    990     int rc = VINF_SUCCESS;
    991 
    992     /* A set DLAB causes a read from the lower 8bits of the divisor latch. */
    993     if (pThis->uRegLcr & UART_REG_LCR_DLAB)
    994         *puVal = pThis->uRegDivisor & 0xff;
    995     else
    996     {
    997         if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
    998         {
    999             /*
    1000              * Only go back to R3 if there is new data available for the FIFO
    1001              * and we would clear the interrupt to fill it up again.
    1002              */
    1003             if (   pThis->FifoRecv.cbUsed <= pThis->FifoRecv.cbItl
    1004                 && ASMAtomicReadU32(&pThis->cbAvailRdr) > 0)
    1005             {
    1006 #ifndef IN_RING3
    1007                 rc = VINF_IOM_R3_IOPORT_READ;
    1008 #else
    1009                 serialR3RecvFifoFill(pThis);
    1010 #endif
    1011             }
    1012 
    1013             if (rc == VINF_SUCCESS)
    1014             {
    1015                 *puVal = serialFifoGet(&pThis->FifoRecv);
    1016                 if (!pThis->FifoRecv.cbUsed)
    1017                     UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_DR);
    1018                 serialIrqUpdate(pThis);
    1019             }
    1020         }
    1021         else
    1022         {
    1023             *puVal = pThis->uRegRbr;
    1024 
    1025             if (pThis->uRegLsr & UART_REG_LSR_DR)
    1026             {
    1027                 uint32_t cbAvail = ASMAtomicDecU32(&pThis->cbAvailRdr);
    1028                 if (!cbAvail)
    1029                 {
    1030                     UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_DR);
    1031                     serialIrqUpdate(pThis);
    1032                 }
    1033                 else
    1034                 {
    1035 #ifndef IN_RING3
    1036                     /* Restore state and go back to R3. */
    1037                     ASMAtomicIncU32(&pThis->cbAvailRdr);
    1038                     rc = VINF_IOM_R3_IOPORT_READ;
    1039 #else
    1040                     /* Fetch new data and keep the DR bit set. */
    1041                     serialR3DataFetch(pThis);
    1042 #endif
    1043                 }
    1044             }
    1045         }
    1046     }
    1047 
    1048     return rc;
    1049 }
    1050 
    1051 
    1052 /**
    1053  * Read handler for the IER/DLM register (depending on the DLAB bit in LCR).
    1054  *
    1055  * @returns VBox status code.
    1056  * @param   pThis               The serial port instance.
    1057  * @param   puVal               Where to store the read value on success.
    1058  */
    1059 DECLINLINE(int) serialRegIerDlmRead(PDEVSERIAL pThis, uint32_t *puVal)
    1060 {
    1061     int rc = VINF_SUCCESS;
    1062 
    1063     /* A set DLAB causes a read from the upper 8bits of the divisor latch. */
    1064     if (pThis->uRegLcr & UART_REG_LCR_DLAB)
    1065         *puVal = (pThis->uRegDivisor & 0xff00) >> 8;
    1066     else
    1067         *puVal = pThis->uRegIer;
    1068 
    1069     return rc;
    1070 }
    1071 
    1072 
    1073 /**
    1074  * Read handler for the IIR register.
    1075  *
    1076  * @returns VBox status code.
    1077  * @param   pThis               The serial port instance.
    1078  * @param   puVal               Where to store the read value on success.
    1079  */
    1080 DECLINLINE(int) serialRegIirRead(PDEVSERIAL pThis, uint32_t *puVal)
    1081 {
    1082     *puVal = pThis->uRegIir;
    1083     return VINF_SUCCESS;
    1084 }
    1085 
    1086 
    1087 /**
    1088  * Read handler for the LSR register.
    1089  *
    1090  * @returns VBox status code.
    1091  * @param   pThis               The serial port instance.
    1092  * @param   puVal               Where to store the read value on success.
    1093  */
    1094 DECLINLINE(int) serialRegLsrRead(PDEVSERIAL pThis, uint32_t *puVal)
    1095 {
    1096     int rc = VINF_SUCCESS;
    1097 
    1098     /* Yield if configured and there is no data available. */
    1099     if (   !(pThis->uRegLsr & UART_REG_LSR_DR)
    1100         && pThis->fYieldOnLSRRead)
    1101     {
    1102 #ifndef IN_RING3
    1103         return VINF_IOM_R3_IOPORT_READ;
    1104 #else
    1105         RTThreadYield();
    1106 #endif
    1107     }
    1108 
    1109     *puVal = pThis->uRegLsr;
    1110     /*
    1111      * Reading this register clears the Overrun (OE), Parity (PE) and Framing (FE) error
    1112      * as well as the Break Interrupt (BI).
    1113      */
    1114     UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_BITS_IIR_RCL);
    1115     serialIrqUpdate(pThis);
    1116 
    1117     return rc;
    1118 }
    1119 
    1120 
    1121 /**
    1122  * Read handler for the MSR register.
    1123  *
    1124  * @returns VBox status code.
    1125  * @param   pThis               The serial port instance.
    1126  * @param   puVal               Where to store the read value on success.
    1127  */
    1128 DECLINLINE(int) serialRegMsrRead(PDEVSERIAL pThis, uint32_t *puVal)
    1129 {
    1130     *puVal = pThis->uRegMsr;
    1131 
    1132     /* Clear any of the delta bits. */
    1133     UART_REG_CLR(pThis->uRegMsr, UART_REG_MSR_BITS_IIR_MS);
    1134     serialIrqUpdate(pThis);
    1135     return VINF_SUCCESS;
    1136 }
    1137 
    1138 
    1139 #ifdef LOG_ENABLED
    1140 /**
    1141  * Converts the register index into a sensible memnonic.
    1142  *
    1143  * @returns Register memnonic.
    1144  * @param   pThis               The serial port instance.
    1145  * @param   idxReg              Register index.
    1146  * @param   fWrite              Flag whether the register gets written.
    1147  */
    1148 DECLINLINE(const char *) serialRegIdx2Str(PDEVSERIAL pThis, uint8_t idxReg, bool fWrite)
    1149 {
    1150     const char *psz = "INV";
    1151 
    1152     switch (idxReg)
    1153     {
    1154         /*case UART_REG_THR_DLL_INDEX:*/
    1155         case UART_REG_RBR_DLL_INDEX:
    1156             if (pThis->uRegLcr & UART_REG_LCR_DLAB)
    1157                 psz = "DLL";
    1158             else if (fWrite)
    1159                 psz = "THR";
    1160             else
    1161                 psz = "RBR";
    1162             break;
    1163         case UART_REG_IER_DLM_INDEX:
    1164             if (pThis->uRegLcr & UART_REG_LCR_DLAB)
    1165                 psz = "DLM";
    1166             else
    1167                 psz = "IER";
    1168             break;
    1169         /*case UART_REG_IIR_INDEX:*/
    1170         case UART_REG_FCR_INDEX:
    1171             if (fWrite)
    1172                 psz = "FCR";
    1173             else
    1174                 psz = "IIR";
    1175             break;
    1176         case UART_REG_LCR_INDEX:
    1177             psz = "LCR";
    1178             break;
    1179         case UART_REG_MCR_INDEX:
    1180             psz = "MCR";
    1181             break;
    1182         case UART_REG_LSR_INDEX:
    1183             psz = "LSR";
    1184             break;
    1185         case UART_REG_MSR_INDEX:
    1186             psz = "MSR";
    1187             break;
    1188         case UART_REG_SCR_INDEX:
    1189             psz = "SCR";
    1190             break;
    1191     }
    1192 
    1193     return psz;
    1194 }
    1195 #endif
    1196 
    1197 /* -=-=-=-=-=-=-=-=- I/O Port Access Handlers -=-=-=-=-=-=-=-=- */
    1198 
    1199 /**
    1200  * @callback_method_impl{FNIOMIOPORTOUT}
    1201  */
    1202 PDMBOTHCBDECL(int) serialIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
    1203 {
    1204     PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1205     Assert(PDMCritSectIsOwner(&pThis->CritSect));
    1206     RT_NOREF_PV(pvUser);
    1207 
    1208     uint8_t idxReg = uPort & 0x7;
    1209     LogFlowFunc(("pDevIns=%#p pvUser=%#p uPort=%RTiop{%s} u32=%#x cb=%u\n",
    1210                  pDevIns, pvUser, uPort, serialRegIdx2Str(pThis, idxReg, true /*fWrite*/), u32, cb));
    1211 
    1212     AssertMsgReturn(cb == 1, ("uPort=%#x cb=%d u32=%#x\n", uPort, cb, u32), VINF_SUCCESS);
    1213 
    1214     int rc = VINF_SUCCESS;
    1215     uint8_t uVal = (uint8_t)u32;
    1216     switch (idxReg)
    1217     {
    1218         case UART_REG_THR_DLL_INDEX:
    1219             rc = serialRegThrDllWrite(pThis, uVal);
    1220             break;
    1221         case UART_REG_IER_DLM_INDEX:
    1222             rc = serialRegIerDlmWrite(pThis, uVal);
    1223             break;
    1224         case UART_REG_FCR_INDEX:
    1225             rc = serialRegFcrWrite(pThis, uVal);
    1226             break;
    1227         case UART_REG_LCR_INDEX:
    1228             rc = serialRegLcrWrite(pThis, uVal);
    1229             break;
    1230         case UART_REG_MCR_INDEX:
    1231             rc = serialRegMcrWrite(pThis, uVal);
    1232             break;
    1233         case UART_REG_SCR_INDEX:
    1234             pThis->uRegScr = u32;
    1235             break;
    1236         default:
    1237             break;
    1238     }
    1239 
    1240     LogFlowFunc(("-> %Rrc\n", rc));
    1241     return rc;
    1242 }
    1243 
    1244 
    1245 /**
    1246  * @callback_method_impl{FNIOMIOPORTIN}
    1247  */
    1248 PDMBOTHCBDECL(int) serialIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
    1249 {
    1250     PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1251     Assert(PDMCritSectIsOwner(&pThis->CritSect));
    1252     RT_NOREF_PV(pvUser);
    1253 
    1254     if (cb != 1)
    1255         return VERR_IOM_IOPORT_UNUSED;
    1256 
    1257     uint8_t idxReg = uPort & 0x7;
    1258     int rc = VINF_SUCCESS;
    1259     switch (idxReg)
    1260     {
    1261         case UART_REG_RBR_DLL_INDEX:
    1262             rc = serialRegRbrDllRead(pThis, pu32);
    1263             break;
    1264         case UART_REG_IER_DLM_INDEX:
    1265             rc = serialRegIerDlmRead(pThis, pu32);
    1266             break;
    1267         case UART_REG_IIR_INDEX:
    1268             rc = serialRegIirRead(pThis, pu32);
    1269             break;
    1270         case UART_REG_LCR_INDEX:
    1271             *pu32 = pThis->uRegLcr;
    1272             break;
    1273         case UART_REG_MCR_INDEX:
    1274             *pu32 = pThis->uRegMcr;
    1275             break;
    1276         case UART_REG_LSR_INDEX:
    1277             rc = serialRegLsrRead(pThis, pu32);
    1278             break;
    1279         case UART_REG_MSR_INDEX:
    1280             rc = serialRegMsrRead(pThis, pu32);
    1281             break;
    1282         case UART_REG_SCR_INDEX:
    1283             *pu32 = pThis->uRegScr;
    1284             break;
    1285         default:
    1286             rc = VERR_IOM_IOPORT_UNUSED;
    1287     }
    1288 
    1289     LogFlowFunc(("pDevIns=%#p pvUser=%#p uPort=%RTiop{%s} u32=%#x cb=%u -> %Rrc\n",
    1290                  pDevIns, pvUser, uPort, serialRegIdx2Str(pThis, idxReg, false /*fWrite*/), *pu32, cb, rc));
    1291     return rc;
    1292 }
    1293 
    1294 
    1295 #ifdef IN_RING3
    1296 
    1297 /* -=-=-=-=-=-=-=-=- PDMISERIALPORT on LUN#0 -=-=-=-=-=-=-=-=- */
    1298 
    1299 
    1300 /**
    1301  * @interface_method_impl{PDMISERIALPORT,pfnDataAvailRdrNotify}
    1302  */
    1303 static DECLCALLBACK(int) serialR3DataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
    1304 {
    1305     LogFlowFunc(("pInterface=%#p cbAvail=%zu\n", pInterface, cbAvail));
    1306     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
    1307 
    1308     AssertMsg((uint32_t)cbAvail == cbAvail, ("Too much data available\n"));
    1309 
    1310     uint32_t cbAvailOld = ASMAtomicAddU32(&pThis->cbAvailRdr, (uint32_t)cbAvail);
    1311     LogFlow(("    cbAvailRdr=%zu -> cbAvailRdr=%zu\n", cbAvailOld, cbAvail + cbAvailOld));
    1312     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    1313     if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
    1314         serialR3RecvFifoFill(pThis);
    1315     else if (!cbAvailOld)
    1316     {
    1317         size_t cbRead = 0;
    1318         int rc = pThis->pDrvSerial->pfnReadRdr(pThis->pDrvSerial, &pThis->uRegRbr, 1, &cbRead);
    1319         AssertMsg(RT_SUCCESS(rc) && cbRead == 1, ("This shouldn't fail and always return one byte!\n"));
    1320         UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
    1321         serialIrqUpdate(pThis);
    1322     }
    1323     PDMCritSectLeave(&pThis->CritSect);
    1324 
    1325     return VINF_SUCCESS;
    1326 }
    1327 
    1328 
    1329 /**
    1330  * @interface_method_impl{PDMISERIALPORT,pfnDataSentNotify}
    1331  */
    1332 static DECLCALLBACK(int) serialR3DataSentNotify(PPDMISERIALPORT pInterface)
    1333 {
    1334     LogFlowFunc(("pInterface=%#p\n", pInterface));
    1335     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
    1336 
    1337     /* Set the transmitter empty bit because everything was sent. */
    1338     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    1339     UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_TEMT);
    1340     serialIrqUpdate(pThis);
    1341     PDMCritSectLeave(&pThis->CritSect);
    1342     return VINF_SUCCESS;
    1343 }
    1344 
    1345 
    1346 /**
    1347  * @interface_method_impl{PDMISERIALPORT,pfnReadWr}
    1348  */
    1349 static DECLCALLBACK(int) serialR3ReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
    1350 {
    1351     LogFlowFunc(("pInterface=%#p pvBuf=%#p cbRead=%zu pcbRead=%#p\n", pInterface, pvBuf, cbRead, pcbRead));
    1352     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
    1353 
    1354     AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
    1355 
    1356     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    1357     if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
    1358     {
    1359         *pcbRead = serialFifoCopyTo(&pThis->FifoXmit, pvBuf, cbRead);
    1360         if (!pThis->FifoXmit.cbUsed)
    1361             UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_THRE);
    1362         if (*pcbRead)
    1363             UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_TEMT);
    1364         serialIrqUpdate(pThis);
    1365     }
    1366     else if (!(pThis->uRegLsr & UART_REG_LSR_THRE))
    1367     {
    1368         *(uint8_t *)pvBuf = pThis->uRegThr;
    1369         *pcbRead = 1;
    1370         UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_THRE);
    1371         UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_TEMT);
    1372         serialIrqUpdate(pThis);
    1373     }
    1374     else
    1375     {
    1376         AssertMsgFailed(("There is no data to read!\n"));
    1377         *pcbRead = 0;
    1378     }
    1379     PDMCritSectLeave(&pThis->CritSect);
    1380 
    1381     LogFlowFunc(("-> VINF_SUCCESS{*pcbRead=%zu}\n", *pcbRead));
    1382     return VINF_SUCCESS;
    1383 }
    1384 
    1385 
    1386 /**
    1387  * @interface_method_impl{PDMISERIALPORT,pfnNotifyStsLinesChanged}
    1388  */
    1389 static DECLCALLBACK(int) serialR3NotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
    1390 {
    1391     LogFlowFunc(("pInterface=%#p fNewStatusLines=%#x\n", pInterface, fNewStatusLines));
    1392     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
    1393 
    1394     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    1395     serialR3StsLinesUpdate(pThis, fNewStatusLines);
    1396     PDMCritSectLeave(&pThis->CritSect);
    1397     return VINF_SUCCESS;
    1398 }
    1399 
    1400 
    1401 /**
    1402  * @interface_method_impl{PDMISERIALPORT,pfnNotifyBrk}
    1403  */
    1404 static DECLCALLBACK(int) serialR3NotifyBrk(PPDMISERIALPORT pInterface)
    1405 {
    1406     LogFlowFunc(("pInterface=%#p\n", pInterface));
    1407     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
    1408 
    1409     PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    1410     UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_BI);
    1411     serialIrqUpdate(pThis);
    1412     PDMCritSectLeave(&pThis->CritSect);
    1413     return VINF_SUCCESS;
    1414 }
    1415 
    1416 
    1417 /* -=-=-=-=-=-=-=-=- PDMIBASE on LUN#0 -=-=-=-=-=-=-=-=- */
    1418 
    1419 /**
    1420  * @interface_method_impl{PDMIBASE,pfnQueryInterface}
    1421  */
    1422 static DECLCALLBACK(void *) serialR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
    1423 {
    1424     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, IBase);
    1425     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
    1426     PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALPORT, &pThis->ISerialPort);
    1427     return NULL;
    1428 }
    1429125
    1430126
     
    1436132static DECLCALLBACK(void) serialR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
    1437133{
    1438     RT_NOREF(offDelta);
    1439     PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1440 
    1441     pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
     134    PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
     135    uartR3Relocate(&pThis->UartCore, offDelta);
    1442136}
    1443137
     
    1449143{
    1450144    PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1451 
    1452     pThis->uRegDivisor = 0x0c; /* Default to 9600 Baud. */
    1453     pThis->uRegRbr     = 0;
    1454     pThis->uRegThr     = 0;
    1455     pThis->uRegIer     = 0;
    1456     pThis->uRegIir     = UART_REG_IIR_IP_NO_INT;
    1457     pThis->uRegFcr     = 0;
    1458     pThis->uRegLcr     = 0; /* 5 data bits, no parity, 1 stop bit. */
    1459     pThis->uRegMcr     = 0;
    1460     pThis->uRegLsr     = UART_REG_LSR_THRE | UART_REG_LSR_TEMT;
    1461     pThis->uRegMsr     = 0; /* Updated below. */
    1462     pThis->uRegScr     = 0;
    1463 
    1464     serialFifoClear(&pThis->FifoXmit);
    1465     serialFifoClear(&pThis->FifoRecv);
    1466     pThis->FifoRecv.cbItl = 1;
    1467 
    1468     serialR3ParamsUpdate(pThis);
    1469     serialIrqUpdate(pThis);
    1470 
    1471     if (pThis->pDrvSerial)
    1472     {
    1473         /* Set the modem lines to reflect the current state. */
    1474         int rc = pThis->pDrvSerial->pfnChgModemLines(pThis->pDrvSerial, false /*fRts*/, false /*fDtr*/);
    1475         if (RT_FAILURE(rc))
    1476             LogRel(("Serial#%d: Failed to set modem lines with %Rrc during reset\n",
    1477                     pThis->pDevInsR3->iInstance, rc));
    1478 
    1479         uint32_t fStsLines = 0;
    1480         rc = pThis->pDrvSerial->pfnQueryStsLines(pThis->pDrvSerial, &fStsLines);
    1481         if (RT_SUCCESS(rc))
    1482             serialR3StsLinesUpdate(pThis, fStsLines);
    1483         else
    1484             LogRel(("Serial#%d: Failed to query status line status with %Rrc during reset\n",
    1485                     pThis->pDevInsR3->iInstance, rc));
    1486     }
     145    uartR3Reset(&pThis->UartCore);
    1487146}
    1488147
     
    1493152static DECLCALLBACK(int) serialR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
    1494153{
     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{
    1495165    RT_NOREF(iLUN, fFlags);
    1496166    PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1497 
    1498     int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
    1499     if (RT_SUCCESS(rc))
    1500     {
    1501         pThis->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMISERIALCONNECTOR);
    1502         if (!pThis->pDrvSerial)
    1503         {
    1504             AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", pDevIns->iInstance));
    1505             return VERR_PDM_MISSING_INTERFACE;
    1506         }
    1507     }
    1508     else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
    1509     {
    1510         pThis->pDrvBase = NULL;
    1511         pThis->pDrvSerial = NULL;
    1512         rc = VINF_SUCCESS;
    1513         LogRel(("Serial#%d: no unit\n", pDevIns->iInstance));
    1514     }
    1515     else /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
    1516         LogRel(("Serial#%d: Failed to attach to serial driver. rc=%Rrc\n", pDevIns->iInstance, rc));
    1517 
    1518    return rc;
    1519 }
    1520 
    1521 
    1522 /**
    1523  * @interface_method_impl{PDMDEVREG,pfnDetach}
    1524  */
    1525 static DECLCALLBACK(void) serialR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
    1526 {
    1527     RT_NOREF(iLUN, fFlags);
    1528     PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1529 
    1530     /* Zero out important members. */
    1531     pThis->pDrvBase   = NULL;
    1532     pThis->pDrvSerial = NULL;
     167    uartR3Detach(&pThis->UartCore);
    1533168}
    1534169
     
    1542177    PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
    1543178
    1544     PDMR3CritSectDelete(&pThis->CritSect);
     179    uartR3Destruct(&pThis->UartCore);
    1545180    return VINF_SUCCESS;
    1546181}
     
    1565200    pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
    1566201    pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
    1567 
    1568     /* IBase */
    1569     pThis->IBase.pfnQueryInterface = serialR3QueryInterface;
    1570 
    1571     /* ISerialPort */
    1572     pThis->ISerialPort.pfnDataAvailRdrNotify    = serialR3DataAvailRdrNotify;
    1573     pThis->ISerialPort.pfnDataSentNotify        = serialR3DataSentNotify;
    1574     pThis->ISerialPort.pfnReadWr                = serialR3ReadWr;
    1575     pThis->ISerialPort.pfnNotifyStsLinesChanged = serialR3NotifyStsLinesChanged;
    1576     pThis->ISerialPort.pfnNotifyBrk             = serialR3NotifyBrk;
    1577202
    1578203    /*
     
    1601226                                N_("Configuration error: Failed to get the \"R0Enabled\" value"));
    1602227
    1603     rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &pThis->fYieldOnLSRRead, false);
     228    bool fYieldOnLSRRead = false;
     229    rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &fYieldOnLSRRead, false);
    1604230    if (RT_FAILURE(rc))
    1605231        return PDMDEV_SET_ERROR(pDevIns, rc,
     
    1637263                                N_("Configuration error: Failed to get the \"IOBase\" value"));
    1638264
    1639     rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &pThis->f16550AEnabled, true);
     265    bool f16550AEnabled = true;
     266    rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &f16550AEnabled, true);
    1640267    if (RT_FAILURE(rc))
    1641268        return PDMDEV_SET_ERROR(pDevIns, rc,
     
    1646273
    1647274    LogRel(("Serial#%d: emulating %s (IOBase: %04x IRQ: %u)\n",
    1648             pDevIns->iInstance, pThis->f16550AEnabled ? "16550A" : "16450", uIoBase, uIrq));
    1649 
    1650     /*
    1651      * Initialize critical section and the semaphore.  Change the default
    1652      * critical section to ours so that TM and IOM will enter it before
    1653      * calling us.
    1654      *
    1655      * Note! This must of be done BEFORE creating timers, registering I/O ports
    1656      *       and other things which might pick up the default CS or end up
    1657      *       calling back into the device.
    1658      */
    1659     rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%d", iInstance);
    1660     AssertRCReturn(rc, rc);
    1661 
    1662     rc = PDMDevHlpSetDeviceCritSect(pDevIns, &pThis->CritSect);
    1663     AssertRCReturn(rc, rc);
     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;
    1664283
    1665284    /*
     
    1672291        return rc;
    1673292
     293    PVM pVM = PDMDevHlpGetVM(pDevIns);
     294    RTR0PTR pfnSerialIrqReqR0 = NIL_RTR0PTR;
     295    RTRCPTR pfnSerialIrqReqRC = NIL_RTRCPTR;
     296
    1674297    if (pThis->fRCEnabled)
    1675298    {
    1676299        rc = PDMDevHlpIOPortRegisterRC(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
    1677300                                      "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
    1678305        if (RT_FAILURE(rc))
    1679306            return rc;
     
    1684311        rc = PDMDevHlpIOPortRegisterR0(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
    1685312                                      "serialIoPortRead", NULL, NULL, "SERIAL");
     313        if (RT_SUCCESS(rc))
     314            rc = PDMR3LdrGetSymbolR0(pVM, pDevIns->pReg->szR0Mod, "serialIrqReq", &pfnSerialIrqReqR0);
     315
    1686316        if (RT_FAILURE(rc))
    1687317            return rc;
     
    1698328#endif
    1699329
    1700     /*
    1701      * Attach the char driver and get the interfaces.
    1702      */
    1703     rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial");
    1704     if (RT_SUCCESS(rc))
    1705     {
    1706         pThis->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMISERIALCONNECTOR);
    1707         if (!pThis->pDrvSerial)
    1708         {
    1709             AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", iInstance));
    1710             return VERR_PDM_MISSING_INTERFACE;
    1711         }
    1712     }
    1713     else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
    1714     {
    1715         pThis->pDrvBase   = NULL;
    1716         pThis->pDrvSerial = NULL;
    1717         LogRel(("Serial#%d: no unit\n", iInstance));
    1718     }
    1719     else
    1720     {
    1721         AssertLogRelMsgFailed(("Serial#%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
    1722         /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
    1723         return rc;
    1724     }
     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);
    1725334
    1726335    serialR3Reset(pDevIns);
  • trunk/src/VBox/Devices/Serial/UartCore.cpp

    r72957 r73135  
    11/* $Id$ */
    22/** @file
    3  * DevSerial - 16550A UART emulation.
     3 * UartCore - UART  (16550A up to 16950) emulation.
    44 *
    55 * The documentation for this device was taken from the PC16550D spec from TI.
     
    2323*********************************************************************************************************************************/
    2424#define LOG_GROUP LOG_GROUP_DEV_SERIAL
    25 #include <VBox/vmm/pdmdev.h>
    26 #include <VBox/vmm/pdmserialifs.h>
     25#include <iprt/uuid.h>
    2726#include <iprt/assert.h>
    28 #include <iprt/uuid.h>
    29 #include <iprt/string.h>
    30 #include <iprt/semaphore.h>
    31 #include <iprt/critsect.h>
    3227
    3328#include "VBoxDD.h"
     29#include "UartCore.h"
    3430
    3531
     
    191187#define UART_REG_CLR(a_Reg, a_Clr)           ((a_Reg) &= ~(a_Clr))
    192188
    193 /** Size of a FIFO. */
    194 #define UART_FIFO_LENGTH                     16
    195 
    196189
    197190/*********************************************************************************************************************************
    198191*   Structures and Typedefs                                                                                                      *
    199192*********************************************************************************************************************************/
    200 
    201 /**
    202  * Serial FIFO.
    203  */
    204 typedef struct SERIALFIFO
    205 {
    206     /** Current amount of bytes used. */
    207     uint8_t                         cbUsed;
    208     /** Next index to write to. */
    209     uint8_t                         offWrite;
    210     /** Next index to read from. */
    211     uint8_t                         offRead;
    212     /** The interrupt trigger level (only used for the receive FIFO). */
    213     uint8_t                         cbItl;
    214     /** The data in the FIFO. */
    215     uint8_t                         abBuf[UART_FIFO_LENGTH];
    216 } SERIALFIFO;
    217 /** Pointer to a FIFO. */
    218 typedef SERIALFIFO *PSERIALFIFO;
    219 
    220 
    221 /**
    222  * Serial device.
    223  *
    224  * @implements  PDMIBASE
    225  * @implements  PDMISERIALPORT
    226  */
    227 typedef struct DEVSERIAL
    228 {
    229     /** Access critical section. */
    230     PDMCRITSECT                     CritSect;
    231     /** Pointer to the device instance - R3 Ptr. */
    232     PPDMDEVINSR3                    pDevInsR3;
    233     /** Pointer to the device instance - R0 Ptr. */
    234     PPDMDEVINSR0                    pDevInsR0;
    235     /** Pointer to the device instance - RC Ptr. */
    236     PPDMDEVINSRC                    pDevInsRC;
    237     /** Alignment. */
    238     RTRCPTR                         Alignment0;
    239     /** LUN\#0: The base interface. */
    240     PDMIBASE                        IBase;
    241     /** LUN\#0: The serial port interface. */
    242     PDMISERIALPORT                  ISerialPort;
    243     /** Pointer to the attached base driver. */
    244     R3PTRTYPE(PPDMIBASE)            pDrvBase;
    245     /** Pointer to the attached serial driver. */
    246     R3PTRTYPE(PPDMISERIALCONNECTOR) pDrvSerial;
    247     /** Flag whether the R0 portion of this device is enabled. */
    248     bool                            fR0Enabled;
    249     /** Flag whether the RC portion of this device is enabled. */
    250     bool                            fRCEnabled;
    251     /** Flag whether an 16550A (with FIFO) or a plain 16450 is emulated. */
    252     bool                            f16550AEnabled;
    253     /** Flag whether to yield on an guest LSR read. */
    254     bool                            fYieldOnLSRRead;
    255     /** The IRQ value. */
    256     uint8_t                         uIrq;
    257     /** The base I/O port the device is registered at. */
    258     RTIOPORT                        PortBase;
    259 
    260     /** The divisor register (DLAB = 1). */
    261     uint16_t                        uRegDivisor;
    262     /** The Receiver Buffer Register (RBR, DLAB = 0). */
    263     uint8_t                         uRegRbr;
    264     /** The Transmitter Holding Register (THR, DLAB = 0). */
    265     uint8_t                         uRegThr;
    266     /** The Interrupt Enable Register (IER, DLAB = 0). */
    267     uint8_t                         uRegIer;
    268     /** The Interrupt Identification Register (IIR). */
    269     uint8_t                         uRegIir;
    270     /** The FIFO Control Register (FCR). */
    271     uint8_t                         uRegFcr;
    272     /** The Line Control Register (LCR). */
    273     uint8_t                         uRegLcr;
    274     /** The Modem Control Register (MCR). */
    275     uint8_t                         uRegMcr;
    276     /** The Line Status Register (LSR). */
    277     uint8_t                         uRegLsr;
    278     /** The Modem Status Register (MSR). */
    279     uint8_t                         uRegMsr;
    280     /** The Scratch Register (SCR). */
    281     uint8_t                         uRegScr;
    282 
    283     /** The transmit FIFO. */
    284     SERIALFIFO                      FifoXmit;
    285     /** The receive FIFO. */
    286     SERIALFIFO                      FifoRecv;
    287 
    288     /** Number of bytes available for reading from the layer below. */
    289     volatile uint32_t               cbAvailRdr;
    290 
    291 } DEVSERIAL;
    292 /** Pointer to the serial device state. */
    293 typedef DEVSERIAL *PDEVSERIAL;
    294193
    295194#ifndef VBOX_DEVICE_STRUCT_TESTCASE
     
    338237 *
    339238 * @returns nothing.
    340  * @param   pThis               The serial port instance.
    341  */
    342 static void serialIrqUpdate(PDEVSERIAL pThis)
     239 * @param   pThis               The UART core instance.
     240 */
     241static void uartIrqUpdate(PUARTCORE pThis)
    343242{
    344243    LogFlowFunc(("pThis=%#p\n", pThis));
     
    383282                 uRegIirNew == UART_REG_IIR_IP_NO_INT ? 0 : 1));
    384283        if (uRegIirNew == UART_REG_IIR_IP_NO_INT)
    385             PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->uIrq, 0);
     284            pThis->CTX_SUFF(pfnUartIrqReq)(pThis->CTX_SUFF(pDevIns), pThis, pThis->iLUN, 0);
    386285        else
    387             PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->uIrq, 1);
     286            pThis->CTX_SUFF(pfnUartIrqReq)(pThis->CTX_SUFF(pDevIns), pThis, pThis->iLUN, 1);
    388287    }
    389288    else
     
    403302 * @param   pFifo               The FIFO to clear.
    404303 */
    405 DECLINLINE(void) serialFifoClear(PSERIALFIFO pFifo)
     304DECLINLINE(void) uartFifoClear(PUARTFIFO pFifo)
    406305{
    407306    memset(&pFifo->abBuf[0], 0, sizeof(pFifo->abBuf));
     
    418317 * @param   pFifo               The FIFO.
    419318 */
    420 DECLINLINE(size_t) serialFifoFreeGet(PSERIALFIFO pFifo)
     319DECLINLINE(size_t) uartFifoFreeGet(PUARTFIFO pFifo)
    421320{
    422321    return UART_FIFO_LENGTH - pFifo->cbUsed;
     
    432331 * @param   bData               The data to add.
    433332 */
    434 DECLINLINE(bool) serialFifoPut(PSERIALFIFO pFifo, bool fOvrWr, uint8_t bData)
     333DECLINLINE(bool) uartFifoPut(PUARTFIFO pFifo, bool fOvrWr, uint8_t bData)
    435334{
    436335    if (fOvrWr || pFifo->cbUsed < UART_FIFO_LENGTH)
     
    460359 * @param   pFifo               The FIFO to get data from.
    461360 */
    462 DECLINLINE(uint8_t) serialFifoGet(PSERIALFIFO pFifo)
     361DECLINLINE(uint8_t) uartFifoGet(PUARTFIFO pFifo)
    463362{
    464363    uint8_t bRet = 0;
     
    483382 * @param   cbCopy              How much to copy.
    484383 */
    485 DECLINLINE(size_t) serialFifoCopyTo(PSERIALFIFO pFifo, void *pvDst, size_t cbCopy)
     384DECLINLINE(size_t) uartFifoCopyTo(PUARTFIFO pFifo, void *pvDst, size_t cbCopy)
    486385{
    487386    size_t cbCopied = 0;
     
    513412 * @param   cbCopy              How much to copy.
    514413 */
    515 DECLINLINE(size_t) serialFifoCopyFrom(PSERIALFIFO pFifo, void *pvSrc, size_t cbCopy)
     414DECLINLINE(size_t) uartFifoCopyFrom(PUARTFIFO pFifo, void *pvSrc, size_t cbCopy)
    516415{
    517416    size_t cbCopied = 0;
    518417    uint8_t *pbSrc = (uint8_t *)pvSrc;
    519418
    520     cbCopy = RT_MIN(cbCopy, serialFifoFreeGet(pFifo));
     419    cbCopy = RT_MIN(cbCopy, uartFifoFreeGet(pFifo));
    521420    while (cbCopy)
    522421    {
     
    544443 * @param   uMsrSts             MSR value with the appropriate status bits set.
    545444 */
    546 static void serialR3MsrUpdate(PDEVSERIAL pThis, uint8_t uMsrSts)
     445static void uartR3MsrUpdate(PUARTCORE pThis, uint8_t uMsrSts)
    547446{
    548447    /* Compare current and new states and set remaining bits accordingly. */
     
    558457    pThis->uRegMsr = uMsrSts;
    559458
    560     serialIrqUpdate(pThis);
     459    uartIrqUpdate(pThis);
    561460}
    562461
     
    568467 * @param   pThis               The serial port instance.
    569468 */
    570 static void serialR3ParamsUpdate(PDEVSERIAL pThis)
     469static void uartR3ParamsUpdate(PUARTCORE pThis)
    571470{
    572471    if (   pThis->uRegDivisor != 0
     
    625524 * @param   fStsLines           The PDM status line states.
    626525 */
    627 static void serialR3StsLinesUpdate(PDEVSERIAL pThis, uint32_t fStsLines)
     526static void uartR3StsLinesUpdate(PUARTCORE pThis, uint32_t fStsLines)
    628527{
    629528    uint8_t uRegMsrNew = 0; /* The new MSR value. */
     
    638537        uRegMsrNew |= UART_REG_MSR_CTS;
    639538
    640     serialR3MsrUpdate(pThis, uRegMsrNew);
     539    uartR3MsrUpdate(pThis, uRegMsrNew);
    641540}
    642541
     
    648547 * @param   pThis               The serial port instance.
    649548 */
    650 static void serialR3RecvFifoFill(PDEVSERIAL pThis)
     549static void uartR3RecvFifoFill(PUARTCORE pThis)
    651550{
    652551    LogFlowFunc(("pThis=%#p\n", pThis));
    653552
    654     PSERIALFIFO pFifo = &pThis->FifoRecv;
    655     size_t cbFill = RT_MIN(serialFifoFreeGet(pFifo),
     553    PUARTFIFO pFifo = &pThis->FifoRecv;
     554    size_t cbFill = RT_MIN(uartFifoFreeGet(pFifo),
    656555                           ASMAtomicReadU32(&pThis->cbAvailRdr));
    657556    size_t cbFilled = 0;
     
    675574    {
    676575        UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
    677         serialIrqUpdate(pThis);
     576        uartIrqUpdate(pThis);
    678577    }
    679578
     
    688587 * @param   pThis               The serial port instance.
    689588 */
    690 static void serialR3ByteFetch(PDEVSERIAL pThis)
     589static void uartR3ByteFetch(PUARTCORE pThis)
    691590{
    692591    if (ASMAtomicReadU32(&pThis->cbAvailRdr))
     
    697596        AssertMsg(RT_SUCCESS(rc2) && cbRead == 1, ("This shouldn't fail and always return one byte!\n"));
    698597        UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
    699         serialIrqUpdate(pThis);
     598        uartIrqUpdate(pThis);
    700599    }
    701600}
     
    708607 * @param   pThis               The serial port instance.
    709608 */
    710 static void serialR3DataFetch(PDEVSERIAL pThis)
     609static void uartR3DataFetch(PUARTCORE pThis)
    711610{
    712611    if (pThis->uRegFcr % UART_REG_FCR_FIFO_EN)
    713         serialR3RecvFifoFill(pThis);
     612        uartR3RecvFifoFill(pThis);
    714613    else
    715         serialR3ByteFetch(pThis);
     614        uartR3ByteFetch(pThis);
    716615}
    717616#endif
     
    725624 * @param   uVal                The value to write.
    726625 */
    727 DECLINLINE(int) serialRegThrDllWrite(PDEVSERIAL pThis, uint8_t uVal)
     626DECLINLINE(int) uartRegThrDllWrite(PUARTCORE pThis, uint8_t uVal)
    728627{
    729628    int rc = VINF_SUCCESS;
     
    738637#else
    739638            pThis->uRegDivisor = (pThis->uRegDivisor & 0xff00) | uVal;
    740             serialR3ParamsUpdate(pThis);
     639            uartR3ParamsUpdate(pThis);
    741640#endif
    742641        }
     
    749648            rc = VINF_IOM_R3_IOPORT_WRITE;
    750649#else
    751             serialFifoPut(&pThis->FifoXmit, true /*fOvrWr*/, uVal);
     650            uartFifoPut(&pThis->FifoXmit, true /*fOvrWr*/, uVal);
    752651            UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
    753             serialIrqUpdate(pThis);
     652            uartIrqUpdate(pThis);
    754653            if (pThis->pDrvSerial)
    755654            {
     
    770669                pThis->uRegThr = uVal;
    771670                UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_THRE | UART_REG_LSR_TEMT);
    772                 serialIrqUpdate(pThis);
     671                uartIrqUpdate(pThis);
    773672                if (pThis->pDrvSerial)
    774673                {
     
    795694 * @param   uVal                The value to write.
    796695 */
    797 DECLINLINE(int) serialRegIerDlmWrite(PDEVSERIAL pThis, uint8_t uVal)
     696DECLINLINE(int) uartRegIerDlmWrite(PUARTCORE pThis, uint8_t uVal)
    798697{
    799698    int rc = VINF_SUCCESS;
     
    808707#else
    809708            pThis->uRegDivisor = (pThis->uRegDivisor & 0xff) | (uVal << 8);
    810             serialR3ParamsUpdate(pThis);
     709            uartR3ParamsUpdate(pThis);
    811710#endif
    812711        }
     
    815714    {
    816715        pThis->uRegIer = uVal & UART_REG_IER_MASK_WR;
    817         serialIrqUpdate(pThis);
     716        uartIrqUpdate(pThis);
    818717    }
    819718
     
    829728 * @param   uVal                The value to write.
    830729 */
    831 DECLINLINE(int) serialRegFcrWrite(PDEVSERIAL pThis, uint8_t uVal)
     730DECLINLINE(int) uartRegFcrWrite(PUARTCORE pThis, uint8_t uVal)
    832731{
    833732    int rc = VINF_SUCCESS;
    834733
    835     if (   pThis->f16550AEnabled
     734    if (   pThis->enmType >= UARTTYPE_16550A
    836735        && uVal != pThis->uRegFcr)
    837736    {
     
    839738        if ((uVal ^ pThis->uRegFcr) & UART_REG_FCR_FIFO_EN)
    840739        {
    841             serialFifoClear(&pThis->FifoXmit);
    842             serialFifoClear(&pThis->FifoRecv);
     740            uartFifoClear(&pThis->FifoXmit);
     741            uartFifoClear(&pThis->FifoRecv);
    843742
    844743            /* Fill in the next data. */
     
    848747                rc = VINF_IOM_R3_IOPORT_WRITE;
    849748#else
    850                 serialR3DataFetch(pThis);
     749                uartR3DataFetch(pThis);
    851750#endif
    852751            }
     
    856755        {
    857756            if (uVal & UART_REG_FCR_RCV_FIFO_RST)
    858                 serialFifoClear(&pThis->FifoRecv);
     757                uartFifoClear(&pThis->FifoRecv);
    859758            if (uVal & UART_REG_FCR_XMIT_FIFO_RST)
    860                 serialFifoClear(&pThis->FifoXmit);
     759                uartFifoClear(&pThis->FifoXmit);
    861760
    862761            if (uVal & UART_REG_FCR_FIFO_EN)
     
    884783            /* The FIFO reset bits are self clearing. */
    885784            pThis->uRegFcr = uVal & UART_REG_FCR_MASK_STICKY;
    886             serialIrqUpdate(pThis);
     785            uartIrqUpdate(pThis);
    887786        }
    888787    }
     
    899798 * @param   uVal                The value to write.
    900799 */
    901 DECLINLINE(int) serialRegLcrWrite(PDEVSERIAL pThis, uint8_t uVal)
     800DECLINLINE(int) uartRegLcrWrite(PUARTCORE pThis, uint8_t uVal)
    902801{
    903802    int rc = VINF_SUCCESS;
     
    913812        bool fBrkChg = fBrkEn != RT_BOOL(pThis->uRegLcr & UART_REG_LCR_BRK_SET);
    914813        pThis->uRegLcr = uVal;
    915         serialR3ParamsUpdate(pThis);
     814        uartR3ParamsUpdate(pThis);
    916815
    917816        if (   fBrkChg
     
    934833 * @param   uVal                The value to write.
    935834 */
    936 DECLINLINE(int) serialRegMcrWrite(PDEVSERIAL pThis, uint8_t uVal)
     835DECLINLINE(int) uartRegMcrWrite(PUARTCORE pThis, uint8_t uVal)
    937836{
    938837    int rc = VINF_SUCCESS;
     
    966865            if (uVal & UART_REG_MCR_OUT2)
    967866                uRegMsrSts |= UART_REG_MSR_DCD;
    968             serialR3MsrUpdate(pThis, uRegMsrSts);
     867            uartR3MsrUpdate(pThis, uRegMsrSts);
    969868        }
    970869        else if (pThis->pDrvSerial)
     
    986885 * @param   puVal               Where to store the read value on success.
    987886 */
    988 DECLINLINE(int) serialRegRbrDllRead(PDEVSERIAL pThis, uint32_t *puVal)
     887DECLINLINE(int) uartRegRbrDllRead(PUARTCORE pThis, uint32_t *puVal)
    989888{
    990889    int rc = VINF_SUCCESS;
     
    1007906                rc = VINF_IOM_R3_IOPORT_READ;
    1008907#else
    1009                 serialR3RecvFifoFill(pThis);
     908                uartR3RecvFifoFill(pThis);
    1010909#endif
    1011910            }
     
    1013912            if (rc == VINF_SUCCESS)
    1014913            {
    1015                 *puVal = serialFifoGet(&pThis->FifoRecv);
     914                *puVal = uartFifoGet(&pThis->FifoRecv);
    1016915                if (!pThis->FifoRecv.cbUsed)
    1017916                    UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_DR);
    1018                 serialIrqUpdate(pThis);
     917                uartIrqUpdate(pThis);
    1019918            }
    1020919        }
     
    1029928                {
    1030929                    UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_DR);
    1031                     serialIrqUpdate(pThis);
     930                    uartIrqUpdate(pThis);
    1032931                }
    1033932                else
     
    1039938#else
    1040939                    /* Fetch new data and keep the DR bit set. */
    1041                     serialR3DataFetch(pThis);
     940                    uartR3DataFetch(pThis);
    1042941#endif
    1043942                }
     
    1057956 * @param   puVal               Where to store the read value on success.
    1058957 */
    1059 DECLINLINE(int) serialRegIerDlmRead(PDEVSERIAL pThis, uint32_t *puVal)
     958DECLINLINE(int) uartRegIerDlmRead(PUARTCORE pThis, uint32_t *puVal)
    1060959{
    1061960    int rc = VINF_SUCCESS;
     
    1078977 * @param   puVal               Where to store the read value on success.
    1079978 */
    1080 DECLINLINE(int) serialRegIirRead(PDEVSERIAL pThis, uint32_t *puVal)
     979DECLINLINE(int) uartRegIirRead(PUARTCORE pThis, uint32_t *puVal)
    1081980{
    1082981    *puVal = pThis->uRegIir;
     
    1092991 * @param   puVal               Where to store the read value on success.
    1093992 */
    1094 DECLINLINE(int) serialRegLsrRead(PDEVSERIAL pThis, uint32_t *puVal)
     993DECLINLINE(int) uartRegLsrRead(PUARTCORE pThis, uint32_t *puVal)
    1095994{
    1096995    int rc = VINF_SUCCESS;
     
    1098997    /* Yield if configured and there is no data available. */
    1099998    if (   !(pThis->uRegLsr & UART_REG_LSR_DR)
    1100         && pThis->fYieldOnLSRRead)
     999        && (pThis->fFlags & UART_CORE_YIELD_ON_LSR_READ))
    11011000    {
    11021001#ifndef IN_RING3
     
    11131012     */
    11141013    UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_BITS_IIR_RCL);
    1115     serialIrqUpdate(pThis);
     1014    uartIrqUpdate(pThis);
    11161015
    11171016    return rc;
     
    11261025 * @param   puVal               Where to store the read value on success.
    11271026 */
    1128 DECLINLINE(int) serialRegMsrRead(PDEVSERIAL pThis, uint32_t *puVal)
     1027DECLINLINE(int) uartRegMsrRead(PUARTCORE pThis, uint32_t *puVal)
    11291028{
    11301029    *puVal = pThis->uRegMsr;
     
    11321031    /* Clear any of the delta bits. */
    11331032    UART_REG_CLR(pThis->uRegMsr, UART_REG_MSR_BITS_IIR_MS);
    1134     serialIrqUpdate(pThis);
     1033    uartIrqUpdate(pThis);
    11351034    return VINF_SUCCESS;
    11361035}
     
    11461045 * @param   fWrite              Flag whether the register gets written.
    11471046 */
    1148 DECLINLINE(const char *) serialRegIdx2Str(PDEVSERIAL pThis, uint8_t idxReg, bool fWrite)
     1047DECLINLINE(const char *) uartRegIdx2Str(PUARTCORE pThis, uint8_t idxReg, bool fWrite)
    11491048{
    11501049    const char *psz = "INV";
     
    11951094#endif
    11961095
    1197 /* -=-=-=-=-=-=-=-=- I/O Port Access Handlers -=-=-=-=-=-=-=-=- */
    1198 
    1199 /**
    1200  * @callback_method_impl{FNIOMIOPORTOUT}
    1201  */
    1202 PDMBOTHCBDECL(int) serialIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
    1203 {
    1204     PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1205     Assert(PDMCritSectIsOwner(&pThis->CritSect));
    1206     RT_NOREF_PV(pvUser);
    1207 
    1208     uint8_t idxReg = uPort & 0x7;
    1209     LogFlowFunc(("pDevIns=%#p pvUser=%#p uPort=%RTiop{%s} u32=%#x cb=%u\n",
    1210                  pDevIns, pvUser, uPort, serialRegIdx2Str(pThis, idxReg, true /*fWrite*/), u32, cb));
    1211 
    1212     AssertMsgReturn(cb == 1, ("uPort=%#x cb=%d u32=%#x\n", uPort, cb, u32), VINF_SUCCESS);
    1213 
    1214     int rc = VINF_SUCCESS;
     1096
     1097DECLHIDDEN(int) uartRegWrite(PUARTCORE pThis, uint32_t uReg, uint32_t u32, size_t cb)
     1098{
     1099    int rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_WRITE);
     1100    if (rc != VINF_SUCCESS)
     1101        return rc;
     1102
     1103    uint8_t idxReg = uReg & 0x7;
     1104    LogFlowFunc(("pThis=%#p uReg=%u{%s} u32=%#x cb=%u\n",
     1105                 pThis, uReg, uartRegIdx2Str(pThis, idxReg, true /*fWrite*/), u32, cb));
     1106
     1107    AssertMsgReturn(cb == 1, ("uReg=%#x cb=%d u32=%#x\n", uReg, cb, u32), VINF_SUCCESS);
     1108
    12151109    uint8_t uVal = (uint8_t)u32;
    12161110    switch (idxReg)
    12171111    {
    12181112        case UART_REG_THR_DLL_INDEX:
    1219             rc = serialRegThrDllWrite(pThis, uVal);
     1113            rc = uartRegThrDllWrite(pThis, uVal);
    12201114            break;
    12211115        case UART_REG_IER_DLM_INDEX:
    1222             rc = serialRegIerDlmWrite(pThis, uVal);
     1116            rc = uartRegIerDlmWrite(pThis, uVal);
    12231117            break;
    12241118        case UART_REG_FCR_INDEX:
    1225             rc = serialRegFcrWrite(pThis, uVal);
     1119            rc = uartRegFcrWrite(pThis, uVal);
    12261120            break;
    12271121        case UART_REG_LCR_INDEX:
    1228             rc = serialRegLcrWrite(pThis, uVal);
     1122            rc = uartRegLcrWrite(pThis, uVal);
    12291123            break;
    12301124        case UART_REG_MCR_INDEX:
    1231             rc = serialRegMcrWrite(pThis, uVal);
     1125            rc = uartRegMcrWrite(pThis, uVal);
    12321126            break;
    12331127        case UART_REG_SCR_INDEX:
     
    12381132    }
    12391133
     1134    PDMCritSectLeave(&pThis->CritSect);
    12401135    LogFlowFunc(("-> %Rrc\n", rc));
    12411136    return rc;
     
    12431138
    12441139
    1245 /**
    1246  * @callback_method_impl{FNIOMIOPORTIN}
    1247  */
    1248 PDMBOTHCBDECL(int) serialIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
    1249 {
    1250     PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1251     Assert(PDMCritSectIsOwner(&pThis->CritSect));
    1252     RT_NOREF_PV(pvUser);
    1253 
     1140DECLHIDDEN(int) uartRegRead(PUARTCORE pThis, uint32_t uReg, uint32_t *pu32, size_t cb)
     1141{
    12541142    if (cb != 1)
    12551143        return VERR_IOM_IOPORT_UNUSED;
    12561144
    1257     uint8_t idxReg = uPort & 0x7;
    1258     int rc = VINF_SUCCESS;
     1145    int rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
     1146    if (rc != VINF_SUCCESS)
     1147        return rc;
     1148
     1149    uint8_t idxReg = uReg & 0x7;
    12591150    switch (idxReg)
    12601151    {
    12611152        case UART_REG_RBR_DLL_INDEX:
    1262             rc = serialRegRbrDllRead(pThis, pu32);
     1153            rc = uartRegRbrDllRead(pThis, pu32);
    12631154            break;
    12641155        case UART_REG_IER_DLM_INDEX:
    1265             rc = serialRegIerDlmRead(pThis, pu32);
     1156            rc = uartRegIerDlmRead(pThis, pu32);
    12661157            break;
    12671158        case UART_REG_IIR_INDEX:
    1268             rc = serialRegIirRead(pThis, pu32);
     1159            rc = uartRegIirRead(pThis, pu32);
    12691160            break;
    12701161        case UART_REG_LCR_INDEX:
     
    12751166            break;
    12761167        case UART_REG_LSR_INDEX:
    1277             rc = serialRegLsrRead(pThis, pu32);
     1168            rc = uartRegLsrRead(pThis, pu32);
    12781169            break;
    12791170        case UART_REG_MSR_INDEX:
    1280             rc = serialRegMsrRead(pThis, pu32);
     1171            rc = uartRegMsrRead(pThis, pu32);
    12811172            break;
    12821173        case UART_REG_SCR_INDEX:
     
    12871178    }
    12881179
    1289     LogFlowFunc(("pDevIns=%#p pvUser=%#p uPort=%RTiop{%s} u32=%#x cb=%u -> %Rrc\n",
    1290                  pDevIns, pvUser, uPort, serialRegIdx2Str(pThis, idxReg, false /*fWrite*/), *pu32, cb, rc));
     1180    PDMCritSectLeave(&pThis->CritSect);
     1181    LogFlowFunc(("pThis=%#p uReg=%u{%s} u32=%#x cb=%u -> %Rrc\n",
     1182                 pThis, uReg, uartRegIdx2Str(pThis, idxReg, false /*fWrite*/), *pu32, cb, rc));
    12911183    return rc;
    12921184}
     
    13011193 * @interface_method_impl{PDMISERIALPORT,pfnDataAvailRdrNotify}
    13021194 */
    1303 static DECLCALLBACK(int) serialR3DataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
     1195static DECLCALLBACK(int) uartR3DataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
    13041196{
    13051197    LogFlowFunc(("pInterface=%#p cbAvail=%zu\n", pInterface, cbAvail));
    1306     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
     1198    PUARTCORE pThis = RT_FROM_MEMBER(pInterface, UARTCORE, ISerialPort);
    13071199
    13081200    AssertMsg((uint32_t)cbAvail == cbAvail, ("Too much data available\n"));
     
    13121204    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    13131205    if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
    1314         serialR3RecvFifoFill(pThis);
     1206        uartR3RecvFifoFill(pThis);
    13151207    else if (!cbAvailOld)
    13161208    {
     
    13191211        AssertMsg(RT_SUCCESS(rc) && cbRead == 1, ("This shouldn't fail and always return one byte!\n"));
    13201212        UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_DR);
    1321         serialIrqUpdate(pThis);
     1213        uartIrqUpdate(pThis);
    13221214    }
    13231215    PDMCritSectLeave(&pThis->CritSect);
     
    13301222 * @interface_method_impl{PDMISERIALPORT,pfnDataSentNotify}
    13311223 */
    1332 static DECLCALLBACK(int) serialR3DataSentNotify(PPDMISERIALPORT pInterface)
     1224static DECLCALLBACK(int) uartR3DataSentNotify(PPDMISERIALPORT pInterface)
    13331225{
    13341226    LogFlowFunc(("pInterface=%#p\n", pInterface));
    1335     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
     1227    PUARTCORE pThis = RT_FROM_MEMBER(pInterface, UARTCORE, ISerialPort);
    13361228
    13371229    /* Set the transmitter empty bit because everything was sent. */
    13381230    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    13391231    UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_TEMT);
    1340     serialIrqUpdate(pThis);
     1232    uartIrqUpdate(pThis);
    13411233    PDMCritSectLeave(&pThis->CritSect);
    13421234    return VINF_SUCCESS;
     
    13471239 * @interface_method_impl{PDMISERIALPORT,pfnReadWr}
    13481240 */
    1349 static DECLCALLBACK(int) serialR3ReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
     1241static DECLCALLBACK(int) uartR3ReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
    13501242{
    13511243    LogFlowFunc(("pInterface=%#p pvBuf=%#p cbRead=%zu pcbRead=%#p\n", pInterface, pvBuf, cbRead, pcbRead));
    1352     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
     1244    PUARTCORE pThis = RT_FROM_MEMBER(pInterface, UARTCORE, ISerialPort);
    13531245
    13541246    AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
     
    13571249    if (pThis->uRegFcr & UART_REG_FCR_FIFO_EN)
    13581250    {
    1359         *pcbRead = serialFifoCopyTo(&pThis->FifoXmit, pvBuf, cbRead);
     1251        *pcbRead = uartFifoCopyTo(&pThis->FifoXmit, pvBuf, cbRead);
    13601252        if (!pThis->FifoXmit.cbUsed)
    13611253            UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_THRE);
    13621254        if (*pcbRead)
    13631255            UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_TEMT);
    1364         serialIrqUpdate(pThis);
     1256        uartIrqUpdate(pThis);
    13651257    }
    13661258    else if (!(pThis->uRegLsr & UART_REG_LSR_THRE))
     
    13701262        UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_THRE);
    13711263        UART_REG_CLR(pThis->uRegLsr, UART_REG_LSR_TEMT);
    1372         serialIrqUpdate(pThis);
     1264        uartIrqUpdate(pThis);
    13731265    }
    13741266    else
     
    13871279 * @interface_method_impl{PDMISERIALPORT,pfnNotifyStsLinesChanged}
    13881280 */
    1389 static DECLCALLBACK(int) serialR3NotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
     1281static DECLCALLBACK(int) uartR3NotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
    13901282{
    13911283    LogFlowFunc(("pInterface=%#p fNewStatusLines=%#x\n", pInterface, fNewStatusLines));
    1392     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
     1284    PUARTCORE pThis = RT_FROM_MEMBER(pInterface, UARTCORE, ISerialPort);
    13931285
    13941286    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    1395     serialR3StsLinesUpdate(pThis, fNewStatusLines);
     1287    uartR3StsLinesUpdate(pThis, fNewStatusLines);
    13961288    PDMCritSectLeave(&pThis->CritSect);
    13971289    return VINF_SUCCESS;
     
    14021294 * @interface_method_impl{PDMISERIALPORT,pfnNotifyBrk}
    14031295 */
    1404 static DECLCALLBACK(int) serialR3NotifyBrk(PPDMISERIALPORT pInterface)
     1296static DECLCALLBACK(int) uartR3NotifyBrk(PPDMISERIALPORT pInterface)
    14051297{
    14061298    LogFlowFunc(("pInterface=%#p\n", pInterface));
    1407     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ISerialPort);
     1299    PUARTCORE pThis = RT_FROM_MEMBER(pInterface, UARTCORE, ISerialPort);
    14081300
    14091301    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    14101302    UART_REG_SET(pThis->uRegLsr, UART_REG_LSR_BI);
    1411     serialIrqUpdate(pThis);
     1303    uartIrqUpdate(pThis);
    14121304    PDMCritSectLeave(&pThis->CritSect);
    14131305    return VINF_SUCCESS;
     
    14151307
    14161308
    1417 /* -=-=-=-=-=-=-=-=- PDMIBASE on LUN#0 -=-=-=-=-=-=-=-=- */
     1309/* -=-=-=-=-=-=-=-=- PDMIBASE -=-=-=-=-=-=-=-=- */
    14181310
    14191311/**
    14201312 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
    14211313 */
    1422 static DECLCALLBACK(void *) serialR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
    1423 {
    1424     PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, IBase);
     1314static DECLCALLBACK(void *) uartR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
     1315{
     1316    PUARTCORE pThis = RT_FROM_MEMBER(pInterface, UARTCORE, IBase);
    14251317    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
    14261318    PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALPORT, &pThis->ISerialPort);
     
    14291321
    14301322
    1431 /* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
    1432 
    1433 /**
    1434  * @interface_method_impl{PDMDEVREG,pfnRelocate}
    1435  */
    1436 static DECLCALLBACK(void) serialR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
     1323DECLHIDDEN(void) uartR3Relocate(PUARTCORE pThis, RTGCINTPTR offDelta)
    14371324{
    14381325    RT_NOREF(offDelta);
    1439     PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1440 
    1441     pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
    1442 }
    1443 
    1444 
    1445 /**
    1446  * @interface_method_impl{PDMDEVREG,pfnReset}
    1447  */
    1448 static DECLCALLBACK(void) serialR3Reset(PPDMDEVINS pDevIns)
    1449 {
    1450     PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1451 
     1326    pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pThis->pDevInsR3);
     1327}
     1328
     1329
     1330DECLHIDDEN(void) uartR3Reset(PUARTCORE pThis)
     1331{
    14521332    pThis->uRegDivisor = 0x0c; /* Default to 9600 Baud. */
    14531333    pThis->uRegRbr     = 0;
     
    14621342    pThis->uRegScr     = 0;
    14631343
    1464     serialFifoClear(&pThis->FifoXmit);
    1465     serialFifoClear(&pThis->FifoRecv);
     1344    uartFifoClear(&pThis->FifoXmit);
     1345    uartFifoClear(&pThis->FifoRecv);
    14661346    pThis->FifoRecv.cbItl = 1;
    14671347
    1468     serialR3ParamsUpdate(pThis);
    1469     serialIrqUpdate(pThis);
     1348    uartR3ParamsUpdate(pThis);
     1349    uartIrqUpdate(pThis);
    14701350
    14711351    if (pThis->pDrvSerial)
     
    14801360        rc = pThis->pDrvSerial->pfnQueryStsLines(pThis->pDrvSerial, &fStsLines);
    14811361        if (RT_SUCCESS(rc))
    1482             serialR3StsLinesUpdate(pThis, fStsLines);
     1362            uartR3StsLinesUpdate(pThis, fStsLines);
    14831363        else
    14841364            LogRel(("Serial#%d: Failed to query status line status with %Rrc during reset\n",
     
    14881368
    14891369
    1490 /**
    1491  * @interface_method_impl{PDMDEVREG,pfnAttach}
    1492  */
    1493 static DECLCALLBACK(int) serialR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
    1494 {
    1495     RT_NOREF(iLUN, fFlags);
    1496     PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1497 
    1498     int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
     1370DECLHIDDEN(int) uartR3Attach(PUARTCORE pThis, unsigned iLUN)
     1371{
     1372    int rc = PDMDevHlpDriverAttach(pThis->pDevInsR3, iLUN, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
    14991373    if (RT_SUCCESS(rc))
    15001374    {
     
    15021376        if (!pThis->pDrvSerial)
    15031377        {
    1504             AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", pDevIns->iInstance));
     1378            AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", pThis->pDevInsR3->iInstance));
    15051379            return VERR_PDM_MISSING_INTERFACE;
    15061380        }
     
    15111385        pThis->pDrvSerial = NULL;
    15121386        rc = VINF_SUCCESS;
    1513         LogRel(("Serial#%d: no unit\n", pDevIns->iInstance));
     1387        LogRel(("Serial#%d: no unit\n", pThis->pDevInsR3->iInstance));
    15141388    }
    15151389    else /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
    1516         LogRel(("Serial#%d: Failed to attach to serial driver. rc=%Rrc\n", pDevIns->iInstance, rc));
     1390        LogRel(("Serial#%d: Failed to attach to serial driver. rc=%Rrc\n", pThis->pDevInsR3->iInstance, rc));
    15171391
    15181392   return rc;
     
    15201394
    15211395
    1522 /**
    1523  * @interface_method_impl{PDMDEVREG,pfnDetach}
    1524  */
    1525 static DECLCALLBACK(void) serialR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
    1526 {
    1527     RT_NOREF(iLUN, fFlags);
    1528     PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1529 
     1396DECLHIDDEN(void) uartR3Detach(PUARTCORE pThis)
     1397{
    15301398    /* Zero out important members. */
    15311399    pThis->pDrvBase   = NULL;
     
    15341402
    15351403
    1536 /**
    1537  * @interface_method_impl{PDMDEVREG,pfnDestruct}
    1538  */
    1539 static DECLCALLBACK(int) serialR3Destruct(PPDMDEVINS pDevIns)
    1540 {
    1541     PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1542     PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
    1543 
     1404DECLHIDDEN(void) uartR3Destruct(PUARTCORE pThis)
     1405{
    15441406    PDMR3CritSectDelete(&pThis->CritSect);
    1545     return VINF_SUCCESS;
    1546 }
    1547 
    1548 
    1549 /**
    1550  * @interface_method_impl{PDMDEVREG,pfnConstruct}
    1551  */
    1552 static DECLCALLBACK(int) serialR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
    1553 {
    1554     PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
    1555     int        rc = VINF_SUCCESS;
    1556 
    1557     Assert(iInstance < 4);
    1558     PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
     1407}
     1408
     1409
     1410DECLHIDDEN(int) uartR3Init(PUARTCORE pThis, PPDMDEVINS pDevInsR3, UARTTYPE enmType, unsigned iLUN, uint32_t fFlags,
     1411                           R3PTRTYPE(PFNUARTCOREIRQREQ) pfnUartIrqReqR3, R0PTRTYPE(PFNUARTCOREIRQREQ) pfnUartIrqReqR0,
     1412                           RCPTRTYPE(PFNUARTCOREIRQREQ) pfnUartIrqReqRC)
     1413{
     1414    int rc = VINF_SUCCESS;
    15591415
    15601416    /*
     
    15621418     * (Do this early or the destructor might choke on something!)
    15631419     */
    1564     pThis->pDevInsR3 = pDevIns;
    1565     pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
    1566     pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
     1420    pThis->pDevInsR3                            = pDevInsR3;
     1421    pThis->pDevInsR0                            = PDMDEVINS_2_R0PTR(pDevInsR3);
     1422    pThis->pDevInsRC                            = PDMDEVINS_2_RCPTR(pDevInsR3);
     1423    pThis->iLUN                                 = iLUN;
     1424    pThis->enmType                              = enmType;
     1425    pThis->fFlags                               = fFlags;
     1426    pThis->pfnUartIrqReqR3                      = pfnUartIrqReqR3;
     1427    pThis->pfnUartIrqReqR0                      = pfnUartIrqReqR0;
     1428    pThis->pfnUartIrqReqRC                      = pfnUartIrqReqRC;
    15671429
    15681430    /* IBase */
    1569     pThis->IBase.pfnQueryInterface = serialR3QueryInterface;
     1431    pThis->IBase.pfnQueryInterface              = uartR3QueryInterface;
    15701432
    15711433    /* ISerialPort */
    1572     pThis->ISerialPort.pfnDataAvailRdrNotify    = serialR3DataAvailRdrNotify;
    1573     pThis->ISerialPort.pfnDataSentNotify        = serialR3DataSentNotify;
    1574     pThis->ISerialPort.pfnReadWr                = serialR3ReadWr;
    1575     pThis->ISerialPort.pfnNotifyStsLinesChanged = serialR3NotifyStsLinesChanged;
    1576     pThis->ISerialPort.pfnNotifyBrk             = serialR3NotifyBrk;
    1577 
    1578     /*
    1579      * Validate and read the configuration.
    1580      */
    1581     if (!CFGMR3AreValuesValid(pCfg, "IRQ\0"
    1582                                     "IOBase\0"
    1583                                     "GCEnabled\0"
    1584                                     "R0Enabled\0"
    1585                                     "YieldOnLSRRead\0"
    1586                                     "Enable16550A\0"
    1587                                     ))
    1588     {
    1589         AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
    1590         return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
    1591     }
    1592 
    1593     rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fRCEnabled, true);
    1594     if (RT_FAILURE(rc))
    1595         return PDMDEV_SET_ERROR(pDevIns, rc,
    1596                                 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
    1597 
    1598     rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
    1599     if (RT_FAILURE(rc))
    1600         return PDMDEV_SET_ERROR(pDevIns, rc,
    1601                                 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
    1602 
    1603     rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &pThis->fYieldOnLSRRead, false);
    1604     if (RT_FAILURE(rc))
    1605         return PDMDEV_SET_ERROR(pDevIns, rc,
    1606                                 N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
    1607 
    1608     uint8_t uIrq = 0;
    1609     rc = CFGMR3QueryU8(pCfg, "IRQ", &uIrq);
    1610     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    1611     {
    1612         /* Provide sensible defaults. */
    1613         if (iInstance == 0)
    1614             uIrq = 4;
    1615         else if (iInstance == 1)
    1616             uIrq = 3;
    1617         else
    1618             AssertReleaseFailed(); /* irq_lvl is undefined. */
    1619     }
    1620     else if (RT_FAILURE(rc))
    1621         return PDMDEV_SET_ERROR(pDevIns, rc,
    1622                                 N_("Configuration error: Failed to get the \"IRQ\" value"));
    1623 
    1624     uint16_t uIoBase = 0;
    1625     rc = CFGMR3QueryU16(pCfg, "IOBase", &uIoBase);
    1626     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    1627     {
    1628         if (iInstance == 0)
    1629             uIoBase = 0x3f8;
    1630         else if (iInstance == 1)
    1631             uIoBase = 0x2f8;
    1632         else
    1633             AssertReleaseFailed(); /* uIoBase is undefined */
    1634     }
    1635     else if (RT_FAILURE(rc))
    1636         return PDMDEV_SET_ERROR(pDevIns, rc,
    1637                                 N_("Configuration error: Failed to get the \"IOBase\" value"));
    1638 
    1639     rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &pThis->f16550AEnabled, true);
    1640     if (RT_FAILURE(rc))
    1641         return PDMDEV_SET_ERROR(pDevIns, rc,
    1642                                 N_("Configuration error: Failed to get the \"Enable16550A\" value"));
    1643 
    1644     pThis->uIrq     = uIrq;
    1645     pThis->PortBase = uIoBase;
    1646 
    1647     LogRel(("Serial#%d: emulating %s (IOBase: %04x IRQ: %u)\n",
    1648             pDevIns->iInstance, pThis->f16550AEnabled ? "16550A" : "16450", uIoBase, uIrq));
    1649 
    1650     /*
    1651      * Initialize critical section and the semaphore.  Change the default
    1652      * critical section to ours so that TM and IOM will enter it before
    1653      * calling us.
    1654      *
    1655      * Note! This must of be done BEFORE creating timers, registering I/O ports
    1656      *       and other things which might pick up the default CS or end up
    1657      *       calling back into the device.
    1658      */
    1659     rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%d", iInstance);
     1434    pThis->ISerialPort.pfnDataAvailRdrNotify    = uartR3DataAvailRdrNotify;
     1435    pThis->ISerialPort.pfnDataSentNotify        = uartR3DataSentNotify;
     1436    pThis->ISerialPort.pfnReadWr                = uartR3ReadWr;
     1437    pThis->ISerialPort.pfnNotifyStsLinesChanged = uartR3NotifyStsLinesChanged;
     1438    pThis->ISerialPort.pfnNotifyBrk             = uartR3NotifyBrk;
     1439
     1440    rc = PDMDevHlpCritSectInit(pDevInsR3, &pThis->CritSect, RT_SRC_POS, "Serial#%d", iLUN);
    16601441    AssertRCReturn(rc, rc);
    1661 
    1662     rc = PDMDevHlpSetDeviceCritSect(pDevIns, &pThis->CritSect);
    1663     AssertRCReturn(rc, rc);
    1664 
    1665     /*
    1666      * Register the I/O ports.
    1667      */
    1668     rc = PDMDevHlpIOPortRegister(pDevIns, uIoBase, 8, 0,
    1669                                  serialIoPortWrite, serialIoPortRead,
    1670                                  NULL, NULL, "SERIAL");
    1671     if (RT_FAILURE(rc))
    1672         return rc;
    1673 
    1674     if (pThis->fRCEnabled)
    1675     {
    1676         rc = PDMDevHlpIOPortRegisterRC(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
    1677                                       "serialIoPortRead", NULL, NULL, "SERIAL");
    1678         if (RT_FAILURE(rc))
    1679             return rc;
    1680     }
    1681 
    1682     if (pThis->fR0Enabled)
    1683     {
    1684         rc = PDMDevHlpIOPortRegisterR0(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
    1685                                       "serialIoPortRead", NULL, NULL, "SERIAL");
    1686         if (RT_FAILURE(rc))
    1687             return rc;
    1688     }
    1689 
    1690 #if 0 /** @todo Later */
    1691     /*
    1692      * Saved state.
    1693      */
    1694     rc = PDMDevHlpSSMRegister3(pDevIns, SERIAL_SAVED_STATE_VERSION, sizeof (*pThis),
    1695                                serialR3LiveExec, serialR3SaveExec, serialR3LoadExec);
    1696     if (RT_FAILURE(rc))
    1697         return rc;
    1698 #endif
    16991442
    17001443    /*
    17011444     * Attach the char driver and get the interfaces.
    17021445     */
    1703     rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial");
     1446    rc = PDMDevHlpDriverAttach(pDevInsR3, iLUN, &pThis->IBase, &pThis->pDrvBase, "UART");
    17041447    if (RT_SUCCESS(rc))
    17051448    {
     
    17071450        if (!pThis->pDrvSerial)
    17081451        {
    1709             AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", iInstance));
     1452            AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", iLUN));
    17101453            return VERR_PDM_MISSING_INTERFACE;
    17111454        }
     
    17151458        pThis->pDrvBase   = NULL;
    17161459        pThis->pDrvSerial = NULL;
    1717         LogRel(("Serial#%d: no unit\n", iInstance));
     1460        LogRel(("Serial#%d: no unit\n", iLUN));
    17181461    }
    17191462    else
    17201463    {
    1721         AssertLogRelMsgFailed(("Serial#%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
     1464        AssertLogRelMsgFailed(("Serial#%d: Failed to attach to char driver. rc=%Rrc\n", iLUN, rc));
    17221465        /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
    17231466        return rc;
    17241467    }
    17251468
    1726     serialR3Reset(pDevIns);
     1469    uartR3Reset(pThis);
    17271470    return VINF_SUCCESS;
    17281471}
    17291472
    1730 
    1731 /**
    1732  * The device registration structure.
    1733  */
    1734 const PDMDEVREG g_DeviceSerialPort =
    1735 {
    1736     /* u32Version */
    1737     PDM_DEVREG_VERSION,
    1738     /* szName */
    1739     "serial",
    1740     /* szRCMod */
    1741     "VBoxDDRC.rc",
    1742     /* szR0Mod */
    1743     "VBoxDDR0.r0",
    1744     /* pszDescription */
    1745     "Serial Communication Port",
    1746     /* fFlags */
    1747     PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
    1748     /* fClass */
    1749     PDM_DEVREG_CLASS_SERIAL,
    1750     /* cMaxInstances */
    1751     UINT32_MAX,
    1752     /* cbInstance */
    1753     sizeof(DEVSERIAL),
    1754     /* pfnConstruct */
    1755     serialR3Construct,
    1756     /* pfnDestruct */
    1757     serialR3Destruct,
    1758     /* pfnRelocate */
    1759     serialR3Relocate,
    1760     /* pfnMemSetup */
    1761     NULL,
    1762     /* pfnPowerOn */
    1763     NULL,
    1764     /* pfnReset */
    1765     serialR3Reset,
    1766     /* pfnSuspend */
    1767     NULL,
    1768     /* pfnResume */
    1769     NULL,
    1770     /* pfnAttach */
    1771     serialR3Attach,
    1772     /* pfnDetach */
    1773     serialR3Detach,
    1774     /* pfnQueryInterface. */
    1775     NULL,
    1776     /* pfnInitComplete */
    1777     NULL,
    1778     /* pfnPowerOff */
    1779     NULL,
    1780     /* pfnSoftReset */
    1781     NULL,
    1782     /* u32VersionEnd */
    1783     PDM_DEVREG_VERSION
    1784 };
    17851473#endif /* IN_RING3 */
    17861474
Note: See TracChangeset for help on using the changeset viewer.

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