Changeset 99152 in vbox for trunk/src/VBox
- Timestamp:
- Mar 23, 2023 6:15:43 PM (22 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Serial/DevPL011.cpp
r99126 r99152 54 54 /** PL011 MMIO region size in bytes. */ 55 55 #define PL011_MMIO_SIZE _4K 56 /** Maximum size of a FIFO. */ 57 #define PL011_FIFO_LENGTH_MAX 32 56 58 57 59 /** The offset of the UARTDR register from the beginning of the region. */ … … 136 138 /** The offset of the UARTCR register from the beginning of the region. */ 137 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) 138 148 /** UART transmit enable flag. */ 139 149 # define PL011_REG_UARTCR_TXE RT_BIT(8) 140 150 /** UART receive enable flag. */ 141 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) 142 164 143 165 /** The offset of the UARTIFLS register from the beginning of the region. */ 144 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 145 181 146 182 /** The offset of the UARTIMSC register from the beginning of the region. */ … … 176 212 #define PL011_REG_UART_PCELL_ID3_INDEX 0xffc 177 213 214 /** Set the specified bits in the given register. */ 215 #define PL011_REG_SET(a_Reg, a_Set) ((a_Reg) |= (a_Set)) 216 /** Clear the specified bits in the given register. */ 217 #define PL011_REG_CLR(a_Reg, a_Clr) ((a_Reg) &= ~(a_Clr)) 218 178 219 179 220 /********************************************************************************************************************************* 180 221 * Structures and Typedefs * 181 222 *********************************************************************************************************************************/ 223 224 /** 225 * UART FIFO. 226 */ 227 typedef struct PL011FIFO 228 { 229 /** Fifo size configured. */ 230 uint8_t cbMax; 231 /** Current amount of bytes used. */ 232 uint8_t cbUsed; 233 /** Next index to write to. */ 234 uint8_t offWrite; 235 /** Next index to read from. */ 236 uint8_t offRead; 237 /** The interrupt trigger level (only used for the receive FIFO). */ 238 uint8_t cbItl; 239 /** The data in the FIFO. */ 240 uint8_t abBuf[PL011_FIFO_LENGTH_MAX]; 241 /** Alignment to a 4 byte boundary. */ 242 uint8_t au8Alignment0[3]; 243 } PL011FIFO; 244 /** Pointer to a FIFO. */ 245 typedef PL011FIFO *PPL011FIFO; 246 182 247 183 248 /** … … 195 260 /** @name Registers. 196 261 * @{ */ 262 uint8_t uRegDr; 197 263 /** UART control register. */ 198 uint 32_t uRegCr;264 uint16_t uRegCr; 199 265 /** UART flag register. */ 200 uint32_t uRegFr; 266 uint16_t uRegFr; 267 /** UART integer baud rate register. */ 268 uint16_t uRegIbrd; 269 /** UART fractional baud rate register. */ 270 uint16_t uRegFbrd; 271 /** UART line control register. */ 272 uint16_t uRegLcrH; 201 273 /** @} */ 274 275 /** Time it takes to transmit/receive a single symbol in timer ticks. */ 276 uint64_t cSymbolXferTicks; 277 /** Number of bytes available for reading from the layer below. */ 278 volatile uint32_t cbAvailRdr; 279 280 /** The transmit FIFO. */ 281 PL011FIFO FifoXmit; 282 /** The receive FIFO. */ 283 PL011FIFO FifoRecv; 202 284 } DEVPL011; 203 285 /** Pointer to the shared serial device state. */ … … 255 337 256 338 339 /********************************************************************************************************************************* 340 * Global Variables * 341 *********************************************************************************************************************************/ 342 343 #ifdef IN_RING3 344 /** 345 * String versions of the parity enum. 346 */ 347 static const char *s_aszParity[] = 348 { 349 "INVALID", 350 "NONE", 351 "EVEN", 352 "ODD", 353 "MARK", 354 "SPACE", 355 "INVALID" 356 }; 357 358 359 /** 360 * String versions of the stop bits enum. 361 */ 362 static const char *s_aszStopBits[] = 363 { 364 "INVALID", 365 "1", 366 "INVALID", 367 "2", 368 "INVALID" 369 }; 370 #endif 371 372 373 /********************************************************************************************************************************* 374 * Internal Functions * 375 *********************************************************************************************************************************/ 376 257 377 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 258 378 379 /** 380 * Updates the IRQ state based on the current device state. 381 * 382 * @returns nothing. 383 * @param pDevIns The device instance. 384 * @param pThis The shared serial port instance data. 385 * @param pThisCC The serial port instance data for the current context. 386 */ 387 static void pl011IrqUpdate(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC) 388 { 389 LogFlowFunc(("pThis=%#p\n", pThis)); 390 RT_NOREF(pDevIns, pThis, pThisCC); 391 } 392 393 394 /** 395 * Transmits the given byte. 396 * 397 * @returns Strict VBox status code. 398 * @param pDevIns The device instance. 399 * @param pThis The shared serial port instance data. 400 * @param pThisCC The serial port instance data for the current context. 401 * @param bVal Byte to transmit. 402 */ 403 static VBOXSTRICTRC pl011Xmit(PPDMDEVINS pDevIns, PDEVPL011CC pThisCC, PDEVPL011 pThis, uint8_t bVal) 404 { 405 int rc = VINF_SUCCESS; 406 #ifdef IN_RING3 407 bool fNotifyDrv = false; 408 #endif 409 410 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_FEN) 411 { 412 AssertReleaseFailed(); /** @todo */ 413 } 414 else 415 { 416 /* Notify the lower driver about available data only if the register was empty before. */ 417 if (!(pThis->uRegFr & PL011_REG_UARTFR_BUSY)) 418 { 419 #ifndef IN_RING3 420 rc = VINF_IOM_R3_IOPORT_WRITE; 421 #else 422 pThis->uRegDr = bVal; 423 pThis->uRegFr |= PL011_REG_UARTFR_BUSY; 424 pl011IrqUpdate(pDevIns, pThis, pThisCC); 425 fNotifyDrv = true; 426 #endif 427 } 428 else 429 pThis->uRegDr = bVal; 430 } 431 432 #ifdef IN_RING3 433 if (fNotifyDrv) 434 { 435 /* Leave the device critical section before calling into the lower driver. */ 436 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3); 437 438 if ( pThisCC->pDrvSerial 439 && !(pThis->uRegCr & PL011_REG_UARTCR_LBE)) 440 { 441 int rc2 = pThisCC->pDrvSerial->pfnDataAvailWrNotify(pThisCC->pDrvSerial); 442 if (RT_FAILURE(rc2)) 443 LogRelMax(10, ("PL011#%d: Failed to send data with %Rrc\n", pDevIns->iInstance, rc2)); 444 } 445 else 446 { 447 AssertReleaseFailed(); /** @todo */ 448 //PDMDevHlpTimerSetRelative(pDevIns, pThis->hTimerTxUnconnected, pThis->cSymbolXferTicks, NULL); 449 } 450 451 rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VINF_SUCCESS); 452 } 453 #endif 454 455 return rc; 456 } 457 458 459 #ifdef IN_RING3 460 /** 461 * Updates the serial port parameters of the attached driver with the current configuration. 462 * 463 * @returns nothing. 464 * @param pDevIns The device instance. 465 * @param pThis The shared serial port instance data. 466 * @param pThisCC The serial port instance data for the current context. 467 */ 468 static void pl011R3ParamsUpdate(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC) 469 { 470 if ( pThis->uRegIbrd != 0 471 && pThisCC->pDrvSerial) 472 { 473 uint32_t uBps = 460800 / pThis->uRegIbrd; /** @todo This is for a 7.3728MHz clock. */ 474 unsigned cDataBits = PL011_REG_UARTLCR_H_WLEN_GET(pThis->uRegLcrH) + 5; 475 uint32_t cFrameBits = cDataBits; 476 PDMSERIALSTOPBITS enmStopBits = PDMSERIALSTOPBITS_ONE; 477 PDMSERIALPARITY enmParity = PDMSERIALPARITY_NONE; 478 479 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_STP2) 480 { 481 enmStopBits = PDMSERIALSTOPBITS_TWO; 482 cFrameBits += 2; 483 } 484 else 485 cFrameBits++; 486 487 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_PEN) 488 { 489 /* Select the correct parity mode based on the even and stick parity bits. */ 490 switch (pThis->uRegLcrH & (PL011_REG_UARTLCR_H_EPS | PL011_REG_UARTLCR_H_SPS)) 491 { 492 case 0: 493 enmParity = PDMSERIALPARITY_ODD; 494 break; 495 case PL011_REG_UARTLCR_H_EPS: 496 enmParity = PDMSERIALPARITY_EVEN; 497 break; 498 case PL011_REG_UARTLCR_H_EPS | PL011_REG_UARTLCR_H_SPS: 499 enmParity = PDMSERIALPARITY_SPACE; 500 break; 501 case PL011_REG_UARTLCR_H_SPS: 502 enmParity = PDMSERIALPARITY_MARK; 503 break; 504 default: 505 /* We should never get here as all cases where caught earlier. */ 506 AssertMsgFailed(("This shouldn't happen at all: %#x\n", 507 pThis->uRegLcrH & (PL011_REG_UARTLCR_H_EPS | PL011_REG_UARTLCR_H_SPS))); 508 } 509 510 cFrameBits++; 511 } 512 513 //uint64_t uTimerFreq = PDMDevHlpTimerGetFreq(pDevIns, pThis->hTimerRcvFifoTimeout); 514 //pThis->cSymbolXferTicks = (uTimerFreq / uBps) * cFrameBits; 515 516 LogFlowFunc(("Changing parameters to: %u,%s,%u,%s\n", 517 uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits])); 518 519 int rc = pThisCC->pDrvSerial->pfnChgParams(pThisCC->pDrvSerial, uBps, enmParity, cDataBits, enmStopBits); 520 if (RT_FAILURE(rc)) 521 LogRelMax(10, ("Serial#%d: Failed to change parameters to %u,%s,%u,%s -> %Rrc\n", 522 pDevIns->iInstance, uBps, s_aszParity[enmParity], cDataBits, s_aszStopBits[enmStopBits], rc)); 523 524 /* Changed parameters will flush all receive queues, so there won't be any data to read even if indicated. */ 525 pThisCC->pDrvSerial->pfnQueuesFlush(pThisCC->pDrvSerial, true /*fQueueRecv*/, false /*fQueueXmit*/); 526 ASMAtomicWriteU32(&pThis->cbAvailRdr, 0); 527 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_BUSY); 528 } 529 } 530 531 532 /** 533 * Reset the transmit/receive related bits to the standard values 534 * (after a detach/attach/reset event). 535 * 536 * @returns nothing. 537 * @param pDevIns The device instance. 538 * @param pThis The shared serial port instance data. 539 * @param pThisCC The serial port instance data for the current context. 540 */ 541 static void pl011R3XferReset(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC) 542 { 543 //PDMDevHlpTimerStop(pDevIns, pThis->hTimerRcvFifoTimeout); 544 //PDMDevHlpTimerStop(pDevIns, pThis->hTimerTxUnconnected); 545 //pThis->uRegLsr = UART_REG_LSR_THRE | UART_REG_LSR_TEMT; 546 547 //uartFifoClear(&pThis->FifoXmit); 548 //uartFifoClear(&pThis->FifoRecv); 549 pl011R3ParamsUpdate(pDevIns, pThis, pThisCC); 550 pl011IrqUpdate(pDevIns, pThis, pThisCC); 551 552 if (pThisCC->pDrvSerial) 553 { 554 /* Set the modem lines to reflect the current state. */ 555 int rc = pThisCC->pDrvSerial->pfnChgModemLines(pThisCC->pDrvSerial, false /*fRts*/, false /*fDtr*/); 556 if (RT_FAILURE(rc)) 557 LogRel(("PL011#%d: Failed to set modem lines with %Rrc during reset\n", 558 pDevIns->iInstance, rc)); 559 560 uint32_t fStsLines = 0; 561 rc = pThisCC->pDrvSerial->pfnQueryStsLines(pThisCC->pDrvSerial, &fStsLines); 562 if (RT_SUCCESS(rc)) 563 {} //uartR3StsLinesUpdate(pDevIns, pThis, pThisCC, fStsLines); 564 else 565 LogRel(("PL011#%d: Failed to query status line status with %Rrc during reset\n", 566 pDevIns->iInstance, rc)); 567 } 568 569 } 570 571 572 /** 573 * Tries to copy the specified amount of data from the active TX queue (register or FIFO). 574 * 575 * @returns nothing. 576 * @param pDevIns The device instance. 577 * @param pThis The shared serial port instance data. 578 * @param pThisCC The serial port instance data for the current context. 579 * @param pvBuf Where to store the data. 580 * @param cbRead How much to read from the TX queue. 581 * @param pcbRead Where to store the amount of data read. 582 */ 583 static void pl011R3TxQueueCopyFrom(PPDMDEVINS pDevIns, PDEVPL011 pThis, PDEVPL011CC pThisCC, 584 void *pvBuf, size_t cbRead, size_t *pcbRead) 585 { 586 if (pThis->uRegLcrH & PL011_REG_UARTLCR_H_FEN) 587 { 588 RT_NOREF(cbRead); 589 AssertReleaseFailed(); 590 } 591 else if (pThis->uRegFr & PL011_REG_UARTFR_BUSY) 592 { 593 *(uint8_t *)pvBuf = pThis->uRegDr; 594 *pcbRead = 1; 595 PL011_REG_CLR(pThis->uRegFr, PL011_REG_UARTFR_BUSY); 596 pl011IrqUpdate(pDevIns, pThis, pThisCC); 597 } 598 else 599 { 600 /* 601 * This can happen if there was data in the FIFO when the connection was closed, 602 * indicate this condition to the lower driver by returning 0 bytes. 603 */ 604 *pcbRead = 0; 605 } 606 } 607 #endif 259 608 260 609 … … 324 673 static DECLCALLBACK(VBOXSTRICTRC) pl011MmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb) 325 674 { 326 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011); 675 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011); 676 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC); 327 677 LogFlowFunc(("cb=%u reg=%RGp val=%llx\n", cb, off, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef)); 328 678 RT_NOREF(pvUser); … … 330 680 Assert(!(off & (cb - 1))); 331 681 332 int rc = VINF_SUCCESS; 333 return rc; 682 VBOXSTRICTRC rcStrict = VINF_SUCCESS; 683 uint32_t u32Val = *(uint32_t *)pv; 684 switch (off) 685 { 686 case PL011_REG_UARTDR_INDEX: 687 if ( (pThis->uRegCr & PL011_REG_UARTCR_UARTEN) 688 && (pThis->uRegCr & PL011_REG_UARTCR_TXE)) 689 rcStrict = pl011Xmit(pDevIns, pThisCC, pThis, (uint8_t)u32Val); 690 break; 691 default: 692 break; 693 694 } 695 return rcStrict; 334 696 } 335 697 … … 400 762 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock); 401 763 402 /** @todo */ 403 RT_NOREF(pThis); 764 pl011R3TxQueueCopyFrom(pDevIns, pThis, pThisCC, pvBuf, cbRead, pcbRead); 404 765 405 766 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3); … … 563 924 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC); 564 925 565 pThis->uRegCr = PL011_REG_UARTCR_TXE | PL011_REG_UARTCR_RXE; 566 pThis->uRegFr = PL011_REG_UARTFR_TXFE | PL011_REG_UARTFR_RXFE; 926 pThis->uRegDr = 0; 927 /* UARTEN is normally 0 on reset but UEFI doesn't set it causing the serial port to not log anything. */ 928 pThis->uRegCr = PL011_REG_UARTCR_TXE | PL011_REG_UARTCR_RXE | PL011_REG_UARTCR_UARTEN; 929 pThis->uRegFr = PL011_REG_UARTFR_TXFE | PL011_REG_UARTFR_RXFE; 930 pThis->uRegIbrd = 0; 931 pThis->uRegFbrd = 0; 932 pThis->uRegLcrH = 0; 567 933 /** @todo */ 568 RT_NOREF(pThisCC); 934 935 pl011R3XferReset(pDevIns, pThis, pThisCC); 569 936 } 570 937 … … 575 942 static DECLCALLBACK(int) pl011R3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags) 576 943 { 944 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011); 577 945 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC); 578 946 RT_NOREF(fFlags); … … 588 956 return VERR_PDM_MISSING_INTERFACE; 589 957 } 958 rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED); 959 if (RT_SUCCESS(rc)) 960 { 961 pl011R3XferReset(pDevIns, pThis, pThisCC); 962 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3); 963 } 590 964 } 591 965 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER) … … 593 967 pThisCC->pDrvBase = NULL; 594 968 pThisCC->pDrvSerial = NULL; 969 rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED); 970 if (RT_SUCCESS(rc)) 971 { 972 pl011R3XferReset(pDevIns, pThis, pThisCC); 973 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3); 974 } 595 975 LogRel(("PL011#%d: no unit\n", pDevIns->iInstance)); 596 976 } … … 607 987 static DECLCALLBACK(void) pl011R3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags) 608 988 { 989 PDEVPL011 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL011); 609 990 PDEVPL011CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL011CC); 610 991 RT_NOREF(fFlags); … … 614 995 pThisCC->pDrvBase = NULL; 615 996 pThisCC->pDrvSerial = NULL; 997 998 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED); 999 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock); 1000 1001 pl011R3XferReset(pDevIns, pThis, pThisCC); 1002 1003 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3); 616 1004 } 617 1005
Note:
See TracChangeset
for help on using the changeset viewer.