summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/Serial/UartCore.h
blob: 25f6328704134b6a9591626a5fd16a583efbf162 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/* $Id: UartCore.h $ */
/** @file
 * UartCore - UART  (16550A up to 16950) emulation.
 *
 * The documentation for this device was taken from the PC16550D spec from TI.
 */

/*
 * Copyright (C) 2018-2023 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, in version 3 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <https://www.gnu.org/licenses>.
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */

#ifndef VBOX_INCLUDED_SRC_Serial_UartCore_h
#define VBOX_INCLUDED_SRC_Serial_UartCore_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include <VBox/types.h>
#include <VBox/vmm/pdmdev.h>
#include <VBox/vmm/pdmserialifs.h>
#include <VBox/vmm/ssm.h>
#include <iprt/assert.h>

RT_C_DECLS_BEGIN

/*********************************************************************************************************************************
*   Defined Constants And Macros                                                                                                 *
*********************************************************************************************************************************/

/** The current serial code saved state version. */
#define UART_SAVED_STATE_VERSION                                        7
/** Saved state version before the TX timer for the connected device case was added. */
#define UART_SAVED_STATE_VERSION_PRE_UNCONNECTED_TX_TIMER               6
/** Saved state version of the legacy code which got replaced after 5.2. */
#define UART_SAVED_STATE_VERSION_LEGACY_CODE                            5
/** Includes some missing bits from the previous saved state. */
#define UART_SAVED_STATE_VERSION_MISSING_BITS                           4
/** Saved state version when only the 16450 variant was implemented. */
#define UART_SAVED_STATE_VERSION_16450                                  3

/** Maximum size of a FIFO. */
#define UART_FIFO_LENGTH_MAX                 128


/*********************************************************************************************************************************
*   Structures and Typedefs                                                                                                      *
*********************************************************************************************************************************/

/** Pointer to the UART core state. */
typedef struct UARTCORE *PUARTCORE;


/**
 * UART core IRQ request callback to let the core instance raise/clear interrupt requests.
 *
 * @param   pDevIns             The owning device instance.
 * @param   pThis               The shared UART core instance data.
 * @param   iLUN                The LUN associated with the UART core.
 * @param   iLvl                The interrupt level.
 */
typedef DECLCALLBACKTYPE(void, FNUARTCOREIRQREQ,(PPDMDEVINS pDevIns, PUARTCORE pThis, unsigned iLUN, int iLvl));
/** Pointer to a UART core IRQ request callback. */
typedef FNUARTCOREIRQREQ *PFNUARTCOREIRQREQ;


/**
 * UART type.
 */
typedef enum UARTTYPE
{
    /** Invalid UART type. */
    UARTTYPE_INVALID = 0,
    /** 16450 UART type. */
    UARTTYPE_16450,
    /** 16550A UART type. */
    UARTTYPE_16550A,
    /** 16750 UART type. */
    UARTTYPE_16750,
        /** 32bit hack. */
    UARTTYPE_32BIT_HACK = 0x7fffffff
} UARTTYPE;


/**
 * UART FIFO.
 */
typedef struct UARTFIFO
{
    /** Fifo size configured. */
    uint8_t                         cbMax;
    /** Current amount of bytes used. */
    uint8_t                         cbUsed;
    /** Next index to write to. */
    uint8_t                         offWrite;
    /** Next index to read from. */
    uint8_t                         offRead;
    /** The interrupt trigger level (only used for the receive FIFO). */
    uint8_t                         cbItl;
    /** The data in the FIFO. */
    uint8_t                         abBuf[UART_FIFO_LENGTH_MAX];
    /** Alignment to a 4 byte boundary. */
    uint8_t                         au8Alignment0[3];
} UARTFIFO;
/** Pointer to a FIFO. */
typedef UARTFIFO *PUARTFIFO;


/**
 * Shared UART core device state.
 *
 * @implements  PDMIBASE
 * @implements  PDMISERIALPORT
 */
typedef struct UARTCORE
{
    /** Access critical section. */
    PDMCRITSECT                     CritSect;
    /** The LUN on the owning device instance for this core. */
    uint32_t                        iLUN;
    /** Configuration flags. */
    uint32_t                        fFlags;
    /** The selected UART type. */
    UARTTYPE                        enmType;

    /** The divisor register (DLAB = 1). */
    uint16_t                        uRegDivisor;
    /** The Receiver Buffer Register (RBR, DLAB = 0). */
    uint8_t                         uRegRbr;
    /** The Transmitter Holding Register (THR, DLAB = 0). */
    uint8_t                         uRegThr;
    /** The Interrupt Enable Register (IER, DLAB = 0). */
    uint8_t                         uRegIer;
    /** The Interrupt Identification Register (IIR). */
    uint8_t                         uRegIir;
    /** The FIFO Control Register (FCR). */
    uint8_t                         uRegFcr;
    /** The Line Control Register (LCR). */
    uint8_t                         uRegLcr;
    /** The Modem Control Register (MCR). */
    uint8_t                         uRegMcr;
    /** The Line Status Register (LSR). */
    uint8_t                         uRegLsr;
    /** The Modem Status Register (MSR). */
    uint8_t                         uRegMsr;
    /** The Scratch Register (SCR). */
    uint8_t                         uRegScr;

    /** Timer handle for the character timeout indication. */
    TMTIMERHANDLE                   hTimerRcvFifoTimeout;
    /** Timer handle for the send loop if no driver is connected/loopback mode is active. */
    TMTIMERHANDLE                   hTimerTxUnconnected;

    /** Flag whether a character timeout interrupt is pending
     * (no symbols were inserted or removed from the receive FIFO
     * during an 4 times the character transmit/receive period and the FIFO
     * is not empty). */
    bool                            fIrqCtiPending;
    /** Flag whether the transmitter holding register went empty since last time the
     * IIR register was read. This gets reset when IIR is read so the guest will get this
     * interrupt ID only once. */
    bool                            fThreEmptyPending;
    /** Explicit alignment. */
    bool                            afAlignment1[2];
    /** The transmit FIFO. */
    UARTFIFO                        FifoXmit;
    /** The receive FIFO. */
    UARTFIFO                        FifoRecv;

    /** Time it takes to transmit/receive a single symbol in timer ticks. */
    uint64_t                        cSymbolXferTicks;
    /** Number of bytes available for reading from the layer below. */
    volatile uint32_t               cbAvailRdr;
    /** Explicit alignment. */
    uint32_t                        u32Alignment2;
} UARTCORE;
AssertCompileSizeAlignment(UARTCORE, 8);


/**
 * Ring-3 UART core device state.
 *
 * @implements  PDMIBASE
 * @implements  PDMISERIALPORT
 */
typedef struct UARTCORER3
{
    /** The LUN on the owning device instance for this core. */
    uint32_t                        iLUN;
    uint32_t                        u32Padding;
    /** LUN\#0: The base interface. */
    PDMIBASE                        IBase;
    /** LUN\#0: The serial port interface. */
    PDMISERIALPORT                  ISerialPort;
    /** Pointer to the attached base driver. */
    R3PTRTYPE(PPDMIBASE)            pDrvBase;
    /** Pointer to the attached serial driver. */
    R3PTRTYPE(PPDMISERIALCONNECTOR) pDrvSerial;

    /** Interrupt request callback of the owning device. */
    R3PTRTYPE(PFNUARTCOREIRQREQ)    pfnUartIrqReq;

    /** Pointer to the shared data - for timers callbacks and interface methods
     *  only. */
    R3PTRTYPE(PUARTCORE)            pShared;
    /** Pointer to the device instance - only for getting our bearings in
     *  interface methods. */
    PPDMDEVINS                      pDevIns;
} UARTCORER3;
/** Pointer to the core ring-3 UART device state. */
typedef UARTCORER3 *PUARTCORER3;


/**
 * Ring-0 UART core device state.
 */
typedef struct UARTCORER0
{
    /** Interrupt request callback of the owning device. */
    R0PTRTYPE(PFNUARTCOREIRQREQ)    pfnUartIrqReq;
} UARTCORER0;
/** Pointer to the core ring-0 UART device state. */
typedef UARTCORER0 *PUARTCORER0;


/**
 * Raw-mode UART core device state.
 */
typedef struct UARTCORERC
{
    /** Interrupt request callback of the owning device. */
    R0PTRTYPE(PFNUARTCOREIRQREQ)    pfnUartIrqReq;
} UARTCORERC;
/** Pointer to the core raw-mode UART device state. */
typedef UARTCORERC *PUARTCORERC;


/** Current context UAR core device state. */
typedef CTX_SUFF(UARTCORE) UARTCORECC;
/** Pointer to the current context UAR core device state. */
typedef CTX_SUFF(PUARTCORE) PUARTCORECC;


#ifndef VBOX_DEVICE_STRUCT_TESTCASE

/** Flag whether to yield the CPU on an LSR read. */
#define UART_CORE_YIELD_ON_LSR_READ      RT_BIT_32(0)

DECLHIDDEN(VBOXSTRICTRC) uartRegWrite(PPDMDEVINS pDevIns, PUARTCORE pThis, PUARTCORECC pThisCC,
                                      uint32_t uReg, uint32_t u32, size_t cb);
DECLHIDDEN(VBOXSTRICTRC) uartRegRead(PPDMDEVINS pDevIns, PUARTCORE pThis, PUARTCORECC pThisCC,
                                     uint32_t uReg, uint32_t *pu32, size_t cb);

# ifdef IN_RING3
DECLHIDDEN(int)  uartR3Init(PPDMDEVINS pDevIns, PUARTCORE pThis, PUARTCORECC pThisCC,
                            UARTTYPE enmType, unsigned iLUN, uint32_t fFlags, PFNUARTCOREIRQREQ pfnUartIrqReq);
DECLHIDDEN(void) uartR3Destruct(PPDMDEVINS pDevIns, PUARTCORE pThis);
DECLHIDDEN(void) uartR3Detach(PPDMDEVINS pDevIns, PUARTCORE pThis, PUARTCORECC pThisCC);
DECLHIDDEN(int)  uartR3Attach(PPDMDEVINS pDevIns, PUARTCORE pThis, PUARTCORECC pThisCC, unsigned iLUN);
DECLHIDDEN(void) uartR3Reset(PPDMDEVINS pDevIns, PUARTCORE pThis, PUARTCORECC pThisCC);
DECLHIDDEN(int)  uartR3SaveExec(PPDMDEVINS pDevIns, PUARTCORE pThis, PSSMHANDLE pSSM);
DECLHIDDEN(int)  uartR3LoadExec(PPDMDEVINS pDevIns, PUARTCORE pThis, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass,
                                uint8_t *puIrq, RTIOPORT *pPortBase);
DECLHIDDEN(int)  uartR3LoadDone(PPDMDEVINS pDevIns, PUARTCORE pThis, PUARTCORECC pThisCC, PSSMHANDLE pSSM);

# endif /* IN_RING3 */
# if !defined(IN_RING3) || defined(DOXYGEN_RUNNING)
DECLHIDDEN(int) uartRZInit(PUARTCORECC pThisCC, PFNUARTCOREIRQREQ pfnUartIrqReq);
# endif

#endif

RT_C_DECLS_END

#endif /* !VBOX_INCLUDED_SRC_Serial_UartCore_h */