riscv_iommu_translate(), the only caller of riscv_iommu_spa_fetch(),
will use riscv_iommu_report_fault() for all faults it detects. And it
will use iotlb->translated_addr as 'iotval2' every time.
At this moment we're updating iotlb->translated_addr only after a
translation step is completed, meaning any fault that occur before that
will have a zeroed iotlb->translated_addr, and as a result iotval2 will
also be zero later on.
Keep iotlb->translated_addr updated with the latest translated addr we
have.
Fixes: 0c54acb824 ("hw/riscv: add RISC-V IOMMU base emulation")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3559
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260702171202.1322493-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Under certain circunstances, like the one described in [1] and [2],
a read operation that faults will be logged as a write fault instead,
and vice-versa, if they happen after the translation phase in
riscv_iommu_spa_fetch().
The first problem is that we're overwriting iotlb->perm with PTE flags,
so an IOMMU_RO access flag can be overwritten by whatever flags
the PTE has. This will cause the wrong fault type to be thrown at
the end of the function in case a fault happens.
To solve the iotlb->perm overwrite we'll bit_and the original
iotlb->perm access flags with the PTE access flags, preserving the
original access type. So a IOMMU_RO access in a R+W PTE will result in
a IOMMU_RO perm.
Second, the resulting fault is received by riscv_iommu_translate(), which
will then report the fault. To do that we require a transaction type
(ttype). We're prioritizing checking "perm & IOMMU_RW" to set a
UADDR_WR ttype, and then checking "perm & IOMMU_RO" to set UADDR_RD
ttype. The issue with that is IOMMU_RO=1 and IOMMU_RW=3, thus checking
"perm & IOMMU_RW" for a write then "perm & IOMMU_RO" for a read will
cause the read fault to always be diagnosed as write.
Make the iotlb->perm matches more strict: "perm & IOMMU_RW" must be
exactly IOMMU_RW, ensuring that 'perm' has both flags. Then we can
check perm & IOMMU_WO and perm & IOMMU_RO without worrying about
overlapping with the RW flag.
[1] https://gitlab.com/qemu-project/qemu/-/work_items/3557
[2] https://gitlab.com/qemu-project/qemu/-/work_items/3577
Fixes: 69a9ae4836 ("hw/riscv/riscv-iommu: add ATS support")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3557
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3577
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260701124034.552271-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Currently fw_cfg_init_mem_dma() allows the caller to customize the
register layout, by specifying separately the offsets for control,
data and DMA registers, plus the width of the data register.
In practice, all the boards using this function specify the same
standard layout: "base + 8, base, 8, base + 16", meaning that the
data register is 8 bytes and the registers are data at offset 0,
control/selector at offset 8, and DMA at offset 16.
Allowing every board to be different is gratuitous and useless
variation which leads to code in guest OSes having architecture
ifdeffery to cope with it. Avoid potentially introducing any more of
this by removing all the arguments from fw_cfg_init_mem_dma(), so
that the callers only specify the base address.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Message-id: 20260529174639.451353-3-peter.maydell@linaro.org
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Add an I2C RTC device and a temperature sensor. These are not present
on the board but help for testing.
The tmp105 is a lm75 compatible temperature sensor used by the
SENSORS_LM75 Linux kernel driver.
The ds1338 is a RTC device that is used by the RTC_DRV_DS1307 Linux
kernel driver.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20260630024952.1520546-13-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
When using OpenSBI fw_dynamic on the Atlantis board OpenSBI fails
to print any output, as it hits an error early on
in the boot process and gets stuck in `sbi_hart_hang()`.
The error occurs in the `sanitize_domain()` function inside OpenSBI.
`sanitize_domain()` is called after a M-Mode OpenSBI Firmware and a generic
coverall S-Mode RWX memory region are created. `sanitize_domain()` is
checking that the next address is executable.
If no next address is provided (which occurs on QEMU with an empty payload),
then `dom->next_addr` will be 0. On most RISC-V boards address 0 will fall
inside the coverall S-Mode RWX memory region and pass this check. On
Atlantis the OpenSBI firmware is running at address 0, so this address
falls inside the M-Mode only OpenSBI firmware region and fails the check.
Once the check has failed OpenSBI aborts and the user doesn't see any
messages. This can be fixed by either supplying a payload, or just
manually forcing a non-zero address (actually just any address that
isn't the OpenSBI firmware) for next_addr.
This patch ensures that if no kernel is loaded we still specify a
default kernel_entry so that OpenSBI happily boots and jumps to
the first address in memory.
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260630024952.1520546-9-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
The Tenstorrent Atlantis platform is a collaboration between Tenstorrent
and CoreLab Technology. It is based on the Atlantis SoC, which includes
the Ascalon-X CPU and other IP from Tenstorrent and CoreLab Technology.
The Tenstorrent Ascalon-X is a high performance 64-bit RVA23 compliant
RISC-V CPU.
Add the tt-atlantis machine containing serial console, interrupt
controllers, and device tree support.
The Atlantis boot images loaded from include OpenSBI and an initial DTB
that is passed to OpenSBI. This is approximated in the model by having
QEMU build the device tree rather than load a DTB image directly.
Subsequent stages may use the modified DTB provided by OpenSBI or opt to
supply their own.
qemu-system-riscv64 -M tt-atlantis -m 512M \
-kernel Image -initrd rootfs.cpio -nographic
Co-Developed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260630024952.1520546-8-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
riscv_create_aia() currently hard-codes the M-IMSIC at one 4 KiB page
per hart and gives callers no way to widen it.
Add an m_imsic_stride parameter that supplies the per hart byte
stride directly. The virt machine passes IMSIC_HART_SIZE(0)
(= 4 KiB), preserving its existing compact layout.
The parameter only changes how the slots are spaced, with the rest of
each slot reserved. This allows future platforms that have different
layouts to control the stride.
Reviewed-by: Philippe Mathieu-Daudé <philmd@mailo.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20260630024952.1520546-6-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
The existing nomenclature can be misleading: regs_rw can cosplay as
'read and write' mask, in particular because we have regs_ro which is a
read only mask.
regs_rw is the current reg value, and all bits that aren't on the
regs_ro mask is considered r/w bits.
Rename regs_rw to 'regs' to be on par with the nomenclature other
devices uses (e.g. cadence_gem).
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260625210833.3294437-2-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
We're still using "/soc/plic@..." as FDT nodename in virt.c. This is
not the right nodename per the DT docs:
https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/sifive%2Cplic-1.0.0.txt
The nodename must be 'interrupt-controller@...' since the node inherits
the 'interrupt-controller' type. In fact, ever since at least the 2020
Linux kernel commit c825a081c169cc7f ("dt-bindings: riscv: convert plic
bindings to json-schema") the correct nodename has been
'interrupt-controller' for the sifive PLIC controller.
There's no deprecation needed for bug fixes so we're just fixing the
name. This was the policy we dud when fixing the aplic [1] and the
imsic [2] nodenames to 'interrupt-controller@...' as well.
The sifive_u PLIC FDT already uses the correct nodename for PLIC, so it
is safe to assume that available SW is already aware of the correct
nodename and this change won't affect well-behaved SW.
[1] commit 29390fd ("hw/riscv/virt.c: rename aplic nodename to 'interrupt-controller'")
[2] commit e8ad581 ("hw/riscv/virt.c: change imsic nodename to 'interrupt-controller'")
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260616235939.1358663-5-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
create_fdt() has the following code sequence:
plic_phandle = phandle++;
(...)
qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
What this is doing is assigning a value to plic_phandle, then use that
as phandle of "nodename", and then fetching the phandle of "nodename"
again in the same variable that already had the right phandle val.
Here's how it looks like in gdb:
Thread 1 "qemu-system-ris" hit Breakpoint 1, create_fdt
(s=0xaaaaac162a30, memmap=0xaaaaab8f70c8 <sifive_u_memmap>,
is_32_bit=false) at ../hw/riscv/sifive_u.c:199
199 plic_phandle = phandle++;
(gdb) n
200 cells = g_new0(uint32_t, ms->smp.cpus * 4 - 2);
(gdb) p plic_phandle
$3 = 12
(gdb) c
Continuing.
Thread 1 "qemu-system-ris" hit Breakpoint 2, create_fdt
(s=0xaaaaac162a30, memmap=0xaaaaab8f70c8 <sifive_u_memmap>,
is_32_bit=false) at ../hw/riscv/sifive_u.c:232
232 plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
(gdb) n
233 g_free(cells);
(gdb) p plic_phandle
$4 = 12
(gdb)
Remove the extra qemu_fdt_get_phandle() call.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260616235939.1358663-2-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Each RISC-V MADT RINTC entry contains an External Interrupt Controller
ID field. On the virt machine without AIA, this field identifies the
S-mode PLIC context associated with the hart.
TCG virt has both M-mode and S-mode PLIC contexts, so the S-mode context
ID is odd and 2 * local_cpu_id + 1 is correct. KVM virt exposes only
S-mode PLIC contexts, and those contexts are numbered contiguously from
0. Reporting the TCG context ID for KVM makes the guest enable a
different PLIC context from the one used by QEMU.
With ACPI enabled, this can leave PCI INTx interrupts pending in QEMU
while the guest-programmed PLIC context remains disabled. A virtio-blk
root disk can then stall during boot because its first interrupt is never
delivered.
Use local_cpu_id for KVM and keep the existing odd S-mode context ID for
TCG.
Fixes: d641da6ed4 ("hw/riscv/virt-acpi-build.c: Add PLIC in MADT")
Signed-off-by: Qingwei Hu <qingwei.hu@bytedance.com>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Reviewed-by: Sunil V L <sunilvl@oss.qualcomm.com>
Message-ID: <20260604120017.398890-1-qingwei.hu@bytedance.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
The sifive_u board does not share the same CPU socket FDT bits from the
other boards. In particular the riscv,isa creation is done using either
CPU0 from soc.e_cpus.harts, and for all other CPUs soc.u_cups.harts is
used.
It would be too cumbersome to add all these details in the common code
so we're going to add a special sifive_u only helper that shares the
common bits with the common helper used by the other boards.
create_fdt_socket_cpu_internal() contains the common bits shared between
the sifive_u board and the rest.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-13-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
We want to consolidate the CPU socket FDT creation into a single helper.
'virt' and spike has the same code but sifive_u does not have cpu-map,
cluster and core subnodes.
These subnodes are present in other boards even in single socket configs
without NUMA. This is a strong indicator that their presence doesn't
hurt a NUMA-less board like sifive_u.
Add these DTs to make the FDT standardization straightforward.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-9-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
The clint FDT generation uses a cells array (clint_cells) that are
populated in the middle of the loop that creates the CPU socket FDT.
This is completely fine but it differs from the other boards that
creates the clint cells array right before creating the clint FDT.
'virt' and 'sifive_u' store the intc phandles in a intc_phandles array
during FDT CPU socket creation, and this array is used to create the
clint FDT cells.
Standardize the clint FDT creation for spike doing the same here,
allowing us to move everything to a common helper later.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-7-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
There's FDT logic gated around 'numa_enabled()' in virt.c and spike.c.
We want to move the FDT code to a common helper without having to call
hw/riscv/numa.c functions from it, but at the same time being aware of
the FDT changes if numa is enabled.
To do that the boards will inform the FDT helpers if we have
numa_enabled in the env or not. And for the boards to be able to do
that we need the static 'numa_enabled' function to be public.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Message-ID: <20260615203734.954428-4-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>