VirtualBox

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

Last change on this file since 107307 was 106541, checked in by vboxsync, 4 months ago

Devices/Serial/DevPL011: Small optimization, only update the IRQ state if it actually changes, bugref:10403

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