VirtualBox

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

Last change on this file was 103425, checked in by vboxsync, 3 months ago

Devices/Serial: Fix some warnings, parfait:3409

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

© 2023 Oracle
ContactPrivacy policyTerms of Use