Third RISC-V PR for QEMU 7.2
* Update qtest comment * Fix coverity issue with Ibex SPI * Move load_image_to_fw_cfg() to common location * Enable booting S-mode firmware from pflash on virt machine * Add disas support for vector instructions * Priority level fixes for PLIC * Fixup TLB size calculation when using PMP -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmNJFR8ACgkQIeENKd+X cFTOzgf+Mg4vy3PpY/hDuYJwZyYrgcY9M/VwUFONUD5TL1ehweuEeu5NF/iJpzfP ywjvESxhFpGQ97zSH10IbTxQwP5fifE7JMlC4ncYTTLQYk43kiYmSM5MAbxgEC44 PgF5/WVUWI8tDJhzfAEII17AohtTc9rzWcoXh+oLX53IB0V7qh4Eq0+Rm/i/yO5I oD70deU+DegHb4ka6w6k2nHEhi9IoNA0uslQrQzKVr/WQPE/1TVkmvy0u3tiFSoI 0MFXQjCirzdJoNU+5Wq3F0ygPMupMopOnidaMR8wH9fk3pb7hzzOve5wQRM+EtIv W2QGnWNaiR7n3UeGWYnh7aidcJ7Dfw== =O3mB -----END PGP SIGNATURE----- Merge tag 'pull-riscv-to-apply-20221014' of https://github.com/alistair23/qemu into staging Third RISC-V PR for QEMU 7.2 * Update qtest comment * Fix coverity issue with Ibex SPI * Move load_image_to_fw_cfg() to common location * Enable booting S-mode firmware from pflash on virt machine * Add disas support for vector instructions * Priority level fixes for PLIC * Fixup TLB size calculation when using PMP # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmNJFR8ACgkQIeENKd+X # cFTOzgf+Mg4vy3PpY/hDuYJwZyYrgcY9M/VwUFONUD5TL1ehweuEeu5NF/iJpzfP # ywjvESxhFpGQ97zSH10IbTxQwP5fifE7JMlC4ncYTTLQYk43kiYmSM5MAbxgEC44 # PgF5/WVUWI8tDJhzfAEII17AohtTc9rzWcoXh+oLX53IB0V7qh4Eq0+Rm/i/yO5I # oD70deU+DegHb4ka6w6k2nHEhi9IoNA0uslQrQzKVr/WQPE/1TVkmvy0u3tiFSoI # 0MFXQjCirzdJoNU+5Wq3F0ygPMupMopOnidaMR8wH9fk3pb7hzzOve5wQRM+EtIv # W2QGnWNaiR7n3UeGWYnh7aidcJ7Dfw== # =O3mB # -----END PGP SIGNATURE----- # gpg: Signature made Fri 14 Oct 2022 03:51:59 EDT # gpg: using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: F6C4 AC46 D493 4868 D3B8 CE8F 21E1 0D29 DF97 7054 * tag 'pull-riscv-to-apply-20221014' of https://github.com/alistair23/qemu: target/riscv: pmp: Fixup TLB size calculation hw/intc: sifive_plic: change interrupt priority register to WARL field hw/intc: sifive_plic: fix hard-coded max priority level disas/riscv.c: rvv: Add disas support for vector instructions hw/riscv: virt: Enable booting S-mode firmware from pflash hw/riscv: virt: Move create_fw_cfg() prior to loading kernel hw/arm, loongarch: Move load_image_to_fw_cfg() to common location hw/ssi: ibex_spi: fixup/add rw1c functionality hw/ssi: ibex_spi: fixup coverity issue hw/riscv: Update comment for qtest check in riscv_find_firmware() Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
5c2439a92c
1432
disas/riscv.c
1432
disas/riscv.c
File diff suppressed because it is too large
Load Diff
@ -822,55 +822,6 @@ static void do_cpu_reset(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
|
||||
* by key.
|
||||
* @fw_cfg: The firmware config instance to store the data in.
|
||||
* @size_key: The firmware config key to store the size of the loaded
|
||||
* data under, with fw_cfg_add_i32().
|
||||
* @data_key: The firmware config key to store the loaded data under,
|
||||
* with fw_cfg_add_bytes().
|
||||
* @image_name: The name of the image file to load. If it is NULL, the
|
||||
* function returns without doing anything.
|
||||
* @try_decompress: Whether the image should be decompressed (gunzipped) before
|
||||
* adding it to fw_cfg. If decompression fails, the image is
|
||||
* loaded as-is.
|
||||
*
|
||||
* In case of failure, the function prints an error message to stderr and the
|
||||
* process exits with status 1.
|
||||
*/
|
||||
static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
|
||||
uint16_t data_key, const char *image_name,
|
||||
bool try_decompress)
|
||||
{
|
||||
size_t size = -1;
|
||||
uint8_t *data;
|
||||
|
||||
if (image_name == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (try_decompress) {
|
||||
size = load_image_gzipped_buffer(image_name,
|
||||
LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
|
||||
}
|
||||
|
||||
if (size == (size_t)-1) {
|
||||
gchar *contents;
|
||||
gsize length;
|
||||
|
||||
if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
|
||||
error_report("failed to load \"%s\"", image_name);
|
||||
exit(1);
|
||||
}
|
||||
size = length;
|
||||
data = (uint8_t *)contents;
|
||||
}
|
||||
|
||||
fw_cfg_add_i32(fw_cfg, size_key, size);
|
||||
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
|
||||
}
|
||||
|
||||
static int do_arm_linux_init(Object *obj, void *opaque)
|
||||
{
|
||||
if (object_dynamic_cast(obj, TYPE_ARM_LINUX_BOOT_IF)) {
|
||||
|
@ -180,8 +180,18 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
if (addr_between(addr, plic->priority_base, plic->num_sources << 2)) {
|
||||
uint32_t irq = ((addr - plic->priority_base) >> 2) + 1;
|
||||
|
||||
plic->source_priority[irq] = value & 7;
|
||||
sifive_plic_update(plic);
|
||||
if (((plic->num_priorities + 1) & plic->num_priorities) == 0) {
|
||||
/*
|
||||
* if "num_priorities + 1" is power-of-2, make each register bit of
|
||||
* interrupt priority WARL (Write-Any-Read-Legal). Just filter
|
||||
* out the access to unsupported priority bits.
|
||||
*/
|
||||
plic->source_priority[irq] = value % (plic->num_priorities + 1);
|
||||
sifive_plic_update(plic);
|
||||
} else if (value <= plic->num_priorities) {
|
||||
plic->source_priority[irq] = value;
|
||||
sifive_plic_update(plic);
|
||||
}
|
||||
} else if (addr_between(addr, plic->pending_base,
|
||||
plic->num_sources >> 3)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
@ -205,7 +215,16 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
uint32_t contextid = (addr & (plic->context_stride - 1));
|
||||
|
||||
if (contextid == 0) {
|
||||
if (value <= plic->num_priorities) {
|
||||
if (((plic->num_priorities + 1) & plic->num_priorities) == 0) {
|
||||
/*
|
||||
* if "num_priorities + 1" is power-of-2, each register bit of
|
||||
* interrupt priority is WARL (Write-Any-Read-Legal). Just
|
||||
* filter out the access to unsupported priority bits.
|
||||
*/
|
||||
plic->target_priority[addrid] = value %
|
||||
(plic->num_priorities + 1);
|
||||
sifive_plic_update(plic);
|
||||
} else if (value <= plic->num_priorities) {
|
||||
plic->target_priority[addrid] = value;
|
||||
sifive_plic_update(plic);
|
||||
}
|
||||
|
@ -598,39 +598,6 @@ static void reset_load_elf(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
/* Load an image file into an fw_cfg entry identified by key. */
|
||||
static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
|
||||
uint16_t data_key, const char *image_name,
|
||||
bool try_decompress)
|
||||
{
|
||||
size_t size = -1;
|
||||
uint8_t *data;
|
||||
|
||||
if (image_name == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (try_decompress) {
|
||||
size = load_image_gzipped_buffer(image_name,
|
||||
LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
|
||||
}
|
||||
|
||||
if (size == (size_t)-1) {
|
||||
gchar *contents;
|
||||
gsize length;
|
||||
|
||||
if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
|
||||
error_report("failed to load \"%s\"", image_name);
|
||||
exit(1);
|
||||
}
|
||||
size = length;
|
||||
data = (uint8_t *)contents;
|
||||
}
|
||||
|
||||
fw_cfg_add_i32(fw_cfg, size_key, size);
|
||||
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
|
||||
}
|
||||
|
||||
static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg)
|
||||
{
|
||||
/*
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "qapi/error.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "hw/loader.h"
|
||||
|
||||
#define FW_CFG_FILE_SLOTS_DFLT 0x20
|
||||
|
||||
@ -1221,6 +1222,37 @@ FWCfgState *fw_cfg_find(void)
|
||||
return FW_CFG(object_resolve_path_type("", TYPE_FW_CFG, NULL));
|
||||
}
|
||||
|
||||
void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
|
||||
uint16_t data_key, const char *image_name,
|
||||
bool try_decompress)
|
||||
{
|
||||
size_t size = -1;
|
||||
uint8_t *data;
|
||||
|
||||
if (image_name == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (try_decompress) {
|
||||
size = load_image_gzipped_buffer(image_name,
|
||||
LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
|
||||
}
|
||||
|
||||
if (size == (size_t)-1) {
|
||||
gchar *contents;
|
||||
gsize length;
|
||||
|
||||
if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
|
||||
error_report("failed to load \"%s\"", image_name);
|
||||
exit(1);
|
||||
}
|
||||
size = length;
|
||||
data = (uint8_t *)contents;
|
||||
}
|
||||
|
||||
fw_cfg_add_i32(fw_cfg, size_key, size);
|
||||
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
|
||||
}
|
||||
|
||||
static void fw_cfg_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
|
@ -111,8 +111,8 @@ char *riscv_find_firmware(const char *firmware_filename)
|
||||
if (filename == NULL) {
|
||||
if (!qtest_enabled()) {
|
||||
/*
|
||||
* We only ship plain binary bios images in the QEMU source.
|
||||
* With Spike machine that uses ELF images as the default bios,
|
||||
* We only ship OpenSBI binary bios images in the QEMU source.
|
||||
* For machines that use images other than the default bios,
|
||||
* running QEMU test will complain hence let's suppress the error
|
||||
* report for QEMU testing.
|
||||
*/
|
||||
@ -338,3 +338,32 @@ void riscv_setup_direct_kernel(hwaddr kernel_addr, hwaddr fdt_addr)
|
||||
riscv_cpu->env.fdt_addr = fdt_addr;
|
||||
}
|
||||
}
|
||||
|
||||
void riscv_setup_firmware_boot(MachineState *machine)
|
||||
{
|
||||
if (machine->kernel_filename) {
|
||||
FWCfgState *fw_cfg;
|
||||
fw_cfg = fw_cfg_find();
|
||||
|
||||
assert(fw_cfg);
|
||||
/*
|
||||
* Expose the kernel, the command line, and the initrd in fw_cfg.
|
||||
* We don't process them here at all, it's all left to the
|
||||
* firmware.
|
||||
*/
|
||||
load_image_to_fw_cfg(fw_cfg,
|
||||
FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
|
||||
machine->kernel_filename,
|
||||
true);
|
||||
load_image_to_fw_cfg(fw_cfg,
|
||||
FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
|
||||
machine->initrd_filename, false);
|
||||
|
||||
if (machine->kernel_cmdline) {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
|
||||
strlen(machine->kernel_cmdline) + 1);
|
||||
fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
|
||||
machine->kernel_cmdline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1267,7 +1267,30 @@ static void virt_machine_done(Notifier *notifier, void *data)
|
||||
RISCV64_BIOS_BIN, start_addr, NULL);
|
||||
}
|
||||
|
||||
if (machine->kernel_filename) {
|
||||
/*
|
||||
* Init fw_cfg. Must be done before riscv_load_fdt, otherwise the device
|
||||
* tree cannot be altered and we get FDT_ERR_NOSPACE.
|
||||
*/
|
||||
s->fw_cfg = create_fw_cfg(machine);
|
||||
rom_set_fw(s->fw_cfg);
|
||||
|
||||
if (drive_get(IF_PFLASH, 0, 1)) {
|
||||
/*
|
||||
* S-mode FW like EDK2 will be kept in second plash (unit 1).
|
||||
* When both kernel, initrd and pflash options are provided in the
|
||||
* command line, the kernel and initrd will be copied to the fw_cfg
|
||||
* table and opensbi will jump to the flash address which is the
|
||||
* entry point of S-mode FW. It is the job of the S-mode FW to load
|
||||
* the kernel and initrd using fw_cfg table.
|
||||
*
|
||||
* If only pflash is given but not -kernel, then it is the job of
|
||||
* of the S-mode firmware to locate and load the kernel.
|
||||
* In either case, the next_addr for opensbi will be the flash address.
|
||||
*/
|
||||
riscv_setup_firmware_boot(machine);
|
||||
kernel_entry = virt_memmap[VIRT_FLASH].base +
|
||||
virt_memmap[VIRT_FLASH].size / 2;
|
||||
} else if (machine->kernel_filename) {
|
||||
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0],
|
||||
firmware_end_addr);
|
||||
|
||||
@ -1300,13 +1323,6 @@ static void virt_machine_done(Notifier *notifier, void *data)
|
||||
start_addr = virt_memmap[VIRT_FLASH].base;
|
||||
}
|
||||
|
||||
/*
|
||||
* Init fw_cfg. Must be done before riscv_load_fdt, otherwise the device
|
||||
* tree cannot be altered and we get FDT_ERR_NOSPACE.
|
||||
*/
|
||||
s->fw_cfg = create_fw_cfg(machine);
|
||||
rom_set_fw(s->fw_cfg);
|
||||
|
||||
/* Compute the fdt load address in dram */
|
||||
fdt_load_addr = riscv_load_fdt(memmap[VIRT_DRAM].base,
|
||||
machine->ram_size, machine->fdt);
|
||||
|
@ -108,18 +108,22 @@ static inline uint8_t div4_round_up(uint8_t dividend)
|
||||
|
||||
static void ibex_spi_rxfifo_reset(IbexSPIHostState *s)
|
||||
{
|
||||
uint32_t data = s->regs[IBEX_SPI_HOST_STATUS];
|
||||
/* Empty the RX FIFO and assert RXEMPTY */
|
||||
fifo8_reset(&s->rx_fifo);
|
||||
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_RXFULL_MASK;
|
||||
s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_RXEMPTY_MASK;
|
||||
data = FIELD_DP32(data, STATUS, RXFULL, 0);
|
||||
data = FIELD_DP32(data, STATUS, RXEMPTY, 1);
|
||||
s->regs[IBEX_SPI_HOST_STATUS] = data;
|
||||
}
|
||||
|
||||
static void ibex_spi_txfifo_reset(IbexSPIHostState *s)
|
||||
{
|
||||
uint32_t data = s->regs[IBEX_SPI_HOST_STATUS];
|
||||
/* Empty the TX FIFO and assert TXEMPTY */
|
||||
fifo8_reset(&s->tx_fifo);
|
||||
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_TXFULL_MASK;
|
||||
s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_TXEMPTY_MASK;
|
||||
data = FIELD_DP32(data, STATUS, TXFULL, 0);
|
||||
data = FIELD_DP32(data, STATUS, TXEMPTY, 1);
|
||||
s->regs[IBEX_SPI_HOST_STATUS] = data;
|
||||
}
|
||||
|
||||
static void ibex_spi_host_reset(DeviceState *dev)
|
||||
@ -162,37 +166,38 @@ static void ibex_spi_host_reset(DeviceState *dev)
|
||||
*/
|
||||
static void ibex_spi_host_irq(IbexSPIHostState *s)
|
||||
{
|
||||
bool error_en = s->regs[IBEX_SPI_HOST_INTR_ENABLE]
|
||||
& R_INTR_ENABLE_ERROR_MASK;
|
||||
bool event_en = s->regs[IBEX_SPI_HOST_INTR_ENABLE]
|
||||
& R_INTR_ENABLE_SPI_EVENT_MASK;
|
||||
bool err_pending = s->regs[IBEX_SPI_HOST_INTR_STATE]
|
||||
& R_INTR_STATE_ERROR_MASK;
|
||||
bool status_pending = s->regs[IBEX_SPI_HOST_INTR_STATE]
|
||||
& R_INTR_STATE_SPI_EVENT_MASK;
|
||||
uint32_t intr_test_reg = s->regs[IBEX_SPI_HOST_INTR_TEST];
|
||||
uint32_t intr_en_reg = s->regs[IBEX_SPI_HOST_INTR_ENABLE];
|
||||
uint32_t intr_state_reg = s->regs[IBEX_SPI_HOST_INTR_STATE];
|
||||
|
||||
uint32_t err_en_reg = s->regs[IBEX_SPI_HOST_ERROR_ENABLE];
|
||||
uint32_t event_en_reg = s->regs[IBEX_SPI_HOST_EVENT_ENABLE];
|
||||
uint32_t err_status_reg = s->regs[IBEX_SPI_HOST_ERROR_STATUS];
|
||||
uint32_t status_reg = s->regs[IBEX_SPI_HOST_STATUS];
|
||||
|
||||
|
||||
bool error_en = FIELD_EX32(intr_en_reg, INTR_ENABLE, ERROR);
|
||||
bool event_en = FIELD_EX32(intr_en_reg, INTR_ENABLE, SPI_EVENT);
|
||||
bool err_pending = FIELD_EX32(intr_state_reg, INTR_STATE, ERROR);
|
||||
bool status_pending = FIELD_EX32(intr_state_reg, INTR_STATE, SPI_EVENT);
|
||||
|
||||
int err_irq = 0, event_irq = 0;
|
||||
|
||||
/* Error IRQ enabled and Error IRQ Cleared */
|
||||
if (error_en && !err_pending) {
|
||||
/* Event enabled, Interrupt Test Error */
|
||||
if (s->regs[IBEX_SPI_HOST_INTR_TEST] & R_INTR_TEST_ERROR_MASK) {
|
||||
if (FIELD_EX32(intr_test_reg, INTR_TEST, ERROR)) {
|
||||
err_irq = 1;
|
||||
} else if ((s->regs[IBEX_SPI_HOST_ERROR_ENABLE]
|
||||
& R_ERROR_ENABLE_CMDBUSY_MASK) &&
|
||||
s->regs[IBEX_SPI_HOST_ERROR_STATUS]
|
||||
& R_ERROR_STATUS_CMDBUSY_MASK) {
|
||||
} else if (FIELD_EX32(err_en_reg, ERROR_ENABLE, CMDBUSY) &&
|
||||
FIELD_EX32(err_status_reg, ERROR_STATUS, CMDBUSY)) {
|
||||
/* Wrote to COMMAND when not READY */
|
||||
err_irq = 1;
|
||||
} else if ((s->regs[IBEX_SPI_HOST_ERROR_ENABLE]
|
||||
& R_ERROR_ENABLE_CMDINVAL_MASK) &&
|
||||
s->regs[IBEX_SPI_HOST_ERROR_STATUS]
|
||||
& R_ERROR_STATUS_CMDINVAL_MASK) {
|
||||
} else if (FIELD_EX32(err_en_reg, ERROR_ENABLE, CMDINVAL) &&
|
||||
FIELD_EX32(err_status_reg, ERROR_STATUS, CMDINVAL)) {
|
||||
/* Invalid command segment */
|
||||
err_irq = 1;
|
||||
} else if ((s->regs[IBEX_SPI_HOST_ERROR_ENABLE]
|
||||
& R_ERROR_ENABLE_CSIDINVAL_MASK) &&
|
||||
s->regs[IBEX_SPI_HOST_ERROR_STATUS]
|
||||
& R_ERROR_STATUS_CSIDINVAL_MASK) {
|
||||
} else if (FIELD_EX32(err_en_reg, ERROR_ENABLE, CSIDINVAL) &&
|
||||
FIELD_EX32(err_status_reg, ERROR_STATUS, CSIDINVAL)) {
|
||||
/* Invalid value for CSID */
|
||||
err_irq = 1;
|
||||
}
|
||||
@ -204,22 +209,19 @@ static void ibex_spi_host_irq(IbexSPIHostState *s)
|
||||
|
||||
/* Event IRQ Enabled and Event IRQ Cleared */
|
||||
if (event_en && !status_pending) {
|
||||
if (s->regs[IBEX_SPI_HOST_INTR_TEST] & R_INTR_TEST_SPI_EVENT_MASK) {
|
||||
if (FIELD_EX32(intr_test_reg, INTR_STATE, SPI_EVENT)) {
|
||||
/* Event enabled, Interrupt Test Event */
|
||||
event_irq = 1;
|
||||
} else if ((s->regs[IBEX_SPI_HOST_EVENT_ENABLE]
|
||||
& R_EVENT_ENABLE_READY_MASK) &&
|
||||
(s->regs[IBEX_SPI_HOST_STATUS] & R_STATUS_READY_MASK)) {
|
||||
} else if (FIELD_EX32(event_en_reg, EVENT_ENABLE, READY) &&
|
||||
FIELD_EX32(status_reg, STATUS, READY)) {
|
||||
/* SPI Host ready for next command */
|
||||
event_irq = 1;
|
||||
} else if ((s->regs[IBEX_SPI_HOST_EVENT_ENABLE]
|
||||
& R_EVENT_ENABLE_TXEMPTY_MASK) &&
|
||||
(s->regs[IBEX_SPI_HOST_STATUS] & R_STATUS_TXEMPTY_MASK)) {
|
||||
} else if (FIELD_EX32(event_en_reg, EVENT_ENABLE, TXEMPTY) &&
|
||||
FIELD_EX32(status_reg, STATUS, TXEMPTY)) {
|
||||
/* SPI TXEMPTY, TXFIFO drained */
|
||||
event_irq = 1;
|
||||
} else if ((s->regs[IBEX_SPI_HOST_EVENT_ENABLE]
|
||||
& R_EVENT_ENABLE_RXFULL_MASK) &&
|
||||
(s->regs[IBEX_SPI_HOST_STATUS] & R_STATUS_RXFULL_MASK)) {
|
||||
} else if (FIELD_EX32(event_en_reg, EVENT_ENABLE, RXFULL) &&
|
||||
FIELD_EX32(status_reg, STATUS, RXFULL)) {
|
||||
/* SPI RXFULL, RXFIFO full */
|
||||
event_irq = 1;
|
||||
}
|
||||
@ -232,10 +234,11 @@ static void ibex_spi_host_irq(IbexSPIHostState *s)
|
||||
|
||||
static void ibex_spi_host_transfer(IbexSPIHostState *s)
|
||||
{
|
||||
uint32_t rx, tx;
|
||||
uint32_t rx, tx, data;
|
||||
/* Get num of one byte transfers */
|
||||
uint8_t segment_len = ((s->regs[IBEX_SPI_HOST_COMMAND] & R_COMMAND_LEN_MASK)
|
||||
>> R_COMMAND_LEN_SHIFT);
|
||||
uint8_t segment_len = FIELD_EX32(s->regs[IBEX_SPI_HOST_COMMAND],
|
||||
COMMAND, LEN);
|
||||
|
||||
while (segment_len > 0) {
|
||||
if (fifo8_is_empty(&s->tx_fifo)) {
|
||||
/* Assert Stall */
|
||||
@ -262,22 +265,21 @@ static void ibex_spi_host_transfer(IbexSPIHostState *s)
|
||||
--segment_len;
|
||||
}
|
||||
|
||||
data = s->regs[IBEX_SPI_HOST_STATUS];
|
||||
/* Assert Ready */
|
||||
s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_READY_MASK;
|
||||
data = FIELD_DP32(data, STATUS, READY, 1);
|
||||
/* Set RXQD */
|
||||
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_RXQD_MASK;
|
||||
s->regs[IBEX_SPI_HOST_STATUS] |= (R_STATUS_RXQD_MASK
|
||||
& div4_round_up(segment_len));
|
||||
data = FIELD_DP32(data, STATUS, RXQD, div4_round_up(segment_len));
|
||||
/* Set TXQD */
|
||||
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_TXQD_MASK;
|
||||
s->regs[IBEX_SPI_HOST_STATUS] |= (fifo8_num_used(&s->tx_fifo) / 4)
|
||||
& R_STATUS_TXQD_MASK;
|
||||
data = FIELD_DP32(data, STATUS, TXQD, fifo8_num_used(&s->tx_fifo) / 4);
|
||||
/* Clear TXFULL */
|
||||
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_TXFULL_MASK;
|
||||
/* Assert TXEMPTY and drop remaining bytes that exceed segment_len */
|
||||
ibex_spi_txfifo_reset(s);
|
||||
data = FIELD_DP32(data, STATUS, TXFULL, 0);
|
||||
/* Reset RXEMPTY */
|
||||
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_RXEMPTY_MASK;
|
||||
data = FIELD_DP32(data, STATUS, RXEMPTY, 0);
|
||||
/* Update register status */
|
||||
s->regs[IBEX_SPI_HOST_STATUS] = data;
|
||||
/* Drop remaining bytes that exceed segment_len */
|
||||
ibex_spi_txfifo_reset(s);
|
||||
|
||||
ibex_spi_host_irq(s);
|
||||
}
|
||||
@ -340,7 +342,7 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
|
||||
{
|
||||
IbexSPIHostState *s = opaque;
|
||||
uint32_t val32 = val64;
|
||||
uint32_t shift_mask = 0xff;
|
||||
uint32_t shift_mask = 0xff, status = 0, data = 0;
|
||||
uint8_t txqd_len;
|
||||
|
||||
trace_ibex_spi_host_write(addr, size, val64);
|
||||
@ -350,7 +352,17 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
|
||||
|
||||
switch (addr) {
|
||||
/* Skipping any R/O registers */
|
||||
case IBEX_SPI_HOST_INTR_STATE...IBEX_SPI_HOST_INTR_ENABLE:
|
||||
case IBEX_SPI_HOST_INTR_STATE:
|
||||
/* rw1c status register */
|
||||
if (FIELD_EX32(val32, INTR_STATE, ERROR)) {
|
||||
data = FIELD_DP32(data, INTR_STATE, ERROR, 0);
|
||||
}
|
||||
if (FIELD_EX32(val32, INTR_STATE, SPI_EVENT)) {
|
||||
data = FIELD_DP32(data, INTR_STATE, SPI_EVENT, 0);
|
||||
}
|
||||
s->regs[addr] = data;
|
||||
break;
|
||||
case IBEX_SPI_HOST_INTR_ENABLE:
|
||||
s->regs[addr] = val32;
|
||||
break;
|
||||
case IBEX_SPI_HOST_INTR_TEST:
|
||||
@ -397,22 +409,24 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
|
||||
s->regs[addr] = val32;
|
||||
|
||||
/* STALL, IP not enabled */
|
||||
if (!(s->regs[IBEX_SPI_HOST_CONTROL] & R_CONTROL_SPIEN_MASK)) {
|
||||
if (!(FIELD_EX32(s->regs[IBEX_SPI_HOST_CONTROL],
|
||||
CONTROL, SPIEN))) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* SPI not ready, IRQ Error */
|
||||
if (!(s->regs[IBEX_SPI_HOST_STATUS] & R_STATUS_READY_MASK)) {
|
||||
if (!(FIELD_EX32(s->regs[IBEX_SPI_HOST_STATUS],
|
||||
STATUS, READY))) {
|
||||
s->regs[IBEX_SPI_HOST_ERROR_STATUS] |= R_ERROR_STATUS_CMDBUSY_MASK;
|
||||
ibex_spi_host_irq(s);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Assert Not Ready */
|
||||
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_READY_MASK;
|
||||
|
||||
if (((val32 & R_COMMAND_DIRECTION_MASK) >> R_COMMAND_DIRECTION_SHIFT)
|
||||
!= BIDIRECTIONAL_TRANSFER) {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
if (FIELD_EX32(val32, COMMAND, DIRECTION) != BIDIRECTIONAL_TRANSFER) {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"%s: Rx Only/Tx Only are not supported\n", __func__);
|
||||
}
|
||||
|
||||
@ -452,8 +466,8 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
|
||||
return;
|
||||
}
|
||||
/* Byte ordering is set by the IP */
|
||||
if ((s->regs[IBEX_SPI_HOST_STATUS] &
|
||||
R_STATUS_BYTEORDER_MASK) == 0) {
|
||||
status = s->regs[IBEX_SPI_HOST_STATUS];
|
||||
if (FIELD_EX32(status, STATUS, BYTEORDER) == 0) {
|
||||
/* LE: LSB transmitted first (default for ibex processor) */
|
||||
shift_mask = 0xff << (i * 8);
|
||||
} else {
|
||||
@ -464,18 +478,18 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
|
||||
|
||||
fifo8_push(&s->tx_fifo, (val32 & shift_mask) >> (i * 8));
|
||||
}
|
||||
|
||||
status = s->regs[IBEX_SPI_HOST_STATUS];
|
||||
/* Reset TXEMPTY */
|
||||
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_TXEMPTY_MASK;
|
||||
status = FIELD_DP32(status, STATUS, TXEMPTY, 0);
|
||||
/* Update TXQD */
|
||||
txqd_len = (s->regs[IBEX_SPI_HOST_STATUS] &
|
||||
R_STATUS_TXQD_MASK) >> R_STATUS_TXQD_SHIFT;
|
||||
txqd_len = FIELD_EX32(status, STATUS, TXQD);
|
||||
/* Partial bytes (size < 4) are padded, in words. */
|
||||
txqd_len += 1;
|
||||
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_TXQD_MASK;
|
||||
s->regs[IBEX_SPI_HOST_STATUS] |= txqd_len;
|
||||
status = FIELD_DP32(status, STATUS, TXQD, txqd_len);
|
||||
/* Assert Ready */
|
||||
s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_READY_MASK;
|
||||
status = FIELD_DP32(status, STATUS, READY, 1);
|
||||
/* Update register status */
|
||||
s->regs[IBEX_SPI_HOST_STATUS] = status;
|
||||
break;
|
||||
case IBEX_SPI_HOST_ERROR_ENABLE:
|
||||
s->regs[addr] = val32;
|
||||
@ -491,7 +505,27 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
|
||||
* When an error occurs, the corresponding bit must be cleared
|
||||
* here before issuing any further commands
|
||||
*/
|
||||
s->regs[addr] = val32;
|
||||
status = s->regs[addr];
|
||||
/* rw1c status register */
|
||||
if (FIELD_EX32(val32, ERROR_STATUS, CMDBUSY)) {
|
||||
status = FIELD_DP32(status, ERROR_STATUS, CMDBUSY, 0);
|
||||
}
|
||||
if (FIELD_EX32(val32, ERROR_STATUS, OVERFLOW)) {
|
||||
status = FIELD_DP32(status, ERROR_STATUS, OVERFLOW, 0);
|
||||
}
|
||||
if (FIELD_EX32(val32, ERROR_STATUS, UNDERFLOW)) {
|
||||
status = FIELD_DP32(status, ERROR_STATUS, UNDERFLOW, 0);
|
||||
}
|
||||
if (FIELD_EX32(val32, ERROR_STATUS, CMDINVAL)) {
|
||||
status = FIELD_DP32(status, ERROR_STATUS, CMDINVAL, 0);
|
||||
}
|
||||
if (FIELD_EX32(val32, ERROR_STATUS, CSIDINVAL)) {
|
||||
status = FIELD_DP32(status, ERROR_STATUS, CSIDINVAL, 0);
|
||||
}
|
||||
if (FIELD_EX32(val32, ERROR_STATUS, ACCESSINVAL)) {
|
||||
status = FIELD_DP32(status, ERROR_STATUS, ACCESSINVAL, 0);
|
||||
}
|
||||
s->regs[addr] = status;
|
||||
break;
|
||||
case IBEX_SPI_HOST_EVENT_ENABLE:
|
||||
/* Controls which classes of SPI events raise an interrupt. */
|
||||
|
@ -364,4 +364,25 @@ bool fw_cfg_dma_enabled(void *opaque);
|
||||
*/
|
||||
const char *fw_cfg_arch_key_name(uint16_t key);
|
||||
|
||||
/**
|
||||
* load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
|
||||
* by key.
|
||||
* @fw_cfg: The firmware config instance to store the data in.
|
||||
* @size_key: The firmware config key to store the size of the loaded
|
||||
* data under, with fw_cfg_add_i32().
|
||||
* @data_key: The firmware config key to store the loaded data under,
|
||||
* with fw_cfg_add_bytes().
|
||||
* @image_name: The name of the image file to load. If it is NULL, the
|
||||
* function returns without doing anything.
|
||||
* @try_decompress: Whether the image should be decompressed (gunzipped) before
|
||||
* adding it to fw_cfg. If decompression fails, the image is
|
||||
* loaded as-is.
|
||||
*
|
||||
* In case of failure, the function prints an error message to stderr and the
|
||||
* process exits with status 1.
|
||||
*/
|
||||
void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
|
||||
uint16_t data_key, const char *image_name,
|
||||
bool try_decompress);
|
||||
|
||||
#endif
|
||||
|
@ -57,5 +57,6 @@ void riscv_rom_copy_firmware_info(MachineState *machine, hwaddr rom_base,
|
||||
uint32_t reset_vec_size,
|
||||
uint64_t kernel_entry);
|
||||
void riscv_setup_direct_kernel(hwaddr kernel_addr, hwaddr fdt_addr);
|
||||
void riscv_setup_firmware_boot(MachineState *machine);
|
||||
|
||||
#endif /* RISCV_BOOT_H */
|
||||
|
@ -40,7 +40,7 @@
|
||||
OBJECT_CHECK(IbexSPIHostState, (obj), TYPE_IBEX_SPI_HOST)
|
||||
|
||||
/* SPI Registers */
|
||||
#define IBEX_SPI_HOST_INTR_STATE (0x00 / 4) /* rw */
|
||||
#define IBEX_SPI_HOST_INTR_STATE (0x00 / 4) /* rw1c */
|
||||
#define IBEX_SPI_HOST_INTR_ENABLE (0x04 / 4) /* rw */
|
||||
#define IBEX_SPI_HOST_INTR_TEST (0x08 / 4) /* wo */
|
||||
#define IBEX_SPI_HOST_ALERT_TEST (0x0c / 4) /* wo */
|
||||
@ -54,7 +54,7 @@
|
||||
#define IBEX_SPI_HOST_TXDATA (0x28 / 4)
|
||||
|
||||
#define IBEX_SPI_HOST_ERROR_ENABLE (0x2c / 4) /* rw */
|
||||
#define IBEX_SPI_HOST_ERROR_STATUS (0x30 / 4) /* rw */
|
||||
#define IBEX_SPI_HOST_ERROR_STATUS (0x30 / 4) /* rw1c */
|
||||
#define IBEX_SPI_HOST_EVENT_ENABLE (0x34 / 4) /* rw */
|
||||
|
||||
/* FIFO Len in Bytes */
|
||||
|
@ -628,6 +628,18 @@ bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa,
|
||||
}
|
||||
|
||||
if (*tlb_size != 0) {
|
||||
/*
|
||||
* At this point we have a tlb_size that is the smallest possible size
|
||||
* That fits within a TARGET_PAGE_SIZE and the PMP region.
|
||||
*
|
||||
* If the size is less then TARGET_PAGE_SIZE we drop the size to 1.
|
||||
* This means the result isn't cached in the TLB and is only used for
|
||||
* a single translation.
|
||||
*/
|
||||
if (*tlb_size < TARGET_PAGE_SIZE) {
|
||||
*tlb_size = 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user