VirtualBox

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

Last change on this file since 99404 was 99152, checked in by vboxsync, 21 months ago

Devices: Updates to the ARM PL011 UART emulation, bugref:10403

  • 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 99152 2023-03-23 18:15:43Z 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 * @returns nothing.
383 * @param pDevIns The device instance.
384 * @param pThis The shared serial port instance data.
385 * @param pThisCC The serial port instance data for the current context.
386 */
387static void pl011IrqUpdate(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC)
388{
389 LogFlowFunc(("pThis=%#p\n", pThis));
390 RT_NOREF(pDevIns, pThis, pThisCC);
391}
392
393
394/**
395 * Transmits the given byte.
396 *
397 * @returns Strict VBox status code.
398 * @param pDevIns The device instance.
399 * @param pThis The shared serial port instance data.
400 * @param pThisCC The serial port instance data for the current context.
401 * @param bVal Byte to transmit.
402 */
403static VBOXSTRICTRC pl011Xmit(PPDMDEVINS pDevIns, PDEVPL011CC pThisCC, PDEVPL011 pThis, uint8_t bVal)
404{
405 int rc = VINF_SUCCESS;
406#ifdef IN_RING3
407 bool fNotifyDrv = false;
408#endif
409
410 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_FEN)
411 {
412 AssertReleaseFailed(); /** @todo */
413 }
414 else
415 {
416 /* Notify the lower driver about available data only if the register was empty before. */
417 if (!(pThis->uRegFr & PL011_REG_UARTFR_BUSY))
418 {
419#ifndef IN_RING3
420 rc = VINF_IOM_R3_IOPORT_WRITE;
421#else
422 pThis->uRegDr = bVal;
423 pThis->uRegFr |= PL011_REG_UARTFR_BUSY;
424 pl011IrqUpdate(pDevIns, pThis, pThisCC);
425 fNotifyDrv = true;
426#endif
427 }
428 else
429 pThis->uRegDr = bVal;
430 }
431
432#ifdef IN_RING3
433 if (fNotifyDrv)
434 {
435 /* Leave the device critical section before calling into the lower driver. */
436 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
437
438 if ( pThisCC->pDrvSerial
439 && !(pThis->uRegCr & PL011_REG_UARTCR_LBE))
440 {
441 int rc2 = pThisCC->pDrvSerial->pfnDataAvailWrNotify(pThisCC->pDrvSerial);
442 if (RT_FAILURE(rc2))
443 LogRelMax(10, ("PL011#%d: Failed to send data with %Rrc\n", pDevIns->iInstance, rc2));
444 }
445 else
446 {
447 AssertReleaseFailed(); /** @todo */
448 //PDMDevHlpTimerSetRelative(pDevIns, pThis->hTimerTxUnconnected, pThis->cSymbolXferTicks, NULL);
449 }
450
451 rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VINF_SUCCESS);
452 }
453#endif
454
455 return rc;
456}
457
458
459#ifdef IN_RING3
460/**
461 * Updates the serial port parameters of the attached driver with the current configuration.
462 *
463 * @returns nothing.
464 * @param pDevIns The device instance.
465 * @param pThis The shared serial port instance data.
466 * @param pThisCC The serial port instance data for the current context.
467 */
468static void pl011R3ParamsUpdate(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC)
469{
470 if ( pThis->uRegIbrd != 0
471 && pThisCC->pDrvSerial)
472 {
473 uint32_t uBps = 460800 / pThis->uRegIbrd; /** @todo This is for a 7.3728MHz clock. */
474 unsigned cDataBits = PL011_REG_UARTLCR_H_WLEN_GET(pThis->uRegLcrH) + 5;
475 uint32_t cFrameBits = cDataBits;
476 PDMSERIALSTOPBITS enmStopBits = PDMSERIALSTOPBITS_ONE;
477 PDMSERIALPARITY enmParity = PDMSERIALPARITY_NONE;
478
479 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_STP2)
480 {
481 enmStopBits = PDMSERIALSTOPBITS_TWO;
482 cFrameBits += 2;
483 }
484 else
485 cFrameBits++;
486
487 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_PEN)
488 {
489 /* Select the correct parity mode based on the even and stick parity bits. */
490 switch (pThis->uRegLcrH & (PL011_REG_UARTLCR_H_EPS | PL011_REG_UARTLCR_H_SPS))
491 {
492 case 0:
493 enmParity = PDMSERIALPARITY_ODD;
494 break;
495 case PL011_REG_UARTLCR_H_EPS:
496 enmParity = PDMSERIALPARITY_EVEN;
497 break;
498 case PL011_REG_UARTLCR_H_EPS | PL011_REG_UARTLCR_H_SPS:
499 enmParity = PDMSERIALPARITY_SPACE;
500 break;
501 case PL011_REG_UARTLCR_H_SPS:
502 enmParity = PDMSERIALPARITY_MARK;
503 break;
504 default:
505 /* We should never get here as all cases where caught earlier. */
506 AssertMsgFailed(("This shouldn't happen at all: %#x\n",
507 pThis->uRegLcrH & (PL011_REG_UARTLCR_H_EPS | PL011_REG_UARTLCR_H_SPS)));
508 }
509
510 cFrameBits++;
511 }
512
513 //uint64_t uTimerFreq = PDMDevHlpTimerGetFreq(pDevIns, pThis->hTimerRcvFifoTimeout);
514 //pThis->cSymbolXferTicks = (uTimerFreq / uBps) * cFrameBits;
515
516 LogFlowFunc(("Changing parameters to: %u,%s,%u,%s\n",
517 uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits]));
518
519 int rc = pThisCC->pDrvSerial->pfnChgParams(pThisCC->pDrvSerial, uBps, enmParity, cDataBits, enmStopBits);
520 if (RT_FAILURE(rc))
521 LogRelMax(10, ("Serial#%d: Failed to change parameters to %u,%s,%u,%s -> %Rrc\n",
522 pDevIns->iInstance, uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits], rc));
523
524 /* Changed parameters will flush all receive queues, so there won't be any data to read even if indicated. */
525 pThisCC->pDrvSerial->pfnQueuesFlush(pThisCC->pDrvSerial, true /*fQueueRecv*/, false /*fQueueXmit*/);
526 ASMAtomicWriteU32(&pThis->cbAvailRdr, 0);
527 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_BUSY);
528 }
529}
530
531
532/**
533 * Reset the transmit/receive related bits to the standard values
534 * (after a detach/attach/reset event).
535 *
536 * @returns nothing.
537 * @param pDevIns The device instance.
538 * @param pThis The shared serial port instance data.
539 * @param pThisCC The serial port instance data for the current context.
540 */
541static void pl011R3XferReset(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC)
542{
543 //PDMDevHlpTimerStop(pDevIns, pThis->hTimerRcvFifoTimeout);
544 //PDMDevHlpTimerStop(pDevIns, pThis->hTimerTxUnconnected);
545 //pThis->uRegLsr = UART_REG_LSR_THRE | UART_REG_LSR_TEMT;
546
547 //uartFifoClear(&pThis->FifoXmit);
548 //uartFifoClear(&pThis->FifoRecv);
549 pl011R3ParamsUpdate(pDevIns, pThis, pThisCC);
550 pl011IrqUpdate(pDevIns, pThis, pThisCC);
551
552 if (pThisCC->pDrvSerial)
553 {
554 /* Set the modem lines to reflect the current state. */
555 int rc = pThisCC->pDrvSerial->pfnChgModemLines(pThisCC->pDrvSerial, false /*fRts*/, false /*fDtr*/);
556 if (RT_FAILURE(rc))
557 LogRel(("PL011#%d: Failed to set modem lines with %Rrc during reset\n",
558 pDevIns->iInstance, rc));
559
560 uint32_t fStsLines = 0;
561 rc = pThisCC->pDrvSerial->pfnQueryStsLines(pThisCC->pDrvSerial, &fStsLines);
562 if (RT_SUCCESS(rc))
563 {} //uartR3StsLinesUpdate(pDevIns, pThis, pThisCC, fStsLines);
564 else
565 LogRel(("PL011#%d: Failed to query status line status with %Rrc during reset\n",
566 pDevIns->iInstance, rc));
567 }
568
569}
570
571
572/**
573 * Tries to copy the specified amount of data from the active TX queue (register or FIFO).
574 *
575 * @returns nothing.
576 * @param pDevIns The device instance.
577 * @param pThis The shared serial port instance data.
578 * @param pThisCC The serial port instance data for the current context.
579 * @param pvBuf Where to store the data.
580 * @param cbRead How much to read from the TX queue.
581 * @param pcbRead Where to store the amount of data read.
582 */
583static void pl011R3TxQueueCopyFrom(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC,
584 void *pvBuf, size_t cbRead, size_t *pcbRead)
585{
586 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_FEN)
587 {
588 RT_NOREF(cbRead);
589 AssertReleaseFailed();
590 }
591 else if (pThis->uRegFr & PL011_REG_UARTFR_BUSY)
592 {
593 *(uint8_t *)pvBuf = pThis->uRegDr;
594 *pcbRead = 1;
595 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_BUSY);
596 pl011IrqUpdate(pDevIns, pThis, pThisCC);
597 }
598 else
599 {
600 /*
601 * This can happen if there was data in the FIFO when the connection was closed,
602 * indicate this condition to the lower driver by returning 0 bytes.
603 */
604 *pcbRead = 0;
605 }
606}
607#endif
608
609
610/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
611
612
613/**
614 * @callback_method_impl{FNIOMMMIONEWREAD}
615 */
616static DECLCALLBACK(VBOXSTRICTRC) pl011MmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
617{
618 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
619 NOREF(pvUser);
620 Assert(cb == 4 || cb == 8);
621 Assert(!(off & (cb - 1)));
622
623 LogFlowFunc(("%RGp cb=%u\n", off, cb));
624
625 uint32_t u32Val = 0;
626 VBOXSTRICTRC rc = VINF_SUCCESS;
627 switch (off)
628 {
629 case PL011_REG_UARTFR_INDEX:
630 u32Val = pThis->uRegFr;
631 break;
632 case PL011_REG_UARTCR_INDEX:
633 u32Val = pThis->uRegCr;
634 break;
635 case PL011_REG_UART_PERIPH_ID0_INDEX:
636 u32Val = 0x11;
637 break;
638 case PL011_REG_UART_PERIPH_ID1_INDEX:
639 u32Val = 0x10;
640 break;
641 case PL011_REG_UART_PERIPH_ID2_INDEX:
642 u32Val = 0x34; /* r1p5 */
643 break;
644 case PL011_REG_UART_PERIPH_ID3_INDEX:
645 u32Val = 0x00;
646 break;
647 case PL011_REG_UART_PCELL_ID0_INDEX:
648 u32Val = 0x0d;
649 break;
650 case PL011_REG_UART_PCELL_ID1_INDEX:
651 u32Val = 0xf0;
652 break;
653 case PL011_REG_UART_PCELL_ID2_INDEX:
654 u32Val = 0x05;
655 break;
656 case PL011_REG_UART_PCELL_ID3_INDEX:
657 u32Val = 0xb1;
658 break;
659 default:
660 break;
661 }
662
663 if (rc == VINF_SUCCESS)
664 *(uint32_t *)pv = u32Val;
665
666 return rc;
667}
668
669
670/**
671 * @callback_method_impl{FNIOMMMIONEWWRITE}
672 */
673static DECLCALLBACK(VBOXSTRICTRC) pl011MmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
674{
675 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
676 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
677 LogFlowFunc(("cb=%u reg=%RGp val=%llx\n", cb, off, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef));
678 RT_NOREF(pvUser);
679 Assert(cb == 4 || cb == 8);
680 Assert(!(off & (cb - 1)));
681
682 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
683 uint32_t u32Val = *(uint32_t *)pv;
684 switch (off)
685 {
686 case PL011_REG_UARTDR_INDEX:
687 if ( (pThis->uRegCr & PL011_REG_UARTCR_UARTEN)
688 && (pThis->uRegCr & PL011_REG_UARTCR_TXE))
689 rcStrict = pl011Xmit(pDevIns, pThisCC, pThis, (uint8_t)u32Val);
690 break;
691 default:
692 break;
693
694 }
695 return rcStrict;
696}
697
698
699#ifdef IN_RING3
700
701/* -=-=-=-=-=-=-=-=- PDMISERIALPORT on LUN#0 -=-=-=-=-=-=-=-=- */
702
703
704/**
705 * @interface_method_impl{PDMISERIALPORT,pfnDataAvailRdrNotify}
706 */
707static DECLCALLBACK(int) pl011R3DataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
708{
709 LogFlowFunc(("pInterface=%#p cbAvail=%zu\n", pInterface, cbAvail));
710 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
711 PPDMDEVINS pDevIns = pThisCC->pDevIns;
712 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
713
714 AssertMsg((uint32_t)cbAvail == cbAvail, ("Too much data available\n"));
715
716 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
717 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
718
719 /** @todo */
720 RT_NOREF(pThis);
721
722 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
723 return VINF_SUCCESS;
724}
725
726
727/**
728 * @interface_method_impl{PDMISERIALPORT,pfnDataSentNotify}
729 */
730static DECLCALLBACK(int) pl011R3DataSentNotify(PPDMISERIALPORT pInterface)
731{
732 LogFlowFunc(("pInterface=%#p\n", pInterface));
733 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
734 PPDMDEVINS pDevIns = pThisCC->pDevIns;
735 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
736
737 /* Set the transmitter empty bit because everything was sent. */
738 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
739 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
740
741 /** @todo */
742 RT_NOREF(pThis);
743
744 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
745 return VINF_SUCCESS;
746}
747
748
749/**
750 * @interface_method_impl{PDMISERIALPORT,pfnReadWr}
751 */
752static DECLCALLBACK(int) pl011R3ReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
753{
754 LogFlowFunc(("pInterface=%#p pvBuf=%#p cbRead=%zu pcbRead=%#p\n", pInterface, pvBuf, cbRead, pcbRead));
755 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
756 PPDMDEVINS pDevIns = pThisCC->pDevIns;
757 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
758
759 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
760
761 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
762 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
763
764 pl011R3TxQueueCopyFrom(pDevIns, pThis, pThisCC, pvBuf, cbRead, pcbRead);
765
766 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
767 LogFlowFunc(("-> VINF_SUCCESS{*pcbRead=%zu}\n", *pcbRead));
768 return VINF_SUCCESS;
769}
770
771
772/**
773 * @interface_method_impl{PDMISERIALPORT,pfnNotifyStsLinesChanged}
774 */
775static DECLCALLBACK(int) pl011R3NotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
776{
777 LogFlowFunc(("pInterface=%#p fNewStatusLines=%#x\n", pInterface, fNewStatusLines));
778 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
779 PPDMDEVINS pDevIns = pThisCC->pDevIns;
780 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
781
782 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
783 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
784
785 /** @todo */
786 RT_NOREF(pThis);
787
788 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
789 return VINF_SUCCESS;
790}
791
792
793/**
794 * @interface_method_impl{PDMISERIALPORT,pfnNotifyBrk}
795 */
796static DECLCALLBACK(int) pl011R3NotifyBrk(PPDMISERIALPORT pInterface)
797{
798 LogFlowFunc(("pInterface=%#p\n", pInterface));
799 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
800 PPDMDEVINS pDevIns = pThisCC->pDevIns;
801 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
802
803 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
804 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
805
806 /** @todo */
807 RT_NOREF(pThis);
808
809 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
810 return VINF_SUCCESS;
811}
812
813
814/* -=-=-=-=-=-=-=-=- PDMIBASE -=-=-=-=-=-=-=-=- */
815
816/**
817 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
818 */
819static DECLCALLBACK(void *) pl011R3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
820{
821 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, IBase);
822 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
823 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALPORT, &pThisCC->ISerialPort);
824 return NULL;
825}
826
827
828/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
829
830/**
831 * @callback_method_impl{FNSSMDEVLIVEEXEC}
832 */
833static DECLCALLBACK(int) pl011R3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
834{
835 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
836 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
837 RT_NOREF(uPass);
838
839 pHlp->pfnSSMPutU16(pSSM, pThis->u16Irq);
840 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmioBase);
841 return VINF_SSM_DONT_CALL_AGAIN;
842}
843
844
845/**
846 * @callback_method_impl{FNSSMDEVSAVEEXEC}
847 */
848static DECLCALLBACK(int) pl011R3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
849{
850 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
851 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
852
853 pHlp->pfnSSMPutU16(pSSM, pThis->u16Irq);
854 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmioBase);
855
856 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
857}
858
859
860/**
861 * @callback_method_impl{FNSSMDEVLOADEXEC}
862 */
863static DECLCALLBACK(int) pl011R3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
864{
865 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
866 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
867 uint16_t u16Irq;
868 RTGCPHYS GCPhysMmioBase;
869 int rc;
870
871 RT_NOREF(uVersion);
872
873 pHlp->pfnSSMGetU16( pSSM, &u16Irq);
874 pHlp->pfnSSMGetGCPhys(pSSM, &GCPhysMmioBase);
875 if (uPass == SSM_PASS_FINAL)
876 {
877 rc = VERR_NOT_IMPLEMENTED;
878 AssertRCReturn(rc, rc);
879 }
880
881 if (uPass == SSM_PASS_FINAL)
882 {
883 /* The marker. */
884 uint32_t u32;
885 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
886 AssertRCReturn(rc, rc);
887 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
888 }
889
890 /*
891 * Check the config.
892 */
893 if ( pThis->u16Irq != u16Irq
894 || pThis->GCPhysMmioBase != GCPhysMmioBase)
895 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
896 N_("Config mismatch - saved Irq=%#x GCPhysMmioBase=%#RGp; configured Irq=%#x GCPhysMmioBase=%#RGp"),
897 u16Irq, GCPhysMmioBase, pThis->u16Irq, pThis->GCPhysMmioBase);
898
899 return VINF_SUCCESS;
900}
901
902
903/**
904 * @callback_method_impl{FNSSMDEVLOADDONE}
905 */
906static DECLCALLBACK(int) pl011R3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
907{
908 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
909 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
910
911 RT_NOREF(pThis, pThisCC, pSSM);
912 return VERR_NOT_IMPLEMENTED;
913}
914
915
916/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
917
918/**
919 * @interface_method_impl{PDMDEVREG,pfnReset}
920 */
921static DECLCALLBACK(void) pl011R3Reset(PPDMDEVINS pDevIns)
922{
923 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
924 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
925
926 pThis->uRegDr = 0;
927 /* UARTEN is normally 0 on reset but UEFI doesn't set it causing the serial port to not log anything. */
928 pThis->uRegCr = PL011_REG_UARTCR_TXE | PL011_REG_UARTCR_RXE | PL011_REG_UARTCR_UARTEN;
929 pThis->uRegFr = PL011_REG_UARTFR_TXFE | PL011_REG_UARTFR_RXFE;
930 pThis->uRegIbrd = 0;
931 pThis->uRegFbrd = 0;
932 pThis->uRegLcrH = 0;
933 /** @todo */
934
935 pl011R3XferReset(pDevIns, pThis, pThisCC);
936}
937
938
939/**
940 * @interface_method_impl{PDMDEVREG,pfnAttach}
941 */
942static DECLCALLBACK(int) pl011R3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
943{
944 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
945 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
946 RT_NOREF(fFlags);
947 AssertReturn(iLUN == 0, VERR_PDM_LUN_NOT_FOUND);
948
949 int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThisCC->IBase, &pThisCC->pDrvBase, "PL011 Char");
950 if (RT_SUCCESS(rc))
951 {
952 pThisCC->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMISERIALCONNECTOR);
953 if (!pThisCC->pDrvSerial)
954 {
955 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", pDevIns->iInstance));
956 return VERR_PDM_MISSING_INTERFACE;
957 }
958 rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
959 if (RT_SUCCESS(rc))
960 {
961 pl011R3XferReset(pDevIns, pThis, pThisCC);
962 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
963 }
964 }
965 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
966 {
967 pThisCC->pDrvBase = NULL;
968 pThisCC->pDrvSerial = NULL;
969 rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
970 if (RT_SUCCESS(rc))
971 {
972 pl011R3XferReset(pDevIns, pThis, pThisCC);
973 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
974 }
975 LogRel(("PL011#%d: no unit\n", pDevIns->iInstance));
976 }
977 else /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
978 LogRel(("PL011#%d: Failed to attach to serial driver. rc=%Rrc\n", pDevIns->iInstance, rc));
979
980 return rc;
981}
982
983
984/**
985 * @interface_method_impl{PDMDEVREG,pfnDetach}
986 */
987static DECLCALLBACK(void) pl011R3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
988{
989 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
990 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
991 RT_NOREF(fFlags);
992 AssertReturnVoid(iLUN == 0);
993
994 /* Zero out important members. */
995 pThisCC->pDrvBase = NULL;
996 pThisCC->pDrvSerial = NULL;
997
998 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
999 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1000
1001 pl011R3XferReset(pDevIns, pThis, pThisCC);
1002
1003 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1004}
1005
1006
1007/**
1008 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1009 */
1010static DECLCALLBACK(int) pl011R3Destruct(PPDMDEVINS pDevIns)
1011{
1012 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1013
1014 /* Nothing to do. */
1015 return VINF_SUCCESS;
1016}
1017
1018
1019/**
1020 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1021 */
1022static DECLCALLBACK(int) pl011R3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1023{
1024 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1025 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1026 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
1027 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1028 int rc;
1029
1030 Assert(iInstance < 4);
1031
1032 pThisCC->pDevIns = pDevIns;
1033
1034 /* IBase */
1035 pThisCC->IBase.pfnQueryInterface = pl011R3QueryInterface;
1036
1037 /* ISerialPort */
1038 pThisCC->ISerialPort.pfnDataAvailRdrNotify = pl011R3DataAvailRdrNotify;
1039 pThisCC->ISerialPort.pfnDataSentNotify = pl011R3DataSentNotify;
1040 pThisCC->ISerialPort.pfnReadWr = pl011R3ReadWr;
1041 pThisCC->ISerialPort.pfnNotifyStsLinesChanged = pl011R3NotifyStsLinesChanged;
1042 pThisCC->ISerialPort.pfnNotifyBrk = pl011R3NotifyBrk;
1043
1044 /*
1045 * Validate and read the configuration.
1046 */
1047 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Irq|MmioBase|YieldOnLSRRead", "");
1048
1049 bool fYieldOnLSRRead = false;
1050 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "YieldOnLSRRead", &fYieldOnLSRRead, false);
1051 if (RT_FAILURE(rc))
1052 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
1053
1054 uint16_t u16Irq = 0;
1055 rc = pHlp->pfnCFGMQueryU16(pCfg, "Irq", &u16Irq);
1056 if (RT_FAILURE(rc))
1057 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Irq\" value"));
1058
1059 RTGCPHYS GCPhysMmioBase = 0;
1060 rc = pHlp->pfnCFGMQueryU64(pCfg, "MmioBase", &GCPhysMmioBase);
1061 if (RT_FAILURE(rc))
1062 return PDMDEV_SET_ERROR(pDevIns, rc,
1063 N_("Configuration error: Failed to get the \"IOBase\" value"));
1064
1065 pThis->u16Irq = u16Irq;
1066 pThis->GCPhysMmioBase = GCPhysMmioBase;
1067
1068 /*
1069 * Register and map the MMIO region.
1070 */
1071 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmioBase, PL011_MMIO_SIZE, pl011MmioWrite, pl011MmioRead,
1072 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "PL011", &pThis->hMmio);
1073 AssertRCReturn(rc, rc);
1074
1075
1076 /*
1077 * Saved state.
1078 */
1079 rc = PDMDevHlpSSMRegisterEx(pDevIns, PL011_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
1080 NULL, pl011R3LiveExec, NULL,
1081 NULL, pl011R3SaveExec, NULL,
1082 NULL, pl011R3LoadExec, pl011R3LoadDone);
1083 AssertRCReturn(rc, rc);
1084
1085 /*
1086 * Attach the char driver and get the interfaces.
1087 */
1088 rc = PDMDevHlpDriverAttach(pDevIns, 0 /*iLUN*/, &pThisCC->IBase, &pThisCC->pDrvBase, "UART");
1089 if (RT_SUCCESS(rc))
1090 {
1091 pThisCC->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMISERIALCONNECTOR);
1092 if (!pThisCC->pDrvSerial)
1093 {
1094 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", iInstance));
1095 return VERR_PDM_MISSING_INTERFACE;
1096 }
1097 }
1098 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1099 {
1100 pThisCC->pDrvBase = NULL;
1101 pThisCC->pDrvSerial = NULL;
1102 LogRel(("PL011#%d: no unit\n", iInstance));
1103 }
1104 else
1105 {
1106 AssertLogRelMsgFailed(("PL011#%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
1107 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1108 return rc;
1109 }
1110
1111 pl011R3Reset(pDevIns);
1112 return VINF_SUCCESS;
1113}
1114
1115#else /* !IN_RING3 */
1116
1117/**
1118 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1119 */
1120static DECLCALLBACK(int) pl011RZConstruct(PPDMDEVINS pDevIns)
1121{
1122 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1123 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1124 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
1125
1126 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, pl011MmioWrite, pl011MmioRead, NULL /*pvUser*/);
1127 AssertRCReturn(rc, rc);
1128
1129 return VINF_SUCCESS;
1130}
1131
1132#endif /* !IN_RING3 */
1133
1134/**
1135 * The device registration structure.
1136 */
1137const PDMDEVREG g_DevicePl011 =
1138{
1139 /* .u32Version = */ PDM_DEVREG_VERSION,
1140 /* .uReserved0 = */ 0,
1141 /* .szName = */ "arm-pl011",
1142 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1143 /* .fClass = */ PDM_DEVREG_CLASS_SERIAL,
1144 /* .cMaxInstances = */ UINT32_MAX,
1145 /* .uSharedVersion = */ 42,
1146 /* .cbInstanceShared = */ sizeof(DEVPL011),
1147 /* .cbInstanceCC = */ sizeof(DEVPL011CC),
1148 /* .cbInstanceRC = */ sizeof(DEVPL011RC),
1149 /* .cMaxPciDevices = */ 0,
1150 /* .cMaxMsixVectors = */ 0,
1151 /* .pszDescription = */ "ARM PL011 PrimeCell UART",
1152#if defined(IN_RING3)
1153 /* .pszRCMod = */ "VBoxDDRC.rc",
1154 /* .pszR0Mod = */ "VBoxDDR0.r0",
1155 /* .pfnConstruct = */ pl011R3Construct,
1156 /* .pfnDestruct = */ pl011R3Destruct,
1157 /* .pfnRelocate = */ NULL,
1158 /* .pfnMemSetup = */ NULL,
1159 /* .pfnPowerOn = */ NULL,
1160 /* .pfnReset = */ pl011R3Reset,
1161 /* .pfnSuspend = */ NULL,
1162 /* .pfnResume = */ NULL,
1163 /* .pfnAttach = */ pl011R3Attach,
1164 /* .pfnDetach = */ pl011R3Detach,
1165 /* .pfnQueryInterface = */ NULL,
1166 /* .pfnInitComplete = */ NULL,
1167 /* .pfnPowerOff = */ NULL,
1168 /* .pfnSoftReset = */ NULL,
1169 /* .pfnReserved0 = */ NULL,
1170 /* .pfnReserved1 = */ NULL,
1171 /* .pfnReserved2 = */ NULL,
1172 /* .pfnReserved3 = */ NULL,
1173 /* .pfnReserved4 = */ NULL,
1174 /* .pfnReserved5 = */ NULL,
1175 /* .pfnReserved6 = */ NULL,
1176 /* .pfnReserved7 = */ NULL,
1177#elif defined(IN_RING0)
1178 /* .pfnEarlyConstruct = */ NULL,
1179 /* .pfnConstruct = */ pl011RZConstruct,
1180 /* .pfnDestruct = */ NULL,
1181 /* .pfnFinalDestruct = */ NULL,
1182 /* .pfnRequest = */ NULL,
1183 /* .pfnReserved0 = */ NULL,
1184 /* .pfnReserved1 = */ NULL,
1185 /* .pfnReserved2 = */ NULL,
1186 /* .pfnReserved3 = */ NULL,
1187 /* .pfnReserved4 = */ NULL,
1188 /* .pfnReserved5 = */ NULL,
1189 /* .pfnReserved6 = */ NULL,
1190 /* .pfnReserved7 = */ NULL,
1191#elif defined(IN_RC)
1192 /* .pfnConstruct = */ pl011RZConstruct,
1193 /* .pfnReserved0 = */ NULL,
1194 /* .pfnReserved1 = */ NULL,
1195 /* .pfnReserved2 = */ NULL,
1196 /* .pfnReserved3 = */ NULL,
1197 /* .pfnReserved4 = */ NULL,
1198 /* .pfnReserved5 = */ NULL,
1199 /* .pfnReserved6 = */ NULL,
1200 /* .pfnReserved7 = */ NULL,
1201#else
1202# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1203#endif
1204 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1205};
1206
1207#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1208
Note: See TracBrowser for help on using the repository browser.

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