VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DevPL011.cpp@ 99739

Last change on this file since 99739 was 99739, checked in by vboxsync, 13 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.3 KB
Line 
1/* $Id: DevPL011.cpp 99739 2023-05-11 01:01:08Z vboxsync $ */
2/** @file
3 * DevSerialPL011 - ARM PL011 PrimeCell UART.
4 *
5 * The documentation for this device was taken from
6 * https://developer.arm.com/documentation/ddi0183/g/programmers-model/summary-of-registers (2023-03-21).
7 */
8
9/*
10 * Copyright (C) 2023 Oracle and/or its affiliates.
11 *
12 * This file is part of VirtualBox base platform packages, as
13 * available from https://www.virtualbox.org.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, in version 3 of the
18 * License.
19 *
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see <https://www.gnu.org/licenses>.
27 *
28 * SPDX-License-Identifier: GPL-3.0-only
29 */
30
31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#define LOG_GROUP LOG_GROUP_DEV_SERIAL
36#include <VBox/vmm/pdmdev.h>
37#include <VBox/vmm/pdmserialifs.h>
38#include <iprt/assert.h>
39#include <iprt/uuid.h>
40#include <iprt/string.h>
41#include <iprt/semaphore.h>
42#include <iprt/critsect.h>
43
44#include "VBoxDD.h"
45
46
47/*********************************************************************************************************************************
48* Defined Constants And Macros *
49*********************************************************************************************************************************/
50
51/** The current serial code saved state version. */
52#define PL011_SAVED_STATE_VERSION 1
53
54/** PL011 MMIO region size in bytes. */
55#define PL011_MMIO_SIZE _4K
56/** Maximum size of a FIFO. */
57#define PL011_FIFO_LENGTH_MAX 32
58
59/** The offset of the UARTDR register from the beginning of the region. */
60#define PL011_REG_UARTDR_INDEX 0x0
61/** Framing error. */
62# define PL011_REG_UARTDR_FE RT_BIT(8)
63/** Parity error. */
64# define PL011_REG_UARTDR_PE RT_BIT(9)
65/** Break error. */
66# define PL011_REG_UARTDR_BE RT_BIT(10)
67/** Overrun error. */
68# define PL011_REG_UARTDR_OE RT_BIT(11)
69
70/** The offset of the UARTRSR/UARTECR register from the beginning of the region. */
71#define PL011_REG_UARTRSR_ECR_INDEX 0x4
72/** Framing error. */
73# define PL011_REG_UARTRSR_ECR_FE RT_BIT(0)
74/** Parity error. */
75# define PL011_REG_UARTRSR_ECR_PE RT_BIT(1)
76/** Break error. */
77# define PL011_REG_UARTRSR_ECR_BE RT_BIT(2)
78/** Overrun error. */
79# define PL011_REG_UARTRSR_ECR_OE RT_BIT(3)
80
81/** The offset of the UARTFR register from the beginning of the region. */
82#define PL011_REG_UARTFR_INDEX 0x18
83/** Clear to send. */
84# define PL011_REG_UARTFR_CTS RT_BIT(0)
85/** Data set ready. */
86# define PL011_REG_UARTFR_DSR RT_BIT(1)
87/** Data carrier detect. */
88# define PL011_REG_UARTFR_DCD RT_BIT(2)
89/** UART busy. */
90# define PL011_REG_UARTFR_BUSY RT_BIT(3)
91/** Receive FIFO empty. */
92# define PL011_REG_UARTFR_RXFE RT_BIT(4)
93/** Transmit FIFO full. */
94# define PL011_REG_UARTFR_TXFF RT_BIT(5)
95/** Receive FIFO full. */
96# define PL011_REG_UARTFR_RXFF RT_BIT(6)
97/** Transmit FIFO empty. */
98# define PL011_REG_UARTFR_TXFE RT_BIT(7)
99/** Ring indicator. */
100# define PL011_REG_UARTFR_RI RT_BIT(8)
101
102/** The offset of the UARTILPR register from the beginning of the region. */
103#define PL011_REG_UARTILPR_INDEX 0x20
104
105/** The offset of the UARTIBRD register from the beginning of the region. */
106#define PL011_REG_UARTIBRD_INDEX 0x24
107
108/** The offset of the UARTFBRD register from the beginning of the region. */
109#define PL011_REG_UARTFBRD_INDEX 0x28
110
111/** The offset of the UARTLCR_H register from the beginning of the region. */
112#define PL011_REG_UARTLCR_H_INDEX 0x2c
113/** Send break. */
114# define PL011_REG_UARTLCR_H_BRK RT_BIT(0)
115/** Parity enable. */
116# define PL011_REG_UARTLCR_H_PEN RT_BIT(1)
117/** Even parity select. */
118# define PL011_REG_UARTLCR_H_EPS RT_BIT(2)
119/** Two stop bits select. */
120# define PL011_REG_UARTLCR_H_STP2 RT_BIT(3)
121/** Enable FIFOs. */
122# define PL011_REG_UARTLCR_H_FEN RT_BIT(4)
123/** Word length. */
124# define PL011_REG_UARTLCR_H_WLEN (RT_BIT(5) | RT_BIT(6))
125# define PL011_REG_UARTLCR_H_WLEN_GET(a_Lcr) (((a_Lcr) & PL011_REG_UARTLCR_H_WLEN) >> 5)
126# define PL011_REG_UARTLCR_H_WLEN_SET(a_Wlen) (((a_Wlen) << 5) & PL011_REG_UARTLCR_H_WLEN)
127/** 5 bits word length. */
128# define PL011_REG_UARTLCR_H_WLEN_5BITS 0
129/** 6 bits word length. */
130# define PL011_REG_UARTLCR_H_WLEN_6BITS 1
131/** 7 bits word length. */
132# define PL011_REG_UARTLCR_H_WLEN_7BITS 2
133/** 8 bits word length. */
134# define PL011_REG_UARTLCR_H_WLEN_8BITS 3
135/** Stick parity select. */
136# define PL011_REG_UARTLCR_H_SPS RT_BIT(7)
137
138/** The offset of the UARTCR register from the beginning of the region. */
139#define PL011_REG_UARTCR_INDEX 0x30
140/** UART enable. */
141# define PL011_REG_UARTCR_UARTEN RT_BIT(0)
142/** SIR enable. */
143# define PL011_REG_UARTCR_SIREN RT_BIT(1)
144/** SIR low-power IrDA mode. */
145# define PL011_REG_UARTCR_SIRLP RT_BIT(2)
146/** Loopback enable. */
147# define PL011_REG_UARTCR_LBE RT_BIT(7)
148/** UART transmit enable flag. */
149# define PL011_REG_UARTCR_TXE RT_BIT(8)
150/** UART receive enable flag. */
151# define PL011_REG_UARTCR_RXE RT_BIT(9)
152/** Data transmit ready. */
153# define PL011_REG_UARTCR_DTR RT_BIT(10)
154/** Request to send. */
155# define PL011_REG_UARTCR_RTS RT_BIT(11)
156/** UART Out1 modem status output (DCD). */
157# define PL011_REG_UARTCR_OUT1_DCD RT_BIT(12)
158/** UART Out2 modem status output (RI). */
159# define PL011_REG_UARTCR_OUT2_RI RT_BIT(13)
160/** RTS hardware flow control enable. */
161# define PL011_REG_UARTCR_OUT1_RTSEn RT_BIT(14)
162/** CTS hardware flow control enable. */
163# define PL011_REG_UARTCR_OUT1_CTSEn RT_BIT(15)
164
165/** The offset of the UARTIFLS register from the beginning of the region. */
166#define PL011_REG_UARTIFLS_INDEX 0x34
167/** Returns the Transmit Interrupt FIFO level. */
168# define PL011_REG_UARTIFLS_TXFIFO_GET(a_Ifls) ((a_Ifls) & 0x7)
169/** Returns the Receive Interrupt FIFO level. */
170# define PL011_REG_UARTIFLS_RXFIFO_GET(a_Ifls) (((a_Ifls) >> 3) & 0x7)
171/** 1/8 Fifo level. */
172# define PL011_REG_UARTIFLS_LVL_1_8 0x0
173/** 1/4 Fifo level. */
174# define PL011_REG_UARTIFLS_LVL_1_4 0x1
175/** 1/2 Fifo level. */
176# define PL011_REG_UARTIFLS_LVL_1_2 0x2
177/** 3/4 Fifo level. */
178# define PL011_REG_UARTIFLS_LVL_3_4 0x3
179/** 7/8 Fifo level. */
180# define PL011_REG_UARTIFLS_LVL_7_8 0x4
181
182/** The offset of the UARTIMSC register from the beginning of the region. */
183#define PL011_REG_UARTIMSC_INDEX 0x38
184
185/** The offset of the UARTRIS register from the beginning of the region. */
186#define PL011_REG_UARTRIS_INDEX 0x3c
187
188/** The offset of the UARTMIS register from the beginning of the region. */
189#define PL011_REG_UARTMIS_INDEX 0x40
190
191/** The offset of the UARTICR register from the beginning of the region. */
192#define PL011_REG_UARTICR_INDEX 0x44
193
194/** The offset of the UARTDMACR register from the beginning of the region. */
195#define PL011_REG_UARTDMACR_INDEX 0x48
196
197/** The offset of the UARTPeriphID0 register from the beginning of the region. */
198#define PL011_REG_UART_PERIPH_ID0_INDEX 0xfe0
199/** The offset of the UARTPeriphID1 register from the beginning of the region. */
200#define PL011_REG_UART_PERIPH_ID1_INDEX 0xfe4
201/** The offset of the UARTPeriphID2 register from the beginning of the region. */
202#define PL011_REG_UART_PERIPH_ID2_INDEX 0xfe8
203/** The offset of the UARTPeriphID3 register from the beginning of the region. */
204#define PL011_REG_UART_PERIPH_ID3_INDEX 0xfec
205/** The offset of the UARTPCellID0 register from the beginning of the region. */
206#define PL011_REG_UART_PCELL_ID0_INDEX 0xff0
207/** The offset of the UARTPCellID1 register from the beginning of the region. */
208#define PL011_REG_UART_PCELL_ID1_INDEX 0xff4
209/** The offset of the UARTPCellID2 register from the beginning of the region. */
210#define PL011_REG_UART_PCELL_ID2_INDEX 0xff8
211/** The offset of the UARTPCellID3 register from the beginning of the region. */
212#define PL011_REG_UART_PCELL_ID3_INDEX 0xffc
213
214/** Set the specified bits in the given register. */
215#define PL011_REG_SET(a_Reg, a_Set) ((a_Reg) |= (a_Set))
216/** Clear the specified bits in the given register. */
217#define PL011_REG_CLR(a_Reg, a_Clr) ((a_Reg) &= ~(a_Clr))
218
219
220/*********************************************************************************************************************************
221* Structures and Typedefs *
222*********************************************************************************************************************************/
223
224/**
225 * UART FIFO.
226 */
227typedef struct PL011FIFO
228{
229 /** Fifo size configured. */
230 uint8_t cbMax;
231 /** Current amount of bytes used. */
232 uint8_t cbUsed;
233 /** Next index to write to. */
234 uint8_t offWrite;
235 /** Next index to read from. */
236 uint8_t offRead;
237 /** The interrupt trigger level (only used for the receive FIFO). */
238 uint8_t cbItl;
239 /** The data in the FIFO. */
240 uint8_t abBuf[PL011_FIFO_LENGTH_MAX];
241 /** Alignment to a 4 byte boundary. */
242 uint8_t au8Alignment0[3];
243} PL011FIFO;
244/** Pointer to a FIFO. */
245typedef PL011FIFO *PPL011FIFO;
246
247
248/**
249 * Shared serial device state.
250 */
251typedef struct DEVPL011
252{
253 /** The MMIO handle. */
254 IOMMMIOHANDLE hMmio;
255 /** The base MMIO address the device is registered at. */
256 RTGCPHYS GCPhysMmioBase;
257 /** The IRQ value. */
258 uint16_t u16Irq;
259
260 /** @name Registers.
261 * @{ */
262 uint8_t uRegDr;
263 /** UART control register. */
264 uint16_t uRegCr;
265 /** UART flag register. */
266 uint16_t uRegFr;
267 /** UART integer baud rate register. */
268 uint16_t uRegIbrd;
269 /** UART fractional baud rate register. */
270 uint16_t uRegFbrd;
271 /** UART line control register. */
272 uint16_t uRegLcrH;
273 /** @} */
274
275 /** Time it takes to transmit/receive a single symbol in timer ticks. */
276 uint64_t cSymbolXferTicks;
277 /** Number of bytes available for reading from the layer below. */
278 volatile uint32_t cbAvailRdr;
279
280 /** The transmit FIFO. */
281 PL011FIFO FifoXmit;
282 /** The receive FIFO. */
283 PL011FIFO FifoRecv;
284} DEVPL011;
285/** Pointer to the shared serial device state. */
286typedef DEVPL011 *PDEVPL011;
287
288
289/**
290 * Serial device state for ring-3.
291 */
292typedef struct DEVPL011R3
293{
294 /** LUN\#0: The base interface. */
295 PDMIBASE IBase;
296 /** LUN\#0: The serial port interface. */
297 PDMISERIALPORT ISerialPort;
298 /** Pointer to the attached base driver. */
299 R3PTRTYPE(PPDMIBASE) pDrvBase;
300 /** Pointer to the attached serial driver. */
301 R3PTRTYPE(PPDMISERIALCONNECTOR) pDrvSerial;
302 /** Pointer to the device instance - only for getting our bearings in
303 * interface methods. */
304 PPDMDEVINS pDevIns;
305} DEVPL011R3;
306/** Pointer to the serial device state for ring-3. */
307typedef DEVPL011R3 *PDEVPL011R3;
308
309
310/**
311 * Serial device state for ring-0.
312 */
313typedef struct DEVPL011R0
314{
315 /** Dummy .*/
316 uint8_t bDummy;
317} DEVPL011R0;
318/** Pointer to the serial device state for ring-0. */
319typedef DEVPL011R0 *PDEVPL011R0;
320
321
322/**
323 * Serial device state for raw-mode.
324 */
325typedef struct DEVPL011RC
326{
327 /** Dummy .*/
328 uint8_t bDummy;
329} DEVPL011RC;
330/** Pointer to the serial device state for raw-mode. */
331typedef DEVPL011RC *PDEVPL011RC;
332
333/** The serial device state for the current context. */
334typedef CTX_SUFF(DEVPL011) DEVPL011CC;
335/** Pointer to the serial device state for the current context. */
336typedef CTX_SUFF(PDEVPL011) PDEVPL011CC;
337
338
339/*********************************************************************************************************************************
340* Global Variables *
341*********************************************************************************************************************************/
342
343#ifdef IN_RING3
344/**
345 * String versions of the parity enum.
346 */
347static const char *s_aszParity[] =
348{
349 "INVALID",
350 "NONE",
351 "EVEN",
352 "ODD",
353 "MARK",
354 "SPACE",
355 "INVALID"
356};
357
358
359/**
360 * String versions of the stop bits enum.
361 */
362static const char *s_aszStopBits[] =
363{
364 "INVALID",
365 "1",
366 "INVALID",
367 "2",
368 "INVALID"
369};
370#endif
371
372
373/*********************************************************************************************************************************
374* Internal Functions *
375*********************************************************************************************************************************/
376
377#ifndef VBOX_DEVICE_STRUCT_TESTCASE
378
379/**
380 * Updates the IRQ state based on the current device state.
381 *
382 * @param pDevIns The device instance.
383 * @param pThis The shared serial port instance data.
384 * @param pThisCC The serial port instance data for the current context.
385 */
386static void pl011IrqUpdate(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC)
387{
388 LogFlowFunc(("pThis=%#p\n", pThis));
389 RT_NOREF(pDevIns, pThis, pThisCC);
390}
391
392
393/**
394 * Transmits the given byte.
395 *
396 * @returns Strict VBox status code.
397 * @param pDevIns The device instance.
398 * @param pThis The shared serial port instance data.
399 * @param pThisCC The serial port instance data for the current context.
400 * @param bVal Byte to transmit.
401 */
402static VBOXSTRICTRC pl011Xmit(PPDMDEVINS pDevIns, PDEVPL011CC pThisCC, PDEVPL011 pThis, uint8_t bVal)
403{
404 int rc = VINF_SUCCESS;
405#ifdef IN_RING3
406 bool fNotifyDrv = false;
407#endif
408
409 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_FEN)
410 {
411 AssertReleaseFailed(); /** @todo */
412 }
413 else
414 {
415 /* Notify the lower driver about available data only if the register was empty before. */
416 if (!(pThis->uRegFr & PL011_REG_UARTFR_BUSY))
417 {
418#ifndef IN_RING3
419 rc = VINF_IOM_R3_IOPORT_WRITE;
420#else
421 pThis->uRegDr = bVal;
422 pThis->uRegFr |= PL011_REG_UARTFR_BUSY | PL011_REG_UARTFR_TXFF;
423 pl011IrqUpdate(pDevIns, pThis, pThisCC);
424 fNotifyDrv = true;
425#endif
426 }
427 else
428 pThis->uRegDr = bVal;
429 }
430
431#ifdef IN_RING3
432 if (fNotifyDrv)
433 {
434 /* Leave the device critical section before calling into the lower driver. */
435 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
436
437 if ( pThisCC->pDrvSerial
438 && !(pThis->uRegCr & PL011_REG_UARTCR_LBE))
439 {
440 int rc2 = pThisCC->pDrvSerial->pfnDataAvailWrNotify(pThisCC->pDrvSerial);
441 if (RT_FAILURE(rc2))
442 LogRelMax(10, ("PL011#%d: Failed to send data with %Rrc\n", pDevIns->iInstance, rc2));
443 }
444 else
445 {
446 AssertReleaseFailed(); /** @todo */
447 //PDMDevHlpTimerSetRelative(pDevIns, pThis->hTimerTxUnconnected, pThis->cSymbolXferTicks, NULL);
448 }
449
450 rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VINF_SUCCESS);
451 }
452#endif
453
454 return rc;
455}
456
457
458#ifdef IN_RING3
459/**
460 * Updates the serial port parameters of the attached driver with the current configuration.
461 *
462 * @param pDevIns The device instance.
463 * @param pThis The shared serial port instance data.
464 * @param pThisCC The serial port instance data for the current context.
465 */
466static void pl011R3ParamsUpdate(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC)
467{
468 if ( pThis->uRegIbrd != 0
469 && pThisCC->pDrvSerial)
470 {
471 uint32_t uBps = 460800 / pThis->uRegIbrd; /** @todo This is for a 7.3728MHz clock. */
472 unsigned cDataBits = PL011_REG_UARTLCR_H_WLEN_GET(pThis->uRegLcrH) + 5;
473 uint32_t cFrameBits = cDataBits;
474 PDMSERIALSTOPBITS enmStopBits = PDMSERIALSTOPBITS_ONE;
475 PDMSERIALPARITY enmParity = PDMSERIALPARITY_NONE;
476
477 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_STP2)
478 {
479 enmStopBits = PDMSERIALSTOPBITS_TWO;
480 cFrameBits += 2;
481 }
482 else
483 cFrameBits++;
484
485 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_PEN)
486 {
487 /* Select the correct parity mode based on the even and stick parity bits. */
488 switch (pThis->uRegLcrH & (PL011_REG_UARTLCR_H_EPS | PL011_REG_UARTLCR_H_SPS))
489 {
490 case 0:
491 enmParity = PDMSERIALPARITY_ODD;
492 break;
493 case PL011_REG_UARTLCR_H_EPS:
494 enmParity = PDMSERIALPARITY_EVEN;
495 break;
496 case PL011_REG_UARTLCR_H_EPS | PL011_REG_UARTLCR_H_SPS:
497 enmParity = PDMSERIALPARITY_SPACE;
498 break;
499 case PL011_REG_UARTLCR_H_SPS:
500 enmParity = PDMSERIALPARITY_MARK;
501 break;
502 default:
503 /* We should never get here as all cases where caught earlier. */
504 AssertMsgFailed(("This shouldn't happen at all: %#x\n",
505 pThis->uRegLcrH & (PL011_REG_UARTLCR_H_EPS | PL011_REG_UARTLCR_H_SPS)));
506 }
507
508 cFrameBits++;
509 }
510
511 //uint64_t uTimerFreq = PDMDevHlpTimerGetFreq(pDevIns, pThis->hTimerRcvFifoTimeout);
512 //pThis->cSymbolXferTicks = (uTimerFreq / uBps) * cFrameBits;
513
514 LogFlowFunc(("Changing parameters to: %u,%s,%u,%s\n",
515 uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits]));
516
517 int rc = pThisCC->pDrvSerial->pfnChgParams(pThisCC->pDrvSerial, uBps, enmParity, cDataBits, enmStopBits);
518 if (RT_FAILURE(rc))
519 LogRelMax(10, ("Serial#%d: Failed to change parameters to %u,%s,%u,%s -> %Rrc\n",
520 pDevIns->iInstance, uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits], rc));
521
522 /* Changed parameters will flush all receive queues, so there won't be any data to read even if indicated. */
523 pThisCC->pDrvSerial->pfnQueuesFlush(pThisCC->pDrvSerial, true /*fQueueRecv*/, false /*fQueueXmit*/);
524 ASMAtomicWriteU32(&pThis->cbAvailRdr, 0);
525 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_BUSY | PL011_REG_UARTFR_TXFF);
526 }
527}
528
529
530/**
531 * Reset the transmit/receive related bits to the standard values
532 * (after a detach/attach/reset event).
533 *
534 * @param pDevIns The device instance.
535 * @param pThis The shared serial port instance data.
536 * @param pThisCC The serial port instance data for the current context.
537 */
538static void pl011R3XferReset(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC)
539{
540 //PDMDevHlpTimerStop(pDevIns, pThis->hTimerRcvFifoTimeout);
541 //PDMDevHlpTimerStop(pDevIns, pThis->hTimerTxUnconnected);
542 //pThis->uRegLsr = UART_REG_LSR_THRE | UART_REG_LSR_TEMT;
543
544 //uartFifoClear(&pThis->FifoXmit);
545 //uartFifoClear(&pThis->FifoRecv);
546 pl011R3ParamsUpdate(pDevIns, pThis, pThisCC);
547 pl011IrqUpdate(pDevIns, pThis, pThisCC);
548
549 if (pThisCC->pDrvSerial)
550 {
551 /* Set the modem lines to reflect the current state. */
552 int rc = pThisCC->pDrvSerial->pfnChgModemLines(pThisCC->pDrvSerial, false /*fRts*/, false /*fDtr*/);
553 if (RT_FAILURE(rc))
554 LogRel(("PL011#%d: Failed to set modem lines with %Rrc during reset\n",
555 pDevIns->iInstance, rc));
556
557 uint32_t fStsLines = 0;
558 rc = pThisCC->pDrvSerial->pfnQueryStsLines(pThisCC->pDrvSerial, &fStsLines);
559 if (RT_SUCCESS(rc))
560 {} //uartR3StsLinesUpdate(pDevIns, pThis, pThisCC, fStsLines);
561 else
562 LogRel(("PL011#%d: Failed to query status line status with %Rrc during reset\n",
563 pDevIns->iInstance, rc));
564 }
565
566}
567
568
569/**
570 * Tries to copy the specified amount of data from the active TX queue (register or FIFO).
571 *
572 * @param pDevIns The device instance.
573 * @param pThis The shared serial port instance data.
574 * @param pThisCC The serial port instance data for the current context.
575 * @param pvBuf Where to store the data.
576 * @param cbRead How much to read from the TX queue.
577 * @param pcbRead Where to store the amount of data read.
578 */
579static void pl011R3TxQueueCopyFrom(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC,
580 void *pvBuf, size_t cbRead, size_t *pcbRead)
581{
582 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_FEN)
583 {
584 RT_NOREF(cbRead);
585 AssertReleaseFailed();
586 }
587 else if (pThis->uRegFr & PL011_REG_UARTFR_BUSY)
588 {
589 *(uint8_t *)pvBuf = pThis->uRegDr;
590 *pcbRead = 1;
591 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_BUSY | PL011_REG_UARTFR_TXFF);
592 pl011IrqUpdate(pDevIns, pThis, pThisCC);
593 }
594 else
595 {
596 /*
597 * This can happen if there was data in the FIFO when the connection was closed,
598 * indicate this condition to the lower driver by returning 0 bytes.
599 */
600 *pcbRead = 0;
601 }
602}
603#endif
604
605
606/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
607
608
609/**
610 * @callback_method_impl{FNIOMMMIONEWREAD}
611 */
612static DECLCALLBACK(VBOXSTRICTRC) pl011MmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
613{
614 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
615 NOREF(pvUser);
616 Assert(cb == 4 || cb == 8);
617 Assert(!(off & (cb - 1)));
618
619 LogFlowFunc(("%RGp cb=%u\n", off, cb));
620
621 uint32_t u32Val = 0;
622 VBOXSTRICTRC rc = VINF_SUCCESS;
623 switch (off)
624 {
625 case PL011_REG_UARTFR_INDEX:
626 u32Val = pThis->uRegFr;
627 break;
628 case PL011_REG_UARTCR_INDEX:
629 u32Val = pThis->uRegCr;
630 break;
631 case PL011_REG_UART_PERIPH_ID0_INDEX:
632 u32Val = 0x11;
633 break;
634 case PL011_REG_UART_PERIPH_ID1_INDEX:
635 u32Val = 0x10;
636 break;
637 case PL011_REG_UART_PERIPH_ID2_INDEX:
638 u32Val = 0x34; /* r1p5 */
639 break;
640 case PL011_REG_UART_PERIPH_ID3_INDEX:
641 u32Val = 0x00;
642 break;
643 case PL011_REG_UART_PCELL_ID0_INDEX:
644 u32Val = 0x0d;
645 break;
646 case PL011_REG_UART_PCELL_ID1_INDEX:
647 u32Val = 0xf0;
648 break;
649 case PL011_REG_UART_PCELL_ID2_INDEX:
650 u32Val = 0x05;
651 break;
652 case PL011_REG_UART_PCELL_ID3_INDEX:
653 u32Val = 0xb1;
654 break;
655 default:
656 break;
657 }
658
659 if (rc == VINF_SUCCESS)
660 *(uint32_t *)pv = u32Val;
661
662 return rc;
663}
664
665
666/**
667 * @callback_method_impl{FNIOMMMIONEWWRITE}
668 */
669static DECLCALLBACK(VBOXSTRICTRC) pl011MmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
670{
671 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
672 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
673 LogFlowFunc(("cb=%u reg=%RGp val=%llx\n", cb, off, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef));
674 RT_NOREF(pvUser);
675 Assert(cb == 4 || cb == 8);
676 Assert(!(off & (cb - 1)));
677
678 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
679 uint32_t u32Val = *(uint32_t *)pv;
680 switch (off)
681 {
682 case PL011_REG_UARTDR_INDEX:
683 if ( (pThis->uRegCr & PL011_REG_UARTCR_UARTEN)
684 && (pThis->uRegCr & PL011_REG_UARTCR_TXE))
685 rcStrict = pl011Xmit(pDevIns, pThisCC, pThis, (uint8_t)u32Val);
686 break;
687 default:
688 break;
689
690 }
691 return rcStrict;
692}
693
694
695#ifdef IN_RING3
696
697/* -=-=-=-=-=-=-=-=- PDMISERIALPORT on LUN#0 -=-=-=-=-=-=-=-=- */
698
699
700/**
701 * @interface_method_impl{PDMISERIALPORT,pfnDataAvailRdrNotify}
702 */
703static DECLCALLBACK(int) pl011R3DataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
704{
705 LogFlowFunc(("pInterface=%#p cbAvail=%zu\n", pInterface, cbAvail));
706 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
707 PPDMDEVINS pDevIns = pThisCC->pDevIns;
708 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
709
710 AssertMsg((uint32_t)cbAvail == cbAvail, ("Too much data available\n"));
711
712 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
713 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
714
715 /** @todo */
716 RT_NOREF(pThis);
717
718 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
719 return VINF_SUCCESS;
720}
721
722
723/**
724 * @interface_method_impl{PDMISERIALPORT,pfnDataSentNotify}
725 */
726static DECLCALLBACK(int) pl011R3DataSentNotify(PPDMISERIALPORT pInterface)
727{
728 LogFlowFunc(("pInterface=%#p\n", pInterface));
729 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
730 PPDMDEVINS pDevIns = pThisCC->pDevIns;
731 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
732
733 /* Set the transmitter empty bit because everything was sent. */
734 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
735 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
736
737 /** @todo */
738 RT_NOREF(pThis);
739
740 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
741 return VINF_SUCCESS;
742}
743
744
745/**
746 * @interface_method_impl{PDMISERIALPORT,pfnReadWr}
747 */
748static DECLCALLBACK(int) pl011R3ReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
749{
750 LogFlowFunc(("pInterface=%#p pvBuf=%#p cbRead=%zu pcbRead=%#p\n", pInterface, pvBuf, cbRead, pcbRead));
751 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
752 PPDMDEVINS pDevIns = pThisCC->pDevIns;
753 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
754
755 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
756
757 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
758 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
759
760 pl011R3TxQueueCopyFrom(pDevIns, pThis, pThisCC, pvBuf, cbRead, pcbRead);
761
762 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
763 LogFlowFunc(("-> VINF_SUCCESS{*pcbRead=%zu}\n", *pcbRead));
764 return VINF_SUCCESS;
765}
766
767
768/**
769 * @interface_method_impl{PDMISERIALPORT,pfnNotifyStsLinesChanged}
770 */
771static DECLCALLBACK(int) pl011R3NotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
772{
773 LogFlowFunc(("pInterface=%#p fNewStatusLines=%#x\n", pInterface, fNewStatusLines));
774 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
775 PPDMDEVINS pDevIns = pThisCC->pDevIns;
776 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
777
778 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
779 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
780
781 /** @todo */
782 RT_NOREF(pThis);
783
784 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
785 return VINF_SUCCESS;
786}
787
788
789/**
790 * @interface_method_impl{PDMISERIALPORT,pfnNotifyBrk}
791 */
792static DECLCALLBACK(int) pl011R3NotifyBrk(PPDMISERIALPORT pInterface)
793{
794 LogFlowFunc(("pInterface=%#p\n", pInterface));
795 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
796 PPDMDEVINS pDevIns = pThisCC->pDevIns;
797 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
798
799 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
800 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
801
802 /** @todo */
803 RT_NOREF(pThis);
804
805 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
806 return VINF_SUCCESS;
807}
808
809
810/* -=-=-=-=-=-=-=-=- PDMIBASE -=-=-=-=-=-=-=-=- */
811
812/**
813 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
814 */
815static DECLCALLBACK(void *) pl011R3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
816{
817 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, IBase);
818 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
819 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALPORT, &pThisCC->ISerialPort);
820 return NULL;
821}
822
823
824/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
825
826/**
827 * @callback_method_impl{FNSSMDEVLIVEEXEC}
828 */
829static DECLCALLBACK(int) pl011R3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
830{
831 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
832 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
833 RT_NOREF(uPass);
834
835 pHlp->pfnSSMPutU16(pSSM, pThis->u16Irq);
836 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmioBase);
837 return VINF_SSM_DONT_CALL_AGAIN;
838}
839
840
841/**
842 * @callback_method_impl{FNSSMDEVSAVEEXEC}
843 */
844static DECLCALLBACK(int) pl011R3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
845{
846 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
847 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
848
849 pHlp->pfnSSMPutU16(pSSM, pThis->u16Irq);
850 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmioBase);
851
852 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
853}
854
855
856/**
857 * @callback_method_impl{FNSSMDEVLOADEXEC}
858 */
859static DECLCALLBACK(int) pl011R3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
860{
861 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
862 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
863 uint16_t u16Irq;
864 RTGCPHYS GCPhysMmioBase;
865 int rc;
866
867 RT_NOREF(uVersion);
868
869 pHlp->pfnSSMGetU16( pSSM, &u16Irq);
870 pHlp->pfnSSMGetGCPhys(pSSM, &GCPhysMmioBase);
871 if (uPass == SSM_PASS_FINAL)
872 {
873 rc = VERR_NOT_IMPLEMENTED;
874 AssertRCReturn(rc, rc);
875 }
876
877 if (uPass == SSM_PASS_FINAL)
878 {
879 /* The marker. */
880 uint32_t u32;
881 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
882 AssertRCReturn(rc, rc);
883 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
884 }
885
886 /*
887 * Check the config.
888 */
889 if ( pThis->u16Irq != u16Irq
890 || pThis->GCPhysMmioBase != GCPhysMmioBase)
891 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
892 N_("Config mismatch - saved Irq=%#x GCPhysMmioBase=%#RGp; configured Irq=%#x GCPhysMmioBase=%#RGp"),
893 u16Irq, GCPhysMmioBase, pThis->u16Irq, pThis->GCPhysMmioBase);
894
895 return VINF_SUCCESS;
896}
897
898
899/**
900 * @callback_method_impl{FNSSMDEVLOADDONE}
901 */
902static DECLCALLBACK(int) pl011R3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
903{
904 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
905 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
906
907 RT_NOREF(pThis, pThisCC, pSSM);
908 return VERR_NOT_IMPLEMENTED;
909}
910
911
912/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
913
914/**
915 * @interface_method_impl{PDMDEVREG,pfnReset}
916 */
917static DECLCALLBACK(void) pl011R3Reset(PPDMDEVINS pDevIns)
918{
919 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
920 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
921
922 pThis->uRegDr = 0;
923 /* UARTEN is normally 0 on reset but UEFI doesn't set it causing the serial port to not log anything. */
924 pThis->uRegCr = PL011_REG_UARTCR_TXE | PL011_REG_UARTCR_RXE | PL011_REG_UARTCR_UARTEN;
925 pThis->uRegFr = PL011_REG_UARTFR_TXFE | PL011_REG_UARTFR_RXFE;
926 pThis->uRegIbrd = 0;
927 pThis->uRegFbrd = 0;
928 pThis->uRegLcrH = 0;
929 /** @todo */
930
931 pl011R3XferReset(pDevIns, pThis, pThisCC);
932}
933
934
935/**
936 * @interface_method_impl{PDMDEVREG,pfnAttach}
937 */
938static DECLCALLBACK(int) pl011R3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
939{
940 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
941 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
942 RT_NOREF(fFlags);
943 AssertReturn(iLUN == 0, VERR_PDM_LUN_NOT_FOUND);
944
945 int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThisCC->IBase, &pThisCC->pDrvBase, "PL011 Char");
946 if (RT_SUCCESS(rc))
947 {
948 pThisCC->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMISERIALCONNECTOR);
949 if (!pThisCC->pDrvSerial)
950 {
951 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", pDevIns->iInstance));
952 return VERR_PDM_MISSING_INTERFACE;
953 }
954 rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
955 if (RT_SUCCESS(rc))
956 {
957 pl011R3XferReset(pDevIns, pThis, pThisCC);
958 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
959 }
960 }
961 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
962 {
963 pThisCC->pDrvBase = NULL;
964 pThisCC->pDrvSerial = NULL;
965 rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
966 if (RT_SUCCESS(rc))
967 {
968 pl011R3XferReset(pDevIns, pThis, pThisCC);
969 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
970 }
971 LogRel(("PL011#%d: no unit\n", pDevIns->iInstance));
972 }
973 else /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
974 LogRel(("PL011#%d: Failed to attach to serial driver. rc=%Rrc\n", pDevIns->iInstance, rc));
975
976 return rc;
977}
978
979
980/**
981 * @interface_method_impl{PDMDEVREG,pfnDetach}
982 */
983static DECLCALLBACK(void) pl011R3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
984{
985 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
986 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
987 RT_NOREF(fFlags);
988 AssertReturnVoid(iLUN == 0);
989
990 /* Zero out important members. */
991 pThisCC->pDrvBase = NULL;
992 pThisCC->pDrvSerial = NULL;
993
994 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
995 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
996
997 pl011R3XferReset(pDevIns, pThis, pThisCC);
998
999 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1000}
1001
1002
1003/**
1004 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1005 */
1006static DECLCALLBACK(int) pl011R3Destruct(PPDMDEVINS pDevIns)
1007{
1008 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1009
1010 /* Nothing to do. */
1011 return VINF_SUCCESS;
1012}
1013
1014
1015/**
1016 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1017 */
1018static DECLCALLBACK(int) pl011R3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1019{
1020 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1021 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1022 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
1023 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1024 int rc;
1025
1026 Assert(iInstance < 4);
1027
1028 pThisCC->pDevIns = pDevIns;
1029
1030 /* IBase */
1031 pThisCC->IBase.pfnQueryInterface = pl011R3QueryInterface;
1032
1033 /* ISerialPort */
1034 pThisCC->ISerialPort.pfnDataAvailRdrNotify = pl011R3DataAvailRdrNotify;
1035 pThisCC->ISerialPort.pfnDataSentNotify = pl011R3DataSentNotify;
1036 pThisCC->ISerialPort.pfnReadWr = pl011R3ReadWr;
1037 pThisCC->ISerialPort.pfnNotifyStsLinesChanged = pl011R3NotifyStsLinesChanged;
1038 pThisCC->ISerialPort.pfnNotifyBrk = pl011R3NotifyBrk;
1039
1040 /*
1041 * Validate and read the configuration.
1042 */
1043 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Irq|MmioBase|YieldOnLSRRead", "");
1044
1045 bool fYieldOnLSRRead = false;
1046 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "YieldOnLSRRead", &fYieldOnLSRRead, false);
1047 if (RT_FAILURE(rc))
1048 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
1049
1050 uint16_t u16Irq = 0;
1051 rc = pHlp->pfnCFGMQueryU16(pCfg, "Irq", &u16Irq);
1052 if (RT_FAILURE(rc))
1053 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Irq\" value"));
1054
1055 RTGCPHYS GCPhysMmioBase = 0;
1056 rc = pHlp->pfnCFGMQueryU64(pCfg, "MmioBase", &GCPhysMmioBase);
1057 if (RT_FAILURE(rc))
1058 return PDMDEV_SET_ERROR(pDevIns, rc,
1059 N_("Configuration error: Failed to get the \"IOBase\" value"));
1060
1061 pThis->u16Irq = u16Irq;
1062 pThis->GCPhysMmioBase = GCPhysMmioBase;
1063
1064 /*
1065 * Register and map the MMIO region.
1066 */
1067 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmioBase, PL011_MMIO_SIZE, pl011MmioWrite, pl011MmioRead,
1068 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "PL011", &pThis->hMmio);
1069 AssertRCReturn(rc, rc);
1070
1071
1072 /*
1073 * Saved state.
1074 */
1075 rc = PDMDevHlpSSMRegisterEx(pDevIns, PL011_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
1076 NULL, pl011R3LiveExec, NULL,
1077 NULL, pl011R3SaveExec, NULL,
1078 NULL, pl011R3LoadExec, pl011R3LoadDone);
1079 AssertRCReturn(rc, rc);
1080
1081 /*
1082 * Attach the char driver and get the interfaces.
1083 */
1084 rc = PDMDevHlpDriverAttach(pDevIns, 0 /*iLUN*/, &pThisCC->IBase, &pThisCC->pDrvBase, "UART");
1085 if (RT_SUCCESS(rc))
1086 {
1087 pThisCC->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMISERIALCONNECTOR);
1088 if (!pThisCC->pDrvSerial)
1089 {
1090 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", iInstance));
1091 return VERR_PDM_MISSING_INTERFACE;
1092 }
1093 }
1094 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1095 {
1096 pThisCC->pDrvBase = NULL;
1097 pThisCC->pDrvSerial = NULL;
1098 LogRel(("PL011#%d: no unit\n", iInstance));
1099 }
1100 else
1101 {
1102 AssertLogRelMsgFailed(("PL011#%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
1103 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1104 return rc;
1105 }
1106
1107 pl011R3Reset(pDevIns);
1108 return VINF_SUCCESS;
1109}
1110
1111#else /* !IN_RING3 */
1112
1113/**
1114 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1115 */
1116static DECLCALLBACK(int) pl011RZConstruct(PPDMDEVINS pDevIns)
1117{
1118 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1119 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1120 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
1121
1122 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, pl011MmioWrite, pl011MmioRead, NULL /*pvUser*/);
1123 AssertRCReturn(rc, rc);
1124
1125 return VINF_SUCCESS;
1126}
1127
1128#endif /* !IN_RING3 */
1129
1130/**
1131 * The device registration structure.
1132 */
1133const PDMDEVREG g_DevicePl011 =
1134{
1135 /* .u32Version = */ PDM_DEVREG_VERSION,
1136 /* .uReserved0 = */ 0,
1137 /* .szName = */ "arm-pl011",
1138 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1139 /* .fClass = */ PDM_DEVREG_CLASS_SERIAL,
1140 /* .cMaxInstances = */ UINT32_MAX,
1141 /* .uSharedVersion = */ 42,
1142 /* .cbInstanceShared = */ sizeof(DEVPL011),
1143 /* .cbInstanceCC = */ sizeof(DEVPL011CC),
1144 /* .cbInstanceRC = */ sizeof(DEVPL011RC),
1145 /* .cMaxPciDevices = */ 0,
1146 /* .cMaxMsixVectors = */ 0,
1147 /* .pszDescription = */ "ARM PL011 PrimeCell UART",
1148#if defined(IN_RING3)
1149 /* .pszRCMod = */ "VBoxDDRC.rc",
1150 /* .pszR0Mod = */ "VBoxDDR0.r0",
1151 /* .pfnConstruct = */ pl011R3Construct,
1152 /* .pfnDestruct = */ pl011R3Destruct,
1153 /* .pfnRelocate = */ NULL,
1154 /* .pfnMemSetup = */ NULL,
1155 /* .pfnPowerOn = */ NULL,
1156 /* .pfnReset = */ pl011R3Reset,
1157 /* .pfnSuspend = */ NULL,
1158 /* .pfnResume = */ NULL,
1159 /* .pfnAttach = */ pl011R3Attach,
1160 /* .pfnDetach = */ pl011R3Detach,
1161 /* .pfnQueryInterface = */ NULL,
1162 /* .pfnInitComplete = */ NULL,
1163 /* .pfnPowerOff = */ NULL,
1164 /* .pfnSoftReset = */ NULL,
1165 /* .pfnReserved0 = */ NULL,
1166 /* .pfnReserved1 = */ NULL,
1167 /* .pfnReserved2 = */ NULL,
1168 /* .pfnReserved3 = */ NULL,
1169 /* .pfnReserved4 = */ NULL,
1170 /* .pfnReserved5 = */ NULL,
1171 /* .pfnReserved6 = */ NULL,
1172 /* .pfnReserved7 = */ NULL,
1173#elif defined(IN_RING0)
1174 /* .pfnEarlyConstruct = */ NULL,
1175 /* .pfnConstruct = */ pl011RZConstruct,
1176 /* .pfnDestruct = */ NULL,
1177 /* .pfnFinalDestruct = */ NULL,
1178 /* .pfnRequest = */ NULL,
1179 /* .pfnReserved0 = */ NULL,
1180 /* .pfnReserved1 = */ NULL,
1181 /* .pfnReserved2 = */ NULL,
1182 /* .pfnReserved3 = */ NULL,
1183 /* .pfnReserved4 = */ NULL,
1184 /* .pfnReserved5 = */ NULL,
1185 /* .pfnReserved6 = */ NULL,
1186 /* .pfnReserved7 = */ NULL,
1187#elif defined(IN_RC)
1188 /* .pfnConstruct = */ pl011RZConstruct,
1189 /* .pfnReserved0 = */ NULL,
1190 /* .pfnReserved1 = */ NULL,
1191 /* .pfnReserved2 = */ NULL,
1192 /* .pfnReserved3 = */ NULL,
1193 /* .pfnReserved4 = */ NULL,
1194 /* .pfnReserved5 = */ NULL,
1195 /* .pfnReserved6 = */ NULL,
1196 /* .pfnReserved7 = */ NULL,
1197#else
1198# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1199#endif
1200 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1201};
1202
1203#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1204
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use