summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/Serial/UartCore.h
blob: 7ec2e6e1e9d6bb258f19d5c3afd2d02b8737f57a (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
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 */