VirtualBox

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

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

Devices: Start implementation of ARM PL011 UART emulation, bugref:10403 [scm fixes]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.1 KB
Line 
1/* $Id: DevPL011.cpp 99126 2023-03-23 08:19:24Z 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
57/** The offset of the UARTDR register from the beginning of the region. */
58#define PL011_REG_UARTDR_INDEX 0x0
59/** Framing error. */
60# define PL011_REG_UARTDR_FE RT_BIT(8)
61/** Parity error. */
62# define PL011_REG_UARTDR_PE RT_BIT(9)
63/** Break error. */
64# define PL011_REG_UARTDR_BE RT_BIT(10)
65/** Overrun error. */
66# define PL011_REG_UARTDR_OE RT_BIT(11)
67
68/** The offset of the UARTRSR/UARTECR register from the beginning of the region. */
69#define PL011_REG_UARTRSR_ECR_INDEX 0x4
70/** Framing error. */
71# define PL011_REG_UARTRSR_ECR_FE RT_BIT(0)
72/** Parity error. */
73# define PL011_REG_UARTRSR_ECR_PE RT_BIT(1)
74/** Break error. */
75# define PL011_REG_UARTRSR_ECR_BE RT_BIT(2)
76/** Overrun error. */
77# define PL011_REG_UARTRSR_ECR_OE RT_BIT(3)
78
79/** The offset of the UARTFR register from the beginning of the region. */
80#define PL011_REG_UARTFR_INDEX 0x18
81/** Clear to send. */
82# define PL011_REG_UARTFR_CTS RT_BIT(0)
83/** Data set ready. */
84# define PL011_REG_UARTFR_DSR RT_BIT(1)
85/** Data carrier detect. */
86# define PL011_REG_UARTFR_DCD RT_BIT(2)
87/** UART busy. */
88# define PL011_REG_UARTFR_BUSY RT_BIT(3)
89/** Receive FIFO empty. */
90# define PL011_REG_UARTFR_RXFE RT_BIT(4)
91/** Transmit FIFO full. */
92# define PL011_REG_UARTFR_TXFF RT_BIT(5)
93/** Receive FIFO full. */
94# define PL011_REG_UARTFR_RXFF RT_BIT(6)
95/** Transmit FIFO empty. */
96# define PL011_REG_UARTFR_TXFE RT_BIT(7)
97/** Ring indicator. */
98# define PL011_REG_UARTFR_RI RT_BIT(8)
99
100/** The offset of the UARTILPR register from the beginning of the region. */
101#define PL011_REG_UARTILPR_INDEX 0x20
102
103/** The offset of the UARTIBRD register from the beginning of the region. */
104#define PL011_REG_UARTIBRD_INDEX 0x24
105
106/** The offset of the UARTFBRD register from the beginning of the region. */
107#define PL011_REG_UARTFBRD_INDEX 0x28
108
109/** The offset of the UARTLCR_H register from the beginning of the region. */
110#define PL011_REG_UARTLCR_H_INDEX 0x2c
111/** Send break. */
112# define PL011_REG_UARTLCR_H_BRK RT_BIT(0)
113/** Parity enable. */
114# define PL011_REG_UARTLCR_H_PEN RT_BIT(1)
115/** Even parity select. */
116# define PL011_REG_UARTLCR_H_EPS RT_BIT(2)
117/** Two stop bits select. */
118# define PL011_REG_UARTLCR_H_STP2 RT_BIT(3)
119/** Enable FIFOs. */
120# define PL011_REG_UARTLCR_H_FEN RT_BIT(4)
121/** Word length. */
122# define PL011_REG_UARTLCR_H_WLEN (RT_BIT(5) | RT_BIT(6))
123# define PL011_REG_UARTLCR_H_WLEN_GET(a_Lcr) (((a_Lcr) & PL011_REG_UARTLCR_H_WLEN) >> 5)
124# define PL011_REG_UARTLCR_H_WLEN_SET(a_Wlen) (((a_Wlen) << 5) & PL011_REG_UARTLCR_H_WLEN)
125/** 5 bits word length. */
126# define PL011_REG_UARTLCR_H_WLEN_5BITS 0
127/** 6 bits word length. */
128# define PL011_REG_UARTLCR_H_WLEN_6BITS 1
129/** 7 bits word length. */
130# define PL011_REG_UARTLCR_H_WLEN_7BITS 2
131/** 8 bits word length. */
132# define PL011_REG_UARTLCR_H_WLEN_8BITS 3
133/** Stick parity select. */
134# define PL011_REG_UARTLCR_H_SPS RT_BIT(7)
135
136/** The offset of the UARTCR register from the beginning of the region. */
137#define PL011_REG_UARTCR_INDEX 0x30
138/** UART transmit enable flag. */
139# define PL011_REG_UARTCR_TXE RT_BIT(8)
140/** UART receive enable flag. */
141# define PL011_REG_UARTCR_RXE RT_BIT(9)
142
143/** The offset of the UARTIFLS register from the beginning of the region. */
144#define PL011_REG_UARTIFLS_INDEX 0x34
145
146/** The offset of the UARTIMSC register from the beginning of the region. */
147#define PL011_REG_UARTIMSC_INDEX 0x38
148
149/** The offset of the UARTRIS register from the beginning of the region. */
150#define PL011_REG_UARTRIS_INDEX 0x3c
151
152/** The offset of the UARTMIS register from the beginning of the region. */
153#define PL011_REG_UARTMIS_INDEX 0x40
154
155/** The offset of the UARTICR register from the beginning of the region. */
156#define PL011_REG_UARTICR_INDEX 0x44
157
158/** The offset of the UARTDMACR register from the beginning of the region. */
159#define PL011_REG_UARTDMACR_INDEX 0x48
160
161/** The offset of the UARTPeriphID0 register from the beginning of the region. */
162#define PL011_REG_UART_PERIPH_ID0_INDEX 0xfe0
163/** The offset of the UARTPeriphID1 register from the beginning of the region. */
164#define PL011_REG_UART_PERIPH_ID1_INDEX 0xfe4
165/** The offset of the UARTPeriphID2 register from the beginning of the region. */
166#define PL011_REG_UART_PERIPH_ID2_INDEX 0xfe8
167/** The offset of the UARTPeriphID3 register from the beginning of the region. */
168#define PL011_REG_UART_PERIPH_ID3_INDEX 0xfec
169/** The offset of the UARTPCellID0 register from the beginning of the region. */
170#define PL011_REG_UART_PCELL_ID0_INDEX 0xff0
171/** The offset of the UARTPCellID1 register from the beginning of the region. */
172#define PL011_REG_UART_PCELL_ID1_INDEX 0xff4
173/** The offset of the UARTPCellID2 register from the beginning of the region. */
174#define PL011_REG_UART_PCELL_ID2_INDEX 0xff8
175/** The offset of the UARTPCellID3 register from the beginning of the region. */
176#define PL011_REG_UART_PCELL_ID3_INDEX 0xffc
177
178
179/*********************************************************************************************************************************
180* Structures and Typedefs *
181*********************************************************************************************************************************/
182
183/**
184 * Shared serial device state.
185 */
186typedef struct DEVPL011
187{
188 /** The MMIO handle. */
189 IOMMMIOHANDLE hMmio;
190 /** The base MMIO address the device is registered at. */
191 RTGCPHYS GCPhysMmioBase;
192 /** The IRQ value. */
193 uint16_t u16Irq;
194
195 /** @name Registers.
196 * @{ */
197 /** UART control register. */
198 uint32_t uRegCr;
199 /** UART flag register. */
200 uint32_t uRegFr;
201 /** @} */
202} DEVPL011;
203/** Pointer to the shared serial device state. */
204typedef DEVPL011 *PDEVPL011;
205
206
207/**
208 * Serial device state for ring-3.
209 */
210typedef struct DEVPL011R3
211{
212 /** LUN\#0: The base interface. */
213 PDMIBASE IBase;
214 /** LUN\#0: The serial port interface. */
215 PDMISERIALPORT ISerialPort;
216 /** Pointer to the attached base driver. */
217 R3PTRTYPE(PPDMIBASE) pDrvBase;
218 /** Pointer to the attached serial driver. */
219 R3PTRTYPE(PPDMISERIALCONNECTOR) pDrvSerial;
220 /** Pointer to the device instance - only for getting our bearings in
221 * interface methods. */
222 PPDMDEVINS pDevIns;
223} DEVPL011R3;
224/** Pointer to the serial device state for ring-3. */
225typedef DEVPL011R3 *PDEVPL011R3;
226
227
228/**
229 * Serial device state for ring-0.
230 */
231typedef struct DEVPL011R0
232{
233 /** Dummy .*/
234 uint8_t bDummy;
235} DEVPL011R0;
236/** Pointer to the serial device state for ring-0. */
237typedef DEVPL011R0 *PDEVPL011R0;
238
239
240/**
241 * Serial device state for raw-mode.
242 */
243typedef struct DEVPL011RC
244{
245 /** Dummy .*/
246 uint8_t bDummy;
247} DEVPL011RC;
248/** Pointer to the serial device state for raw-mode. */
249typedef DEVPL011RC *PDEVPL011RC;
250
251/** The serial device state for the current context. */
252typedef CTX_SUFF(DEVPL011) DEVPL011CC;
253/** Pointer to the serial device state for the current context. */
254typedef CTX_SUFF(PDEVPL011) PDEVPL011CC;
255
256
257#ifndef VBOX_DEVICE_STRUCT_TESTCASE
258
259
260
261/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
262
263
264/**
265 * @callback_method_impl{FNIOMMMIONEWREAD}
266 */
267static DECLCALLBACK(VBOXSTRICTRC) pl011MmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
268{
269 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
270 NOREF(pvUser);
271 Assert(cb == 4 || cb == 8);
272 Assert(!(off & (cb - 1)));
273
274 LogFlowFunc(("%RGp cb=%u\n", off, cb));
275
276 uint32_t u32Val = 0;
277 VBOXSTRICTRC rc = VINF_SUCCESS;
278 switch (off)
279 {
280 case PL011_REG_UARTFR_INDEX:
281 u32Val = pThis->uRegFr;
282 break;
283 case PL011_REG_UARTCR_INDEX:
284 u32Val = pThis->uRegCr;
285 break;
286 case PL011_REG_UART_PERIPH_ID0_INDEX:
287 u32Val = 0x11;
288 break;
289 case PL011_REG_UART_PERIPH_ID1_INDEX:
290 u32Val = 0x10;
291 break;
292 case PL011_REG_UART_PERIPH_ID2_INDEX:
293 u32Val = 0x34; /* r1p5 */
294 break;
295 case PL011_REG_UART_PERIPH_ID3_INDEX:
296 u32Val = 0x00;
297 break;
298 case PL011_REG_UART_PCELL_ID0_INDEX:
299 u32Val = 0x0d;
300 break;
301 case PL011_REG_UART_PCELL_ID1_INDEX:
302 u32Val = 0xf0;
303 break;
304 case PL011_REG_UART_PCELL_ID2_INDEX:
305 u32Val = 0x05;
306 break;
307 case PL011_REG_UART_PCELL_ID3_INDEX:
308 u32Val = 0xb1;
309 break;
310 default:
311 break;
312 }
313
314 if (rc == VINF_SUCCESS)
315 *(uint32_t *)pv = u32Val;
316
317 return rc;
318}
319
320
321/**
322 * @callback_method_impl{FNIOMMMIONEWWRITE}
323 */
324static DECLCALLBACK(VBOXSTRICTRC) pl011MmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
325{
326 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
327 LogFlowFunc(("cb=%u reg=%RGp val=%llx\n", cb, off, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef));
328 RT_NOREF(pvUser);
329 Assert(cb == 4 || cb == 8);
330 Assert(!(off & (cb - 1)));
331
332 int rc = VINF_SUCCESS;
333 return rc;
334}
335
336
337#ifdef IN_RING3
338
339/* -=-=-=-=-=-=-=-=- PDMISERIALPORT on LUN#0 -=-=-=-=-=-=-=-=- */
340
341
342/**
343 * @interface_method_impl{PDMISERIALPORT,pfnDataAvailRdrNotify}
344 */
345static DECLCALLBACK(int) pl011R3DataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
346{
347 LogFlowFunc(("pInterface=%#p cbAvail=%zu\n", pInterface, cbAvail));
348 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
349 PPDMDEVINS pDevIns = pThisCC->pDevIns;
350 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
351
352 AssertMsg((uint32_t)cbAvail == cbAvail, ("Too much data available\n"));
353
354 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
355 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
356
357 /** @todo */
358 RT_NOREF(pThis);
359
360 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
361 return VINF_SUCCESS;
362}
363
364
365/**
366 * @interface_method_impl{PDMISERIALPORT,pfnDataSentNotify}
367 */
368static DECLCALLBACK(int) pl011R3DataSentNotify(PPDMISERIALPORT pInterface)
369{
370 LogFlowFunc(("pInterface=%#p\n", pInterface));
371 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
372 PPDMDEVINS pDevIns = pThisCC->pDevIns;
373 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
374
375 /* Set the transmitter empty bit because everything was sent. */
376 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
377 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
378
379 /** @todo */
380 RT_NOREF(pThis);
381
382 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
383 return VINF_SUCCESS;
384}
385
386
387/**
388 * @interface_method_impl{PDMISERIALPORT,pfnReadWr}
389 */
390static DECLCALLBACK(int) pl011R3ReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
391{
392 LogFlowFunc(("pInterface=%#p pvBuf=%#p cbRead=%zu pcbRead=%#p\n", pInterface, pvBuf, cbRead, pcbRead));
393 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
394 PPDMDEVINS pDevIns = pThisCC->pDevIns;
395 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
396
397 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
398
399 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
400 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
401
402 /** @todo */
403 RT_NOREF(pThis);
404
405 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
406 LogFlowFunc(("-> VINF_SUCCESS{*pcbRead=%zu}\n", *pcbRead));
407 return VINF_SUCCESS;
408}
409
410
411/**
412 * @interface_method_impl{PDMISERIALPORT,pfnNotifyStsLinesChanged}
413 */
414static DECLCALLBACK(int) pl011R3NotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
415{
416 LogFlowFunc(("pInterface=%#p fNewStatusLines=%#x\n", pInterface, fNewStatusLines));
417 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
418 PPDMDEVINS pDevIns = pThisCC->pDevIns;
419 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
420
421 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
422 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
423
424 /** @todo */
425 RT_NOREF(pThis);
426
427 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
428 return VINF_SUCCESS;
429}
430
431
432/**
433 * @interface_method_impl{PDMISERIALPORT,pfnNotifyBrk}
434 */
435static DECLCALLBACK(int) pl011R3NotifyBrk(PPDMISERIALPORT pInterface)
436{
437 LogFlowFunc(("pInterface=%#p\n", pInterface));
438 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, ISerialPort);
439 PPDMDEVINS pDevIns = pThisCC->pDevIns;
440 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
441
442 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
443 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
444
445 /** @todo */
446 RT_NOREF(pThis);
447
448 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
449 return VINF_SUCCESS;
450}
451
452
453/* -=-=-=-=-=-=-=-=- PDMIBASE -=-=-=-=-=-=-=-=- */
454
455/**
456 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
457 */
458static DECLCALLBACK(void *) pl011R3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
459{
460 PDEVPL011CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL011CC, IBase);
461 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
462 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALPORT, &pThisCC->ISerialPort);
463 return NULL;
464}
465
466
467/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
468
469/**
470 * @callback_method_impl{FNSSMDEVLIVEEXEC}
471 */
472static DECLCALLBACK(int) pl011R3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
473{
474 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
475 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
476 RT_NOREF(uPass);
477
478 pHlp->pfnSSMPutU16(pSSM, pThis->u16Irq);
479 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmioBase);
480 return VINF_SSM_DONT_CALL_AGAIN;
481}
482
483
484/**
485 * @callback_method_impl{FNSSMDEVSAVEEXEC}
486 */
487static DECLCALLBACK(int) pl011R3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
488{
489 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
490 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
491
492 pHlp->pfnSSMPutU16(pSSM, pThis->u16Irq);
493 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmioBase);
494
495 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
496}
497
498
499/**
500 * @callback_method_impl{FNSSMDEVLOADEXEC}
501 */
502static DECLCALLBACK(int) pl011R3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
503{
504 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
505 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
506 uint16_t u16Irq;
507 RTGCPHYS GCPhysMmioBase;
508 int rc;
509
510 RT_NOREF(uVersion);
511
512 pHlp->pfnSSMGetU16( pSSM, &u16Irq);
513 pHlp->pfnSSMGetGCPhys(pSSM, &GCPhysMmioBase);
514 if (uPass == SSM_PASS_FINAL)
515 {
516 rc = VERR_NOT_IMPLEMENTED;
517 AssertRCReturn(rc, rc);
518 }
519
520 if (uPass == SSM_PASS_FINAL)
521 {
522 /* The marker. */
523 uint32_t u32;
524 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
525 AssertRCReturn(rc, rc);
526 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
527 }
528
529 /*
530 * Check the config.
531 */
532 if ( pThis->u16Irq != u16Irq
533 || pThis->GCPhysMmioBase != GCPhysMmioBase)
534 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
535 N_("Config mismatch - saved Irq=%#x GCPhysMmioBase=%#RGp; configured Irq=%#x GCPhysMmioBase=%#RGp"),
536 u16Irq, GCPhysMmioBase, pThis->u16Irq, pThis->GCPhysMmioBase);
537
538 return VINF_SUCCESS;
539}
540
541
542/**
543 * @callback_method_impl{FNSSMDEVLOADDONE}
544 */
545static DECLCALLBACK(int) pl011R3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
546{
547 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
548 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
549
550 RT_NOREF(pThis, pThisCC, pSSM);
551 return VERR_NOT_IMPLEMENTED;
552}
553
554
555/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
556
557/**
558 * @interface_method_impl{PDMDEVREG,pfnReset}
559 */
560static DECLCALLBACK(void) pl011R3Reset(PPDMDEVINS pDevIns)
561{
562 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
563 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
564
565 pThis->uRegCr = PL011_REG_UARTCR_TXE | PL011_REG_UARTCR_RXE;
566 pThis->uRegFr = PL011_REG_UARTFR_TXFE | PL011_REG_UARTFR_RXFE;
567 /** @todo */
568 RT_NOREF(pThisCC);
569}
570
571
572/**
573 * @interface_method_impl{PDMDEVREG,pfnAttach}
574 */
575static DECLCALLBACK(int) pl011R3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
576{
577 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
578 RT_NOREF(fFlags);
579 AssertReturn(iLUN == 0, VERR_PDM_LUN_NOT_FOUND);
580
581 int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThisCC->IBase, &pThisCC->pDrvBase, "PL011 Char");
582 if (RT_SUCCESS(rc))
583 {
584 pThisCC->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMISERIALCONNECTOR);
585 if (!pThisCC->pDrvSerial)
586 {
587 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", pDevIns->iInstance));
588 return VERR_PDM_MISSING_INTERFACE;
589 }
590 }
591 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
592 {
593 pThisCC->pDrvBase = NULL;
594 pThisCC->pDrvSerial = NULL;
595 LogRel(("PL011#%d: no unit\n", pDevIns->iInstance));
596 }
597 else /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
598 LogRel(("PL011#%d: Failed to attach to serial driver. rc=%Rrc\n", pDevIns->iInstance, rc));
599
600 return rc;
601}
602
603
604/**
605 * @interface_method_impl{PDMDEVREG,pfnDetach}
606 */
607static DECLCALLBACK(void) pl011R3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
608{
609 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
610 RT_NOREF(fFlags);
611 AssertReturnVoid(iLUN == 0);
612
613 /* Zero out important members. */
614 pThisCC->pDrvBase = NULL;
615 pThisCC->pDrvSerial = NULL;
616}
617
618
619/**
620 * @interface_method_impl{PDMDEVREG,pfnDestruct}
621 */
622static DECLCALLBACK(int) pl011R3Destruct(PPDMDEVINS pDevIns)
623{
624 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
625
626 /* Nothing to do. */
627 return VINF_SUCCESS;
628}
629
630
631/**
632 * @interface_method_impl{PDMDEVREG,pfnConstruct}
633 */
634static DECLCALLBACK(int) pl011R3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
635{
636 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
637 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
638 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
639 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
640 int rc;
641
642 Assert(iInstance < 4);
643
644 pThisCC->pDevIns = pDevIns;
645
646 /* IBase */
647 pThisCC->IBase.pfnQueryInterface = pl011R3QueryInterface;
648
649 /* ISerialPort */
650 pThisCC->ISerialPort.pfnDataAvailRdrNotify = pl011R3DataAvailRdrNotify;
651 pThisCC->ISerialPort.pfnDataSentNotify = pl011R3DataSentNotify;
652 pThisCC->ISerialPort.pfnReadWr = pl011R3ReadWr;
653 pThisCC->ISerialPort.pfnNotifyStsLinesChanged = pl011R3NotifyStsLinesChanged;
654 pThisCC->ISerialPort.pfnNotifyBrk = pl011R3NotifyBrk;
655
656 /*
657 * Validate and read the configuration.
658 */
659 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Irq|MmioBase|YieldOnLSRRead", "");
660
661 bool fYieldOnLSRRead = false;
662 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "YieldOnLSRRead", &fYieldOnLSRRead, false);
663 if (RT_FAILURE(rc))
664 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
665
666 uint16_t u16Irq = 0;
667 rc = pHlp->pfnCFGMQueryU16(pCfg, "Irq", &u16Irq);
668 if (RT_FAILURE(rc))
669 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Irq\" value"));
670
671 RTGCPHYS GCPhysMmioBase = 0;
672 rc = pHlp->pfnCFGMQueryU64(pCfg, "MmioBase", &GCPhysMmioBase);
673 if (RT_FAILURE(rc))
674 return PDMDEV_SET_ERROR(pDevIns, rc,
675 N_("Configuration error: Failed to get the \"IOBase\" value"));
676
677 pThis->u16Irq = u16Irq;
678 pThis->GCPhysMmioBase = GCPhysMmioBase;
679
680 /*
681 * Register and map the MMIO region.
682 */
683 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmioBase, PL011_MMIO_SIZE, pl011MmioWrite, pl011MmioRead,
684 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "PL011", &pThis->hMmio);
685 AssertRCReturn(rc, rc);
686
687
688 /*
689 * Saved state.
690 */
691 rc = PDMDevHlpSSMRegisterEx(pDevIns, PL011_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
692 NULL, pl011R3LiveExec, NULL,
693 NULL, pl011R3SaveExec, NULL,
694 NULL, pl011R3LoadExec, pl011R3LoadDone);
695 AssertRCReturn(rc, rc);
696
697 /*
698 * Attach the char driver and get the interfaces.
699 */
700 rc = PDMDevHlpDriverAttach(pDevIns, 0 /*iLUN*/, &pThisCC->IBase, &pThisCC->pDrvBase, "UART");
701 if (RT_SUCCESS(rc))
702 {
703 pThisCC->pDrvSerial = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMISERIALCONNECTOR);
704 if (!pThisCC->pDrvSerial)
705 {
706 AssertLogRelMsgFailed(("Configuration error: instance %d has no serial interface!\n", iInstance));
707 return VERR_PDM_MISSING_INTERFACE;
708 }
709 }
710 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
711 {
712 pThisCC->pDrvBase = NULL;
713 pThisCC->pDrvSerial = NULL;
714 LogRel(("PL011#%d: no unit\n", iInstance));
715 }
716 else
717 {
718 AssertLogRelMsgFailed(("PL011#%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
719 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
720 return rc;
721 }
722
723 pl011R3Reset(pDevIns);
724 return VINF_SUCCESS;
725}
726
727#else /* !IN_RING3 */
728
729/**
730 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
731 */
732static DECLCALLBACK(int) pl011RZConstruct(PPDMDEVINS pDevIns)
733{
734 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
735 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011);
736 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC);
737
738 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, pl011MmioWrite, pl011MmioRead, NULL /*pvUser*/);
739 AssertRCReturn(rc, rc);
740
741 return VINF_SUCCESS;
742}
743
744#endif /* !IN_RING3 */
745
746/**
747 * The device registration structure.
748 */
749const PDMDEVREG g_DevicePl011 =
750{
751 /* .u32Version = */ PDM_DEVREG_VERSION,
752 /* .uReserved0 = */ 0,
753 /* .szName = */ "arm-pl011",
754 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
755 /* .fClass = */ PDM_DEVREG_CLASS_SERIAL,
756 /* .cMaxInstances = */ UINT32_MAX,
757 /* .uSharedVersion = */ 42,
758 /* .cbInstanceShared = */ sizeof(DEVPL011),
759 /* .cbInstanceCC = */ sizeof(DEVPL011CC),
760 /* .cbInstanceRC = */ sizeof(DEVPL011RC),
761 /* .cMaxPciDevices = */ 0,
762 /* .cMaxMsixVectors = */ 0,
763 /* .pszDescription = */ "ARM PL011 PrimeCell UART",
764#if defined(IN_RING3)
765 /* .pszRCMod = */ "VBoxDDRC.rc",
766 /* .pszR0Mod = */ "VBoxDDR0.r0",
767 /* .pfnConstruct = */ pl011R3Construct,
768 /* .pfnDestruct = */ pl011R3Destruct,
769 /* .pfnRelocate = */ NULL,
770 /* .pfnMemSetup = */ NULL,
771 /* .pfnPowerOn = */ NULL,
772 /* .pfnReset = */ pl011R3Reset,
773 /* .pfnSuspend = */ NULL,
774 /* .pfnResume = */ NULL,
775 /* .pfnAttach = */ pl011R3Attach,
776 /* .pfnDetach = */ pl011R3Detach,
777 /* .pfnQueryInterface = */ NULL,
778 /* .pfnInitComplete = */ NULL,
779 /* .pfnPowerOff = */ NULL,
780 /* .pfnSoftReset = */ NULL,
781 /* .pfnReserved0 = */ NULL,
782 /* .pfnReserved1 = */ NULL,
783 /* .pfnReserved2 = */ NULL,
784 /* .pfnReserved3 = */ NULL,
785 /* .pfnReserved4 = */ NULL,
786 /* .pfnReserved5 = */ NULL,
787 /* .pfnReserved6 = */ NULL,
788 /* .pfnReserved7 = */ NULL,
789#elif defined(IN_RING0)
790 /* .pfnEarlyConstruct = */ NULL,
791 /* .pfnConstruct = */ pl011RZConstruct,
792 /* .pfnDestruct = */ NULL,
793 /* .pfnFinalDestruct = */ NULL,
794 /* .pfnRequest = */ NULL,
795 /* .pfnReserved0 = */ NULL,
796 /* .pfnReserved1 = */ NULL,
797 /* .pfnReserved2 = */ NULL,
798 /* .pfnReserved3 = */ NULL,
799 /* .pfnReserved4 = */ NULL,
800 /* .pfnReserved5 = */ NULL,
801 /* .pfnReserved6 = */ NULL,
802 /* .pfnReserved7 = */ NULL,
803#elif defined(IN_RC)
804 /* .pfnConstruct = */ pl011RZConstruct,
805 /* .pfnReserved0 = */ NULL,
806 /* .pfnReserved1 = */ NULL,
807 /* .pfnReserved2 = */ NULL,
808 /* .pfnReserved3 = */ NULL,
809 /* .pfnReserved4 = */ NULL,
810 /* .pfnReserved5 = */ NULL,
811 /* .pfnReserved6 = */ NULL,
812 /* .pfnReserved7 = */ NULL,
813#else
814# error "Not in IN_RING3, IN_RING0 or IN_RC!"
815#endif
816 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
817};
818
819#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
820
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