mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-09 18:44:58 -06:00
RISC-V PR for 9.2
* Fix an access to VXSAT * Expose RV32 cpu to RV64 QEMU * Don't clear PLIC pending bits on IRQ lowering * Make PLIC zeroth priority register read-only * Set vtype.vill on CPU reset * Check and update APLIC pending when write sourcecfg * Avoid dropping charecters with HTIF * Apply FIFO backpressure to guests using SiFive UART * Support for control flow integrity extensions * Support for the IOMMU with the virt machine * set 'aia_mode' to default in error path * clarify how 'riscv-aia' default works -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEaukCtqfKh31tZZKWr3yVEwxTgBMFAmci/tQACgkQr3yVEwxT gBNPAQ//dZKjjJm4Sh+UFdUslivBJYtL1rl2UUG2UqiNn/UoYh/vcHoSArljHTjt 8riEStnaQqXziOpMIJjIMLJ4KoiIk2SMvjNfFtcmPiPZEDEpjsTxfUxBFsBee+fI 4KNQKKFeljq4pa+VzVvXEqzCNJIzCThFXTZhZmer00M91HPA8ZQIHpv2JL1sWlgZ /HW24XEDFLGc/JsR55fxpPftlAqP+BfOrqMmbWy7x2Y+G8WI05hM2zTP/W8pnIz3 z0GCRYSBlADtrp+3RqzTwQfK5pXoFc0iDktWVYlhoXaeEmOwo8IYxTjrvBGhnBq+ ySX1DzTa23QmOIxSYYvCRuOxyOK9ziNn+EQ9FiFBt1h1o251CYMil1bwmYXMCMNJ rZwF1HfUx0g2GQW1ZOqh1eeyLO29JiOdV3hxlDO7X4bbISNgU6il5MXmnvf0/XVW Af3YhALeeDbHgHL1iVfjafzaviQc9+YrEX13eX6N2AjcgE5a3F7XNmGfFpFJ+mfQ CPgiwVBXat6UpBUGAt14UM+6wzp+crSgQR5IEGth+mKMKdkWoykvo7A2oHdu39zn 2cdzsshg2qcLLUPTFy06OOTXX382kCWXuykhHOjZ4uu2SJJ7R0W3PlYV8HSde2Vu Rj+89ZlUSICJNXXweQB39r87hNbtRuDIO22V0B9XrApQbJj6/yE= =rPaa -----END PGP SIGNATURE----- Merge tag 'pull-riscv-to-apply-20241031-1' of https://github.com/alistair23/qemu into staging RISC-V PR for 9.2 * Fix an access to VXSAT * Expose RV32 cpu to RV64 QEMU * Don't clear PLIC pending bits on IRQ lowering * Make PLIC zeroth priority register read-only * Set vtype.vill on CPU reset * Check and update APLIC pending when write sourcecfg * Avoid dropping charecters with HTIF * Apply FIFO backpressure to guests using SiFive UART * Support for control flow integrity extensions * Support for the IOMMU with the virt machine * set 'aia_mode' to default in error path * clarify how 'riscv-aia' default works # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEEaukCtqfKh31tZZKWr3yVEwxTgBMFAmci/tQACgkQr3yVEwxT # gBNPAQ//dZKjjJm4Sh+UFdUslivBJYtL1rl2UUG2UqiNn/UoYh/vcHoSArljHTjt # 8riEStnaQqXziOpMIJjIMLJ4KoiIk2SMvjNfFtcmPiPZEDEpjsTxfUxBFsBee+fI # 4KNQKKFeljq4pa+VzVvXEqzCNJIzCThFXTZhZmer00M91HPA8ZQIHpv2JL1sWlgZ # /HW24XEDFLGc/JsR55fxpPftlAqP+BfOrqMmbWy7x2Y+G8WI05hM2zTP/W8pnIz3 # z0GCRYSBlADtrp+3RqzTwQfK5pXoFc0iDktWVYlhoXaeEmOwo8IYxTjrvBGhnBq+ # ySX1DzTa23QmOIxSYYvCRuOxyOK9ziNn+EQ9FiFBt1h1o251CYMil1bwmYXMCMNJ # rZwF1HfUx0g2GQW1ZOqh1eeyLO29JiOdV3hxlDO7X4bbISNgU6il5MXmnvf0/XVW # Af3YhALeeDbHgHL1iVfjafzaviQc9+YrEX13eX6N2AjcgE5a3F7XNmGfFpFJ+mfQ # CPgiwVBXat6UpBUGAt14UM+6wzp+crSgQR5IEGth+mKMKdkWoykvo7A2oHdu39zn # 2cdzsshg2qcLLUPTFy06OOTXX382kCWXuykhHOjZ4uu2SJJ7R0W3PlYV8HSde2Vu # Rj+89ZlUSICJNXXweQB39r87hNbtRuDIO22V0B9XrApQbJj6/yE= # =rPaa # -----END PGP SIGNATURE----- # gpg: Signature made Thu 31 Oct 2024 03:51:48 GMT # gpg: using RSA key 6AE902B6A7CA877D6D659296AF7C95130C538013 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 6AE9 02B6 A7CA 877D 6D65 9296 AF7C 9513 0C53 8013 * tag 'pull-riscv-to-apply-20241031-1' of https://github.com/alistair23/qemu: (50 commits) target/riscv: Fix vcompress with rvv_ta_all_1s target/riscv/kvm: clarify how 'riscv-aia' default works target/riscv/kvm: set 'aia_mode' to default in error path docs/specs: add riscv-iommu qtest/riscv-iommu-test: add init queues test hw/riscv/riscv-iommu: add DBG support hw/riscv/riscv-iommu: add ATS support hw/riscv/riscv-iommu: add Address Translation Cache (IOATC) test/qtest: add riscv-iommu-pci tests hw/riscv/virt.c: support for RISC-V IOMMU PCIDevice hotplug hw/riscv: add riscv-iommu-pci reference device pci-ids.rst: add Red Hat pci-id for RISC-V IOMMU device hw/riscv: add RISC-V IOMMU base emulation hw/riscv: add riscv-iommu-bits.h exec/memtxattr: add process identifier to the transaction attributes target/riscv: Expose zicfiss extension as a cpu property disas/riscv: enable disassembly for compressed sspush/sspopchk disas/riscv: enable disassembly for zicfiss instructions target/riscv: compressed encodings for sspush and sspopchk target/riscv: implement zicfiss instructions ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
92ec780519
65 changed files with 4790 additions and 139 deletions
|
@ -217,7 +217,11 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
|
|||
tswap64(syscall[3]) == HTIF_CONSOLE_CMD_PUTC) {
|
||||
uint8_t ch;
|
||||
cpu_physical_memory_read(tswap64(syscall[2]), &ch, 1);
|
||||
qemu_chr_fe_write(&s->chr, &ch, 1);
|
||||
/*
|
||||
* XXX this blocks entire thread. Rewrite to use
|
||||
* qemu_chr_fe_write and background I/O callbacks
|
||||
*/
|
||||
qemu_chr_fe_write_all(&s->chr, &ch, 1);
|
||||
resp = 0x100 | (uint8_t)payload;
|
||||
} else {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
|
@ -236,7 +240,11 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
|
|||
return;
|
||||
} else if (cmd == HTIF_CONSOLE_CMD_PUTC) {
|
||||
uint8_t ch = (uint8_t)payload;
|
||||
qemu_chr_fe_write(&s->chr, &ch, 1);
|
||||
/*
|
||||
* XXX this blocks entire thread. Rewrite to use
|
||||
* qemu_chr_fe_write and background I/O callbacks
|
||||
*/
|
||||
qemu_chr_fe_write_all(&s->chr, &ch, 1);
|
||||
resp = 0x100 | (uint8_t)payload;
|
||||
} else {
|
||||
qemu_log("HTIF device %d: unknown command\n", device);
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "hw/char/sifive_uart.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
|
||||
#define TX_INTERRUPT_TRIGGER_DELAY_NS 100
|
||||
|
||||
/*
|
||||
* Not yet implemented:
|
||||
*
|
||||
|
@ -64,6 +66,72 @@ static void sifive_uart_update_irq(SiFiveUARTState *s)
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean sifive_uart_xmit(void *do_not_use, GIOCondition cond,
|
||||
void *opaque)
|
||||
{
|
||||
SiFiveUARTState *s = opaque;
|
||||
int ret;
|
||||
const uint8_t *characters;
|
||||
uint32_t numptr = 0;
|
||||
|
||||
/* instant drain the fifo when there's no back-end */
|
||||
if (!qemu_chr_fe_backend_connected(&s->chr)) {
|
||||
fifo8_reset(&s->tx_fifo);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
if (fifo8_is_empty(&s->tx_fifo)) {
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
/* Don't pop the FIFO in case the write fails */
|
||||
characters = fifo8_peek_bufptr(&s->tx_fifo,
|
||||
fifo8_num_used(&s->tx_fifo), &numptr);
|
||||
ret = qemu_chr_fe_write(&s->chr, characters, numptr);
|
||||
|
||||
if (ret >= 0) {
|
||||
/* We wrote the data, actually pop the fifo */
|
||||
fifo8_pop_bufptr(&s->tx_fifo, ret, NULL);
|
||||
}
|
||||
|
||||
if (!fifo8_is_empty(&s->tx_fifo)) {
|
||||
guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
|
||||
sifive_uart_xmit, s);
|
||||
if (!r) {
|
||||
fifo8_reset(&s->tx_fifo);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the TX Full bit */
|
||||
if (!fifo8_is_full(&s->tx_fifo)) {
|
||||
s->txfifo &= ~SIFIVE_UART_TXFIFO_FULL;
|
||||
}
|
||||
|
||||
sifive_uart_update_irq(s);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, const uint8_t *buf,
|
||||
int size)
|
||||
{
|
||||
uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
|
||||
if (size > fifo8_num_free(&s->tx_fifo)) {
|
||||
size = fifo8_num_free(&s->tx_fifo);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "sifive_uart: TX FIFO overflow");
|
||||
}
|
||||
|
||||
fifo8_push_all(&s->tx_fifo, buf, size);
|
||||
|
||||
if (fifo8_is_full(&s->tx_fifo)) {
|
||||
s->txfifo |= SIFIVE_UART_TXFIFO_FULL;
|
||||
}
|
||||
|
||||
timer_mod(s->fifo_trigger_handle, current_time +
|
||||
TX_INTERRUPT_TRIGGER_DELAY_NS);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
sifive_uart_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
|
@ -82,7 +150,7 @@ sifive_uart_read(void *opaque, hwaddr addr, unsigned int size)
|
|||
return 0x80000000;
|
||||
|
||||
case SIFIVE_UART_TXFIFO:
|
||||
return 0; /* Should check tx fifo */
|
||||
return s->txfifo;
|
||||
case SIFIVE_UART_IE:
|
||||
return s->ie;
|
||||
case SIFIVE_UART_IP:
|
||||
|
@ -106,12 +174,10 @@ sifive_uart_write(void *opaque, hwaddr addr,
|
|||
{
|
||||
SiFiveUARTState *s = opaque;
|
||||
uint32_t value = val64;
|
||||
unsigned char ch = value;
|
||||
|
||||
switch (addr) {
|
||||
case SIFIVE_UART_TXFIFO:
|
||||
qemu_chr_fe_write(&s->chr, &ch, 1);
|
||||
sifive_uart_update_irq(s);
|
||||
sifive_uart_write_tx_fifo(s, (uint8_t *) &value, 1);
|
||||
return;
|
||||
case SIFIVE_UART_IE:
|
||||
s->ie = val64;
|
||||
|
@ -131,6 +197,13 @@ sifive_uart_write(void *opaque, hwaddr addr,
|
|||
__func__, (int)addr, (int)value);
|
||||
}
|
||||
|
||||
static void fifo_trigger_update(void *opaque)
|
||||
{
|
||||
SiFiveUARTState *s = opaque;
|
||||
|
||||
sifive_uart_xmit(NULL, G_IO_OUT, s);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sifive_uart_ops = {
|
||||
.read = sifive_uart_read,
|
||||
.write = sifive_uart_write,
|
||||
|
@ -197,6 +270,9 @@ static void sifive_uart_realize(DeviceState *dev, Error **errp)
|
|||
{
|
||||
SiFiveUARTState *s = SIFIVE_UART(dev);
|
||||
|
||||
s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
fifo_trigger_update, s);
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr, sifive_uart_can_rx, sifive_uart_rx,
|
||||
sifive_uart_event, sifive_uart_be_change, s,
|
||||
NULL, true);
|
||||
|
@ -206,12 +282,18 @@ static void sifive_uart_realize(DeviceState *dev, Error **errp)
|
|||
static void sifive_uart_reset_enter(Object *obj, ResetType type)
|
||||
{
|
||||
SiFiveUARTState *s = SIFIVE_UART(obj);
|
||||
|
||||
s->txfifo = 0;
|
||||
s->ie = 0;
|
||||
s->ip = 0;
|
||||
s->txctrl = 0;
|
||||
s->rxctrl = 0;
|
||||
s->div = 0;
|
||||
|
||||
s->rx_fifo_len = 0;
|
||||
|
||||
memset(s->rx_fifo, 0, SIFIVE_UART_RX_FIFO_SIZE);
|
||||
fifo8_create(&s->tx_fifo, SIFIVE_UART_TX_FIFO_SIZE);
|
||||
}
|
||||
|
||||
static void sifive_uart_reset_hold(Object *obj, ResetType type)
|
||||
|
@ -222,8 +304,8 @@ static void sifive_uart_reset_hold(Object *obj, ResetType type)
|
|||
|
||||
static const VMStateDescription vmstate_sifive_uart = {
|
||||
.name = TYPE_SIFIVE_UART,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT8_ARRAY(rx_fifo, SiFiveUARTState,
|
||||
SIFIVE_UART_RX_FIFO_SIZE),
|
||||
|
@ -233,6 +315,9 @@ static const VMStateDescription vmstate_sifive_uart = {
|
|||
VMSTATE_UINT32(txctrl, SiFiveUARTState),
|
||||
VMSTATE_UINT32(rxctrl, SiFiveUARTState),
|
||||
VMSTATE_UINT32(div, SiFiveUARTState),
|
||||
VMSTATE_UINT32(txfifo, SiFiveUARTState),
|
||||
VMSTATE_FIFO8(tx_fifo, SiFiveUARTState),
|
||||
VMSTATE_TIMER_PTR(fifo_trigger_handle, SiFiveUARTState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
|
|
@ -159,31 +159,42 @@ static bool is_kvm_aia(bool msimode)
|
|||
return kvm_irqchip_in_kernel() && msimode;
|
||||
}
|
||||
|
||||
static bool riscv_aplic_irq_rectified_val(RISCVAPLICState *aplic,
|
||||
uint32_t irq)
|
||||
{
|
||||
uint32_t sourcecfg, sm, raw_input, irq_inverted;
|
||||
|
||||
if (!irq || aplic->num_irqs <= irq) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sourcecfg = aplic->sourcecfg[irq];
|
||||
if (sourcecfg & APLIC_SOURCECFG_D) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sm = sourcecfg & APLIC_SOURCECFG_SM_MASK;
|
||||
if (sm == APLIC_SOURCECFG_SM_INACTIVE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
raw_input = (aplic->state[irq] & APLIC_ISTATE_INPUT) ? 1 : 0;
|
||||
irq_inverted = (sm == APLIC_SOURCECFG_SM_LEVEL_LOW ||
|
||||
sm == APLIC_SOURCECFG_SM_EDGE_FALL) ? 1 : 0;
|
||||
|
||||
return !!(raw_input ^ irq_inverted);
|
||||
}
|
||||
|
||||
static uint32_t riscv_aplic_read_input_word(RISCVAPLICState *aplic,
|
||||
uint32_t word)
|
||||
{
|
||||
uint32_t i, irq, sourcecfg, sm, raw_input, irq_inverted, ret = 0;
|
||||
uint32_t i, irq, rectified_val, ret = 0;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
irq = word * 32 + i;
|
||||
if (!irq || aplic->num_irqs <= irq) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sourcecfg = aplic->sourcecfg[irq];
|
||||
if (sourcecfg & APLIC_SOURCECFG_D) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sm = sourcecfg & APLIC_SOURCECFG_SM_MASK;
|
||||
if (sm == APLIC_SOURCECFG_SM_INACTIVE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
raw_input = (aplic->state[irq] & APLIC_ISTATE_INPUT) ? 1 : 0;
|
||||
irq_inverted = (sm == APLIC_SOURCECFG_SM_LEVEL_LOW ||
|
||||
sm == APLIC_SOURCECFG_SM_EDGE_FALL) ? 1 : 0;
|
||||
ret |= (raw_input ^ irq_inverted) << i;
|
||||
rectified_val = riscv_aplic_irq_rectified_val(aplic, irq);
|
||||
ret |= rectified_val << i;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -702,6 +713,10 @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value,
|
|||
(aplic->sourcecfg[irq] == 0)) {
|
||||
riscv_aplic_set_pending_raw(aplic, irq, false);
|
||||
riscv_aplic_set_enabled_raw(aplic, irq, false);
|
||||
} else {
|
||||
if (riscv_aplic_irq_rectified_val(aplic, irq)) {
|
||||
riscv_aplic_set_pending_raw(aplic, irq, true);
|
||||
}
|
||||
}
|
||||
} else if (aplic->mmode && aplic->msimode &&
|
||||
(addr == APLIC_MMSICFGADDR)) {
|
||||
|
|
|
@ -189,8 +189,13 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value,
|
|||
|
||||
if (addr_between(addr, plic->priority_base, plic->num_sources << 2)) {
|
||||
uint32_t irq = (addr - plic->priority_base) >> 2;
|
||||
|
||||
if (((plic->num_priorities + 1) & plic->num_priorities) == 0) {
|
||||
if (irq == 0) {
|
||||
/* IRQ 0 source prioority is reserved */
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Invalid source priority write 0x%"
|
||||
HWADDR_PRIx "\n", __func__, addr);
|
||||
return;
|
||||
} else if (((plic->num_priorities + 1) & plic->num_priorities) == 0) {
|
||||
/*
|
||||
* if "num_priorities + 1" is power-of-2, make each register bit of
|
||||
* interrupt priority WARL (Write-Any-Read-Legal). Just filter
|
||||
|
@ -349,8 +354,10 @@ static void sifive_plic_irq_request(void *opaque, int irq, int level)
|
|||
{
|
||||
SiFivePLICState *s = opaque;
|
||||
|
||||
sifive_plic_set_pending(s, irq, level > 0);
|
||||
sifive_plic_update(s);
|
||||
if (level > 0) {
|
||||
sifive_plic_set_pending(s, irq, true);
|
||||
sifive_plic_update(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void sifive_plic_realize(DeviceState *dev, Error **errp)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
config RISCV_IOMMU
|
||||
bool
|
||||
|
||||
config RISCV_NUMA
|
||||
bool
|
||||
|
||||
|
@ -47,6 +50,7 @@ config RISCV_VIRT
|
|||
select SERIAL_MM
|
||||
select RISCV_ACLINT
|
||||
select RISCV_APLIC
|
||||
select RISCV_IOMMU
|
||||
select RISCV_IMSIC
|
||||
select SIFIVE_PLIC
|
||||
select SIFIVE_TEST
|
||||
|
|
|
@ -343,27 +343,33 @@ void riscv_load_fdt(hwaddr fdt_addr, void *fdt)
|
|||
rom_ptr_for_as(&address_space_memory, fdt_addr, fdtsize));
|
||||
}
|
||||
|
||||
void riscv_rom_copy_firmware_info(MachineState *machine, hwaddr rom_base,
|
||||
hwaddr rom_size, uint32_t reset_vec_size,
|
||||
void riscv_rom_copy_firmware_info(MachineState *machine,
|
||||
RISCVHartArrayState *harts,
|
||||
hwaddr rom_base, hwaddr rom_size,
|
||||
uint32_t reset_vec_size,
|
||||
uint64_t kernel_entry)
|
||||
{
|
||||
struct fw_dynamic_info32 dinfo32;
|
||||
struct fw_dynamic_info dinfo;
|
||||
size_t dinfo_len;
|
||||
|
||||
if (sizeof(dinfo.magic) == 4) {
|
||||
dinfo.magic = cpu_to_le32(FW_DYNAMIC_INFO_MAGIC_VALUE);
|
||||
dinfo.version = cpu_to_le32(FW_DYNAMIC_INFO_VERSION);
|
||||
dinfo.next_mode = cpu_to_le32(FW_DYNAMIC_INFO_NEXT_MODE_S);
|
||||
dinfo.next_addr = cpu_to_le32(kernel_entry);
|
||||
if (riscv_is_32bit(harts)) {
|
||||
dinfo32.magic = cpu_to_le32(FW_DYNAMIC_INFO_MAGIC_VALUE);
|
||||
dinfo32.version = cpu_to_le32(FW_DYNAMIC_INFO_VERSION);
|
||||
dinfo32.next_mode = cpu_to_le32(FW_DYNAMIC_INFO_NEXT_MODE_S);
|
||||
dinfo32.next_addr = cpu_to_le32(kernel_entry);
|
||||
dinfo32.options = 0;
|
||||
dinfo32.boot_hart = 0;
|
||||
dinfo_len = sizeof(dinfo32);
|
||||
} else {
|
||||
dinfo.magic = cpu_to_le64(FW_DYNAMIC_INFO_MAGIC_VALUE);
|
||||
dinfo.version = cpu_to_le64(FW_DYNAMIC_INFO_VERSION);
|
||||
dinfo.next_mode = cpu_to_le64(FW_DYNAMIC_INFO_NEXT_MODE_S);
|
||||
dinfo.next_addr = cpu_to_le64(kernel_entry);
|
||||
dinfo.options = 0;
|
||||
dinfo.boot_hart = 0;
|
||||
dinfo_len = sizeof(dinfo);
|
||||
}
|
||||
dinfo.options = 0;
|
||||
dinfo.boot_hart = 0;
|
||||
dinfo_len = sizeof(dinfo);
|
||||
|
||||
/**
|
||||
* copy the dynamic firmware info. This information is specific to
|
||||
|
@ -375,7 +381,10 @@ void riscv_rom_copy_firmware_info(MachineState *machine, hwaddr rom_base,
|
|||
exit(1);
|
||||
}
|
||||
|
||||
rom_add_blob_fixed_as("mrom.finfo", &dinfo, dinfo_len,
|
||||
rom_add_blob_fixed_as("mrom.finfo",
|
||||
riscv_is_32bit(harts) ?
|
||||
(void *)&dinfo32 : (void *)&dinfo,
|
||||
dinfo_len,
|
||||
rom_base + reset_vec_size,
|
||||
&address_space_memory);
|
||||
}
|
||||
|
@ -431,7 +440,9 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts
|
|||
}
|
||||
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
|
||||
rom_base, &address_space_memory);
|
||||
riscv_rom_copy_firmware_info(machine, rom_base, rom_size, sizeof(reset_vec),
|
||||
riscv_rom_copy_firmware_info(machine, harts,
|
||||
rom_base, rom_size,
|
||||
sizeof(reset_vec),
|
||||
kernel_entry);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,5 +10,6 @@ riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c'))
|
|||
riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c'))
|
||||
riscv_ss.add(when: 'CONFIG_MICROCHIP_PFSOC', if_true: files('microchip_pfsoc.c'))
|
||||
riscv_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c'))
|
||||
riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files('riscv-iommu.c', 'riscv-iommu-pci.c'))
|
||||
|
||||
hw_arch += {'riscv': riscv_ss}
|
||||
|
|
421
hw/riscv/riscv-iommu-bits.h
Normal file
421
hw/riscv/riscv-iommu-bits.h
Normal file
|
@ -0,0 +1,421 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright © 2022-2023 Rivos Inc.
|
||||
* Copyright © 2023 FORTH-ICS/CARV
|
||||
* Copyright © 2023 RISC-V IOMMU Task Group
|
||||
*
|
||||
* RISC-V IOMMU - Register Layout and Data Structures.
|
||||
*
|
||||
* Based on the IOMMU spec version 1.0, 3/2023
|
||||
* https://github.com/riscv-non-isa/riscv-iommu
|
||||
*/
|
||||
|
||||
#ifndef HW_RISCV_IOMMU_BITS_H
|
||||
#define HW_RISCV_IOMMU_BITS_H
|
||||
|
||||
#define RISCV_IOMMU_SPEC_DOT_VER 0x010
|
||||
|
||||
#ifndef GENMASK_ULL
|
||||
#define GENMASK_ULL(h, l) (((~0ULL) >> (63 - (h) + (l))) << (l))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* struct riscv_iommu_fq_record - Fault/Event Queue Record
|
||||
* See section 3.2 for more info.
|
||||
*/
|
||||
struct riscv_iommu_fq_record {
|
||||
uint64_t hdr;
|
||||
uint64_t _reserved;
|
||||
uint64_t iotval;
|
||||
uint64_t iotval2;
|
||||
};
|
||||
/* Header fields */
|
||||
#define RISCV_IOMMU_FQ_HDR_CAUSE GENMASK_ULL(11, 0)
|
||||
#define RISCV_IOMMU_FQ_HDR_PID GENMASK_ULL(31, 12)
|
||||
#define RISCV_IOMMU_FQ_HDR_PV BIT_ULL(32)
|
||||
#define RISCV_IOMMU_FQ_HDR_TTYPE GENMASK_ULL(39, 34)
|
||||
#define RISCV_IOMMU_FQ_HDR_DID GENMASK_ULL(63, 40)
|
||||
|
||||
/*
|
||||
* struct riscv_iommu_pq_record - PCIe Page Request record
|
||||
* For more infos on the PCIe Page Request queue see chapter 3.3.
|
||||
*/
|
||||
struct riscv_iommu_pq_record {
|
||||
uint64_t hdr;
|
||||
uint64_t payload;
|
||||
};
|
||||
/* Header fields */
|
||||
#define RISCV_IOMMU_PREQ_HDR_PID GENMASK_ULL(31, 12)
|
||||
#define RISCV_IOMMU_PREQ_HDR_PV BIT_ULL(32)
|
||||
#define RISCV_IOMMU_PREQ_HDR_PRIV BIT_ULL(33)
|
||||
#define RISCV_IOMMU_PREQ_HDR_EXEC BIT_ULL(34)
|
||||
#define RISCV_IOMMU_PREQ_HDR_DID GENMASK_ULL(63, 40)
|
||||
/* Payload fields */
|
||||
#define RISCV_IOMMU_PREQ_PAYLOAD_M GENMASK_ULL(2, 0)
|
||||
|
||||
/* Common field positions */
|
||||
#define RISCV_IOMMU_PPN_FIELD GENMASK_ULL(53, 10)
|
||||
#define RISCV_IOMMU_QUEUE_LOGSZ_FIELD GENMASK_ULL(4, 0)
|
||||
#define RISCV_IOMMU_QUEUE_INDEX_FIELD GENMASK_ULL(31, 0)
|
||||
#define RISCV_IOMMU_QUEUE_ENABLE BIT(0)
|
||||
#define RISCV_IOMMU_QUEUE_INTR_ENABLE BIT(1)
|
||||
#define RISCV_IOMMU_QUEUE_MEM_FAULT BIT(8)
|
||||
#define RISCV_IOMMU_QUEUE_OVERFLOW BIT(9)
|
||||
#define RISCV_IOMMU_QUEUE_ACTIVE BIT(16)
|
||||
#define RISCV_IOMMU_QUEUE_BUSY BIT(17)
|
||||
#define RISCV_IOMMU_ATP_PPN_FIELD GENMASK_ULL(43, 0)
|
||||
#define RISCV_IOMMU_ATP_MODE_FIELD GENMASK_ULL(63, 60)
|
||||
|
||||
/* 5.3 IOMMU Capabilities (64bits) */
|
||||
#define RISCV_IOMMU_REG_CAP 0x0000
|
||||
#define RISCV_IOMMU_CAP_VERSION GENMASK_ULL(7, 0)
|
||||
#define RISCV_IOMMU_CAP_SV32 BIT_ULL(8)
|
||||
#define RISCV_IOMMU_CAP_SV39 BIT_ULL(9)
|
||||
#define RISCV_IOMMU_CAP_SV48 BIT_ULL(10)
|
||||
#define RISCV_IOMMU_CAP_SV57 BIT_ULL(11)
|
||||
#define RISCV_IOMMU_CAP_SV32X4 BIT_ULL(16)
|
||||
#define RISCV_IOMMU_CAP_SV39X4 BIT_ULL(17)
|
||||
#define RISCV_IOMMU_CAP_SV48X4 BIT_ULL(18)
|
||||
#define RISCV_IOMMU_CAP_SV57X4 BIT_ULL(19)
|
||||
#define RISCV_IOMMU_CAP_MSI_FLAT BIT_ULL(22)
|
||||
#define RISCV_IOMMU_CAP_MSI_MRIF BIT_ULL(23)
|
||||
#define RISCV_IOMMU_CAP_ATS BIT_ULL(25)
|
||||
#define RISCV_IOMMU_CAP_T2GPA BIT_ULL(26)
|
||||
#define RISCV_IOMMU_CAP_IGS GENMASK_ULL(29, 28)
|
||||
#define RISCV_IOMMU_CAP_DBG BIT_ULL(31)
|
||||
#define RISCV_IOMMU_CAP_PAS GENMASK_ULL(37, 32)
|
||||
#define RISCV_IOMMU_CAP_PD8 BIT_ULL(38)
|
||||
#define RISCV_IOMMU_CAP_PD17 BIT_ULL(39)
|
||||
#define RISCV_IOMMU_CAP_PD20 BIT_ULL(40)
|
||||
|
||||
/* 5.4 Features control register (32bits) */
|
||||
#define RISCV_IOMMU_REG_FCTL 0x0008
|
||||
#define RISCV_IOMMU_FCTL_BE BIT(0)
|
||||
#define RISCV_IOMMU_FCTL_WSI BIT(1)
|
||||
#define RISCV_IOMMU_FCTL_GXL BIT(2)
|
||||
|
||||
/* 5.5 Device-directory-table pointer (64bits) */
|
||||
#define RISCV_IOMMU_REG_DDTP 0x0010
|
||||
#define RISCV_IOMMU_DDTP_MODE GENMASK_ULL(3, 0)
|
||||
#define RISCV_IOMMU_DDTP_BUSY BIT_ULL(4)
|
||||
#define RISCV_IOMMU_DDTP_PPN RISCV_IOMMU_PPN_FIELD
|
||||
|
||||
enum riscv_iommu_ddtp_modes {
|
||||
RISCV_IOMMU_DDTP_MODE_OFF = 0,
|
||||
RISCV_IOMMU_DDTP_MODE_BARE = 1,
|
||||
RISCV_IOMMU_DDTP_MODE_1LVL = 2,
|
||||
RISCV_IOMMU_DDTP_MODE_2LVL = 3,
|
||||
RISCV_IOMMU_DDTP_MODE_3LVL = 4,
|
||||
RISCV_IOMMU_DDTP_MODE_MAX = 4
|
||||
};
|
||||
|
||||
/* 5.6 Command Queue Base (64bits) */
|
||||
#define RISCV_IOMMU_REG_CQB 0x0018
|
||||
#define RISCV_IOMMU_CQB_LOG2SZ RISCV_IOMMU_QUEUE_LOGSZ_FIELD
|
||||
#define RISCV_IOMMU_CQB_PPN RISCV_IOMMU_PPN_FIELD
|
||||
|
||||
/* 5.7 Command Queue head (32bits) */
|
||||
#define RISCV_IOMMU_REG_CQH 0x0020
|
||||
|
||||
/* 5.8 Command Queue tail (32bits) */
|
||||
#define RISCV_IOMMU_REG_CQT 0x0024
|
||||
|
||||
/* 5.9 Fault Queue Base (64bits) */
|
||||
#define RISCV_IOMMU_REG_FQB 0x0028
|
||||
#define RISCV_IOMMU_FQB_LOG2SZ RISCV_IOMMU_QUEUE_LOGSZ_FIELD
|
||||
#define RISCV_IOMMU_FQB_PPN RISCV_IOMMU_PPN_FIELD
|
||||
|
||||
/* 5.10 Fault Queue Head (32bits) */
|
||||
#define RISCV_IOMMU_REG_FQH 0x0030
|
||||
|
||||
/* 5.11 Fault Queue tail (32bits) */
|
||||
#define RISCV_IOMMU_REG_FQT 0x0034
|
||||
|
||||
/* 5.12 Page Request Queue base (64bits) */
|
||||
#define RISCV_IOMMU_REG_PQB 0x0038
|
||||
#define RISCV_IOMMU_PQB_LOG2SZ RISCV_IOMMU_QUEUE_LOGSZ_FIELD
|
||||
#define RISCV_IOMMU_PQB_PPN RISCV_IOMMU_PPN_FIELD
|
||||
|
||||
/* 5.13 Page Request Queue head (32bits) */
|
||||
#define RISCV_IOMMU_REG_PQH 0x0040
|
||||
|
||||
/* 5.14 Page Request Queue tail (32bits) */
|
||||
#define RISCV_IOMMU_REG_PQT 0x0044
|
||||
|
||||
/* 5.15 Command Queue CSR (32bits) */
|
||||
#define RISCV_IOMMU_REG_CQCSR 0x0048
|
||||
#define RISCV_IOMMU_CQCSR_CQEN RISCV_IOMMU_QUEUE_ENABLE
|
||||
#define RISCV_IOMMU_CQCSR_CIE RISCV_IOMMU_QUEUE_INTR_ENABLE
|
||||
#define RISCV_IOMMU_CQCSR_CQMF RISCV_IOMMU_QUEUE_MEM_FAULT
|
||||
#define RISCV_IOMMU_CQCSR_CMD_TO BIT(9)
|
||||
#define RISCV_IOMMU_CQCSR_CMD_ILL BIT(10)
|
||||
#define RISCV_IOMMU_CQCSR_FENCE_W_IP BIT(11)
|
||||
#define RISCV_IOMMU_CQCSR_CQON RISCV_IOMMU_QUEUE_ACTIVE
|
||||
#define RISCV_IOMMU_CQCSR_BUSY RISCV_IOMMU_QUEUE_BUSY
|
||||
|
||||
/* 5.16 Fault Queue CSR (32bits) */
|
||||
#define RISCV_IOMMU_REG_FQCSR 0x004C
|
||||
#define RISCV_IOMMU_FQCSR_FQEN RISCV_IOMMU_QUEUE_ENABLE
|
||||
#define RISCV_IOMMU_FQCSR_FIE RISCV_IOMMU_QUEUE_INTR_ENABLE
|
||||
#define RISCV_IOMMU_FQCSR_FQMF RISCV_IOMMU_QUEUE_MEM_FAULT
|
||||
#define RISCV_IOMMU_FQCSR_FQOF RISCV_IOMMU_QUEUE_OVERFLOW
|
||||
#define RISCV_IOMMU_FQCSR_FQON RISCV_IOMMU_QUEUE_ACTIVE
|
||||
#define RISCV_IOMMU_FQCSR_BUSY RISCV_IOMMU_QUEUE_BUSY
|
||||
|
||||
/* 5.17 Page Request Queue CSR (32bits) */
|
||||
#define RISCV_IOMMU_REG_PQCSR 0x0050
|
||||
#define RISCV_IOMMU_PQCSR_PQEN RISCV_IOMMU_QUEUE_ENABLE
|
||||
#define RISCV_IOMMU_PQCSR_PIE RISCV_IOMMU_QUEUE_INTR_ENABLE
|
||||
#define RISCV_IOMMU_PQCSR_PQMF RISCV_IOMMU_QUEUE_MEM_FAULT
|
||||
#define RISCV_IOMMU_PQCSR_PQOF RISCV_IOMMU_QUEUE_OVERFLOW
|
||||
#define RISCV_IOMMU_PQCSR_PQON RISCV_IOMMU_QUEUE_ACTIVE
|
||||
#define RISCV_IOMMU_PQCSR_BUSY RISCV_IOMMU_QUEUE_BUSY
|
||||
|
||||
/* 5.18 Interrupt Pending Status (32bits) */
|
||||
#define RISCV_IOMMU_REG_IPSR 0x0054
|
||||
#define RISCV_IOMMU_IPSR_CIP BIT(0)
|
||||
#define RISCV_IOMMU_IPSR_FIP BIT(1)
|
||||
#define RISCV_IOMMU_IPSR_PIP BIT(3)
|
||||
|
||||
enum {
|
||||
RISCV_IOMMU_INTR_CQ,
|
||||
RISCV_IOMMU_INTR_FQ,
|
||||
RISCV_IOMMU_INTR_PM,
|
||||
RISCV_IOMMU_INTR_PQ,
|
||||
RISCV_IOMMU_INTR_COUNT
|
||||
};
|
||||
|
||||
/* 5.24 Translation request IOVA (64bits) */
|
||||
#define RISCV_IOMMU_REG_TR_REQ_IOVA 0x0258
|
||||
|
||||
/* 5.25 Translation request control (64bits) */
|
||||
#define RISCV_IOMMU_REG_TR_REQ_CTL 0x0260
|
||||
#define RISCV_IOMMU_TR_REQ_CTL_GO_BUSY BIT_ULL(0)
|
||||
#define RISCV_IOMMU_TR_REQ_CTL_NW BIT_ULL(3)
|
||||
#define RISCV_IOMMU_TR_REQ_CTL_PID GENMASK_ULL(31, 12)
|
||||
#define RISCV_IOMMU_TR_REQ_CTL_DID GENMASK_ULL(63, 40)
|
||||
|
||||
/* 5.26 Translation request response (64bits) */
|
||||
#define RISCV_IOMMU_REG_TR_RESPONSE 0x0268
|
||||
#define RISCV_IOMMU_TR_RESPONSE_FAULT BIT_ULL(0)
|
||||
#define RISCV_IOMMU_TR_RESPONSE_S BIT_ULL(9)
|
||||
#define RISCV_IOMMU_TR_RESPONSE_PPN RISCV_IOMMU_PPN_FIELD
|
||||
|
||||
/* 5.27 Interrupt cause to vector (64bits) */
|
||||
#define RISCV_IOMMU_REG_ICVEC 0x02F8
|
||||
#define RISCV_IOMMU_ICVEC_CIV GENMASK_ULL(3, 0)
|
||||
#define RISCV_IOMMU_ICVEC_FIV GENMASK_ULL(7, 4)
|
||||
#define RISCV_IOMMU_ICVEC_PMIV GENMASK_ULL(11, 8)
|
||||
#define RISCV_IOMMU_ICVEC_PIV GENMASK_ULL(15, 12)
|
||||
|
||||
/* 5.28 MSI Configuration table (32 * 64bits) */
|
||||
#define RISCV_IOMMU_REG_MSI_CONFIG 0x0300
|
||||
|
||||
#define RISCV_IOMMU_REG_SIZE 0x1000
|
||||
|
||||
#define RISCV_IOMMU_DDTE_VALID BIT_ULL(0)
|
||||
#define RISCV_IOMMU_DDTE_PPN RISCV_IOMMU_PPN_FIELD
|
||||
|
||||
/* Struct riscv_iommu_dc - Device Context - section 2.1 */
|
||||
struct riscv_iommu_dc {
|
||||
uint64_t tc;
|
||||
uint64_t iohgatp;
|
||||
uint64_t ta;
|
||||
uint64_t fsc;
|
||||
uint64_t msiptp;
|
||||
uint64_t msi_addr_mask;
|
||||
uint64_t msi_addr_pattern;
|
||||
uint64_t _reserved;
|
||||
};
|
||||
|
||||
/* Translation control fields */
|
||||
#define RISCV_IOMMU_DC_TC_V BIT_ULL(0)
|
||||
#define RISCV_IOMMU_DC_TC_EN_ATS BIT_ULL(1)
|
||||
#define RISCV_IOMMU_DC_TC_EN_PRI BIT_ULL(2)
|
||||
#define RISCV_IOMMU_DC_TC_T2GPA BIT_ULL(3)
|
||||
#define RISCV_IOMMU_DC_TC_DTF BIT_ULL(4)
|
||||
#define RISCV_IOMMU_DC_TC_PDTV BIT_ULL(5)
|
||||
#define RISCV_IOMMU_DC_TC_PRPR BIT_ULL(6)
|
||||
#define RISCV_IOMMU_DC_TC_GADE BIT_ULL(7)
|
||||
#define RISCV_IOMMU_DC_TC_SADE BIT_ULL(8)
|
||||
#define RISCV_IOMMU_DC_TC_DPE BIT_ULL(9)
|
||||
#define RISCV_IOMMU_DC_TC_SBE BIT_ULL(10)
|
||||
#define RISCV_IOMMU_DC_TC_SXL BIT_ULL(11)
|
||||
|
||||
/* Second-stage (aka G-stage) context fields */
|
||||
#define RISCV_IOMMU_DC_IOHGATP_PPN RISCV_IOMMU_ATP_PPN_FIELD
|
||||
#define RISCV_IOMMU_DC_IOHGATP_GSCID GENMASK_ULL(59, 44)
|
||||
#define RISCV_IOMMU_DC_IOHGATP_MODE RISCV_IOMMU_ATP_MODE_FIELD
|
||||
|
||||
enum riscv_iommu_dc_iohgatp_modes {
|
||||
RISCV_IOMMU_DC_IOHGATP_MODE_BARE = 0,
|
||||
RISCV_IOMMU_DC_IOHGATP_MODE_SV32X4 = 8,
|
||||
RISCV_IOMMU_DC_IOHGATP_MODE_SV39X4 = 8,
|
||||
RISCV_IOMMU_DC_IOHGATP_MODE_SV48X4 = 9,
|
||||
RISCV_IOMMU_DC_IOHGATP_MODE_SV57X4 = 10
|
||||
};
|
||||
|
||||
/* Translation attributes fields */
|
||||
#define RISCV_IOMMU_DC_TA_PSCID GENMASK_ULL(31, 12)
|
||||
|
||||
/* First-stage context fields */
|
||||
#define RISCV_IOMMU_DC_FSC_PPN RISCV_IOMMU_ATP_PPN_FIELD
|
||||
#define RISCV_IOMMU_DC_FSC_MODE RISCV_IOMMU_ATP_MODE_FIELD
|
||||
|
||||
/* Generic I/O MMU command structure - check section 3.1 */
|
||||
struct riscv_iommu_command {
|
||||
uint64_t dword0;
|
||||
uint64_t dword1;
|
||||
};
|
||||
|
||||
#define RISCV_IOMMU_CMD_OPCODE GENMASK_ULL(6, 0)
|
||||
#define RISCV_IOMMU_CMD_FUNC GENMASK_ULL(9, 7)
|
||||
|
||||
#define RISCV_IOMMU_CMD_IOTINVAL_OPCODE 1
|
||||
#define RISCV_IOMMU_CMD_IOTINVAL_FUNC_VMA 0
|
||||
#define RISCV_IOMMU_CMD_IOTINVAL_FUNC_GVMA 1
|
||||
#define RISCV_IOMMU_CMD_IOTINVAL_AV BIT_ULL(10)
|
||||
#define RISCV_IOMMU_CMD_IOTINVAL_PSCID GENMASK_ULL(31, 12)
|
||||
#define RISCV_IOMMU_CMD_IOTINVAL_PSCV BIT_ULL(32)
|
||||
#define RISCV_IOMMU_CMD_IOTINVAL_GV BIT_ULL(33)
|
||||
#define RISCV_IOMMU_CMD_IOTINVAL_GSCID GENMASK_ULL(59, 44)
|
||||
|
||||
#define RISCV_IOMMU_CMD_IOFENCE_OPCODE 2
|
||||
#define RISCV_IOMMU_CMD_IOFENCE_FUNC_C 0
|
||||
#define RISCV_IOMMU_CMD_IOFENCE_AV BIT_ULL(10)
|
||||
#define RISCV_IOMMU_CMD_IOFENCE_DATA GENMASK_ULL(63, 32)
|
||||
|
||||
#define RISCV_IOMMU_CMD_IODIR_OPCODE 3
|
||||
#define RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_DDT 0
|
||||
#define RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_PDT 1
|
||||
#define RISCV_IOMMU_CMD_IODIR_PID GENMASK_ULL(31, 12)
|
||||
#define RISCV_IOMMU_CMD_IODIR_DV BIT_ULL(33)
|
||||
#define RISCV_IOMMU_CMD_IODIR_DID GENMASK_ULL(63, 40)
|
||||
|
||||
/* 3.1.4 I/O MMU PCIe ATS */
|
||||
#define RISCV_IOMMU_CMD_ATS_OPCODE 4
|
||||
#define RISCV_IOMMU_CMD_ATS_FUNC_INVAL 0
|
||||
#define RISCV_IOMMU_CMD_ATS_FUNC_PRGR 1
|
||||
#define RISCV_IOMMU_CMD_ATS_PID GENMASK_ULL(31, 12)
|
||||
#define RISCV_IOMMU_CMD_ATS_PV BIT_ULL(32)
|
||||
#define RISCV_IOMMU_CMD_ATS_DSV BIT_ULL(33)
|
||||
#define RISCV_IOMMU_CMD_ATS_RID GENMASK_ULL(55, 40)
|
||||
#define RISCV_IOMMU_CMD_ATS_DSEG GENMASK_ULL(63, 56)
|
||||
/* dword1 is the ATS payload, two different payload types for INVAL and PRGR */
|
||||
|
||||
/* ATS.PRGR payload */
|
||||
#define RISCV_IOMMU_CMD_ATS_PRGR_RESP_CODE GENMASK_ULL(47, 44)
|
||||
|
||||
enum riscv_iommu_dc_fsc_atp_modes {
|
||||
RISCV_IOMMU_DC_FSC_MODE_BARE = 0,
|
||||
RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV32 = 8,
|
||||
RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39 = 8,
|
||||
RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV48 = 9,
|
||||
RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57 = 10,
|
||||
RISCV_IOMMU_DC_FSC_PDTP_MODE_PD8 = 1,
|
||||
RISCV_IOMMU_DC_FSC_PDTP_MODE_PD17 = 2,
|
||||
RISCV_IOMMU_DC_FSC_PDTP_MODE_PD20 = 3
|
||||
};
|
||||
|
||||
enum riscv_iommu_fq_causes {
|
||||
RISCV_IOMMU_FQ_CAUSE_INST_FAULT = 1,
|
||||
RISCV_IOMMU_FQ_CAUSE_RD_ADDR_MISALIGNED = 4,
|
||||
RISCV_IOMMU_FQ_CAUSE_RD_FAULT = 5,
|
||||
RISCV_IOMMU_FQ_CAUSE_WR_ADDR_MISALIGNED = 6,
|
||||
RISCV_IOMMU_FQ_CAUSE_WR_FAULT = 7,
|
||||
RISCV_IOMMU_FQ_CAUSE_INST_FAULT_S = 12,
|
||||
RISCV_IOMMU_FQ_CAUSE_RD_FAULT_S = 13,
|
||||
RISCV_IOMMU_FQ_CAUSE_WR_FAULT_S = 15,
|
||||
RISCV_IOMMU_FQ_CAUSE_INST_FAULT_VS = 20,
|
||||
RISCV_IOMMU_FQ_CAUSE_RD_FAULT_VS = 21,
|
||||
RISCV_IOMMU_FQ_CAUSE_WR_FAULT_VS = 23,
|
||||
RISCV_IOMMU_FQ_CAUSE_DMA_DISABLED = 256,
|
||||
RISCV_IOMMU_FQ_CAUSE_DDT_LOAD_FAULT = 257,
|
||||
RISCV_IOMMU_FQ_CAUSE_DDT_INVALID = 258,
|
||||
RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED = 259,
|
||||
RISCV_IOMMU_FQ_CAUSE_TTYPE_BLOCKED = 260,
|
||||
RISCV_IOMMU_FQ_CAUSE_MSI_LOAD_FAULT = 261,
|
||||
RISCV_IOMMU_FQ_CAUSE_MSI_INVALID = 262,
|
||||
RISCV_IOMMU_FQ_CAUSE_MSI_MISCONFIGURED = 263,
|
||||
RISCV_IOMMU_FQ_CAUSE_MRIF_FAULT = 264,
|
||||
RISCV_IOMMU_FQ_CAUSE_PDT_LOAD_FAULT = 265,
|
||||
RISCV_IOMMU_FQ_CAUSE_PDT_INVALID = 266,
|
||||
RISCV_IOMMU_FQ_CAUSE_PDT_MISCONFIGURED = 267,
|
||||
RISCV_IOMMU_FQ_CAUSE_DDT_CORRUPTED = 268,
|
||||
RISCV_IOMMU_FQ_CAUSE_PDT_CORRUPTED = 269,
|
||||
RISCV_IOMMU_FQ_CAUSE_MSI_PT_CORRUPTED = 270,
|
||||
RISCV_IOMMU_FQ_CAUSE_MRIF_CORRUIPTED = 271,
|
||||
RISCV_IOMMU_FQ_CAUSE_INTERNAL_DP_ERROR = 272,
|
||||
RISCV_IOMMU_FQ_CAUSE_MSI_WR_FAULT = 273,
|
||||
RISCV_IOMMU_FQ_CAUSE_PT_CORRUPTED = 274
|
||||
};
|
||||
|
||||
/* MSI page table pointer */
|
||||
#define RISCV_IOMMU_DC_MSIPTP_PPN RISCV_IOMMU_ATP_PPN_FIELD
|
||||
#define RISCV_IOMMU_DC_MSIPTP_MODE RISCV_IOMMU_ATP_MODE_FIELD
|
||||
#define RISCV_IOMMU_DC_MSIPTP_MODE_OFF 0
|
||||
#define RISCV_IOMMU_DC_MSIPTP_MODE_FLAT 1
|
||||
|
||||
/* Translation attributes fields */
|
||||
#define RISCV_IOMMU_PC_TA_V BIT_ULL(0)
|
||||
#define RISCV_IOMMU_PC_TA_RESERVED GENMASK_ULL(63, 32)
|
||||
|
||||
/* First stage context fields */
|
||||
#define RISCV_IOMMU_PC_FSC_PPN GENMASK_ULL(43, 0)
|
||||
#define RISCV_IOMMU_PC_FSC_RESERVED GENMASK_ULL(59, 44)
|
||||
|
||||
enum riscv_iommu_fq_ttypes {
|
||||
RISCV_IOMMU_FQ_TTYPE_NONE = 0,
|
||||
RISCV_IOMMU_FQ_TTYPE_UADDR_INST_FETCH = 1,
|
||||
RISCV_IOMMU_FQ_TTYPE_UADDR_RD = 2,
|
||||
RISCV_IOMMU_FQ_TTYPE_UADDR_WR = 3,
|
||||
RISCV_IOMMU_FQ_TTYPE_TADDR_INST_FETCH = 5,
|
||||
RISCV_IOMMU_FQ_TTYPE_TADDR_RD = 6,
|
||||
RISCV_IOMMU_FQ_TTYPE_TADDR_WR = 7,
|
||||
RISCV_IOMMU_FQ_TTYPE_PCIE_ATS_REQ = 8,
|
||||
RISCV_IOMMU_FW_TTYPE_PCIE_MSG_REQ = 9,
|
||||
};
|
||||
|
||||
/* Header fields */
|
||||
#define RISCV_IOMMU_PREQ_HDR_PID GENMASK_ULL(31, 12)
|
||||
#define RISCV_IOMMU_PREQ_HDR_PV BIT_ULL(32)
|
||||
#define RISCV_IOMMU_PREQ_HDR_PRIV BIT_ULL(33)
|
||||
#define RISCV_IOMMU_PREQ_HDR_EXEC BIT_ULL(34)
|
||||
#define RISCV_IOMMU_PREQ_HDR_DID GENMASK_ULL(63, 40)
|
||||
|
||||
/* Payload fields */
|
||||
#define RISCV_IOMMU_PREQ_PAYLOAD_R BIT_ULL(0)
|
||||
#define RISCV_IOMMU_PREQ_PAYLOAD_W BIT_ULL(1)
|
||||
#define RISCV_IOMMU_PREQ_PAYLOAD_L BIT_ULL(2)
|
||||
#define RISCV_IOMMU_PREQ_PAYLOAD_M GENMASK_ULL(2, 0)
|
||||
#define RISCV_IOMMU_PREQ_PRG_INDEX GENMASK_ULL(11, 3)
|
||||
#define RISCV_IOMMU_PREQ_UADDR GENMASK_ULL(63, 12)
|
||||
|
||||
|
||||
/*
|
||||
* struct riscv_iommu_msi_pte - MSI Page Table Entry
|
||||
*/
|
||||
struct riscv_iommu_msi_pte {
|
||||
uint64_t pte;
|
||||
uint64_t mrif_info;
|
||||
};
|
||||
|
||||
/* Fields on pte */
|
||||
#define RISCV_IOMMU_MSI_PTE_V BIT_ULL(0)
|
||||
#define RISCV_IOMMU_MSI_PTE_M GENMASK_ULL(2, 1)
|
||||
|
||||
#define RISCV_IOMMU_MSI_PTE_M_MRIF 1
|
||||
#define RISCV_IOMMU_MSI_PTE_M_BASIC 3
|
||||
|
||||
/* When M == 1 (MRIF mode) */
|
||||
#define RISCV_IOMMU_MSI_PTE_MRIF_ADDR GENMASK_ULL(53, 7)
|
||||
/* When M == 3 (basic mode) */
|
||||
#define RISCV_IOMMU_MSI_PTE_PPN RISCV_IOMMU_PPN_FIELD
|
||||
#define RISCV_IOMMU_MSI_PTE_C BIT_ULL(63)
|
||||
|
||||
/* Fields on mrif_info */
|
||||
#define RISCV_IOMMU_MSI_MRIF_NID GENMASK_ULL(9, 0)
|
||||
#define RISCV_IOMMU_MSI_MRIF_NPPN RISCV_IOMMU_PPN_FIELD
|
||||
#define RISCV_IOMMU_MSI_MRIF_NID_MSB BIT_ULL(60)
|
||||
|
||||
#endif /* _RISCV_IOMMU_BITS_H_ */
|
202
hw/riscv/riscv-iommu-pci.c
Normal file
202
hw/riscv/riscv-iommu-pci.c
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* QEMU emulation of an RISC-V IOMMU
|
||||
*
|
||||
* Copyright (C) 2022-2023 Rivos Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/pci/msix.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#include "cpu_bits.h"
|
||||
#include "riscv-iommu.h"
|
||||
#include "riscv-iommu-bits.h"
|
||||
|
||||
/* RISC-V IOMMU PCI Device Emulation */
|
||||
#define RISCV_PCI_CLASS_SYSTEM_IOMMU 0x0806
|
||||
|
||||
/*
|
||||
* 4 MSIx vectors for ICVEC, one for MRIF. The spec mentions in
|
||||
* the "Placement and data flow" section that:
|
||||
*
|
||||
* "The interfaces related to recording an incoming MSI in a memory-resident
|
||||
* interrupt file (MRIF) are implementation-specific. The partitioning of
|
||||
* responsibility between the IOMMU and the IO bridge for recording the
|
||||
* incoming MSI in an MRIF and generating the associated notice MSI are
|
||||
* implementation-specific."
|
||||
*
|
||||
* We're making a design decision to create the MSIx for MRIF in the
|
||||
* IOMMU MSIx emulation.
|
||||
*/
|
||||
#define RISCV_IOMMU_PCI_MSIX_VECTORS 5
|
||||
|
||||
/*
|
||||
* 4 vectors that can be used by civ, fiv, pmiv and piv. Number of
|
||||
* vectors is represented by 2^N, where N = number of writable bits
|
||||
* in each cause. For 4 vectors we'll write 0b11 (3) in each reg.
|
||||
*/
|
||||
#define RISCV_IOMMU_PCI_ICVEC_VECTORS 0x3333
|
||||
|
||||
typedef struct RISCVIOMMUStatePci {
|
||||
PCIDevice pci; /* Parent PCIe device state */
|
||||
uint16_t vendor_id;
|
||||
uint16_t device_id;
|
||||
uint8_t revision;
|
||||
MemoryRegion bar0; /* PCI BAR (including MSI-x config) */
|
||||
RISCVIOMMUState iommu; /* common IOMMU state */
|
||||
} RISCVIOMMUStatePci;
|
||||
|
||||
/* interrupt delivery callback */
|
||||
static void riscv_iommu_pci_notify(RISCVIOMMUState *iommu, unsigned vector)
|
||||
{
|
||||
RISCVIOMMUStatePci *s = container_of(iommu, RISCVIOMMUStatePci, iommu);
|
||||
|
||||
if (msix_enabled(&(s->pci))) {
|
||||
msix_notify(&(s->pci), vector);
|
||||
}
|
||||
}
|
||||
|
||||
static void riscv_iommu_pci_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
RISCVIOMMUStatePci *s = DO_UPCAST(RISCVIOMMUStatePci, pci, dev);
|
||||
RISCVIOMMUState *iommu = &s->iommu;
|
||||
uint8_t *pci_conf = dev->config;
|
||||
Error *err = NULL;
|
||||
|
||||
pci_set_word(pci_conf + PCI_VENDOR_ID, s->vendor_id);
|
||||
pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, s->vendor_id);
|
||||
pci_set_word(pci_conf + PCI_DEVICE_ID, s->device_id);
|
||||
pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, s->device_id);
|
||||
pci_set_byte(pci_conf + PCI_REVISION_ID, s->revision);
|
||||
|
||||
/* Set device id for trace / debug */
|
||||
DEVICE(iommu)->id = g_strdup_printf("%02x:%02x.%01x",
|
||||
pci_dev_bus_num(dev), PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
|
||||
qdev_realize(DEVICE(iommu), NULL, errp);
|
||||
|
||||
memory_region_init(&s->bar0, OBJECT(s), "riscv-iommu-bar0",
|
||||
QEMU_ALIGN_UP(memory_region_size(&iommu->regs_mr), TARGET_PAGE_SIZE));
|
||||
memory_region_add_subregion(&s->bar0, 0, &iommu->regs_mr);
|
||||
|
||||
pcie_endpoint_cap_init(dev, 0);
|
||||
|
||||
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
|
||||
PCI_BASE_ADDRESS_MEM_TYPE_64, &s->bar0);
|
||||
|
||||
int ret = msix_init(dev, RISCV_IOMMU_PCI_MSIX_VECTORS,
|
||||
&s->bar0, 0, RISCV_IOMMU_REG_MSI_CONFIG,
|
||||
&s->bar0, 0, RISCV_IOMMU_REG_MSI_CONFIG + 256, 0, &err);
|
||||
|
||||
if (ret == -ENOTSUP) {
|
||||
/*
|
||||
* MSI-x is not supported by the platform.
|
||||
* Driver should use timer/polling based notification handlers.
|
||||
*/
|
||||
warn_report_err(err);
|
||||
} else if (ret < 0) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
} else {
|
||||
/* Mark all ICVEC MSIx vectors as used */
|
||||
for (int i = 0; i < RISCV_IOMMU_PCI_MSIX_VECTORS; i++) {
|
||||
msix_vector_use(dev, i);
|
||||
}
|
||||
|
||||
iommu->notify = riscv_iommu_pci_notify;
|
||||
}
|
||||
|
||||
PCIBus *bus = pci_device_root_bus(dev);
|
||||
if (!bus) {
|
||||
error_setg(errp, "can't find PCIe root port for %02x:%02x.%x",
|
||||
pci_bus_num(pci_get_bus(dev)), PCI_SLOT(dev->devfn),
|
||||
PCI_FUNC(dev->devfn));
|
||||
return;
|
||||
}
|
||||
|
||||
riscv_iommu_pci_setup_iommu(iommu, bus, errp);
|
||||
}
|
||||
|
||||
static void riscv_iommu_pci_exit(PCIDevice *pci_dev)
|
||||
{
|
||||
pci_setup_iommu(pci_device_root_bus(pci_dev), NULL, NULL);
|
||||
}
|
||||
|
||||
static const VMStateDescription riscv_iommu_vmstate = {
|
||||
.name = "riscv-iommu",
|
||||
.unmigratable = 1
|
||||
};
|
||||
|
||||
static void riscv_iommu_pci_init(Object *obj)
|
||||
{
|
||||
RISCVIOMMUStatePci *s = RISCV_IOMMU_PCI(obj);
|
||||
RISCVIOMMUState *iommu = &s->iommu;
|
||||
|
||||
object_initialize_child(obj, "iommu", iommu, TYPE_RISCV_IOMMU);
|
||||
qdev_alias_all_properties(DEVICE(iommu), obj);
|
||||
|
||||
iommu->icvec_avail_vectors = RISCV_IOMMU_PCI_ICVEC_VECTORS;
|
||||
}
|
||||
|
||||
static Property riscv_iommu_pci_properties[] = {
|
||||
DEFINE_PROP_UINT16("vendor-id", RISCVIOMMUStatePci, vendor_id,
|
||||
PCI_VENDOR_ID_REDHAT),
|
||||
DEFINE_PROP_UINT16("device-id", RISCVIOMMUStatePci, device_id,
|
||||
PCI_DEVICE_ID_REDHAT_RISCV_IOMMU),
|
||||
DEFINE_PROP_UINT8("revision", RISCVIOMMUStatePci, revision, 0x01),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void riscv_iommu_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->realize = riscv_iommu_pci_realize;
|
||||
k->exit = riscv_iommu_pci_exit;
|
||||
k->class_id = RISCV_PCI_CLASS_SYSTEM_IOMMU;
|
||||
dc->desc = "RISCV-IOMMU DMA Remapping device";
|
||||
dc->vmsd = &riscv_iommu_vmstate;
|
||||
dc->hotpluggable = false;
|
||||
dc->user_creatable = true;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
device_class_set_props(dc, riscv_iommu_pci_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo riscv_iommu_pci = {
|
||||
.name = TYPE_RISCV_IOMMU_PCI,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.class_init = riscv_iommu_pci_class_init,
|
||||
.instance_init = riscv_iommu_pci_init,
|
||||
.instance_size = sizeof(RISCVIOMMUStatePci),
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ INTERFACE_PCIE_DEVICE },
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static void riscv_iommu_register_pci_types(void)
|
||||
{
|
||||
type_register_static(&riscv_iommu_pci);
|
||||
}
|
||||
|
||||
type_init(riscv_iommu_register_pci_types);
|
2399
hw/riscv/riscv-iommu.c
Normal file
2399
hw/riscv/riscv-iommu.c
Normal file
File diff suppressed because it is too large
Load diff
130
hw/riscv/riscv-iommu.h
Normal file
130
hw/riscv/riscv-iommu.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* QEMU emulation of an RISC-V IOMMU
|
||||
*
|
||||
* Copyright (C) 2022-2023 Rivos Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HW_RISCV_IOMMU_STATE_H
|
||||
#define HW_RISCV_IOMMU_STATE_H
|
||||
|
||||
#include "qom/object.h"
|
||||
#include "hw/riscv/iommu.h"
|
||||
|
||||
struct RISCVIOMMUState {
|
||||
/*< private >*/
|
||||
DeviceState parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
uint32_t version; /* Reported interface version number */
|
||||
uint32_t pid_bits; /* process identifier width */
|
||||
uint32_t bus; /* PCI bus mapping for non-root endpoints */
|
||||
|
||||
uint64_t cap; /* IOMMU supported capabilities */
|
||||
uint64_t fctl; /* IOMMU enabled features */
|
||||
uint64_t icvec_avail_vectors; /* Available interrupt vectors in ICVEC */
|
||||
|
||||
bool enable_off; /* Enable out-of-reset OFF mode (DMA disabled) */
|
||||
bool enable_msi; /* Enable MSI remapping */
|
||||
bool enable_ats; /* Enable ATS support */
|
||||
bool enable_s_stage; /* Enable S/VS-Stage translation */
|
||||
bool enable_g_stage; /* Enable G-Stage translation */
|
||||
|
||||
/* IOMMU Internal State */
|
||||
uint64_t ddtp; /* Validated Device Directory Tree Root Pointer */
|
||||
|
||||
dma_addr_t cq_addr; /* Command queue base physical address */
|
||||
dma_addr_t fq_addr; /* Fault/event queue base physical address */
|
||||
dma_addr_t pq_addr; /* Page request queue base physical address */
|
||||
|
||||
uint32_t cq_mask; /* Command queue index bit mask */
|
||||
uint32_t fq_mask; /* Fault/event queue index bit mask */
|
||||
uint32_t pq_mask; /* Page request queue index bit mask */
|
||||
|
||||
/* interrupt notifier */
|
||||
void (*notify)(RISCVIOMMUState *iommu, unsigned vector);
|
||||
|
||||
/* IOMMU State Machine */
|
||||
QemuThread core_proc; /* Background processing thread */
|
||||
QemuCond core_cond; /* Background processing wake up signal */
|
||||
unsigned core_exec; /* Processing thread execution actions */
|
||||
|
||||
/* IOMMU target address space */
|
||||
AddressSpace *target_as;
|
||||
MemoryRegion *target_mr;
|
||||
|
||||
/* MSI / MRIF access trap */
|
||||
AddressSpace trap_as;
|
||||
MemoryRegion trap_mr;
|
||||
|
||||
GHashTable *ctx_cache; /* Device translation Context Cache */
|
||||
|
||||
GHashTable *iot_cache; /* IO Translated Address Cache */
|
||||
unsigned iot_limit; /* IO Translation Cache size limit */
|
||||
|
||||
/* MMIO Hardware Interface */
|
||||
MemoryRegion regs_mr;
|
||||
uint8_t *regs_rw; /* register state (user write) */
|
||||
uint8_t *regs_wc; /* write-1-to-clear mask */
|
||||
uint8_t *regs_ro; /* read-only mask */
|
||||
|
||||
QLIST_ENTRY(RISCVIOMMUState) iommus;
|
||||
QLIST_HEAD(, RISCVIOMMUSpace) spaces;
|
||||
};
|
||||
|
||||
void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus,
|
||||
Error **errp);
|
||||
|
||||
/* private helpers */
|
||||
|
||||
/* Register helper functions */
|
||||
static inline uint32_t riscv_iommu_reg_mod32(RISCVIOMMUState *s,
|
||||
unsigned idx, uint32_t set, uint32_t clr)
|
||||
{
|
||||
uint32_t val = ldl_le_p(s->regs_rw + idx);
|
||||
stl_le_p(s->regs_rw + idx, (val & ~clr) | set);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void riscv_iommu_reg_set32(RISCVIOMMUState *s, unsigned idx,
|
||||
uint32_t set)
|
||||
{
|
||||
stl_le_p(s->regs_rw + idx, set);
|
||||
}
|
||||
|
||||
static inline uint32_t riscv_iommu_reg_get32(RISCVIOMMUState *s, unsigned idx)
|
||||
{
|
||||
return ldl_le_p(s->regs_rw + idx);
|
||||
}
|
||||
|
||||
static inline uint64_t riscv_iommu_reg_mod64(RISCVIOMMUState *s, unsigned idx,
|
||||
uint64_t set, uint64_t clr)
|
||||
{
|
||||
uint64_t val = ldq_le_p(s->regs_rw + idx);
|
||||
stq_le_p(s->regs_rw + idx, (val & ~clr) | set);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void riscv_iommu_reg_set64(RISCVIOMMUState *s, unsigned idx,
|
||||
uint64_t set)
|
||||
{
|
||||
stq_le_p(s->regs_rw + idx, set);
|
||||
}
|
||||
|
||||
static inline uint64_t riscv_iommu_reg_get64(RISCVIOMMUState *s,
|
||||
unsigned idx)
|
||||
{
|
||||
return ldq_le_p(s->regs_rw + idx);
|
||||
}
|
||||
#endif
|
|
@ -645,7 +645,8 @@ static void sifive_u_machine_init(MachineState *machine)
|
|||
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
|
||||
memmap[SIFIVE_U_DEV_MROM].base, &address_space_memory);
|
||||
|
||||
riscv_rom_copy_firmware_info(machine, memmap[SIFIVE_U_DEV_MROM].base,
|
||||
riscv_rom_copy_firmware_info(machine, &s->soc.u_cpus,
|
||||
memmap[SIFIVE_U_DEV_MROM].base,
|
||||
memmap[SIFIVE_U_DEV_MROM].size,
|
||||
sizeof(reset_vec), kernel_entry);
|
||||
|
||||
|
|
17
hw/riscv/trace-events
Normal file
17
hw/riscv/trace-events
Normal file
|
@ -0,0 +1,17 @@
|
|||
# See documentation at docs/devel/tracing.rst
|
||||
|
||||
# riscv-iommu.c
|
||||
riscv_iommu_new(const char *id, unsigned b, unsigned d, unsigned f) "%s: device attached %04x:%02x.%d"
|
||||
riscv_iommu_flt(const char *id, unsigned b, unsigned d, unsigned f, uint64_t reason, uint64_t iova) "%s: fault %04x:%02x.%u reason: 0x%"PRIx64" iova: 0x%"PRIx64
|
||||
riscv_iommu_pri(const char *id, unsigned b, unsigned d, unsigned f, uint64_t iova) "%s: page request %04x:%02x.%u iova: 0x%"PRIx64
|
||||
riscv_iommu_dma(const char *id, unsigned b, unsigned d, unsigned f, unsigned pasid, const char *dir, uint64_t iova, uint64_t phys) "%s: translate %04x:%02x.%u #%u %s 0x%"PRIx64" -> 0x%"PRIx64
|
||||
riscv_iommu_msi(const char *id, unsigned b, unsigned d, unsigned f, uint64_t iova, uint64_t phys) "%s: translate %04x:%02x.%u MSI 0x%"PRIx64" -> 0x%"PRIx64
|
||||
riscv_iommu_mrif_notification(const char *id, uint32_t nid, uint64_t phys) "%s: sent MRIF notification 0x%x to 0x%"PRIx64
|
||||
riscv_iommu_cmd(const char *id, uint64_t l, uint64_t u) "%s: command 0x%"PRIx64" 0x%"PRIx64
|
||||
riscv_iommu_notifier_add(const char *id) "%s: dev-iotlb notifier added"
|
||||
riscv_iommu_notifier_del(const char *id) "%s: dev-iotlb notifier removed"
|
||||
riscv_iommu_notify_int_vector(uint32_t cause, uint32_t vector) "Interrupt cause 0x%x sent via vector 0x%x"
|
||||
riscv_iommu_icvec_write(uint32_t orig, uint32_t actual) "ICVEC write: incoming 0x%x actual 0x%x"
|
||||
riscv_iommu_ats(const char *id, unsigned b, unsigned d, unsigned f, uint64_t iova) "%s: translate request %04x:%02x.%u iova: 0x%"PRIx64
|
||||
riscv_iommu_ats_inval(const char *id) "%s: dev-iotlb invalidate"
|
||||
riscv_iommu_ats_prgr(const char *id) "%s: dev-iotlb page request group response"
|
1
hw/riscv/trace.h
Normal file
1
hw/riscv/trace.h
Normal file
|
@ -0,0 +1 @@
|
|||
#include "trace/trace-hw_riscv.h"
|
|
@ -32,6 +32,7 @@
|
|||
#include "hw/core/sysbus-fdt.h"
|
||||
#include "target/riscv/pmu.h"
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
#include "hw/riscv/iommu.h"
|
||||
#include "hw/riscv/virt.h"
|
||||
#include "hw/riscv/boot.h"
|
||||
#include "hw/riscv/numa.h"
|
||||
|
@ -1032,6 +1033,30 @@ static void create_fdt_virtio_iommu(RISCVVirtState *s, uint16_t bdf)
|
|||
bdf + 1, iommu_phandle, bdf + 1, 0xffff - bdf);
|
||||
}
|
||||
|
||||
static void create_fdt_iommu(RISCVVirtState *s, uint16_t bdf)
|
||||
{
|
||||
const char comp[] = "riscv,pci-iommu";
|
||||
void *fdt = MACHINE(s)->fdt;
|
||||
uint32_t iommu_phandle;
|
||||
g_autofree char *iommu_node = NULL;
|
||||
g_autofree char *pci_node = NULL;
|
||||
|
||||
pci_node = g_strdup_printf("/soc/pci@%lx",
|
||||
(long) virt_memmap[VIRT_PCIE_ECAM].base);
|
||||
iommu_node = g_strdup_printf("%s/iommu@%x", pci_node, bdf);
|
||||
iommu_phandle = qemu_fdt_alloc_phandle(fdt);
|
||||
qemu_fdt_add_subnode(fdt, iommu_node);
|
||||
|
||||
qemu_fdt_setprop(fdt, iommu_node, "compatible", comp, sizeof(comp));
|
||||
qemu_fdt_setprop_cell(fdt, iommu_node, "#iommu-cells", 1);
|
||||
qemu_fdt_setprop_cell(fdt, iommu_node, "phandle", iommu_phandle);
|
||||
qemu_fdt_setprop_cells(fdt, iommu_node, "reg",
|
||||
bdf << 8, 0, 0, 0, 0);
|
||||
qemu_fdt_setprop_cells(fdt, pci_node, "iommu-map",
|
||||
0, iommu_phandle, 0, bdf,
|
||||
bdf + 1, iommu_phandle, bdf + 1, 0xffff - bdf);
|
||||
}
|
||||
|
||||
static void finalize_fdt(RISCVVirtState *s)
|
||||
{
|
||||
uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1;
|
||||
|
@ -1738,9 +1763,11 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
|
|||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
|
||||
if (device_is_dynamic_sysbus(mc, dev) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_RISCV_IOMMU_PCI)) {
|
||||
return HOTPLUG_HANDLER(machine);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1761,6 +1788,10 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
|
|||
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
|
||||
create_fdt_virtio_iommu(s, pci_get_bdf(PCI_DEVICE(dev)));
|
||||
}
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_RISCV_IOMMU_PCI)) {
|
||||
create_fdt_iommu(s, pci_get_bdf(PCI_DEVICE(dev)));
|
||||
}
|
||||
}
|
||||
|
||||
static void virt_machine_class_init(ObjectClass *oc, void *data)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue