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
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
|
/* $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-2019 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#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.
*
* @returns nothing.
* @param pDevIns The owning device instance.
* @param pThis The UART core instance.
* @param iLUN The LUN associated with the UART core.
* @param iLvl The interrupt level.
*/
typedef DECLCALLBACK(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;
/**
* UART core device.
*
* @implements PDMIBASE
* @implements PDMISERIALPORT
*/
typedef struct UARTCORE
{
/** Access critical section. */
PDMCRITSECT CritSect;
/** Pointer to the device instance - R3 Ptr. */
PPDMDEVINSR3 pDevInsR3;
/** Pointer to the device instance - R0 Ptr. */
PPDMDEVINSR0 pDevInsR0;
/** Pointer to the device instance - RC Ptr. */
PPDMDEVINSRC pDevInsRC;
/** The LUN on the owning device instance for this core. */
uint32_t iLUN;
/** 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;
/** Configuration flags. */
uint32_t fFlags;
/** The selected UART type. */
UARTTYPE enmType;
/** R3 timer pointer for the character timeout indication. */
PTMTIMERR3 pTimerRcvFifoTimeoutR3;
/** R3 timer pointer for the send loop if no driver is connected. */
PTMTIMERR3 pTimerTxUnconnectedR3;
/** R3 interrupt request callback of the owning device. */
R3PTRTYPE(PFNUARTCOREIRQREQ) pfnUartIrqReqR3;
/** R0 timer pointer fo the character timeout indication. */
PTMTIMERR0 pTimerRcvFifoTimeoutR0;
/** R0 timer pointer for the send loop if no driver is connected. */
PTMTIMERR0 pTimerTxUnconnectedR0;
/** R0 interrupt request callback of the owning device. */
R0PTRTYPE(PFNUARTCOREIRQREQ) pfnUartIrqReqR0;
/** RC timer pointer fo the character timeout indication. */
PTMTIMERRC pTimerRcvFifoTimeoutRC;
/** RC timer pointer for the send loop if no driver is connected. */
PTMTIMERRC pTimerTxUnconnectedRC;
/** RC interrupt request callback of the owning device. */
RCPTRTYPE(PFNUARTCOREIRQREQ) pfnUartIrqReqRC;
/** Alignment */
uint32_t u32Alignment;
/** 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;
/** 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;
/** Alignment. */
bool afAlignment[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;
#if defined(IN_RC) || HC_ARCH_BITS == 32
uint32_t uAlignment;
#endif
} UARTCORE;
AssertCompileSizeAlignment(UARTCORE, 8);
#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)
/**
* Performs a register write to the given register offset.
*
* @returns VBox status code.
* @param pThis The UART core instance.
* @param uReg The register offset (byte offset) to start writing to.
* @param u32 The value to write.
* @param cb Number of bytes to write.
*/
DECLHIDDEN(int) uartRegWrite(PUARTCORE pThis, uint32_t uReg, uint32_t u32, size_t cb);
/**
* Performs a register read from the given register offset.
*
* @returns VBox status code.
* @param pThis The UART core instance.
* @param uReg The register offset (byte offset) to start reading from.
* @param pu32 Where to store the read value.
* @param cb Number of bytes to read.
*/
DECLHIDDEN(int) uartRegRead(PUARTCORE pThis, uint32_t uReg, uint32_t *pu32, size_t cb);
# ifdef IN_RING3
/**
* Initializes the given UART core instance using the provided configuration.
*
* @returns VBox status code.
* @param pThis The UART core instance to initialize.
* @param pDevInsR3 The R3 device instance pointer.
* @param enmType The type of UART emulated.
* @param iLUN The LUN the UART should look for attached drivers.
* @param fFlags Additional flags controlling device behavior.
* @param pfnUartIrqReqR3 Pointer to the R3 interrupt request callback.
* @param pfnUartIrqReqR0 Pointer to the R0 interrupt request callback.
* @param pfnUartIrqReqRC Pointer to the RC interrupt request callback.
*/
DECLHIDDEN(int) uartR3Init(PUARTCORE pThis, PPDMDEVINS pDevInsR3, UARTTYPE enmType, unsigned iLUN, uint32_t fFlags,
R3PTRTYPE(PFNUARTCOREIRQREQ) pfnUartIrqReqR3, R0PTRTYPE(PFNUARTCOREIRQREQ) pfnUartIrqReqR0,
RCPTRTYPE(PFNUARTCOREIRQREQ) pfnUartIrqReqRC);
/**
* Destroys the given UART core instance freeing all allocated resources.
*
* @returns nothing.
* @param pThis The UART core instance.
*/
DECLHIDDEN(void) uartR3Destruct(PUARTCORE pThis);
/**
* Detaches any attached driver from the given UART core instance.
*
* @returns nothing.
* @param pThis The UART core instance.
*/
DECLHIDDEN(void) uartR3Detach(PUARTCORE pThis);
/**
* Attaches the given UART core instance to the drivers at the given LUN.
*
* @returns VBox status code.
* @param pThis The UART core instance.
* @param iLUN The LUN being attached.
*/
DECLHIDDEN(int) uartR3Attach(PUARTCORE pThis, unsigned iLUN);
/**
* Resets the given UART core instance.
*
* @returns nothing.
* @param pThis The UART core instance.
*/
DECLHIDDEN(void) uartR3Reset(PUARTCORE pThis);
/**
* Relocates an RC pointers of the given UART core instance
*
* @returns nothing.
* @param pThis The UART core instance.
* @param offDelta The delta to relocate RC pointers with.
*/
DECLHIDDEN(void) uartR3Relocate(PUARTCORE pThis, RTGCINTPTR offDelta);
/**
* Saves the UART state to the given SSM handle.
*
* @returns VBox status code.
* @param pThis The UART core instance.
* @param pSSM The SSM handle to save to.
*/
DECLHIDDEN(int) uartR3SaveExec(PUARTCORE pThis, PSSMHANDLE pSSM);
/**
* Loads the UART state from the given SSM handle.
*
* @returns VBox status code.
* @param pThis The UART core instance.
* @param pSSM The SSM handle to load from.
* @param uVersion Saved state version.
* @param uPass The SSM pass the call is done in.
* @param puIrq Where to store the IRQ value for legacy
* saved states - optional.
* @param pPortBase Where to store the I/O port base for legacy
* saved states - optional.
*/
DECLHIDDEN(int) uartR3LoadExec(PUARTCORE pThis, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass,
uint8_t *puIrq, RTIOPORT *pPortBase);
/**
* Called when loading the state completed, updates the parameters of any driver underneath.
*
* @returns VBox status code.
* @param pThis The UART core instance.
* @param pSSM The SSM handle.
*/
DECLHIDDEN(int) uartR3LoadDone(PUARTCORE pThis, PSSMHANDLE pSSM);
# endif
#endif
RT_C_DECLS_END
#endif /* !VBOX_INCLUDED_SRC_Serial_UartCore_h */
|