1
0
mirror of https://github.com/projectacrn/acrn-hypervisor.git synced 2025-05-03 05:56:57 +00:00

doc: add module design for peripheral vuart device

GAI Tooling Notice: These contents may have been developed with support from one
or more generative artificial intelligence solutions.

This patch is to add doxygen style comments for some elements in
vp-dm_vperipheral vuart module.

Tracked-On: 

Signed-off-by: Haiwei Li <haiwei.li@intel.com>
This commit is contained in:
Haiwei Li 2024-08-13 16:38:56 +08:00 committed by acrnsi-robot
parent 436cb9cddf
commit aba53e78ef
2 changed files with 254 additions and 27 deletions
hypervisor
dm
include/dm

View File

@ -1,7 +1,7 @@
/*-
* Copyright (c) 2012 NetApp, Inc.
* Copyright (c) 2013 Neel Natu <neel@freebsd.org>
* Copyright (c) 2018-2022 Intel Corporation.
* Copyright (c) 2018-2024 Intel Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -36,6 +36,20 @@
#include <asm/guest/vm.h>
#include <logmsg.h>
/**
* @addtogroup vp-dm_vperipheral
*
* @{
*/
/**
* @file
* @brief Implementation of virtual UART device.
*
* This file implements all the APIs to support virtual UART device. It also defines some helper functions to simulate
* the device that are commonly used in this file.
*/
#define init_vuart_lock(vu) spinlock_init(&((vu)->lock))
#define obtain_vuart_lock(vu, flags) spinlock_irqsave_obtain(&((vu)->lock), &(flags))
#define release_vuart_lock(vu, flags) spinlock_irqrestore_release(&((vu)->lock), (flags))
@ -376,8 +390,31 @@ static void write_reg(struct acrn_vuart *vu, uint16_t reg, uint8_t value_u8)
release_vuart_lock(vu, rflags);
}
/*
* @pre: vu != NULL
/**
* @brief Write a value to a register in the virtual UART.
*
* This function writes a 8-bit value to a specified register in the virtual UART (vUART). It is a basic function used
* for port I/O write or MMIO write.
*
* - When the following conditions are met, data is sent to the target vUART's RXFIFO:
* 1) The target vUART exists for the specified vUART, which is used for communication.
* 2) The accessed register is the THR (Transmitter Holding Register).
* 3) Loopback mode is not enabled.
* 4) DLAB (Divisor Latch Access Bit) is not set.
* - Additionally, to ensure reliable communication, it raises the THRE interrupt (indicating that more data can be
* processed) only if the target vUART's RXFIFO is not full.
* - If these conditions are not met, the virtual registers specified by the offset are updated according to the 16550
* UART specification.
*
* @param[inout] vu The virtual UART structure to which the register value is to be written.
* @param[in] offset The offset of the register within the vUART.
* @param[in] value_u8 The 8-bit value to be written to the register.
*
* @return None
*
* @pre vu != NULL
*
* @post N/A
*/
void vuart_write_reg(struct acrn_vuart *vu, uint16_t offset, uint8_t value_u8)
{
@ -401,8 +438,28 @@ void vuart_write_reg(struct acrn_vuart *vu, uint16_t offset, uint8_t value_u8)
}
/**
* @brief Write a value to a port in the legacy virtual UART.
*
* This function writes a value to the legacy virtual UART (vUART) based on the specified port address. It is used to
* handle I/O port write operations in the VM by updating the vUART's register. This function is typically called when
* the vCPU needs to write data to the vUART during emulation of I/O port operations.
*
* - Based on the specified port address, it first finds the vUART device within the VM corresponding to the given vCPU.
* - If the vUART is found, the value is written to the corresponding register. For detailed write operations, refer to
* vuart_write_reg().
* - If the vUART is not found, the write operation is ignored.
*
* @param[inout] vcpu A pointer to the vCPU that initiates the write operation.
* @param[in] offset_arg The port address to write to.
* @param[in] width The width of the write operation (unused in this function).
* @param[in] value The value to be written to the register.
*
* @return Always returns true.
*
* @pre vcpu != NULL
* @pre vcpu->vm != NULL
*
* @post N/A
*/
static bool vuart_write(struct acrn_vcpu *vcpu, uint16_t offset_arg,
__unused size_t width, uint32_t value)
@ -435,7 +492,28 @@ static void notify_target(const struct acrn_vuart *vu)
}
/**
* @brief Read a register from the virtual UART.
*
* This function returns the 8-bit value of a specified register. It is a basic function used for port I/O read or MMIO
* read. The registers in the UART will affect each other, such as reading the LSR register will clear some bits in it.
* This function carefully simulates this behavior.
*
* - If the DLAB bit in LCR is set, only the DLL and DLH registers are accessed. Other registers are considered as 0.
* - Otherwise, according to the UART16550 specification, set and read the corresponding register. For registers greater
* than 0x07 (SCR), the value will be 0xFF.
* - It will toggle the interrupt.
* - For communication vUART, when the data in FIFO is read out (read from RBR), it will notify the target vUART to send
* more data.
* - Finally, it will return the value of the specified register.
*
* @param[inout] vu Pointer to the virtual UART device.
* @param[in] offset The specified offset of the register to read.
*
* @return The value of the specified register.
*
* @pre vu != NULL
*
* @post N/A
*/
uint8_t vuart_read_reg(struct acrn_vuart *vu, uint16_t offset)
{
@ -529,8 +607,27 @@ uint8_t vuart_read_reg(struct acrn_vuart *vu, uint16_t offset)
}
/**
* @brief Read a value from a port in the legacy virtual UART.
*
* This function reads a value from the legacy virtual UART (vUART) based on the specified port address. It is used to
* handle I/O port read operations in the VM by retrieving the value from the vUART's registers. This function is
* typically called when the vCPU needs to read data from the vUART during emulation of I/O port operations.
*
* - Based on the specified port address, it first finds the vUART device within the VM corresponding to the given vCPU.
* - If the vUART is found, the value is read from the corresponding virtual register and stored in the vCPU's PIO
* request. For detailed read operations, refer to vuart_read_reg().
* - If the vUART is not found, the vCPU's PIO request remains unchanged.
*
* @param[inout] vcpu A pointer to the vCPU that initiates the read operation.
* @param[in] offset_arg The port address to read from.
* @param[in] width The width of the read operation (unused in this function).
*
* @return Always returns true.
*
* @pre vcpu != NULL
* @pre vcpu->vm != NULL
*
* @post N/A
*/
static bool vuart_read(struct acrn_vcpu *vcpu, uint16_t offset_arg, __unused size_t width)
{
@ -628,6 +725,27 @@ static void vuart_deinit_connection(struct acrn_vuart *vu)
vu->target_vu = NULL;
}
/**
* @brief Check if any of the vUARTs in the given VM uses the specified INTx interrupt.
*
* This function checks whether the INTx interrupt is already used by vUART. It's usually used when the hypervisor
* tries to add a new INTx remapping.
*
* It will check all the vUARTs in the VM to see if any of them uses the specified INTx interrupt. If any of the vUARTs
* is active and using the specified INTx interrupt, the function will return true. Otherwise, it will return false.
*
* @param[in] vm Pointer to the VM.
* @param[in] intx_gsi The INTx interrupt number to check against the vUART configurations.
*
* @return A boolean value indicating if any of the vUARTs in the VM uses the specified INTx interrupt.
*
* @retval true If any of the vUARTs in the VM uses the specified INTx interrupt.
* @retval false If none of the vUARTs in the VM uses the specified INTx interrupt.
*
* @pre vm != NULL
*
* @post N/A
*/
bool is_vuart_intx(const struct acrn_vm *vm, uint32_t intx_gsi)
{
uint8_t i;
@ -641,6 +759,28 @@ bool is_vuart_intx(const struct acrn_vm *vm, uint32_t intx_gsi)
return ret;
}
/**
* @brief Initialize legacy virtual UART devices.
*
* This function initializes the legacy virtual UARTs (vUARTs) in hypervisor. A vUART is emulated as a 16550 UART device
* and can exchange data between the hypervisor and a VM or between two VMs. It sets up the necessary configurations and
* resources required for the vUARTs to function correctly. This function is usually called during VM creation.
*
* A VM can have several vUARTs (including legacy and PCI vUARTs). The first vUART is used for the VM console, and the
* rest are used for communication between VMs. Every legacy vUART device defined in the vUART configuration list is
* initialized and configured. It will also register port I/O handlers for every vUART device and set up the connection
* between vUARTs for communication.
*
* @param[inout] vm Pointer to the VM that owns the vUART devices.
* @param[in] vu_config Pointer to the vUART configuration structure list that contains the configuration information.
*
* @return None
*
* @pre vm != NULL
* @pre vu_config != NULL
*
* @post N/A
*/
void init_legacy_vuarts(struct acrn_vm *vm, const struct vuart_config *vu_config)
{
uint8_t i;
@ -668,6 +808,24 @@ void init_legacy_vuarts(struct acrn_vm *vm, const struct vuart_config *vu_config
}
}
/**
* @brief Deinitialize legacy virtual UART devices.
*
* This function deinitializes the legacy virtual UARTs (vUARTs) in hypervisor. It cleans up the resources and
* configurations that were set up for the vUARTs during initialization. This function should be called when the vUARTs
* are no longer needed, such as when a VM is being destroyed.
*
* The function will deinitialize all vUARTs associated with the given VM. It will set the active flag to false and
* remove the connection between vUARTs for communication.
*
* @param[inout] vm Pointer to the VM that owns the vUART devices.
*
* @return None
*
* @pre vm != NULL
*
* @post N/A
*/
void deinit_legacy_vuarts(struct acrn_vm *vm)
{
uint8_t i;
@ -683,6 +841,26 @@ void deinit_legacy_vuarts(struct acrn_vm *vm)
}
}
/**
* @brief Initialize a PCI virtual UART device.
*
* This function initializes a PCI-based virtual UART (vUART) in hypervisor. A MCS9900 controller is emulated as a PCI
* device, and the vUART device is a part of the MCS9900 controller. This function is usually called during the VM
* creation and after the MCS9900 controller device is initialized.
*
* A VM can have several vUARTs (including legacy and PCI vUARTs). The first vUART is used for the VM console, and the
* rest are used for communication between VMs. The PCI vUARTs are only used for communication between VMs for now. It
* will initialize the vUART associated with the given PCI device and set up the connection between vUARTs for
* communication.
*
* @param[inout] vdev Pointer to the PCI device that owns the vUART.
*
* @return None
*
* @pre vdev != NULL
*
* @post N/A
*/
void init_pci_vuart(struct pci_vdev *vdev)
{
struct acrn_vuart *vu = vdev->priv_data;
@ -705,6 +883,24 @@ void init_pci_vuart(struct pci_vdev *vdev)
}
/**
* @brief Deinitialize a PCI virtual UART device.
*
* This function deinitializes a PCI virtual UART (vUART) in hypervisor. It cleans up the resources and configurations
* that were set up for the vUART during initialization. This function should be called when the vUART is no longer
* needed, such as when a VM is being destroyed.
*
* The function will deinitialize the vUART associated with the given PCI device. It will set the active flag to false
* and remove the connection between vUARTs for communication.
*
* @param[inout] vdev Pointer to the PCI device that owns the vUART.
*
* @return None
*
* @pre vdev != NULL
*
* @post N/A
*/
void deinit_pci_vuart(struct pci_vdev *vdev)
{
struct acrn_vuart *vu = vdev->priv_data;
@ -715,3 +911,7 @@ void deinit_pci_vuart(struct pci_vdev *vdev)
vuart_deinit_connection(vu);
}
}
/**
* @}
*/

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2013 Neel Natu <neel@freebsd.org>
* Copyright (c) 2018-2022 Intel Corporation.
* Copyright (c) 2018-2024 Intel Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -32,6 +32,19 @@
#include <asm/lib/spinlock.h>
#include <asm/vm_config.h>
/**
* @addtogroup vp-dm_vperipheral
*
* @{
*/
/**
* @file
* @brief All APIs to support virtual UART device.
*
* This file defines macros, structures and function declarations for emulating virtual UART device.
*/
#define RX_BUF_SIZE CONFIG_VUART_RX_BUF_SIZE
#define TX_BUF_SIZE CONFIG_VUART_TX_BUF_SIZE
#define VUART_TIMER_CPU CONFIG_VUART_TIMER_PCPU
@ -56,31 +69,41 @@ struct vuart_fifo {
uint32_t size; /* size of the fifo */
};
/**
* @brief Data structure to illustrate a virtual UART device.
*
* This structure contains the information of a virtual UART device.
*
* @consistency self.vm->vuart[X] == self
* @alignment N/A
*
* @remark N/A
*/
struct acrn_vuart {
uint8_t data; /* Data register (R/W) */
uint8_t ier; /* Interrupt enable register (R/W) */
uint8_t lcr; /* Line control register (R/W) */
uint8_t mcr; /* Modem control register (R/W) */
uint8_t lsr; /* Line status register (R/W) */
uint8_t msr; /* Modem status register (R/W) */
uint8_t fcr; /* FIFO control register (W) */
uint8_t scr; /* Scratch register (R/W) */
uint8_t dll; /* Baudrate divisor latch LSB */
uint8_t dlh; /* Baudrate divisor latch MSB */
uint8_t data; /**< Data register (R/W). */
uint8_t ier; /**< Interrupt enable register (R/W). */
uint8_t lcr; /**< Line control register (R/W). */
uint8_t mcr; /**< Modem control register (R/W). */
uint8_t lsr; /**< Line status register (R/W). */
uint8_t msr; /**< Modem status register (R/W). */
uint8_t fcr; /**< FIFO control register (W). */
uint8_t scr; /**< Scratch register (R/W). */
uint8_t dll; /**< Baudrate divisor latch LSB. */
uint8_t dlh; /**< Baudrate divisor latch MSB. */
struct vuart_fifo rxfifo;
struct vuart_fifo txfifo;
uint16_t port_base;
uint32_t irq;
char vuart_rx_buf[RX_BUF_SIZE];
char vuart_tx_buf[TX_BUF_SIZE];
bool thre_int_pending; /* THRE interrupt pending */
bool active;
bool escaping; /* in escaping sequence, for console vuarts */
struct acrn_vuart *target_vu; /* Pointer to target vuart */
struct acrn_vm *vm;
struct pci_vdev *vdev; /* pci vuart */
spinlock_t lock; /* protects all softc elements */
struct vuart_fifo rxfifo; /**< FIFO queue for received data. */
struct vuart_fifo txfifo; /**< FIFO queue for transmitted data. */
uint16_t port_base; /**< Base port address of the virtual UART device. */
uint32_t irq; /**< IRQ number of the virtual UART device. */
char vuart_rx_buf[RX_BUF_SIZE]; /**< Buffer for received data. */
char vuart_tx_buf[TX_BUF_SIZE]; /**< Buffer for transmitted data. */
bool thre_int_pending; /**< Whether Transmitter Holding Register Empty(THRE) interrupt is pending. */
bool active; /**< Whether the vuart is active. */
bool escaping; /**< Whether in escaping sequence, only for console vuarts. */
struct acrn_vuart *target_vu; /**< Pointer to target vuart */
struct acrn_vm *vm; /**< Pointer to the VM that owns the virtual UART device. */
struct pci_vdev *vdev; /**< Pointer to the PCI device, only for a PCI vuart. */
spinlock_t lock; /**< The spinlock to protect simultaneous access of all elements. */
};
void init_legacy_vuarts(struct acrn_vm *vm, const struct vuart_config *vu_config);
@ -97,3 +120,7 @@ bool is_vuart_intx(const struct acrn_vm *vm, uint32_t intx_gsi);
uint8_t vuart_read_reg(struct acrn_vuart *vu, uint16_t offset);
void vuart_write_reg(struct acrn_vuart *vu, uint16_t offset, uint8_t value);
#endif /* VUART_H */
/**
* @}
*/