VirtualBox

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

Last change on this file since 100168 was 100168, checked in by vboxsync, 18 months ago

Devices/DevPL011: Updates to the emulation, implement some basic input support as well as support for the TX and RX FIFOs, bugref:10403

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.4 KB
Line 
1/* $Id: DevPL011.cpp 100168 2023-06-13 11:58:50Z 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/** Bit 0 - Ring Indicator Modem interrupt mask. */
185# define PL011_REG_UARTIMSC_RIMIM RT_BIT(0)
186/** Bit 1 - Clear To Send Modem interrupt mask. */
187# define PL011_REG_UARTIMSC_CTSMIM RT_BIT(1)
188/** Bit 2 - Data Carrier Detect Modem interrupt mask. */
189# define PL011_REG_UARTIMSC_DCDMIM RT_BIT(2)
190/** Bit 3 - Data Set Ready Modem interrupt mask. */
191# define PL011_REG_UARTIMSC_DSRMIM RT_BIT(3)
192/** Bit 4 - Receive interrupt mask. */
193# define PL011_REG_UARTIMSC_RXIM RT_BIT(4)
194/** Bit 5 - Transmit interrupt mask. */
195# define PL011_REG_UARTIMSC_TXIM RT_BIT(5)
196/** Bit 6 - Receive timeout interrupt mask. */
197# define PL011_REG_UARTIMSC_RTIM RT_BIT(6)
198/** Bit 7 - Frameing Error interrupt mask. */
199# define PL011_REG_UARTIMSC_FEIM RT_BIT(7)
200/** Bit 8 - Parity Error interrupt mask. */
201# define PL011_REG_UARTIMSC_PEIM RT_BIT(8)
202/** Bit 9 - Break Error interrupt mask. */
203# define PL011_REG_UARTIMSC_BEIM RT_BIT(9)
204/** Bit 10 - Overrun Error interrupt mask. */
205# define PL011_REG_UARTIMSC_OEIM RT_BIT(10)
206
207/** The offset of the UARTRIS register from the beginning of the region. */
208#define PL011_REG_UARTRIS_INDEX 0x3c
209/** Bit 0 - Ring Indicator Modem raw interrupt status. */
210# define PL011_REG_UARTRIS_RIRMIS RT_BIT(0)
211/** Bit 1 - Clear To Send Modem raw interrupt status. */
212# define PL011_REG_UARTRIS_CTSRMIS RT_BIT(1)
213/** Bit 2 - Data Carrier Detect Modem raw interrupt status. */
214# define PL011_REG_UARTRIS_DCDRMIS RT_BIT(2)
215/** Bit 3 - Data Set Ready Modem raw interrupt status. */
216# define PL011_REG_UARTRIS_DSRRMIS RT_BIT(3)
217/** Bit 4 - Receive raw interrupt status. */
218# define PL011_REG_UARTRIS_RXRIS RT_BIT(4)
219/** Bit 5 - Transmit raw interrupt status. */
220# define PL011_REG_UARTRIS_TXRIS RT_BIT(5)
221/** Bit 6 - Receive timeout raw interrupt status. */
222# define PL011_REG_UARTRIS_RTRIS RT_BIT(6)
223/** Bit 7 - Frameing Error raw interrupt status. */
224# define PL011_REG_UARTRIS_FERIS RT_BIT(7)
225/** Bit 8 - Parity Error raw interrupt status. */
226# define PL011_REG_UARTRIS_PERIS RT_BIT(8)
227/** Bit 9 - Break Error raw interrupt status. */
228# define PL011_REG_UARTRIS_BERIS RT_BIT(9)
229/** Bit 10 - Overrun Error raw interrupt status. */
230# define PL011_REG_UARTRIS_OERIS RT_BIT(10)
231
232/** The offset of the UARTMIS register from the beginning of the region. */
233#define PL011_REG_UARTMIS_INDEX 0x40
234/** Bit 0 - Ring Indicator Modem masked interrupt status. */
235# define PL011_REG_UARTRIS_RIMMIS RT_BIT(0)
236/** Bit 1 - Clear To Send Modem masked interrupt status. */
237# define PL011_REG_UARTRIS_CTSMMIS RT_BIT(1)
238/** Bit 2 - Data Carrier Detect Modem masked interrupt status. */
239# define PL011_REG_UARTRIS_DCDMMIS RT_BIT(2)
240/** Bit 3 - Data Set Ready Modem masked interrupt status. */
241# define PL011_REG_UARTRIS_DSRMMIS RT_BIT(3)
242/** Bit 4 - Receive masked interrupt status. */
243# define PL011_REG_UARTRIS_RXMIS RT_BIT(4)
244/** Bit 5 - Transmit masked interrupt status. */
245# define PL011_REG_UARTRIS_TXMIS RT_BIT(5)
246/** Bit 6 - Receive timeout masked interrupt status. */
247# define PL011_REG_UARTRIS_RTMIS RT_BIT(6)
248/** Bit 7 - Frameing Error masked interrupt status. */
249# define PL011_REG_UARTRIS_FEMIS RT_BIT(7)
250/** Bit 8 - Parity Error masked interrupt status. */
251# define PL011_REG_UARTRIS_PEMIS RT_BIT(8)
252/** Bit 9 - Break Error masked interrupt status. */
253# define PL011_REG_UARTRIS_BEMIS RT_BIT(9)
254/** Bit 10 - Overrun Error masked interrupt status. */
255# define PL011_REG_UARTRIS_OEMIS RT_BIT(10)
256
257/** The offset of the UARTICR register from the beginning of the region. */
258#define PL011_REG_UARTICR_INDEX 0x44
259/** Bit 0 - Ring Indicator Modem interrupt clear. */
260# define PL011_REG_UARTICR_RIMIC RT_BIT(0)
261/** Bit 1 - Clear To Send Modem interrupt clear. */
262# define PL011_REG_UARTICR_CTSMIC RT_BIT(1)
263/** Bit 2 - Data Carrier Detect Modem interrupt clear. */
264# define PL011_REG_UARTICR_DCDMIC RT_BIT(2)
265/** Bit 3 - Data Set Ready Modem interrupt clear. */
266# define PL011_REG_UARTICR_DSRMIC RT_BIT(3)
267/** Bit 4 - Receive interrupt clear. */
268# define PL011_REG_UARTICR_RXIC RT_BIT(4)
269/** Bit 5 - Transmit interrupt clear. */
270# define PL011_REG_UARTICR_TXIC RT_BIT(5)
271/** Bit 6 - Receive timeout interrupt clear. */
272# define PL011_REG_UARTICR_RTIC RT_BIT(6)
273/** Bit 7 - Frameing Error interrupt clear. */
274# define PL011_REG_UARTICR_FEIC RT_BIT(7)
275/** Bit 8 - Parity Error interrupt clear. */
276# define PL011_REG_UARTICR_PEIC RT_BIT(8)
277/** Bit 9 - Break Error interrupt clear. */
278# define PL011_REG_UARTICR_BEIC RT_BIT(9)
279/** Bit 10 - Overrun Error interrupt clear. */
280# define PL011_REG_UARTICR_OEIC RT_BIT(10)
281
282/** The offset of the UARTDMACR register from the beginning of the region. */
283#define PL011_REG_UARTDMACR_INDEX 0x48
284
285/** The offset of the UARTPeriphID0 register from the beginning of the region. */
286#define PL011_REG_UART_PERIPH_ID0_INDEX 0xfe0
287/** The offset of the UARTPeriphID1 register from the beginning of the region. */
288#define PL011_REG_UART_PERIPH_ID1_INDEX 0xfe4
289/** The offset of the UARTPeriphID2 register from the beginning of the region. */
290#define PL011_REG_UART_PERIPH_ID2_INDEX 0xfe8
291/** The offset of the UARTPeriphID3 register from the beginning of the region. */
292#define PL011_REG_UART_PERIPH_ID3_INDEX 0xfec
293/** The offset of the UARTPCellID0 register from the beginning of the region. */
294#define PL011_REG_UART_PCELL_ID0_INDEX 0xff0
295/** The offset of the UARTPCellID1 register from the beginning of the region. */
296#define PL011_REG_UART_PCELL_ID1_INDEX 0xff4
297/** The offset of the UARTPCellID2 register from the beginning of the region. */
298#define PL011_REG_UART_PCELL_ID2_INDEX 0xff8
299/** The offset of the UARTPCellID3 register from the beginning of the region. */
300#define PL011_REG_UART_PCELL_ID3_INDEX 0xffc
301
302/** Set the specified bits in the given register. */
303#define PL011_REG_SET(a_Reg, a_Set) ((a_Reg) |= (a_Set))
304/** Clear the specified bits in the given register. */
305#define PL011_REG_CLR(a_Reg, a_Clr) ((a_Reg) &= ~(a_Clr))
306
307
308/*********************************************************************************************************************************
309* Structures and Typedefs *
310*********************************************************************************************************************************/
311
312/**
313 * UART FIFO.
314 */
315typedef struct PL011FIFO
316{
317 /** Fifo size configured. */
318 uint8_t cbMax;
319 /** Current amount of bytes used. */
320 uint8_t cbUsed;
321 /** Next index to write to. */
322 uint8_t offWrite;
323 /** Next index to read from. */
324 uint8_t offRead;
325 /** The interrupt trigger level (only used for the receive FIFO). */
326 uint8_t cbItl;
327 /** The data in the FIFO. */
328 uint8_t abBuf[PL011_FIFO_LENGTH_MAX];
329 /** Alignment to a 4 byte boundary. */
330 uint8_t au8Alignment0[3];
331} PL011FIFO;
332/** Pointer to a FIFO. */
333typedef PL011FIFO *PPL011FIFO;
334
335
336/**
337 * Shared serial device state.
338 */
339typedef struct DEVPL011
340{
341 /** The MMIO handle. */
342 IOMMMIOHANDLE hMmio;
343 /** The base MMIO address the device is registered at. */
344 RTGCPHYS GCPhysMmioBase;
345 /** The IRQ value. */
346 uint16_t u16Irq;
347
348 /** @name Registers.
349 * @{ */
350 /** UART data register when written. */
351 uint8_t uRegDr;
352 /** UART data register when read. */
353 uint8_t uRegDrRd;
354 /** UART control register. */
355 uint16_t uRegCr;
356 /** UART flag register. */
357 uint16_t uRegFr;
358 /** UART integer baud rate register. */
359 uint16_t uRegIbrd;
360 /** UART fractional baud rate register. */
361 uint16_t uRegFbrd;
362 /** UART line control register. */
363 uint16_t uRegLcrH;
364 /** Interrupt FIFO Level Select register. */
365 uint16_t uRegFifoLvlSel;
366 /** Interrupt mask register. */
367 uint16_t uRegIrqMask;
368 /** Raw interrupt status register. */
369 uint16_t uRegIrqSts;
370 /** @} */
371
372 /** Time it takes to transmit/receive a single symbol in timer ticks. */
373 uint64_t cSymbolXferTicks;
374 /** Number of bytes available for reading from the layer below. */
375 volatile uint32_t cbAvailRdr;
376
377 /** Timer handle for the send loop if no driver is connected/loopback mode is active. */
378 TMTIMERHANDLE hTimerTxUnconnected;
379
380 /** The transmit FIFO. */
381 PL011FIFO FifoXmit;
382 /** The receive FIFO. */
383 PL011FIFO FifoRecv;
384} DEVPL011;
385/** Pointer to the shared serial device state. */
386typedef DEVPL011 *PDEVPL011;
387
388
389/**
390 * Serial device state for ring-3.
391 */
392typedef struct DEVPL011R3
393{
394 /** LUN\#0: The base interface. */
395 PDMIBASE IBase;
396 /** LUN\#0: The serial port interface. */
397 PDMISERIALPORT ISerialPort;
398 /** Pointer to the attached base driver. */
399 R3PTRTYPE(PPDMIBASE) pDrvBase;
400 /** Pointer to the attached serial driver. */
401 R3PTRTYPE(PPDMISERIALCONNECTOR) pDrvSerial;
402 /** Pointer to the device instance - only for getting our bearings in
403 * interface methods. */
404 PPDMDEVINS pDevIns;
405} DEVPL011R3;
406/** Pointer to the serial device state for ring-3. */
407typedef DEVPL011R3 *PDEVPL011R3;
408
409
410/**
411 * Serial device state for ring-0.
412 */
413typedef struct DEVPL011R0
414{
415 /** Dummy .*/
416 uint8_t bDummy;
417} DEVPL011R0;
418/** Pointer to the serial device state for ring-0. */
419typedef DEVPL011R0 *PDEVPL011R0;
420
421
422/**
423 * Serial device state for raw-mode.
424 */
425typedef struct DEVPL011RC
426{
427 /** Dummy .*/
428 uint8_t bDummy;
429} DEVPL011RC;
430/** Pointer to the serial device state for raw-mode. */
431typedef DEVPL011RC *PDEVPL011RC;
432
433/** The serial device state for the current context. */
434typedef CTX_SUFF(DEVPL011) DEVPL011CC;
435/** Pointer to the serial device state for the current context. */
436typedef CTX_SUFF(PDEVPL011) PDEVPL011CC;
437
438
439/*********************************************************************************************************************************
440* Global Variables *
441*********************************************************************************************************************************/
442
443#ifdef IN_RING3
444/**
445 * String versions of the parity enum.
446 */
447static const char *s_aszParity[] =
448{
449 "INVALID",
450 "NONE",
451 "EVEN",
452 "ODD",
453 "MARK",
454 "SPACE",
455 "INVALID"
456};
457
458
459/**
460 * String versions of the stop bits enum.
461 */
462static const char *s_aszStopBits[] =
463{
464 "INVALID",
465 "1",
466 "INVALID",
467 "2",
468 "INVALID"
469};
470#endif
471
472
473/*********************************************************************************************************************************
474* Internal Functions *
475*********************************************************************************************************************************/
476
477#ifndef VBOX_DEVICE_STRUCT_TESTCASE
478
479/**
480 * Updates the IRQ state based on the current device state.
481 *
482 * @param pDevIns The device instance.
483 * @param pThis The shared serial port instance data.
484 * @param pThisCC The serial port instance data for the current context.
485 */
486DECLINLINE(void) pl011IrqUpdate(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC)
487{
488 LogFlowFunc(("pThis=%#p uRegIrqSts=%#RX16 uRegIrqMask=%#RX16\n",
489 pThis, pThis->uRegIrqSts, pThis->uRegIrqMask));
490
491 RT_NOREF(pThisCC);
492 if (pThis->uRegIrqSts & ~pThis->uRegIrqMask)
493 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->u16Irq, 1);
494 else
495 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->u16Irq, 0);
496}
497
498
499/**
500 * Returns the amount of bytes stored in the given FIFO.
501 *
502 * @returns Amount of bytes stored in the FIFO.
503 * @param pFifo The FIFO.
504 */
505DECLINLINE(size_t) pl011FifoUsedGet(PPL011FIFO pFifo)
506{
507 return pFifo->cbUsed;
508}
509
510
511/**
512 * Puts a new character into the given FIFO.
513 *
514 * @returns Flag whether the FIFO overflowed.
515 * @param pFifo The FIFO to put the data into.
516 * @param fOvrWr Flag whether to overwrite data if the FIFO is full.
517 * @param bData The data to add.
518 */
519DECLINLINE(bool) pl011FifoPut(PPL011FIFO pFifo, bool fOvrWr, uint8_t bData)
520{
521 if (fOvrWr || pFifo->cbUsed < pFifo->cbMax)
522 {
523 pFifo->abBuf[pFifo->offWrite] = bData;
524 pFifo->offWrite = (pFifo->offWrite + 1) % pFifo->cbMax;
525 }
526
527 bool fOverFlow = false;
528 if (pFifo->cbUsed < pFifo->cbMax)
529 pFifo->cbUsed++;
530 else
531 {
532 fOverFlow = true;
533 if (fOvrWr) /* Advance the read position to account for the lost character. */
534 pFifo->offRead = (pFifo->offRead + 1) % pFifo->cbMax;
535 }
536
537 return fOverFlow;
538}
539
540
541/**
542 * Returns the next character in the FIFO.
543 *
544 * @return Next byte in the FIFO.
545 * @param pFifo The FIFO to get data from.
546 */
547DECLINLINE(uint8_t) pl011FifoGet(PPL011FIFO pFifo)
548{
549 uint8_t bRet = 0;
550
551 if (pFifo->cbUsed)
552 {
553 bRet = pFifo->abBuf[pFifo->offRead];
554 pFifo->offRead = (pFifo->offRead + 1) % pFifo->cbMax;
555 pFifo->cbUsed--;
556 }
557
558 return bRet;
559}
560
561
562/**
563 * Clears the given FIFO.
564 *
565 * @param pFifo The FIFO to clear.
566 */
567DECLINLINE(void) pl011FifoClear(PPL011FIFO pFifo)
568{
569 memset(&pFifo->abBuf[0], 0, sizeof(pFifo->abBuf));
570 pFifo->cbUsed = 0;
571 pFifo->offWrite = 0;
572 pFifo->offRead = 0;
573}
574
575
576/**
577 * Returns the amount of free bytes in the given FIFO.
578 *
579 * @returns The amount of bytes free in the given FIFO.
580 * @param pFifo The FIFO.
581 */
582DECLINLINE(size_t) pl011FifoFreeGet(PPL011FIFO pFifo)
583{
584 return pFifo->cbMax - pFifo->cbUsed;
585}
586
587
588/**
589 * Tries to copy the requested amount of data from the given FIFO into the provided buffer.
590 *
591 * @returns Amount of bytes actually copied.
592 * @param pFifo The FIFO to copy data from.
593 * @param pvDst Where to copy the data to.
594 * @param cbCopy How much to copy.
595 */
596DECLINLINE(size_t) pl011FifoCopyTo(PPL011FIFO pFifo, void *pvDst, size_t cbCopy)
597{
598 size_t cbCopied = 0;
599 uint8_t *pbDst = (uint8_t *)pvDst;
600
601 cbCopy = RT_MIN(cbCopy, pFifo->cbUsed);
602 while (cbCopy)
603 {
604 uint8_t cbThisCopy = (uint8_t)RT_MIN(cbCopy, (uint8_t)(pFifo->cbMax - pFifo->offRead));
605 memcpy(pbDst, &pFifo->abBuf[pFifo->offRead], cbThisCopy);
606
607 pFifo->offRead = (pFifo->offRead + cbThisCopy) % pFifo->cbMax;
608 pFifo->cbUsed -= cbThisCopy;
609 pbDst += cbThisCopy;
610 cbCopied += cbThisCopy;
611 cbCopy -= cbThisCopy;
612 }
613
614 return cbCopied;
615}
616
617
618/**
619 * Transmits the given byte.
620 *
621 * @returns Strict VBox status code.
622 * @param pDevIns The device instance.
623 * @param pThis The shared serial port instance data.
624 * @param pThisCC The serial port instance data for the current context.
625 * @param bVal Byte to transmit.
626 */
627static VBOXSTRICTRC pl011Xmit(PPDMDEVINS pDevIns, PDEVPL011CC pThisCC, PDEVPL011 pThis, uint8_t bVal)
628{
629 int rc = VINF_SUCCESS;
630#ifdef IN_RING3
631 bool fNotifyDrv = false;
632#endif
633
634 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_FEN)
635 {
636#ifndef IN_RING3
637 RT_NOREF(pDevIns, pThisCC);
638 if (!pl011FifoUsedGet(&pThis->FifoXmit))
639 rc = VINF_IOM_R3_MMIO_WRITE;
640 else
641 {
642 pl011FifoPut(&pThis->FifoXmit, true /*fOvrWr*/, bVal);
643 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_TXFE);
644 PL011_REG_SET(pThis->uRegFr, PL011_REG_UARTFR_BUSY);
645 }
646#else
647 pl011FifoPut(&pThis->FifoXmit, true /*fOvrWr*/, bVal);
648 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_TXFE);
649 PL011_REG_SET(pThis->uRegFr, PL011_REG_UARTFR_BUSY);
650 pl011IrqUpdate(pDevIns, pThis, pThisCC);
651 if (pl011FifoUsedGet(&pThis->FifoXmit) == 1)
652 fNotifyDrv = true;
653#endif
654 }
655 else
656 {
657 /* Notify the lower driver about available data only if the register was empty before. */
658 if (!(pThis->uRegFr & PL011_REG_UARTFR_BUSY))
659 {
660#ifndef IN_RING3
661 rc = VINF_IOM_R3_IOPORT_WRITE;
662#else
663 pThis->uRegDr = bVal;
664 pThis->uRegFr |= PL011_REG_UARTFR_BUSY | PL011_REG_UARTFR_TXFF;
665 pl011IrqUpdate(pDevIns, pThis, pThisCC);
666 fNotifyDrv = true;
667#endif
668 }
669 else
670 pThis->uRegDr = bVal;
671 }
672
673#ifdef IN_RING3
674 if (fNotifyDrv)
675 {
676 /* Leave the device critical section before calling into the lower driver. */
677 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
678
679 if ( pThisCC->pDrvSerial
680 && !(pThis->uRegCr & PL011_REG_UARTCR_LBE))
681 {
682 int rc2 = pThisCC->pDrvSerial->pfnDataAvailWrNotify(pThisCC->pDrvSerial);
683 if (RT_FAILURE(rc2))
684 LogRelMax(10, ("PL011#%d: Failed to send data with %Rrc\n", pDevIns->iInstance, rc2));
685 }
686 else
687 PDMDevHlpTimerSetRelative(pDevIns, pThis->hTimerTxUnconnected, pThis->cSymbolXferTicks, NULL);
688
689 rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VINF_SUCCESS);
690 }
691#endif
692
693 return rc;
694}
695
696
697#ifdef IN_RING3
698/**
699 * Fills up the receive FIFO with as much data as possible.
700 *
701 * @param pDevIns The device instance.
702 * @param pThis The shared serial port instance data.
703 * @param pThisCC The serial port instance data for the current context.
704 */
705static void pl011R3RecvFifoFill(PPDMDEVINS pDevIns, PDEVPL011CC pThisCC, PDEVPL011 pThis)
706{
707 LogFlowFunc(("pThis=%#p\n", pThis));
708
709 PPL011FIFO pFifo = &pThis->FifoRecv;
710 size_t cbFill = RT_MIN(pl011FifoFreeGet(pFifo),
711 ASMAtomicReadU32(&pThis->cbAvailRdr));
712 size_t cbFilled = 0;
713
714 while (cbFilled < cbFill)
715 {
716 size_t cbThisRead = cbFill - cbFilled;
717
718 if (pFifo->offRead <= pFifo->offWrite)
719 cbThisRead = RT_MIN(cbThisRead, (uint8_t)(pFifo->cbMax - pFifo->offWrite));
720 else
721 cbThisRead = RT_MIN(cbThisRead, (uint8_t)(pFifo->offRead - pFifo->offWrite));
722
723 size_t cbRead = 0;
724 int rc = pThisCC->pDrvSerial->pfnReadRdr(pThisCC->pDrvSerial, &pFifo->abBuf[pFifo->offWrite], cbThisRead, &cbRead);
725 AssertRC(rc); Assert(cbRead <= UINT8_MAX); RT_NOREF(rc);
726
727 pFifo->offWrite = (pFifo->offWrite + (uint8_t)cbRead) % pFifo->cbMax;
728 pFifo->cbUsed += (uint8_t)cbRead;
729 cbFilled += cbRead;
730
731 if (cbRead < cbThisRead)
732 break;
733 }
734
735 if (cbFilled)
736 {
737 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_RXFE);
738 PL011_REG_SET(pThis->uRegIrqSts, PL011_REG_UARTRIS_RXRIS);
739 if (pFifo->cbUsed < pFifo->cbItl)
740 {
741 //pThis->fIrqCtiPending = false;
742 //PDMDevHlpTimerSetRelative(pDevIns, pThis->hTimerRcvFifoTimeout, pThis->cSymbolXferTicks * 4, NULL);
743 }
744 pl011IrqUpdate(pDevIns, pThis, pThisCC);
745 }
746
747 Assert(cbFilled <= (size_t)pThis->cbAvailRdr);
748 ASMAtomicSubU32(&pThis->cbAvailRdr, (uint32_t)cbFilled);
749}
750
751
752/**
753 * Fetches a single byte and writes it to RBR.
754 *
755 * @param pDevIns The device instance.
756 * @param pThis The shared serial port instance data.
757 * @param pThisCC The serial port instance data for the current context.
758 */
759static void pl011R3ByteFetch(PPDMDEVINS pDevIns, PDEVPL011CC pThisCC, PDEVPL011 pThis)
760{
761 if (ASMAtomicReadU32(&pThis->cbAvailRdr))
762 {
763 size_t cbRead = 0;
764 int rc2 = pThisCC->pDrvSerial->pfnReadRdr(pThisCC->pDrvSerial, &pThis->uRegDrRd, 1, &cbRead);
765 AssertMsg(RT_SUCCESS(rc2) && cbRead == 1, ("This shouldn't fail and always return one byte!\n")); RT_NOREF(rc2);
766 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_RXFE);
767 PL011_REG_SET(pThis->uRegIrqSts, PL011_REG_UARTRIS_RXRIS);
768 pl011IrqUpdate(pDevIns, pThis, pThisCC);
769 }
770}
771
772
773/**
774 * Fetches a ready data based on the FIFO setting.
775 *
776 * @param pDevIns The device instance.
777 * @param pThis The shared serial port instance data.
778 * @param pThisCC The serial port instance data for the current context.
779 */
780static void pl011R3DataFetch(PPDMDEVINS pDevIns, PDEVPL011CC pThisCC, PDEVPL011 pThis)
781{
782 AssertPtrReturnVoid(pThisCC->pDrvSerial);
783
784 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_FEN)
785 pl011R3RecvFifoFill(pDevIns, pThisCC, pThis);
786 else
787 pl011R3ByteFetch(pDevIns, pThisCC, pThis);
788}
789
790
791/**
792 * Updates the serial port parameters of the attached driver with the current configuration.
793 *
794 * @param pDevIns The device instance.
795 * @param pThis The shared serial port instance data.
796 * @param pThisCC The serial port instance data for the current context.
797 */
798static void pl011R3ParamsUpdate(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC)
799{
800 if ( pThis->uRegIbrd != 0
801 && pThisCC->pDrvSerial)
802 {
803 uint32_t uBps = 460800 / pThis->uRegIbrd; /** @todo This is for a 7.3728MHz clock. */
804 unsigned cDataBits = PL011_REG_UARTLCR_H_WLEN_GET(pThis->uRegLcrH) + 5;
805 uint32_t cFrameBits = cDataBits;
806 PDMSERIALSTOPBITS enmStopBits = PDMSERIALSTOPBITS_ONE;
807 PDMSERIALPARITY enmParity = PDMSERIALPARITY_NONE;
808
809 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_STP2)
810 {
811 enmStopBits = PDMSERIALSTOPBITS_TWO;
812 cFrameBits += 2;
813 }
814 else
815 cFrameBits++;
816
817 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_PEN)
818 {
819 /* Select the correct parity mode based on the even and stick parity bits. */
820 switch (pThis->uRegLcrH & (PL011_REG_UARTLCR_H_EPS | PL011_REG_UARTLCR_H_SPS))
821 {
822 case 0:
823 enmParity = PDMSERIALPARITY_ODD;
824 break;
825 case PL011_REG_UARTLCR_H_EPS:
826 enmParity = PDMSERIALPARITY_EVEN;
827 break;
828 case PL011_REG_UARTLCR_H_EPS | PL011_REG_UARTLCR_H_SPS:
829 enmParity = PDMSERIALPARITY_SPACE;
830 break;
831 case PL011_REG_UARTLCR_H_SPS:
832 enmParity = PDMSERIALPARITY_MARK;
833 break;
834 default:
835 /* We should never get here as all cases where caught earlier. */
836 AssertMsgFailed(("This shouldn't happen at all: %#x\n",
837 pThis->uRegLcrH & (PL011_REG_UARTLCR_H_EPS | PL011_REG_UARTLCR_H_SPS)));
838 }
839
840 cFrameBits++;
841 }
842
843 uint64_t uTimerFreq = PDMDevHlpTimerGetFreq(pDevIns, pThis->hTimerTxUnconnected);
844 pThis->cSymbolXferTicks = (uTimerFreq / uBps) * cFrameBits;
845
846 LogFlowFunc(("Changing parameters to: %u,%s,%u,%s\n",
847 uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits]));
848
849 int rc = pThisCC->pDrvSerial->pfnChgParams(pThisCC->pDrvSerial, uBps, enmParity, cDataBits, enmStopBits);
850 if (RT_FAILURE(rc))
851 LogRelMax(10, ("Serial#%d: Failed to change parameters to %u,%s,%u,%s -> %Rrc\n",
852 pDevIns->iInstance, uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits], rc));
853
854 /* Changed parameters will flush all receive queues, so there won't be any data to read even if indicated. */
855 pThisCC->pDrvSerial->pfnQueuesFlush(pThisCC->pDrvSerial, true /*fQueueRecv*/, false /*fQueueXmit*/);
856 ASMAtomicWriteU32(&pThis->cbAvailRdr, 0);
857 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_BUSY | PL011_REG_UARTFR_TXFF);
858 }
859}
860
861
862/**
863 * Reset the transmit/receive related bits to the standard values
864 * (after a detach/attach/reset event).
865 *
866 * @param pDevIns The device instance.
867 * @param pThis The shared serial port instance data.
868 * @param pThisCC The serial port instance data for the current context.
869 */
870static void pl011R3XferReset(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC)
871{
872 //PDMDevHlpTimerStop(pDevIns, pThis->hTimerRcvFifoTimeout);
873 PDMDevHlpTimerStop(pDevIns, pThis->hTimerTxUnconnected);
874 pThis->uRegFr = PL011_REG_UARTFR_TXFE | PL011_REG_UARTFR_RXFE;
875
876 pl011FifoClear(&pThis->FifoXmit);
877 pl011FifoClear(&pThis->FifoRecv);
878 pl011R3ParamsUpdate(pDevIns, pThis, pThisCC);
879 pl011IrqUpdate(pDevIns, pThis, pThisCC);
880
881 if (pThisCC->pDrvSerial)
882 {
883 /* Set the modem lines to reflect the current state. */
884 int rc = pThisCC->pDrvSerial->pfnChgModemLines(pThisCC->pDrvSerial, false /*fRts*/, false /*fDtr*/);
885 if (RT_FAILURE(rc))
886 LogRel(("PL011#%d: Failed to set modem lines with %Rrc during reset\n",
887 pDevIns->iInstance, rc));
888
889 uint32_t fStsLines = 0;
890 rc = pThisCC->pDrvSerial->pfnQueryStsLines(pThisCC->pDrvSerial, &fStsLines);
891 if (RT_SUCCESS(rc))
892 {} //uartR3StsLinesUpdate(pDevIns, pThis, pThisCC, fStsLines);
893 else
894 LogRel(("PL011#%d: Failed to query status line status with %Rrc during reset\n",
895 pDevIns->iInstance, rc));
896 }
897
898}
899
900
901/**
902 * Tries to copy the specified amount of data from the active TX queue (register or FIFO).
903 *
904 * @param pDevIns The device instance.
905 * @param pThis The shared serial port instance data.
906 * @param pThisCC The serial port instance data for the current context.
907 * @param pvBuf Where to store the data.
908 * @param cbRead How much to read from the TX queue.
909 * @param pcbRead Where to store the amount of data read.
910 */
911static void pl011R3TxQueueCopyFrom(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC,
912 void *pvBuf, size_t cbRead, size_t *pcbRead)
913{
914 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_FEN)
915 {
916 *pcbRead = pl011FifoCopyTo(&pThis->FifoXmit, pvBuf, cbRead);
917 if (!pThis->FifoXmit.cbUsed)
918 {
919 PL011_REG_SET(pThis->uRegFr, PL011_REG_UARTFR_TXFE);
920 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_BUSY);
921 //pThis->fThreEmptyPending = true;
922 }
923 if (*pcbRead)
924 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_TXFF);
925 pl011IrqUpdate(pDevIns, pThis, pThisCC);
926 }
927 else if (pThis->uRegFr & PL011_REG_UARTFR_BUSY)
928 {
929 *(uint8_t *)pvBuf = pThis->uRegDr;
930 *pcbRead = 1;
931 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_BUSY | PL011_REG_UARTFR_TXFF);
932 pl011IrqUpdate(pDevIns, pThis, pThisCC);
933 }
934 else
935 {
936 /*
937 * This can happen if there was data in the FIFO when the connection was closed,
938 * indicate this condition to the lower driver by returning 0 bytes.
939 */
940 *pcbRead = 0;
941 }
942}
943#endif
944
945
946/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
947
948
949/**
950 * @callback_method_impl{FNIOMMMIONEWREAD}
951 */
952static DECLCALLBACK(VBOXSTRICTRC) pl011MmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
953{
954 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
955 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
956 NOREF(pvUser);
957 Assert(cb == 4 || cb == 8);
958 Assert(!(off & (cb - 1))); RT_NOREF(cb);
959
960 uint32_t u32Val = 0;
961 VBOXSTRICTRC rc = VINF_SUCCESS;
962 switch (off)
963 {
964 case PL011_REG_UARTDR_INDEX:
965 {
966 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_FEN)
967 {
968 /*
969 * Only go back to R3 if there is new data available for the FIFO
970 * and we would clear the interrupt to fill it up again.
971 */
972 if ( pThis->FifoRecv.cbUsed <= pThis->FifoRecv.cbItl
973 && ASMAtomicReadU32(&pThis->cbAvailRdr) > 0)
974 {
975#ifndef IN_RING3
976 rc = VINF_IOM_R3_MMIO_READ;
977#else
978 pl011R3RecvFifoFill(pDevIns, pThisCC, pThis);
979#endif
980 }
981
982 if (rc == VINF_SUCCESS)
983 {
984 u32Val = pl011FifoGet(&pThis->FifoRecv);
985 //pThis->fIrqCtiPending = false;
986 if (!pThis->FifoRecv.cbUsed)
987 {
988 //PDMDevHlpTimerStop(pDevIns, pThis->hTimerRcvFifoTimeout);
989 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_RXFF);
990 PL011_REG_SET(pThis->uRegFr, PL011_REG_UARTFR_RXFE);
991 }
992 pl011IrqUpdate(pDevIns, pThis, pThisCC);
993 }
994 }
995 else
996 {
997 u32Val = pThis->uRegDrRd;
998 if (pThis->cbAvailRdr)
999 {
1000 uint32_t cbAvail = ASMAtomicDecU32(&pThis->cbAvailRdr);
1001 if (!cbAvail)
1002 {
1003 PL011_REG_SET(pThis->uRegFr, PL011_REG_UARTFR_RXFE);
1004 PL011_REG_CLR(pThis->uRegIrqSts, PL011_REG_UARTRIS_RXRIS);
1005 pl011IrqUpdate(pDevIns, pThis, pThisCC);
1006 }
1007 else
1008 {
1009 #ifndef IN_RING3
1010 /* Restore state and go back to R3. */
1011 ASMAtomicIncU32(&pThis->cbAvailRdr);
1012 rc = VINF_IOM_R3_MMIO_READ;
1013 #else
1014 /* Fetch new data and keep the DR bit set. */
1015 pl011R3DataFetch(pDevIns, pThisCC, pThis);
1016 #endif
1017 }
1018 }
1019 }
1020 break;
1021 }
1022 case PL011_REG_UARTRSR_ECR_INDEX:
1023 {
1024 AssertReleaseFailed();
1025 break;
1026 }
1027 case PL011_REG_UARTFR_INDEX:
1028 u32Val = pThis->uRegFr;
1029 break;
1030 case PL011_REG_UARTILPR_INDEX:
1031 u32Val = 0;
1032 AssertReleaseFailed();
1033 break;
1034 case PL011_REG_UARTIBRD_INDEX:
1035 u32Val = pThis->uRegIbrd;
1036 break;
1037 case PL011_REG_UARTFBRD_INDEX:
1038 u32Val = pThis->uRegFbrd;
1039 break;
1040 case PL011_REG_UARTLCR_H_INDEX:
1041 u32Val = pThis->uRegLcrH;
1042 break;
1043 case PL011_REG_UARTCR_INDEX:
1044 u32Val = pThis->uRegCr;
1045 break;
1046 case PL011_REG_UARTIFLS_INDEX:
1047 u32Val = pThis->uRegFifoLvlSel;
1048 break;
1049 case PL011_REG_UARTIMSC_INDEX:
1050 u32Val = pThis->uRegIrqMask;
1051 break;
1052 case PL011_REG_UARTRIS_INDEX:
1053 u32Val = pThis->uRegIrqSts;
1054 break;
1055 case PL011_REG_UARTMIS_INDEX:
1056 u32Val = pThis->uRegIrqSts & ~pThis->uRegIrqMask;
1057 break;
1058 case PL011_REG_UART_PERIPH_ID0_INDEX:
1059 u32Val = 0x11;
1060 break;
1061 case PL011_REG_UART_PERIPH_ID1_INDEX:
1062 u32Val = 0x10;
1063 break;
1064 case PL011_REG_UART_PERIPH_ID2_INDEX:
1065 u32Val = 0x34; /* r1p5 */
1066 break;
1067 case PL011_REG_UART_PERIPH_ID3_INDEX:
1068 u32Val = 0x00;
1069 break;
1070 case PL011_REG_UART_PCELL_ID0_INDEX:
1071 u32Val = 0x0d;
1072 break;
1073 case PL011_REG_UART_PCELL_ID1_INDEX:
1074 u32Val = 0xf0;
1075 break;
1076 case PL011_REG_UART_PCELL_ID2_INDEX:
1077 u32Val = 0x05;
1078 break;
1079 case PL011_REG_UART_PCELL_ID3_INDEX:
1080 u32Val = 0xb1;
1081 break;
1082 default:
1083 break;
1084 }
1085
1086 if (rc == VINF_SUCCESS)
1087 *(uint32_t *)pv = u32Val;
1088
1089 LogFlowFunc(("%RGp cb=%u u32Val=%#RX32 -> %Rrc\n", off, cb, u32Val, rc));
1090
1091 return rc;
1092}
1093
1094
1095/**
1096 * @callback_method_impl{FNIOMMMIONEWWRITE}
1097 */
1098static DECLCALLBACK(VBOXSTRICTRC) pl011MmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1099{
1100 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1101 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
1102 LogFlowFunc(("cb=%u reg=%RGp val=%llx\n", cb, off, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef));
1103 RT_NOREF(pvUser);
1104 Assert(cb == 4 || cb == 8);
1105 Assert(!(off & (cb - 1))); RT_NOREF(cb);
1106
1107 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
1108 uint32_t u32Val = *(uint32_t *)pv;
1109 switch (off)
1110 {
1111 case PL011_REG_UARTDR_INDEX:
1112 if ( (pThis->uRegCr & PL011_REG_UARTCR_UARTEN)
1113 && (pThis->uRegCr & PL011_REG_UARTCR_TXE))
1114 rcStrict = pl011Xmit(pDevIns, pThisCC, pThis, (uint8_t)u32Val);
1115 break;
1116 case PL011_REG_UARTLCR_H_INDEX:
1117 pThis->uRegLcrH = (uint16_t)u32Val;
1118 pl011R3ParamsUpdate(pDevIns, pThis, pThisCC);
1119 break;
1120 case PL011_REG_UARTIMSC_INDEX:
1121 pThis->uRegIrqMask = (uint16_t)u32Val;
1122 break;
1123 case PL011_REG_UARTICR_INDEX:
1124 pThis->uRegIrqSts = 0;
1125 pl011IrqUpdate(pDevIns, pThis, pThisCC);
1126 break;
1127 default:
1128 break;
1129
1130 }
1131 return rcStrict;
1132}
1133
1134
1135#ifdef IN_RING3
1136
1137/* -=-=-=-=-=-=-=-=- Timer callbacks -=-=-=-=-=-=-=-=- */
1138
1139/**
1140 * @callback_method_impl{FNTMTIMERDEV,
1141 * TX timer function when there is no driver connected for
1142 * draining the THR/FIFO.}
1143 */
1144static DECLCALLBACK(void) pl011R3TxUnconnectedTimer(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)
1145{
1146 RT_NOREF(pvUser);
1147
1148 LogFlowFunc(("pDevIns=%#p hTimer=%#p pvUser=%#p\n", pDevIns, hTimer, pvUser));
1149 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1150 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
1151 Assert(hTimer == pThis->hTimerTxUnconnected);
1152
1153 uint8_t bVal = 0;
1154 size_t cbRead = 0;
1155 pl011R3TxQueueCopyFrom(pDevIns, pThis, pThisCC, &bVal, sizeof(bVal), &cbRead);
1156 if (pThis->uRegCr & PL011_REG_UARTCR_LBE)
1157 {
1158 /* Loopback mode is active, feed in the data at the receiving end. */
1159 uint32_t cbAvailOld = ASMAtomicAddU32(&pThis->cbAvailRdr, 1);
1160 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_FEN)
1161 {
1162 AssertReleaseFailed();
1163 ASMAtomicSubU32(&pThis->cbAvailRdr, 1);
1164 }
1165 else if (!cbAvailOld)
1166 {
1167 pThis->uRegDr = bVal;
1168 PL011_REG_SET(pThis->uRegFr, PL011_REG_UARTFR_TXFF);
1169 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_TXFE);
1170 pl011IrqUpdate(pDevIns, pThis, pThisCC);
1171 }
1172 else
1173 ASMAtomicSubU32(&pThis->cbAvailRdr, 1);
1174 }
1175
1176 if (cbRead == 1)
1177 PDMDevHlpTimerSetRelative(pDevIns, hTimer, pThis->cSymbolXferTicks, NULL);
1178 else
1179 {
1180 /* No data left, set the transmitter holding register as empty. */
1181 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_BUSY | PL011_REG_UARTFR_TXFF);
1182 PL011_REG_SET(pThis->uRegFr, PL011_REG_UARTFR_TXFE);
1183 }
1184}
1185
1186
1187/* -=-=-=-=-=-=-=-=- PDMISERIALPORT on LUN#0 -=-=-=-=-=-=-=-=- */
1188
1189
1190/**
1191 * @interface_method_impl{PDMISERIALPORT,pfnDataAvailRdrNotify}
1192 */
1193static DECLCALLBACK(int) pl011R3DataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
1194{
1195 LogFlowFunc(("pInterface=%#p cbAvail=%zu\n", pInterface, cbAvail));
1196 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
1197 PPDMDEVINS pDevIns = pThisCC->pDevIns;
1198 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1199
1200 AssertMsg((uint32_t)cbAvail == cbAvail, ("Too much data available\n"));
1201
1202 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1203 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1204
1205 uint32_t cbAvailOld = ASMAtomicAddU32(&pThis->cbAvailRdr, (uint32_t)cbAvail);
1206 LogFlow((" cbAvailRdr=%u -> cbAvailRdr=%u\n", cbAvailOld, cbAvail + cbAvailOld));
1207 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_FEN)
1208 pl011R3RecvFifoFill(pDevIns, pThisCC, pThis);
1209 else if (!cbAvailOld)
1210 {
1211 size_t cbRead = 0;
1212 int rc = pThisCC->pDrvSerial->pfnReadRdr(pThisCC->pDrvSerial, &pThis->uRegDrRd, 1, &cbRead);
1213 AssertRC(rc);
1214
1215 if (cbRead)
1216 {
1217 PL011_REG_SET(pThis->uRegIrqSts, PL011_REG_UARTRIS_RXRIS);
1218 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_TXFE);
1219 PL011_REG_SET(pThis->uRegFr, PL011_REG_UARTFR_TXFF);
1220
1221 pl011IrqUpdate(pDevIns, pThis, pThisCC);
1222 }
1223 }
1224
1225 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1226 return VINF_SUCCESS;
1227}
1228
1229
1230/**
1231 * @interface_method_impl{PDMISERIALPORT,pfnDataSentNotify}
1232 */
1233static DECLCALLBACK(int) pl011R3DataSentNotify(PPDMISERIALPORT pInterface)
1234{
1235 LogFlowFunc(("pInterface=%#p\n", pInterface));
1236 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
1237 PPDMDEVINS pDevIns = pThisCC->pDevIns;
1238 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1239
1240 /* Set the transmitter empty bit because everything was sent. */
1241 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1242 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1243
1244 /** @todo */
1245 RT_NOREF(pThis);
1246
1247 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1248 return VINF_SUCCESS;
1249}
1250
1251
1252/**
1253 * @interface_method_impl{PDMISERIALPORT,pfnReadWr}
1254 */
1255static DECLCALLBACK(int) pl011R3ReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
1256{
1257 LogFlowFunc(("pInterface=%#p pvBuf=%#p cbRead=%zu pcbRead=%#p\n", pInterface, pvBuf, cbRead, pcbRead));
1258 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
1259 PPDMDEVINS pDevIns = pThisCC->pDevIns;
1260 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1261
1262 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
1263
1264 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1265 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1266
1267 pl011R3TxQueueCopyFrom(pDevIns, pThis, pThisCC, pvBuf, cbRead, pcbRead);
1268
1269 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1270 LogFlowFunc(("-> VINF_SUCCESS{*pcbRead=%zu}\n", *pcbRead));
1271 return VINF_SUCCESS;
1272}
1273
1274
1275/**
1276 * @interface_method_impl{PDMISERIALPORT,pfnNotifyStsLinesChanged}
1277 */
1278static DECLCALLBACK(int) pl011R3NotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
1279{
1280 LogFlowFunc(("pInterface=%#p fNewStatusLines=%#x\n", pInterface, fNewStatusLines));
1281 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
1282 PPDMDEVINS pDevIns = pThisCC->pDevIns;
1283 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1284
1285 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1286 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1287
1288 /** @todo */
1289 RT_NOREF(pThis, fNewStatusLines);
1290
1291 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1292 return VINF_SUCCESS;
1293}
1294
1295
1296/**
1297 * @interface_method_impl{PDMISERIALPORT,pfnNotifyBrk}
1298 */
1299static DECLCALLBACK(int) pl011R3NotifyBrk(PPDMISERIALPORT pInterface)
1300{
1301 LogFlowFunc(("pInterface=%#p\n", pInterface));
1302 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
1303 PPDMDEVINS pDevIns = pThisCC->pDevIns;
1304 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1305
1306 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1307 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1308
1309 PL011_REG_SET(pThis->uRegIrqSts, PL011_REG_UARTRIS_BERIS);
1310 pl011IrqUpdate(pDevIns, pThis, pThisCC);
1311
1312 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1313 return VINF_SUCCESS;
1314}
1315
1316
1317/* -=-=-=-=-=-=-=-=- PDMIBASE -=-=-=-=-=-=-=-=- */
1318
1319/**
1320 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1321 */
1322static DECLCALLBACK(void *) pl011R3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
1323{
1324 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, IBase);
1325 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
1326 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALPORT, &pThisCC->ISerialPort);
1327 return NULL;
1328}
1329
1330
1331/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
1332
1333/**
1334 * @callback_method_impl{FNSSMDEVLIVEEXEC}
1335 */
1336static DECLCALLBACK(int) pl011R3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1337{
1338 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1339 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1340 RT_NOREF(uPass);
1341
1342 pHlp->pfnSSMPutU16(pSSM, pThis->u16Irq);
1343 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmioBase);
1344 return VINF_SSM_DONT_CALL_AGAIN;
1345}
1346
1347
1348/**
1349 * @callback_method_impl{FNSSMDEVSAVEEXEC}
1350 */
1351static DECLCALLBACK(int) pl011R3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1352{
1353 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1354 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1355
1356 pHlp->pfnSSMPutU16(pSSM, pThis->u16Irq);
1357 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmioBase);
1358
1359 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
1360}
1361
1362
1363/**
1364 * @callback_method_impl{FNSSMDEVLOADEXEC}
1365 */
1366static DECLCALLBACK(int) pl011R3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1367{
1368 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1369 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1370 uint16_t u16Irq;
1371 RTGCPHYS GCPhysMmioBase;
1372 int rc;
1373
1374 RT_NOREF(uVersion);
1375
1376 pHlp->pfnSSMGetU16( pSSM, &u16Irq);
1377 pHlp->pfnSSMGetGCPhys(pSSM, &GCPhysMmioBase);
1378 if (uPass == SSM_PASS_FINAL)
1379 {
1380 rc = VERR_NOT_IMPLEMENTED;
1381 AssertRCReturn(rc, rc);
1382 }
1383
1384 if (uPass == SSM_PASS_FINAL)
1385 {
1386 /* The marker. */
1387 uint32_t u32;
1388 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
1389 AssertRCReturn(rc, rc);
1390 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1391 }
1392
1393 /*
1394 * Check the config.
1395 */
1396 if ( pThis->u16Irq != u16Irq
1397 || pThis->GCPhysMmioBase != GCPhysMmioBase)
1398 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1399 N_("Config mismatch - saved Irq=%#x GCPhysMmioBase=%#RGp; configured Irq=%#x GCPhysMmioBase=%#RGp"),
1400 u16Irq, GCPhysMmioBase, pThis->u16Irq, pThis->GCPhysMmioBase);
1401
1402 return VINF_SUCCESS;
1403}
1404
1405
1406/**
1407 * @callback_method_impl{FNSSMDEVLOADDONE}
1408 */
1409static DECLCALLBACK(int) pl011R3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1410{
1411 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1412 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
1413
1414 RT_NOREF(pThis, pThisCC, pSSM);
1415 return VERR_NOT_IMPLEMENTED;
1416}
1417
1418
1419/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
1420
1421/**
1422 * @interface_method_impl{PDMDEVREG,pfnReset}
1423 */
1424static DECLCALLBACK(void) pl011R3Reset(PPDMDEVINS pDevIns)
1425{
1426 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1427 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
1428
1429 pThis->uRegDr = 0;
1430 /* UARTEN is normally 0 on reset but UEFI doesn't set it causing the serial port to not log anything. */
1431 pThis->uRegCr = PL011_REG_UARTCR_TXE | PL011_REG_UARTCR_RXE | PL011_REG_UARTCR_UARTEN;
1432 pThis->uRegFr = PL011_REG_UARTFR_TXFE | PL011_REG_UARTFR_RXFE;
1433 pThis->uRegIbrd = 0;
1434 pThis->uRegFbrd = 0;
1435 pThis->uRegLcrH = 0;
1436 pThis->uRegFifoLvlSel = 0;
1437 pThis->uRegIrqSts = 0; /** @todo Not entirely correct as the modem status bits should reflect the lower state. */
1438 pThis->uRegIrqMask = 0;
1439 /** @todo */
1440
1441 pThis->FifoXmit.cbMax = 32;
1442 pThis->FifoRecv.cbMax = 32;
1443 pThis->FifoRecv.cbItl = 1;
1444
1445 pl011R3XferReset(pDevIns, pThis, pThisCC);
1446}
1447
1448
1449/**
1450 * @interface_method_impl{PDMDEVREG,pfnAttach}
1451 */
1452static DECLCALLBACK(int) pl011R3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1453{
1454 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1455 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
1456 RT_NOREF(fFlags);
1457 AssertReturn(iLUN == 0, VERR_PDM_LUN_NOT_FOUND);
1458
1459 int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThisCC->IBase, &pThisCC->pDrvBase, "PL011 Char");
1460 if (RT_SUCCESS(rc))
1461 {
1462 pThisCC->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMISERIALCONNECTOR);
1463 if (!pThisCC->pDrvSerial)
1464 {
1465 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", pDevIns->iInstance));
1466 return VERR_PDM_MISSING_INTERFACE;
1467 }
1468 rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1469 if (RT_SUCCESS(rc))
1470 {
1471 pl011R3XferReset(pDevIns, pThis, pThisCC);
1472 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1473 }
1474 }
1475 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1476 {
1477 pThisCC->pDrvBase = NULL;
1478 pThisCC->pDrvSerial = NULL;
1479 rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1480 if (RT_SUCCESS(rc))
1481 {
1482 pl011R3XferReset(pDevIns, pThis, pThisCC);
1483 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1484 }
1485 LogRel(("PL011#%d: no unit\n", pDevIns->iInstance));
1486 }
1487 else /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1488 LogRel(("PL011#%d: Failed to attach to serial driver. rc=%Rrc\n", pDevIns->iInstance, rc));
1489
1490 return rc;
1491}
1492
1493
1494/**
1495 * @interface_method_impl{PDMDEVREG,pfnDetach}
1496 */
1497static DECLCALLBACK(void) pl011R3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1498{
1499 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1500 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
1501 RT_NOREF(fFlags);
1502 AssertReturnVoid(iLUN == 0);
1503
1504 /* Zero out important members. */
1505 pThisCC->pDrvBase = NULL;
1506 pThisCC->pDrvSerial = NULL;
1507
1508 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1509 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1510
1511 pl011R3XferReset(pDevIns, pThis, pThisCC);
1512
1513 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1514}
1515
1516
1517/**
1518 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1519 */
1520static DECLCALLBACK(int) pl011R3Destruct(PPDMDEVINS pDevIns)
1521{
1522 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1523
1524 /* Nothing to do. */
1525 return VINF_SUCCESS;
1526}
1527
1528
1529/**
1530 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1531 */
1532static DECLCALLBACK(int) pl011R3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1533{
1534 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1535 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1536 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
1537 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1538 int rc;
1539
1540 Assert(iInstance < 4);
1541
1542 pThisCC->pDevIns = pDevIns;
1543
1544 /* IBase */
1545 pThisCC->IBase.pfnQueryInterface = pl011R3QueryInterface;
1546
1547 /* ISerialPort */
1548 pThisCC->ISerialPort.pfnDataAvailRdrNotify = pl011R3DataAvailRdrNotify;
1549 pThisCC->ISerialPort.pfnDataSentNotify = pl011R3DataSentNotify;
1550 pThisCC->ISerialPort.pfnReadWr = pl011R3ReadWr;
1551 pThisCC->ISerialPort.pfnNotifyStsLinesChanged = pl011R3NotifyStsLinesChanged;
1552 pThisCC->ISerialPort.pfnNotifyBrk = pl011R3NotifyBrk;
1553
1554 /*
1555 * Validate and read the configuration.
1556 */
1557 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Irq|MmioBase", "");
1558
1559 uint16_t u16Irq = 0;
1560 rc = pHlp->pfnCFGMQueryU16(pCfg, "Irq", &u16Irq);
1561 if (RT_FAILURE(rc))
1562 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Irq\" value"));
1563
1564 RTGCPHYS GCPhysMmioBase = 0;
1565 rc = pHlp->pfnCFGMQueryU64(pCfg, "MmioBase", &GCPhysMmioBase);
1566 if (RT_FAILURE(rc))
1567 return PDMDEV_SET_ERROR(pDevIns, rc,
1568 N_("Configuration error: Failed to get the \"MmioBase\" value"));
1569
1570 pThis->u16Irq = u16Irq;
1571 pThis->GCPhysMmioBase = GCPhysMmioBase;
1572
1573 /*
1574 * Register and map the MMIO region.
1575 */
1576 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmioBase, PL011_MMIO_SIZE, pl011MmioWrite, pl011MmioRead,
1577 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "PL011", &pThis->hMmio);
1578 AssertRCReturn(rc, rc);
1579
1580
1581 /*
1582 * Saved state.
1583 */
1584 rc = PDMDevHlpSSMRegisterEx(pDevIns, PL011_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
1585 NULL, pl011R3LiveExec, NULL,
1586 NULL, pl011R3SaveExec, NULL,
1587 NULL, pl011R3LoadExec, pl011R3LoadDone);
1588 AssertRCReturn(rc, rc);
1589
1590 /*
1591 * Attach the char driver and get the interfaces.
1592 */
1593 rc = PDMDevHlpDriverAttach(pDevIns, 0 /*iLUN*/, &pThisCC->IBase, &pThisCC->pDrvBase, "UART");
1594 if (RT_SUCCESS(rc))
1595 {
1596 pThisCC->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMISERIALCONNECTOR);
1597 if (!pThisCC->pDrvSerial)
1598 {
1599 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", iInstance));
1600 return VERR_PDM_MISSING_INTERFACE;
1601 }
1602 }
1603 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1604 {
1605 pThisCC->pDrvBase = NULL;
1606 pThisCC->pDrvSerial = NULL;
1607 LogRel(("PL011#%d: no unit\n", iInstance));
1608 }
1609 else
1610 {
1611 AssertLogRelMsgFailed(("PL011#%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
1612 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
1613 return rc;
1614 }
1615
1616 /*
1617 * Create the transmit timer when no device is connected.
1618 */
1619 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, pl011R3TxUnconnectedTimer, pThisCC,
1620 TMTIMER_FLAGS_NO_RING0, "UART TX unconnect",
1621 &pThis->hTimerTxUnconnected);
1622 AssertRCReturn(rc, rc);
1623
1624 pl011R3Reset(pDevIns);
1625 return VINF_SUCCESS;
1626}
1627
1628#else /* !IN_RING3 */
1629
1630/**
1631 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1632 */
1633static DECLCALLBACK(int) pl011RZConstruct(PPDMDEVINS pDevIns)
1634{
1635 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1636 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
1637 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
1638
1639 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, pl011MmioWrite, pl011MmioRead, NULL /*pvUser*/);
1640 AssertRCReturn(rc, rc);
1641
1642 return VINF_SUCCESS;
1643}
1644
1645#endif /* !IN_RING3 */
1646
1647/**
1648 * The device registration structure.
1649 */
1650const PDMDEVREG g_DevicePl011 =
1651{
1652 /* .u32Version = */ PDM_DEVREG_VERSION,
1653 /* .uReserved0 = */ 0,
1654 /* .szName = */ "arm-pl011",
1655 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1656 /* .fClass = */ PDM_DEVREG_CLASS_SERIAL,
1657 /* .cMaxInstances = */ UINT32_MAX,
1658 /* .uSharedVersion = */ 42,
1659 /* .cbInstanceShared = */ sizeof(DEVPL011),
1660 /* .cbInstanceCC = */ sizeof(DEVPL011CC),
1661 /* .cbInstanceRC = */ sizeof(DEVPL011RC),
1662 /* .cMaxPciDevices = */ 0,
1663 /* .cMaxMsixVectors = */ 0,
1664 /* .pszDescription = */ "ARM PL011 PrimeCell UART",
1665#if defined(IN_RING3)
1666 /* .pszRCMod = */ "VBoxDDRC.rc",
1667 /* .pszR0Mod = */ "VBoxDDR0.r0",
1668 /* .pfnConstruct = */ pl011R3Construct,
1669 /* .pfnDestruct = */ pl011R3Destruct,
1670 /* .pfnRelocate = */ NULL,
1671 /* .pfnMemSetup = */ NULL,
1672 /* .pfnPowerOn = */ NULL,
1673 /* .pfnReset = */ pl011R3Reset,
1674 /* .pfnSuspend = */ NULL,
1675 /* .pfnResume = */ NULL,
1676 /* .pfnAttach = */ pl011R3Attach,
1677 /* .pfnDetach = */ pl011R3Detach,
1678 /* .pfnQueryInterface = */ NULL,
1679 /* .pfnInitComplete = */ NULL,
1680 /* .pfnPowerOff = */ NULL,
1681 /* .pfnSoftReset = */ NULL,
1682 /* .pfnReserved0 = */ NULL,
1683 /* .pfnReserved1 = */ NULL,
1684 /* .pfnReserved2 = */ NULL,
1685 /* .pfnReserved3 = */ NULL,
1686 /* .pfnReserved4 = */ NULL,
1687 /* .pfnReserved5 = */ NULL,
1688 /* .pfnReserved6 = */ NULL,
1689 /* .pfnReserved7 = */ NULL,
1690#elif defined(IN_RING0)
1691 /* .pfnEarlyConstruct = */ NULL,
1692 /* .pfnConstruct = */ pl011RZConstruct,
1693 /* .pfnDestruct = */ NULL,
1694 /* .pfnFinalDestruct = */ NULL,
1695 /* .pfnRequest = */ NULL,
1696 /* .pfnReserved0 = */ NULL,
1697 /* .pfnReserved1 = */ NULL,
1698 /* .pfnReserved2 = */ NULL,
1699 /* .pfnReserved3 = */ NULL,
1700 /* .pfnReserved4 = */ NULL,
1701 /* .pfnReserved5 = */ NULL,
1702 /* .pfnReserved6 = */ NULL,
1703 /* .pfnReserved7 = */ NULL,
1704#elif defined(IN_RC)
1705 /* .pfnConstruct = */ pl011RZConstruct,
1706 /* .pfnReserved0 = */ NULL,
1707 /* .pfnReserved1 = */ NULL,
1708 /* .pfnReserved2 = */ NULL,
1709 /* .pfnReserved3 = */ NULL,
1710 /* .pfnReserved4 = */ NULL,
1711 /* .pfnReserved5 = */ NULL,
1712 /* .pfnReserved6 = */ NULL,
1713 /* .pfnReserved7 = */ NULL,
1714#else
1715# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1716#endif
1717 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1718};
1719
1720#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1721
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