[PATCH v3 00/11] OpenRISC Virtual Machine
Hello, This is the OpenRISC Virtual Machine plaform which we are now using for OpenRISC CI such as the wireguard testing that Jason has been working on. I also have recently used it to test glibc 2.36 and it worked well. Previous glibc testsuite runs on my FPGA board took about 3 days, running on qemu virt now takes 6 hours. The first few patches help get OpenRISC QEMU ready for the virtual machine. There is one bug fix for GDB debugging there too. Next we have the Virt patch followed by a separate patch to add PCI support which is split out because it's a bit easier to review that way I thought. The next few patches are fixes to get the Multicore platform stable, such as adding MTTCG support and fixing some interrupt and timer related bugs. The platform is relatively stable now, but every few boots we get about 10 second hangs. However, overall this is much more stable than the SMP support we had before. So I want to submit this for review and maybe upstream it before tracking down these last issues which might take significant more time. This is being tested with the or1k-5.20-updates kernel branch here: https://github.com/stffrdhrn/linux/commits/or1k-5.20-updates This tree has support for: OpenRISC PCI and virt_defconfig and an irqchip bug fix. Changes since v2: - Changed goldfish_rtc endian property to boolean - Moved or1k timer init from init to reset - Removed cpu_openrisc_timer_has_advanced lock optimization in MTTCG patch, measuring revealed it did not help much. Changes since v1: - Dropped semihosting support - Added PCI support - Added OpenRISC documentation - Added OpenRISC support for MTTCG - Support Configurating Goldfish RTC endianness - Added a few bug fix patches Jason A. Donenfeld (1): hw/openrisc: virt: pass random seed to fdt Stafford Horne (10): hw/openrisc: Split re-usable boot time apis out to boot.c target/openrisc: Fix memory reading in debugger goldfish_rtc: Add big-endian property hw/openrisc: Add the OpenRISC virtual machine hw/openrisc: Add PCI bus support to virt hw/openrisc: Initialize timer time at startup target/openrisc: Add interrupted CPU to log target/openrisc: Enable MTTCG target/openrisc: Interrupt handling fixes docs/system: openrisc: Add OpenRISC documentation configs/devices/or1k-softmmu/default.mak | 1 + configs/targets/or1k-softmmu.mak | 1 + docs/system/openrisc/cpu-features.rst| 15 + docs/system/openrisc/emulation.rst | 17 + docs/system/openrisc/or1k-sim.rst| 43 ++ docs/system/openrisc/virt.rst| 50 ++ docs/system/target-openrisc.rst | 72 +++ docs/system/targets.rst | 1 + hw/m68k/virt.c | 1 + hw/openrisc/Kconfig | 12 + hw/openrisc/boot.c | 117 + hw/openrisc/cputimer.c | 22 +- hw/openrisc/meson.build | 2 + hw/openrisc/openrisc_sim.c | 106 + hw/openrisc/virt.c | 571 +++ hw/rtc/goldfish_rtc.c| 37 +- include/hw/openrisc/boot.h | 34 ++ include/hw/rtc/goldfish_rtc.h| 2 + target/openrisc/cpu.c| 1 - target/openrisc/cpu.h| 2 + target/openrisc/interrupt.c | 4 +- target/openrisc/mmu.c| 8 +- target/openrisc/sys_helper.c | 14 +- 23 files changed, 1019 insertions(+), 114 deletions(-) create mode 100644 docs/system/openrisc/cpu-features.rst create mode 100644 docs/system/openrisc/emulation.rst create mode 100644 docs/system/openrisc/or1k-sim.rst create mode 100644 docs/system/openrisc/virt.rst create mode 100644 docs/system/target-openrisc.rst create mode 100644 hw/openrisc/boot.c create mode 100644 hw/openrisc/virt.c create mode 100644 include/hw/openrisc/boot.h -- 2.37.1
[PATCH v3 04/11] hw/openrisc: Add the OpenRISC virtual machine
This patch adds the OpenRISC virtual machine 'virt' for OpenRISC. This platform allows for a convenient CI platform for toolchain, software ports and the OpenRISC linux kernel port. Much of this has been sourced from the m68k and riscv virt platforms. The platform provides: - OpenRISC SMP with up to 4 cpus - A virtio bus with up to 8 devices - Standard ns16550a serial - Goldfish RTC - SiFive TEST device for poweroff and reboot - Generated Device Tree to automatically configure the guest kernel Signed-off-by: Stafford Horne --- Since v2: - No changes configs/devices/or1k-softmmu/default.mak | 1 + hw/openrisc/Kconfig | 9 + hw/openrisc/meson.build | 1 + hw/openrisc/virt.c | 417 +++ 4 files changed, 428 insertions(+) create mode 100644 hw/openrisc/virt.c diff --git a/configs/devices/or1k-softmmu/default.mak b/configs/devices/or1k-softmmu/default.mak index 168101c39a..89c39e3123 100644 --- a/configs/devices/or1k-softmmu/default.mak +++ b/configs/devices/or1k-softmmu/default.mak @@ -3,3 +3,4 @@ # Boards: # CONFIG_OR1K_SIM=y +CONFIG_OR1K_VIRT=y diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 8f284f3ba0..202134668e 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -4,3 +4,12 @@ config OR1K_SIM select OPENCORES_ETH select OMPIC select SPLIT_IRQ + +config OR1K_VIRT +bool +imply VIRTIO_VGA +imply TEST_DEVICES +select GOLDFISH_RTC +select SERIAL +select SIFIVE_TEST +select VIRTIO_MMIO diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ab563820c5..2dbc6365bb 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -2,5 +2,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) +openrisc_ss.add(when: 'CONFIG_OR1K_VIRT', if_true: [files('virt.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c new file mode 100644 index 00..54f2732a6b --- /dev/null +++ b/hw/openrisc/virt.c @@ -0,0 +1,417 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * OpenRISC QEMU virtual machine. + * + * (c) 2022 Stafford Horne + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "cpu.h" +#include "exec/address-spaces.h" +#include "hw/irq.h" +#include "hw/boards.h" +#include "hw/char/serial.h" +#include "hw/core/split-irq.h" +#include "hw/openrisc/boot.h" +#include "hw/misc/sifive_test.h" +#include "hw/qdev-properties.h" +#include "hw/rtc/goldfish_rtc.h" +#include "hw/sysbus.h" +#include "hw/virtio/virtio-mmio.h" +#include "sysemu/device_tree.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "sysemu/reset.h" + +#include + +#define VIRT_CPUS_MAX 4 +#define VIRT_CLK_MHZ 2000 + +#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +#define VIRT_MACHINE(obj) \ +OBJECT_CHECK(OR1KVirtState, (obj), TYPE_VIRT_MACHINE) + +typedef struct OR1KVirtState { +/*< private >*/ +MachineState parent_obj; + +/*< public >*/ +void *fdt; +int fdt_size; + +} OR1KVirtState; + +enum { +VIRT_DRAM, +VIRT_TEST, +VIRT_RTC, +VIRT_VIRTIO, +VIRT_UART, +VIRT_OMPIC, +}; + +enum { +VIRT_OMPIC_IRQ = 1, +VIRT_UART_IRQ = 2, +VIRT_RTC_IRQ = 3, +VIRT_VIRTIO_IRQ = 4, /* to 12 */ +VIRTIO_COUNT = 8, +}; + +static const struct MemmapEntry { +hwaddr base; +hwaddr size; +} virt_memmap[] = { +[VIRT_DRAM] = { 0x, 0 }, +[VIRT_UART] = { 0x9000, 0x100 }, +[VIRT_TEST] = { 0x9600,0x8 }, +[VIRT_RTC] = { 0x96005000, 0x1000 }, +[VIRT_VIRTIO] ={ 0x9700, 0x1000 }, +[VIRT_OMPIC] = { 0x9800, VIRT_CPUS_MAX * 8 }, +}; + +static struct openrisc_boot_info { +uint32_t bootstrap_pc; +uint32_t fdt_addr; +} boot_info; + +static void main_cpu_reset(void *opaque) +{ +OpenRISCCPU *cpu = opaque; +CPUState *cs = CPU(cpu); + +cpu_reset(CPU(cpu)); + +cpu_set_pc(cs, boot_info.bootstrap_pc); +cpu_set_gpr(&cpu->env, 3, boot_info.fdt_addr); +} + +static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) +{ +return qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "IRQ", irq_pin); +} + +static qemu_irq get_per_cpu_irq(OpenRISCCPU *cpus[], int num_cpus, int irq_pin) +{ +int i; + +if (num_cpus > 1) { +DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); +qdev_prop_set_uint32(splitter, "num-lin
[PATCH v3 06/11] hw/openrisc: Initialize timer time at startup
The last_clk time was initialized at zero, this means when we calculate the first delta we will calculate 0 vs current time which could cause unnecessary hops. This patch moves timer initialization to the cpu reset. There are two resets registered here: 1. Per cpu timer mask (ttmr) reset. 2. Global cpu timer (last_clk and ttcr) reset, attached to the first cpu only. Signed-off-by: Stafford Horne --- Since v2: - Moved timer init from init to reset suggested by Richard hw/openrisc/cputimer.c | 22 +- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index 93268815d8..10163b391b 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "migration/vmstate.h" #include "qemu/timer.h" +#include "sysemu/reset.h" #define TIMER_PERIOD 50 /* 50 ns period for 20 MHz timer */ @@ -122,6 +123,24 @@ static void openrisc_timer_cb(void *opaque) qemu_cpu_kick(CPU(cpu)); } +/* Reset the per CPU counter state. */ +static void openrisc_count_reset(void *opaque) +{ +OpenRISCCPU *cpu = opaque; + +if (cpu->env.is_counting) { +cpu_openrisc_count_stop(cpu); +} +cpu->env.ttmr = 0x; +} + +/* Reset the global timer state. */ +static void openrisc_timer_reset(void *opaque) +{ +or1k_timer->ttcr = 0x; +or1k_timer->last_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +} + static const VMStateDescription vmstate_or1k_timer = { .name = "or1k_timer", .version_id = 1, @@ -136,10 +155,11 @@ static const VMStateDescription vmstate_or1k_timer = { void cpu_openrisc_clock_init(OpenRISCCPU *cpu) { cpu->env.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &openrisc_timer_cb, cpu); -cpu->env.ttmr = 0x; +qemu_register_reset(openrisc_count_reset, cpu); if (or1k_timer == NULL) { or1k_timer = g_new0(OR1KTimerState, 1); +qemu_register_reset(openrisc_timer_reset, cpu); vmstate_register(NULL, 0, &vmstate_or1k_timer, or1k_timer); } } -- 2.37.1
[PATCH v3 09/11] target/openrisc: Interrupt handling fixes
When running SMP systems we sometimes were seeing lockups where IPI interrupts were being raised by never handled. This looks to be caused by 2 issues in the openrisc interrupt handling logic. 1. After clearing an interrupt the openrisc_cpu_set_irq handler will always clear PICSR. This is not correct as masked interrupts should still be visible in PICSR. 2. After setting PICMR (mask register) and exposed interrupts should cause an interrupt to be raised. This was not being done so add it. This patch fixes both issues. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- Since v2: - Added Reviewed-by target/openrisc/cpu.c| 1 - target/openrisc/sys_helper.c | 7 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 41d1b2a24a..cb9f35f408 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -98,7 +98,6 @@ static void openrisc_cpu_set_irq(void *opaque, int irq, int level) cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); -cpu->env.picsr = 0; } } #endif diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index da88ad9e77..09b3c97d7c 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -139,6 +139,13 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) break; case TO_SPR(9, 0): /* PICMR */ env->picmr = rb; +qemu_mutex_lock_iothread(); +if (env->picsr & env->picmr) { +cpu_interrupt(cs, CPU_INTERRUPT_HARD); +} else { +cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); +} +qemu_mutex_unlock_iothread(); break; case TO_SPR(9, 2): /* PICSR */ env->picsr &= ~rb; -- 2.37.1
[PATCH v3 01/11] hw/openrisc: Split re-usable boot time apis out to boot.c
These will be shared with the virt platform. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- Since v2: - No changes hw/openrisc/boot.c | 117 + hw/openrisc/meson.build| 1 + hw/openrisc/openrisc_sim.c | 106 ++--- include/hw/openrisc/boot.h | 34 +++ 4 files changed, 158 insertions(+), 100 deletions(-) create mode 100644 hw/openrisc/boot.c create mode 100644 include/hw/openrisc/boot.h diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c new file mode 100644 index 00..ca773b385e --- /dev/null +++ b/hw/openrisc/boot.c @@ -0,0 +1,117 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * QEMU OpenRISC boot helpers. + * + * (c) 2022 Stafford Horne + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/cpu-defs.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/openrisc/boot.h" +#include "sysemu/device_tree.h" +#include "sysemu/qtest.h" + +#include + +#define KERNEL_LOAD_ADDR 0x100 + +hwaddr openrisc_load_kernel(ram_addr_t ram_size, +const char *kernel_filename, +uint32_t *bootstrap_pc) +{ +long kernel_size; +uint64_t elf_entry; +uint64_t high_addr; +hwaddr entry; + +if (kernel_filename && !qtest_enabled()) { +kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, + &elf_entry, NULL, &high_addr, NULL, 1, + EM_OPENRISC, 1, 0); +entry = elf_entry; +if (kernel_size < 0) { +kernel_size = load_uimage(kernel_filename, + &entry, NULL, NULL, NULL, NULL); +high_addr = entry + kernel_size; +} +if (kernel_size < 0) { +kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); +high_addr = KERNEL_LOAD_ADDR + kernel_size; +} + +if (entry <= 0) { +entry = KERNEL_LOAD_ADDR; +} + +if (kernel_size < 0) { +error_report("couldn't load the kernel '%s'", kernel_filename); +exit(1); +} +*bootstrap_pc = entry; + +return high_addr; +} +return 0; +} + +hwaddr openrisc_load_initrd(void *fdt, const char *filename, +hwaddr load_start, uint64_t mem_size) +{ +int size; +hwaddr start; + +/* We put the initrd right after the kernel; page aligned. */ +start = TARGET_PAGE_ALIGN(load_start); + +size = load_ramdisk(filename, start, mem_size - start); +if (size < 0) { +size = load_image_targphys(filename, start, mem_size - start); +if (size < 0) { +error_report("could not load ramdisk '%s'", filename); +exit(1); +} +} + +if (fdt) { +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-start", start); +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-end", start + size); +} + +return start + size; +} + +uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start, + uint64_t mem_size) +{ +uint32_t fdt_addr; +int ret; +int fdtsize = fdt_totalsize(fdt); + +if (fdtsize <= 0) { +error_report("invalid device-tree"); +exit(1); +} + +/* We put fdt right after the kernel and/or initrd. */ +fdt_addr = TARGET_PAGE_ALIGN(load_start); + +ret = fdt_pack(fdt); +/* Should only fail if we've built a corrupted tree */ +g_assert(ret == 0); +/* copy in the device tree */ +qemu_fdt_dumpdtb(fdt, fdtsize); + +rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, + &address_space_memory); + +return fdt_addr; +} + diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ec48172c9d..ab563820c5 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -1,5 +1,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) +openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 35adce17ac..35da123aef 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -24,10 +24,9 @@ #include "cpu.h" #include "hw/irq.h" #include "hw/boards.h" -#include "elf.h" #include "hw/char/serial.h"
[PATCH v3 02/11] target/openrisc: Fix memory reading in debugger
In commit f0655423ca ("target/openrisc: Reorg tlb lookup") data and instruction TLB reads were combined. This, broke debugger reads where we first tried to map using the data tlb then fall back to the instruction tlb. This patch replicates this logic by first requesting a PAGE_READ protection mapping then falling back to PAGE_EXEC. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- Since v2: - No changes, added Reviewed-by target/openrisc/mmu.c | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c index d7e1320998..0b8afdbacf 100644 --- a/target/openrisc/mmu.c +++ b/target/openrisc/mmu.c @@ -148,7 +148,13 @@ hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) case SR_DME | SR_IME: /* The mmu is definitely enabled. */ excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, -PAGE_EXEC | PAGE_READ | PAGE_WRITE, +PAGE_READ, +(sr & SR_SM) != 0); +if (!excp) { +return phys_addr; +} +excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, +PAGE_EXEC, (sr & SR_SM) != 0); return excp ? -1 : phys_addr; -- 2.37.1
[PATCH v3 07/11] target/openrisc: Add interrupted CPU to log
When we are tracing it's helpful to know which CPU's are getting interrupted, add that detail to the log line. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- Since v2: - Added Reviewed-by target/openrisc/interrupt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index e5724f5371..c31c6f12c4 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -83,7 +83,9 @@ void openrisc_cpu_do_interrupt(CPUState *cs) [EXCP_TRAP] = "TRAP", }; -qemu_log_mask(CPU_LOG_INT, "INT: %s\n", int_name[exception]); +qemu_log_mask(CPU_LOG_INT, "CPU: %d INT: %s\n", + cs->cpu_index, + int_name[exception]); hwaddr vect_pc = exception << 8; if (env->cpucfgr & CPUCFGR_EVBARP) { -- 2.37.1
[PATCH v3 05/11] hw/openrisc: Add PCI bus support to virt
This is mostly borrowed from xtensa and riscv as examples. The create_pcie_irq_map swizzle function is almost and exact copy but here we use a single cell interrupt, possibly we can make this generic. Signed-off-by: Stafford Horne --- Since v2: - No changes hw/openrisc/Kconfig | 3 + hw/openrisc/virt.c | 160 ++-- 2 files changed, 157 insertions(+), 6 deletions(-) diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 202134668e..97af258b55 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -7,8 +7,11 @@ config OR1K_SIM config OR1K_VIRT bool +imply PCI_DEVICES imply VIRTIO_VGA imply TEST_DEVICES +select PCI +select PCI_EXPRESS_GENERIC_BRIDGE select GOLDFISH_RTC select SERIAL select SIFIVE_TEST diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index 54f2732a6b..9a78234a28 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -17,6 +17,8 @@ #include "hw/core/split-irq.h" #include "hw/openrisc/boot.h" #include "hw/misc/sifive_test.h" +#include "hw/pci/pci.h" +#include "hw/pci-host/gpex.h" #include "hw/qdev-properties.h" #include "hw/rtc/goldfish_rtc.h" #include "hw/sysbus.h" @@ -47,6 +49,9 @@ typedef struct OR1KVirtState { enum { VIRT_DRAM, +VIRT_ECAM, +VIRT_MMIO, +VIRT_PIO, VIRT_TEST, VIRT_RTC, VIRT_VIRTIO, @@ -60,6 +65,7 @@ enum { VIRT_RTC_IRQ = 3, VIRT_VIRTIO_IRQ = 4, /* to 12 */ VIRTIO_COUNT = 8, +VIRT_PCI_IRQ_BASE = 13, /* to 17 */ }; static const struct MemmapEntry { @@ -72,6 +78,9 @@ static const struct MemmapEntry { [VIRT_RTC] = { 0x96005000, 0x1000 }, [VIRT_VIRTIO] ={ 0x9700, 0x1000 }, [VIRT_OMPIC] = { 0x9800, VIRT_CPUS_MAX * 8 }, +[VIRT_ECAM] = { 0x9e00, 0x100 }, +[VIRT_PIO] = { 0x9f00, 0x100 }, +[VIRT_MMIO] = { 0xa000, 0x1000 }, }; static struct openrisc_boot_info { @@ -115,12 +124,12 @@ static qemu_irq get_per_cpu_irq(OpenRISCCPU *cpus[], int num_cpus, int irq_pin) static void openrisc_create_fdt(OR1KVirtState *state, const struct MemmapEntry *memmap, int num_cpus, uint64_t mem_size, -const char *cmdline) +const char *cmdline, +int32_t *pic_phandle) { void *fdt; int cpu; char *nodename; -int pic_ph; fdt = state->fdt = create_device_tree(&state->fdt_size); if (!fdt) { @@ -163,14 +172,14 @@ static void openrisc_create_fdt(OR1KVirtState *state, nodename = (char *)"/pic"; qemu_fdt_add_subnode(fdt, nodename); -pic_ph = qemu_fdt_alloc_phandle(fdt); +*pic_phandle = qemu_fdt_alloc_phandle(fdt); qemu_fdt_setprop_string(fdt, nodename, "compatible", "opencores,or1k-pic-level"); qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1); qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); -qemu_fdt_setprop_cell(fdt, nodename, "phandle", pic_ph); +qemu_fdt_setprop_cell(fdt, nodename, "phandle", *pic_phandle); -qemu_fdt_setprop_cell(fdt, "/", "interrupt-parent", pic_ph); +qemu_fdt_setprop_cell(fdt, "/", "interrupt-parent", *pic_phandle); qemu_fdt_add_subnode(fdt, "/chosen"); if (cmdline) { @@ -275,6 +284,7 @@ static void openrisc_virt_test_init(OR1KVirtState *state, hwaddr base, g_free(nodename); } + static void openrisc_virt_rtc_init(OR1KVirtState *state, hwaddr base, hwaddr size, int num_cpus, OpenRISCCPU *cpus[], int irq_pin) @@ -296,6 +306,134 @@ static void openrisc_virt_rtc_init(OR1KVirtState *state, hwaddr base, g_free(nodename); } + +static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, +uint32_t irqchip_phandle) +{ +int pin, dev; +uint32_t irq_map_stride = 0; +uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] = {}; +uint32_t *irq_map = full_irq_map; + +/* + * This code creates a standard swizzle of interrupts such that + * each device's first interrupt is based on it's PCI_SLOT number. + * (See pci_swizzle_map_irq_fn()) + * + * We only need one entry per interrupt in the table (not one per + * possible slot) seeing the interrupt-map-mask will allow the table + * to wrap to any number of devices. + */ +for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { +int devfn = dev << 3; + +for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { +int irq_nr = irq_base + ((pin + PCI_SLOT(dev
[PATCH v3 10/11] hw/openrisc: virt: pass random seed to fdt
From: "Jason A. Donenfeld" If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to initialize early. Set this using the usual guest random number generation function. This is confirmed to successfully initialize the RNG on Linux 5.19-rc2. Signed-off-by: Jason A. Donenfeld Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- Since v2: - No changes hw/openrisc/virt.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index 9a78234a28..f8a68a6a6b 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qemu/guest-random.h" #include "qapi/error.h" #include "cpu.h" #include "exec/address-spaces.h" @@ -130,6 +131,7 @@ static void openrisc_create_fdt(OR1KVirtState *state, void *fdt; int cpu; char *nodename; +uint8_t rng_seed[32]; fdt = state->fdt = create_device_tree(&state->fdt_size); if (!fdt) { @@ -186,6 +188,10 @@ static void openrisc_create_fdt(OR1KVirtState *state, qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); } +/* Pass seed to RNG. */ +qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); +qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + /* Create aliases node for use by devices. */ qemu_fdt_add_subnode(fdt, "/aliases"); } -- 2.37.1
[PATCH v3 03/11] goldfish_rtc: Add big-endian property
Add a new property "big-endian" to allow configuring the RTC as either little or big endian, the default is little endian. Currently overriding the default to big endian is only used by the m68k virt platform. New platforms should prefer to use little endian and not set this. Cc: Laurent Vivier Reviewed-by: Anup Patel Signed-off-by: Stafford Horne --- Since v2: - Added Reviewed-by - Changed from enum property to boolean as suggested by Richard hw/m68k/virt.c| 1 + hw/rtc/goldfish_rtc.c | 37 ++- include/hw/rtc/goldfish_rtc.h | 2 ++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index 0aa383fa6b..c7a6c766e3 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -173,6 +173,7 @@ static void virt_init(MachineState *machine) io_base = VIRT_GF_RTC_MMIO_BASE; for (i = 0; i < VIRT_GF_RTC_NB; i++) { dev = qdev_new(TYPE_GOLDFISH_RTC); +qdev_prop_set_bit(dev, "big-endian", true); sysbus = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, io_base); diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 35e493be31..19a56402a0 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -216,14 +216,25 @@ static int goldfish_rtc_post_load(void *opaque, int version_id) return 0; } -static const MemoryRegionOps goldfish_rtc_ops = { -.read = goldfish_rtc_read, -.write = goldfish_rtc_write, -.endianness = DEVICE_NATIVE_ENDIAN, -.valid = { -.min_access_size = 4, -.max_access_size = 4 -} +static const MemoryRegionOps goldfish_rtc_ops[2] = { +[false] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_LITTLE_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, +[true] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_BIG_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, }; static const VMStateDescription goldfish_rtc_vmstate = { @@ -265,7 +276,8 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) SysBusDevice *dev = SYS_BUS_DEVICE(d); GoldfishRTCState *s = GOLDFISH_RTC(d); -memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_rtc_ops, s, +memory_region_init_io(&s->iomem, OBJECT(s), + &goldfish_rtc_ops[s->big_endian], s, "goldfish_rtc", 0x24); sysbus_init_mmio(dev, &s->iomem); @@ -274,10 +286,17 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s); } +static Property goldfish_rtc_properties[] = { +DEFINE_PROP_BOOL("big-endian", GoldfishRTCState, big_endian, + false), +DEFINE_PROP_END_OF_LIST(), +}; + static void goldfish_rtc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); +device_class_set_props(dc, goldfish_rtc_properties); dc->realize = goldfish_rtc_realize; dc->reset = goldfish_rtc_reset; dc->vmsd = &goldfish_rtc_vmstate; diff --git a/include/hw/rtc/goldfish_rtc.h b/include/hw/rtc/goldfish_rtc.h index 79ca7daf5d..162be33863 100644 --- a/include/hw/rtc/goldfish_rtc.h +++ b/include/hw/rtc/goldfish_rtc.h @@ -42,6 +42,8 @@ struct GoldfishRTCState { uint32_t irq_pending; uint32_t irq_enabled; uint32_t time_high; + +bool big_endian; }; #endif -- 2.37.1
[PATCH v3 08/11] target/openrisc: Enable MTTCG
This patch enables multithread TCG for OpenRISC. Since the or1k shared syncrhonized timer can be updated from each vCPU via helpers we use a mutex to synchronize updates. Signed-off-by: Stafford Horne --- Since v2: - Removed cpu_openrisc_timer_has_advanced lock optimization, measuring revealed it did not help much. configs/targets/or1k-softmmu.mak | 1 + target/openrisc/cpu.h| 2 ++ target/openrisc/sys_helper.c | 7 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/configs/targets/or1k-softmmu.mak b/configs/targets/or1k-softmmu.mak index 263e970870..432f855a30 100644 --- a/configs/targets/or1k-softmmu.mak +++ b/configs/targets/or1k-softmmu.mak @@ -1,3 +1,4 @@ TARGET_ARCH=openrisc +TARGET_SUPPORTS_MTTCG=y TARGET_BIG_ENDIAN=y TARGET_NEED_FDT=y diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index b9584f10d4..1d5efa5ca2 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -25,6 +25,8 @@ #include "hw/core/cpu.h" #include "qom/object.h" +#define TCG_GUEST_DEFAULT_MO (0) + #define TYPE_OPENRISC_CPU "or1k-cpu" OBJECT_DECLARE_CPU_TYPE(OpenRISCCPU, OpenRISCCPUClass, OPENRISC_CPU) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 48674231e7..da88ad9e77 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -145,6 +145,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) break; case TO_SPR(10, 0): /* TTMR */ { +qemu_mutex_lock_iothread(); if ((env->ttmr & TTMR_M) ^ (rb & TTMR_M)) { switch (rb & TTMR_M) { case TIMER_NONE: @@ -168,14 +169,16 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) env->ttmr = rb & ~TTMR_IP; cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; } - cpu_openrisc_timer_update(cpu); +qemu_mutex_unlock_iothread(); } break; case TO_SPR(10, 1): /* TTCR */ +qemu_mutex_lock_iothread(); cpu_openrisc_count_set(cpu, rb); cpu_openrisc_timer_update(cpu); +qemu_mutex_unlock_iothread(); break; #endif @@ -303,7 +306,9 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, return env->ttmr; case TO_SPR(10, 1): /* TTCR */ +qemu_mutex_lock_iothread(); cpu_openrisc_count_update(cpu); +qemu_mutex_unlock_iothread(); return cpu_openrisc_count_get(cpu); #endif -- 2.37.1
[PATCH v3 11/11] docs/system: openrisc: Add OpenRISC documentation
Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- Since v2; - Added Reviewed-by docs/system/openrisc/cpu-features.rst | 15 ++ docs/system/openrisc/emulation.rst| 17 +++ docs/system/openrisc/or1k-sim.rst | 43 docs/system/openrisc/virt.rst | 50 +++ docs/system/target-openrisc.rst | 72 +++ docs/system/targets.rst | 1 + 6 files changed, 198 insertions(+) create mode 100644 docs/system/openrisc/cpu-features.rst create mode 100644 docs/system/openrisc/emulation.rst create mode 100644 docs/system/openrisc/or1k-sim.rst create mode 100644 docs/system/openrisc/virt.rst create mode 100644 docs/system/target-openrisc.rst diff --git a/docs/system/openrisc/cpu-features.rst b/docs/system/openrisc/cpu-features.rst new file mode 100644 index 00..aeb65e22ff --- /dev/null +++ b/docs/system/openrisc/cpu-features.rst @@ -0,0 +1,15 @@ +CPU Features + + +The QEMU emulation of the OpenRISC architecture provides following built in +features. + +- Shadow GPRs +- MMU TLB with 128 entries, 1 way +- Power Management (PM) +- Programmable Interrupt Controller (PIC) +- Tick Timer + +These features are on by default and the presence can be confirmed by checking +the contents of the Unit Presence Register (``UPR``) and CPU Configuration +Register (``CPUCFGR``). diff --git a/docs/system/openrisc/emulation.rst b/docs/system/openrisc/emulation.rst new file mode 100644 index 00..0af898ab20 --- /dev/null +++ b/docs/system/openrisc/emulation.rst @@ -0,0 +1,17 @@ +OpenRISC 1000 CPU architecture support +== + +QEMU's TCG emulation includes support for the OpenRISC or1200 implementation of +the OpenRISC 1000 cpu architecture. + +The or1200 cpu also has support for the following instruction subsets: + +- ORBIS32 (OpenRISC Basic Instruction Set) +- ORFPX32 (OpenRISC Floating-Point eXtension) + +In addition to the instruction subsets the QEMU TCG emulation also has support +for most Class II (optional) instructions. + +For information on all OpenRISC instructions please refer to the latest +architecture manual available on the OpenRISC website in the +`OpenRISC Architecture <https://openrisc.io/architecture>`_ section. diff --git a/docs/system/openrisc/or1k-sim.rst b/docs/system/openrisc/or1k-sim.rst new file mode 100644 index 00..ef10439737 --- /dev/null +++ b/docs/system/openrisc/or1k-sim.rst @@ -0,0 +1,43 @@ +Or1ksim board += + +The QEMU Or1ksim machine emulates the standard OpenRISC board simulator which is +also the standard SoC configuration. + +Supported devices +- + + * 16550A UART + * ETHOC Ethernet controller + * SMP (OpenRISC multicore using ompic) + +Boot options + + +The Or1ksim machine can be started using the ``-kernel`` and ``-initrd`` options +to load a Linux kernel and optional disk image. + +.. code-block:: bash + + $ qemu-system-or1k -cpu or1220 -M or1k-sim -nographic \ +-kernel vmlinux \ +-initrd initramfs.cpio.gz \ +-m 128 + +Linux guest kernel configuration +"""""""""""""""""""""""""""""""" + +The 'or1ksim_defconfig' for Linux openrisc kernels includes the right +drivers for the or1ksim machine. If you would like to run an SMP system +choose the 'simple_smp_defconfig' config. + +Hardware configuration information +"""""""""""""""""""""""""""""""""" + +The ``or1k-sim`` board automatically generates a device tree blob ("dtb") +which it passes to the guest. This provides information about the +addresses, interrupt lines and other configuration of the various devices +in the system. + +The location of the DTB will be passed in register ``r3`` to the guest operating +system. diff --git a/docs/system/openrisc/virt.rst b/docs/system/openrisc/virt.rst new file mode 100644 index 00..2fe61ac942 --- /dev/null +++ b/docs/system/openrisc/virt.rst @@ -0,0 +1,50 @@ +'virt' generic virtual platform +=== + +The ``virt`` board is a platform which does not correspond to any +real hardware; it is designed for use in virtual machines. +It is the recommended board type if you simply want to run +a guest such as Linux and do not care about reproducing the +idiosyncrasies and limitations of a particular bit of real-world +hardware. + +Supported devices +- + + * PCI/PCIe devices + * 8 virtio-mmio transport devices + * 16550A UART + * Goldfish RTC + * SiFive Test device for poweroff and reboot + * SMP (OpenRISC multicore using ompic) + +Boot options +---
Re: [PATCH v3 08/11] target/openrisc: Enable MTTCG
On Fri, Jul 29, 2022 at 04:42:54PM -0700, Richard Henderson wrote: > On 7/29/22 16:01, Stafford Horne wrote: > > This patch enables multithread TCG for OpenRISC. Since the or1k shared > > syncrhonized timer can be updated from each vCPU via helpers we use a > > mutex to synchronize updates. > > > > Signed-off-by: Stafford Horne > > --- > > Since v2: > > - Removed cpu_openrisc_timer_has_advanced lock optimization, measuring > > revealed > > it did not help much. > > > > configs/targets/or1k-softmmu.mak | 1 + > > target/openrisc/cpu.h| 2 ++ > > target/openrisc/sys_helper.c | 7 ++- > > 3 files changed, 9 insertions(+), 1 deletion(-) > > Reviewed-by: Richard Henderson Thank you, I guess this whole series is a bit late for 7.1.0 now. I will post the PR after 7.1.0 is released and target it for 7.2.0. -Stafford
[PATCH] target/openrisc: Set EPCR to next PC on FPE exceptions
The architecture specification calls for the EPCR to be set to "Address of next not executed instruction" when there is a floating point exception (FPE). This was not being done, so fix it by using the same method as syscall. Note, this may need a lot more work if we start seeing floating point operations in delay slots which exceptions enabled. Without this patch FPU exceptions will loop, as the exception hanlding will always return back to the failed floating point instruction. This was not noticed in earlier testing because: 1. The compiler usually generates code which clobbers the input operand such as: lf.div.s r19,r17,r19 2. The target will store the operation output before to the register before handling the exception. So an operation such as: float a = 100.0f; float b = 0.0f; float c = a / b;/* lf.div.s r19,r17,r19 */ Will first execute: 100 / 0-> Store inf to c (r19) -> triggering divide by zero exception -> handle and return Then it will exectute: 100 / inf -> Store 0 to c (no exception) To confirm the looping behavoid and the fix I used the following: float fpu_div(float a, float b) { float c; asm volatile("lf.div.s %0, %1, %2" : "+r" (c) : "r" (a), "r" (b)); return c; } Signed-off-by: Stafford Horne --- target/openrisc/interrupt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index 3887812810..9b14b8a2c6 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -34,7 +34,7 @@ void openrisc_cpu_do_interrupt(CPUState *cs) int exception = cs->exception_index; env->epcr = env->pc; -if (exception == EXCP_SYSCALL) { +if (exception == EXCP_SYSCALL || exception == EXCP_FPE) { env->epcr += 4; } /* When we have an illegal instruction the error effective address -- 2.39.1
Re: [PATCH] target/openrisc: Set EPCR to next PC on FPE exceptions
On Sat, Jul 29, 2023 at 10:08:51PM +0100, Stafford Horne wrote: > The architecture specification calls for the EPCR to be set to "Address > of next not executed instruction" when there is a floating point > exception (FPE). This was not being done, so fix it by using the same > method as syscall. Note, this may need a lot more work if we start > seeing floating point operations in delay slots which exceptions > enabled. It should be "with exceptions enabled." > > Without this patch FPU exceptions will loop, as the exception hanlding "handling" > will always return back to the failed floating point instruction. > > This was not noticed in earlier testing because: > > 1. The compiler usually generates code which clobbers the input operand > such as: > > lf.div.s r19,r17,r19 > > 2. The target will store the operation output before to the register > before handling the exception. So an operation such as: > > float a = 100.0f; > float b = 0.0f; > float c = a / b;/* lf.div.s r19,r17,r19 */ > > Will first execute: > > 100 / 0-> Store inf to c (r19) > -> triggering divide by zero exception > -> handle and return > > Then it will exectute: > > 100 / inf -> Store 0 to c (no exception) > > To confirm the looping behavoid and the fix I used the following: "behavior" > float fpu_div(float a, float b) { > float c; > asm volatile("lf.div.s %0, %1, %2" > : "+r" (c) > : "r" (a), "r" (b)); > return c; > } > > Signed-off-by: Stafford Horne -Stafford > --- > target/openrisc/interrupt.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c > index 3887812810..9b14b8a2c6 100644 > --- a/target/openrisc/interrupt.c > +++ b/target/openrisc/interrupt.c > @@ -34,7 +34,7 @@ void openrisc_cpu_do_interrupt(CPUState *cs) > int exception = cs->exception_index; > > env->epcr = env->pc; > -if (exception == EXCP_SYSCALL) { > +if (exception == EXCP_SYSCALL || exception == EXCP_FPE) { > env->epcr += 4; > } > /* When we have an illegal instruction the error effective address > -- > 2.39.1 >
Re: [PATCH] target/openrisc: Set EPCR to next PC on FPE exceptions
On Sun, Jul 30, 2023 at 10:43:45AM -0700, Richard Henderson wrote: > On 7/29/23 14:08, Stafford Horne wrote: > > The architecture specification calls for the EPCR to be set to "Address > > of next not executed instruction" when there is a floating point > > exception (FPE). This was not being done, so fix it by using the same > > method as syscall. Note, this may need a lot more work if we start > > seeing floating point operations in delay slots which exceptions > > enabled. > > > > Without this patch FPU exceptions will loop, as the exception hanlding > > will always return back to the failed floating point instruction. > > > > This was not noticed in earlier testing because: > > > > 1. The compiler usually generates code which clobbers the input operand > > such as: > > > >lf.div.s r19,r17,r19 > > > > 2. The target will store the operation output before to the register > > before handling the exception. So an operation such as: > > > >float a = 100.0f; > >float b = 0.0f; > >float c = a / b;/* lf.div.s r19,r17,r19 */ > > > > Will first execute: > > > >100 / 0-> Store inf to c (r19) > > -> triggering divide by zero exception > > -> handle and return > > > > Then it will exectute: > > > >100 / inf -> Store 0 to c (no exception) > > > > To confirm the looping behavoid and the fix I used the following: > > > > float fpu_div(float a, float b) { > > float c; > > asm volatile("lf.div.s %0, %1, %2" > > : "+r" (c) > > : "r" (a), "r" (b)); > > return c; > > } > > > > Signed-off-by: Stafford Horne > > --- > > target/openrisc/interrupt.c | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c > > index 3887812810..9b14b8a2c6 100644 > > --- a/target/openrisc/interrupt.c > > +++ b/target/openrisc/interrupt.c > > @@ -34,7 +34,7 @@ void openrisc_cpu_do_interrupt(CPUState *cs) > > int exception = cs->exception_index; > > env->epcr = env->pc; > > -if (exception == EXCP_SYSCALL) { > > +if (exception == EXCP_SYSCALL || exception == EXCP_FPE) { > > env->epcr += 4; > > } > > /* When we have an illegal instruction the error effective address > > According to Table 6-3, when in a delay slot the EPCR should be the address > of the jump, for both syscall and fpe. This whole block should be moved > down... > > > /* Set/clear dsx to indicate if we are in a delay slot exception. */ > > if (env->dflag) { > > env->dflag = 0; > > env->sr |= SR_DSX; > > env->epcr -= 4; > > } else { > > env->sr &= ~SR_DSX; > > } > > ... into the else. Thanks for looking at this. This is correct. I will fix it this way, though this points to an issue in the architecture (in the manual as "Particular delay slot issues"). If we have instructions causing exceptions in delay slots like l.sys it will cause looping. > With that, > Reviewed-by: Richard Henderson Thank you. -Stafford
[PATCH v2] target/openrisc: Set EPCR to next PC on FPE exceptions
The architecture specification calls for the EPCR to be set to "Address of next not executed instruction" when there is a floating point exception (FPE). This was not being done, so fix it by using the same pattern as syscall. Also, we move this logic down to be done for instructions not in the delay slot as called for by the architecture manual. Without this patch FPU exceptions will loop, as the exception handling will always return back to the failed floating point instruction. This was not noticed in earlier testing because: 1. The compiler usually generates code which clobbers the input operand such as: lf.div.s r19,r17,r19 2. The target will store the operation output before to the register before handling the exception. So an operation such as: float a = 100.0f; float b = 0.0f; float c = a / b;/* lf.div.s r19,r17,r19 */ Will first execute: 100 / 0-> Store inf to c (r19) -> triggering divide by zero exception -> handle and return Then it will execute: 100 / inf -> Store 0 to c (no exception) To confirm the looping behavior and the fix I used the following: float fpu_div(float a, float b) { float c; asm volatile("lf.div.s %0, %1, %2" : "+r" (c) : "r" (a), "r" (b)); return c; } Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- target/openrisc/interrupt.c | 7 --- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index 3887812810..d4fdb8ce8e 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -34,9 +34,7 @@ void openrisc_cpu_do_interrupt(CPUState *cs) int exception = cs->exception_index; env->epcr = env->pc; -if (exception == EXCP_SYSCALL) { -env->epcr += 4; -} + /* When we have an illegal instruction the error effective address shall be set to the illegal instruction address. */ if (exception == EXCP_ILLEGAL) { @@ -63,6 +61,9 @@ void openrisc_cpu_do_interrupt(CPUState *cs) env->epcr -= 4; } else { env->sr &= ~SR_DSX; +if (exception == EXCP_SYSCALL || exception == EXCP_FPE) { +env->epcr += 4; +} } if (exception > 0 && exception < EXCP_NR) { -- 2.39.1
Re: [Qemu-devel] [PATCH] target/openrisc: Fix LGPL information in the file headers
Hello, On Mon, May 06, 2019 at 07:53:45AM +0200, Thomas Huth wrote: > On 13/02/2019 16.59, Thomas Huth wrote: > > It's either "GNU *Library* General Public License version 2" or "GNU > > Lesser General Public License version *2.1*", but there was no "version > > 2.0" of the "Lesser" license. So assume that version 2.1 is meant here. Acked-by: Stafford Horne > > Signed-off-by: Thomas Huth > > --- > > hw/openrisc/cputimer.c | 2 +- > > hw/openrisc/openrisc_sim.c | 2 +- > > hw/openrisc/pic_cpu.c| 2 +- > > linux-user/openrisc/target_cpu.h | 2 +- > > linux-user/openrisc/target_structs.h | 2 +- > > target/openrisc/cpu.h| 2 +- > > target/openrisc/exception.c | 2 +- > > target/openrisc/exception_helper.c | 2 +- > > target/openrisc/fpu_helper.c | 2 +- > > target/openrisc/insns.decode | 2 +- > > target/openrisc/interrupt.c | 2 +- > > target/openrisc/machine.c| 2 +- > > target/openrisc/mmu.c| 2 +- > > 13 files changed, 13 insertions(+), 13 deletions(-) > > [...] > > > > Ping? Sorry, I must have missed this. What is your plan for sending upstream? I don't really have anything in my queue right now so if you have another queue that would be great. If not let me know and I can queue it. -Stafford
Re: [Qemu-devel] [PATCH 2/3] MAINTAINERS: Improve section headlines
On Thu, Jun 06, 2019 at 07:01:49PM +0200, Markus Armbruster wrote: Stafford Horne writes: On Mon, Jun 03, 2019 at 10:45:14AM +0200, Philippe Mathieu-Daudé wrote: On 5/31/19 5:36 AM, Stafford Horne wrote: > On Wed, May 29, 2019 at 05:08:52PM +0200, Markus Armbruster wrote: >> When scripts/get_maintainer.pl reports something like >> >> John Doe (maintainer:Overall) >> >> the user is left to wonder *which* of our three "Overall" sections >> applies. We have three, one each under "Guest CPU cores (TCG)", >> "Guest CPU Cores (KVM)", and "Overall usermode emulation". >> >> Rename sections under >> >> * "Guest CPU cores (TCG)" from "FOO" to "FOO CPU cores (TCG)" >> >> * "Guest CPU Cores (KVM)" from "FOO" to "FOO CPU cores (KVM)" >> >> * "Guest CPU Cores (Xen)" from "FOO" to "FOO CPU cores (Xen)" >> >> * "Architecture support" from "FOO" to "FOO general architecture >> support" >> >> * "Tiny Code Generator (TCG)" from "FOO target" to "FOO TCG target" >> >> While there, >> >> Signed-off-by: Markus Armbruster >> --- >> MAINTAINERS | 78 ++--- >> 1 file changed, 39 insertions(+), 39 deletions(-) > > ... > >> -OpenRISC >> +OpenRISC CPU cores (TCG) >> M: Stafford Horne >> S: Odd Fixes >> F: target/openrisc/ >> F: hw/openrisc/ >> F: tests/tcg/openrisc/ >> > > As directories listed there I look over both target/ (TCG?) and hw/. > Would it be better to be 'OpenRISC general architecture'? There is a historical separation between target/ and hw/ because they cover different concepts, and have different maintainers/reviewers. - target/$arch/ is for TCG/KVM - hw/ is for machines and their devices (some devices are reused by multiple archs) Although the separation is not always clear (some devices are tied to an architecture, some architecture instruction directly access devices) I'd prefer we keep 2 distincts MAINTAINERS sections (keeping you maintainer of both). This will ease developper with specific background/interests to volunteer to a particular section. Hello, Thanks for the explaination. I think it makes sense to have 2 different maintainer sections. In that case should this patch be amended to move the 'F: hw/openrisc/' etc out to a different section with the different header? This patch merely improves headlines. Splitting up the OpenRISC section above should be separate. Care to send the patch? Sure, now that I look at it, there is a section for 'OpenRISC Machines' and the maintainer is out of date. -Stafford
Re: [Qemu-devel] Maintainers, please tell us how to boot your machines!
On Tue, Mar 12, 2019 at 06:36:05PM +0100, Markus Armbruster wrote: > = hw/openrisc/openrisc_sim.c = > Jia Liu (maintainer:or1k-sim) > Stafford Horne (odd fixer:OpenRISC) For OpenRISC the main test I do is booting linux. The steps and a link to a system image are described here: https://wiki.qemu.org/Documentation/Platforms/OpenRISC I just confirmed with the latest QEMU and it works well. For good measure, we probably should have an SMP kernel as well and try to boot both so we would have 2 test cases. I will update the wiki to add SMP. Let me know if you need me to create patches for the automated tests. -Stafford
Re: [PATCH 0/9] linux-user: Update syscall numbers to kernel 5.5 level
On Tue, Feb 04, 2020 at 01:07:29PM +0100, Aleksandar Markovic wrote: > From: Aleksandar Markovic > > This series also doesn't cover following files (since I can't find > corresponding kernel code - and I am also asking corresponding > target maintainers or Lauren to update them, if possible, before > our 5.0 release): OpenRISC is in the kernel under arch/openrisc and the syscall numbers we user are just like other architectures, it's in: linux/arch/openrisc/include/uapi/asm/unistd.h This then includes the generic numbers: linux/include/uapi/asm-generic/unistd.h There are other architectures in the kernel, like arm64, risvc, nios2 using the generic syscall numbers. Should QEMU also have linux-user/generic/syscall_nr.h that mirrors the generic file in linux? This way this could be maintained in just one place. > - linux-user/cris/cpu_loop.c > - linux-user/hppa/syscall_nr.h > - linux-user/openrisc/syscall_nr.h > - linux-user/tilegx/syscall_nr.h > > CC: Edgar E. Iglesias > CC: Richard Henderson > CC: Stafford Horne > > Again, I don't plan (I am really running out of time resources) to > work in a significant way on this issue any more, and I am asking > you guys other maintainers to help finish updating syscall numbers > before QEMU 5.0 release. I actually have a patch to add syscall numbers for openrisc which I am using to test our new glibc port right now. I will clean if up and submit for review. It looks like for 5.0 we would need to get changes in by March 23: https://wiki.qemu.org/Planning/5.0 I'll try to aim to get my change up for review soon then. -Stafford
[PATCH v2 1/3] target/openrisc: Allow fpcsr access in user mode
As per OpenRISC spec 1.4 FPCSR can be read and written in user mode. Update mtspr and mfspr helpers to support this by moving the is_user check into the helper. Link: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf Signed-off-by: Stafford Horne --- Since v1: - Update commit message to remove text about no-existant logic change. target/openrisc/sys_helper.c | 45 +- target/openrisc/translate.c | 72 2 files changed, 67 insertions(+), 50 deletions(-) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index ec145960e3..8a0259c710 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -29,17 +29,37 @@ #define TO_SPR(group, number) (((group) << 11) + (number)) +static inline bool is_user(CPUOpenRISCState *env) +{ +#ifdef CONFIG_USER_ONLY +return true; +#else +return (env->sr & SR_SM) == 0; +#endif +} + void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) { -#ifndef CONFIG_USER_ONLY OpenRISCCPU *cpu = env_archcpu(env); +#ifndef CONFIG_USER_ONLY CPUState *cs = env_cpu(env); target_ulong mr; int idx; #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +cpu_set_fpcsr(env, rb); +return; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 11): /* EVBAR */ env->evbar = rb; break; @@ -187,12 +207,8 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) cpu_openrisc_timer_update(cpu); qemu_mutex_unlock_iothread(); break; -#endif - -case TO_SPR(0, 20): /* FPCSR */ -cpu_set_fpcsr(env, rb); -break; } +#endif } target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, @@ -204,10 +220,22 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, OpenRISCCPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); int idx; +#else +OpenRISCCPU *cpu = env_archcpu(env); #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +return env->fpcsr; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 0): /* VR */ return env->vr; @@ -324,11 +352,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, cpu_openrisc_count_update(cpu); qemu_mutex_unlock_iothread(); return cpu_openrisc_count_get(cpu); -#endif - -case TO_SPR(0, 20): /* FPCSR */ -return env->fpcsr; } +#endif /* for rd is passed in, if rd unchanged, just keep it back. */ return rd; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 76e53c78d4..43ba0cc1ad 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -819,45 +819,12 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a) static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) { -check_r0_write(dc, a->d); - -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr = tcg_temp_new(); - -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -if (dc->delayed_branch) { -tcg_gen_mov_tl(cpu_pc, jmp_pc); -tcg_gen_discard_tl(jmp_pc); -} else { -tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); -} -dc->base.is_jmp = DISAS_EXIT; -} +TCGv spr = tcg_temp_new(); -tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); -gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); -} -return true; -} - -static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) -{ -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr; +check_r0_write(dc, a->d); -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -} -/* For SR, we will need to exit the TB to recognize the new - * exception state. For NPC, in theory this counts as a branch - * (although the SPR only exists for use by an ICE). Save all - * of the cpu state first, allowing it to be overwritten. - */ +if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { +gen_io_start(); if (dc->delayed_branch) { tcg_gen_mov_tl(cpu_pc, jmp_pc); tcg_gen_discard_tl(jmp_pc); @@ -865,11 +832,36 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); } dc->
[PATCH v2 0/3] OpenRISC updates for user space FPU
Since v1: - Fixups suggested by Richard Henderson This series adds support for the FPU related architecture changes defined in architecture spec revision v1.4. - https://openrisc.io/revisions/r1.4 In summary the architecture changes are: - Change FPCSR SPR permissions to allow for reading and writing from user space. - Clarify that FPU underflow detection is done by detecting tininess before rounding. Previous to this series FPCSR reads and writes from user-mode in QEMU would throw an illegal argument exception. The proper behavior should have been to treat these operations as no-ops as the cpu implementations do. As mentioned series changes FPCSR read/write to follow the spec. The series has been tested with the FPU support added in glibc test suite and all math tests are passing. Stafford Horne (3): target/openrisc: Allow fpcsr access in user mode target/openrisc: Set PC to cpu state on FPU exception target/openrisc: Setup FPU for detecting tininess before rounding target/openrisc/cpu.c| 4 ++ target/openrisc/fpu_helper.c | 13 ++- target/openrisc/sys_helper.c | 45 +- target/openrisc/translate.c | 72 4 files changed, 82 insertions(+), 52 deletions(-) -- 2.39.1
[PATCH v2 2/3] target/openrisc: Set PC to cpu state on FPU exception
Store the PC to ensure the correct value can be read in the exception handler. Signed-off-by: Stafford Horne --- Since v1: - Use function do_fpe (similar to do_range) to raise exception. target/openrisc/fpu_helper.c | 13 +++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index f9e34fa2cc..8b81d2f62f 100644 --- a/target/openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c @@ -20,8 +20,8 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/exec-all.h" #include "exec/helper-proto.h" -#include "exception.h" #include "fpu/softfloat.h" static int ieee_ex_to_openrisc(int fexcp) @@ -45,6 +45,15 @@ static int ieee_ex_to_openrisc(int fexcp) return ret; } +static G_NORETURN +void do_fpe(CPUOpenRISCState *env, uintptr_t pc) +{ +CPUState *cs = env_cpu(env); + +cs->exception_index = EXCP_FPE; +cpu_loop_exit_restore(cs, pc); +} + void HELPER(update_fpcsr)(CPUOpenRISCState *env) { int tmp = get_float_exception_flags(&env->fp_status); @@ -55,7 +64,7 @@ void HELPER(update_fpcsr)(CPUOpenRISCState *env) if (tmp) { env->fpcsr |= tmp; if (env->fpcsr & FPCSR_FPEE) { -helper_exception(env, EXCP_FPE); +do_fpe(env, GETPC()); } } } -- 2.39.1
[PATCH v2 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
OpenRISC defines tininess to be detected before rounding. Setup qemu to obey this. Signed-off-by: Stafford Horne --- Since v1: - Remove setting default NaN behavior. I discussed with the FPU developers and they mentioned the OpenRISC hardware should be IEEE compliant when handling and forwarding NaN payloads, and they don't want try change this. target/openrisc/cpu.c | 4 1 file changed, 4 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 0ce4f796fa..61d748cfdc 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -22,6 +22,7 @@ #include "qemu/qemu-print.h" #include "cpu.h" #include "exec/exec-all.h" +#include "fpu/softfloat-helpers.h" #include "tcg/tcg.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) @@ -90,6 +91,9 @@ static void openrisc_cpu_reset_hold(Object *obj) s->exception_index = -1; cpu_set_fpcsr(&cpu->env, 0); +set_float_detect_tininess(float_tininess_before_rounding, + &cpu->env.fp_status); + #ifndef CONFIG_USER_ONLY cpu->env.picmr = 0x; cpu->env.picsr = 0x; -- 2.39.1
Re: [PATCH v2 1/3] target/openrisc: Allow fpcsr access in user mode
On Wed, May 10, 2023 at 05:13:03PM +0100, Richard Henderson wrote: > On 5/10/23 16:32, Stafford Horne wrote: > > void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong > > rb) > > { > > -#ifndef CONFIG_USER_ONLY > > OpenRISCCPU *cpu = env_archcpu(env); > > +#ifndef CONFIG_USER_ONLY > > CPUState *cs = env_cpu(env); > > Pulled cpu out if ifdef here... > > > @@ -204,10 +220,22 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, > > target_ulong rd, > > OpenRISCCPU *cpu = env_archcpu(env); > > CPUState *cs = env_cpu(env); > > int idx; > > +#else > > +OpenRISCCPU *cpu = env_archcpu(env); > > #endif > > But replicated it here. Right, let me make it consistent in this patch. > Otherwise, > Reviewed-by: Richard Henderson Thank you, -Stafford
Re: [PATCH v2 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
On Wed, May 10, 2023 at 05:16:20PM +0100, Richard Henderson wrote: > On 5/10/23 16:32, Stafford Horne wrote: > > OpenRISC defines tininess to be detected before rounding. Setup qemu to > > obey this. > > > > Signed-off-by: Stafford Horne > > --- > > Since v1: > > - Remove setting default NaN behavior. I discussed with the FPU > > developers and > > they mentioned the OpenRISC hardware should be IEEE compliant when > > handling > > and forwarding NaN payloads, and they don't want try change this. > > There is no such thing as IEEE compliant for NaN payloads. > All of that is implementation defined. I see, I haven't yet seen to IEEE 754 spec so I don't know how much is covered. It was incorrect to assume forwarding semantics was covered. > All OpenRISC needs to do is document its intentions (and then double-check > that fpu/softfloat-specialize.c.inc does what is documented). Understood, that makes sense, also reading that code I see how all other architectures are able to ifdef their way to a specific behavior. I will see what our current implementions do and update the spec and qemu as a separate task. > > Anyway, back to this patch, > Reviewed-by: Richard Henderson > > :-) Thank you ^_^ -Stafford
[PATCH v3 2/3] target/openrisc: Set PC to cpu state on FPU exception
Store the PC to ensure the correct value can be read in the exception handler. Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- Since v2: - Add reviewed-by Since v1: - Use function do_fpe (similar to do_range) to raise exception. target/openrisc/fpu_helper.c | 13 +++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index f9e34fa2cc..8b81d2f62f 100644 --- a/target/openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c @@ -20,8 +20,8 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/exec-all.h" #include "exec/helper-proto.h" -#include "exception.h" #include "fpu/softfloat.h" static int ieee_ex_to_openrisc(int fexcp) @@ -45,6 +45,15 @@ static int ieee_ex_to_openrisc(int fexcp) return ret; } +static G_NORETURN +void do_fpe(CPUOpenRISCState *env, uintptr_t pc) +{ +CPUState *cs = env_cpu(env); + +cs->exception_index = EXCP_FPE; +cpu_loop_exit_restore(cs, pc); +} + void HELPER(update_fpcsr)(CPUOpenRISCState *env) { int tmp = get_float_exception_flags(&env->fp_status); @@ -55,7 +64,7 @@ void HELPER(update_fpcsr)(CPUOpenRISCState *env) if (tmp) { env->fpcsr |= tmp; if (env->fpcsr & FPCSR_FPEE) { -helper_exception(env, EXCP_FPE); +do_fpe(env, GETPC()); } } } -- 2.39.1
[PATCH v3 1/3] target/openrisc: Allow fpcsr access in user mode
As per OpenRISC spec 1.4 FPCSR can be read and written in user mode. Update mtspr and mfspr helpers to support this by moving the is_user check into the helper. Link: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- Since v2: - Add reviewed-by - In helper_mfspr bring cpu out of ifdef to avoid replicatig the definition. Originally I left it in the ifdef to avoid having to mix having pointers and the data array defined on the stack. But that's overthinking. Since v1: - Update commit message to remove text about no-existant logic change. target/openrisc/sys_helper.c | 45 -- target/openrisc/translate.c | 72 2 files changed, 66 insertions(+), 51 deletions(-) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index ec145960e3..ccdee3b8be 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -29,17 +29,37 @@ #define TO_SPR(group, number) (((group) << 11) + (number)) +static inline bool is_user(CPUOpenRISCState *env) +{ +#ifdef CONFIG_USER_ONLY +return true; +#else +return (env->sr & SR_SM) == 0; +#endif +} + void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) { -#ifndef CONFIG_USER_ONLY OpenRISCCPU *cpu = env_archcpu(env); +#ifndef CONFIG_USER_ONLY CPUState *cs = env_cpu(env); target_ulong mr; int idx; #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +cpu_set_fpcsr(env, rb); +return; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 11): /* EVBAR */ env->evbar = rb; break; @@ -187,27 +207,33 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) cpu_openrisc_timer_update(cpu); qemu_mutex_unlock_iothread(); break; -#endif - -case TO_SPR(0, 20): /* FPCSR */ -cpu_set_fpcsr(env, rb); -break; } +#endif } target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, target_ulong spr) { +OpenRISCCPU *cpu = env_archcpu(env); #ifndef CONFIG_USER_ONLY uint64_t data[TARGET_INSN_START_WORDS]; MachineState *ms = MACHINE(qdev_get_machine()); -OpenRISCCPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); int idx; #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +return env->fpcsr; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 0): /* VR */ return env->vr; @@ -324,11 +350,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, cpu_openrisc_count_update(cpu); qemu_mutex_unlock_iothread(); return cpu_openrisc_count_get(cpu); -#endif - -case TO_SPR(0, 20): /* FPCSR */ -return env->fpcsr; } +#endif /* for rd is passed in, if rd unchanged, just keep it back. */ return rd; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 76e53c78d4..43ba0cc1ad 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -819,45 +819,12 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a) static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) { -check_r0_write(dc, a->d); - -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr = tcg_temp_new(); - -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -if (dc->delayed_branch) { -tcg_gen_mov_tl(cpu_pc, jmp_pc); -tcg_gen_discard_tl(jmp_pc); -} else { -tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); -} -dc->base.is_jmp = DISAS_EXIT; -} +TCGv spr = tcg_temp_new(); -tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); -gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); -} -return true; -} - -static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) -{ -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr; +check_r0_write(dc, a->d); -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -} -/* For SR, we will need to exit the TB to recognize the new - * exception state. For NPC, in theory this counts as a branch - * (although the SPR only exists for use by an ICE). Save all - * of the cpu state first, allowing it to be overwritten. - */ +if (tb_cflags(d
[PATCH v3 0/3] OpenRISC updates for user space FPU
Hello, Since v2: - Add reviewed-by's from Richard - Pull cpu definition out of ifdef in helper_mfspr Since v1: - Fixups suggested by Richard Henderson This series adds support for the FPU related architecture changes defined in architecture spec revision v1.4. - https://openrisc.io/revisions/r1.4 In summary the architecture changes are: - Change FPCSR SPR permissions to allow for reading and writing from user space. - Clarify that FPU underflow detection is done by detecting tininess before rounding. Previous to this series FPCSR reads and writes from user-mode in QEMU would throw an illegal argument exception. The proper behavior should have been to treat these operations as no-ops as the cpu implementations do. As mentioned series changes FPCSR read/write to follow the spec. The series has been tested with the FPU support added in glibc test suite and all math tests are passing. Stafford Horne (3): target/openrisc: Allow fpcsr access in user mode target/openrisc: Set PC to cpu state on FPU exception target/openrisc: Setup FPU for detecting tininess before rounding target/openrisc/cpu.c| 4 ++ target/openrisc/fpu_helper.c | 13 ++- target/openrisc/sys_helper.c | 45 -- target/openrisc/translate.c | 72 4 files changed, 81 insertions(+), 53 deletions(-) -- 2.39.1
[PATCH v3 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
OpenRISC defines tininess to be detected before rounding. Setup qemu to obey this. Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- Since v2: - Add reviewed-by Since v1: - Remove setting default NaN behavior. target/openrisc/cpu.c | 4 1 file changed, 4 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 0ce4f796fa..61d748cfdc 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -22,6 +22,7 @@ #include "qemu/qemu-print.h" #include "cpu.h" #include "exec/exec-all.h" +#include "fpu/softfloat-helpers.h" #include "tcg/tcg.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) @@ -90,6 +91,9 @@ static void openrisc_cpu_reset_hold(Object *obj) s->exception_index = -1; cpu_set_fpcsr(&cpu->env, 0); +set_float_detect_tininess(float_tininess_before_rounding, + &cpu->env.fp_status); + #ifndef CONFIG_USER_ONLY cpu->env.picmr = 0x; cpu->env.picsr = 0x; -- 2.39.1
[PULL 2/3] target/openrisc: Set PC to cpu state on FPU exception
Store the PC to ensure the correct value can be read in the exception handler. Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- target/openrisc/fpu_helper.c | 13 +++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index f9e34fa2cc..8b81d2f62f 100644 --- a/target/openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c @@ -20,8 +20,8 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/exec-all.h" #include "exec/helper-proto.h" -#include "exception.h" #include "fpu/softfloat.h" static int ieee_ex_to_openrisc(int fexcp) @@ -45,6 +45,15 @@ static int ieee_ex_to_openrisc(int fexcp) return ret; } +static G_NORETURN +void do_fpe(CPUOpenRISCState *env, uintptr_t pc) +{ +CPUState *cs = env_cpu(env); + +cs->exception_index = EXCP_FPE; +cpu_loop_exit_restore(cs, pc); +} + void HELPER(update_fpcsr)(CPUOpenRISCState *env) { int tmp = get_float_exception_flags(&env->fp_status); @@ -55,7 +64,7 @@ void HELPER(update_fpcsr)(CPUOpenRISCState *env) if (tmp) { env->fpcsr |= tmp; if (env->fpcsr & FPCSR_FPEE) { -helper_exception(env, EXCP_FPE); +do_fpe(env, GETPC()); } } } -- 2.39.1
[PULL 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
OpenRISC defines tininess to be detected before rounding. Setup qemu to obey this. Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- target/openrisc/cpu.c | 4 1 file changed, 4 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 0ce4f796fa..61d748cfdc 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -22,6 +22,7 @@ #include "qemu/qemu-print.h" #include "cpu.h" #include "exec/exec-all.h" +#include "fpu/softfloat-helpers.h" #include "tcg/tcg.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) @@ -90,6 +91,9 @@ static void openrisc_cpu_reset_hold(Object *obj) s->exception_index = -1; cpu_set_fpcsr(&cpu->env, 0); +set_float_detect_tininess(float_tininess_before_rounding, + &cpu->env.fp_status); + #ifndef CONFIG_USER_ONLY cpu->env.picmr = 0x; cpu->env.picsr = 0x; -- 2.39.1
[PULL 1/3] target/openrisc: Allow fpcsr access in user mode
As per OpenRISC spec 1.4 FPCSR can be read and written in user mode. Update mtspr and mfspr helpers to support this by moving the is_user check into the helper. Link: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- target/openrisc/sys_helper.c | 45 -- target/openrisc/translate.c | 72 2 files changed, 66 insertions(+), 51 deletions(-) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index ec145960e3..ccdee3b8be 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -29,17 +29,37 @@ #define TO_SPR(group, number) (((group) << 11) + (number)) +static inline bool is_user(CPUOpenRISCState *env) +{ +#ifdef CONFIG_USER_ONLY +return true; +#else +return (env->sr & SR_SM) == 0; +#endif +} + void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) { -#ifndef CONFIG_USER_ONLY OpenRISCCPU *cpu = env_archcpu(env); +#ifndef CONFIG_USER_ONLY CPUState *cs = env_cpu(env); target_ulong mr; int idx; #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +cpu_set_fpcsr(env, rb); +return; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 11): /* EVBAR */ env->evbar = rb; break; @@ -187,27 +207,33 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) cpu_openrisc_timer_update(cpu); qemu_mutex_unlock_iothread(); break; -#endif - -case TO_SPR(0, 20): /* FPCSR */ -cpu_set_fpcsr(env, rb); -break; } +#endif } target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, target_ulong spr) { +OpenRISCCPU *cpu = env_archcpu(env); #ifndef CONFIG_USER_ONLY uint64_t data[TARGET_INSN_START_WORDS]; MachineState *ms = MACHINE(qdev_get_machine()); -OpenRISCCPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); int idx; #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +return env->fpcsr; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 0): /* VR */ return env->vr; @@ -324,11 +350,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, cpu_openrisc_count_update(cpu); qemu_mutex_unlock_iothread(); return cpu_openrisc_count_get(cpu); -#endif - -case TO_SPR(0, 20): /* FPCSR */ -return env->fpcsr; } +#endif /* for rd is passed in, if rd unchanged, just keep it back. */ return rd; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 76e53c78d4..43ba0cc1ad 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -819,45 +819,12 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a) static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) { -check_r0_write(dc, a->d); - -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr = tcg_temp_new(); - -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -if (dc->delayed_branch) { -tcg_gen_mov_tl(cpu_pc, jmp_pc); -tcg_gen_discard_tl(jmp_pc); -} else { -tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); -} -dc->base.is_jmp = DISAS_EXIT; -} +TCGv spr = tcg_temp_new(); -tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); -gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); -} -return true; -} - -static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) -{ -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr; +check_r0_write(dc, a->d); -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -} -/* For SR, we will need to exit the TB to recognize the new - * exception state. For NPC, in theory this counts as a branch - * (although the SPR only exists for use by an ICE). Save all - * of the cpu state first, allowing it to be overwritten. - */ +if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { +gen_io_start(); if (dc->delayed_branch) { tcg_gen_mov_tl(cpu_pc, jmp_pc); tcg_gen_discard_tl(jmp_pc); @@ -865,11 +832,36 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); }
[PULL 0/3] OpenRISC FPU Updates for 8.1
The following changes since commit c1eb2ddf0f8075faddc5f7c3d39feae3e8e9d6b4: Update version for v8.0.0 release (2023-04-19 17:27:13 +0100) are available in the Git repository at: https://github.com/stffrdhrn/qemu.git tags/or1k-pull-request-20230513 for you to fetch changes up to 874c52991e1fbe020812b4b15440b6875369aacf: target/openrisc: Setup FPU for detecting tininess before rounding (2023-05-11 15:40:28 +0100) OpenRISC FPU Updates for 8.1 A few fixes and updates to bring OpenRISC inline with the latest architecture spec updates: - Allow FPCSR to be accessed in user mode - Select tininess detection before rounding - Fix FPE Exception PC value Stafford Horne (3): target/openrisc: Allow fpcsr access in user mode target/openrisc: Set PC to cpu state on FPU exception target/openrisc: Setup FPU for detecting tininess before rounding target/openrisc/cpu.c| 4 +++ target/openrisc/fpu_helper.c | 13 ++-- target/openrisc/sys_helper.c | 45 --- target/openrisc/translate.c | 72 4 files changed, 81 insertions(+), 53 deletions(-)
Re: [PATCH v2] hw/openrisc: virt: pass random seed to fdt
On Wed, Jun 22, 2022 at 01:45:13PM +0200, Jason A. Donenfeld wrote: > If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to > initialize early. Set this using the usual guest random number > generation function. This is confirmed to successfully initialize the > RNG on Linux 5.19-rc2. > > Cc: Stafford Horne > Signed-off-by: Jason A. Donenfeld > --- > Changes v1->v2: > - This is rebased on top of your "or1k-virt-2" branch. > - It makes the change to the new "virt" platform, since that's where it > makes most sense to have. Thanks I have placed this on my or1k-virt-2 branch. -Stafford
[PATCH v2 01/11] hw/openrisc: Split re-usable boot time apis out to boot.c
These will be shared with the virt platform. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- hw/openrisc/boot.c | 117 + hw/openrisc/meson.build| 1 + hw/openrisc/openrisc_sim.c | 106 ++--- include/hw/openrisc/boot.h | 34 +++ 4 files changed, 158 insertions(+), 100 deletions(-) create mode 100644 hw/openrisc/boot.c create mode 100644 include/hw/openrisc/boot.h diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c new file mode 100644 index 00..ca773b385e --- /dev/null +++ b/hw/openrisc/boot.c @@ -0,0 +1,117 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * QEMU OpenRISC boot helpers. + * + * (c) 2022 Stafford Horne + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/cpu-defs.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/openrisc/boot.h" +#include "sysemu/device_tree.h" +#include "sysemu/qtest.h" + +#include + +#define KERNEL_LOAD_ADDR 0x100 + +hwaddr openrisc_load_kernel(ram_addr_t ram_size, +const char *kernel_filename, +uint32_t *bootstrap_pc) +{ +long kernel_size; +uint64_t elf_entry; +uint64_t high_addr; +hwaddr entry; + +if (kernel_filename && !qtest_enabled()) { +kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, + &elf_entry, NULL, &high_addr, NULL, 1, + EM_OPENRISC, 1, 0); +entry = elf_entry; +if (kernel_size < 0) { +kernel_size = load_uimage(kernel_filename, + &entry, NULL, NULL, NULL, NULL); +high_addr = entry + kernel_size; +} +if (kernel_size < 0) { +kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); +high_addr = KERNEL_LOAD_ADDR + kernel_size; +} + +if (entry <= 0) { +entry = KERNEL_LOAD_ADDR; +} + +if (kernel_size < 0) { +error_report("couldn't load the kernel '%s'", kernel_filename); +exit(1); +} +*bootstrap_pc = entry; + +return high_addr; +} +return 0; +} + +hwaddr openrisc_load_initrd(void *fdt, const char *filename, +hwaddr load_start, uint64_t mem_size) +{ +int size; +hwaddr start; + +/* We put the initrd right after the kernel; page aligned. */ +start = TARGET_PAGE_ALIGN(load_start); + +size = load_ramdisk(filename, start, mem_size - start); +if (size < 0) { +size = load_image_targphys(filename, start, mem_size - start); +if (size < 0) { +error_report("could not load ramdisk '%s'", filename); +exit(1); +} +} + +if (fdt) { +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-start", start); +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-end", start + size); +} + +return start + size; +} + +uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start, + uint64_t mem_size) +{ +uint32_t fdt_addr; +int ret; +int fdtsize = fdt_totalsize(fdt); + +if (fdtsize <= 0) { +error_report("invalid device-tree"); +exit(1); +} + +/* We put fdt right after the kernel and/or initrd. */ +fdt_addr = TARGET_PAGE_ALIGN(load_start); + +ret = fdt_pack(fdt); +/* Should only fail if we've built a corrupted tree */ +g_assert(ret == 0); +/* copy in the device tree */ +qemu_fdt_dumpdtb(fdt, fdtsize); + +rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, + &address_space_memory); + +return fdt_addr; +} + diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ec48172c9d..ab563820c5 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -1,5 +1,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) +openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 35adce17ac..35da123aef 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -24,10 +24,9 @@ #include "cpu.h" #include "hw/irq.h" #include "hw/boards.h" -#include "elf.h" #include "hw/char/serial.h" #include "net
[PATCH v2 02/11] target/openrisc: Fix memory reading in debugger
In commit f0655423ca ("target/openrisc: Reorg tlb lookup") data and instruction TLB reads were combined. This, broke debugger reads where we first tried to map using the data tlb then fall back to the instruction tlb. This patch replicates this logic by first requesting a PAGE_READ protection mapping then falling back to PAGE_EXEC. Signed-off-by: Stafford Horne --- target/openrisc/mmu.c | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c index d7e1320998..0b8afdbacf 100644 --- a/target/openrisc/mmu.c +++ b/target/openrisc/mmu.c @@ -148,7 +148,13 @@ hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) case SR_DME | SR_IME: /* The mmu is definitely enabled. */ excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, -PAGE_EXEC | PAGE_READ | PAGE_WRITE, +PAGE_READ, +(sr & SR_SM) != 0); +if (!excp) { +return phys_addr; +} +excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, +PAGE_EXEC, (sr & SR_SM) != 0); return excp ? -1 : phys_addr; -- 2.36.1
[PATCH v2 00/11] OpenRISC Virtual Machine
Hello, This is the OpenRISC Virtual Machine plaform which we are now using for OpenRISC CI such as the wireguard testing that Jason has been working on. The first few patches help get OpenRISC QEMU ready for the virtual machine. There is one bug fix for GDB debugging there too. Next we have the Virt patch followed by a separate patch to add PCI support which is split out because it's a bit easier to review that way I thought. The next few patches are fixes to get the Multicore platform stable, such as adding MTTCG support and fixing some interrupt and timer related bugs. The platform is relatively stable now, but every few boots we get ~10 second soft lockups. My hunch is that this is another interrupt race condition where IPI's end up getting lost. However, overall the is much more stable than the SMP support we had before. So I want to submit this for review and maybe upstream it before tracking down these last issues which might take significant more time. This is being tested with my or1k-virt kernel branch here: https://github.com/stffrdhrn/linux/commits/or1k-virt This tree has support for: OpenRISC PCI and virt_defconfig and an irqchip bug fix. Changes since v1: - Dropped semihosting support - Added PCI support - Added OpenRISC documentation - Added OpenRISC support for MTTCG - Support Configurating Goldfish RTC endianness - Added a few bug fix patches -Stafford Jason A. Donenfeld (1): hw/openrisc: virt: pass random seed to fdt Stafford Horne (10): hw/openrisc: Split re-usable boot time apis out to boot.c target/openrisc: Fix memory reading in debugger goldfish_rtc: Add endianness property hw/openrisc: Add the OpenRISC virtual machine hw/openrisc: Add PCI bus support to virt hw/openrisc: Initialize timer time at startup target/openrisc: Add interrupted CPU to log target/openrisc: Enable MTTCG target/openrisc: Interrupt handling fixes docs/system: openrisc: Add OpenRISC documentation configs/devices/or1k-softmmu/default.mak | 1 + configs/targets/or1k-softmmu.mak | 1 + docs/system/openrisc/cpu-features.rst| 15 + docs/system/openrisc/emulation.rst | 17 + docs/system/openrisc/or1k-sim.rst| 43 ++ docs/system/openrisc/virt.rst| 50 ++ docs/system/target-openrisc.rst | 72 +++ docs/system/targets.rst | 1 + hw/openrisc/Kconfig | 12 + hw/openrisc/boot.c | 117 + hw/openrisc/cputimer.c | 18 + hw/openrisc/meson.build | 2 + hw/openrisc/openrisc_sim.c | 106 + hw/openrisc/virt.c | 578 +++ hw/rtc/goldfish_rtc.c| 46 +- include/hw/openrisc/boot.h | 34 ++ include/hw/rtc/goldfish_rtc.h| 2 + target/openrisc/cpu.c| 1 - target/openrisc/cpu.h| 3 + target/openrisc/interrupt.c | 4 +- target/openrisc/mmu.c| 8 +- target/openrisc/sys_helper.c | 18 +- 22 files changed, 1035 insertions(+), 114 deletions(-) create mode 100644 docs/system/openrisc/cpu-features.rst create mode 100644 docs/system/openrisc/emulation.rst create mode 100644 docs/system/openrisc/or1k-sim.rst create mode 100644 docs/system/openrisc/virt.rst create mode 100644 docs/system/target-openrisc.rst create mode 100644 hw/openrisc/boot.c create mode 100644 hw/openrisc/virt.c create mode 100644 include/hw/openrisc/boot.h -- 2.36.1
[PATCH v2 03/11] goldfish_rtc: Add endianness property
Add an endianness property to allow configuring the RTC as either native, little or big endian. Cc: Laurent Vivier Signed-off-by: Stafford Horne --- hw/rtc/goldfish_rtc.c | 46 --- include/hw/rtc/goldfish_rtc.h | 2 ++ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 35e493be31..24f6587086 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -216,14 +216,34 @@ static int goldfish_rtc_post_load(void *opaque, int version_id) return 0; } -static const MemoryRegionOps goldfish_rtc_ops = { -.read = goldfish_rtc_read, -.write = goldfish_rtc_write, -.endianness = DEVICE_NATIVE_ENDIAN, -.valid = { -.min_access_size = 4, -.max_access_size = 4 -} +static const MemoryRegionOps goldfish_rtc_ops[3] = { +[DEVICE_NATIVE_ENDIAN] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, +[DEVICE_LITTLE_ENDIAN] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_LITTLE_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, +[DEVICE_BIG_ENDIAN] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_BIG_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, }; static const VMStateDescription goldfish_rtc_vmstate = { @@ -265,7 +285,8 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) SysBusDevice *dev = SYS_BUS_DEVICE(d); GoldfishRTCState *s = GOLDFISH_RTC(d); -memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_rtc_ops, s, +memory_region_init_io(&s->iomem, OBJECT(s), + &goldfish_rtc_ops[s->endianness], s, "goldfish_rtc", 0x24); sysbus_init_mmio(dev, &s->iomem); @@ -274,10 +295,17 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s); } +static Property goldfish_rtc_properties[] = { +DEFINE_PROP_UINT8("endianness", GoldfishRTCState, endianness, + DEVICE_NATIVE_ENDIAN), +DEFINE_PROP_END_OF_LIST(), +}; + static void goldfish_rtc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); +device_class_set_props(dc, goldfish_rtc_properties); dc->realize = goldfish_rtc_realize; dc->reset = goldfish_rtc_reset; dc->vmsd = &goldfish_rtc_vmstate; diff --git a/include/hw/rtc/goldfish_rtc.h b/include/hw/rtc/goldfish_rtc.h index 79ca7daf5d..8e1aeb85e3 100644 --- a/include/hw/rtc/goldfish_rtc.h +++ b/include/hw/rtc/goldfish_rtc.h @@ -42,6 +42,8 @@ struct GoldfishRTCState { uint32_t irq_pending; uint32_t irq_enabled; uint32_t time_high; + +uint8_t endianness; }; #endif -- 2.36.1
[PATCH v2 05/11] hw/openrisc: Add PCI bus support to virt
This is mostly borrowed from xtensa and riscv as examples. The create_pcie_irq_map swizzle function is almost and exact copy but here we use a single cell interrupt, possibly we can make this generic. Signed-off-by: Stafford Horne --- hw/openrisc/Kconfig | 3 + hw/openrisc/virt.c | 160 ++-- 2 files changed, 157 insertions(+), 6 deletions(-) diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 202134668e..97af258b55 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -7,8 +7,11 @@ config OR1K_SIM config OR1K_VIRT bool +imply PCI_DEVICES imply VIRTIO_VGA imply TEST_DEVICES +select PCI +select PCI_EXPRESS_GENERIC_BRIDGE select GOLDFISH_RTC select SERIAL select SIFIVE_TEST diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index bdb00f6e32..f1d1293eeb 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -17,6 +17,8 @@ #include "hw/core/split-irq.h" #include "hw/openrisc/boot.h" #include "hw/misc/sifive_test.h" +#include "hw/pci/pci.h" +#include "hw/pci-host/gpex.h" #include "hw/qdev-properties.h" #include "hw/rtc/goldfish_rtc.h" #include "hw/sysbus.h" @@ -47,6 +49,9 @@ typedef struct OR1KVirtState { enum { VIRT_DRAM, +VIRT_ECAM, +VIRT_MMIO, +VIRT_PIO, VIRT_TEST, VIRT_RTC, VIRT_VIRTIO, @@ -60,6 +65,7 @@ enum { VIRT_RTC_IRQ = 3, VIRT_VIRTIO_IRQ = 4, /* to 12 */ VIRTIO_COUNT = 8, +VIRT_PCI_IRQ_BASE = 13, /* to 17 */ }; static const struct MemmapEntry { @@ -72,6 +78,9 @@ static const struct MemmapEntry { [VIRT_RTC] = { 0x96005000, 0x1000 }, [VIRT_VIRTIO] ={ 0x9700, 0x1000 }, [VIRT_OMPIC] = { 0x9800, VIRT_CPUS_MAX * 8 }, +[VIRT_ECAM] = { 0x9e00, 0x100 }, +[VIRT_PIO] = { 0x9f00, 0x100 }, +[VIRT_MMIO] = { 0xa000, 0x1000 }, }; static struct openrisc_boot_info { @@ -115,12 +124,12 @@ static qemu_irq get_per_cpu_irq(OpenRISCCPU *cpus[], int num_cpus, int irq_pin) static void openrisc_create_fdt(OR1KVirtState *state, const struct MemmapEntry *memmap, int num_cpus, uint64_t mem_size, -const char *cmdline) +const char *cmdline, +int32_t *pic_phandle) { void *fdt; int cpu; char *nodename; -int pic_ph; fdt = state->fdt = create_device_tree(&state->fdt_size); if (!fdt) { @@ -163,14 +172,14 @@ static void openrisc_create_fdt(OR1KVirtState *state, nodename = (char *)"/pic"; qemu_fdt_add_subnode(fdt, nodename); -pic_ph = qemu_fdt_alloc_phandle(fdt); +*pic_phandle = qemu_fdt_alloc_phandle(fdt); qemu_fdt_setprop_string(fdt, nodename, "compatible", "opencores,or1k-pic-level"); qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1); qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); -qemu_fdt_setprop_cell(fdt, nodename, "phandle", pic_ph); +qemu_fdt_setprop_cell(fdt, nodename, "phandle", *pic_phandle); -qemu_fdt_setprop_cell(fdt, "/", "interrupt-parent", pic_ph); +qemu_fdt_setprop_cell(fdt, "/", "interrupt-parent", *pic_phandle); qemu_fdt_add_subnode(fdt, "/chosen"); if (cmdline) { @@ -275,6 +284,7 @@ static void openrisc_virt_test_init(OR1KVirtState *state, hwaddr base, g_free(nodename); } + static void openrisc_virt_rtc_init(OR1KVirtState *state, hwaddr base, hwaddr size, int num_cpus, OpenRISCCPU *cpus[], int irq_pin) @@ -303,6 +313,134 @@ static void openrisc_virt_rtc_init(OR1KVirtState *state, hwaddr base, g_free(nodename); } + +static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, +uint32_t irqchip_phandle) +{ +int pin, dev; +uint32_t irq_map_stride = 0; +uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] = {}; +uint32_t *irq_map = full_irq_map; + +/* + * This code creates a standard swizzle of interrupts such that + * each device's first interrupt is based on it's PCI_SLOT number. + * (See pci_swizzle_map_irq_fn()) + * + * We only need one entry per interrupt in the table (not one per + * possible slot) seeing the interrupt-map-mask will allow the table + * to wrap to any number of devices. + */ +for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { +int devfn = dev << 3; + +for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { +int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_
[PATCH v2 06/11] hw/openrisc: Initialize timer time at startup
The last_clk time was initialized at zero, this means when we calculate the first delta we will calculate 0 vs current time which could cause unnecessary hops. Initialize last_clk to the qemu clock on initialization. Signed-off-by: Stafford Horne --- hw/openrisc/cputimer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index 93268815d8..4dbba3a3d4 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -140,6 +140,7 @@ void cpu_openrisc_clock_init(OpenRISCCPU *cpu) if (or1k_timer == NULL) { or1k_timer = g_new0(OR1KTimerState, 1); +or1k_timer->last_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); vmstate_register(NULL, 0, &vmstate_or1k_timer, or1k_timer); } } -- 2.36.1
[PATCH v2 07/11] target/openrisc: Add interrupted CPU to log
When we are tracing it's helpful to know which CPU's are getting interrupted, att that detail to the log line. Signed-off-by: Stafford Horne --- target/openrisc/interrupt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index e5724f5371..c31c6f12c4 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -83,7 +83,9 @@ void openrisc_cpu_do_interrupt(CPUState *cs) [EXCP_TRAP] = "TRAP", }; -qemu_log_mask(CPU_LOG_INT, "INT: %s\n", int_name[exception]); +qemu_log_mask(CPU_LOG_INT, "CPU: %d INT: %s\n", + cs->cpu_index, + int_name[exception]); hwaddr vect_pc = exception << 8; if (env->cpucfgr & CPUCFGR_EVBARP) { -- 2.36.1
[PATCH v2 04/11] hw/openrisc: Add the OpenRISC virtual machine
This patch adds the OpenRISC virtual machine 'virt' for OpenRISC. This platform allows for a convenient CI platform for toolchain, software ports and the OpenRISC linux kernel port. Much of this has been sourced from the m68k and riscv virt platforms. The platform provides: - OpenRISC SMP with up to 4 cpus - A virtio bus with up to 8 devices - Standard ns16550a serial - Goldfish RTC - SiFive TEST device for poweroff and reboot - Generated Device Tree to automatically configure the guest kernel Signed-off-by: Stafford Horne --- configs/devices/or1k-softmmu/default.mak | 1 + hw/openrisc/Kconfig | 9 + hw/openrisc/meson.build | 1 + hw/openrisc/virt.c | 424 +++ 4 files changed, 435 insertions(+) create mode 100644 hw/openrisc/virt.c diff --git a/configs/devices/or1k-softmmu/default.mak b/configs/devices/or1k-softmmu/default.mak index 168101c39a..89c39e3123 100644 --- a/configs/devices/or1k-softmmu/default.mak +++ b/configs/devices/or1k-softmmu/default.mak @@ -3,3 +3,4 @@ # Boards: # CONFIG_OR1K_SIM=y +CONFIG_OR1K_VIRT=y diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 8f284f3ba0..202134668e 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -4,3 +4,12 @@ config OR1K_SIM select OPENCORES_ETH select OMPIC select SPLIT_IRQ + +config OR1K_VIRT +bool +imply VIRTIO_VGA +imply TEST_DEVICES +select GOLDFISH_RTC +select SERIAL +select SIFIVE_TEST +select VIRTIO_MMIO diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ab563820c5..2dbc6365bb 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -2,5 +2,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) +openrisc_ss.add(when: 'CONFIG_OR1K_VIRT', if_true: [files('virt.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c new file mode 100644 index 00..bdb00f6e32 --- /dev/null +++ b/hw/openrisc/virt.c @@ -0,0 +1,424 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * OpenRISC QEMU virtual machine. + * + * (c) 2022 Stafford Horne + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "cpu.h" +#include "exec/address-spaces.h" +#include "hw/irq.h" +#include "hw/boards.h" +#include "hw/char/serial.h" +#include "hw/core/split-irq.h" +#include "hw/openrisc/boot.h" +#include "hw/misc/sifive_test.h" +#include "hw/qdev-properties.h" +#include "hw/rtc/goldfish_rtc.h" +#include "hw/sysbus.h" +#include "hw/virtio/virtio-mmio.h" +#include "sysemu/device_tree.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "sysemu/reset.h" + +#include + +#define VIRT_CPUS_MAX 4 +#define VIRT_CLK_MHZ 2000 + +#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +#define VIRT_MACHINE(obj) \ +OBJECT_CHECK(OR1KVirtState, (obj), TYPE_VIRT_MACHINE) + +typedef struct OR1KVirtState { +/*< private >*/ +MachineState parent_obj; + +/*< public >*/ +void *fdt; +int fdt_size; + +} OR1KVirtState; + +enum { +VIRT_DRAM, +VIRT_TEST, +VIRT_RTC, +VIRT_VIRTIO, +VIRT_UART, +VIRT_OMPIC, +}; + +enum { +VIRT_OMPIC_IRQ = 1, +VIRT_UART_IRQ = 2, +VIRT_RTC_IRQ = 3, +VIRT_VIRTIO_IRQ = 4, /* to 12 */ +VIRTIO_COUNT = 8, +}; + +static const struct MemmapEntry { +hwaddr base; +hwaddr size; +} virt_memmap[] = { +[VIRT_DRAM] = { 0x, 0 }, +[VIRT_UART] = { 0x9000, 0x100 }, +[VIRT_TEST] = { 0x9600,0x8 }, +[VIRT_RTC] = { 0x96005000, 0x1000 }, +[VIRT_VIRTIO] ={ 0x9700, 0x1000 }, +[VIRT_OMPIC] = { 0x9800, VIRT_CPUS_MAX * 8 }, +}; + +static struct openrisc_boot_info { +uint32_t bootstrap_pc; +uint32_t fdt_addr; +} boot_info; + +static void main_cpu_reset(void *opaque) +{ +OpenRISCCPU *cpu = opaque; +CPUState *cs = CPU(cpu); + +cpu_reset(CPU(cpu)); + +cpu_set_pc(cs, boot_info.bootstrap_pc); +cpu_set_gpr(&cpu->env, 3, boot_info.fdt_addr); +} + +static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) +{ +return qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "IRQ", irq_pin); +} + +static qemu_irq get_per_cpu_irq(OpenRISCCPU *cpus[], int num_cpus, int irq_pin) +{ +int i; + +if (num_cpus > 1) { +DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); +qdev_prop_set_uint32(splitter, "num-lines", num_cpus); +
[PATCH v2 08/11] target/openrisc: Enable MTTCG
This patch enables multithread TCG for OpenRISC. Since the or1k shared syncrhonized timer can be updated from each vCPU via helpers we use a mutex to synchronize updates. Signed-off-by: Stafford Horne --- configs/targets/or1k-softmmu.mak | 1 + hw/openrisc/cputimer.c | 17 + target/openrisc/cpu.h| 3 +++ target/openrisc/sys_helper.c | 11 +-- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/configs/targets/or1k-softmmu.mak b/configs/targets/or1k-softmmu.mak index 263e970870..432f855a30 100644 --- a/configs/targets/or1k-softmmu.mak +++ b/configs/targets/or1k-softmmu.mak @@ -1,3 +1,4 @@ TARGET_ARCH=openrisc +TARGET_SUPPORTS_MTTCG=y TARGET_BIG_ENDIAN=y TARGET_NEED_FDT=y diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index 4dbba3a3d4..2298eff8b9 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -43,6 +43,23 @@ uint32_t cpu_openrisc_count_get(OpenRISCCPU *cpu) return or1k_timer->ttcr; } +/* + * Check to see if calling cpu_openrisc_count_update will + * actually advance the time. + * + * Used in hot spots to avoid taking expensive locks. + */ +bool cpu_openrisc_timer_has_advanced(OpenRISCCPU *cpu) +{ +uint64_t now; + +if (!cpu->env.is_counting) { +return false; +} +now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +return (now - or1k_timer->last_clk) >= TIMER_PERIOD; +} + /* Add elapsed ticks to ttcr */ void cpu_openrisc_count_update(OpenRISCCPU *cpu) { diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index b9584f10d4..5354d681f5 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -25,6 +25,8 @@ #include "hw/core/cpu.h" #include "qom/object.h" +#define TCG_GUEST_DEFAULT_MO (0) + #define TYPE_OPENRISC_CPU "or1k-cpu" OBJECT_DECLARE_CPU_TYPE(OpenRISCCPU, OpenRISCCPUClass, OPENRISC_CPU) @@ -333,6 +335,7 @@ void cpu_openrisc_pic_init(OpenRISCCPU *cpu); /* hw/openrisc_timer.c */ void cpu_openrisc_clock_init(OpenRISCCPU *cpu); +bool cpu_openrisc_timer_has_advanced(OpenRISCCPU *cpu); uint32_t cpu_openrisc_count_get(OpenRISCCPU *cpu); void cpu_openrisc_count_set(OpenRISCCPU *cpu, uint32_t val); void cpu_openrisc_count_update(OpenRISCCPU *cpu); diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 48674231e7..7c0d3d6187 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -145,6 +145,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) break; case TO_SPR(10, 0): /* TTMR */ { +qemu_mutex_lock_iothread(); if ((env->ttmr & TTMR_M) ^ (rb & TTMR_M)) { switch (rb & TTMR_M) { case TIMER_NONE: @@ -168,14 +169,16 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) env->ttmr = rb & ~TTMR_IP; cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; } - cpu_openrisc_timer_update(cpu); +qemu_mutex_unlock_iothread(); } break; case TO_SPR(10, 1): /* TTCR */ +qemu_mutex_lock_iothread(); cpu_openrisc_count_set(cpu, rb); cpu_openrisc_timer_update(cpu); +qemu_mutex_unlock_iothread(); break; #endif @@ -303,7 +306,11 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, return env->ttmr; case TO_SPR(10, 1): /* TTCR */ -cpu_openrisc_count_update(cpu); +if (cpu_openrisc_timer_has_advanced(cpu)) { +qemu_mutex_lock_iothread(); +cpu_openrisc_count_update(cpu); +qemu_mutex_unlock_iothread(); +} return cpu_openrisc_count_get(cpu); #endif -- 2.36.1
[PATCH v2 09/11] target/openrisc: Interrupt handling fixes
When running SMP systems we sometimes were seeing lockups where IPI interrupts were being raised by never handled. This looks to be caused by 2 issues in the openrisc interrupt handling logic. 1. After clearing an interrupt the openrisc_cpu_set_irq handler will always clear PICSR. This is not correct as masked interrupts should still be visible in PICSR. 2. After setting PICMR (mask register) and exposed interrupts should cause an interrupt to be raised. This was not being done so add it. This patch fixes both issues. Signed-off-by: Stafford Horne --- target/openrisc/cpu.c| 1 - target/openrisc/sys_helper.c | 7 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 41d1b2a24a..cb9f35f408 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -98,7 +98,6 @@ static void openrisc_cpu_set_irq(void *opaque, int irq, int level) cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); -cpu->env.picsr = 0; } } #endif diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 7c0d3d6187..5336110b5e 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -139,6 +139,13 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) break; case TO_SPR(9, 0): /* PICMR */ env->picmr = rb; +qemu_mutex_lock_iothread(); +if (env->picsr & env->picmr) { +cpu_interrupt(cs, CPU_INTERRUPT_HARD); +} else { +cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); +} +qemu_mutex_unlock_iothread(); break; case TO_SPR(9, 2): /* PICSR */ env->picsr &= ~rb; -- 2.36.1
[PATCH v2 10/11] hw/openrisc: virt: pass random seed to fdt
From: "Jason A. Donenfeld" If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to initialize early. Set this using the usual guest random number generation function. This is confirmed to successfully initialize the RNG on Linux 5.19-rc2. Cc: Stafford Horne Signed-off-by: Jason A. Donenfeld Signed-off-by: Stafford Horne --- hw/openrisc/virt.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index f1d1293eeb..a301d0d769 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qemu/guest-random.h" #include "qapi/error.h" #include "cpu.h" #include "exec/address-spaces.h" @@ -130,6 +131,7 @@ static void openrisc_create_fdt(OR1KVirtState *state, void *fdt; int cpu; char *nodename; +uint8_t rng_seed[32]; fdt = state->fdt = create_device_tree(&state->fdt_size); if (!fdt) { @@ -186,6 +188,10 @@ static void openrisc_create_fdt(OR1KVirtState *state, qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); } +/* Pass seed to RNG. */ +qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); +qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + /* Create aliases node for use by devices. */ qemu_fdt_add_subnode(fdt, "/aliases"); } -- 2.36.1
[PATCH v2 11/11] docs/system: openrisc: Add OpenRISC documentation
Signed-off-by: Stafford Horne --- docs/system/openrisc/cpu-features.rst | 15 ++ docs/system/openrisc/emulation.rst| 17 +++ docs/system/openrisc/or1k-sim.rst | 43 docs/system/openrisc/virt.rst | 50 +++ docs/system/target-openrisc.rst | 72 +++ docs/system/targets.rst | 1 + 6 files changed, 198 insertions(+) create mode 100644 docs/system/openrisc/cpu-features.rst create mode 100644 docs/system/openrisc/emulation.rst create mode 100644 docs/system/openrisc/or1k-sim.rst create mode 100644 docs/system/openrisc/virt.rst create mode 100644 docs/system/target-openrisc.rst diff --git a/docs/system/openrisc/cpu-features.rst b/docs/system/openrisc/cpu-features.rst new file mode 100644 index 00..aeb65e22ff --- /dev/null +++ b/docs/system/openrisc/cpu-features.rst @@ -0,0 +1,15 @@ +CPU Features + + +The QEMU emulation of the OpenRISC architecture provides following built in +features. + +- Shadow GPRs +- MMU TLB with 128 entries, 1 way +- Power Management (PM) +- Programmable Interrupt Controller (PIC) +- Tick Timer + +These features are on by default and the presence can be confirmed by checking +the contents of the Unit Presence Register (``UPR``) and CPU Configuration +Register (``CPUCFGR``). diff --git a/docs/system/openrisc/emulation.rst b/docs/system/openrisc/emulation.rst new file mode 100644 index 00..0af898ab20 --- /dev/null +++ b/docs/system/openrisc/emulation.rst @@ -0,0 +1,17 @@ +OpenRISC 1000 CPU architecture support +== + +QEMU's TCG emulation includes support for the OpenRISC or1200 implementation of +the OpenRISC 1000 cpu architecture. + +The or1200 cpu also has support for the following instruction subsets: + +- ORBIS32 (OpenRISC Basic Instruction Set) +- ORFPX32 (OpenRISC Floating-Point eXtension) + +In addition to the instruction subsets the QEMU TCG emulation also has support +for most Class II (optional) instructions. + +For information on all OpenRISC instructions please refer to the latest +architecture manual available on the OpenRISC website in the +`OpenRISC Architecture <https://openrisc.io/architecture>`_ section. diff --git a/docs/system/openrisc/or1k-sim.rst b/docs/system/openrisc/or1k-sim.rst new file mode 100644 index 00..ef10439737 --- /dev/null +++ b/docs/system/openrisc/or1k-sim.rst @@ -0,0 +1,43 @@ +Or1ksim board += + +The QEMU Or1ksim machine emulates the standard OpenRISC board simulator which is +also the standard SoC configuration. + +Supported devices +- + + * 16550A UART + * ETHOC Ethernet controller + * SMP (OpenRISC multicore using ompic) + +Boot options + + +The Or1ksim machine can be started using the ``-kernel`` and ``-initrd`` options +to load a Linux kernel and optional disk image. + +.. code-block:: bash + + $ qemu-system-or1k -cpu or1220 -M or1k-sim -nographic \ +-kernel vmlinux \ +-initrd initramfs.cpio.gz \ +-m 128 + +Linux guest kernel configuration +"""""""""""""""""""""""""""""""" + +The 'or1ksim_defconfig' for Linux openrisc kernels includes the right +drivers for the or1ksim machine. If you would like to run an SMP system +choose the 'simple_smp_defconfig' config. + +Hardware configuration information +"""""""""""""""""""""""""""""""""" + +The ``or1k-sim`` board automatically generates a device tree blob ("dtb") +which it passes to the guest. This provides information about the +addresses, interrupt lines and other configuration of the various devices +in the system. + +The location of the DTB will be passed in register ``r3`` to the guest operating +system. diff --git a/docs/system/openrisc/virt.rst b/docs/system/openrisc/virt.rst new file mode 100644 index 00..2fe61ac942 --- /dev/null +++ b/docs/system/openrisc/virt.rst @@ -0,0 +1,50 @@ +'virt' generic virtual platform +=== + +The ``virt`` board is a platform which does not correspond to any +real hardware; it is designed for use in virtual machines. +It is the recommended board type if you simply want to run +a guest such as Linux and do not care about reproducing the +idiosyncrasies and limitations of a particular bit of real-world +hardware. + +Supported devices +- + + * PCI/PCIe devices + * 8 virtio-mmio transport devices + * 16550A UART + * Goldfish RTC + * SiFive Test device for poweroff and reboot + * SMP (OpenRISC multicore using ompic) + +Boot options + + +The virt machine can be started using the
Re: [PATCH v2 07/11] target/openrisc: Add interrupted CPU to log
On Mon, Jul 04, 2022 at 03:34:52PM +0530, Richard Henderson wrote: > On 7/4/22 02:58, Stafford Horne wrote: > > When we are tracing it's helpful to know which CPU's are getting > > interrupted, att that detail to the log line. > > "at". > > Reviewed-by: Richard Henderson Actually it should be "add", thanks I fixed it. -Stafford
Re: [PATCH v2 08/11] target/openrisc: Enable MTTCG
On Mon, Jul 04, 2022 at 03:37:04PM +0530, Richard Henderson wrote: > On 7/4/22 02:58, Stafford Horne wrote: > > case TO_SPR(10, 1): /* TTCR */ > > -cpu_openrisc_count_update(cpu); > > +if (cpu_openrisc_timer_has_advanced(cpu)) { > > +qemu_mutex_lock_iothread(); > > +cpu_openrisc_count_update(cpu); > > +qemu_mutex_unlock_iothread(); > > +} > > Lock around the whole if, I think. Otherwise looks good. Well, actually the cpu_openrisc_timer_has_advanced read is done once outside the lock as an optimization to avoid taking the lock when it is not needed. i.e. if we have 4 cores that all try to update the clock at the same time in theory only one will have to take the lock and update the shared timer. But I do see that could be flawed as after it takes the lock the timer could have been updated by then. Ill move it inside and see if there is any perfromance hit / increase in the sync-profile. > Reviewed-by: Richard Henderson > > > r~
Re: [PATCH v2 06/11] hw/openrisc: Initialize timer time at startupi
On Mon, Jul 04, 2022 at 03:33:26PM +0530, Richard Henderson wrote: > On 7/4/22 02:58, Stafford Horne wrote: > > The last_clk time was initialized at zero, this means when we calculate > > the first delta we will calculate 0 vs current time which could cause > > unnecessary hops. > > > > Initialize last_clk to the qemu clock on initialization. > > > > Signed-off-by: Stafford Horne > > --- > > hw/openrisc/cputimer.c | 1 + > > 1 file changed, 1 insertion(+) > > > > diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c > > index 93268815d8..4dbba3a3d4 100644 > > --- a/hw/openrisc/cputimer.c > > +++ b/hw/openrisc/cputimer.c > > @@ -140,6 +140,7 @@ void cpu_openrisc_clock_init(OpenRISCCPU *cpu) > > if (or1k_timer == NULL) { > > or1k_timer = g_new0(OR1KTimerState, 1); > > +or1k_timer->last_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); > > vmstate_register(NULL, 0, &vmstate_or1k_timer, or1k_timer); > > } > > } > > Init doesn't seem right. Should be in reset? Good point, I think reset would be better.
Re: [PATCH v2 03/11] goldfish_rtc: Add endianness property
On Mon, Jul 04, 2022 at 03:29:57PM +0530, Richard Henderson wrote: > On 7/4/22 02:58, Stafford Horne wrote: > > -static const MemoryRegionOps goldfish_rtc_ops = { > > -.read = goldfish_rtc_read, > > -.write = goldfish_rtc_write, > > -.endianness = DEVICE_NATIVE_ENDIAN, > > -.valid = { > > -.min_access_size = 4, > > -.max_access_size = 4 > > -} > > +static const MemoryRegionOps goldfish_rtc_ops[3] = { > > +[DEVICE_NATIVE_ENDIAN] = { > > +.read = goldfish_rtc_read, > > +.write = goldfish_rtc_write, > > +.endianness = DEVICE_NATIVE_ENDIAN, > > +.valid = { > > +.min_access_size = 4, > > +.max_access_size = 4 > > +} > > +}, > > +[DEVICE_LITTLE_ENDIAN] = { > > +.read = goldfish_rtc_read, > > +.write = goldfish_rtc_write, > > +.endianness = DEVICE_LITTLE_ENDIAN, > > +.valid = { > > +.min_access_size = 4, > > +.max_access_size = 4 > > +} > > +}, > > +[DEVICE_BIG_ENDIAN] = { > > +.read = goldfish_rtc_read, > > +.write = goldfish_rtc_write, > > +.endianness = DEVICE_BIG_ENDIAN, > > +.valid = { > > +.min_access_size = 4, > > +.max_access_size = 4 > > +} > > +}, > > }; > > You don't need 3 copies, only big and little. > > > +static Property goldfish_rtc_properties[] = { > > +DEFINE_PROP_UINT8("endianness", GoldfishRTCState, endianness, > > + DEVICE_NATIVE_ENDIAN), > > +DEFINE_PROP_END_OF_LIST(), > > +}; > > ... and I think the clear desire for default is little-endian. I would make > the property be bool, and add a comment that this is only for m68k > compatibility, so don't use it in new code. Yeah, that makes sense. -Stafford
Re: [PATCH v2 03/11] goldfish_rtc: Add endianness property
On Mon, Jul 04, 2022 at 12:23:23PM +0200, Laurent Vivier wrote: > On 04/07/2022 12:21, Richard Henderson wrote: > > On 7/4/22 15:46, Laurent Vivier wrote: > > > On 04/07/2022 11:59, Richard Henderson wrote: > > > > On 7/4/22 02:58, Stafford Horne wrote: > > > > > -static const MemoryRegionOps goldfish_rtc_ops = { > > > > > - .read = goldfish_rtc_read, > > > > > - .write = goldfish_rtc_write, > > > > > - .endianness = DEVICE_NATIVE_ENDIAN, > > > > > - .valid = { > > > > > - .min_access_size = 4, > > > > > - .max_access_size = 4 > > > > > - } > > > > > +static const MemoryRegionOps goldfish_rtc_ops[3] = { > > > > > + [DEVICE_NATIVE_ENDIAN] = { > > > > > + .read = goldfish_rtc_read, > > > > > + .write = goldfish_rtc_write, > > > > > + .endianness = DEVICE_NATIVE_ENDIAN, > > > > > + .valid = { > > > > > + .min_access_size = 4, > > > > > + .max_access_size = 4 > > > > > + } > > > > > + }, > > > > > + [DEVICE_LITTLE_ENDIAN] = { > > > > > + .read = goldfish_rtc_read, > > > > > + .write = goldfish_rtc_write, > > > > > + .endianness = DEVICE_LITTLE_ENDIAN, > > > > > + .valid = { > > > > > + .min_access_size = 4, > > > > > + .max_access_size = 4 > > > > > + } > > > > > + }, > > > > > + [DEVICE_BIG_ENDIAN] = { > > > > > + .read = goldfish_rtc_read, > > > > > + .write = goldfish_rtc_write, > > > > > + .endianness = DEVICE_BIG_ENDIAN, > > > > > + .valid = { > > > > > + .min_access_size = 4, > > > > > + .max_access_size = 4 > > > > > + } > > > > > + }, > > > > > }; > > > > > > > > You don't need 3 copies, only big and little. > > > > > > > > > +static Property goldfish_rtc_properties[] = { > > > > > + DEFINE_PROP_UINT8("endianness", GoldfishRTCState, endianness, > > > > > + DEVICE_NATIVE_ENDIAN), > > > > > + DEFINE_PROP_END_OF_LIST(), > > > > > +}; > > > > > > > > ... and I think the clear desire for default is little-endian. > > > > I would make the property be bool, and add a comment that this > > > > is only for m68k compatibility, so don't use it in new code. > > > > > > m68k doesn't really need this. > > > > > > kernel with the m68k virt machine and goldfish device supports > > > "native" mode so I think it's not needed to add another layer of > > > complexity for it. > > > > "Another level"? I'm talking about removing "native", and only having > > "big" and "little", which is less complexity. > > "Less complexity" is to keep only native. I'm not against the change, I'm > just saying it's not needed by m68k. Hi Laurent, I would agree if we only had m68k. But I am making this change so that OpenRISC (another big-endian architecture) could use this. In the OpenRISC case we want to use this as little-endian so no kernel updates would be needed. So in the end we will have the following qemu platforms: riscv{LE}--->goldfish_rtc{LE} mips-longsoon3{LE}-->goldfish_rtc{LE} openrisc{BE}>goldfish_rtc{LE} (LE to BE conversion done in driver) m68k{BE}>goldfish_rtc{BE} (only big-endian user) -Stafford
[PATCH 0/3] OpenRISC updates for user space FPU
This series adds support for the FPU related architecture changes defined in architecture spec revision v1.4. - https://openrisc.io/revisions/r1.4 In summary the architecture changes are: - Change FPCSR SPR permissions to allow for reading and writing from user space. - Clarify that FPU underflow detection is done by detecting tininess before rounding. Previous to this series FPCSR reads and writes from user-mode in QEMU would throw an illegal argument exception. The proper behavior should have been to treat these operations as no-ops as the cpu implementations do. As mentioned series changes FPCSR read/write to follow the spec. The series has been tested with the FPU support added in glibc test suite and all math tests are passing. Stafford Horne (3): target/openrisc: Allow fpcsr access in user mode target/openrisc: Set PC to cpu state on FPU exception target/openrisc: Setup FPU for detecting tininess before rounding target/openrisc/cpu.c| 5 +++ target/openrisc/fpu_helper.c | 4 ++ target/openrisc/sys_helper.c | 45 +- target/openrisc/translate.c | 72 4 files changed, 76 insertions(+), 50 deletions(-) -- 2.39.1
[PATCH 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
OpenRISC defines tininess to be detected before rounding. Setup qemu to obey this. Signed-off-by: Stafford Horne --- target/openrisc/cpu.c | 5 + 1 file changed, 5 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 0ce4f796fa..cdbff26fb5 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -22,6 +22,7 @@ #include "qemu/qemu-print.h" #include "cpu.h" #include "exec/exec-all.h" +#include "fpu/softfloat-helpers.h" #include "tcg/tcg.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) @@ -90,6 +91,10 @@ static void openrisc_cpu_reset_hold(Object *obj) s->exception_index = -1; cpu_set_fpcsr(&cpu->env, 0); +set_default_nan_mode(1, &cpu->env.fp_status); +set_float_detect_tininess(float_tininess_before_rounding, + &cpu->env.fp_status); + #ifndef CONFIG_USER_ONLY cpu->env.picmr = 0x; cpu->env.picsr = 0x; -- 2.39.1
[PATCH 1/3] target/openrisc: Allow fpcsr access in user mode
As per OpenRISC spec 1.4 FPCSR can be read and written in user mode. Update mtspr and mfspr helpers to support this by moving the is_user check into the helper. There is a logic change here to no longer throw an illegal instruction exception when executing mtspr/mfspr in user mode. The illegal instruction exception is not part of the spec, so this should be OK. Link: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf Signed-off-by: Stafford Horne --- target/openrisc/sys_helper.c | 45 +- target/openrisc/translate.c | 72 2 files changed, 67 insertions(+), 50 deletions(-) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index ec145960e3..8a0259c710 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -29,17 +29,37 @@ #define TO_SPR(group, number) (((group) << 11) + (number)) +static inline bool is_user(CPUOpenRISCState *env) +{ +#ifdef CONFIG_USER_ONLY +return true; +#else +return (env->sr & SR_SM) == 0; +#endif +} + void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) { -#ifndef CONFIG_USER_ONLY OpenRISCCPU *cpu = env_archcpu(env); +#ifndef CONFIG_USER_ONLY CPUState *cs = env_cpu(env); target_ulong mr; int idx; #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +cpu_set_fpcsr(env, rb); +return; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 11): /* EVBAR */ env->evbar = rb; break; @@ -187,12 +207,8 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) cpu_openrisc_timer_update(cpu); qemu_mutex_unlock_iothread(); break; -#endif - -case TO_SPR(0, 20): /* FPCSR */ -cpu_set_fpcsr(env, rb); -break; } +#endif } target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, @@ -204,10 +220,22 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, OpenRISCCPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); int idx; +#else +OpenRISCCPU *cpu = env_archcpu(env); #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +return env->fpcsr; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 0): /* VR */ return env->vr; @@ -324,11 +352,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, cpu_openrisc_count_update(cpu); qemu_mutex_unlock_iothread(); return cpu_openrisc_count_get(cpu); -#endif - -case TO_SPR(0, 20): /* FPCSR */ -return env->fpcsr; } +#endif /* for rd is passed in, if rd unchanged, just keep it back. */ return rd; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 76e53c78d4..43ba0cc1ad 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -819,45 +819,12 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a) static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) { -check_r0_write(dc, a->d); - -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr = tcg_temp_new(); - -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -if (dc->delayed_branch) { -tcg_gen_mov_tl(cpu_pc, jmp_pc); -tcg_gen_discard_tl(jmp_pc); -} else { -tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); -} -dc->base.is_jmp = DISAS_EXIT; -} +TCGv spr = tcg_temp_new(); -tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); -gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); -} -return true; -} - -static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) -{ -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr; +check_r0_write(dc, a->d); -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -} -/* For SR, we will need to exit the TB to recognize the new - * exception state. For NPC, in theory this counts as a branch - * (although the SPR only exists for use by an ICE). Save all - * of the cpu state first, allowing it to be overwritten. - */ +if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { +gen_io_start(); if (dc->delayed_branch) { tcg_gen_mov_tl(cpu_pc, jmp_pc); tcg_gen_discard_tl(jmp_pc); @@ -865,11 +832,36 @@ static bool trans_l_mtspr(DisasContext *dc
[PATCH 2/3] target/openrisc: Set PC to cpu state on FPU exception
Store the PC to ensure the correct value can be read in the exception handler. Signed-off-by: Stafford Horne --- target/openrisc/fpu_helper.c | 4 1 file changed, 4 insertions(+) diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index f9e34fa2cc..1feebb9ac7 100644 --- a/target/openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "exception.h" #include "fpu/softfloat.h" @@ -55,6 +56,9 @@ void HELPER(update_fpcsr)(CPUOpenRISCState *env) if (tmp) { env->fpcsr |= tmp; if (env->fpcsr & FPCSR_FPEE) { +CPUState *cs = env_cpu(env); + +cpu_restore_state(cs, GETPC()); helper_exception(env, EXCP_FPE); } } -- 2.39.1
Re: [PATCH 1/3] target/openrisc: Allow fpcsr access in user mode
On Tue, May 02, 2023 at 07:57:29PM +0100, Stafford Horne wrote: > As per OpenRISC spec 1.4 FPCSR can be read and written in user mode. > > Update mtspr and mfspr helpers to support this by moving the is_user > check into the helper. > > There is a logic change here to no longer throw an illegal instruction > exception when executing mtspr/mfspr in user mode. The illegal > instruction exception is not part of the spec, so this should be OK. This is wrong, I considered doing it but left the exception in (moved to the helper). I will remove this bit of the commit messages in the next version. But it is something we could consider doing. Conversely, the architecture pec should be more clear as to what happens when mfspr/mtspr privileges are violated. -Stafford > Link: > https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf > Signed-off-by: Stafford Horne > --- > target/openrisc/sys_helper.c | 45 +- > target/openrisc/translate.c | 72 > 2 files changed, 67 insertions(+), 50 deletions(-) > > diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c > index ec145960e3..8a0259c710 100644 > --- a/target/openrisc/sys_helper.c > +++ b/target/openrisc/sys_helper.c > @@ -29,17 +29,37 @@ > > #define TO_SPR(group, number) (((group) << 11) + (number)) > > +static inline bool is_user(CPUOpenRISCState *env) > +{ > +#ifdef CONFIG_USER_ONLY > +return true; > +#else > +return (env->sr & SR_SM) == 0; > +#endif > +} > + > void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) > { > -#ifndef CONFIG_USER_ONLY > OpenRISCCPU *cpu = env_archcpu(env); > +#ifndef CONFIG_USER_ONLY > CPUState *cs = env_cpu(env); > target_ulong mr; > int idx; > #endif > > +/* Handle user accessible SPRs first. */ > switch (spr) { > +case TO_SPR(0, 20): /* FPCSR */ > +cpu_set_fpcsr(env, rb); > +return; > +} > + > +if (is_user(env)) { > +raise_exception(cpu, EXCP_ILLEGAL); > +} > + > #ifndef CONFIG_USER_ONLY > +switch (spr) { > case TO_SPR(0, 11): /* EVBAR */ > env->evbar = rb; > break; > @@ -187,12 +207,8 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong > spr, target_ulong rb) > cpu_openrisc_timer_update(cpu); > qemu_mutex_unlock_iothread(); > break; > -#endif > - > -case TO_SPR(0, 20): /* FPCSR */ > -cpu_set_fpcsr(env, rb); > -break; > } > +#endif > } > > target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, > @@ -204,10 +220,22 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, > target_ulong rd, > OpenRISCCPU *cpu = env_archcpu(env); > CPUState *cs = env_cpu(env); > int idx; > +#else > +OpenRISCCPU *cpu = env_archcpu(env); > #endif > > +/* Handle user accessible SPRs first. */ > switch (spr) { > +case TO_SPR(0, 20): /* FPCSR */ > +return env->fpcsr; > +} > + > +if (is_user(env)) { > +raise_exception(cpu, EXCP_ILLEGAL); > +} > + > #ifndef CONFIG_USER_ONLY > +switch (spr) { > case TO_SPR(0, 0): /* VR */ > return env->vr; > > @@ -324,11 +352,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, > target_ulong rd, > cpu_openrisc_count_update(cpu); > qemu_mutex_unlock_iothread(); > return cpu_openrisc_count_get(cpu); > -#endif > - > -case TO_SPR(0, 20): /* FPCSR */ > -return env->fpcsr; > } > +#endif > > /* for rd is passed in, if rd unchanged, just keep it back. */ > return rd; > diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c > index 76e53c78d4..43ba0cc1ad 100644 > --- a/target/openrisc/translate.c > +++ b/target/openrisc/translate.c > @@ -819,45 +819,12 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a) > > static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) > { > -check_r0_write(dc, a->d); > - > -if (is_user(dc)) { > -gen_illegal_exception(dc); > -} else { > -TCGv spr = tcg_temp_new(); > - > -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { > -gen_io_start(); > -if (dc->delayed_branch) { > -tcg_gen_mov_tl(cpu_pc, jmp_pc); > -tcg_gen_discard_tl(jmp_pc); > -} else { > -tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); > -} > -dc->base.is_jmp = DISAS_EXIT; > -
Re: [PATCH 2/3] target/openrisc: Set PC to cpu state on FPU exception
On Wed, May 03, 2023 at 08:36:13AM +0100, Richard Henderson wrote: > On 5/2/23 19:57, Stafford Horne wrote: > > @@ -55,6 +56,9 @@ void HELPER(update_fpcsr)(CPUOpenRISCState *env) > > if (tmp) { > > env->fpcsr |= tmp; > > if (env->fpcsr & FPCSR_FPEE) { > > +CPUState *cs = env_cpu(env); > > + > > +cpu_restore_state(cs, GETPC()); > > helper_exception(env, EXCP_FPE); > > Better to mirror do_range(). OK.
Re: [PATCH 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
On Wed, May 03, 2023 at 08:37:31AM +0100, Richard Henderson wrote: > On 5/2/23 19:57, Stafford Horne wrote: > > OpenRISC defines tininess to be detected before rounding. Setup qemu to > > obey this. > > > > Signed-off-by: Stafford Horne > > --- > > target/openrisc/cpu.c | 5 + > > 1 file changed, 5 insertions(+) > > > > diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c > > index 0ce4f796fa..cdbff26fb5 100644 > > --- a/target/openrisc/cpu.c > > +++ b/target/openrisc/cpu.c > > @@ -22,6 +22,7 @@ > > #include "qemu/qemu-print.h" > > #include "cpu.h" > > #include "exec/exec-all.h" > > +#include "fpu/softfloat-helpers.h" > > #include "tcg/tcg.h" > > static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) > > @@ -90,6 +91,10 @@ static void openrisc_cpu_reset_hold(Object *obj) > > s->exception_index = -1; > > cpu_set_fpcsr(&cpu->env, 0); > > +set_default_nan_mode(1, &cpu->env.fp_status); > > +set_float_detect_tininess(float_tininess_before_rounding, > > + &cpu->env.fp_status); > > You don't mention the nan change in the commit message. Right, and I am not sure I need it. Let me remove it and run tests again. I was just adding it as a few other architectures did who set float_tininess_before_rounding. Will clean this up.
Re: [PATCH 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
On Wed, May 03, 2023 at 10:41:42AM +0100, Richard Henderson wrote: > On 5/3/23 10:14, Stafford Horne wrote: > > > > +set_default_nan_mode(1, &cpu->env.fp_status); > > > > +set_float_detect_tininess(float_tininess_before_rounding, > > > > + &cpu->env.fp_status); > > > > > > You don't mention the nan change in the commit message. > > > > Right, and I am not sure I need it. Let me remove it and run tests again. > > I > > was just adding it as a few other architectures did who set > > float_tininess_before_rounding. > > What that does is *not* propagate NaN payloads from (some) input to the > output. This is certainly true of RISC-V, which specifies this in their > architecture manual. OpenRISC does not specify any NaN behaviour at all. Thanks, that is what I also gathered from reading up on it. > It's not a bad choice, really, and it almost certainly simplifies the design > of the FPU, as you can do NaN propagation and silencing in one step. Right, it makes sense to optimize. It doesn't look like any of our FPU implementation do that at the moment. I will check with bandvig who implemented the FPU to understand his thought on this. It at least deserves to be discussed how nan payload is to be handled in the architecture spec. -Stafford
Re: [PATCH] scripts/coverity-scan: Add xtensa and openrisc components
On Thu, May 04, 2023 at 02:45:26PM +0100, Peter Maydell wrote: > We have two target architectures which don't have Coverity components > defined for them: xtensa and openrisc. Add them. > > Signed-off-by: Peter Maydell > --- > As usual with coverity components, these will need to be added > manually via the scanner UI, since it has no import-from-file... > > scripts/coverity-scan/COMPONENTS.md | 6 ++ > 1 file changed, 6 insertions(+) > > diff --git a/scripts/coverity-scan/COMPONENTS.md > b/scripts/coverity-scan/COMPONENTS.md > index 7c48e0f1d21..add7c5a279c 100644 > --- a/scripts/coverity-scan/COMPONENTS.md > +++ b/scripts/coverity-scan/COMPONENTS.md > @@ -143,3 +143,9 @@ loongarch > > riscv >~ > (/qemu)?((/include)?/hw/riscv/.*|/target/riscv/.*|/hw/.*/(riscv_|ibex_|sifive_).*) > + > +openrisc > + ~ (/qemu)?((/include)?/hw/openrisc/.*|/target/openrisc/.*) This looks good to me for OpenRISC. Where can we view the coverity reports? Is it this?: https://scan.coverity.com/projects/378 Acked-by: Stafford Horne > +xtensa > + ~ (/qemu)?((/include)?/hw/xtensa/.*|/target/xtensa/.*)
[PULL 6/6] hw/openrisc/openrisc_sim: Add support for initrd loading
The initrd passed via the command line is loaded into memory. It's location and size is then added to the device tree so the kernel knows where to find it. Signed-off-by: Stafford Horne Reviewed-by: Peter Maydell --- hw/openrisc/openrisc_sim.c | 31 +++ 1 file changed, 31 insertions(+) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index e0e71c0faa..8184caa60b 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -315,6 +315,33 @@ static hwaddr openrisc_load_kernel(ram_addr_t ram_size, return 0; } +static hwaddr openrisc_load_initrd(Or1ksimState *state, const char *filename, + hwaddr load_start, uint64_t mem_size) +{ +void *fdt = state->fdt; +int size; +hwaddr start; + +/* We put the initrd right after the kernel; page aligned. */ +start = TARGET_PAGE_ALIGN(load_start); + +size = load_ramdisk(filename, start, mem_size - start); +if (size < 0) { +size = load_image_targphys(filename, start, mem_size - start); +if (size < 0) { +error_report("could not load ramdisk '%s'", filename); +exit(1); +} +} + +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-start", start); +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-end", start + size); + +return start + size; +} + static uint32_t openrisc_load_fdt(Or1ksimState *state, hwaddr load_start, uint64_t mem_size) { @@ -393,6 +420,10 @@ static void openrisc_sim_init(MachineState *machine) load_addr = openrisc_load_kernel(ram_size, kernel_filename); if (load_addr > 0) { +if (machine->initrd_filename) { +load_addr = openrisc_load_initrd(state, machine->initrd_filename, + load_addr, machine->ram_size); +} boot_info.fdt_addr = openrisc_load_fdt(state, load_addr, machine->ram_size); } -- 2.31.1
[PULL 0/6] OpenRISC DTS Generation patches for 7.0
The following changes since commit 4aa2e497a98bafe962e72997f67a369e4b52d9c1: Merge remote-tracking branch 'remotes/berrange-gitlab/tags/misc-next-pull-request' into staging (2022-02-23 09:25:05 +) are available in the Git repository at: git://github.com/stffrdhrn/qemu.git tags/or1k-pull-request for you to fetch changes up to 94c71f14e9ca15ede4172e0826d690b15069a7f8: hw/openrisc/openrisc_sim: Add support for initrd loading (2022-02-25 15:42:23 +0900) OpenRISC patches - Add automatic DTS generation to openrisc_sim ---- Stafford Horne (6): hw/openrisc/openrisc_sim: Create machine state for or1ksim hw/openrisc/openrisc_sim: Parameterize initialization hw/openrisc/openrisc_sim: Use IRQ splitter when connecting UART hw/openrisc/openrisc_sim: Increase max_cpus to 4 hw/openrisc/openrisc_sim: Add automatic device tree generation hw/openrisc/openrisc_sim: Add support for initrd loading configs/targets/or1k-softmmu.mak | 1 + hw/openrisc/openrisc_sim.c | 308 --- 2 files changed, 285 insertions(+), 24 deletions(-)
[PULL 4/6] hw/openrisc/openrisc_sim: Increase max_cpus to 4
Now that we no longer have a limit of 2 CPUs due to fixing the IRQ routing issues we can increase the max. Here we increase the limit to 4, we could go higher, but currently OMPIC has a limit of 4, so we align with that. Signed-off-by: Stafford Horne Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé --- hw/openrisc/openrisc_sim.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 5bfbac00f8..8cfb92bec6 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -37,6 +37,8 @@ #define KERNEL_LOAD_ADDR 0x100 +#define OR1KSIM_CPUS_MAX 4 + #define TYPE_OR1KSIM_MACHINE MACHINE_TYPE_NAME("or1k-sim") #define OR1KSIM_MACHINE(obj) \ OBJECT_CHECK(Or1ksimState, (obj), TYPE_OR1KSIM_MACHINE) @@ -197,12 +199,12 @@ static void openrisc_sim_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; const char *kernel_filename = machine->kernel_filename; -OpenRISCCPU *cpus[2] = {}; +OpenRISCCPU *cpus[OR1KSIM_CPUS_MAX] = {}; MemoryRegion *ram; int n; unsigned int smp_cpus = machine->smp.cpus; -assert(smp_cpus >= 1 && smp_cpus <= 2); +assert(smp_cpus >= 1 && smp_cpus <= OR1KSIM_CPUS_MAX); for (n = 0; n < smp_cpus; n++) { cpus[n] = OPENRISC_CPU(cpu_create(machine->cpu_type)); if (cpus[n] == NULL) { @@ -243,7 +245,7 @@ static void openrisc_sim_machine_init(ObjectClass *oc, void *data) mc->desc = "or1k simulation"; mc->init = openrisc_sim_init; -mc->max_cpus = 2; +mc->max_cpus = OR1KSIM_CPUS_MAX; mc->is_default = true; mc->default_cpu_type = OPENRISC_CPU_TYPE_NAME("or1200"); } -- 2.31.1
[PULL 2/6] hw/openrisc/openrisc_sim: Parameterize initialization
Move magic numbers to variables and enums. These will be reused for upcoming fdt initialization. Signed-off-by: Stafford Horne Reviewed-by: Philippe Mathieu-Daudé --- hw/openrisc/openrisc_sim.c | 42 ++ 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 26d2370e60..d12b3e0c5e 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -49,6 +49,29 @@ typedef struct Or1ksimState { } Or1ksimState; +enum { +OR1KSIM_DRAM, +OR1KSIM_UART, +OR1KSIM_ETHOC, +OR1KSIM_OMPIC, +}; + +enum { +OR1KSIM_OMPIC_IRQ = 1, +OR1KSIM_UART_IRQ = 2, +OR1KSIM_ETHOC_IRQ = 4, +}; + +static const struct MemmapEntry { +hwaddr base; +hwaddr size; +} or1ksim_memmap[] = { +[OR1KSIM_DRAM] = { 0x, 0 }, +[OR1KSIM_UART] = { 0x9000, 0x100 }, +[OR1KSIM_ETHOC] = { 0x9200, 0x800 }, +[OR1KSIM_OMPIC] = { 0x9800, 16 }, +}; + static struct openrisc_boot_info { uint32_t bootstrap_pc; } boot_info; @@ -176,21 +199,24 @@ static void openrisc_sim_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), 0, ram); if (nd_table[0].used) { -openrisc_sim_net_init(0x9200, 0x92000400, smp_cpus, - cpus, 4, nd_table); +openrisc_sim_net_init(or1ksim_memmap[OR1KSIM_ETHOC].base, + or1ksim_memmap[OR1KSIM_ETHOC].base + 0x400, + smp_cpus, cpus, + OR1KSIM_ETHOC_IRQ, nd_table); } if (smp_cpus > 1) { -openrisc_sim_ompic_init(0x9800, smp_cpus, cpus, 1); +openrisc_sim_ompic_init(or1ksim_memmap[OR1KSIM_OMPIC].base, smp_cpus, +cpus, OR1KSIM_OMPIC_IRQ); -serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, 2), -get_cpu_irq(cpus, 1, 2)); +serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, OR1KSIM_UART_IRQ), +get_cpu_irq(cpus, 1, OR1KSIM_UART_IRQ)); } else { -serial_irq = get_cpu_irq(cpus, 0, 2); +serial_irq = get_cpu_irq(cpus, 0, OR1KSIM_UART_IRQ); } -serial_mm_init(get_system_memory(), 0x9000, 0, serial_irq, - 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); +serial_mm_init(get_system_memory(), or1ksim_memmap[OR1KSIM_UART].base, 0, + serial_irq, 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); openrisc_load_kernel(ram_size, kernel_filename); } -- 2.31.1
[PULL 3/6] hw/openrisc/openrisc_sim: Use IRQ splitter when connecting UART
Currently the OpenRISC SMP configuration only supports 2 cores due to the UART IRQ routing being limited to 2 cores. As was done in commit 1eeffbeb11 ("hw/openrisc/openrisc_sim: Use IRQ splitter when connecting IRQ to multiple CPUs") we can use a splitter to wire more than 2 CPUs. This patch moves serial initialization out to it's own function and uses a splitter to connect multiple CPU irq lines to the UART. Signed-off-by: Stafford Horne Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé --- hw/openrisc/openrisc_sim.c | 32 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index d12b3e0c5e..5bfbac00f8 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -137,6 +137,28 @@ static void openrisc_sim_ompic_init(hwaddr base, int num_cpus, sysbus_mmio_map(s, 0, base); } +static void openrisc_sim_serial_init(hwaddr base, int num_cpus, + OpenRISCCPU *cpus[], int irq_pin) +{ +qemu_irq serial_irq; +int i; + +if (num_cpus > 1) { +DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); +qdev_prop_set_uint32(splitter, "num-lines", num_cpus); +qdev_realize_and_unref(splitter, NULL, &error_fatal); +for (i = 0; i < num_cpus; i++) { +qdev_connect_gpio_out(splitter, i, get_cpu_irq(cpus, i, irq_pin)); +} +serial_irq = qdev_get_gpio_in(splitter, 0); +} else { +serial_irq = get_cpu_irq(cpus, 0, irq_pin); +} +serial_mm_init(get_system_memory(), base, 0, serial_irq, 115200, + serial_hd(0), DEVICE_NATIVE_ENDIAN); +} + + static void openrisc_load_kernel(ram_addr_t ram_size, const char *kernel_filename) { @@ -177,7 +199,6 @@ static void openrisc_sim_init(MachineState *machine) const char *kernel_filename = machine->kernel_filename; OpenRISCCPU *cpus[2] = {}; MemoryRegion *ram; -qemu_irq serial_irq; int n; unsigned int smp_cpus = machine->smp.cpus; @@ -208,15 +229,10 @@ static void openrisc_sim_init(MachineState *machine) if (smp_cpus > 1) { openrisc_sim_ompic_init(or1ksim_memmap[OR1KSIM_OMPIC].base, smp_cpus, cpus, OR1KSIM_OMPIC_IRQ); - -serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, OR1KSIM_UART_IRQ), -get_cpu_irq(cpus, 1, OR1KSIM_UART_IRQ)); -} else { -serial_irq = get_cpu_irq(cpus, 0, OR1KSIM_UART_IRQ); } -serial_mm_init(get_system_memory(), or1ksim_memmap[OR1KSIM_UART].base, 0, - serial_irq, 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); +openrisc_sim_serial_init(or1ksim_memmap[OR1KSIM_UART].base, smp_cpus, cpus, + OR1KSIM_UART_IRQ); openrisc_load_kernel(ram_size, kernel_filename); } -- 2.31.1
[PULL 1/6] hw/openrisc/openrisc_sim: Create machine state for or1ksim
This will allow us to attach machine state attributes like the device tree fdt. Signed-off-by: Stafford Horne Reviewed-by: Philippe Mathieu-Daudé --- hw/openrisc/openrisc_sim.c | 30 -- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 73fe383c2d..26d2370e60 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -37,6 +37,18 @@ #define KERNEL_LOAD_ADDR 0x100 +#define TYPE_OR1KSIM_MACHINE MACHINE_TYPE_NAME("or1k-sim") +#define OR1KSIM_MACHINE(obj) \ +OBJECT_CHECK(Or1ksimState, (obj), TYPE_OR1KSIM_MACHINE) + +typedef struct Or1ksimState { +/*< private >*/ +MachineState parent_obj; + +/*< public >*/ + +} Or1ksimState; + static struct openrisc_boot_info { uint32_t bootstrap_pc; } boot_info; @@ -183,8 +195,10 @@ static void openrisc_sim_init(MachineState *machine) openrisc_load_kernel(ram_size, kernel_filename); } -static void openrisc_sim_machine_init(MachineClass *mc) +static void openrisc_sim_machine_init(ObjectClass *oc, void *data) { +MachineClass *mc = MACHINE_CLASS(oc); + mc->desc = "or1k simulation"; mc->init = openrisc_sim_init; mc->max_cpus = 2; @@ -192,4 +206,16 @@ static void openrisc_sim_machine_init(MachineClass *mc) mc->default_cpu_type = OPENRISC_CPU_TYPE_NAME("or1200"); } -DEFINE_MACHINE("or1k-sim", openrisc_sim_machine_init) +static const TypeInfo or1ksim_machine_typeinfo = { +.name = TYPE_OR1KSIM_MACHINE, +.parent = TYPE_MACHINE, +.class_init = openrisc_sim_machine_init, +.instance_size = sizeof(Or1ksimState), +}; + +static void or1ksim_machine_init_register_types(void) +{ +type_register_static(&or1ksim_machine_typeinfo); +} + +type_init(or1ksim_machine_init_register_types) -- 2.31.1
[PULL 5/6] hw/openrisc/openrisc_sim: Add automatic device tree generation
Using the device tree means that qemu can now directly tell the kernel what hardware is configured rather than use having to maintain and update a separate device tree file. This patch adds automatic device tree generation support for the OpenRISC simulator. A device tree is built up based on the state of the configure openrisc simulator. This is then dumped to memory and the load address is passed to the kernel in register r3. Signed-off-by: Stafford Horne Reviewed-by: Peter Maydell --- configs/targets/or1k-softmmu.mak | 1 + hw/openrisc/openrisc_sim.c | 189 --- 2 files changed, 175 insertions(+), 15 deletions(-) diff --git a/configs/targets/or1k-softmmu.mak b/configs/targets/or1k-softmmu.mak index 1dfb93e46d..9e1d4a1fb1 100644 --- a/configs/targets/or1k-softmmu.mak +++ b/configs/targets/or1k-softmmu.mak @@ -1,2 +1,3 @@ TARGET_ARCH=openrisc TARGET_WORDS_BIGENDIAN=y +TARGET_NEED_FDT=y diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 8cfb92bec6..e0e71c0faa 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -29,15 +29,20 @@ #include "net/net.h" #include "hw/loader.h" #include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "sysemu/device_tree.h" #include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" #include "hw/core/split-irq.h" +#include + #define KERNEL_LOAD_ADDR 0x100 #define OR1KSIM_CPUS_MAX 4 +#define OR1KSIM_CLK_MHZ 2000 #define TYPE_OR1KSIM_MACHINE MACHINE_TYPE_NAME("or1k-sim") #define OR1KSIM_MACHINE(obj) \ @@ -48,6 +53,8 @@ typedef struct Or1ksimState { MachineState parent_obj; /*< public >*/ +void *fdt; +int fdt_size; } Or1ksimState; @@ -76,6 +83,7 @@ static const struct MemmapEntry { static struct openrisc_boot_info { uint32_t bootstrap_pc; +uint32_t fdt_addr; } boot_info; static void main_cpu_reset(void *opaque) @@ -86,6 +94,7 @@ static void main_cpu_reset(void *opaque) cpu_reset(CPU(cpu)); cpu_set_pc(cs, boot_info.bootstrap_pc); +cpu_set_gpr(&cpu->env, 3, boot_info.fdt_addr); } static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) @@ -93,12 +102,77 @@ static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) return qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "IRQ", irq_pin); } -static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors, +static void openrisc_create_fdt(Or1ksimState *state, +const struct MemmapEntry *memmap, +int num_cpus, uint64_t mem_size, +const char *cmdline) +{ +void *fdt; +int cpu; +char *nodename; +int pic_ph; + +fdt = state->fdt = create_device_tree(&state->fdt_size); +if (!fdt) { +error_report("create_device_tree() failed"); +exit(1); +} + +qemu_fdt_setprop_string(fdt, "/", "compatible", "opencores,or1ksim"); +qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x1); +qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1); + +nodename = g_strdup_printf("/memory@%" HWADDR_PRIx, + memmap[OR1KSIM_DRAM].base); +qemu_fdt_add_subnode(fdt, nodename); +qemu_fdt_setprop_cells(fdt, nodename, "reg", + memmap[OR1KSIM_DRAM].base, mem_size); +qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory"); +g_free(nodename); + +qemu_fdt_add_subnode(fdt, "/cpus"); +qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0); +qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1); + +for (cpu = 0; cpu < num_cpus; cpu++) { +nodename = g_strdup_printf("/cpus/cpu@%d", cpu); +qemu_fdt_add_subnode(fdt, nodename); +qemu_fdt_setprop_string(fdt, nodename, "compatible", +"opencores,or1200-rtlsvn481"); +qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu); +qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", + OR1KSIM_CLK_MHZ); +g_free(nodename); +} + +nodename = (char *)"/pic"; +qemu_fdt_add_subnode(fdt, nodename); +pic_ph = qemu_fdt_alloc_phandle(fdt); +qemu_fdt_setprop_string(fdt, nodename, "compatible", +"opencores,or1k-pic-level"); +qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1); +qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); +qemu_fdt_setprop_cell
Re: [PULL 0/6] OpenRISC DTS Generation patches for 7.0
On Fri, Feb 25, 2022 at 01:52:52PM +, Peter Maydell wrote: > On Fri, 25 Feb 2022 at 09:19, Stafford Horne wrote: > > > > The following changes since commit 4aa2e497a98bafe962e72997f67a369e4b52d9c1: > > > > Merge remote-tracking branch > > 'remotes/berrange-gitlab/tags/misc-next-pull-request' into staging > > (2022-02-23 09:25:05 +) > > > > are available in the Git repository at: > > > > git://github.com/stffrdhrn/qemu.git tags/or1k-pull-request > > > > for you to fetch changes up to 94c71f14e9ca15ede4172e0826d690b15069a7f8: > > > > hw/openrisc/openrisc_sim: Add support for initrd loading (2022-02-25 > > 15:42:23 +0900) > > > > > > OpenRISC patches > > > > - Add automatic DTS generation to openrisc_sim > > > > > > Stafford Horne (6): > > hw/openrisc/openrisc_sim: Create machine state for or1ksim > > hw/openrisc/openrisc_sim: Parameterize initialization > > hw/openrisc/openrisc_sim: Use IRQ splitter when connecting UART > > hw/openrisc/openrisc_sim: Increase max_cpus to 4 > > hw/openrisc/openrisc_sim: Add automatic device tree generation > > hw/openrisc/openrisc_sim: Add support for initrd loading > > Hi; this fails to build on various CI configs, eg: > https://gitlab.com/qemu-project/qemu/-/jobs/2137393314 > https://gitlab.com/qemu-project/qemu/-/jobs/2137393335 > > ../hw/openrisc/openrisc_sim.c:40:10: fatal error: libfdt.h: No such > file or directory > 40 | #include > | ^~ > > > This happens because meson doesn't put the include path for libfdt > on the include path for every .c file -- you have to do something > special in the meson.build file for the files that include it. > Paolo can tell you what that is, I expect. OK, I missed the CI results as it was all working for me. I will fix and test with the same as CI configs. -Stafford > Paolo: are we going to be able to stop doing this at some point > and get meson to just DTRT and put includes on the path for > every C file ? > > thanks > -- PMM
[PULL v2 0/6] OpenRISC DTS Generation patches for 7.0
The following changes since commit 4aa2e497a98bafe962e72997f67a369e4b52d9c1: Merge remote-tracking branch 'remotes/berrange-gitlab/tags/misc-next-pull-request' into staging (2022-02-23 09:25:05 +) are available in the Git repository at: git://github.com/stffrdhrn/qemu.git tags/or1k-pull-request for you to fetch changes up to 9576abf28280499a4497f39c2fae55bf97285e94: hw/openrisc/openrisc_sim: Add support for initrd loading (2022-02-26 10:39:36 +0900) OpenRISC patches - Add automatic DTS generation to openrisc_sim Since v1: - Added fdt file include into meson.build - I couldn't figure out how to run CI easily, so but I think this is the right fix. Stafford Horne (6): hw/openrisc/openrisc_sim: Create machine state for or1ksim hw/openrisc/openrisc_sim: Parameterize initialization hw/openrisc/openrisc_sim: Use IRQ splitter when connecting UART hw/openrisc/openrisc_sim: Increase max_cpus to 4 hw/openrisc/openrisc_sim: Add automatic device tree generation hw/openrisc/openrisc_sim: Add support for initrd loading configs/targets/or1k-softmmu.mak | 1 + hw/openrisc/meson.build | 2 +- hw/openrisc/openrisc_sim.c | 308 --- 3 files changed, 286 insertions(+), 25 deletions(-)
[PULL v2 1/6] hw/openrisc/openrisc_sim: Create machine state for or1ksim
This will allow us to attach machine state attributes like the device tree fdt. Signed-off-by: Stafford Horne Reviewed-by: Philippe Mathieu-Daudé --- hw/openrisc/openrisc_sim.c | 30 -- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 73fe383c2d..26d2370e60 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -37,6 +37,18 @@ #define KERNEL_LOAD_ADDR 0x100 +#define TYPE_OR1KSIM_MACHINE MACHINE_TYPE_NAME("or1k-sim") +#define OR1KSIM_MACHINE(obj) \ +OBJECT_CHECK(Or1ksimState, (obj), TYPE_OR1KSIM_MACHINE) + +typedef struct Or1ksimState { +/*< private >*/ +MachineState parent_obj; + +/*< public >*/ + +} Or1ksimState; + static struct openrisc_boot_info { uint32_t bootstrap_pc; } boot_info; @@ -183,8 +195,10 @@ static void openrisc_sim_init(MachineState *machine) openrisc_load_kernel(ram_size, kernel_filename); } -static void openrisc_sim_machine_init(MachineClass *mc) +static void openrisc_sim_machine_init(ObjectClass *oc, void *data) { +MachineClass *mc = MACHINE_CLASS(oc); + mc->desc = "or1k simulation"; mc->init = openrisc_sim_init; mc->max_cpus = 2; @@ -192,4 +206,16 @@ static void openrisc_sim_machine_init(MachineClass *mc) mc->default_cpu_type = OPENRISC_CPU_TYPE_NAME("or1200"); } -DEFINE_MACHINE("or1k-sim", openrisc_sim_machine_init) +static const TypeInfo or1ksim_machine_typeinfo = { +.name = TYPE_OR1KSIM_MACHINE, +.parent = TYPE_MACHINE, +.class_init = openrisc_sim_machine_init, +.instance_size = sizeof(Or1ksimState), +}; + +static void or1ksim_machine_init_register_types(void) +{ +type_register_static(&or1ksim_machine_typeinfo); +} + +type_init(or1ksim_machine_init_register_types) -- 2.31.1
[PULL v2 4/6] hw/openrisc/openrisc_sim: Increase max_cpus to 4
Now that we no longer have a limit of 2 CPUs due to fixing the IRQ routing issues we can increase the max. Here we increase the limit to 4, we could go higher, but currently OMPIC has a limit of 4, so we align with that. Signed-off-by: Stafford Horne Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé --- hw/openrisc/openrisc_sim.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 5bfbac00f8..8cfb92bec6 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -37,6 +37,8 @@ #define KERNEL_LOAD_ADDR 0x100 +#define OR1KSIM_CPUS_MAX 4 + #define TYPE_OR1KSIM_MACHINE MACHINE_TYPE_NAME("or1k-sim") #define OR1KSIM_MACHINE(obj) \ OBJECT_CHECK(Or1ksimState, (obj), TYPE_OR1KSIM_MACHINE) @@ -197,12 +199,12 @@ static void openrisc_sim_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; const char *kernel_filename = machine->kernel_filename; -OpenRISCCPU *cpus[2] = {}; +OpenRISCCPU *cpus[OR1KSIM_CPUS_MAX] = {}; MemoryRegion *ram; int n; unsigned int smp_cpus = machine->smp.cpus; -assert(smp_cpus >= 1 && smp_cpus <= 2); +assert(smp_cpus >= 1 && smp_cpus <= OR1KSIM_CPUS_MAX); for (n = 0; n < smp_cpus; n++) { cpus[n] = OPENRISC_CPU(cpu_create(machine->cpu_type)); if (cpus[n] == NULL) { @@ -243,7 +245,7 @@ static void openrisc_sim_machine_init(ObjectClass *oc, void *data) mc->desc = "or1k simulation"; mc->init = openrisc_sim_init; -mc->max_cpus = 2; +mc->max_cpus = OR1KSIM_CPUS_MAX; mc->is_default = true; mc->default_cpu_type = OPENRISC_CPU_TYPE_NAME("or1200"); } -- 2.31.1
[PULL v2 2/6] hw/openrisc/openrisc_sim: Parameterize initialization
Move magic numbers to variables and enums. These will be reused for upcoming fdt initialization. Signed-off-by: Stafford Horne Reviewed-by: Philippe Mathieu-Daudé --- hw/openrisc/openrisc_sim.c | 42 ++ 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 26d2370e60..d12b3e0c5e 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -49,6 +49,29 @@ typedef struct Or1ksimState { } Or1ksimState; +enum { +OR1KSIM_DRAM, +OR1KSIM_UART, +OR1KSIM_ETHOC, +OR1KSIM_OMPIC, +}; + +enum { +OR1KSIM_OMPIC_IRQ = 1, +OR1KSIM_UART_IRQ = 2, +OR1KSIM_ETHOC_IRQ = 4, +}; + +static const struct MemmapEntry { +hwaddr base; +hwaddr size; +} or1ksim_memmap[] = { +[OR1KSIM_DRAM] = { 0x, 0 }, +[OR1KSIM_UART] = { 0x9000, 0x100 }, +[OR1KSIM_ETHOC] = { 0x9200, 0x800 }, +[OR1KSIM_OMPIC] = { 0x9800, 16 }, +}; + static struct openrisc_boot_info { uint32_t bootstrap_pc; } boot_info; @@ -176,21 +199,24 @@ static void openrisc_sim_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), 0, ram); if (nd_table[0].used) { -openrisc_sim_net_init(0x9200, 0x92000400, smp_cpus, - cpus, 4, nd_table); +openrisc_sim_net_init(or1ksim_memmap[OR1KSIM_ETHOC].base, + or1ksim_memmap[OR1KSIM_ETHOC].base + 0x400, + smp_cpus, cpus, + OR1KSIM_ETHOC_IRQ, nd_table); } if (smp_cpus > 1) { -openrisc_sim_ompic_init(0x9800, smp_cpus, cpus, 1); +openrisc_sim_ompic_init(or1ksim_memmap[OR1KSIM_OMPIC].base, smp_cpus, +cpus, OR1KSIM_OMPIC_IRQ); -serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, 2), -get_cpu_irq(cpus, 1, 2)); +serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, OR1KSIM_UART_IRQ), +get_cpu_irq(cpus, 1, OR1KSIM_UART_IRQ)); } else { -serial_irq = get_cpu_irq(cpus, 0, 2); +serial_irq = get_cpu_irq(cpus, 0, OR1KSIM_UART_IRQ); } -serial_mm_init(get_system_memory(), 0x9000, 0, serial_irq, - 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); +serial_mm_init(get_system_memory(), or1ksim_memmap[OR1KSIM_UART].base, 0, + serial_irq, 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); openrisc_load_kernel(ram_size, kernel_filename); } -- 2.31.1
[PULL v2 3/6] hw/openrisc/openrisc_sim: Use IRQ splitter when connecting UART
Currently the OpenRISC SMP configuration only supports 2 cores due to the UART IRQ routing being limited to 2 cores. As was done in commit 1eeffbeb11 ("hw/openrisc/openrisc_sim: Use IRQ splitter when connecting IRQ to multiple CPUs") we can use a splitter to wire more than 2 CPUs. This patch moves serial initialization out to it's own function and uses a splitter to connect multiple CPU irq lines to the UART. Signed-off-by: Stafford Horne Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé --- hw/openrisc/openrisc_sim.c | 32 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index d12b3e0c5e..5bfbac00f8 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -137,6 +137,28 @@ static void openrisc_sim_ompic_init(hwaddr base, int num_cpus, sysbus_mmio_map(s, 0, base); } +static void openrisc_sim_serial_init(hwaddr base, int num_cpus, + OpenRISCCPU *cpus[], int irq_pin) +{ +qemu_irq serial_irq; +int i; + +if (num_cpus > 1) { +DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); +qdev_prop_set_uint32(splitter, "num-lines", num_cpus); +qdev_realize_and_unref(splitter, NULL, &error_fatal); +for (i = 0; i < num_cpus; i++) { +qdev_connect_gpio_out(splitter, i, get_cpu_irq(cpus, i, irq_pin)); +} +serial_irq = qdev_get_gpio_in(splitter, 0); +} else { +serial_irq = get_cpu_irq(cpus, 0, irq_pin); +} +serial_mm_init(get_system_memory(), base, 0, serial_irq, 115200, + serial_hd(0), DEVICE_NATIVE_ENDIAN); +} + + static void openrisc_load_kernel(ram_addr_t ram_size, const char *kernel_filename) { @@ -177,7 +199,6 @@ static void openrisc_sim_init(MachineState *machine) const char *kernel_filename = machine->kernel_filename; OpenRISCCPU *cpus[2] = {}; MemoryRegion *ram; -qemu_irq serial_irq; int n; unsigned int smp_cpus = machine->smp.cpus; @@ -208,15 +229,10 @@ static void openrisc_sim_init(MachineState *machine) if (smp_cpus > 1) { openrisc_sim_ompic_init(or1ksim_memmap[OR1KSIM_OMPIC].base, smp_cpus, cpus, OR1KSIM_OMPIC_IRQ); - -serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, OR1KSIM_UART_IRQ), -get_cpu_irq(cpus, 1, OR1KSIM_UART_IRQ)); -} else { -serial_irq = get_cpu_irq(cpus, 0, OR1KSIM_UART_IRQ); } -serial_mm_init(get_system_memory(), or1ksim_memmap[OR1KSIM_UART].base, 0, - serial_irq, 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); +openrisc_sim_serial_init(or1ksim_memmap[OR1KSIM_UART].base, smp_cpus, cpus, + OR1KSIM_UART_IRQ); openrisc_load_kernel(ram_size, kernel_filename); } -- 2.31.1
[PULL v2 5/6] hw/openrisc/openrisc_sim: Add automatic device tree generation
Using the device tree means that qemu can now directly tell the kernel what hardware is configured rather than use having to maintain and update a separate device tree file. This patch adds automatic device tree generation support for the OpenRISC simulator. A device tree is built up based on the state of the configure openrisc simulator. This is then dumped to memory and the load address is passed to the kernel in register r3. Signed-off-by: Stafford Horne Reviewed-by: Peter Maydell --- Since v1: - Added fdt to CONFIG_OR1K_SIM source set configs/targets/or1k-softmmu.mak | 1 + hw/openrisc/meson.build | 2 +- hw/openrisc/openrisc_sim.c | 189 --- 3 files changed, 176 insertions(+), 16 deletions(-) diff --git a/configs/targets/or1k-softmmu.mak b/configs/targets/or1k-softmmu.mak index 1dfb93e46d..9e1d4a1fb1 100644 --- a/configs/targets/or1k-softmmu.mak +++ b/configs/targets/or1k-softmmu.mak @@ -1,2 +1,3 @@ TARGET_ARCH=openrisc TARGET_WORDS_BIGENDIAN=y +TARGET_NEED_FDT=y diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index 947f63ee08..ec48172c9d 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -1,5 +1,5 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) -openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: files('openrisc_sim.c')) +openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 8cfb92bec6..e0e71c0faa 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -29,15 +29,20 @@ #include "net/net.h" #include "hw/loader.h" #include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "sysemu/device_tree.h" #include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" #include "hw/core/split-irq.h" +#include + #define KERNEL_LOAD_ADDR 0x100 #define OR1KSIM_CPUS_MAX 4 +#define OR1KSIM_CLK_MHZ 2000 #define TYPE_OR1KSIM_MACHINE MACHINE_TYPE_NAME("or1k-sim") #define OR1KSIM_MACHINE(obj) \ @@ -48,6 +53,8 @@ typedef struct Or1ksimState { MachineState parent_obj; /*< public >*/ +void *fdt; +int fdt_size; } Or1ksimState; @@ -76,6 +83,7 @@ static const struct MemmapEntry { static struct openrisc_boot_info { uint32_t bootstrap_pc; +uint32_t fdt_addr; } boot_info; static void main_cpu_reset(void *opaque) @@ -86,6 +94,7 @@ static void main_cpu_reset(void *opaque) cpu_reset(CPU(cpu)); cpu_set_pc(cs, boot_info.bootstrap_pc); +cpu_set_gpr(&cpu->env, 3, boot_info.fdt_addr); } static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) @@ -93,12 +102,77 @@ static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) return qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "IRQ", irq_pin); } -static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors, +static void openrisc_create_fdt(Or1ksimState *state, +const struct MemmapEntry *memmap, +int num_cpus, uint64_t mem_size, +const char *cmdline) +{ +void *fdt; +int cpu; +char *nodename; +int pic_ph; + +fdt = state->fdt = create_device_tree(&state->fdt_size); +if (!fdt) { +error_report("create_device_tree() failed"); +exit(1); +} + +qemu_fdt_setprop_string(fdt, "/", "compatible", "opencores,or1ksim"); +qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x1); +qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1); + +nodename = g_strdup_printf("/memory@%" HWADDR_PRIx, + memmap[OR1KSIM_DRAM].base); +qemu_fdt_add_subnode(fdt, nodename); +qemu_fdt_setprop_cells(fdt, nodename, "reg", + memmap[OR1KSIM_DRAM].base, mem_size); +qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory"); +g_free(nodename); + +qemu_fdt_add_subnode(fdt, "/cpus"); +qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0); +qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1); + +for (cpu = 0; cpu < num_cpus; cpu++) { +nodename = g_strdup_printf("/cpus/cpu@%d", cpu); +qemu_fdt_add_subnode(fdt, nodename); +qemu_fdt_setprop_string(fdt, nodename, "compatible", +"opencores,or1200-rtlsvn481"); +qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu); +
[PULL v2 6/6] hw/openrisc/openrisc_sim: Add support for initrd loading
The initrd passed via the command line is loaded into memory. It's location and size is then added to the device tree so the kernel knows where to find it. Signed-off-by: Stafford Horne Reviewed-by: Peter Maydell --- hw/openrisc/openrisc_sim.c | 31 +++ 1 file changed, 31 insertions(+) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index e0e71c0faa..8184caa60b 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -315,6 +315,33 @@ static hwaddr openrisc_load_kernel(ram_addr_t ram_size, return 0; } +static hwaddr openrisc_load_initrd(Or1ksimState *state, const char *filename, + hwaddr load_start, uint64_t mem_size) +{ +void *fdt = state->fdt; +int size; +hwaddr start; + +/* We put the initrd right after the kernel; page aligned. */ +start = TARGET_PAGE_ALIGN(load_start); + +size = load_ramdisk(filename, start, mem_size - start); +if (size < 0) { +size = load_image_targphys(filename, start, mem_size - start); +if (size < 0) { +error_report("could not load ramdisk '%s'", filename); +exit(1); +} +} + +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-start", start); +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-end", start + size); + +return start + size; +} + static uint32_t openrisc_load_fdt(Or1ksimState *state, hwaddr load_start, uint64_t mem_size) { @@ -393,6 +420,10 @@ static void openrisc_sim_init(MachineState *machine) load_addr = openrisc_load_kernel(ram_size, kernel_filename); if (load_addr > 0) { +if (machine->initrd_filename) { +load_addr = openrisc_load_initrd(state, machine->initrd_filename, + load_addr, machine->ram_size); +} boot_info.fdt_addr = openrisc_load_fdt(state, load_addr, machine->ram_size); } -- 2.31.1
Re: [PATCH v4 32/41] linux-user/openrisc: Adjust signal for EXCP_RANGE, EXCP_FPE
On Wed, Oct 06, 2021 at 10:22:58AM -0700, Richard Henderson wrote: > The kernel vectors both of these through unhandled_exception, which > results in force_sig(SIGSEGV). This isn't very useful for userland > when enabling overflow traps or fpu traps, but c'est la vie. Thanks for looking into it. I am happy to accept kernel patches ;), otherwise these are now on my todo list. The FPU support is already something I am looking to take care of as mentioned before, but that is after I finish getting the glibc port upstreamed. That said, Reviewed-by: Stafford Horne > Cc: Stafford Horne > Signed-off-by: Richard Henderson > --- > linux-user/openrisc/cpu_loop.c | 13 + > 1 file changed, 5 insertions(+), 8 deletions(-) > > diff --git a/linux-user/openrisc/cpu_loop.c b/linux-user/openrisc/cpu_loop.c > index f6360db47c..de5417a262 100644 > --- a/linux-user/openrisc/cpu_loop.c > +++ b/linux-user/openrisc/cpu_loop.c > @@ -56,13 +56,17 @@ void cpu_loop(CPUOpenRISCState *env) > break; > case EXCP_DPF: > case EXCP_IPF: > -case EXCP_RANGE: > info.si_signo = TARGET_SIGSEGV; > info.si_errno = 0; > info.si_code = TARGET_SEGV_MAPERR; > info._sifields._sigfault._addr = env->pc; > queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); > break; > +case EXCP_RANGE: > +case EXCP_FPE: > +/* ??? The kernel vectors both of these to unhandled_exception. > */ > +force_sig(TARGET_SIGSEGV); > +break; > case EXCP_ALIGN: > info.si_signo = TARGET_SIGBUS; > info.si_errno = 0; > @@ -77,13 +81,6 @@ void cpu_loop(CPUOpenRISCState *env) > info._sifields._sigfault._addr = env->pc; > queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); > break; > -case EXCP_FPE: > -info.si_signo = TARGET_SIGFPE; > -info.si_errno = 0; > -info.si_code = 0; > -info._sifields._sigfault._addr = env->pc; > -queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); > -break; > case EXCP_INTERRUPT: > /* We processed the pending cpu work above. */ > break; > -- > 2.25.1 >
[PATCH 4/4] hw/openrisc/openrisc_sim: Add support for initrd loading
The loaded initrd is loaded into memory. It's location and size is then added to the device tree so the kernel knows where to find it. Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 32 +++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index d7c26af82c..5354797e20 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -187,6 +187,32 @@ static hwaddr openrisc_load_kernel(ram_addr_t ram_size, return 0; } +static hwaddr openrisc_load_initrd(Or1ksimState *s, const char *filename, +hwaddr load_start, uint64_t mem_size) +{ +int size; +hwaddr start; + +/* We put the initrd right after the kernel; page aligned. */ +start = TARGET_PAGE_ALIGN(load_start); + +size = load_ramdisk(filename, start, mem_size - start); +if (size < 0) { +size = load_image_targphys(filename, start, mem_size - start); +if (size < 0) { +error_report("could not load ramdisk '%s'", filename); +exit(1); +} +} + +qemu_fdt_setprop_cell(s->fdt, "/chosen", + "linux,initrd-start", start); +qemu_fdt_setprop_cell(s->fdt, "/chosen", + "linux,initrd-end", start + size); + +return start + size; +} + static uint32_t openrisc_load_fdt(Or1ksimState *s, hwaddr load_start, uint64_t mem_size) { @@ -198,7 +224,7 @@ static uint32_t openrisc_load_fdt(Or1ksimState *s, hwaddr load_start, exit(1); } -/* We should put fdt right after the kernel */ +/* We put fdt right after the kernel and/or initrd. */ fdt_addr = ROUND_UP(load_start, 4); fdt_pack(s->fdt); @@ -369,6 +395,10 @@ static void openrisc_sim_init(MachineState *machine) machine->kernel_cmdline); load_addr = openrisc_load_kernel(ram_size, kernel_filename); +if (machine->initrd_filename) { +load_addr = openrisc_load_initrd(s, machine->initrd_filename, + load_addr, machine->ram_size); +} boot_info.fdt_addr = openrisc_load_fdt(s, load_addr, machine->ram_size); } -- 2.31.1
[PATCH 3/4] hw/openrisc/openrisc_sim; Add support for loading a decice tree
Using the device tree means that qemu can now directly tell the kernel what hardware is configured rather than use having to maintain and update a separate device tree file. This patch adds device tree support for the OpenRISC simulator. A device tree is built up based on the state of the configure openrisc simulator. This is then dumpt to memory and the load address is passed to the kernel in register r3. Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 158 - 1 file changed, 154 insertions(+), 4 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 5a0cc4d27e..d7c26af82c 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -29,14 +29,20 @@ #include "net/net.h" #include "hw/loader.h" #include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "sysemu/device_tree.h" #include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" #include "hw/core/split-irq.h" +#include + #define KERNEL_LOAD_ADDR 0x100 +#define OR1KSIM_CLK_MHZ 2000 + #define TYPE_OR1KSIM_MACHINE MACHINE_TYPE_NAME("or1k-sim") #define OR1KSIM_MACHINE(obj) \ OBJECT_CHECK(Or1ksimState, (obj), TYPE_OR1KSIM_MACHINE) @@ -46,6 +52,8 @@ typedef struct Or1ksimState { MachineState parent_obj; /*< public >*/ +void *fdt; +int fdt_size; } Or1ksimState; @@ -74,6 +82,7 @@ static const struct MemmapEntry { static struct openrisc_boot_info { uint32_t bootstrap_pc; +uint32_t fdt_addr; } boot_info; static void main_cpu_reset(void *opaque) @@ -84,6 +93,7 @@ static void main_cpu_reset(void *opaque) cpu_reset(CPU(cpu)); cpu_set_pc(cs, boot_info.bootstrap_pc); +cpu_set_gpr(&cpu->env, 3, boot_info.fdt_addr); } static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) @@ -137,26 +147,29 @@ static void openrisc_sim_ompic_init(hwaddr base, int num_cpus, sysbus_mmio_map(s, 0, base); } -static void openrisc_load_kernel(ram_addr_t ram_size, +static hwaddr openrisc_load_kernel(ram_addr_t ram_size, const char *kernel_filename) { long kernel_size; uint64_t elf_entry; +uint64_t high_addr; hwaddr entry; if (kernel_filename && !qtest_enabled()) { kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - &elf_entry, NULL, NULL, NULL, 1, EM_OPENRISC, - 1, 0); + &elf_entry, NULL, &high_addr, NULL, 1, + EM_OPENRISC, 1, 0); entry = elf_entry; if (kernel_size < 0) { kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL, NULL, NULL); +high_addr = entry + kernel_size; } if (kernel_size < 0) { kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, ram_size - KERNEL_LOAD_ADDR); +high_addr = KERNEL_LOAD_ADDR + kernel_size; } if (entry <= 0) { @@ -168,7 +181,139 @@ static void openrisc_load_kernel(ram_addr_t ram_size, exit(1); } boot_info.bootstrap_pc = entry; + +return high_addr; +} +return 0; +} + +static uint32_t openrisc_load_fdt(Or1ksimState *s, hwaddr load_start, +uint64_t mem_size) +{ +uint32_t fdt_addr; +int fdtsize = fdt_totalsize(s->fdt); + +if (fdtsize <= 0) { +error_report("invalid device-tree"); +exit(1); +} + +/* We should put fdt right after the kernel */ +fdt_addr = ROUND_UP(load_start, 4); + +fdt_pack(s->fdt); +/* copy in the device tree */ +qemu_fdt_dumpdtb(s->fdt, fdtsize); + +rom_add_blob_fixed_as("fdt", s->fdt, fdtsize, fdt_addr, + &address_space_memory); + +return fdt_addr; +} + +static void openrisc_create_fdt(Or1ksimState *s, +const struct MemmapEntry *memmap, int num_cpus, uint64_t mem_size, +const char *cmdline) +{ +void *fdt; +int cpu; +char *nodename; +int pic_ph; + +fdt = s->fdt = create_device_tree(&s->fdt_size); +if (!fdt) { +error_report("create_device_tree() failed"); +exit(1); +} + +qemu_fdt_setprop_string(fdt, "/", "compatible", "opencores,or1ksim"); +qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x1); +qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1); + +nodename = g_strdup_printf("/memory@%lx", +
[PATCH 2/4] hw/openrisc/openrisc_sim: Paramatarize initialization
Move magic numbers to variables and enums. These will be reused for upcoming fdt initialization. Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 42 ++ 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index b83cc1c191..5a0cc4d27e 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -49,6 +49,29 @@ typedef struct Or1ksimState { } Or1ksimState; +enum { +OR1KSIM_DRAM, +OR1KSIM_UART, +OR1KSIM_ETHOC, +OR1KSIM_OMPIC, +}; + +enum { +OR1KSIM_OMPIC_IRQ = 1, +OR1KSIM_UART_IRQ = 2, +OR1KSIM_ETHOC_IRQ = 4, +}; + +static const struct MemmapEntry { +hwaddr base; +hwaddr size; +} or1ksim_memmap[] = { +[OR1KSIM_DRAM] = { 0x, 0 }, +[OR1KSIM_UART] = { 0x9000, 0x100 }, +[OR1KSIM_ETHOC] = { 0x9200, 0x800 }, +[OR1KSIM_OMPIC] = { 0x9800, 16 }, +}; + static struct openrisc_boot_info { uint32_t bootstrap_pc; } boot_info; @@ -177,21 +200,24 @@ static void openrisc_sim_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), 0, ram); if (nd_table[0].used) { -openrisc_sim_net_init(0x9200, 0x92000400, smp_cpus, - cpus, 4, nd_table); +openrisc_sim_net_init(or1ksim_memmap[OR1KSIM_ETHOC].base, + or1ksim_memmap[OR1KSIM_ETHOC].base + 0x400, + smp_cpus, cpus, + OR1KSIM_ETHOC_IRQ, nd_table); } if (smp_cpus > 1) { -openrisc_sim_ompic_init(0x9800, smp_cpus, cpus, 1); +openrisc_sim_ompic_init(or1ksim_memmap[OR1KSIM_OMPIC].base, smp_cpus, +cpus, OR1KSIM_OMPIC_IRQ); -serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, 2), -get_cpu_irq(cpus, 1, 2)); +serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, OR1KSIM_UART_IRQ), +get_cpu_irq(cpus, 1, OR1KSIM_UART_IRQ)); } else { -serial_irq = get_cpu_irq(cpus, 0, 2); +serial_irq = get_cpu_irq(cpus, 0, OR1KSIM_UART_IRQ); } -serial_mm_init(get_system_memory(), 0x9000, 0, serial_irq, - 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); +serial_mm_init(get_system_memory(), or1ksim_memmap[OR1KSIM_UART].base, 0, + serial_irq, 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); openrisc_load_kernel(ram_size, kernel_filename); } -- 2.31.1
[PATCH 1/4] hw/openrisc/openrisc_sim: Create machine state for or1ksim
This will allow us to attach machine state attributes like the device tree fdt. Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 31 +-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 73fe383c2d..b83cc1c191 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -37,6 +37,18 @@ #define KERNEL_LOAD_ADDR 0x100 +#define TYPE_OR1KSIM_MACHINE MACHINE_TYPE_NAME("or1k-sim") +#define OR1KSIM_MACHINE(obj) \ +OBJECT_CHECK(Or1ksimState, (obj), TYPE_OR1KSIM_MACHINE) + +typedef struct Or1ksimState { +/*< private >*/ +MachineState parent_obj; + +/*< public >*/ + +} Or1ksimState; + static struct openrisc_boot_info { uint32_t bootstrap_pc; } boot_info; @@ -141,6 +153,7 @@ static void openrisc_sim_init(MachineState *machine) ram_addr_t ram_size = machine->ram_size; const char *kernel_filename = machine->kernel_filename; OpenRISCCPU *cpus[2] = {}; +Or1ksimState *s = OR1KSIM_MACHINE(machine); MemoryRegion *ram; qemu_irq serial_irq; int n; @@ -183,8 +196,10 @@ static void openrisc_sim_init(MachineState *machine) openrisc_load_kernel(ram_size, kernel_filename); } -static void openrisc_sim_machine_init(MachineClass *mc) +static void openrisc_sim_machine_init(ObjectClass *oc, void *data) { +MachineClass *mc = MACHINE_CLASS(oc); + mc->desc = "or1k simulation"; mc->init = openrisc_sim_init; mc->max_cpus = 2; @@ -192,4 +207,16 @@ static void openrisc_sim_machine_init(MachineClass *mc) mc->default_cpu_type = OPENRISC_CPU_TYPE_NAME("or1200"); } -DEFINE_MACHINE("or1k-sim", openrisc_sim_machine_init) +static const TypeInfo or1ksim_machine_typeinfo = { +.name = TYPE_OR1KSIM_MACHINE, +.parent = TYPE_MACHINE, +.class_init = openrisc_sim_machine_init, +.instance_size = sizeof(Or1ksimState), +}; + +static void or1ksim_machine_init_register_types(void) +{ +type_register_static(&or1ksim_machine_typeinfo); +} + +type_init(or1ksim_machine_init_register_types) -- 2.31.1
[PATCH 0/4] OpenRISC Device Tree Support
This series adds device tree support for the OpenRISC SIM hardware. The simulator will generate an FDT and pass it to the kernel. For example: qemu-system-or1k -cpu or1200 -M or1k-sim \ -kernel /home/shorne/work/linux/vmlinux \ -initrd /home/shorne/work/linux/initramfs.cpio.gz \ -serial mon:stdio -nographic -gdb tcp::10001 -m 32 Using the linux kernel or1ksim_defconfig we can remove the built-in dts and the kernel will boot as expected. The real benefit here is being able to specify an external initrd which qemu will load into memory and the device tree will tell the kernel where to find it. -Stafford Stafford Horne (4): hw/openrisc/openrisc_sim: Create machine state for or1ksim hw/openrisc/openrisc_sim: Paramatarize initialization hw/openrisc/openrisc_sim; Add support for loading a decice tree hw/openrisc/openrisc_sim: Add support for initrd loading hw/openrisc/openrisc_sim.c | 261 +++-- 1 file changed, 247 insertions(+), 14 deletions(-) -- 2.31.1
Re: [PATCH v3 17/23] linux-user/openrisc: Use force_sig_fault
On Wed, Nov 03, 2021 at 10:08:41AM -0400, Richard Henderson wrote: > Use the new function instead of setting up a target_siginfo_t > and calling queue_signal. Fill in the missing PC for SIGTRAP. > > Signed-off-by: Richard Henderson > --- > linux-user/openrisc/cpu_loop.c | 18 +++--- > 1 file changed, 3 insertions(+), 15 deletions(-) > > diff --git a/linux-user/openrisc/cpu_loop.c b/linux-user/openrisc/cpu_loop.c > index 3cfdbbf037..9b3d6743d2 100644 > --- a/linux-user/openrisc/cpu_loop.c > +++ b/linux-user/openrisc/cpu_loop.c > @@ -29,7 +29,6 @@ void cpu_loop(CPUOpenRISCState *env) > CPUState *cs = env_cpu(env); > int trapnr; > abi_long ret; > -target_siginfo_t info; > > for (;;) { > cpu_exec_start(cs); > @@ -55,27 +54,16 @@ void cpu_loop(CPUOpenRISCState *env) > } > break; > case EXCP_ALIGN: > -info.si_signo = TARGET_SIGBUS; > -info.si_errno = 0; > -info.si_code = TARGET_BUS_ADRALN; > -info._sifields._sigfault._addr = env->pc; > -queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); > +force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, env->eear); > break; > case EXCP_ILLEGAL: > -info.si_signo = TARGET_SIGILL; > -info.si_errno = 0; > -info.si_code = TARGET_ILL_ILLOPC; > -info._sifields._sigfault._addr = env->pc; > -queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); > +force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc); > break; > case EXCP_INTERRUPT: > /* We processed the pending cpu work above. */ > break; > case EXCP_DEBUG: > -info.si_signo = TARGET_SIGTRAP; > -info.si_errno = 0; > -info.si_code = TARGET_TRAP_BRKPT; > -queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); > +force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); > break; > case EXCP_ATOMIC: > cpu_exec_step_atomic(cs); This looks ok to me. Reviewed-by: Stafford Horne
[PATCH] target/openrisc: Do not reset delay slot flag on early tb exit
This was found when running linux crypto algorithm selftests used by wireguard. We found that randomly the tests would fail. We found through investigation that a combination of a tick timer interrupt, raised when executing a delay slot instruction at a page boundary caused the issue. This was caused when handling the TB_EXIT_REQUESTED case in cpu_tb_exec. On OpenRISC, which doesn't implement synchronize_from_tb, set_pc was being used as a fallback. The OpenRISC set_pc implementation clears dflag, which caused the exception handling logic to not account for the delay slot. This was the bug, because it meant when execution resumed after the interrupt was handling it resumed in the wrong place. Fix this by implementing synchronize_from_tb which simply updates pc, and not clear the delay slot flag. Reported-by: Jason A. Donenfeld Signed-off-by: Stafford Horne --- target/openrisc/cpu.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index dfbafc5236..41d1b2a24a 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -21,6 +21,7 @@ #include "qapi/error.h" #include "qemu/qemu-print.h" #include "cpu.h" +#include "exec/exec-all.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) { @@ -30,6 +31,15 @@ static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.dflag = 0; } +static void openrisc_cpu_synchronize_from_tb(CPUState *cs, + const TranslationBlock *tb) +{ +OpenRISCCPU *cpu = OPENRISC_CPU(cs); + +cpu->env.pc = tb->pc; +} + + static bool openrisc_cpu_has_work(CPUState *cs) { return cs->interrupt_request & (CPU_INTERRUPT_HARD | @@ -186,6 +196,7 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = { static const struct TCGCPUOps openrisc_tcg_ops = { .initialize = openrisc_translate_init, +.synchronize_from_tb = openrisc_cpu_synchronize_from_tb, #ifndef CONFIG_USER_ONLY .tlb_fill = openrisc_cpu_tlb_fill, -- 2.31.1
Re: [PULL 3/4] Normalize header guard symbol definition
On Wed, May 11, 2022 at 04:59:21PM +0200, Markus Armbruster wrote: > We commonly define the header guard symbol without an explicit value. > Normalize the exceptions. > > Done with scripts/clean-header-guards.pl. > > Signed-off-by: Markus Armbruster > Message-Id: <20220506134911.2856099-4-arm...@redhat.com> > Reviewed-by: Richard Henderson > --- > include/exec/memopidx.h | 2 +- > include/tcg/tcg-ldst.h| 2 +- > target/alpha/cpu-param.h | 2 +- > target/arm/cpu-param.h| 2 +- > target/cris/cpu-param.h | 2 +- > target/hppa/cpu-param.h | 2 +- > target/i386/cpu-param.h | 2 +- > target/m68k/cpu-param.h | 2 +- > target/microblaze/cpu-param.h | 2 +- > target/mips/cpu-param.h | 2 +- > target/nios2/cpu-param.h | 2 +- > target/openrisc/cpu-param.h | 2 +- > target/ppc/cpu-param.h| 2 +- > target/riscv/cpu-param.h | 2 +- > target/s390x/cpu-param.h | 2 +- > target/sh4/cpu-param.h| 2 +- > target/sparc/cpu-param.h | 2 +- > target/tricore/cpu-param.h| 2 +- > target/xtensa/cpu-param.h | 2 +- > tcg/tcg-internal.h| 2 +- > 20 files changed, 20 insertions(+), 20 deletions(-) I looked at this for the OpenRISC changes, but the whole patch looks ok to me. Reviewed-by: Stafford Horne
Re: [PATCH] target/openrisc: Do not reset delay slot flag on early tb exit
On Wed, May 11, 2022 at 07:32:58AM -0700, Richard Henderson wrote: > On 5/11/22 05:05, Stafford Horne wrote: > > +static void openrisc_cpu_synchronize_from_tb(CPUState *cs, > > + const TranslationBlock *tb) > > +{ > > +OpenRISCCPU *cpu = OPENRISC_CPU(cs); > > + > > +cpu->env.pc = tb->pc; > > +} > > If mips is a guide, you'd want to set dflag based on > > tb->flags & TB_FLAGS_DFLAG > > as well. But I think openrisc is more careful to keep dflag up-to-date. I was thinking that too so I left it out. For example: 0xc01e3ffc: l.bf 3 0xc01e4000: l.ori r12, r0, 1 --- c01e3ffc movcond_i32 jmp_pc,sr_f,$0x0,$0xc01e4008,$0xc01e4004,ne sync: 0 dead: 0 1 2 3 4 pref=0x mov_i32 dflag,$0x1 sync: 0 dead: 0 1 pref=0x mov_i32 ppc,$0xc01e3ffc sync: 0 dead: 0 1 pref=0x mov_i32 pc,$0xc01e4000 sync: 0 dead: 0 1 pref=0x call lookup_tb_ptr,$0x6,$1,tmp7,env dead: 1 pref=none goto_ptr tmp7dead: 0 set_label $L0 exit_tb $0x7f7b047f3b43 --- ld_i32 tmp0,env,$0xfff0 pref=0x brcond_i32 tmp0,$0x0,lt,$L0 dead: 0 c01e4000 0001 mov_i32 r12,$0x1 sync: 0 dead: 0 1 pref=0x mov_i32 dflag,$0x0 sync: 0 dead: 0 1 pref=0x mov_i32 ppc,$0xc01e4000 sync: 0 dead: 0 1 pref=0x mov_i32 pc,jmp_pcsync: 0 dead: 0 1 pref=0x discard jmp_pc pref=none call lookup_tb_ptr,$0x6,$1,tmp4,env dead: 1 pref=none goto_ptr tmp4dead: 0 set_label $L0 exit_tb $0x7f7b047f3c83 This is an example of a branch followed by a branch delay slot. If we exit the branch delay slot via `exit_tb $0x7f7b047f3c83`. The `mov_i32 dflag,$0x1` instruction would have run from `c01e3ffc` having env already updated. At this point how would tb->flags have the right value? Would it always be set correctly by `cpu_get_tb_cpu_state` in the `lookup_tb_ptr`call? -Stafford
Re: [PATCH] target/openrisc: Do not reset delay slot flag on early tb exit
On Wed, May 11, 2022 at 02:56:37PM -0700, Richard Henderson wrote: > On 5/11/22 14:43, Stafford Horne wrote: > > At this point how would tb->flags have the right value? Would it always be > > set > > correctly by `cpu_get_tb_cpu_state` in the `lookup_tb_ptr`call? > > Well, it would be set by cpu_get_tb_cpu_state in cpu_exec, which is then > passed to tb_gen_code. If we go around a loop and look it up a second time, > we'll find a tb with a matching set of flags. Right, cpu_get_tb_cpu_state called in lookup_tb_ptr will not update tb->flags. What you mention, that is for when we have to generate a new TB, the tb->flags get set right before tb_gen_code. But for the case where we exit the delay-slot TB due to a pending exception I think the flow would go. TB chain: -> branch-TB : set env->flag 1 -> delay-slot-TB : exit_tb due to condition Exit: -> return to cpu_tb_exec -> tcg_ops->synchronize_from_tb In this case I don't see how the tb->flag would be updated, ooh, I guess it would have been set earlier when the TB was generated. Maybe that is what I am missing. -Stafford
Re: [PATCH] target/openrisc: Do not reset delay slot flag on early tb exit
On Wed, May 11, 2022 at 07:11:20PM -0700, Richard Henderson wrote: > On 5/11/22 15:34, Stafford Horne wrote: > > In this case I don't see how the tb->flag would be updated, ooh, I guess it > > would have been set earlier when the TB was generated. Maybe that is what > > I am > > missing. > > Correct, it should be unchanged (and correct) from generation. OK, its very clear now thanks. With that said, I am still not convinced we need something like: --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -37,6 +37,7 @@ static void openrisc_cpu_synchronize_from_tb(CPUState *cs, OpenRISCCPU *cpu = OPENRISC_CPU(cs); cpu->env.pc = tb->pc; +cpu->env.dflag = (tb->flags & TB_FLAGS_DFLAG) ? 1 : 0; } I will leave it out for now as I feel comfortable that the env.dflag will be correct. But if you think of something let me know. -Stafford
[PULL 0/4] OpenRISC fixes for QEMU 2022-05-15
The following changes since commit 2e3408b3cc7de4e87a9adafc8c19bfce3abec947: Merge tag 'misc-pull-request' of gitlab.com:marcandre.lureau/qemu into staging (2022-05-03 09:13:17 -0700) are available in the Git repository at: https://github.com/stffrdhrn/qemu.git tags/or1k-pull-request-20220515 for you to fetch changes up to e8f0ab0cd674241cbab7231ce05ac1bfa0b4f5ed: target/openrisc: Do not reset delay slot flag on early tb exit (2022-05-15 10:33:01 +0900) OpenRISC Fixes for 7.0 - A few or1ksim fixes and enhancements - A fix for OpenRISC tcg backend around delay slot handling Jason A. Donenfeld (3): hw/openrisc: page-align FDT address hw/openrisc: support 4 serial ports in or1ksim hw/openrisc: use right OMPIC size variable Stafford Horne (1): target/openrisc: Do not reset delay slot flag on early tb exit hw/openrisc/openrisc_sim.c | 28 +++- target/openrisc/cpu.c | 11 +++ 2 files changed, 30 insertions(+), 9 deletions(-) Jason A. Donenfeld (3): hw/openrisc: page-align FDT address hw/openrisc: support 4 serial ports in or1ksim hw/openrisc: use right OMPIC size variable Stafford Horne (1): target/openrisc: Do not reset delay slot flag on early tb exit hw/openrisc/openrisc_sim.c | 28 +++- target/openrisc/cpu.c | 11 +++ 2 files changed, 30 insertions(+), 9 deletions(-) -- 2.31.1
[PULL 1/4] hw/openrisc: page-align FDT address
From: "Jason A. Donenfeld" The QEMU-provided FDT was only being recognized by the kernel when it was used in conjunction with -initrd. Without it, the magic bytes wouldn't be there and the kernel couldn't load it. This patch fixes the issue by page aligning the provided FDT. Cc: Stafford Horne Cc: Peter Maydell Signed-off-by: Jason A. Donenfeld Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 8184caa60b..99b14940f4 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -356,7 +356,7 @@ static uint32_t openrisc_load_fdt(Or1ksimState *state, hwaddr load_start, } /* We put fdt right after the kernel and/or initrd. */ -fdt_addr = ROUND_UP(load_start, 4); +fdt_addr = TARGET_PAGE_ALIGN(load_start); ret = fdt_pack(fdt); /* Should only fail if we've built a corrupted tree */ -- 2.31.1
[PULL 3/4] hw/openrisc: use right OMPIC size variable
From: "Jason A. Donenfeld" This appears to be a copy and paste error. The UART size was used instead of the much smaller OMPIC size. But actually that smaller OMPIC size is wrong too and doesn't allow the IPI to work in Linux. So set it to the old value. Signed-off-by: Jason A. Donenfeld [smh:Updated OR1KSIM_OMPIC size to use OR1KSIM_CPUS_MAX] Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 6873124f74..35adce17ac 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -82,7 +82,7 @@ static const struct MemmapEntry { [OR1KSIM_DRAM] = { 0x, 0 }, [OR1KSIM_UART] = { 0x9000, 0x100 }, [OR1KSIM_ETHOC] = { 0x9200, 0x800 }, -[OR1KSIM_OMPIC] = { 0x9800, 16 }, +[OR1KSIM_OMPIC] = { 0x9800, OR1KSIM_CPUS_MAX * 8 }, }; static struct openrisc_boot_info { @@ -418,7 +418,7 @@ static void openrisc_sim_init(MachineState *machine) if (smp_cpus > 1) { openrisc_sim_ompic_init(state, or1ksim_memmap[OR1KSIM_OMPIC].base, -or1ksim_memmap[OR1KSIM_UART].size, +or1ksim_memmap[OR1KSIM_OMPIC].size, smp_cpus, cpus, OR1KSIM_OMPIC_IRQ); } -- 2.31.1
[PULL 2/4] hw/openrisc: support 4 serial ports in or1ksim
From: "Jason A. Donenfeld" The 8250 serial controller supports 4 serial ports, so wire them all up, so that we can have more than one basic I/O channel. Cc: Stafford Horne Signed-off-by: Jason A. Donenfeld [smh:Fixup indentation and lines over 80 chars] Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 22 -- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 99b14940f4..6873124f74 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -71,6 +71,10 @@ enum { OR1KSIM_ETHOC_IRQ = 4, }; +enum { +OR1KSIM_UART_COUNT = 4 +}; + static const struct MemmapEntry { hwaddr base; hwaddr size; @@ -239,11 +243,13 @@ static void openrisc_sim_ompic_init(Or1ksimState *state, hwaddr base, static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, hwaddr size, int num_cpus, - OpenRISCCPU *cpus[], int irq_pin) + OpenRISCCPU *cpus[], int irq_pin, + int uart_idx) { void *fdt = state->fdt; char *nodename; qemu_irq serial_irq; +char alias[sizeof("uart0")]; int i; if (num_cpus > 1) { @@ -258,7 +264,8 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, serial_irq = get_cpu_irq(cpus, 0, irq_pin); } serial_mm_init(get_system_memory(), base, 0, serial_irq, 115200, - serial_hd(0), DEVICE_NATIVE_ENDIAN); + serial_hd(OR1KSIM_UART_COUNT - uart_idx - 1), + DEVICE_NATIVE_ENDIAN); /* Add device tree node for serial. */ nodename = g_strdup_printf("/serial@%" HWADDR_PRIx, base); @@ -271,7 +278,8 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, /* The /chosen node is created during fdt creation. */ qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename); -qemu_fdt_setprop_string(fdt, "/aliases", "uart0", nodename); +snprintf(alias, sizeof(alias), "uart%d", uart_idx); +qemu_fdt_setprop_string(fdt, "/aliases", alias, nodename); g_free(nodename); } @@ -414,9 +422,11 @@ static void openrisc_sim_init(MachineState *machine) smp_cpus, cpus, OR1KSIM_OMPIC_IRQ); } -openrisc_sim_serial_init(state, or1ksim_memmap[OR1KSIM_UART].base, - or1ksim_memmap[OR1KSIM_UART].size, smp_cpus, cpus, - OR1KSIM_UART_IRQ); +for (n = 0; n < OR1KSIM_UART_COUNT; ++n) +openrisc_sim_serial_init(state, or1ksim_memmap[OR1KSIM_UART].base + +or1ksim_memmap[OR1KSIM_UART].size * n, + or1ksim_memmap[OR1KSIM_UART].size, + smp_cpus, cpus, OR1KSIM_UART_IRQ, n); load_addr = openrisc_load_kernel(ram_size, kernel_filename); if (load_addr > 0) { -- 2.31.1
[PULL 4/4] target/openrisc: Do not reset delay slot flag on early tb exit
This was found when running linux crypto algorithm selftests used by wireguard. We found that randomly the tests would fail. We found through investigation that a combination of a tick timer interrupt, raised when executing a delay slot instruction at a page boundary caused the issue. This was caused when handling the TB_EXIT_REQUESTED case in cpu_tb_exec. On OpenRISC, which doesn't implement synchronize_from_tb, set_pc was being used as a fallback. The OpenRISC set_pc implementation clears dflag, which caused the exception handling logic to not account for the delay slot. This was the bug, because it meant when execution resumed after the interrupt was handling it resumed in the wrong place. Fix this by implementing synchronize_from_tb which simply updates pc, and not clear the delay slot flag. Reported-by: Jason A. Donenfeld Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- target/openrisc/cpu.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index dfbafc5236..41d1b2a24a 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -21,6 +21,7 @@ #include "qapi/error.h" #include "qemu/qemu-print.h" #include "cpu.h" +#include "exec/exec-all.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) { @@ -30,6 +31,15 @@ static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.dflag = 0; } +static void openrisc_cpu_synchronize_from_tb(CPUState *cs, + const TranslationBlock *tb) +{ +OpenRISCCPU *cpu = OPENRISC_CPU(cs); + +cpu->env.pc = tb->pc; +} + + static bool openrisc_cpu_has_work(CPUState *cs) { return cs->interrupt_request & (CPU_INTERRUPT_HARD | @@ -186,6 +196,7 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = { static const struct TCGCPUOps openrisc_tcg_ops = { .initialize = openrisc_translate_init, +.synchronize_from_tb = openrisc_cpu_synchronize_from_tb, #ifndef CONFIG_USER_ONLY .tlb_fill = openrisc_cpu_tlb_fill, -- 2.31.1
Re: [PULL 0/4] OpenRISC fixes for QEMU 2022-05-15
On Sun, May 15, 2022 at 04:12:50PM -0700, Richard Henderson wrote: > On 5/14/22 18:39, Stafford Horne wrote: > > The following changes since commit 2e3408b3cc7de4e87a9adafc8c19bfce3abec947: > > > >Merge tag 'misc-pull-request' of gitlab.com:marcandre.lureau/qemu into > > staging (2022-05-03 09:13:17 -0700) > > > > are available in the Git repository at: > > > >https://github.com/stffrdhrn/qemu.git tags/or1k-pull-request-20220515 > > > > for you to fetch changes up to e8f0ab0cd674241cbab7231ce05ac1bfa0b4f5ed: > > > >target/openrisc: Do not reset delay slot flag on early tb exit > > (2022-05-15 10:33:01 +0900) > > > > > > OpenRISC Fixes for 7.0 > > > > - A few or1ksim fixes and enhancements > > - A fix for OpenRISC tcg backend around delay slot handling > > Applied, thanks. Please update https://wiki.qemu.org/ChangeLog/7.1 as > appropriate. > > The gpg key I have for you is expired. Have you refreshed the expiration > date and pushed the new copy somewhere? Hello Richard, I updated my PGP key (C3B31C2D5E6627E4) last year or so to extend the expiry day. It should be uploaded to pgp.mit.edu, but for some reason that server is not responding to searches for me right now. I have also just uploaded it to keyserver.ubuntu.com if that helps. - https://keyserver.ubuntu.com/pks/lookup?search=stafford+horne&fingerprint=on&op=index sec rsa4096/C3B31C2D5E6627E4 created: 2016-09-14 expires: never usage: SC If you still have any issue I can try to work it out. -Stafford
Re: [PATCH 1/4] hw/openrisc/openrisc_sim: Create machine state for or1ksim
On Thu, Feb 10, 2022 at 12:05:22PM +0100, Philippe Mathieu-Daudé wrote: > On 10/2/22 07:30, Stafford Horne wrote: > > This will allow us to attach machine state attributes like > > the device tree fdt. > > > > Signed-off-by: Stafford Horne > > --- > > hw/openrisc/openrisc_sim.c | 31 +-- > > 1 file changed, 29 insertions(+), 2 deletions(-) > > > @@ -141,6 +153,7 @@ static void openrisc_sim_init(MachineState *machine) > > ram_addr_t ram_size = machine->ram_size; > > const char *kernel_filename = machine->kernel_filename; > > OpenRISCCPU *cpus[2] = {}; > > +Or1ksimState *s = OR1KSIM_MACHINE(machine); > > This change belong to patch #3. Yes, when I was splitting this patch out I left it here because I was "preparing". But it is not being used, so fair enough. > Otherwise: > Reviewed-by: Philippe Mathieu-Daudé Thanks > > MemoryRegion *ram; > > qemu_irq serial_irq; > > int n; > > @@ -183,8 +196,10 @@ static void openrisc_sim_init(MachineState *machine) > > openrisc_load_kernel(ram_size, kernel_filename); > > }
Re: [PATCH 2/4] hw/openrisc/openrisc_sim: Paramatarize initialization
On Thu, Feb 10, 2022 at 12:07:02PM +0100, Philippe Mathieu-Daudé wrote: > On 10/2/22 07:30, Stafford Horne wrote: > > Move magic numbers to variables and enums. These will be > > reused for upcoming fdt initialization. > > > > Signed-off-by: Stafford Horne > > --- > > hw/openrisc/openrisc_sim.c | 42 ++ > > 1 file changed, 34 insertions(+), 8 deletions(-) > > Typo "Parameterize" in subject. Yes. > Reviewed-by: Philippe Mathieu-Daudé Thank you.
[PATCH v2 2/4] hw/openrisc/openrisc_sim: Parameterize initialization
Move magic numbers to variables and enums. These will be reused for upcoming fdt initialization. Signed-off-by: Stafford Horne Reviewed-by: Philippe Mathieu-Daudé --- hw/openrisc/openrisc_sim.c | 42 ++ 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 26d2370e60..d12b3e0c5e 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -49,6 +49,29 @@ typedef struct Or1ksimState { } Or1ksimState; +enum { +OR1KSIM_DRAM, +OR1KSIM_UART, +OR1KSIM_ETHOC, +OR1KSIM_OMPIC, +}; + +enum { +OR1KSIM_OMPIC_IRQ = 1, +OR1KSIM_UART_IRQ = 2, +OR1KSIM_ETHOC_IRQ = 4, +}; + +static const struct MemmapEntry { +hwaddr base; +hwaddr size; +} or1ksim_memmap[] = { +[OR1KSIM_DRAM] = { 0x, 0 }, +[OR1KSIM_UART] = { 0x9000, 0x100 }, +[OR1KSIM_ETHOC] = { 0x9200, 0x800 }, +[OR1KSIM_OMPIC] = { 0x9800, 16 }, +}; + static struct openrisc_boot_info { uint32_t bootstrap_pc; } boot_info; @@ -176,21 +199,24 @@ static void openrisc_sim_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), 0, ram); if (nd_table[0].used) { -openrisc_sim_net_init(0x9200, 0x92000400, smp_cpus, - cpus, 4, nd_table); +openrisc_sim_net_init(or1ksim_memmap[OR1KSIM_ETHOC].base, + or1ksim_memmap[OR1KSIM_ETHOC].base + 0x400, + smp_cpus, cpus, + OR1KSIM_ETHOC_IRQ, nd_table); } if (smp_cpus > 1) { -openrisc_sim_ompic_init(0x9800, smp_cpus, cpus, 1); +openrisc_sim_ompic_init(or1ksim_memmap[OR1KSIM_OMPIC].base, smp_cpus, +cpus, OR1KSIM_OMPIC_IRQ); -serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, 2), -get_cpu_irq(cpus, 1, 2)); +serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, OR1KSIM_UART_IRQ), +get_cpu_irq(cpus, 1, OR1KSIM_UART_IRQ)); } else { -serial_irq = get_cpu_irq(cpus, 0, 2); +serial_irq = get_cpu_irq(cpus, 0, OR1KSIM_UART_IRQ); } -serial_mm_init(get_system_memory(), 0x9000, 0, serial_irq, - 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); +serial_mm_init(get_system_memory(), or1ksim_memmap[OR1KSIM_UART].base, 0, + serial_irq, 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); openrisc_load_kernel(ram_size, kernel_filename); } -- 2.31.1
[PATCH v2 4/4] hw/openrisc/openrisc_sim: Add support for initrd loading
The initrd passed via the command line is loaded into memory. It's location and size is then added to the device tree so the kernel knows where to find it. Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 32 +++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index d7c26af82c..5354797e20 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -187,6 +187,32 @@ static hwaddr openrisc_load_kernel(ram_addr_t ram_size, return 0; } +static hwaddr openrisc_load_initrd(Or1ksimState *s, const char *filename, +hwaddr load_start, uint64_t mem_size) +{ +int size; +hwaddr start; + +/* We put the initrd right after the kernel; page aligned. */ +start = TARGET_PAGE_ALIGN(load_start); + +size = load_ramdisk(filename, start, mem_size - start); +if (size < 0) { +size = load_image_targphys(filename, start, mem_size - start); +if (size < 0) { +error_report("could not load ramdisk '%s'", filename); +exit(1); +} +} + +qemu_fdt_setprop_cell(s->fdt, "/chosen", + "linux,initrd-start", start); +qemu_fdt_setprop_cell(s->fdt, "/chosen", + "linux,initrd-end", start + size); + +return start + size; +} + static uint32_t openrisc_load_fdt(Or1ksimState *s, hwaddr load_start, uint64_t mem_size) { @@ -198,7 +224,7 @@ static uint32_t openrisc_load_fdt(Or1ksimState *s, hwaddr load_start, exit(1); } -/* We should put fdt right after the kernel */ +/* We put fdt right after the kernel and/or initrd. */ fdt_addr = ROUND_UP(load_start, 4); fdt_pack(s->fdt); @@ -369,6 +395,10 @@ static void openrisc_sim_init(MachineState *machine) machine->kernel_cmdline); load_addr = openrisc_load_kernel(ram_size, kernel_filename); +if (machine->initrd_filename) { +load_addr = openrisc_load_initrd(s, machine->initrd_filename, + load_addr, machine->ram_size); +} boot_info.fdt_addr = openrisc_load_fdt(s, load_addr, machine->ram_size); } -- 2.31.1
[PATCH v2 3/4] hw/openrisc/openrisc_sim; Add support for loading a device tree
Using the device tree means that qemu can now directly tell the kernel what hardware is configured rather than use having to maintain and update a separate device tree file. This patch adds device tree support for the OpenRISC simulator. A device tree is built up based on the state of the configure openrisc simulator. This is then dumped to memory and the load address is passed to the kernel in register r3. Signed-off-by: Stafford Horne --- configs/targets/or1k-softmmu.mak | 1 + hw/openrisc/openrisc_sim.c | 159 ++- 2 files changed, 156 insertions(+), 4 deletions(-) diff --git a/configs/targets/or1k-softmmu.mak b/configs/targets/or1k-softmmu.mak index 1dfb93e46d..9e1d4a1fb1 100644 --- a/configs/targets/or1k-softmmu.mak +++ b/configs/targets/or1k-softmmu.mak @@ -1,2 +1,3 @@ TARGET_ARCH=openrisc TARGET_WORDS_BIGENDIAN=y +TARGET_NEED_FDT=y diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index d12b3e0c5e..d7c26af82c 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -29,14 +29,20 @@ #include "net/net.h" #include "hw/loader.h" #include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "sysemu/device_tree.h" #include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" #include "hw/core/split-irq.h" +#include + #define KERNEL_LOAD_ADDR 0x100 +#define OR1KSIM_CLK_MHZ 2000 + #define TYPE_OR1KSIM_MACHINE MACHINE_TYPE_NAME("or1k-sim") #define OR1KSIM_MACHINE(obj) \ OBJECT_CHECK(Or1ksimState, (obj), TYPE_OR1KSIM_MACHINE) @@ -46,6 +52,8 @@ typedef struct Or1ksimState { MachineState parent_obj; /*< public >*/ +void *fdt; +int fdt_size; } Or1ksimState; @@ -74,6 +82,7 @@ static const struct MemmapEntry { static struct openrisc_boot_info { uint32_t bootstrap_pc; +uint32_t fdt_addr; } boot_info; static void main_cpu_reset(void *opaque) @@ -84,6 +93,7 @@ static void main_cpu_reset(void *opaque) cpu_reset(CPU(cpu)); cpu_set_pc(cs, boot_info.bootstrap_pc); +cpu_set_gpr(&cpu->env, 3, boot_info.fdt_addr); } static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) @@ -137,26 +147,29 @@ static void openrisc_sim_ompic_init(hwaddr base, int num_cpus, sysbus_mmio_map(s, 0, base); } -static void openrisc_load_kernel(ram_addr_t ram_size, +static hwaddr openrisc_load_kernel(ram_addr_t ram_size, const char *kernel_filename) { long kernel_size; uint64_t elf_entry; +uint64_t high_addr; hwaddr entry; if (kernel_filename && !qtest_enabled()) { kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - &elf_entry, NULL, NULL, NULL, 1, EM_OPENRISC, - 1, 0); + &elf_entry, NULL, &high_addr, NULL, 1, + EM_OPENRISC, 1, 0); entry = elf_entry; if (kernel_size < 0) { kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL, NULL, NULL); +high_addr = entry + kernel_size; } if (kernel_size < 0) { kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, ram_size - KERNEL_LOAD_ADDR); +high_addr = KERNEL_LOAD_ADDR + kernel_size; } if (entry <= 0) { @@ -168,7 +181,139 @@ static void openrisc_load_kernel(ram_addr_t ram_size, exit(1); } boot_info.bootstrap_pc = entry; + +return high_addr; +} +return 0; +} + +static uint32_t openrisc_load_fdt(Or1ksimState *s, hwaddr load_start, +uint64_t mem_size) +{ +uint32_t fdt_addr; +int fdtsize = fdt_totalsize(s->fdt); + +if (fdtsize <= 0) { +error_report("invalid device-tree"); +exit(1); +} + +/* We should put fdt right after the kernel */ +fdt_addr = ROUND_UP(load_start, 4); + +fdt_pack(s->fdt); +/* copy in the device tree */ +qemu_fdt_dumpdtb(s->fdt, fdtsize); + +rom_add_blob_fixed_as("fdt", s->fdt, fdtsize, fdt_addr, + &address_space_memory); + +return fdt_addr; +} + +static void openrisc_create_fdt(Or1ksimState *s, +const struct MemmapEntry *memmap, int num_cpus, uint64_t mem_size, +const char *cmdline) +{ +void *fdt; +int cpu; +char *nodename; +int pic_ph; + +fdt = s->fdt = create_device_tree(&s->fdt_size); +if (!fdt) { +error_report("create_device_tree() failed"); +exit(1); +} + +qemu_fdt_setprop_str