mirror of
https://gitlab.com/qemu-project/qemu.git
synced 2026-10-28 14:04:39 +08:00
Merge tag 'pull-hex-20261027' of https://github.com/qualcomm/qemu into staging
hexagon: v85, DSP machines, singlestep, bugfixes
- v85 scalar: atomics, CFI/_rb, vector stack
- new DSP machines: SM8975 NSP, SA8797P NSP0, SC8480XP NSP0, SA8775P CDSP0,
QCS6490 CDSP.
- bugfixes:
- coverity, ubsan findings in semihosting, decoder
- handling framekey w/dealloc_return
- handle singlestep exception
- performance improvements: TLB flush, l2vic
- test coverage
- MTTCG fixes: enabling MTTCG exposed races in lock/interrupts and ciad.
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCgAdFiEEPWaq5HRZSCTIjOD4GlSvuOVkbDIFAmrgtXAACgkQGlSvuOVk
# bDKC0A//WTrd7fSFsLP2wGMbsRrXgfOl+xa4B0aqi3agQrH8Q4Gk3f0JbJILi0QJ
# nRPyOkTDYbqQdvA7u2uJ2qZSZlaaPNJK5M9QPI43MSPrxF7hapvuSjympHXa9fpB
# Uy+opBzlx2/d7AlVnYe6m6eYVRtyiVgnskS56au4RtHkie+PL9kahsvtXkJbd2ci
# riAzVr1Swcd+uHDxHdn/9OkD1z1Ym1BIJsezTDdsX+HDx/rTR9REDMOG5DPU3tSe
# jaj+TmO3wtO/OtmZIHnKwPEQQJJuvfyNgIyN2hIFTSG/CSXZmZA8wG1G7bzk8+fr
# lHcC9+Kz7wsfaDOnoYtP/Kox3QkCSH759mSLblSJB1SRIfl0FxxIAGdr7c65wQYH
# Kt8qT15rDI3mdTs/IVcBkN62pKPXjuwjwTlR7dzi81DPk8LtxUDw68hIWVXqsNsl
# brOk9bbLgwmIAwt+tTL2D7gysNGD/pekWNA52V3bVBHgM/Mi54VSr76nP25WiaJX
# lWfbVdANpUWmvrec0y5f/sQSK89TF6INu2kkke5/+XlbCfVV4/ZJIpZP5Us1hTyS
# sV4anuskTN6jQM1ro5zvP5BCfNpnWTSZu+PEpyxmPNSpesSzxzFtkSx1SiEKEe53
# zgOAeP9tNsnFSSVTrm5ddZawiVpS53AnNYq4y5Eb64uUEdottCg=
# =+PH4
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 27 Oct 2026 09:30:08 AM CDT
# gpg: using RSA key 3D66AAE474594824C88CE0F81A54AFB8E5646C32
# gpg: Good signature from "Brian Cain (OSS Qualcomm) <brian.cain@oss.qualcomm.com>" [unknown]
# gpg: aka "Brian Cain (QUIC) <quic_bcain@quicinc.com>" [unknown]
# gpg: aka "Brian Cain <bcain@kernel.org>" [unknown]
# gpg: aka "Brian Cain (QuIC) <bcain@quicinc.com>" [unknown]
# gpg: aka "Brian Cain (CAF) <bcain@codeaurora.org>" [unknown]
# gpg: aka "bcain" [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: 6350 20F9 67A7 7164 79EF 49E0 175C 464E 541B 6D47
# Subkey fingerprint: 3D66 AAE4 7459 4824 C88C E0F8 1A54 AFB8 E564 6C32
* tag 'pull-hex-20261027' of https://github.com/qualcomm/qemu: (42 commits)
scripts/clean_functional_cache: tolerate missing .stamp files
hw/intc/hex-l2vic: find the next pending irq a word at a time
target/hexagon: only flush the softtlb when SSR.ASID changes
target/hexagon: flush the softtlb once per tlbinvasid
target/hexagon: avoid negative slot shift
target/hexagon: reset implicit USR write state
target/hexagon: assert qfloat shift
hw/intc: ciad should forward its mask to l2vic
target/hexagon: drop a pending HALT when resuming
target/hexagon: check exception_index in has_work
target/hexagon: acquire BQL before reading interrupt state
tests/functional/hexagon: boot DSP firmware
hw/hexagon: add subsystem-base property
hw/hexagon: serialize config table as little endian
hw/hexagon: add v79NA1 machine
hw/hexagon: add the SM8975 NSP machine
hw/hexagon: add the SA8797P NSP0 machine
hw/hexagon: add the SC8480XP NSP0 machine
hw/hexagon: add the SA8775P CDSP machine
hw/hexagon: add the QCS6490 CDSP machine
...
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
9b77fa7a4f
103 files changed
+4349
-474
No files matched your search
@@ -257,6 +257,8 @@ F: tests/qtest/l2vic-test.c
|
||||
F: hw/timer/qct-qtimer.c
|
||||
F: include/hw/timer/qct-qtimer.h
|
||||
F: tests/qtest/qct-qtimer-test.c
|
||||
F: hw/hexagon/hex-board.c
|
||||
F: include/hw/hexagon/hex-board.h
|
||||
X: target/hexagon/idef-parser/
|
||||
X: target/hexagon/gen_idef_parser_funcs.py
|
||||
F: linux-user/hexagon/
|
||||
@@ -1383,10 +1385,14 @@ M: Brian Cain <brian.cain@oss.qualcomm.com>
|
||||
R: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
|
||||
S: Supported
|
||||
F: hw/hexagon/
|
||||
F: hw/misc/qcom-qdsp6ss-clk.c
|
||||
F: include/hw/hexagon/
|
||||
F: include/hw/misc/qcom-qdsp6ss-clk.h
|
||||
F: configs/devices/hexagon-softmmu/default.mak
|
||||
F: docs/system/hexagon/
|
||||
F: tests/functional/hexagon/
|
||||
F: tests/qtest/hexagon-config-test.c
|
||||
F: tests/qtest/qcom-dsp-test.c
|
||||
F: docs/devel/hexagon-sys.rst
|
||||
|
||||
LoongArch Machines
|
||||
|
||||
@@ -6,7 +6,7 @@ Hexagon CPU architecture support
|
||||
================================
|
||||
|
||||
QEMU's TCG emulation includes support for v65, v66, v67, v68, v69, v71, v73,
|
||||
v75, v77, v79, v81.
|
||||
v75, v77, v79, v81, v83, v85.
|
||||
It also has support for the following architecture extensions:
|
||||
|
||||
- HVX (Hexagon Vector eXtensions)
|
||||
|
||||
+46
-2
@@ -7,12 +7,56 @@ config HEX_DSP
|
||||
select HEX_QTIMER
|
||||
select ARM_COMPATIBLE_SEMIHOSTING
|
||||
|
||||
config HEX_VIRT
|
||||
config HEX_BOARD
|
||||
bool
|
||||
default y
|
||||
depends on HEX_DSP && FDT
|
||||
select DEVICE_TREE
|
||||
select VIRTIO_MMIO
|
||||
select PL011
|
||||
|
||||
config HEX_VIRT
|
||||
bool
|
||||
default y
|
||||
depends on HEX_DSP && FDT
|
||||
select HEX_BOARD
|
||||
select VIRTIO_BLK
|
||||
select VIRTIO_SCSI
|
||||
|
||||
config HEX_QCOM_DSP
|
||||
bool
|
||||
depends on HEX_DSP && FDT
|
||||
select HEX_BOARD
|
||||
select UNIMP
|
||||
select QCOM_QDSP6SS_CLK
|
||||
select VIRTIO_BLK
|
||||
select VIRTIO_SCSI
|
||||
|
||||
config HEX_QCS6490_CDSP
|
||||
bool
|
||||
default y
|
||||
depends on HEX_DSP && FDT
|
||||
select HEX_QCOM_DSP
|
||||
|
||||
config HEX_SA8775P_CDSP
|
||||
bool
|
||||
default y
|
||||
depends on HEX_DSP && FDT
|
||||
select HEX_QCOM_DSP
|
||||
|
||||
config HEX_SC8480XP_NSP0
|
||||
bool
|
||||
default y
|
||||
depends on HEX_DSP && FDT
|
||||
select HEX_QCOM_DSP
|
||||
|
||||
config HEX_SA8797P_NSP0
|
||||
bool
|
||||
default y
|
||||
depends on HEX_DSP && FDT
|
||||
select HEX_QCOM_DSP
|
||||
|
||||
config HEX_SM8975_NSP
|
||||
bool
|
||||
default y
|
||||
depends on HEX_DSP && FDT
|
||||
select HEX_QCOM_DSP
|
||||
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Board-construction helpers shared by the Hexagon machines that describe
|
||||
* themselves to the guest with a generated device tree.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "elf.h"
|
||||
#include "hw/char/pl011.h"
|
||||
#include "hw/core/boards.h"
|
||||
#include "hw/core/clock.h"
|
||||
#include "hw/core/loader.h"
|
||||
#include "hw/core/qdev-clock.h"
|
||||
#include "hw/core/qdev-properties.h"
|
||||
#include "hw/core/sysbus.h"
|
||||
#include "hw/hexagon/hex-board.h"
|
||||
#include "hw/hexagon/hex-subsys.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "system/address-spaces.h"
|
||||
#include "system/device_tree.h"
|
||||
#include "system/reset.h"
|
||||
#include "system/system.h"
|
||||
#include "target/hexagon/cpu.h"
|
||||
|
||||
#define APB_CLK_HZ 24000000
|
||||
|
||||
void hex_board_create_fdt(MachineState *ms, const char *model,
|
||||
const char *compatible, int *fdt_size)
|
||||
{
|
||||
void *fdt = create_device_tree(fdt_size);
|
||||
uint8_t rng_seed[32];
|
||||
|
||||
if (!fdt) {
|
||||
error_report("create_device_tree() failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ms->fdt = fdt;
|
||||
|
||||
qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
|
||||
qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1);
|
||||
qemu_fdt_setprop_string(fdt, "/", "model", model);
|
||||
qemu_fdt_setprop_string(fdt, "/", "compatible", compatible);
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/soc");
|
||||
qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
|
||||
qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x1);
|
||||
qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/chosen");
|
||||
qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
|
||||
qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
|
||||
}
|
||||
|
||||
static void fdt_set_irq(MachineState *ms, const char *nodename, int irq)
|
||||
{
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
|
||||
HEX_BOARD_L2VIC_SPI_BASE + irq, 0);
|
||||
}
|
||||
|
||||
int32_t hex_board_fdt_add_l2vic(MachineState *ms,
|
||||
const struct hexagon_machine_config *cfg)
|
||||
{
|
||||
int32_t l2vic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
||||
g_autofree char *nodename = g_strdup_printf("/soc/interrupt-controller@%x",
|
||||
cfg->l2vic_base);
|
||||
static const char compat[] = "qcom,h2-pic\0hvm-pic";
|
||||
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/soc", "interrupt-parent", l2vic_phandle);
|
||||
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x0);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, cfg->l2vic_base,
|
||||
cfg->l2vic_size);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", l2vic_phandle);
|
||||
|
||||
return l2vic_phandle;
|
||||
}
|
||||
|
||||
void hex_board_fdt_add_hvx(MachineState *ms,
|
||||
const struct hexagon_machine_config *cfg)
|
||||
{
|
||||
const union hexagon_config_table *t = &cfg->cfgtable;
|
||||
|
||||
if (t->vtcm_size_kb > 0) {
|
||||
qemu_fdt_add_subnode(ms->fdt, "/soc/vtcm");
|
||||
qemu_fdt_setprop_string(ms->fdt, "/soc/vtcm", "compatible",
|
||||
"qcom,hexagon_vtcm");
|
||||
qemu_fdt_setprop_cells(ms->fdt, "/soc/vtcm", "reg", 0,
|
||||
t->vtcm_base << 16, t->vtcm_size_kb * 1024);
|
||||
}
|
||||
|
||||
if (t->ext_contexts > 0) {
|
||||
qemu_fdt_add_subnode(ms->fdt, "/soc/hvx");
|
||||
qemu_fdt_setprop_string(ms->fdt, "/soc/hvx", "compatible",
|
||||
"qcom,hexagon-hvx");
|
||||
qemu_fdt_setprop_cells(ms->fdt, "/soc/hvx", "qcom,hvx-max-ctxts",
|
||||
t->ext_contexts);
|
||||
qemu_fdt_setprop_cells(ms->fdt, "/soc/hvx", "qcom,hvx-vlength",
|
||||
t->hvx_vec_log_length);
|
||||
}
|
||||
}
|
||||
|
||||
void hex_board_fdt_add_cpus(MachineState *ms)
|
||||
{
|
||||
qemu_fdt_add_subnode(ms->fdt, "/cpus");
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
|
||||
|
||||
for (int num = ms->smp.cpus - 1; num >= 0; num--) {
|
||||
g_autofree char *nodename = g_strdup_printf("/cpus/cpu@%d", num);
|
||||
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
|
||||
qemu_fdt_alloc_phandle(ms->fdt));
|
||||
}
|
||||
}
|
||||
|
||||
void hex_board_create_tcm(const struct hexagon_machine_config *cfg,
|
||||
MemoryRegion *tcm)
|
||||
{
|
||||
if (cfg->l2tcm_size) {
|
||||
memory_region_init_ram(tcm, NULL, "tcm.ram", cfg->l2tcm_size,
|
||||
&error_fatal);
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
(hwaddr)cfg->cfgtable.l2tcm_base << 16,
|
||||
tcm);
|
||||
}
|
||||
}
|
||||
|
||||
void hex_board_create_uart(MachineState *ms, hwaddr base, hwaddr size,
|
||||
int irq, int32_t l2vic_phandle)
|
||||
{
|
||||
static const char compat[] = "arm,pl011\0arm,primecell";
|
||||
static const char clocknames[] = "uartclk\0apb_pclk";
|
||||
HexagonCommonMachineState *hms = HEXAGON_COMMON_MACHINE(ms);
|
||||
int32_t clk_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
||||
g_autofree char *nodename = g_strdup_printf("/pl011@%" PRIx64, base);
|
||||
Clock *apb_clk = clock_new(OBJECT(ms), "apb-pclk");
|
||||
DeviceState *dev = qdev_new(TYPE_PL011);
|
||||
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
||||
|
||||
clock_set_hz(apb_clk, APB_CLK_HZ);
|
||||
|
||||
qdev_prop_set_chr(dev, "chardev", serial_hd(0));
|
||||
qdev_connect_clock_in(dev, "clk", apb_clk);
|
||||
sysbus_realize_and_unref(s, &error_fatal);
|
||||
sysbus_mmio_map(s, 0, base);
|
||||
sysbus_connect_irq(s, 0, qdev_get_gpio_in(hms->l2vic, irq));
|
||||
|
||||
qemu_fdt_add_subnode(ms->fdt, "/apb-pclk");
|
||||
qemu_fdt_setprop_string(ms->fdt, "/apb-pclk", "compatible", "fixed-clock");
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "#clock-cells", 0x0);
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "clock-frequency", APB_CLK_HZ);
|
||||
qemu_fdt_setprop_string(ms->fdt, "/apb-pclk", "clock-output-names",
|
||||
"clk24mhz");
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "phandle", clk_phandle);
|
||||
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
/* Can't use setprop_string because of the embedded NUL */
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, size);
|
||||
fdt_set_irq(ms, nodename, irq);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
|
||||
l2vic_phandle);
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "clocks", clk_phandle,
|
||||
clk_phandle);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "clock-names", clocknames,
|
||||
sizeof(clocknames));
|
||||
|
||||
qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
|
||||
qemu_fdt_add_subnode(ms->fdt, "/aliases");
|
||||
qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", nodename);
|
||||
}
|
||||
|
||||
void hex_board_create_virtio(MachineState *ms, hwaddr base, hwaddr size,
|
||||
int irq_base, int count,
|
||||
int32_t l2vic_phandle)
|
||||
{
|
||||
HexagonCommonMachineState *hms = HEXAGON_COMMON_MACHINE(ms);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int irq = irq_base + i;
|
||||
hwaddr slot = base + i * size;
|
||||
g_autofree char *nodename = g_strdup_printf("/soc/virtio_mmio@%" PRIx64,
|
||||
slot);
|
||||
DeviceState *dev = qdev_new("virtio-mmio");
|
||||
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
||||
|
||||
object_property_add_child(OBJECT(ms), "virtio-mmio[*]", OBJECT(dev));
|
||||
sysbus_realize_and_unref(s, &error_fatal);
|
||||
sysbus_mmio_map(s, 0, slot);
|
||||
sysbus_connect_irq(s, 0, qdev_get_gpio_in(hms->l2vic, irq));
|
||||
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
||||
"virtio,mmio");
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, slot, size);
|
||||
fdt_set_irq(ms, nodename, irq);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
|
||||
l2vic_phandle);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t hex_board_load_elf(const char *filename,
|
||||
uint64_t (*translate)(void *opaque, uint64_t addr),
|
||||
void *opaque, uint64_t *high)
|
||||
{
|
||||
uint64_t entry = 0;
|
||||
|
||||
if (load_elf_ram_sym(filename, NULL, translate, opaque, &entry, NULL,
|
||||
high, NULL, 0, EM_HEXAGON, 0, 0,
|
||||
&address_space_memory, false, NULL) <= 0) {
|
||||
error_report("error loading '%s'", filename);
|
||||
exit(1);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
void hex_board_load_fdt(MachineState *ms, int fdt_size, hwaddr addr)
|
||||
{
|
||||
rom_add_blob_fixed_as("fdt", ms->fdt, fdt_size, addr,
|
||||
&address_space_memory);
|
||||
qemu_register_reset_nosnapshotload(
|
||||
qemu_fdt_randomize_seeds,
|
||||
rom_ptr_for_as(&address_space_memory, addr, fdt_size));
|
||||
}
|
||||
|
||||
static void hex_board_cpu_reset(void *opaque)
|
||||
{
|
||||
cpu_reset(CPU(opaque));
|
||||
}
|
||||
|
||||
void hex_board_create_cpus(MachineState *ms, bool have_start, uint64_t start)
|
||||
{
|
||||
HexagonCommonMachineState *hms = HEXAGON_COMMON_MACHINE(ms);
|
||||
g_autofree HexagonCPU **cpus = g_new(HexagonCPU *, ms->smp.cpus);
|
||||
|
||||
for (int i = 0; i < ms->smp.cpus; i++) {
|
||||
HexagonCPU *cpu = HEXAGON_CPU(object_new(ms->cpu_type));
|
||||
|
||||
qemu_register_reset(hex_board_cpu_reset, cpu);
|
||||
if (i == 0 && have_start) {
|
||||
qdev_prop_set_uint32(DEVICE(cpu), "exec-start-addr", start);
|
||||
}
|
||||
qdev_prop_set_uint32(DEVICE(cpu), "htid", i);
|
||||
qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", i != 0);
|
||||
hex_subsys_add_cpu(hms, DEVICE(cpu));
|
||||
cpus[i] = cpu;
|
||||
}
|
||||
|
||||
hex_subsys_realize_cluster(hms);
|
||||
for (int i = 0; i < ms->smp.cpus; i++) {
|
||||
hex_subsys_realize_cpu(hms, DEVICE(cpus[i]), i == 0);
|
||||
}
|
||||
}
|
||||
@@ -135,19 +135,23 @@ void hex_subsys_create(HexagonCommonMachineState *hms,
|
||||
{
|
||||
MachineState *machine = MACHINE(hms);
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
size_t i;
|
||||
|
||||
/* Main DDR at the reset vector. */
|
||||
/* Main DDR. */
|
||||
memory_region_init_ram(&hms->ram, NULL, "ddr.ram", machine->ram_size,
|
||||
&error_fatal);
|
||||
memory_region_add_subregion(sysmem, 0x0, &hms->ram);
|
||||
memory_region_add_subregion(sysmem, m_cfg->ddr_base, &hms->ram);
|
||||
|
||||
/* Config-table ROM and the blob that backs it. */
|
||||
memory_region_init_rom(&hms->cfgtable_rom, NULL, "config_table.rom",
|
||||
sizeof(m_cfg->cfgtable), &error_fatal);
|
||||
memory_region_add_subregion(sysmem, m_cfg->cfgbase, &hms->cfgtable_rom);
|
||||
rom_add_blob_fixed_as("config_table.rom", &m_cfg->cfgtable,
|
||||
sizeof(m_cfg->cfgtable), m_cfg->cfgbase,
|
||||
&address_space_memory);
|
||||
for (i = 0; i < ARRAY_SIZE(hms->cfgtable_data); i++) {
|
||||
hms->cfgtable_data[i] = cpu_to_le32(m_cfg->cfgtable.raw[i]);
|
||||
}
|
||||
rom_add_blob_fixed_as("config_table.rom", hms->cfgtable_data,
|
||||
sizeof(m_cfg->cfgtable), m_cfg->cfgbase,
|
||||
&address_space_memory);
|
||||
|
||||
if (m_cfg->cfgtable.vtcm_size_kb > 0) {
|
||||
memory_region_init_ram(&hms->vtcm, NULL, "vtcm.ram",
|
||||
|
||||
+161
-2
@@ -17,6 +17,7 @@
|
||||
#include "hw/hexagon/hex-subsys.h"
|
||||
#include "hw/core/loader.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/log.h"
|
||||
#include "elf.h"
|
||||
@@ -30,10 +31,16 @@
|
||||
|
||||
#include "machine_cfg_v66g_1024.h.inc"
|
||||
#include "machine_cfg_v68n_1024.h.inc"
|
||||
#include "machine_cfg_v73nc_1.h.inc"
|
||||
#include "machine_cfg_v79na_1.h.inc"
|
||||
#include "machine_cfg_v81dgb_1.h.inc"
|
||||
#include "machine_cfg_v81qa_1.h.inc"
|
||||
#include "machine_cfg_v85na_1.h.inc"
|
||||
#include "machine_cfg_v85qa_1.h.inc"
|
||||
|
||||
#define TYPE_HEXAGON_DSP_MACHINE "hexagon-dsp-machine"
|
||||
#define HEXAGON_DSP_SUBSYSTEM_BASE 0xfc900000
|
||||
#define HEXAGON_DSP_SUBSYSTEM_SIZE (HEXAGON_QTIMER_OFFSET + 0x1000)
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(HexagonDspMachineState, HEXAGON_DSP_MACHINE)
|
||||
|
||||
struct HexagonDspMachineState {
|
||||
@@ -41,6 +48,8 @@ struct HexagonDspMachineState {
|
||||
|
||||
hwaddr isdb_secure_flag;
|
||||
hwaddr isdb_trusted_flag;
|
||||
uint32_t subsystem_base;
|
||||
struct hexagon_machine_config config;
|
||||
};
|
||||
|
||||
static HexagonDspMachineState *current_dms;
|
||||
@@ -106,6 +115,58 @@ static void do_cpu_reset(void *opaque)
|
||||
cpu_reset(cs);
|
||||
}
|
||||
|
||||
static void hexagon_sim_get_subsystem_base(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
HexagonDspMachineState *dms = HEXAGON_DSP_MACHINE(obj);
|
||||
uint32_t value = dms->subsystem_base;
|
||||
|
||||
visit_type_uint32(v, name, &value, errp);
|
||||
}
|
||||
|
||||
static void hexagon_sim_set_subsystem_base(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
HexagonDspMachineState *dms = HEXAGON_DSP_MACHINE(obj);
|
||||
uint64_t subsystem_end;
|
||||
uint32_t value;
|
||||
|
||||
if (!visit_type_uint32(v, name, &value, errp)) {
|
||||
return;
|
||||
}
|
||||
if (!value || !QEMU_IS_ALIGNED(value, 64 * KiB)) {
|
||||
error_setg(errp, "subsystem-base must be nonzero and 64 KiB aligned");
|
||||
return;
|
||||
}
|
||||
subsystem_end = (uint64_t)value + HEXAGON_DSP_SUBSYSTEM_SIZE;
|
||||
if (subsystem_end > (uint64_t)UINT32_MAX + 1) {
|
||||
error_setg(errp, "subsystem-base 0x%x requires 0x%x bytes for the "
|
||||
"subsystem, beyond the end of the address space",
|
||||
value, HEXAGON_DSP_SUBSYSTEM_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
dms->subsystem_base = value;
|
||||
}
|
||||
|
||||
static void add_dsp_properties(ObjectClass *oc)
|
||||
{
|
||||
object_class_property_add(oc, "subsystem-base", "uint32",
|
||||
hexagon_sim_get_subsystem_base,
|
||||
hexagon_sim_set_subsystem_base, NULL, NULL);
|
||||
object_class_property_set_description(oc, "subsystem-base",
|
||||
"Simulator subsystem base address");
|
||||
}
|
||||
|
||||
static void hexagon_dsp_init(Object *obj)
|
||||
{
|
||||
HexagonDspMachineState *dms = HEXAGON_DSP_MACHINE(obj);
|
||||
|
||||
dms->subsystem_base = HEXAGON_DSP_SUBSYSTEM_BASE;
|
||||
}
|
||||
|
||||
static void hexagon_common_init(MachineState *machine, Rev_t rev,
|
||||
const struct hexagon_machine_config *m_cfg)
|
||||
{
|
||||
@@ -120,7 +181,13 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev,
|
||||
|
||||
machine->enable_graphics = 0;
|
||||
|
||||
hex_subsys_create(hms, m_cfg, rev);
|
||||
dms->config = *m_cfg;
|
||||
dms->config.csr_base = dms->subsystem_base;
|
||||
dms->config.l2vic_base = dms->subsystem_base + HEXAGON_L2VIC_OFFSET;
|
||||
dms->config.qtmr_region = dms->subsystem_base + HEXAGON_QTIMER_OFFSET;
|
||||
dms->config.cfgtable.subsystem_base = dms->subsystem_base >> 16;
|
||||
|
||||
hex_subsys_create(hms, &dms->config, rev);
|
||||
|
||||
g_autofree HexagonCPU **cpus = g_new(HexagonCPU *, machine->smp.cpus);
|
||||
|
||||
@@ -182,6 +249,7 @@ static void v66g_1024_init(ObjectClass *oc, const void *data)
|
||||
mc->is_default = true;
|
||||
mc->default_cpu_type = TYPE_HEXAGON_CPU_V66;
|
||||
mc->default_cpus = 4;
|
||||
add_dsp_properties(oc);
|
||||
}
|
||||
|
||||
static void v68n_1024_config_init(MachineState *machine)
|
||||
@@ -198,6 +266,23 @@ static void v68n_1024_init(ObjectClass *oc, const void *data)
|
||||
init_mc(mc);
|
||||
mc->default_cpu_type = TYPE_HEXAGON_CPU_V68;
|
||||
mc->default_cpus = 6;
|
||||
add_dsp_properties(oc);
|
||||
}
|
||||
|
||||
static void v73nc_1_config_init(MachineState *machine)
|
||||
{
|
||||
hexagon_common_init(machine, v73nc_1_rev, &v73nc_1);
|
||||
}
|
||||
|
||||
static void v73nc_1_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Hexagon V73NC_1";
|
||||
mc->init = v73nc_1_config_init;
|
||||
init_mc(mc);
|
||||
mc->default_cpu_type = TYPE_HEXAGON_CPU_V73;
|
||||
mc->default_cpus = 6;
|
||||
}
|
||||
|
||||
static void v81dgb_1_config_init(MachineState *machine)
|
||||
@@ -205,6 +290,23 @@ static void v81dgb_1_config_init(MachineState *machine)
|
||||
hexagon_common_init(machine, v81dgb_1_rev, &v81dgb_1);
|
||||
}
|
||||
|
||||
static void v79na_1_config_init(MachineState *machine)
|
||||
{
|
||||
hexagon_common_init(machine, v79_rev, &v79na_1);
|
||||
}
|
||||
|
||||
static void v79na_1_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Hexagon V79NA_1";
|
||||
mc->init = v79na_1_config_init;
|
||||
init_mc(mc);
|
||||
mc->default_cpu_type = TYPE_HEXAGON_CPU_V79;
|
||||
mc->default_cpus = 8;
|
||||
add_dsp_properties(oc);
|
||||
}
|
||||
|
||||
static void v81dgb_1_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
@@ -215,6 +317,7 @@ static void v81dgb_1_init(ObjectClass *oc, const void *data)
|
||||
mc->default_cpu_type = TYPE_HEXAGON_CPU_V81;
|
||||
mc->max_cpus = 12;
|
||||
mc->default_cpus = 12;
|
||||
add_dsp_properties(oc);
|
||||
}
|
||||
|
||||
static void v81qa_1_config_init(MachineState *machine)
|
||||
@@ -227,12 +330,47 @@ static void v81qa_1_init(ObjectClass *oc, const void *data)
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Hexagon V81QA_1";
|
||||
mc->alias = "sim";
|
||||
mc->init = v81qa_1_config_init;
|
||||
init_mc(mc);
|
||||
mc->default_cpu_type = TYPE_HEXAGON_CPU_V81;
|
||||
mc->max_cpus = 12;
|
||||
mc->default_cpus = 12;
|
||||
add_dsp_properties(oc);
|
||||
}
|
||||
|
||||
static void v85qa_1_config_init(MachineState *machine)
|
||||
{
|
||||
hexagon_common_init(machine, v85qa_1_rev, &v85qa_1);
|
||||
}
|
||||
|
||||
static void v85qa_1_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Hexagon V85QA_1";
|
||||
mc->init = v85qa_1_config_init;
|
||||
init_mc(mc);
|
||||
mc->default_cpu_type = TYPE_HEXAGON_CPU_V85;
|
||||
mc->max_cpus = 12;
|
||||
mc->default_cpus = 12;
|
||||
}
|
||||
|
||||
static void v85na_1_config_init(MachineState *machine)
|
||||
{
|
||||
hexagon_common_init(machine, v85na_1_rev, &v85na_1);
|
||||
}
|
||||
|
||||
static void v85na_1_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Hexagon V85NA_1";
|
||||
mc->alias = "sim";
|
||||
mc->init = v85na_1_config_init;
|
||||
init_mc(mc);
|
||||
mc->default_cpu_type = TYPE_HEXAGON_CPU_V85;
|
||||
mc->max_cpus = 12;
|
||||
mc->default_cpus = 12;
|
||||
}
|
||||
|
||||
static const TypeInfo hexagon_machine_types[] = {
|
||||
@@ -246,6 +384,7 @@ static const TypeInfo hexagon_machine_types[] = {
|
||||
.name = TYPE_HEXAGON_DSP_MACHINE,
|
||||
.parent = TYPE_HEXAGON_COMMON_MACHINE,
|
||||
.instance_size = sizeof(HexagonDspMachineState),
|
||||
.instance_init = hexagon_dsp_init,
|
||||
.abstract = true,
|
||||
},
|
||||
{
|
||||
@@ -258,6 +397,16 @@ static const TypeInfo hexagon_machine_types[] = {
|
||||
.parent = TYPE_HEXAGON_DSP_MACHINE,
|
||||
.class_init = v68n_1024_init,
|
||||
},
|
||||
{
|
||||
.name = MACHINE_TYPE_NAME("V73NC_1"),
|
||||
.parent = TYPE_HEXAGON_DSP_MACHINE,
|
||||
.class_init = v73nc_1_init,
|
||||
},
|
||||
{
|
||||
.name = MACHINE_TYPE_NAME("V79NA_1"),
|
||||
.parent = TYPE_HEXAGON_DSP_MACHINE,
|
||||
.class_init = v79na_1_init,
|
||||
},
|
||||
{
|
||||
.name = MACHINE_TYPE_NAME("V81DGB_1"),
|
||||
.parent = TYPE_HEXAGON_DSP_MACHINE,
|
||||
@@ -268,6 +417,16 @@ static const TypeInfo hexagon_machine_types[] = {
|
||||
.parent = TYPE_HEXAGON_DSP_MACHINE,
|
||||
.class_init = v81qa_1_init,
|
||||
},
|
||||
{
|
||||
.name = MACHINE_TYPE_NAME("V85QA_1"),
|
||||
.parent = TYPE_HEXAGON_DSP_MACHINE,
|
||||
.class_init = v85qa_1_init,
|
||||
},
|
||||
{
|
||||
.name = MACHINE_TYPE_NAME("V85NA_1"),
|
||||
.parent = TYPE_HEXAGON_DSP_MACHINE,
|
||||
.class_init = v85na_1_init,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(hexagon_machine_types)
|
||||
@@ -321,6 +321,24 @@ uint64_t hexagon_tlb_write(HexagonTLBState *tlb, uint32_t index,
|
||||
return old;
|
||||
}
|
||||
|
||||
uint32_t hexagon_tlb_invalidate_asid(HexagonTLBState *tlb, uint32_t asid)
|
||||
{
|
||||
uint32_t invalidated = 0;
|
||||
|
||||
for (uint32_t i = 0; i < tlb->num_entries; i++) {
|
||||
uint64_t entry = tlb->entries[i];
|
||||
|
||||
if (!GET_PTE_V(entry) || GET_PTE_G(entry) ||
|
||||
GET_PTE_ASID(entry) != asid) {
|
||||
continue;
|
||||
}
|
||||
tlb->entries[i] = deposit64(entry, 63, 1, 0);
|
||||
invalidated++;
|
||||
}
|
||||
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
bool hexagon_tlb_find_match(HexagonTLBState *tlb, uint32_t asid,
|
||||
uint32_t VA, MMUAccessType access_type,
|
||||
hwaddr *PA, int *prot, uint64_t *size,
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
static const struct hexagon_machine_config qcs6490_cdsp = {
|
||||
.ddr_base = 0x80000000,
|
||||
.cfgbase = 0x09980000,
|
||||
.l2tcm_size = 0x00000000,
|
||||
.l2vic_base = 0x0a390000,
|
||||
.l2vic_size = 0x00001000,
|
||||
.csr_base = 0x0a3a0000,
|
||||
.qtmr_region = 0x0a3a1000,
|
||||
.cfgtable = {
|
||||
.l2tcm_base = 0x00000980,
|
||||
.reserved0 = 0x00000000,
|
||||
.subsystem_base = 0x00000a38,
|
||||
.etm_base = 0x00000999,
|
||||
.l2cfg_base = 0x0000099a,
|
||||
.reserved1 = 0x0000099b,
|
||||
.l1s0_base = 0x000009c0,
|
||||
.axi2_lowaddr = 0x00000000,
|
||||
.streamer_base = 0x0000099c,
|
||||
.reserved2 = 0x0000099d,
|
||||
.fastl2vic_base = 0x0000099e,
|
||||
.jtlb_size_entries = 0x00000080,
|
||||
.coproc_present = 0x00000001,
|
||||
.ext_contexts = 0x00000002,
|
||||
.vtcm_base = 0x000009c0,
|
||||
.vtcm_size_kb = 0x00000800,
|
||||
.l2tag_size = 0x00000400,
|
||||
.l2ecomem_size = 0x00000400,
|
||||
.thread_enable_mask = 0x0000003f,
|
||||
.eccreg_base = 0x0000099f,
|
||||
.l2line_size = 0x00000080,
|
||||
.tiny_core = 0x00000000,
|
||||
.l2itcm_size = 0x00000000,
|
||||
.l2itcm_base = 0x00000980,
|
||||
.reserved3 = 0x00000000,
|
||||
.dtm_present = 0x00000000,
|
||||
.dma_version = 0x00000001,
|
||||
.hvx_vec_log_length = 0x00000007,
|
||||
.core_id = 0x00000000,
|
||||
.core_count = 0x00000000,
|
||||
.coproc2_reg0 = 0x00000040,
|
||||
.coproc2_reg1 = 0x00000020,
|
||||
.v2x_mode = 0x00000001,
|
||||
.coproc2_reg2 = 0x00000002,
|
||||
.coproc2_reg3 = 0x00000000,
|
||||
.coproc2_reg4 = 0x00000000,
|
||||
.coproc2_reg5 = 0x00000000,
|
||||
.coproc2_reg6 = 0x00000000,
|
||||
.coproc2_reg7 = 0x00000000,
|
||||
.acd_preset = 0x00000001,
|
||||
.mnd_preset = 0x00000001,
|
||||
.l1d_size_kb = 0x00000010,
|
||||
.l1i_size_kb = 0x00000020,
|
||||
.l1d_write_policy = 0x00000002,
|
||||
.vtcm_bank_width = 0x00000040,
|
||||
.reserved4 = 0x00000001,
|
||||
.reserved5 = 0x00000000,
|
||||
.reserved6 = 0x00000000,
|
||||
.coproc2_cvt_mpy_size = 0x0000000a,
|
||||
.consistency_domain = 0x00000000,
|
||||
.capacity_domain = 0x00000000,
|
||||
.axi3_lowaddr = 0x00000000,
|
||||
},
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
static const struct hexagon_machine_config SA8775P_cdsp0 = {
|
||||
.ddr_base = 0x80000000,
|
||||
.cfgbase = 0x24000000 + 0x180000,
|
||||
.l2tcm_size = 0x00000000,
|
||||
.l2vic_base = 0x26300000 + 0x90000,
|
||||
@@ -25,7 +26,7 @@ static const struct hexagon_machine_config SA8775P_cdsp0 = {
|
||||
.vtcm_base = 0x00002500,
|
||||
.vtcm_size_kb = 0x00002000,
|
||||
.l2tag_size = 0x00000400,
|
||||
.l2ecomem_size = 0x00000000,
|
||||
.l2ecomem_size = 0x00000400,
|
||||
.thread_enable_mask = 0x0000003f,
|
||||
.eccreg_base = 0x0000241f,
|
||||
.l2line_size = 0x00000080,
|
||||
@@ -60,5 +61,8 @@ static const struct hexagon_machine_config SA8775P_cdsp0 = {
|
||||
.consistency_domain = 0x000000e0,
|
||||
.capacity_domain = 0x00000080,
|
||||
.axi3_lowaddr = 0x00000000,
|
||||
.coproc2_int8_subcolumns = 0x00000002,
|
||||
.corecfg_present = 0x00000005,
|
||||
.coproc2_fp16_acc_exp = 0x00000007,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
static const struct hexagon_machine_config sa8797p_nsp0 = {
|
||||
.ddr_base = 0x80000000,
|
||||
.cfgbase = 0x30180000,
|
||||
.l2vic_base = 0x32390000,
|
||||
.l2vic_size = 0x1000,
|
||||
.l2tcm_size = 0x100000,
|
||||
.csr_base = 0x323a0000,
|
||||
.qtmr_region = 0x323a1000,
|
||||
.cfgtable = {
|
||||
.l2tcm_base = 0x3000,
|
||||
.subsystem_base = 0x3238,
|
||||
.etm_base = 0x3019,
|
||||
.l2cfg_base = 0x301a,
|
||||
.l1s0_base = 0x3100,
|
||||
.fastl2vic_base = 0x301e,
|
||||
.jtlb_size_entries = 0x80,
|
||||
.coproc_present = 0xd,
|
||||
.ext_contexts = 8,
|
||||
.vtcm_base = 0x3100,
|
||||
.vtcm_size_kb = 0x4000,
|
||||
.l2tag_size = 0x400,
|
||||
.l2ecomem_size = 0x400,
|
||||
.thread_enable_mask = 0xfff,
|
||||
.eccreg_base = 0x301f,
|
||||
.l2line_size = 0x80,
|
||||
.l2itcm_base = 0x3000,
|
||||
.dma_version = 8,
|
||||
.hvx_vec_log_length = 7,
|
||||
.coproc2_reg0 = 0x10,
|
||||
.coproc2_reg1 = 8,
|
||||
.v2x_mode = 1,
|
||||
.acd_preset = 1,
|
||||
.mnd_preset = 1,
|
||||
.l1d_size_kb = 0x40,
|
||||
.l1i_size_kb = 0x40,
|
||||
.l1d_write_policy = 2,
|
||||
.vtcm_bank_width = 0x80,
|
||||
.reserved4 = 1,
|
||||
.reserved6 = 3,
|
||||
.consistency_domain = 0xe0,
|
||||
.capacity_domain = 0x80,
|
||||
.corecfg_present = 0xd,
|
||||
.coproc2_fp16_acc_exp = 1,
|
||||
.AXIM_data_width = 0x100,
|
||||
.l1d_ways = 8,
|
||||
.l1i_ways = 4,
|
||||
.l2way_num = 8,
|
||||
.dma_jtlb_entries = 0x40,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
/* Config table of the SC8480XP NSP0. */
|
||||
static const struct hexagon_machine_config sc8480xp_nsp0 = {
|
||||
.ddr_base = 0x80000000,
|
||||
.cfgbase = 0x30180000,
|
||||
.l2vic_base = 0x32390000,
|
||||
.l2vic_size = 0x1000,
|
||||
.csr_base = 0x323a0000,
|
||||
.qtmr_region = 0x323a1000,
|
||||
.cfgtable = {
|
||||
.l2tcm_base = 0x3000,
|
||||
.subsystem_base = 0x3238,
|
||||
.etm_base = 0x3019,
|
||||
.l2cfg_base = 0x301a,
|
||||
.l1s0_base = 0x3100,
|
||||
.fastl2vic_base = 0x301e,
|
||||
.jtlb_size_entries = 0x80,
|
||||
.coproc_present = 0xd,
|
||||
.ext_contexts = 8,
|
||||
.vtcm_base = 0x3100,
|
||||
.vtcm_size_kb = 0x2000,
|
||||
.l2tag_size = 0x400,
|
||||
.l2ecomem_size = 0x400,
|
||||
.thread_enable_mask = 0xfff,
|
||||
.l2line_size = 0x80,
|
||||
.l2itcm_base = 0xd800,
|
||||
.dma_version = 8,
|
||||
.hvx_vec_log_length = 7,
|
||||
.coproc2_reg0 = 0x10,
|
||||
.coproc2_reg1 = 8,
|
||||
.acd_preset = 1,
|
||||
.mnd_preset = 1,
|
||||
.l1d_size_kb = 0x40,
|
||||
.l1i_size_kb = 0x40,
|
||||
.l1d_write_policy = 2,
|
||||
.vtcm_bank_width = 0x80,
|
||||
.reserved4 = 1,
|
||||
.axi3_lowaddr = 0x4000,
|
||||
.corecfg_present = 0xd,
|
||||
.coproc2_fp16_acc_exp = 1,
|
||||
.AXIM_data_width = 0x100,
|
||||
.l1d_ways = 8,
|
||||
.l1i_ways = 4,
|
||||
.l2way_num = 8,
|
||||
.dma_jtlb_entries = 0x40,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
/* Config table of the SM8975 NSP. */
|
||||
static const struct hexagon_machine_config sm8975_nsp = {
|
||||
.ddr_base = 0x80000000,
|
||||
.cfgbase = 0x24180000,
|
||||
.l2tcm_size = 0x100000,
|
||||
.l2vic_base = 0x26390000,
|
||||
.l2vic_size = 0x1000,
|
||||
.csr_base = 0x263a0000,
|
||||
.qtmr_region = 0x263a1000,
|
||||
.cfgtable = {
|
||||
.l2tcm_base = 0x2400,
|
||||
.subsystem_base = 0x2638,
|
||||
.etm_base = 0x2419,
|
||||
.l2cfg_base = 0x241a,
|
||||
.l1s0_base = 0x2500,
|
||||
.fastl2vic_base = 0x241e,
|
||||
.jtlb_size_entries = 0x80,
|
||||
.coproc_present = 0x1d,
|
||||
.ext_contexts = 8,
|
||||
.vtcm_base = 0x2500,
|
||||
.vtcm_size_kb = 0x3000,
|
||||
.l2tag_size = 0x400,
|
||||
.l2ecomem_size = 0x400,
|
||||
.thread_enable_mask = 0xfff,
|
||||
.l2line_size = 0x80,
|
||||
.l2itcm_base = 0x2400,
|
||||
.dma_version = 0xc,
|
||||
.hvx_vec_log_length = 7,
|
||||
.coproc2_reg0 = 0x10,
|
||||
.coproc2_reg1 = 8,
|
||||
.coproc2_reg2 = 3,
|
||||
.acd_preset = 1,
|
||||
.mnd_preset = 1,
|
||||
.l1d_size_kb = 0x40,
|
||||
.l1i_size_kb = 0x40,
|
||||
.l1d_write_policy = 2,
|
||||
.vtcm_bank_width = 0x80,
|
||||
.consistency_domain = 0xe0,
|
||||
.capacity_domain = 0x80,
|
||||
.axi3_lowaddr = 0x4000,
|
||||
.corecfg_present = 0xd,
|
||||
.coproc2_fp16_acc_exp = 3,
|
||||
.AXIM_data_width = 0x100,
|
||||
.l1d_ways = 8,
|
||||
.l1i_ways = 4,
|
||||
.l2way_num = 8,
|
||||
.dma_jtlb_entries = 0x40,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
static const struct hexagon_machine_config v73nc_1 = {
|
||||
.cfgbase = 0xd8180000,
|
||||
.l2tcm_size = 0x00000000,
|
||||
.l2vic_base = 0xfc910000,
|
||||
.l2vic_size = 0x00001000,
|
||||
.csr_base = 0xfc900000,
|
||||
.qtmr_region = 0xfc921000,
|
||||
.cfgtable = {
|
||||
.l2tcm_base = 0x0000d800,
|
||||
.reserved0 = 0x00000000,
|
||||
.subsystem_base = 0x00002000,
|
||||
.etm_base = 0x0000d819,
|
||||
.l2cfg_base = 0x0000d81a,
|
||||
.reserved1 = 0x00000000,
|
||||
.l1s0_base = 0x0000d900,
|
||||
.axi2_lowaddr = 0x00003000,
|
||||
.streamer_base = 0x00000000,
|
||||
.reserved2 = 0x00000000,
|
||||
.fastl2vic_base = 0x0000d81e,
|
||||
.jtlb_size_entries = 0x00000080,
|
||||
.coproc_present = 0x00000001,
|
||||
.ext_contexts = 0x00000002,
|
||||
.vtcm_base = 0x0000d900,
|
||||
.vtcm_size_kb = 0x00000800,
|
||||
.l2tag_size = 0x00000400,
|
||||
.l2ecomem_size = 0x00000400,
|
||||
.thread_enable_mask = 0x0000003f,
|
||||
.eccreg_base = 0x00000000,
|
||||
.l2line_size = 0x00000080,
|
||||
.tiny_core = 0x00000000,
|
||||
.l2itcm_size = 0x00000000,
|
||||
.l2itcm_base = 0x0000d800,
|
||||
.reserved3 = 0x00000000,
|
||||
.dtm_present = 0x00000000,
|
||||
.dma_version = 0x00000002,
|
||||
.hvx_vec_log_length = 0x00000007,
|
||||
.core_id = 0x00000000,
|
||||
.core_count = 0x00000000,
|
||||
.coproc2_reg0 = 0x00000040,
|
||||
.coproc2_reg1 = 0x00000020,
|
||||
.v2x_mode = 0x00000001,
|
||||
.coproc2_reg2 = 0x00000001,
|
||||
.coproc2_reg3 = 0x00000000,
|
||||
.coproc2_reg4 = 0x00000000,
|
||||
.coproc2_reg5 = 0x00000000,
|
||||
.coproc2_reg6 = 0x00000000,
|
||||
.coproc2_reg7 = 0x00000000,
|
||||
.acd_preset = 0x00000000,
|
||||
.mnd_preset = 0x00000000,
|
||||
.l1d_size_kb = 0x00000010,
|
||||
.l1i_size_kb = 0x00000020,
|
||||
.l1d_write_policy = 0x00000002,
|
||||
.vtcm_bank_width = 0x00000080,
|
||||
.reserved4 = 0x00000001,
|
||||
.reserved5 = 0x00000000,
|
||||
.reserved6 = 0x00000000,
|
||||
.coproc2_cvt_mpy_size = 0x0000000a,
|
||||
.consistency_domain = 0x000000e0,
|
||||
.capacity_domain = 0x00000080,
|
||||
.axi3_lowaddr = 0x00004000,
|
||||
.coproc2_int8_subcolumns = 0x00000002,
|
||||
.corecfg_present = 0x00000001,
|
||||
.coproc2_fp16_acc_exp = 0x00000000,
|
||||
.AXIM2_secondary_base = 0x00004000,
|
||||
.AXIM_data_width = 0x00000000,
|
||||
.l1d_ways = 0x00000000,
|
||||
.l1i_ways = 0x00000000,
|
||||
.l2way_num = 0x00000000,
|
||||
.dma_jtlb_entries = 0x00000000,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
static const struct hexagon_machine_config v79na_1 = {
|
||||
.cfgbase = 0xd8180000,
|
||||
.l2tcm_size = 0x00000000,
|
||||
.l2vic_base = 0xfc910000,
|
||||
.l2vic_size = 0x00001000,
|
||||
.csr_base = 0xfc900000,
|
||||
.qtmr_region = 0xfc921000,
|
||||
.cfgtable = {
|
||||
.l2tcm_base = 0x0000d800, .subsystem_base = 0x00002000,
|
||||
.etm_base = 0x0000d819, .l2cfg_base = 0x0000d81a,
|
||||
.l1s0_base = 0x0000d900, .axi2_lowaddr = 0x00003000,
|
||||
.fastl2vic_base = 0x0000d81e, .jtlb_size_entries = 0x00000080,
|
||||
.coproc_present = 0x0000000d, .ext_contexts = 0x00000006,
|
||||
.vtcm_base = 0x0000d900, .vtcm_size_kb = 0x00002000,
|
||||
.l2tag_size = 0x00000400, .l2ecomem_size = 0x00000400,
|
||||
.thread_enable_mask = 0x000000ff, .l2line_size = 0x00000080,
|
||||
.l2itcm_base = 0x0000d800, .dma_version = 0x00000006,
|
||||
.hvx_vec_log_length = 0x00000007, .coproc2_reg0 = 0x00000040,
|
||||
.coproc2_reg1 = 0x00000020, .v2x_mode = 0x00000001,
|
||||
.coproc2_reg2 = 0x00000010, .coproc2_reg3 = 0x00000020,
|
||||
.coproc2_reg4 = 0x00000020, .coproc2_reg5 = 0x00000008,
|
||||
.coproc2_reg6 = 0x00000016, .coproc2_reg7 = 0x00000008,
|
||||
.acd_preset = 0x00000001, .mnd_preset = 0x00000001,
|
||||
.l1d_size_kb = 0x00000020, .l1i_size_kb = 0x00000020,
|
||||
.l1d_write_policy = 0x00000002, .vtcm_bank_width = 0x00000080,
|
||||
.reserved4 = 0x00000001, .coproc2_cvt_mpy_size = 0x0000000a,
|
||||
.consistency_domain = 0x000000e0, .capacity_domain = 0x00000080,
|
||||
.axi3_lowaddr = 0x00004000, .coproc2_int8_subcolumns = 0x00000002,
|
||||
.corecfg_present = 0x0000000d, .coproc2_fp16_acc_exp = 0x00000007,
|
||||
.AXIM2_secondary_base = 0x00004000, .AXIM_data_width = 0x00000100,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
static const struct hexagon_machine_config v85na_1 = {
|
||||
.cfgbase = 0xd8180000,
|
||||
.l2tcm_size = 0x00000000,
|
||||
.l2vic_base = 0xfc910000,
|
||||
.l2vic_size = 0x00001000,
|
||||
.csr_base = 0xfc900000,
|
||||
.qtmr_region = 0xfc921000,
|
||||
.cfgtable = {
|
||||
.l2tcm_base = 0x0000d800,
|
||||
.subsystem_base = 0x00002000,
|
||||
.etm_base = 0x0000d819,
|
||||
.l2cfg_base = 0x0000d81a,
|
||||
.reserved1 = 0x0000d81b,
|
||||
.l1s0_base = 0x0000d900,
|
||||
.fastl2vic_base = 0x0000d81e,
|
||||
.jtlb_size_entries = 0x00000080,
|
||||
.coproc_present = 0x0000001d,
|
||||
.ext_contexts = 0x00000008,
|
||||
.vtcm_base = 0x0000d900,
|
||||
.vtcm_size_kb = 0x00003000,
|
||||
.l2tag_size = 0x00000400,
|
||||
.l2ecomem_size = 0x00000400,
|
||||
.thread_enable_mask = 0x00000fff,
|
||||
.l2line_size = 0x00000080,
|
||||
.l2itcm_base = 0x0000d800,
|
||||
.dma_version = 0x0000000c,
|
||||
.hvx_vec_log_length = 0x00000007,
|
||||
.coproc2_reg0 = 0x00000010,
|
||||
.coproc2_reg1 = 0x00000008,
|
||||
.coproc2_reg2 = 0x00000003,
|
||||
.acd_preset = 0x00000001,
|
||||
.mnd_preset = 0x00000001,
|
||||
.l1d_size_kb = 0x00000040,
|
||||
.l1i_size_kb = 0x00000040,
|
||||
.l1d_write_policy = 0x00000002,
|
||||
.vtcm_bank_width = 0x00000080,
|
||||
.consistency_domain = 0x000000e0,
|
||||
.capacity_domain = 0x00000080,
|
||||
.axi3_lowaddr = 0x00004000,
|
||||
.corecfg_present = 0x0000000d,
|
||||
.coproc2_fp16_acc_exp = 0x00000003,
|
||||
.AXIM_data_width = 0x00000100,
|
||||
.l1d_ways = 0x00000008,
|
||||
.l1i_ways = 0x00000004,
|
||||
.l2way_num = 0x00000008,
|
||||
.dma_jtlb_entries = 0x00000040,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
static const struct hexagon_machine_config v85qa_1 = {
|
||||
.cfgbase = 0xd8180000,
|
||||
.l2tcm_size = 0x00000000,
|
||||
.l2vic_base = 0xfc910000,
|
||||
.l2vic_size = 0x00001000,
|
||||
.csr_base = 0xfc900000,
|
||||
.qtmr_region = 0xfc921000,
|
||||
.cfgtable = {
|
||||
.l2tcm_base = 0x0000d800,
|
||||
.subsystem_base = 0x0000fc90,
|
||||
.etm_base = 0x0000d819,
|
||||
.l2cfg_base = 0x0000d81a,
|
||||
.reserved1 = 0x0000d81b,
|
||||
.l1s0_base = 0x0000d900,
|
||||
.fastl2vic_base = 0x0000d81e,
|
||||
.jtlb_size_entries = 0x00000080,
|
||||
.coproc_present = 0x0000001d,
|
||||
.ext_contexts = 0x00000008,
|
||||
.vtcm_base = 0x0000d900,
|
||||
.vtcm_size_kb = 0x00004000,
|
||||
.l2tag_size = 0x00000400,
|
||||
.l2ecomem_size = 0x00000400,
|
||||
.thread_enable_mask = 0x00000fff,
|
||||
.eccreg_base = 0x0000d81f,
|
||||
.l2line_size = 0x00000080,
|
||||
.l2itcm_base = 0x0000d800,
|
||||
.dma_version = 0x0000000c,
|
||||
.hvx_vec_log_length = 0x00000007,
|
||||
.coproc2_reg0 = 0x00000010,
|
||||
.coproc2_reg1 = 0x00000008,
|
||||
.coproc2_reg2 = 0x00000003,
|
||||
.acd_preset = 0x00000001,
|
||||
.mnd_preset = 0x00000001,
|
||||
.l1d_size_kb = 0x00000040,
|
||||
.l1i_size_kb = 0x00000040,
|
||||
.l1d_write_policy = 0x00000002,
|
||||
.vtcm_bank_width = 0x00000080,
|
||||
.consistency_domain = 0x000000e0,
|
||||
.capacity_domain = 0x00000080,
|
||||
.axi3_lowaddr = 0x00004000,
|
||||
.corecfg_present = 0x0000000d,
|
||||
.coproc2_fp16_acc_exp = 0x00000003,
|
||||
.AXIM_data_width = 0x00000100,
|
||||
.l1d_ways = 0x00000008,
|
||||
.l1i_ways = 0x00000004,
|
||||
.l2way_num = 0x00000008,
|
||||
.dma_jtlb_entries = 0x00000040,
|
||||
},
|
||||
};
|
||||
@@ -4,6 +4,13 @@ hexagon_ss.add(files('hexagon_globalreg.c'))
|
||||
hexagon_ss.add(files('hexagon_hvx_context.c'))
|
||||
hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hex-subsys.c'))
|
||||
hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hexagon_dsp.c'))
|
||||
hexagon_ss.add(when: 'CONFIG_HEX_BOARD', if_true: files('hex-board.c'))
|
||||
hexagon_ss.add(when: 'CONFIG_HEX_VIRT', if_true: files('virt.c'))
|
||||
hexagon_ss.add(when: 'CONFIG_HEX_QCOM_DSP', if_true: files('qcom_dsp.c'))
|
||||
hexagon_ss.add(when: 'CONFIG_HEX_QCS6490_CDSP', if_true: files('qcs6490_cdsp.c'))
|
||||
hexagon_ss.add(when: 'CONFIG_HEX_SA8775P_CDSP', if_true: files('sa8775p_cdsp.c'))
|
||||
hexagon_ss.add(when: 'CONFIG_HEX_SC8480XP_NSP0', if_true: files('sc8480xp_nsp0.c'))
|
||||
hexagon_ss.add(when: 'CONFIG_HEX_SA8797P_NSP0', if_true: files('sa8797p_nsp0.c'))
|
||||
hexagon_ss.add(when: 'CONFIG_HEX_SM8975_NSP', if_true: files('sm8975_nsp.c'))
|
||||
|
||||
hw_arch += {'hexagon': hexagon_ss}
|
||||
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* DSP subsystem machines: the board layer shared by the SoC models.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/core/boards.h"
|
||||
#include "hw/core/loader.h"
|
||||
#include "hw/core/sysbus.h"
|
||||
#include "hw/hexagon/hexagon.h"
|
||||
#include "hw/hexagon/hex-board.h"
|
||||
#include "hw/hexagon/hex-subsys.h"
|
||||
#include "hw/hexagon/qcom_dsp.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/units.h"
|
||||
#include "system/address-spaces.h"
|
||||
#include "system/device_tree.h"
|
||||
|
||||
enum {
|
||||
QCOM_DSP_UART0,
|
||||
QCOM_DSP_VIRTIO,
|
||||
QCOM_DSP_GPT,
|
||||
QCOM_DSP_BOOT,
|
||||
};
|
||||
|
||||
static const MemMapEntry qcom_dsp_memmap[] = {
|
||||
[QCOM_DSP_UART0] = { 0x37000000, 0x00001000 },
|
||||
[QCOM_DSP_VIRTIO] = { 0x37010000, 0x00001000 },
|
||||
/* Not a device: the window the kernel's H2 timer driver binds to. */
|
||||
[QCOM_DSP_GPT] = { 0xab000000, 0x00001000 },
|
||||
[QCOM_DSP_BOOT] = { 0x99c00000, 0x00000200 },
|
||||
};
|
||||
|
||||
static const int QCOM_DSP_UART0_IRQ = 15;
|
||||
/* Virtio IRQs run from QCOM_DSP_VIRTIO_IRQ to QCOM_DSP_VIRTIO_IRQ + 7 */
|
||||
static const int QCOM_DSP_VIRTIO_IRQ = 96;
|
||||
static const int QCOM_DSP_GPT_IRQ = 12;
|
||||
|
||||
#define QCOM_DSP_L2_ECC_SIZE 0x1000
|
||||
|
||||
#define QCOM_DSP_MAX_KERNEL_RAM (896 * MiB)
|
||||
|
||||
static const uint32_t bootloader[] = {
|
||||
/* Load fdt_base_low value into r0: */
|
||||
0x099c4000, /* { immext(#0x99c00000) */
|
||||
0x7800c606, /* r6 = ##-0x662fffd0 } */
|
||||
0x9186c000, /* { r0 = memw(r6+#0x0) } */
|
||||
|
||||
/* Load fdt_base_high value into r1: */
|
||||
0x099c4000, /* { immext(#0x99c00000) */
|
||||
0x7800c586, /* r6 = ##-0x662fffd4 } */
|
||||
0x9186c001, /* { r1 = memw(r6+#0x0) } */
|
||||
|
||||
/* Load next_stage_entry value into r7: */
|
||||
0x099c4000, /* { immext(#0x99c00000) */
|
||||
0x7800c687, /* r7 = ##-0x662fffcc } */
|
||||
0x9187c007, /* { r7 = memw(r7+#0x0) } */
|
||||
|
||||
/* Jump to next_stage_entry, r1:0 now contains fdt_base: */
|
||||
0x5287c000, /* { jumpr r7 } */
|
||||
0x0, /* Invalid packet */
|
||||
0x0, /* Pad for fdt_base_high */
|
||||
0x0, /* Pad for fdt_base_low */
|
||||
0x0, /* Pad for next_stage_entry */
|
||||
};
|
||||
|
||||
enum {
|
||||
FDT_HI = 11,
|
||||
FDT_LO,
|
||||
ENTRY_ADDR,
|
||||
};
|
||||
|
||||
static const QcomDspMachineInfo *qcom_dsp_info(MachineState *ms)
|
||||
{
|
||||
return QCOM_DSP_MACHINE_GET_CLASS(ms)->info;
|
||||
}
|
||||
|
||||
void qcom_dsp_add_regions(MachineState *ms, const QcomDspRegion *regions,
|
||||
unsigned int count)
|
||||
{
|
||||
const char *machine = MACHINE_GET_CLASS(ms)->name;
|
||||
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
g_autofree char *name = g_strdup_printf("%s.%s@%" HWADDR_PRIx, machine,
|
||||
regions[i].name,
|
||||
regions[i].base);
|
||||
|
||||
create_unimplemented_device(name, regions[i].base,
|
||||
regions[i].size ? regions[i].size : 0x1000);
|
||||
}
|
||||
}
|
||||
|
||||
void qcom_dsp_add_device(const char *type, hwaddr base)
|
||||
{
|
||||
DeviceState *dev = qdev_new(type);
|
||||
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
}
|
||||
|
||||
void qcom_soc_add_qup_geni_ports(const char *soc, hwaddr base,
|
||||
unsigned int ports, hwaddr size)
|
||||
{
|
||||
for (unsigned int i = 0; i < ports; i++) {
|
||||
g_autofree char *name = g_strdup_printf("%s.qup-geni@%" HWADDR_PRIx,
|
||||
soc, base + i * size);
|
||||
|
||||
create_unimplemented_device(name, base + i * size, size);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The firmware programs the L2 ECC registers and polls them until what it
|
||||
* wrote reads back, so they need to hold state.
|
||||
*/
|
||||
static void qcom_dsp_add_l2_ecc_regs(QcomDspMachineState *qms,
|
||||
const QcomDspMachineInfo *info)
|
||||
{
|
||||
hwaddr base = (hwaddr)info->cfg->cfgtable.eccreg_base << 16;
|
||||
|
||||
if (!base) {
|
||||
return;
|
||||
}
|
||||
memory_region_init_ram(&qms->l2_ecc, NULL, "l2-ecc-regs",
|
||||
QCOM_DSP_L2_ECC_SIZE, &error_fatal);
|
||||
memory_region_add_subregion(get_system_memory(), base, &qms->l2_ecc);
|
||||
}
|
||||
|
||||
static void qcom_dsp_create_fdt(QcomDspMachineState *qms)
|
||||
{
|
||||
MachineState *ms = MACHINE(qms);
|
||||
g_autofree char *compatible = g_strdup_printf("qcom,%s",
|
||||
MACHINE_GET_CLASS(ms)->name);
|
||||
|
||||
hex_board_create_fdt(ms, MACHINE_GET_CLASS(ms)->desc, compatible,
|
||||
&qms->fdt_size);
|
||||
qemu_fdt_setprop_string(ms->fdt, "/soc", "compatible", "simple-bus");
|
||||
}
|
||||
|
||||
/*
|
||||
* The H2 hypervisor provides the guest timer through hypercalls, so this
|
||||
* node only tells the kernel's timer driver which interrupt to expect.
|
||||
*/
|
||||
static void qcom_dsp_fdt_add_gpt(MachineState *ms)
|
||||
{
|
||||
static const char compat[] = "qcom,h2-timer\0hvm-timer";
|
||||
g_autofree char *name = g_strdup_printf("/soc/gpt@%" PRIx64,
|
||||
qcom_dsp_memmap[QCOM_DSP_GPT].base);
|
||||
|
||||
qemu_fdt_add_subnode(ms->fdt, name);
|
||||
qemu_fdt_setprop(ms->fdt, name, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", QCOM_DSP_GPT_IRQ, 0);
|
||||
qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0,
|
||||
qcom_dsp_memmap[QCOM_DSP_GPT].base,
|
||||
qcom_dsp_memmap[QCOM_DSP_GPT].size);
|
||||
}
|
||||
|
||||
static void qcom_dsp_fdt_add_memory(MachineState *ms)
|
||||
{
|
||||
hwaddr kernel_addr = qcom_dsp_info(ms)->kernel_addr;
|
||||
hwaddr ram_end = qcom_dsp_info(ms)->cfg->ddr_base + ms->ram_size;
|
||||
hwaddr size = MIN(ram_end - kernel_addr, QCOM_DSP_MAX_KERNEL_RAM);
|
||||
g_autofree char *nodename = g_strdup_printf("/memory@%" HWADDR_PRIx,
|
||||
kernel_addr);
|
||||
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, kernel_addr,
|
||||
size);
|
||||
}
|
||||
|
||||
static uint64_t qcom_dsp_kernel_translate(void *opaque, uint64_t addr)
|
||||
{
|
||||
return addr + qcom_dsp_info(MACHINE(opaque))->kernel_addr;
|
||||
}
|
||||
|
||||
static uint64_t qcom_dsp_load_kernel(MachineState *ms, bool through_firmware,
|
||||
hwaddr *image_high)
|
||||
{
|
||||
return hex_board_load_elf(ms->kernel_filename,
|
||||
through_firmware ? qcom_dsp_kernel_translate
|
||||
: NULL,
|
||||
ms, image_high);
|
||||
}
|
||||
|
||||
static uint64_t qcom_dsp_load_firmware(QcomDspMachineState *qms)
|
||||
{
|
||||
return hex_board_load_elf(qms->firmware_path, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Place the FDT after the kernel image, inside the RAM window the kernel
|
||||
* maps, and the initrd after that.
|
||||
*/
|
||||
static void qcom_dsp_load_initrd(QcomDspMachineState *qms)
|
||||
{
|
||||
MachineState *ms = MACHINE(qms);
|
||||
hwaddr start = qms->fdt_addr + 4 * MiB;
|
||||
hwaddr ram_end = qcom_dsp_info(ms)->cfg->ddr_base + ms->ram_size;
|
||||
hwaddr available;
|
||||
ssize_t size;
|
||||
|
||||
available = qms->fdt_addr < ram_end ? ram_end - qms->fdt_addr : 0;
|
||||
if (qms->fdt_size > available) {
|
||||
error_report("no room for the FDT (size 0x%x): only 0x%" HWADDR_PRIx
|
||||
" bytes available at 0x%" HWADDR_PRIx,
|
||||
qms->fdt_size, available, qms->fdt_addr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!ms->initrd_filename) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (start >= ram_end) {
|
||||
error_report("no room for the initrd: RAM ends at 0x%" HWADDR_PRIx
|
||||
" but the initrd would start at 0x%" HWADDR_PRIx,
|
||||
ram_end, start);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
size = load_image_targphys_as(ms->initrd_filename, start, ram_end - start,
|
||||
&address_space_memory, &error_fatal);
|
||||
|
||||
qemu_fdt_setprop_u64(ms->fdt, "/chosen", "linux,initrd-start", start);
|
||||
qemu_fdt_setprop_u64(ms->fdt, "/chosen", "linux,initrd-end", start + size);
|
||||
}
|
||||
|
||||
/*
|
||||
* A boot stub that passes the FDT address to the firmware in r1:r0, then
|
||||
* jumps to the firmware's entry point.
|
||||
*/
|
||||
static uint64_t qcom_dsp_setup_boot_stub(QcomDspMachineState *qms,
|
||||
uint64_t firmware_entry)
|
||||
{
|
||||
hwaddr bootl_base = qcom_dsp_memmap[QCOM_DSP_BOOT].base;
|
||||
uint32_t stub[ARRAY_SIZE(bootloader)];
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(stub); i++) {
|
||||
stub[i] = cpu_to_le32(bootloader[i]);
|
||||
}
|
||||
stub[FDT_LO] = cpu_to_le32(extract64(qms->fdt_addr, 0, 32));
|
||||
stub[FDT_HI] = cpu_to_le32(extract64(qms->fdt_addr, 32, 32));
|
||||
stub[ENTRY_ADDR] = cpu_to_le32(extract64(firmware_entry, 0, 32));
|
||||
|
||||
g_assert(sizeof(stub) <= qcom_dsp_memmap[QCOM_DSP_BOOT].size);
|
||||
rom_add_blob_fixed_as("bootloader", stub, sizeof(stub), bootl_base,
|
||||
&address_space_memory);
|
||||
|
||||
return bootl_base;
|
||||
}
|
||||
|
||||
/* Reject boot options that do not make sense together, and find -bios. */
|
||||
static void qcom_dsp_check_boot_options(QcomDspMachineState *qms)
|
||||
{
|
||||
MachineState *ms = MACHINE(qms);
|
||||
hwaddr ddr_base = qcom_dsp_info(ms)->cfg->ddr_base;
|
||||
hwaddr kernel_addr = qcom_dsp_info(ms)->kernel_addr;
|
||||
|
||||
if (ms->firmware) {
|
||||
qms->firmware_path = qemu_find_file(QEMU_FILE_TYPE_BIOS, ms->firmware);
|
||||
if (!qms->firmware_path) {
|
||||
error_report("Could not find firmware '%s'", ms->firmware);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (ms->initrd_filename && !(ms->kernel_filename && qms->firmware_path)) {
|
||||
error_report("-initrd needs both -kernel and the H2 loadlinux "
|
||||
"firmware given with -bios");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ms->kernel_filename && qms->firmware_path &&
|
||||
(ddr_base > qcom_dsp_memmap[QCOM_DSP_BOOT].base ||
|
||||
ddr_base + ms->ram_size <= kernel_addr)) {
|
||||
error_report("RAM (%" PRIu64 " MiB at 0x%" HWADDR_PRIx ") is too "
|
||||
"small: the kernel is loaded at 0x%" HWADDR_PRIx,
|
||||
ms->ram_size / MiB, ddr_base, kernel_addr);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Load what -bios and -kernel name and return where CPU 0 starts, if known. */
|
||||
static bool qcom_dsp_load_images(QcomDspMachineState *qms, uint64_t *start)
|
||||
{
|
||||
MachineState *ms = MACHINE(qms);
|
||||
hwaddr image_high = 0;
|
||||
|
||||
if (ms->kernel_filename && qms->firmware_path) {
|
||||
uint64_t firmware_entry = qcom_dsp_load_firmware(qms);
|
||||
|
||||
qcom_dsp_load_kernel(ms, true, &image_high);
|
||||
qms->fdt_addr = QEMU_ALIGN_UP(image_high + 16 * MiB, 4 * MiB);
|
||||
qcom_dsp_load_initrd(qms);
|
||||
*start = qcom_dsp_setup_boot_stub(qms, firmware_entry);
|
||||
return true;
|
||||
}
|
||||
if (ms->kernel_filename) {
|
||||
*start = qcom_dsp_load_kernel(ms, false, &image_high);
|
||||
return true;
|
||||
}
|
||||
if (qms->firmware_path) {
|
||||
*start = qcom_dsp_load_firmware(qms);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void qcom_dsp_init(MachineState *ms)
|
||||
{
|
||||
QcomDspMachineState *qms = QCOM_DSP_MACHINE(ms);
|
||||
HexagonCommonMachineState *hms = HEXAGON_COMMON_MACHINE(ms);
|
||||
const QcomDspMachineInfo *info = qcom_dsp_info(ms);
|
||||
int32_t l2vic_phandle;
|
||||
uint64_t start = 0;
|
||||
bool have_start;
|
||||
|
||||
qcom_dsp_check_boot_options(qms);
|
||||
qcom_dsp_create_fdt(qms);
|
||||
qemu_fdt_setprop_string(ms->fdt, "/chosen", "bootargs", ms->kernel_cmdline);
|
||||
|
||||
hex_subsys_create(hms, info->cfg, info->rev);
|
||||
hex_board_create_tcm(info->cfg, &qms->tcm);
|
||||
|
||||
hex_board_fdt_add_hvx(ms, info->cfg);
|
||||
l2vic_phandle = hex_board_fdt_add_l2vic(ms, info->cfg);
|
||||
qcom_dsp_fdt_add_gpt(ms);
|
||||
/* loadlinux gives the kernel a virtual CPU for every thread that runs. */
|
||||
hex_board_fdt_add_cpus(ms);
|
||||
if (ms->kernel_filename && qms->firmware_path) {
|
||||
qcom_dsp_fdt_add_memory(ms);
|
||||
}
|
||||
hex_board_create_uart(ms, qcom_dsp_memmap[QCOM_DSP_UART0].base,
|
||||
qcom_dsp_memmap[QCOM_DSP_UART0].size,
|
||||
QCOM_DSP_UART0_IRQ, l2vic_phandle);
|
||||
hex_board_create_virtio(ms, qcom_dsp_memmap[QCOM_DSP_VIRTIO].base,
|
||||
qcom_dsp_memmap[QCOM_DSP_VIRTIO].size,
|
||||
QCOM_DSP_VIRTIO_IRQ, QCOM_DSP_VIRTIO_COUNT,
|
||||
l2vic_phandle);
|
||||
qcom_dsp_add_l2_ecc_regs(qms, info);
|
||||
if (info->init_devices) {
|
||||
info->init_devices(ms);
|
||||
}
|
||||
|
||||
if (ms->dtb) {
|
||||
g_free(ms->fdt);
|
||||
ms->fdt = load_device_tree(ms->dtb, &qms->fdt_size);
|
||||
if (!ms->fdt) {
|
||||
error_report("could not load device tree '%s'", ms->dtb);
|
||||
exit(1);
|
||||
}
|
||||
if (ms->kernel_cmdline && *ms->kernel_cmdline) {
|
||||
qemu_fdt_setprop_string(ms->fdt, "/chosen", "bootargs",
|
||||
ms->kernel_cmdline);
|
||||
}
|
||||
}
|
||||
|
||||
have_start = qcom_dsp_load_images(qms, &start);
|
||||
hex_board_create_cpus(ms, have_start, start);
|
||||
|
||||
if (ms->kernel_filename && qms->firmware_path) {
|
||||
hex_board_load_fdt(ms, qms->fdt_size, qms->fdt_addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void qcom_dsp_base_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->init = qcom_dsp_init;
|
||||
mc->default_ram_size = 1 * GiB;
|
||||
mc->is_default = false;
|
||||
mc->block_default_type = IF_VIRTIO;
|
||||
mc->no_cdrom = true;
|
||||
mc->no_floppy = true;
|
||||
mc->no_parallel = true;
|
||||
mc->numa_mem_supported = false;
|
||||
}
|
||||
|
||||
void qcom_dsp_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
QcomDspMachineClass *qc = QCOM_DSP_MACHINE_CLASS(oc);
|
||||
const QcomDspMachineInfo *info = data;
|
||||
|
||||
qc->info = info;
|
||||
mc->desc = info->desc;
|
||||
mc->default_cpu_type = info->cpu_type;
|
||||
mc->default_cpus = info->cpus;
|
||||
mc->max_cpus = info->cpus;
|
||||
}
|
||||
|
||||
static const TypeInfo qcom_dsp_types[] = {
|
||||
{
|
||||
.name = TYPE_QCOM_DSP_MACHINE,
|
||||
.parent = TYPE_HEXAGON_COMMON_MACHINE,
|
||||
.instance_size = sizeof(QcomDspMachineState),
|
||||
.class_size = sizeof(QcomDspMachineClass),
|
||||
.class_init = qcom_dsp_base_class_init,
|
||||
.abstract = true,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(qcom_dsp_types)
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* QCS6490 CDSP machine.
|
||||
*
|
||||
* Models the Hexagon v68 CDSP subsystem of the QCS6490/SM7325.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/core/boards.h"
|
||||
#include "hw/hexagon/hexagon.h"
|
||||
#include "hw/hexagon/qcom_dsp.h"
|
||||
#include "hw/misc/qcom-qdsp6ss-clk.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "qapi/error.h"
|
||||
#include "system/address-spaces.h"
|
||||
#include "target/hexagon/cpu.h"
|
||||
|
||||
#include "machine_cfg_qcs6490_cdsp.h.inc"
|
||||
|
||||
#define TYPE_QCS6490_CDSP_MACHINE MACHINE_TYPE_NAME("qcs6490-cdsp")
|
||||
|
||||
#define QCS6490_CFGSPACE_BASE 0x09990000
|
||||
#define QCS6490_CFGSPACE_SIZE 0x00070000
|
||||
|
||||
static const QcomDspRegion qcs6490_regions[] = {
|
||||
{ "ss-csr", 0x0a380000, 0x10000 },
|
||||
};
|
||||
|
||||
static void qcs6490_cdsp_init_devices(MachineState *ms)
|
||||
{
|
||||
MemoryRegion *cfgspace = g_new(MemoryRegion, 1);
|
||||
|
||||
memory_region_init_ram(cfgspace, NULL, "cfgspace.ram",
|
||||
QCS6490_CFGSPACE_SIZE, &error_fatal);
|
||||
memory_region_add_subregion_overlap(get_system_memory(),
|
||||
QCS6490_CFGSPACE_BASE, cfgspace, -1);
|
||||
qcom_dsp_add_regions(ms, qcs6490_regions, ARRAY_SIZE(qcs6490_regions));
|
||||
qcom_dsp_add_device(TYPE_QCOM_LUCID_PLL, 0x0a001000);
|
||||
qcom_dsp_add_device(TYPE_QCOM_LUCID_PLL, 0x0a340000);
|
||||
qcom_dsp_add_device(TYPE_QCOM_RCG, 0x0a341000);
|
||||
}
|
||||
|
||||
static const QcomDspMachineInfo qcs6490_cdsp_info = {
|
||||
.desc = "QCS6490 CDSP",
|
||||
.cpu_type = HEXAGON_CPU_TYPE_NAME("v68"),
|
||||
.cpus = 6,
|
||||
.rev = v68_qcs6490_rev,
|
||||
.cfg = &qcs6490_cdsp,
|
||||
.kernel_addr = 0xa1000000,
|
||||
.init_devices = qcs6490_cdsp_init_devices,
|
||||
};
|
||||
|
||||
static const TypeInfo qcs6490_cdsp_types[] = {
|
||||
{
|
||||
.name = TYPE_QCS6490_CDSP_MACHINE,
|
||||
.parent = TYPE_QCOM_DSP_MACHINE,
|
||||
.class_init = qcom_dsp_class_init,
|
||||
.class_data = &qcs6490_cdsp_info,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(qcs6490_cdsp_types)
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Models the v73 CDSP0 of the SA8775P.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/core/boards.h"
|
||||
#include "hw/hexagon/hexagon.h"
|
||||
#include "hw/hexagon/qcom_dsp.h"
|
||||
#include "target/hexagon/cpu.h"
|
||||
|
||||
#include "machine_cfg_sa8775_cdsp0.h.inc"
|
||||
|
||||
#define TYPE_SA8775P_CDSP_MACHINE MACHINE_TYPE_NAME("sa8775p-cdsp")
|
||||
|
||||
static const QcomDspRegion sa8775p_cdsp_regions[] = {
|
||||
{ "tcsr", 0x01fc0000 },
|
||||
{ "hwkm-prng", 0x010da000 },
|
||||
{ "gdscr", 0x00151000 },
|
||||
{ "pll0", 0x26340000 },
|
||||
{ "pll1", 0x26000000 },
|
||||
{ "clkctl", 0x26348000 },
|
||||
{ "ccswi", 0x26008000 },
|
||||
{ "rsc", 0x260a4000 },
|
||||
};
|
||||
|
||||
static void sa8775p_cdsp_init_devices(MachineState *ms)
|
||||
{
|
||||
qcom_dsp_add_regions(ms, sa8775p_cdsp_regions,
|
||||
ARRAY_SIZE(sa8775p_cdsp_regions));
|
||||
|
||||
qcom_soc_add_qup_geni_ports("sa8775p", 0x00b80000, 1, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sa8775p", 0x00880000, 7, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sa8775p", 0x00980000, 7, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sa8775p", 0x00a80000, 7, 0x4000);
|
||||
}
|
||||
|
||||
static const QcomDspMachineInfo sa8775p_cdsp_info = {
|
||||
.desc = "SA8775P CDSP0",
|
||||
.cpu_type = HEXAGON_CPU_TYPE_NAME("v73"),
|
||||
.cpus = 6,
|
||||
.rev = v73_rev,
|
||||
.cfg = &SA8775P_cdsp0,
|
||||
.kernel_addr = 0xa0000000,
|
||||
.init_devices = sa8775p_cdsp_init_devices,
|
||||
};
|
||||
|
||||
static const TypeInfo sa8775p_cdsp_types[] = {
|
||||
{
|
||||
.name = TYPE_SA8775P_CDSP_MACHINE,
|
||||
.parent = TYPE_QCOM_DSP_MACHINE,
|
||||
.class_init = qcom_dsp_class_init,
|
||||
.class_data = &sa8775p_cdsp_info,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(sa8775p_cdsp_types)
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Models the v81 NSP0 of the SA8797P.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/core/boards.h"
|
||||
#include "hw/hexagon/hexagon.h"
|
||||
#include "hw/hexagon/qcom_dsp.h"
|
||||
#include "target/hexagon/cpu.h"
|
||||
|
||||
#include "machine_cfg_sa8797p_nsp0.h.inc"
|
||||
|
||||
#define TYPE_SA8797P_NSP0_MACHINE MACHINE_TYPE_NAME("sa8797p-nsp0")
|
||||
|
||||
static const QcomDspRegion sa8797p_nsp0_regions[] = {
|
||||
{ "gcc", 0x00100000, 0x200000 },
|
||||
{ "ne-gcc", 0x08900000, 0x100000 },
|
||||
{ "se-gcc", 0x08a00000, 0x100000 },
|
||||
{ "nw-gcc", 0x08b00000, 0x100000 },
|
||||
{ "nsp-cc", 0x320c0000, 0x10000 },
|
||||
{ "qfprom", 0x360c8000, 0x8000 },
|
||||
{ "q6-cc", 0x32340000, 0x11000 },
|
||||
{ "pinctrl", 0x0f100000, 0x0f00000 },
|
||||
{ "ipcc", 0x09000000 },
|
||||
{ "ipcc-legacy", 0x32380000 },
|
||||
{ "stmtrace", 0x16000000, 0x1000000 },
|
||||
{ "tpdm", 0x117c0000, 0x2000 },
|
||||
{ "tpdm", 0x117c5000, 0x2000 },
|
||||
{ "tpda", 0x117c8000 },
|
||||
};
|
||||
|
||||
static void sa8797p_nsp0_init_devices(MachineState *ms)
|
||||
{
|
||||
qcom_dsp_add_regions(ms, sa8797p_nsp0_regions,
|
||||
ARRAY_SIZE(sa8797p_nsp0_regions));
|
||||
|
||||
qcom_soc_add_qup_geni_ports("sa8797p", 0x09b86000, 5, 0x2000);
|
||||
qcom_soc_add_qup_geni_ports("sa8797p", 0x09c06000, 5, 0x2000);
|
||||
qcom_soc_add_qup_geni_ports("sa8797p", 0x00c80000, 1, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sa8797p", 0x00a80000, 7, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sa8797p", 0x00980000, 7, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sa8797p", 0x00880000, 7, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sa8797p", 0x198880000, 6, 0x4000);
|
||||
}
|
||||
|
||||
static const QcomDspMachineInfo sa8797p_nsp0_info = {
|
||||
.desc = "SA8797P NSP",
|
||||
.cpu_type = HEXAGON_CPU_TYPE_NAME("v81"),
|
||||
.cpus = 12,
|
||||
.rev = v81_rev,
|
||||
.cfg = &sa8797p_nsp0,
|
||||
.kernel_addr = 0xa0000000,
|
||||
.init_devices = sa8797p_nsp0_init_devices,
|
||||
};
|
||||
|
||||
static const TypeInfo sa8797p_nsp0_types[] = {
|
||||
{
|
||||
.name = TYPE_SA8797P_NSP0_MACHINE,
|
||||
.parent = TYPE_QCOM_DSP_MACHINE,
|
||||
.class_init = qcom_dsp_class_init,
|
||||
.class_data = &sa8797p_nsp0_info,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(sa8797p_nsp0_types)
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Models the Hexagon v81 NSP of the SC8480XP.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/core/boards.h"
|
||||
#include "hw/hexagon/hexagon.h"
|
||||
#include "hw/hexagon/qcom_dsp.h"
|
||||
#include "target/hexagon/cpu.h"
|
||||
|
||||
#include "machine_cfg_sc8480xp_nsp0.h.inc"
|
||||
|
||||
#define TYPE_SC8480XP_NSP0_MACHINE MACHINE_TYPE_NAME("sc8480xp-nsp0")
|
||||
|
||||
static const QcomDspRegion sc8480xp_nsp0_regions[] = {
|
||||
{ "tcsr", 0x01f40000, 0xc0000 },
|
||||
{ "hwkm-prng", 0x010ca000 },
|
||||
{ "pll", 0x32340000 },
|
||||
{ "clkctl", 0x32344000, 0x4000 },
|
||||
{ "turing-cc", 0x32008000, 0x14000 },
|
||||
{ "rsc", 0x320a4000 },
|
||||
{ "dsp-rsc", 0x323c0000 },
|
||||
{ "ipcc", 0x03e00000 },
|
||||
{ "ipcc-legacy", 0x32380000 },
|
||||
{ "pinctrl", 0x0f100000, 0x0f00000 },
|
||||
{ "gcc", 0x00100000, 0x200000 },
|
||||
{ "turing-cc-pll", 0x32000000, 0x8000 },
|
||||
{ "q6-acd", 0x32350000, 0x800 },
|
||||
{ "hmx-pll", 0x32348000 },
|
||||
{ "hmx-cc", 0x3234c000, 0x4000 },
|
||||
{ "hmx-acd", 0x32350800, 0x800 },
|
||||
{ "stmtrace", 0x16000000, 0x1000000 },
|
||||
{ "stmcfg", 0x10002000 },
|
||||
{ "etb", 0x11c05000 },
|
||||
{ "tpdm", 0x11181000, 0x6000 },
|
||||
{ "tpda", 0x11188000 },
|
||||
{ "funnel", 0x10041000 },
|
||||
{ "funnel", 0x11c04000 },
|
||||
{ "llcc", 0x20400000, 0x100000 },
|
||||
{ "llcc", 0x20600000, 0x100000 },
|
||||
{ "llcc", 0x21800000, 0x100000 },
|
||||
{ "llcc", 0x21a00000, 0x100000 },
|
||||
{ "llcc", 0x21c00000, 0x100000 },
|
||||
{ "llcc", 0x21e00000, 0x100000 },
|
||||
{ "llcc", 0x22800000, 0x100000 },
|
||||
{ "llcc", 0x22a00000, 0x100000 },
|
||||
{ "llcc", 0x22c00000, 0x100000 },
|
||||
{ "llcc", 0x22e00000, 0x100000 },
|
||||
{ "llcc", 0x23800000, 0x100000 },
|
||||
{ "llcc", 0x23a00000, 0x100000 },
|
||||
{ "llcc", 0x23c00000, 0x100000 },
|
||||
{ "llcc", 0x23e00000, 0x100000 },
|
||||
{ "ddrss", 0x20280000, 0x400 },
|
||||
};
|
||||
|
||||
static void sc8480xp_nsp0_init_devices(MachineState *ms)
|
||||
{
|
||||
qcom_dsp_add_regions(ms, sc8480xp_nsp0_regions,
|
||||
ARRAY_SIZE(sc8480xp_nsp0_regions));
|
||||
|
||||
qcom_soc_add_qup_geni_ports("sc8480xp", 0x07980000, 15, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sc8480xp", 0x00b80000, 8, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sc8480xp", 0x00a80000, 8, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sc8480xp", 0x00980000, 2, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sc8480xp", 0x00880000, 8, 0x4000);
|
||||
}
|
||||
|
||||
static const QcomDspMachineInfo sc8480xp_nsp0_info = {
|
||||
.desc = "SC8480XP NSP",
|
||||
.cpu_type = HEXAGON_CPU_TYPE_NAME("v81"),
|
||||
.cpus = 12,
|
||||
.rev = v81_sc8480xp_rev,
|
||||
.cfg = &sc8480xp_nsp0,
|
||||
.kernel_addr = 0xa0000000,
|
||||
.init_devices = sc8480xp_nsp0_init_devices,
|
||||
};
|
||||
|
||||
static const TypeInfo sc8480xp_nsp0_types[] = {
|
||||
{
|
||||
.name = TYPE_SC8480XP_NSP0_MACHINE,
|
||||
.parent = TYPE_QCOM_DSP_MACHINE,
|
||||
.class_init = qcom_dsp_class_init,
|
||||
.class_data = &sc8480xp_nsp0_info,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(sc8480xp_nsp0_types)
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* sm8975-nsp machine.
|
||||
*
|
||||
* Models the Hexagon v85 NSP of the SM8975.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/core/boards.h"
|
||||
#include "hw/hexagon/hexagon.h"
|
||||
#include "hw/hexagon/qcom_dsp.h"
|
||||
#include "target/hexagon/cpu.h"
|
||||
|
||||
#include "machine_cfg_sm8975_nsp.h.inc"
|
||||
|
||||
#define TYPE_SM8975_NSP_MACHINE MACHINE_TYPE_NAME("sm8975-nsp")
|
||||
|
||||
static const QcomDspRegion sm8975_nsp_regions[] = {
|
||||
{ "dspss-pub", 0x26300000, 0x10000 },
|
||||
{ "wdog", 0x26384000 },
|
||||
{ "turing-cc", 0x26008000, 0x14000 },
|
||||
{ "pll", 0x26340000 },
|
||||
{ "clkctl", 0x26344000, 0x4000 },
|
||||
{ "compute-rsc", 0x260a4000 },
|
||||
{ "qdsp6-rsc", 0x263c0000 },
|
||||
{ "ipcc", 0x01100000 },
|
||||
{ "tcsr", 0x26080000, 0x1f000 },
|
||||
{ "turing-cc-pll", 0x26000000 },
|
||||
{ "turing-cc-pll", 0x26001000 },
|
||||
{ "turing-cc-pll", 0x26002000 },
|
||||
{ "turing-cc-pll", 0x26003000 },
|
||||
{ "turing-cc-pll", 0x26004000 },
|
||||
{ "ahb2phy", 0x26006000, 0x2000 },
|
||||
{ "ahbe-time", 0x260b7000 },
|
||||
{ "nsp-noc", 0x260c0000, 0x21280 },
|
||||
{ "ceng", 0x26260000, 0xc000 },
|
||||
{ "ceng-irq", 0x2626c000 },
|
||||
{ "ubwcd", 0x26280000, 0x10000 },
|
||||
{ "vapss", 0x262c0000, 0x40000 },
|
||||
{ "llm-isense", 0x26310000, 0x10000 },
|
||||
{ "lpm-stats", 0x26320000, 0x10000 },
|
||||
{ "mxu-pll", 0x26348000 },
|
||||
{ "acd-mnd-dcc", 0x26350000, 0x800 },
|
||||
{ "hmx-acd-mnd-dcc", 0x26350800, 0x800 },
|
||||
{ "gcc", 0x00100000, 0x200000 },
|
||||
{ "fuse", 0x221c8000 },
|
||||
{ "hmx-swman", 0x2634a000, 0x400 },
|
||||
{ "hmx-broadcast", 0x2634b000, 0x400 },
|
||||
{ "hmx-cc", 0x2634c000, 0x4000 },
|
||||
{ "ipcc-legacy", 0x26380000 },
|
||||
{ "pinctrl", 0x0f100000, 0x0f00000 },
|
||||
{ "llcc", 0x31800000, 0x200000 },
|
||||
{ "llcc", 0x31c00000, 0x200000 },
|
||||
{ "llcc", 0x32800000, 0x200000 },
|
||||
{ "llcc", 0x32c00000, 0x200000 },
|
||||
{ "llcc", 0x34800000, 0x200000 },
|
||||
{ "llcc", 0x34c00000, 0x200000 },
|
||||
{ "stmtrace", 0x16000000, 0x1000000 },
|
||||
{ "stmcfg", 0x10002000 },
|
||||
{ "etb", 0x11305000 },
|
||||
{ "tpdm", 0x11181000, 0x2000 },
|
||||
{ "tpdm", 0x11185000, 0x2000 },
|
||||
{ "funnel", 0x10041000 },
|
||||
{ "funnel", 0x11304000 },
|
||||
{ "tpda", 0x11188000 },
|
||||
};
|
||||
|
||||
static void sm8975_nsp_init_devices(MachineState *ms)
|
||||
{
|
||||
qcom_dsp_add_regions(ms, sm8975_nsp_regions,
|
||||
ARRAY_SIZE(sm8975_nsp_regions));
|
||||
|
||||
qcom_soc_add_qup_geni_ports("sm8975", 0x08180000, 8, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sm8975", 0x08280000, 8, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sm8975", 0x01980000, 6, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sm8975", 0x01a80000, 5, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sm8975", 0x00a80000, 8, 0x4000);
|
||||
qcom_soc_add_qup_geni_ports("sm8975", 0x00880000, 5, 0x4000);
|
||||
}
|
||||
|
||||
static const QcomDspMachineInfo sm8975_nsp_info = {
|
||||
.desc = "SM8975 NSP",
|
||||
.cpu_type = HEXAGON_CPU_TYPE_NAME("v85"),
|
||||
.cpus = 12,
|
||||
.rev = v85_sm8975_rev,
|
||||
.cfg = &sm8975_nsp,
|
||||
.kernel_addr = 0xa0000000,
|
||||
.init_devices = sm8975_nsp_init_devices,
|
||||
};
|
||||
|
||||
static const TypeInfo sm8975_nsp_types[] = {
|
||||
{
|
||||
.name = TYPE_SM8975_NSP_MACHINE,
|
||||
.parent = TYPE_QCOM_DSP_MACHINE,
|
||||
.class_init = qcom_dsp_class_init,
|
||||
.class_data = &sm8975_nsp_info,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(sm8975_nsp_types)
|
||||
+25
-282
@@ -8,26 +8,15 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hexagon/virt.h"
|
||||
#include "elf.h"
|
||||
#include "hw/char/pl011.h"
|
||||
#include "hw/core/clock.h"
|
||||
#include "hw/core/sysbus-fdt.h"
|
||||
#include "hw/hexagon/hexagon.h"
|
||||
#include "hw/hexagon/hex-board.h"
|
||||
#include "hw/hexagon/hex-subsys.h"
|
||||
#include "hw/core/loader.h"
|
||||
#include "hw/core/qdev-properties.h"
|
||||
#include "hw/core/qdev-clock.h"
|
||||
#include "hw/core/register.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "qemu/target-info.h"
|
||||
#include "qemu/units.h"
|
||||
#include "machine_cfg_v68n_1024.h.inc"
|
||||
#include "system/address-spaces.h"
|
||||
#include "system/device_tree.h"
|
||||
#include "system/reset.h"
|
||||
#include "system/system.h"
|
||||
#include <libfdt.h>
|
||||
|
||||
enum {
|
||||
VIRT_UART0,
|
||||
@@ -49,222 +38,9 @@ static const MemMapEntry base_memmap[] = {
|
||||
};
|
||||
|
||||
|
||||
static void create_fdt(HexagonVirtMachineState *vms)
|
||||
{
|
||||
MachineState *ms = MACHINE(vms);
|
||||
void *fdt = create_device_tree(&vms->fdt_size);
|
||||
uint8_t rng_seed[32];
|
||||
|
||||
if (!fdt) {
|
||||
error_report("create_device_tree() failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ms->fdt = fdt;
|
||||
|
||||
qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
|
||||
qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1);
|
||||
qemu_fdt_setprop_string(fdt, "/", "model", "hexagon-virt,qemu");
|
||||
qemu_fdt_setprop_string(fdt, "/", "compatible", "qcom,sm8150");
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/soc");
|
||||
qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
|
||||
qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x1);
|
||||
qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/chosen");
|
||||
qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
|
||||
qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
|
||||
}
|
||||
|
||||
static int32_t fdt_add_l2vic(HexagonVirtMachineState *vms,
|
||||
const struct hexagon_machine_config *m_cfg)
|
||||
{
|
||||
MachineState *ms = MACHINE(vms);
|
||||
int32_t l2vic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
||||
char *nodename = g_strdup_printf("/soc/interrupt-controller@%x",
|
||||
m_cfg->l2vic_base);
|
||||
const char compat[] = "qcom,h2-pic\0hvm-pic";
|
||||
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/soc", "interrupt-parent", l2vic_phandle);
|
||||
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x0);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 0x1);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0,
|
||||
m_cfg->l2vic_base, m_cfg->l2vic_size);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", l2vic_phandle);
|
||||
|
||||
g_free(nodename);
|
||||
return l2vic_phandle;
|
||||
}
|
||||
|
||||
static void fdt_add_hvx(HexagonVirtMachineState *vms,
|
||||
const struct hexagon_machine_config *m_cfg)
|
||||
{
|
||||
const MachineState *ms = MACHINE(vms);
|
||||
uint32_t vtcm_size_bytes = m_cfg->cfgtable.vtcm_size_kb * 1024;
|
||||
if (vtcm_size_bytes > 0) {
|
||||
qemu_fdt_add_subnode(ms->fdt, "/soc/vtcm");
|
||||
qemu_fdt_setprop_string(ms->fdt, "/soc/vtcm", "compatible",
|
||||
"qcom,hexagon_vtcm");
|
||||
|
||||
assert(sizeof(m_cfg->cfgtable.vtcm_base) == sizeof(uint32_t));
|
||||
qemu_fdt_setprop_cells(ms->fdt, "/soc/vtcm", "reg", 0,
|
||||
m_cfg->cfgtable.vtcm_base << 16,
|
||||
vtcm_size_bytes);
|
||||
}
|
||||
|
||||
if (m_cfg->cfgtable.ext_contexts > 0) {
|
||||
qemu_fdt_add_subnode(ms->fdt, "/soc/hvx");
|
||||
qemu_fdt_setprop_string(ms->fdt, "/soc/hvx", "compatible",
|
||||
"qcom,hexagon-hvx");
|
||||
qemu_fdt_setprop_cells(ms->fdt, "/soc/hvx", "qcom,hvx-max-ctxts",
|
||||
m_cfg->cfgtable.ext_contexts);
|
||||
qemu_fdt_setprop_cells(ms->fdt, "/soc/hvx", "qcom,hvx-vlength",
|
||||
m_cfg->cfgtable.hvx_vec_log_length);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t fdt_add_clocks(const HexagonVirtMachineState *vms)
|
||||
{
|
||||
MachineState *ms = MACHINE(vms);
|
||||
int32_t clk_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
||||
|
||||
qemu_fdt_add_subnode(ms->fdt, "/apb-pclk");
|
||||
qemu_fdt_setprop_string(ms->fdt, "/apb-pclk", "compatible", "fixed-clock");
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "#clock-cells", 0x0);
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "clock-frequency", 24000000);
|
||||
qemu_fdt_setprop_string(ms->fdt, "/apb-pclk", "clock-output-names",
|
||||
"clk24mhz");
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "phandle", clk_phandle);
|
||||
|
||||
return clk_phandle;
|
||||
}
|
||||
|
||||
static void fdt_add_uart(const HexagonVirtMachineState *vms, int uart,
|
||||
int32_t clk_phandle, int32_t l2vic_phandle)
|
||||
{
|
||||
char *nodename;
|
||||
hwaddr base = base_memmap[uart].base;
|
||||
hwaddr size = base_memmap[uart].size;
|
||||
assert(uart == 0);
|
||||
const char compat[] = "arm,pl011\0arm,primecell";
|
||||
const char clocknames[] = "uartclk\0apb_pclk";
|
||||
MachineState *ms = MACHINE(vms);
|
||||
DeviceState *dev;
|
||||
SysBusDevice *s;
|
||||
|
||||
dev = qdev_new(TYPE_PL011);
|
||||
s = SYS_BUS_DEVICE(dev);
|
||||
qdev_prop_set_chr(dev, "chardev", serial_hd(0));
|
||||
qdev_connect_clock_in(dev, "clk", vms->apb_clk);
|
||||
sysbus_realize_and_unref(s, &error_fatal);
|
||||
sysbus_mmio_map(s, 0, base);
|
||||
sysbus_connect_irq(s, 0,
|
||||
qdev_get_gpio_in(vms->parent_obj.l2vic, VIRT_UART0_IRQ));
|
||||
|
||||
nodename = g_strdup_printf("/pl011@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
|
||||
/* Note that we can't use setprop_string because of the embedded NUL */
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, size);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", VIRT_UART0_IRQ);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
|
||||
l2vic_phandle);
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "clocks", clk_phandle,
|
||||
clk_phandle);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "clock-names", clocknames,
|
||||
sizeof(clocknames));
|
||||
|
||||
qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
|
||||
qemu_fdt_add_subnode(ms->fdt, "/aliases");
|
||||
qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", nodename);
|
||||
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
static void fdt_add_cpu_nodes(const HexagonVirtMachineState *vms)
|
||||
{
|
||||
MachineState *ms = MACHINE(vms);
|
||||
qemu_fdt_add_subnode(ms->fdt, "/cpus");
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
|
||||
|
||||
/* cpu nodes */
|
||||
for (int num = ms->smp.cpus - 1; num >= 0; num--) {
|
||||
char *nodename = g_strdup_printf("/cpus/cpu@%d", num);
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
|
||||
qemu_fdt_alloc_phandle(ms->fdt));
|
||||
g_free(nodename);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_virtio_devices(HexagonVirtMachineState *vms,
|
||||
int32_t l2vic_phandle)
|
||||
{
|
||||
MachineState *ms = MACHINE(vms);
|
||||
hwaddr size = base_memmap[VIRT_MMIO].size;
|
||||
|
||||
for (int i = 0; i < VIRTIO_DEV_COUNT; i++) {
|
||||
int irq = VIRTIO_IRQ_BASE + i;
|
||||
hwaddr base = base_memmap[VIRT_MMIO].base + i * size;
|
||||
char *nodename = g_strdup_printf("/soc/virtio_mmio@%" PRIx64, base);
|
||||
DeviceState *dev = qdev_new("virtio-mmio");
|
||||
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
||||
|
||||
object_property_add_child(OBJECT(MACHINE(vms)), "virtio-mmio[*]",
|
||||
OBJECT(dev));
|
||||
sysbus_realize_and_unref(s, &error_fatal);
|
||||
sysbus_mmio_map(s, 0, base);
|
||||
sysbus_connect_irq(s, 0,
|
||||
qdev_get_gpio_in(vms->parent_obj.l2vic, irq));
|
||||
vms->virtio_mmio[i] = dev;
|
||||
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
||||
"virtio,mmio");
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, size);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", irq);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
|
||||
l2vic_phandle);
|
||||
|
||||
g_free(nodename);
|
||||
}
|
||||
}
|
||||
|
||||
void hexagon_load_fdt(const HexagonVirtMachineState *vms)
|
||||
{
|
||||
MachineState *ms = MACHINE(vms);
|
||||
hwaddr fdt_addr = base_memmap[VIRT_FDT].base;
|
||||
uint32_t fdtsize = vms->fdt_size;
|
||||
|
||||
g_assert(fdtsize <= base_memmap[VIRT_FDT].size);
|
||||
/* copy in the device tree */
|
||||
rom_add_blob_fixed_as("fdt", ms->fdt, fdtsize, fdt_addr,
|
||||
&address_space_memory);
|
||||
qemu_register_reset_nosnapshotload(
|
||||
qemu_fdt_randomize_seeds,
|
||||
rom_ptr_for_as(&address_space_memory, fdt_addr, fdtsize));
|
||||
}
|
||||
|
||||
static uint64_t load_kernel(const HexagonVirtMachineState *vms)
|
||||
{
|
||||
MachineState *ms = MACHINE(vms);
|
||||
uint64_t entry = 0;
|
||||
if (load_elf_ram_sym(ms->kernel_filename, NULL, NULL, NULL, &entry, NULL,
|
||||
NULL, NULL, 0, EM_HEXAGON, 0, 0, &address_space_memory,
|
||||
false, NULL) > 0) {
|
||||
return entry;
|
||||
}
|
||||
error_report("error loading '%s'", ms->kernel_filename);
|
||||
exit(1);
|
||||
return hex_board_load_elf(MACHINE(vms)->kernel_filename, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static uint64_t load_bios(HexagonVirtMachineState *vms)
|
||||
@@ -283,75 +59,42 @@ static uint64_t load_bios(HexagonVirtMachineState *vms)
|
||||
return bios_addr; /* Return entry point at address 0x0 */
|
||||
}
|
||||
|
||||
static void do_cpu_reset(void *opaque)
|
||||
{
|
||||
HexagonCPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
cpu_reset(cs);
|
||||
}
|
||||
|
||||
static void virt_init(MachineState *ms)
|
||||
{
|
||||
HexagonVirtMachineState *vms = HEXAGON_VIRT_MACHINE(ms);
|
||||
const struct hexagon_machine_config *m_cfg = &v68n_1024;
|
||||
int32_t clk_phandle;
|
||||
int32_t l2vic_phandle;
|
||||
uint64_t start = 0;
|
||||
bool have_start = false;
|
||||
|
||||
create_fdt(vms);
|
||||
hex_board_create_fdt(ms, "hexagon-virt,qemu", "qcom,sm8150",
|
||||
&vms->fdt_size);
|
||||
qemu_fdt_setprop_string(ms->fdt, "/chosen", "bootargs", ms->kernel_cmdline);
|
||||
|
||||
vms->sys = get_system_memory();
|
||||
|
||||
/* Create APB clock for peripherals */
|
||||
vms->apb_clk = clock_new(OBJECT(ms), "apb-pclk");
|
||||
clock_set_hz(vms->apb_clk, 24000000);
|
||||
|
||||
hex_subsys_create(&vms->parent_obj, m_cfg, v68_rev);
|
||||
hex_board_create_tcm(m_cfg, &vms->tcm);
|
||||
hex_board_fdt_add_hvx(ms, m_cfg);
|
||||
|
||||
if (m_cfg->l2tcm_size) {
|
||||
memory_region_init_ram(&vms->tcm, NULL, "tcm.ram", m_cfg->l2tcm_size,
|
||||
&error_fatal);
|
||||
memory_region_add_subregion(vms->sys, m_cfg->cfgtable.l2tcm_base << 16,
|
||||
&vms->tcm);
|
||||
l2vic_phandle = hex_board_fdt_add_l2vic(ms, m_cfg);
|
||||
hex_board_create_virtio(ms, base_memmap[VIRT_MMIO].base,
|
||||
base_memmap[VIRT_MMIO].size, VIRTIO_IRQ_BASE,
|
||||
VIRTIO_DEV_COUNT, l2vic_phandle);
|
||||
|
||||
if (ms->kernel_filename) {
|
||||
start = load_kernel(vms);
|
||||
have_start = true;
|
||||
} else if (ms->firmware) {
|
||||
start = load_bios(vms);
|
||||
have_start = true;
|
||||
}
|
||||
hex_board_create_cpus(ms, have_start, start);
|
||||
|
||||
fdt_add_hvx(vms, m_cfg);
|
||||
hex_board_fdt_add_cpus(ms);
|
||||
hex_board_create_uart(ms, base_memmap[VIRT_UART0].base,
|
||||
base_memmap[VIRT_UART0].size, VIRT_UART0_IRQ,
|
||||
l2vic_phandle);
|
||||
|
||||
l2vic_phandle = fdt_add_l2vic(vms, m_cfg);
|
||||
create_virtio_devices(vms, l2vic_phandle);
|
||||
|
||||
g_autofree HexagonCPU **cpus = g_new(HexagonCPU *, ms->smp.cpus);
|
||||
|
||||
for (int i = 0; i < ms->smp.cpus; i++) {
|
||||
HexagonCPU *cpu = HEXAGON_CPU(object_new(ms->cpu_type));
|
||||
qemu_register_reset(do_cpu_reset, cpu);
|
||||
|
||||
if (i == 0) {
|
||||
if (ms->kernel_filename) {
|
||||
uint64_t entry = load_kernel(vms);
|
||||
qdev_prop_set_uint32(DEVICE(cpu), "exec-start-addr", entry);
|
||||
} else if (ms->firmware) {
|
||||
uint64_t entry = load_bios(vms);
|
||||
qdev_prop_set_uint32(DEVICE(cpu), "exec-start-addr", entry);
|
||||
}
|
||||
}
|
||||
qdev_prop_set_uint32(DEVICE(cpu), "htid", i);
|
||||
qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0));
|
||||
hex_subsys_add_cpu(&vms->parent_obj, DEVICE(cpu));
|
||||
cpus[i] = cpu;
|
||||
}
|
||||
|
||||
hex_subsys_realize_cluster(&vms->parent_obj);
|
||||
|
||||
for (int i = 0; i < ms->smp.cpus; i++) {
|
||||
hex_subsys_realize_cpu(&vms->parent_obj, DEVICE(cpus[i]), (i == 0));
|
||||
}
|
||||
|
||||
fdt_add_cpu_nodes(vms);
|
||||
clk_phandle = fdt_add_clocks(vms);
|
||||
fdt_add_uart(vms, VIRT_UART0, clk_phandle, l2vic_phandle);
|
||||
|
||||
hexagon_load_fdt(vms);
|
||||
hex_board_load_fdt(ms, vms->fdt_size, base_memmap[VIRT_FDT].base);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+21
-6
@@ -290,9 +290,20 @@ static bool l2vic_update(HexL2VICState *s, int irq)
|
||||
|
||||
static void l2vic_update_all(HexL2VICState *s)
|
||||
{
|
||||
for (int i = 0; i < L2VIC_INTERRUPT_MAX; i++) {
|
||||
if (l2vic_update(s, i)) {
|
||||
/* once vid is active, no-one else can set it until ciad */
|
||||
/* once vid is active, no-one else can set it until ciad */
|
||||
if (vid_active(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Quickly find lowest-numbered irq ready by scanning their statuses
|
||||
* range by range instead of one by one.
|
||||
*/
|
||||
for (int slice = 0; slice < SLICE_MAX; slice++) {
|
||||
uint32_t ready = s->int_pending[slice] & s->int_enable[slice];
|
||||
|
||||
if (ready) {
|
||||
l2vic_update(s, slice * 32 + ctz32(ready));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -448,12 +459,16 @@ static void l2vic_interface_update_vid_impl(HexL2VicInterface *iface,
|
||||
l2vic_update_all(s);
|
||||
}
|
||||
|
||||
static void l2vic_interface_clear_interrupt_impl(HexL2VicInterface *iface)
|
||||
static void l2vic_interface_clear_interrupt_impl(HexL2VicInterface *iface,
|
||||
uint32_t mask)
|
||||
{
|
||||
HexL2VICState *s = HEX_L2VIC(iface);
|
||||
const uint32_t size = L2VIC_INTERRUPT_MAX;
|
||||
const uint32_t active_irq = find_first_bit32(s->int_status, size);
|
||||
|
||||
if (s->vid < L2VIC_INTERRUPT_MAX) {
|
||||
clear_bit32(s->vid, s->int_status);
|
||||
/* VID group n is delivered on CPU interrupt n + 2 */
|
||||
if (active_irq != size && (mask & BIT(get_vid(s, active_irq) + 2))) {
|
||||
clear_bit32(active_irq, s->int_status);
|
||||
}
|
||||
l2vic_update_all(s);
|
||||
}
|
||||
|
||||
@@ -267,3 +267,6 @@ config SOPHGO_CV1800B_CLK
|
||||
bool
|
||||
|
||||
source macio/Kconfig
|
||||
|
||||
config QCOM_QDSP6SS_CLK
|
||||
bool
|
||||
@@ -181,3 +181,6 @@ system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c'))
|
||||
system_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c'))
|
||||
|
||||
system_ss.add(when: 'CONFIG_AXIADO_CLK', if_true: files('axiado_clk.c'))
|
||||
|
||||
# Qualcomm Hexagon DSP subsystems
|
||||
system_ss.add(when: 'CONFIG_QCOM_QDSP6SS_CLK', if_true: files('qcom-qdsp6ss-clk.c'))
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Qualcomm QDSP6SS clock blocks
|
||||
*
|
||||
* Firmware brings the DSP's PLLs up by programming them, releasing reset,
|
||||
* selecting the RUN mode and then polling for lock; it then asks the root
|
||||
* clock generator to switch over to the new clock by setting UPDATE and
|
||||
* waiting for the hardware to clear it. Neither the frequencies nor the
|
||||
* clock tree matter to the model: these devices only complete those
|
||||
* handshakes, and otherwise hold whatever is written to them.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/core/resettable.h"
|
||||
#include "hw/core/sysbus.h"
|
||||
#include "hw/misc/qcom-qdsp6ss-clk.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define QCOM_CLK_REGS_SIZE 0x1000
|
||||
#define QCOM_CLK_NUM_REGS (QCOM_CLK_REGS_SIZE / 4)
|
||||
|
||||
/* Lucid PLL registers */
|
||||
#define PLL_MODE 0x00
|
||||
#define PLL_OPMODE 0x38
|
||||
|
||||
#define PLL_MODE_OUTCTRL BIT(0)
|
||||
#define PLL_MODE_BYPASSNL BIT(1)
|
||||
#define PLL_MODE_RESET_N BIT(2)
|
||||
#define PLL_MODE_ACTIVE BIT(30)
|
||||
#define PLL_MODE_LOCK_DET BIT(31)
|
||||
|
||||
#define PLL_OPMODE_MASK 0x7
|
||||
#define PLL_OPMODE_RUN 0x1
|
||||
|
||||
/* RCG registers */
|
||||
#define RCG_CMD 0x20
|
||||
|
||||
#define RCG_CMD_UPDATE BIT(0)
|
||||
#define RCG_CMD_ROOT_EN BIT(1)
|
||||
#define RCG_CMD_ROOT_OFF BIT(31)
|
||||
|
||||
typedef struct QcomClkRegsState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
uint32_t regs[QCOM_CLK_NUM_REGS];
|
||||
} QcomClkRegsState;
|
||||
|
||||
#define TYPE_QCOM_CLK_REGS "qcom-clk-regs"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(QcomClkRegsState, QCOM_CLK_REGS)
|
||||
|
||||
static uint64_t qcom_clk_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
QcomClkRegsState *s = opaque;
|
||||
|
||||
return s->regs[offset / 4];
|
||||
}
|
||||
|
||||
static void qcom_lucid_pll_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
QcomClkRegsState *s = opaque;
|
||||
|
||||
s->regs[offset / 4] = value;
|
||||
if (offset == PLL_MODE || offset == PLL_OPMODE) {
|
||||
uint32_t mode = s->regs[PLL_MODE / 4];
|
||||
uint32_t opmode = s->regs[PLL_OPMODE / 4];
|
||||
|
||||
/* The PLL locks once it is out of reset and running */
|
||||
if ((mode & PLL_MODE_RESET_N) &&
|
||||
(opmode & PLL_OPMODE_MASK) == PLL_OPMODE_RUN) {
|
||||
mode |= PLL_MODE_LOCK_DET | PLL_MODE_ACTIVE;
|
||||
} else {
|
||||
mode &= ~(PLL_MODE_LOCK_DET | PLL_MODE_ACTIVE);
|
||||
}
|
||||
s->regs[PLL_MODE / 4] = mode;
|
||||
}
|
||||
}
|
||||
|
||||
static void qcom_rcg_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
QcomClkRegsState *s = opaque;
|
||||
|
||||
s->regs[offset / 4] = value;
|
||||
if (offset == RCG_CMD) {
|
||||
/* The update completes at once; the root is on if it was enabled */
|
||||
value &= ~(RCG_CMD_UPDATE | RCG_CMD_ROOT_OFF);
|
||||
if (!(value & RCG_CMD_ROOT_EN)) {
|
||||
value |= RCG_CMD_ROOT_OFF;
|
||||
}
|
||||
s->regs[RCG_CMD / 4] = value;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps qcom_lucid_pll_ops = {
|
||||
.read = qcom_clk_read,
|
||||
.write = qcom_lucid_pll_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static const MemoryRegionOps qcom_rcg_ops = {
|
||||
.read = qcom_clk_read,
|
||||
.write = qcom_rcg_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void qcom_clk_realize(DeviceState *dev, const MemoryRegionOps *ops,
|
||||
const char *name)
|
||||
{
|
||||
QcomClkRegsState *s = QCOM_CLK_REGS(dev);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(dev), ops, s, name,
|
||||
QCOM_CLK_REGS_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
|
||||
}
|
||||
|
||||
static void qcom_lucid_pll_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
qcom_clk_realize(dev, &qcom_lucid_pll_ops, TYPE_QCOM_LUCID_PLL);
|
||||
}
|
||||
|
||||
static void qcom_rcg_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
qcom_clk_realize(dev, &qcom_rcg_ops, TYPE_QCOM_RCG);
|
||||
}
|
||||
|
||||
static void qcom_clk_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
QcomClkRegsState *s = QCOM_CLK_REGS(obj);
|
||||
|
||||
memset(s->regs, 0, sizeof(s->regs));
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_qcom_clk = {
|
||||
.name = "qcom-qdsp6ss-clk",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, QcomClkRegsState, QCOM_CLK_NUM_REGS),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void qcom_clk_regs_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->vmsd = &vmstate_qcom_clk;
|
||||
RESETTABLE_CLASS(oc)->phases.hold = qcom_clk_reset_hold;
|
||||
}
|
||||
|
||||
static void qcom_lucid_pll_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = qcom_lucid_pll_realize;
|
||||
dc->desc = "Qualcomm Lucid alpha PLL";
|
||||
}
|
||||
|
||||
static void qcom_rcg_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = qcom_rcg_realize;
|
||||
dc->desc = "Qualcomm root clock generator";
|
||||
}
|
||||
|
||||
static const TypeInfo qcom_qdsp6ss_clk_types[] = {
|
||||
{
|
||||
.name = TYPE_QCOM_CLK_REGS,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(QcomClkRegsState),
|
||||
.class_init = qcom_clk_regs_class_init,
|
||||
.abstract = true,
|
||||
},
|
||||
{
|
||||
.name = TYPE_QCOM_LUCID_PLL,
|
||||
.parent = TYPE_QCOM_CLK_REGS,
|
||||
.class_init = qcom_lucid_pll_class_init,
|
||||
},
|
||||
{
|
||||
.name = TYPE_QCOM_RCG,
|
||||
.parent = TYPE_QCOM_CLK_REGS,
|
||||
.class_init = qcom_rcg_class_init,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(qcom_qdsp6ss_clk_types)
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Board-construction helpers shared by the Hexagon machines.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef HW_HEXAGON_HEX_BOARD_H
|
||||
#define HW_HEXAGON_HEX_BOARD_H
|
||||
|
||||
#include "hw/hexagon/hexagon.h"
|
||||
|
||||
/* The L2VIC interrupt specifiers of the 32 per-cpu lines precede its lines. */
|
||||
#define HEX_BOARD_L2VIC_SPI_BASE 32
|
||||
|
||||
/*
|
||||
* Create the device tree with its root, /soc and /chosen (including an
|
||||
* rng-seed) nodes. Returns its size in @fdt_size.
|
||||
*/
|
||||
void hex_board_create_fdt(MachineState *ms, const char *model,
|
||||
const char *compatible, int *fdt_size);
|
||||
|
||||
/* Add the L2VIC node and make it the interrupt parent of /soc. */
|
||||
int32_t hex_board_fdt_add_l2vic(MachineState *ms,
|
||||
const struct hexagon_machine_config *cfg);
|
||||
|
||||
/* Add the /soc/vtcm and /soc/hvx nodes, for what the config provides. */
|
||||
void hex_board_fdt_add_hvx(MachineState *ms,
|
||||
const struct hexagon_machine_config *cfg);
|
||||
|
||||
/* Add one /cpus/cpu@N node per CPU of the machine. */
|
||||
void hex_board_fdt_add_cpus(MachineState *ms);
|
||||
|
||||
/* Create the L2 TCM RAM, if the config has any. */
|
||||
void hex_board_create_tcm(const struct hexagon_machine_config *cfg,
|
||||
MemoryRegion *tcm);
|
||||
|
||||
/* Create the PL011 console and its fixed clock, and describe them. */
|
||||
void hex_board_create_uart(MachineState *ms, hwaddr base, hwaddr size,
|
||||
int irq, int32_t l2vic_phandle);
|
||||
|
||||
/* Create @count virtio-mmio transports on consecutive lines and slots. */
|
||||
void hex_board_create_virtio(MachineState *ms, hwaddr base, hwaddr size,
|
||||
int irq_base, int count,
|
||||
int32_t l2vic_phandle);
|
||||
|
||||
/*
|
||||
* Load an ELF for the guest and return its entry point. If @translate is
|
||||
* given it maps the ELF's addresses. The highest address used is returned
|
||||
* in @high, if non-NULL. Exits on failure.
|
||||
*/
|
||||
uint64_t hex_board_load_elf(const char *filename,
|
||||
uint64_t (*translate)(void *opaque, uint64_t addr),
|
||||
void *opaque, uint64_t *high);
|
||||
|
||||
/* Copy the device tree to @addr and refresh its rng-seed on reset. */
|
||||
void hex_board_load_fdt(MachineState *ms, int fdt_size, hwaddr addr);
|
||||
|
||||
/*
|
||||
* Create the machine's CPUs, with CPU 0 starting at @start if @have_start,
|
||||
* and realize the cluster.
|
||||
*/
|
||||
void hex_board_create_cpus(MachineState *ms, bool have_start, uint64_t start);
|
||||
|
||||
#endif /* HW_HEXAGON_HEX_BOARD_H */
|
||||
@@ -23,15 +23,22 @@ typedef enum {
|
||||
v66_rev = 0xa666,
|
||||
v67_rev = 0x2667,
|
||||
v68_rev = 0x8d68,
|
||||
v68_qcs6490_rev = 0x8a68,
|
||||
v69_rev = 0x8c69,
|
||||
v71_rev = 0x8c71,
|
||||
v73_rev = 0x8c73,
|
||||
v73m_rev = 0xcc73,
|
||||
v73nc_1_rev = 0x8b73,
|
||||
v79_rev = 0x8c79,
|
||||
v81_rev = 0x8781,
|
||||
v81_sc8480xp_rev = 0x8081,
|
||||
v81dgb_1_rev = 0xcc81,
|
||||
v85qa_1_rev = 0x8185,
|
||||
v85na_1_rev = 0x8085,
|
||||
v85_sm8975_rev = v85na_1_rev,
|
||||
} Rev_t;
|
||||
#define HEXAGON_LATEST_REV v73
|
||||
#define HEXAGON_LATEST_REV_UPPER V73
|
||||
#define HEXAGON_LATEST_REV v85
|
||||
#define HEXAGON_LATEST_REV_UPPER V85
|
||||
|
||||
/*
|
||||
* Config table address bases represent bits [35:16].
|
||||
@@ -40,6 +47,10 @@ typedef enum {
|
||||
|
||||
#define HEXAGON_CFGSPACE_ENTRIES (128)
|
||||
|
||||
/* Offsets of q6ss cfg peripherals from the subsystem base. */
|
||||
#define HEXAGON_L2VIC_OFFSET 0x10000
|
||||
#define HEXAGON_QTIMER_OFFSET 0x21000
|
||||
|
||||
union hexagon_config_table {
|
||||
struct {
|
||||
/* Base address of L2TCM space */
|
||||
@@ -145,6 +156,8 @@ union hexagon_config_table {
|
||||
};
|
||||
|
||||
struct hexagon_machine_config {
|
||||
/* Base address of the main DDR region */
|
||||
hwaddr ddr_base;
|
||||
/* Base address of config table */
|
||||
uint32_t cfgbase;
|
||||
/* Size of L2 TCM */
|
||||
@@ -167,6 +180,7 @@ struct HexagonCommonMachineState {
|
||||
|
||||
MemoryRegion ram;
|
||||
MemoryRegion cfgtable_rom;
|
||||
uint32_t cfgtable_data[HEXAGON_CFGSPACE_ENTRIES];
|
||||
MemoryRegion vtcm;
|
||||
DeviceState *cluster;
|
||||
DeviceState *l2vic;
|
||||
|
||||
@@ -30,6 +30,8 @@ uint64_t hexagon_tlb_read(HexagonTLBState *tlb, uint32_t index);
|
||||
uint64_t hexagon_tlb_write(HexagonTLBState *tlb, uint32_t index,
|
||||
uint64_t value);
|
||||
|
||||
uint32_t hexagon_tlb_invalidate_asid(HexagonTLBState *tlb, uint32_t asid);
|
||||
|
||||
bool hexagon_tlb_find_match(HexagonTLBState *tlb, uint32_t asid,
|
||||
uint32_t VA, MMUAccessType access_type,
|
||||
hwaddr *PA, int *prot, uint64_t *size,
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Qualcomm DSP subsystem machines: the board layer shared by the SoC models.
|
||||
*
|
||||
* Each SoC provides a QcomDspMachineInfo describing its subsystem, and the
|
||||
* layer supplies what every one of them has in common: the CPUs, a QEMU-only
|
||||
* PL011 console, virtio-mmio slots, a generated device tree, and the
|
||||
* -bios/-kernel/-initrd boot flow.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef HW_HEXAGON_QCOM_DSP_H
|
||||
#define HW_HEXAGON_QCOM_DSP_H
|
||||
|
||||
#include "hw/hexagon/hexagon.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_QCOM_DSP_MACHINE MACHINE_TYPE_NAME("qcom-dsp")
|
||||
OBJECT_DECLARE_TYPE(QcomDspMachineState, QcomDspMachineClass, QCOM_DSP_MACHINE)
|
||||
|
||||
/* Number of virtio-mmio transports every machine provides. */
|
||||
#define QCOM_DSP_VIRTIO_COUNT 8
|
||||
|
||||
typedef struct QcomDspMachineInfo {
|
||||
const char *desc;
|
||||
const char *cpu_type;
|
||||
unsigned int cpus;
|
||||
Rev_t rev;
|
||||
const struct hexagon_machine_config *cfg;
|
||||
/* Where the H2 loadlinux of this SoC expects to find the Linux kernel. */
|
||||
hwaddr kernel_addr;
|
||||
/* Add the devices that are specific to this SoC; may be NULL. */
|
||||
void (*init_devices)(MachineState *ms);
|
||||
} QcomDspMachineInfo;
|
||||
|
||||
struct QcomDspMachineState {
|
||||
HexagonCommonMachineState parent_obj;
|
||||
|
||||
MemoryRegion tcm;
|
||||
MemoryRegion l2_ecc;
|
||||
int fdt_size;
|
||||
hwaddr fdt_addr;
|
||||
char *firmware_path;
|
||||
};
|
||||
|
||||
struct QcomDspMachineClass {
|
||||
MachineClass parent_class;
|
||||
|
||||
const QcomDspMachineInfo *info;
|
||||
};
|
||||
|
||||
/* Describes a register window the machine stubs out as unimplemented. */
|
||||
typedef struct QcomDspRegion {
|
||||
const char *name;
|
||||
hwaddr base;
|
||||
/* Zero means one 4 KiB page. */
|
||||
hwaddr size;
|
||||
} QcomDspRegion;
|
||||
|
||||
/*
|
||||
* Stub out register windows the guest may probe, named
|
||||
* "<machine>.<name>@<base>".
|
||||
*/
|
||||
void qcom_dsp_add_regions(MachineState *ms, const QcomDspRegion *regions,
|
||||
unsigned int count);
|
||||
|
||||
/* Create the sysbus device @type and map it at @base. */
|
||||
void qcom_dsp_add_device(const char *type, hwaddr base);
|
||||
|
||||
/*
|
||||
* Stub out @ports consecutive QUP GENI serial engines of @size bytes. They
|
||||
* belong to the SoC @soc rather than to the DSP.
|
||||
*/
|
||||
void qcom_soc_add_qup_geni_ports(const char *soc, hwaddr base,
|
||||
unsigned int ports, hwaddr size);
|
||||
|
||||
/* Class init for a machine type whose class_data is a QcomDspMachineInfo. */
|
||||
void qcom_dsp_class_init(ObjectClass *oc, const void *data);
|
||||
|
||||
#endif /* HW_HEXAGON_QCOM_DSP_H */
|
||||
@@ -17,15 +17,9 @@ struct HexagonVirtMachineState {
|
||||
HexagonCommonMachineState parent_obj;
|
||||
|
||||
int fdt_size;
|
||||
MemoryRegion *sys;
|
||||
MemoryRegion tcm;
|
||||
MemoryRegion bios;
|
||||
Clock *apb_clk;
|
||||
DeviceState *virtio_mmio[VIRTIO_DEV_COUNT];
|
||||
};
|
||||
|
||||
void hexagon_load_fdt(const struct HexagonVirtMachineState *vms);
|
||||
|
||||
#define TYPE_HEXAGON_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(HexagonVirtMachineState, HEXAGON_VIRT_MACHINE)
|
||||
|
||||
|
||||
@@ -31,8 +31,13 @@ typedef struct HexL2VicInterfaceClass {
|
||||
void (*update_vid)(HexL2VicInterface *l2vic, uint32_t group,
|
||||
uint32_t value);
|
||||
|
||||
/* Clear interrupt using CIAD instruction */
|
||||
void (*clear_interrupt)(HexL2VicInterface *l2vic);
|
||||
/*
|
||||
* Clear interrupts using the CIAD instruction.
|
||||
* @mask the CPU interrupts that the CIAD acknowledged. The interrupt is
|
||||
* only cleared if @mask has the CPU interrupt that its VID group is
|
||||
* delivered on.
|
||||
*/
|
||||
void (*clear_interrupt)(HexL2VicInterface *l2vic, uint32_t mask);
|
||||
} HexL2VicInterfaceClass;
|
||||
|
||||
DECLARE_OBJ_CHECKERS(HexL2VicInterface, HexL2VicInterfaceClass,
|
||||
@@ -52,10 +57,11 @@ static inline void l2vic_update_vid(HexL2VicInterface *l2vic, uint32_t group,
|
||||
k->update_vid(l2vic, group, value);
|
||||
}
|
||||
|
||||
static inline void l2vic_clear_interrupt(HexL2VicInterface *l2vic)
|
||||
static inline void l2vic_clear_interrupt(HexL2VicInterface *l2vic,
|
||||
uint32_t mask)
|
||||
{
|
||||
HexL2VicInterfaceClass *k = HEX_L2VIC_INTERFACE_GET_CLASS(l2vic);
|
||||
k->clear_interrupt(l2vic);
|
||||
k->clear_interrupt(l2vic, mask);
|
||||
}
|
||||
|
||||
#endif /* HW_INTC_HEX_L2VIC_H */
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Qualcomm QDSP6SS clock blocks: the Lucid alpha PLL and the root clock
|
||||
* generator that firmware programs while bringing a Hexagon DSP up.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef HW_MISC_QCOM_QDSP6SS_CLK_H
|
||||
#define HW_MISC_QCOM_QDSP6SS_CLK_H
|
||||
|
||||
#define TYPE_QCOM_LUCID_PLL "qcom-lucid-pll"
|
||||
#define TYPE_QCOM_RCG "qcom-rcg"
|
||||
|
||||
#endif /* HW_MISC_QCOM_QDSP6SS_CLK_H */
|
||||
@@ -48,6 +48,10 @@ void cpu_loop(CPUHexagonState *env)
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case HEX_EVENT_TRAP0:
|
||||
case HEX_EVENT_TRAP2:
|
||||
/* Exception entry ends any pending restricted-branch check. */
|
||||
env->cfi_active = 0;
|
||||
env->cfi_updated = 0;
|
||||
syscallnum = env->gpr[6];
|
||||
env->gpr[HEX_REG_PC] += 4;
|
||||
ret = do_syscall(env,
|
||||
@@ -73,6 +77,16 @@ void cpu_loop(CPUHexagonState *env)
|
||||
force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
|
||||
env->gpr[HEX_REG_PC]);
|
||||
break;
|
||||
case HEX_CAUSE_VECTOR_STACK_OVERFLOW:
|
||||
force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_BNDERR,
|
||||
env->gpr[HEX_REG_PC]);
|
||||
break;
|
||||
case HEX_CAUSE_CFI_VIOLATION:
|
||||
env->cfi_active = 0;
|
||||
env->cfi_updated = 0;
|
||||
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC,
|
||||
env->gpr[HEX_REG_PC]);
|
||||
break;
|
||||
case HEX_CAUSE_PRIV_USER_NO_GINSN:
|
||||
case HEX_CAUSE_PRIV_USER_NO_SINSN:
|
||||
case HEX_CAUSE_INVALID_PACKET:
|
||||
|
||||
@@ -62,6 +62,12 @@ abi_ulong get_elf_hwcap(CPUState *cs)
|
||||
case HEX_VER_V81:
|
||||
hwcaps = HWCAP_HEXAGON_ISA_V81;
|
||||
break;
|
||||
case HEX_VER_V83:
|
||||
hwcaps = HWCAP_HEXAGON_ISA_V83;
|
||||
break;
|
||||
case HEX_VER_V85:
|
||||
hwcaps = HWCAP_HEXAGON_ISA_V85;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -113,6 +119,10 @@ const char *get_elf_cpu_model(uint32_t eflags)
|
||||
return "v79";
|
||||
case 0x81:
|
||||
return "v81";
|
||||
case 0x83:
|
||||
return "v83";
|
||||
case 0x85:
|
||||
return "v85";
|
||||
}
|
||||
|
||||
err = snprintf(buf, sizeof(buf), "unknown (0x%x)", eflags);
|
||||
|
||||
@@ -106,6 +106,10 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPUHexagonState *env)
|
||||
|
||||
__put_user(env->gpr[HEX_REG_CS0], &sc->sc_regs.cs0);
|
||||
__put_user(env->gpr[HEX_REG_CS1], &sc->sc_regs.cs1);
|
||||
/* Preserve a pending restricted-branch landing pad across the signal. */
|
||||
__put_user(env->cfi_active, &sc->sc_regs.pad1);
|
||||
env->cfi_active = 0;
|
||||
env->cfi_updated = 0;
|
||||
}
|
||||
|
||||
static void setup_ucontext(struct target_ucontext *uc,
|
||||
@@ -176,6 +180,7 @@ static void restore_sigcontext(CPUHexagonState *env,
|
||||
struct target_sigcontext *sc)
|
||||
{
|
||||
abi_ulong preds;
|
||||
abi_ulong cfi;
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
__get_user(env->gpr[HEX_REG_R00 + i], &sc->sc_regs.gpr[i]);
|
||||
@@ -199,6 +204,9 @@ static void restore_sigcontext(CPUHexagonState *env,
|
||||
|
||||
__get_user(env->gpr[HEX_REG_CS0], &sc->sc_regs.cs0);
|
||||
__get_user(env->gpr[HEX_REG_CS1], &sc->sc_regs.cs1);
|
||||
__get_user(cfi, &sc->sc_regs.pad1);
|
||||
env->cfi_active = cfi & 1;
|
||||
env->cfi_updated = 0;
|
||||
}
|
||||
|
||||
static void restore_ucontext(CPUHexagonState *env, struct target_ucontext *uc)
|
||||
|
||||
@@ -43,6 +43,8 @@ enum {
|
||||
HWCAP_HEXAGON_ISA_V77 = 16,
|
||||
HWCAP_HEXAGON_ISA_V79 = 17,
|
||||
HWCAP_HEXAGON_ISA_V81 = 18,
|
||||
HWCAP_HEXAGON_ISA_V83 = 19,
|
||||
HWCAP_HEXAGON_ISA_V85 = 20,
|
||||
HWCAP_HEXAGON_HVX = 1 << 7,
|
||||
HWCAP_HEXAGON_CABAC = 1 << 8,
|
||||
HWCAP_HEXAGON_HVX_LENGTH_128B = 1 << 9,
|
||||
|
||||
@@ -44,4 +44,4 @@ for file in cache_dir.iterdir():
|
||||
print(f"Removing {cache_dir}/{file.name}.")
|
||||
file.chmod(stat.S_IWRITE)
|
||||
file.unlink()
|
||||
stampfile.unlink()
|
||||
stampfile.unlink(missing_ok=True)
|
||||
@@ -60,6 +60,7 @@ DEF_ATTRIB(COPBYADDRESS, "Cache operation by address", "", "")
|
||||
DEF_ATTRIB(COPBYIDX, "Cache operation by index", "", "")
|
||||
DEF_ATTRIB(RELEASE, "Releases a lock", "", "")
|
||||
DEF_ATTRIB(ACQUIRE, "Acquires a lock", "", "")
|
||||
DEF_ATTRIB(ATOMIC, "Atomic memory instruction", "", "")
|
||||
|
||||
DEF_ATTRIB(RLS_INNER, "Store release inner visibility", "", "")
|
||||
DEF_ATTRIB(RLS_ALL_THREAD, "Store release among all threads", "", "")
|
||||
@@ -199,6 +200,7 @@ DEF_ATTRIB(NOTE_SHIFT_RESOURCE, "Uses the HVX shift resource.", "", "")
|
||||
/* Restrictions to make note of */
|
||||
DEF_ATTRIB(RESTRICT_NOSLOT1_STORE, "Packet must not have slot 1 store", "", "")
|
||||
DEF_ATTRIB(RESTRICT_LATEPRED, "Predicate can not be used as a .new.", "", "")
|
||||
DEF_ATTRIB(RESTRICT_TARGET, "Restricted branch target instruction", "", "")
|
||||
|
||||
/* HVX IEEE FP extension attributes */
|
||||
DEF_ATTRIB(HVX_IEEE_FP, "HVX IEEE FP extension instruction", "", "")
|
||||
|
||||
@@ -28,6 +28,8 @@ typedef enum {
|
||||
HEX_VER_V75 = 0x75,
|
||||
HEX_VER_V79 = 0x79,
|
||||
HEX_VER_V81 = 0x81,
|
||||
HEX_VER_V83 = 0x83,
|
||||
HEX_VER_V85 = 0x85,
|
||||
HEX_VER_ANY = 0xff,
|
||||
} HexagonVersion;
|
||||
|
||||
@@ -55,6 +57,8 @@ typedef struct {
|
||||
#define TYPE_HEXAGON_CPU_V75 HEXAGON_CPU_TYPE_NAME("v75")
|
||||
#define TYPE_HEXAGON_CPU_V79 HEXAGON_CPU_TYPE_NAME("v79")
|
||||
#define TYPE_HEXAGON_CPU_V81 HEXAGON_CPU_TYPE_NAME("v81")
|
||||
#define TYPE_HEXAGON_CPU_V83 HEXAGON_CPU_TYPE_NAME("v83")
|
||||
#define TYPE_HEXAGON_CPU_V85 HEXAGON_CPU_TYPE_NAME("v85")
|
||||
|
||||
OBJECT_DECLARE_CPU_TYPE(HexagonCPU, HexagonCPUClass, HEXAGON_CPU)
|
||||
|
||||
|
||||
+16
-1
@@ -88,7 +88,7 @@ const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = {
|
||||
"sa0", "lc0", "sa1", "lc1", "p3_0", "c5", "m0", "m1",
|
||||
"usr", "pc", "ugp", "gp", "cs0", "cs1", "c14", "c15",
|
||||
"c16", "c17", "c18", "c19", "pkt_cnt", "insn_cnt", "hvx_cnt", "c23",
|
||||
"c24", "c25", "c26", "c27", "c28", "c29", "c30", "c31",
|
||||
"c24", "c25", "c26", "c27", "vframelimit", "vsp", "c30", "c31",
|
||||
};
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
@@ -388,6 +388,10 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
|
||||
GET_SSR_FIELD(SSR_XE, env->t_sreg[HEX_SREG_SSR]));
|
||||
hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, CPU_MODE,
|
||||
get_cpu_mode(env));
|
||||
/* Single-step applies only to user and guest mode packets */
|
||||
hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, SS_ACTIVE,
|
||||
GET_SSR_FIELD(SSR_SS, env->t_sreg[HEX_SREG_SSR]) &&
|
||||
get_cpu_mode(env) != HEX_CPU_MODE_MONITOR);
|
||||
#else
|
||||
hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, MMU_USER_IDX);
|
||||
#endif
|
||||
@@ -426,6 +430,9 @@ static bool hexagon_cpu_has_work(CPUState *cs)
|
||||
{
|
||||
CPUHexagonState *env = cpu_env(cs);
|
||||
|
||||
if (qatomic_read(&cs->exception_index) != HEX_EVENT_NONE) {
|
||||
return true;
|
||||
}
|
||||
return hexagon_thread_is_enabled(env) &&
|
||||
(cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_SWI
|
||||
| CPU_INTERRUPT_K0_UNLOCK | CPU_INTERRUPT_TLB_UNLOCK
|
||||
@@ -448,6 +455,9 @@ void hexagon_cpu_soft_reset(CPUHexagonState *env)
|
||||
|
||||
BQL_LOCK_GUARD();
|
||||
env->llsc_addr = ~0;
|
||||
env->cfi_active = 0;
|
||||
env->cfi_active_log = 0;
|
||||
env->cfi_updated = 0;
|
||||
env->t_sreg[HEX_SREG_SSR] = 0;
|
||||
hexagon_ssr_set_cause(env, HEX_CAUSE_RESET);
|
||||
|
||||
@@ -485,6 +495,9 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
|
||||
set_float_default_nan_pattern(0b01111111, &env->hvx_fp_status);
|
||||
|
||||
env->llsc_addr = ~0;
|
||||
env->cfi_active = 0;
|
||||
env->cfi_active_log = 0;
|
||||
env->cfi_updated = 0;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
memset(env->t_sreg, 0, sizeof(uint32_t) * NUM_SREGS);
|
||||
memset(env->greg, 0, sizeof(uint32_t) * NUM_GREGS);
|
||||
@@ -975,6 +988,8 @@ static const TypeInfo hexagon_cpu_type_infos[] = {
|
||||
DEFINE_CPU(TYPE_HEXAGON_CPU_V75, HEX_VER_V75),
|
||||
DEFINE_CPU(TYPE_HEXAGON_CPU_V79, HEX_VER_V79),
|
||||
DEFINE_CPU(TYPE_HEXAGON_CPU_V81, HEX_VER_V81),
|
||||
DEFINE_CPU(TYPE_HEXAGON_CPU_V83, HEX_VER_V83),
|
||||
DEFINE_CPU(TYPE_HEXAGON_CPU_V85, HEX_VER_V85),
|
||||
};
|
||||
|
||||
DEFINE_TYPES(hexagon_cpu_type_infos)
|
||||
@@ -76,6 +76,14 @@ typedef struct HexagonHVXContextState HexagonHVXContextState;
|
||||
#define MMU_GUEST_IDX 1
|
||||
#define MMU_KERNEL_IDX 2
|
||||
|
||||
/*
|
||||
* TLB entry match is by ASID and global bit, neither of which is encoded in
|
||||
* mmu_idx, so a JTLB change has to be flushed out of every mmu_idx.
|
||||
*/
|
||||
#define MMU_IDX_ALL ((1 << MMU_USER_IDX) | \
|
||||
(1 << MMU_GUEST_IDX) | \
|
||||
(1 << MMU_KERNEL_IDX))
|
||||
|
||||
typedef enum {
|
||||
HEX_LOCK_UNLOCKED = 0,
|
||||
HEX_LOCK_WAITING = 1,
|
||||
@@ -132,6 +140,9 @@ typedef struct CPUArchState {
|
||||
target_ulong gpr[TOTAL_PER_THREAD_REGS];
|
||||
target_ulong pred[NUM_PREGS];
|
||||
uint32_t cause_code;
|
||||
uint32_t cfi_active;
|
||||
uint32_t cfi_active_log;
|
||||
uint32_t cfi_updated;
|
||||
|
||||
/* For comparing with LLDB on target - see adjust_stack_ptrs function */
|
||||
target_ulong last_pc_dumped;
|
||||
@@ -227,6 +238,7 @@ FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1)
|
||||
FIELD(TB_FLAGS, MMU_INDEX, 1, 3)
|
||||
FIELD(TB_FLAGS, HVX_COPROC_ENABLED, 5, 1)
|
||||
FIELD(TB_FLAGS, CPU_MODE, 6, 2)
|
||||
FIELD(TB_FLAGS, SS_ACTIVE, 8, 1)
|
||||
|
||||
G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env,
|
||||
uint32_t exception,
|
||||
|
||||
@@ -41,6 +41,7 @@ enum hex_event {
|
||||
HEX_EVENT_TLB_MISS_RW = 0x6,
|
||||
HEX_EVENT_TRAP0 = 0x8,
|
||||
HEX_EVENT_TRAP1 = 0x9,
|
||||
HEX_EVENT_TRAP2 = 0xa,
|
||||
HEX_EVENT_FPTRAP = 0xb,
|
||||
HEX_EVENT_DEBUG = 0xc,
|
||||
HEX_EVENT_INT0 = 0x10,
|
||||
@@ -73,12 +74,14 @@ enum hex_cause {
|
||||
HEX_CAUSE_TRAP1 = 0x009,
|
||||
HEX_CAUSE_FETCH_NO_XPAGE = 0x011,
|
||||
HEX_CAUSE_FETCH_NO_UPAGE = 0x012,
|
||||
HEX_CAUSE_CFI_VIOLATION = 0x014,
|
||||
HEX_CAUSE_INVALID_PACKET = 0x015,
|
||||
HEX_CAUSE_INVALID_OPCODE = 0x015, /* alias: same cause as INVALID_PACKET */
|
||||
HEX_CAUSE_NO_COPROC_ENABLE = 0x016,
|
||||
HEX_CAUSE_NO_COPROC2_ENABLE = 0x018,
|
||||
HEX_CAUSE_PRIV_USER_NO_GINSN = 0x01a,
|
||||
HEX_CAUSE_PRIV_USER_NO_SINSN = 0x01b,
|
||||
HEX_CAUSE_VECTOR_STACK_OVERFLOW = 0x01c,
|
||||
HEX_CAUSE_REG_WRITE_CONFLICT = 0x01d,
|
||||
HEX_CAUSE_PC_NOT_ALIGNED = 0x01e,
|
||||
HEX_CAUSE_MISALIGNED_LOAD = 0x020,
|
||||
|
||||
@@ -28,48 +28,6 @@
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
static bool hexagon_read_memory_small(CPUHexagonState *env, target_ulong addr,
|
||||
int byte_count, uint64_t *data,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
/* handle small sizes */
|
||||
switch (byte_count) {
|
||||
case 1:
|
||||
*data = cpu_ldub_mmuidx_ra(env, addr, mmu_idx, retaddr);
|
||||
return true;
|
||||
|
||||
case 2:
|
||||
*data = cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
|
||||
return true;
|
||||
|
||||
case 4:
|
||||
*data = cpu_ldl_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
|
||||
return true;
|
||||
|
||||
case 8:
|
||||
*data = cpu_ldq_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
|
||||
return true;
|
||||
|
||||
default:
|
||||
/* larger request, handle elsewhere */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void hexagon_read_memory(CPUHexagonState *env, target_ulong vaddr, int size,
|
||||
void *retptr, uintptr_t retaddr)
|
||||
{
|
||||
BQL_LOCK_GUARD();
|
||||
CPUState *cs = env_cpu(env);
|
||||
unsigned mmu_idx = cpu_mmu_index(cs, false);
|
||||
uint64_t data;
|
||||
if (hexagon_read_memory_small(env, vaddr, size, &data, mmu_idx, retaddr)) {
|
||||
stn_he_p(retptr, size, data);
|
||||
} else {
|
||||
cpu_abort(cs, "%s: ERROR: bad size = %d!\n", __func__, size);
|
||||
}
|
||||
}
|
||||
|
||||
static bool hexagon_write_memory_small(CPUHexagonState *env, target_ulong addr,
|
||||
int byte_count, uint64_t data,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
@@ -117,11 +75,13 @@ static inline uint32_t page_start(uint32_t addr)
|
||||
void hexagon_peek_memory_range(CPUHexagonState *env, uint32_t start_addr,
|
||||
uint32_t length, uintptr_t retaddr)
|
||||
{
|
||||
unsigned int warm;
|
||||
CPUState *cs = env_cpu(env);
|
||||
unsigned int mmu_idx = cpu_mmu_index(cs, false);
|
||||
uint32_t first = page_start(start_addr);
|
||||
uint32_t last = page_start(start_addr + length - 1);
|
||||
|
||||
for (uint32_t page = first; page <= last; page += TARGET_PAGE_SIZE) {
|
||||
hexagon_read_memory(env, page, 1, &warm, retaddr);
|
||||
cpu_ldub_mmuidx_ra(env, page, mmu_idx, retaddr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +98,7 @@ static void hexagon_resume_thread(CPUHexagonState *env)
|
||||
clear_wait_mode(env);
|
||||
cs = env_cpu(env);
|
||||
ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index);
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_HALT);
|
||||
cs->halted = false;
|
||||
cs->exception_index = HEX_EVENT_NONE;
|
||||
qemu_cpu_kick(cs);
|
||||
@@ -231,27 +192,17 @@ unsigned hexagon_hvx_select_context(CPUHexagonState *env, uint32_t ssr)
|
||||
|
||||
void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old)
|
||||
{
|
||||
bool old_EX, old_UM, old_GM, old_IE;
|
||||
bool new_EX, new_UM, new_GM, new_IE;
|
||||
bool old_EX, old_IE;
|
||||
bool new_EX, new_IE;
|
||||
uint8_t old_asid, new_asid;
|
||||
|
||||
g_assert(bql_locked());
|
||||
|
||||
old_EX = GET_SSR_FIELD(SSR_EX, old);
|
||||
old_UM = GET_SSR_FIELD(SSR_UM, old);
|
||||
old_GM = GET_SSR_FIELD(SSR_GM, old);
|
||||
old_IE = GET_SSR_FIELD(SSR_IE, old);
|
||||
new_EX = GET_SSR_FIELD(SSR_EX, new);
|
||||
new_UM = GET_SSR_FIELD(SSR_UM, new);
|
||||
new_GM = GET_SSR_FIELD(SSR_GM, new);
|
||||
new_IE = GET_SSR_FIELD(SSR_IE, new);
|
||||
|
||||
if ((old_EX != new_EX) ||
|
||||
(old_UM != new_UM) ||
|
||||
(old_GM != new_GM)) {
|
||||
hex_mmu_mode_change(env);
|
||||
}
|
||||
|
||||
bool xa_changed = GET_SSR_FIELD(SSR_XA, new) != GET_SSR_FIELD(SSR_XA, old);
|
||||
bool xe_changed = GET_SSR_FIELD(SSR_XE, new) != GET_SSR_FIELD(SSR_XE, old);
|
||||
|
||||
@@ -267,8 +218,7 @@ void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old)
|
||||
old_asid = GET_SSR_FIELD(SSR_ASID, old);
|
||||
new_asid = GET_SSR_FIELD(SSR_ASID, new);
|
||||
if (new_asid != old_asid) {
|
||||
CPUState *cs = env_cpu(env);
|
||||
tlb_flush(cs);
|
||||
hex_mmu_asid_change(env);
|
||||
}
|
||||
|
||||
/* See if the interrupts have been enabled or we have exited EX mode */
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#ifndef HEXAGON_CPU_HELPER_H
|
||||
#define HEXAGON_CPU_HELPER_H
|
||||
|
||||
void hexagon_read_memory(CPUHexagonState *env, target_ulong vaddr, int size,
|
||||
void *retptr, uintptr_t retaddr);
|
||||
void hexagon_write_memory(CPUHexagonState *env, target_ulong vaddr,
|
||||
int size, uint64_t data, uintptr_t retaddr);
|
||||
void hexagon_peek_memory_range(CPUHexagonState *env, uint32_t start_addr,
|
||||
|
||||
+24
-1
@@ -186,6 +186,7 @@ static bool decode_opcode_can_jump(int opcode)
|
||||
(GET_ATTRIB(opcode, A_CALL)) ||
|
||||
(opcode == J2_trap0) ||
|
||||
(opcode == J2_trap1) ||
|
||||
(opcode == J2_trap2) ||
|
||||
(opcode == J2_rte) ||
|
||||
(opcode == J2_pause)) {
|
||||
/* Exception to A_JUMP attribute */
|
||||
@@ -600,9 +601,12 @@ decode_set_slot_number(Packet *pkt)
|
||||
for (i = 0, slot = 3; i < pkt->num_insns; i++) {
|
||||
SlotMask valid_slots = get_valid_slots(pkt, i);
|
||||
|
||||
while (!(valid_slots & (1 << slot))) {
|
||||
while (slot >= 0 && !(valid_slots & (1 << slot))) {
|
||||
slot--;
|
||||
}
|
||||
if (slot < 0) {
|
||||
return false;
|
||||
}
|
||||
pkt->insn[i].slot = slot;
|
||||
if (slot) {
|
||||
/* I've assigned the slot, now decrement it for the next insn */
|
||||
@@ -691,6 +695,22 @@ bool opcode_supported(uint16_t opcode, const HexagonCPUDef *hex_def)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some encodings of an otherwise supported opcode are reserved on newer
|
||||
* versions. HEX_VER_ANY (used when only disassembling) accepts everything.
|
||||
*/
|
||||
bool encoding_supported(uint16_t opcode, uint32_t encoding,
|
||||
const HexagonCPUDef *hex_def)
|
||||
{
|
||||
/* Bit 7 of L4_loadw_phys became reserved in v83. */
|
||||
if (hex_def->hex_version != HEX_VER_ANY &&
|
||||
hex_def->hex_version >= HEX_VER_V83 &&
|
||||
opcode == L4_loadw_phys && (encoding & 0x80)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode_packet
|
||||
* Decodes packet with given words
|
||||
@@ -721,6 +741,9 @@ int decode_packet(DisasContext *ctx, int max_words, const uint32_t *words,
|
||||
/* Invalid instruction encoding */
|
||||
return 0;
|
||||
}
|
||||
if (!encoding_supported(insn->opcode, encoding32, ctx->hex_def)) {
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* If we saw an extender, mark next word extended so immediate
|
||||
* decode works
|
||||
|
||||
@@ -31,5 +31,7 @@ int decode_packet(DisasContext *ctx, int max_words, const uint32_t *words,
|
||||
Packet *pkt, bool disas_only);
|
||||
|
||||
bool opcode_supported(uint16_t opcode, const HexagonCPUDef *hex_def);
|
||||
bool encoding_supported(uint16_t opcode, uint32_t encoding,
|
||||
const HexagonCPUDef *hex_def);
|
||||
|
||||
#endif
|
||||
@@ -68,6 +68,8 @@ def main():
|
||||
## Skip the guest instructions
|
||||
if "A_GUEST" in hex_common.attribdict[tag]:
|
||||
continue
|
||||
if "A_ATOMIC" in hex_common.attribdict[tag]:
|
||||
continue
|
||||
## Skip instructions that saturate in a ternary expression
|
||||
if tag in {"S2_asr_r_r_sat", "S2_asl_r_r_sat"}:
|
||||
continue
|
||||
@@ -75,7 +77,7 @@ def main():
|
||||
if tag in {"S4_vrcrotate_acc", "S4_vrcrotate"}:
|
||||
continue
|
||||
## Skip trap instructions
|
||||
if tag in {"J2_trap0", "J2_trap1"}:
|
||||
if tag in {"J2_trap0", "J2_trap1", "J2_trap2"}:
|
||||
continue
|
||||
## Skip 128-bit instructions
|
||||
if tag in {"A7_croundd_ri", "A7_croundd_rr"}:
|
||||
|
||||
+123
-1
@@ -100,6 +100,28 @@
|
||||
#define fGEN_TCG_L4_loadrd_ap(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_AP(RddV, 8, u)
|
||||
|
||||
#define fGEN_TCG_ATOMIC4(OP) \
|
||||
do { \
|
||||
fEA_REG(RsV); \
|
||||
gen_atomic4(ctx, RdV, EA, RtV, OP); \
|
||||
} while (0)
|
||||
#define fGEN_TCG_AM_addw_aq(SHORTCODE) fGEN_TCG_ATOMIC4(HEX_ATOMIC_ADD)
|
||||
#define fGEN_TCG_AM_addw_rl(SHORTCODE) fGEN_TCG_ATOMIC4(HEX_ATOMIC_ADD)
|
||||
#define fGEN_TCG_AM_andw_aq(SHORTCODE) fGEN_TCG_ATOMIC4(HEX_ATOMIC_AND)
|
||||
#define fGEN_TCG_AM_andw_rl(SHORTCODE) fGEN_TCG_ATOMIC4(HEX_ATOMIC_AND)
|
||||
#define fGEN_TCG_AM_orw_aq(SHORTCODE) fGEN_TCG_ATOMIC4(HEX_ATOMIC_OR)
|
||||
#define fGEN_TCG_AM_orw_rl(SHORTCODE) fGEN_TCG_ATOMIC4(HEX_ATOMIC_OR)
|
||||
#define fGEN_TCG_AM_xorw_aq(SHORTCODE) fGEN_TCG_ATOMIC4(HEX_ATOMIC_XOR)
|
||||
#define fGEN_TCG_AM_xorw_rl(SHORTCODE) fGEN_TCG_ATOMIC4(HEX_ATOMIC_XOR)
|
||||
#define fGEN_TCG_AM_swapw_aq(SHORTCODE) fGEN_TCG_ATOMIC4(HEX_ATOMIC_SWAP)
|
||||
#define fGEN_TCG_AM_swapw_rl(SHORTCODE) fGEN_TCG_ATOMIC4(HEX_ATOMIC_SWAP)
|
||||
#define fGEN_TCG_AM_swapd_aq(SHORTCODE) \
|
||||
do { \
|
||||
fEA_REG(RsV); \
|
||||
gen_atomic8(ctx, RddV, EA, RttV); \
|
||||
} while (0)
|
||||
#define fGEN_TCG_AM_swapd_rl(SHORTCODE) fGEN_TCG_AM_swapd_aq(SHORTCODE)
|
||||
|
||||
#define fGEN_TCG_L2_loadrub_pci(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrb_pci(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadruh_pci(SHORTCODE) SHORTCODE
|
||||
@@ -509,6 +531,31 @@
|
||||
do { RsV = RsV; } while (0)
|
||||
#endif
|
||||
|
||||
#define fGEN_TCG_V2_CHECK_AND_WRITE_VSP(VSP) \
|
||||
gen_vframecheck(ctx, VSP)
|
||||
#define fGEN_TCG_V2_vallocframe_imm(SHORTCODE) \
|
||||
do { \
|
||||
TCGv vsp = tcg_temp_new(); \
|
||||
tcg_gen_subi_tl(vsp, hex_gpr[HEX_REG_VSP], uiV << 11); \
|
||||
fGEN_TCG_V2_CHECK_AND_WRITE_VSP(vsp); \
|
||||
} while (0)
|
||||
#define fGEN_TCG_V2_vallocframe_reg(SHORTCODE) \
|
||||
do { \
|
||||
TCGv size = tcg_temp_new(); \
|
||||
TCGv vsp = tcg_temp_new(); \
|
||||
tcg_gen_shli_tl(size, RsV, 11); \
|
||||
tcg_gen_sub_tl(vsp, hex_gpr[HEX_REG_VSP], size); \
|
||||
fGEN_TCG_V2_CHECK_AND_WRITE_VSP(vsp); \
|
||||
} while (0)
|
||||
#define fGEN_TCG_V2_vdeallocframe_imm(SHORTCODE) \
|
||||
tcg_gen_addi_tl(hex_gpr[HEX_REG_VSP], hex_gpr[HEX_REG_VSP], uiV << 11)
|
||||
#define fGEN_TCG_V2_vdeallocframe_reg(SHORTCODE) \
|
||||
do { \
|
||||
TCGv size = tcg_temp_new(); \
|
||||
tcg_gen_shli_tl(size, RsV, 11); \
|
||||
tcg_gen_add_tl(hex_gpr[HEX_REG_VSP], hex_gpr[HEX_REG_VSP], size); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* allocframe(#uiV)
|
||||
* RxV == r29
|
||||
@@ -516,6 +563,9 @@
|
||||
#define fGEN_TCG_S2_allocframe(SHORTCODE) \
|
||||
gen_allocframe(ctx, RxV, uiV)
|
||||
|
||||
#define fGEN_TCG_S2_allocframe_rb(SHORTCODE) \
|
||||
fGEN_TCG_S2_allocframe(SHORTCODE)
|
||||
|
||||
/* sub-instruction version (no RxV, so handle it manually) */
|
||||
#define fGEN_TCG_SS2_allocframe(SHORTCODE) \
|
||||
do { \
|
||||
@@ -524,6 +574,9 @@
|
||||
gen_allocframe(ctx, r29, uiV); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_SS2_allocframe_rb(SHORTCODE) \
|
||||
fGEN_TCG_SS2_allocframe(SHORTCODE)
|
||||
|
||||
/*
|
||||
* Rdd32 = deallocframe(Rs32):raw
|
||||
* RddV == r31:30
|
||||
@@ -704,6 +757,16 @@
|
||||
gen_callr(ctx, RsV)
|
||||
#define fGEN_TCG_J2_callrh(SHORTCODE) \
|
||||
gen_callr(ctx, RsV)
|
||||
#define fGEN_TCG_J2_callr_rb(SHORTCODE) \
|
||||
do { \
|
||||
gen_callr(ctx, RsV); \
|
||||
gen_set_cfi(ctx); \
|
||||
} while (0)
|
||||
#define fGEN_TCG_J2_callrh_rb(SHORTCODE) \
|
||||
do { \
|
||||
gen_callr(ctx, RsV); \
|
||||
gen_set_cfi(ctx); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_J2_callt(SHORTCODE) \
|
||||
gen_cond_call(ctx, PuV, TCG_COND_TSTEQ, riV)
|
||||
@@ -713,6 +776,16 @@
|
||||
gen_cond_callr(ctx, TCG_COND_TSTEQ, PuV, RsV)
|
||||
#define fGEN_TCG_J2_callrf(SHORTCODE) \
|
||||
gen_cond_callr(ctx, TCG_COND_TSTNE, PuV, RsV)
|
||||
#define fGEN_TCG_J2_callrt_rb(SHORTCODE) \
|
||||
do { \
|
||||
gen_cond_callr(ctx, TCG_COND_TSTEQ, PuV, RsV); \
|
||||
gen_cond_set_cfi(ctx, true, PuV, -1); \
|
||||
} while (0)
|
||||
#define fGEN_TCG_J2_callrf_rb(SHORTCODE) \
|
||||
do { \
|
||||
gen_cond_callr(ctx, TCG_COND_TSTNE, PuV, RsV); \
|
||||
gen_cond_set_cfi(ctx, false, PuV, -1); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_J2_loop0r(SHORTCODE) \
|
||||
gen_loop0r(ctx, RsV, riV)
|
||||
@@ -933,6 +1006,39 @@
|
||||
gen_jumpr(ctx, RsV)
|
||||
#define fGEN_TCG_J2_jumprh(SHORTCODE) \
|
||||
gen_jumpr(ctx, RsV)
|
||||
#define fGEN_TCG_J2_jumpr_rb(SHORTCODE) \
|
||||
do { \
|
||||
gen_jumpr(ctx, RsV); \
|
||||
gen_set_cfi_for_target(ctx, RsN); \
|
||||
} while (0)
|
||||
#define fGEN_TCG_J2_jumprh_rb(SHORTCODE) \
|
||||
fGEN_TCG_J2_jumpr_rb(SHORTCODE)
|
||||
#define fGEN_TCG_J2_jumprt_rb(SHORTCODE) \
|
||||
do { \
|
||||
gen_cond_jumpr(ctx, RsV, TCG_COND_TSTEQ, PuV); \
|
||||
gen_cond_set_cfi(ctx, true, PuV, RsN); \
|
||||
} while (0)
|
||||
#define fGEN_TCG_J2_jumprf_rb(SHORTCODE) \
|
||||
do { \
|
||||
gen_cond_jumpr(ctx, RsV, TCG_COND_TSTNE, PuV); \
|
||||
gen_cond_set_cfi(ctx, false, PuV, RsN); \
|
||||
} while (0)
|
||||
#define fGEN_TCG_J2_jumprtpt_rb(SHORTCODE) fGEN_TCG_J2_jumprt_rb(SHORTCODE)
|
||||
#define fGEN_TCG_J2_jumprfpt_rb(SHORTCODE) fGEN_TCG_J2_jumprf_rb(SHORTCODE)
|
||||
#define fGEN_TCG_J2_jumprtnew_rb(SHORTCODE) \
|
||||
do { \
|
||||
gen_cond_jumpr(ctx, RsV, TCG_COND_TSTEQ, PuN); \
|
||||
gen_cond_set_cfi(ctx, true, PuN, RsN); \
|
||||
} while (0)
|
||||
#define fGEN_TCG_J2_jumprfnew_rb(SHORTCODE) \
|
||||
do { \
|
||||
gen_cond_jumpr(ctx, RsV, TCG_COND_TSTNE, PuN); \
|
||||
gen_cond_set_cfi(ctx, false, PuN, RsN); \
|
||||
} while (0)
|
||||
#define fGEN_TCG_J2_jumprtnewpt_rb(SHORTCODE) \
|
||||
fGEN_TCG_J2_jumprtnew_rb(SHORTCODE)
|
||||
#define fGEN_TCG_J2_jumprfnewpt_rb(SHORTCODE) \
|
||||
fGEN_TCG_J2_jumprfnew_rb(SHORTCODE)
|
||||
#define fGEN_TCG_J4_jumpseti(SHORTCODE) \
|
||||
do { \
|
||||
tcg_gen_movi_tl(RdV, UiV); \
|
||||
@@ -1122,7 +1228,7 @@
|
||||
RdV, tcg_constant_tl(0)); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_Y2_break(SHORTCODE)
|
||||
#define fGEN_TCG_Y2_break(SHORTCODE) gen_reset_cfi(ctx)
|
||||
#define fGEN_TCG_J2_unpause(SHORTCODE)
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
@@ -1261,6 +1367,16 @@
|
||||
gen_helper_sfadd(RdV, tcg_env, RsV, RtV, pkt_need_commit)
|
||||
#define fGEN_TCG_F2_sfsub(SHORTCODE) \
|
||||
gen_helper_sfsub(RdV, tcg_env, RsV, RtV, pkt_need_commit)
|
||||
#define fGEN_TCG_F7_vsfadd(SHORTCODE) \
|
||||
gen_helper_vsfadd(RddV, tcg_env, RssV, RttV, pkt_need_commit)
|
||||
#define fGEN_TCG_F7_vsfsub(SHORTCODE) \
|
||||
gen_helper_vsfsub(RddV, tcg_env, RssV, RttV, pkt_need_commit)
|
||||
#define fGEN_TCG_F7_vsfmpy(SHORTCODE) \
|
||||
gen_helper_vsfmpy(RddV, tcg_env, RssV, RttV, pkt_need_commit)
|
||||
#define fGEN_TCG_F7_vsffma(SHORTCODE) \
|
||||
gen_helper_vsffma(RxxV, tcg_env, RxxV, RssV, RttV, pkt_need_commit)
|
||||
#define fGEN_TCG_F7_vsffms(SHORTCODE) \
|
||||
gen_helper_vsffms(RxxV, tcg_env, RxxV, RssV, RttV, pkt_need_commit)
|
||||
#define fGEN_TCG_F2_sfcmpeq(SHORTCODE) \
|
||||
gen_helper_sfcmpeq(PdV, tcg_env, RsV, RtV, pkt_need_commit)
|
||||
#define fGEN_TCG_F2_sfcmpgt(SHORTCODE) \
|
||||
@@ -1377,6 +1493,11 @@
|
||||
RsV = RsV; \
|
||||
uiV = uiV; \
|
||||
} while (0)
|
||||
#define fGEN_TCG_Y4_dcfetch_multi(SHORTCODE) \
|
||||
do { \
|
||||
RsV = RsV; \
|
||||
RtV = RtV; \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_L2_loadw_aq(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L4_loadd_aq(SHORTCODE) SHORTCODE
|
||||
@@ -1399,4 +1520,5 @@
|
||||
#endif
|
||||
|
||||
#define fGEN_TCG_A2_nop(SHORTCODE) do { } while (0)
|
||||
#define fGEN_TCG_A2_nop_rb(SHORTCODE) gen_reset_cfi(ctx)
|
||||
#define fGEN_TCG_SA1_setin1(SHORTCODE) tcg_gen_movi_tl(RdV, -1)
|
||||
@@ -20,6 +20,9 @@
|
||||
#define fGEN_TCG_Y4_siad(SHORTCODE) \
|
||||
gen_helper_siad(tcg_env, RsV)
|
||||
|
||||
#define fGEN_TCG_Y5_tlbasidi(SHORTCODE) \
|
||||
gen_helper_tlbinvasid(tcg_env, RsV)
|
||||
|
||||
#define fGEN_TCG_Y2_iassignw(SHORTCODE) \
|
||||
gen_helper_iassignw(tcg_env, RsV)
|
||||
|
||||
@@ -131,11 +134,17 @@
|
||||
*/
|
||||
#define fGEN_TCG_J2_rte(SHORTCODE) \
|
||||
do { \
|
||||
TCGv_i32 cfi = tcg_temp_new_i32(); \
|
||||
TCGv_i32 new_ssr = tcg_temp_new_i32(); \
|
||||
tcg_gen_extract_i32(cfi, hex_t_sreg[HEX_SREG_SSR], \
|
||||
reg_field_info[SSR_CFI].offset, 1); \
|
||||
fSET_CFI(cfi); \
|
||||
tcg_gen_deposit_tl(new_ssr, hex_t_sreg[HEX_SREG_SSR], \
|
||||
tcg_constant_tl(0), \
|
||||
reg_field_info[SSR_EX].offset, \
|
||||
reg_field_info[SSR_EX].width); \
|
||||
tcg_gen_deposit_tl(new_ssr, new_ssr, tcg_constant_tl(0), \
|
||||
reg_field_info[SSR_CFI].offset, 1); \
|
||||
gen_log_sreg_write(ctx, HEX_SREG_SSR, new_ssr); \
|
||||
gen_jumpr(ctx, hex_t_sreg[HEX_SREG_ELR]); \
|
||||
} while (0)
|
||||
|
||||
@@ -698,6 +698,59 @@ static inline void gen_store_conditional8(DisasContext *ctx,
|
||||
tcg_gen_movi_tl(hex_llsc_addr, ~0);
|
||||
}
|
||||
|
||||
void gen_atomic4(DisasContext *ctx, TCGv dest, TCGv vaddr, TCGv src,
|
||||
HexAtomicOp operation)
|
||||
{
|
||||
MemOp memop = MO_LE | MO_32 | MO_ALIGN;
|
||||
|
||||
switch (operation) {
|
||||
case HEX_ATOMIC_ADD:
|
||||
tcg_gen_atomic_fetch_add_tl(dest, vaddr, src, ctx->mem_idx, memop);
|
||||
break;
|
||||
case HEX_ATOMIC_AND:
|
||||
tcg_gen_atomic_fetch_and_tl(dest, vaddr, src, ctx->mem_idx, memop);
|
||||
break;
|
||||
case HEX_ATOMIC_OR:
|
||||
tcg_gen_atomic_fetch_or_tl(dest, vaddr, src, ctx->mem_idx, memop);
|
||||
break;
|
||||
case HEX_ATOMIC_XOR:
|
||||
tcg_gen_atomic_fetch_xor_tl(dest, vaddr, src, ctx->mem_idx, memop);
|
||||
break;
|
||||
case HEX_ATOMIC_SWAP:
|
||||
tcg_gen_atomic_xchg_tl(dest, vaddr, src, ctx->mem_idx, memop);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
void gen_atomic8(DisasContext *ctx, TCGv_i64 dest, TCGv vaddr, TCGv_i64 src)
|
||||
{
|
||||
tcg_gen_atomic_xchg_i64(dest, vaddr, src, ctx->mem_idx,
|
||||
MO_LE | MO_64 | MO_ALIGN);
|
||||
}
|
||||
|
||||
void gen_vframecheck(DisasContext *ctx, TCGv vsp)
|
||||
{
|
||||
TCGLabel *write_vsp = gen_new_label();
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv mode = tcg_temp_new();
|
||||
|
||||
tcg_gen_andi_tl(mode, hex_t_sreg[HEX_SREG_SSR],
|
||||
1 << reg_field_info[SSR_EX].offset);
|
||||
tcg_gen_brcondi_tl(TCG_COND_NE, mode, 0, write_vsp);
|
||||
tcg_gen_andi_tl(mode, hex_t_sreg[HEX_SREG_SSR],
|
||||
1 << reg_field_info[SSR_UM].offset);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, mode, 0, write_vsp);
|
||||
#endif
|
||||
tcg_gen_brcond_tl(TCG_COND_GEU, vsp,
|
||||
hex_gpr[HEX_REG_VFRAMELIMIT], write_vsp);
|
||||
gen_precise_exception(HEX_CAUSE_VECTOR_STACK_OVERFLOW, ctx->pkt.pc);
|
||||
gen_set_label(write_vsp);
|
||||
tcg_gen_mov_tl(hex_gpr[HEX_REG_VSP], vsp);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_HEXAGON_IDEF_PARSER
|
||||
static TCGv gen_slotval(DisasContext *ctx)
|
||||
{
|
||||
@@ -1006,6 +1059,8 @@ static void gen_call(DisasContext *ctx, int pc_off)
|
||||
static void gen_callr(DisasContext *ctx, TCGv new_pc)
|
||||
{
|
||||
TCGv lr = get_result_gpr(ctx, HEX_REG_LR);
|
||||
|
||||
new_pc = gen_unalias_gpr_src(new_pc, lr);
|
||||
tcg_gen_movi_tl(lr, ctx->next_PC);
|
||||
gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL);
|
||||
}
|
||||
@@ -1030,6 +1085,42 @@ static void gen_cond_callr(DisasContext *ctx,
|
||||
gen_set_label(skip);
|
||||
}
|
||||
|
||||
static void gen_set_cfi(DisasContext *ctx)
|
||||
{
|
||||
fSET_CFI(tcg_constant_i32(1));
|
||||
}
|
||||
|
||||
static void gen_reset_cfi(DisasContext *ctx)
|
||||
{
|
||||
fSET_CFI(tcg_constant_i32(0));
|
||||
}
|
||||
|
||||
/* Indirect transfers through LR are returns, which do not set the CFI state */
|
||||
static void gen_set_cfi_for_target(DisasContext *ctx, int rs_num)
|
||||
{
|
||||
if (rs_num == HEX_REG_LR) {
|
||||
gen_reset_cfi(ctx);
|
||||
} else {
|
||||
gen_set_cfi(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the CFI state if the predicate (true if @sense, else false) holds.
|
||||
* @rs_num is the jump target register, or -1 for calls.
|
||||
*/
|
||||
static void gen_cond_set_cfi(DisasContext *ctx, bool sense, TCGv pred,
|
||||
int rs_num)
|
||||
{
|
||||
TCGv lsb = tcg_temp_new();
|
||||
TCGLabel *skip = gen_new_label();
|
||||
|
||||
tcg_gen_andi_tl(lsb, pred, 1);
|
||||
tcg_gen_brcondi_tl(sense ? TCG_COND_EQ : TCG_COND_NE, lsb, 0, skip);
|
||||
gen_set_cfi_for_target(ctx, rs_num);
|
||||
gen_set_label(skip);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_HEXAGON_IDEF_PARSER
|
||||
/* frame = ((LR << 32) | FP) ^ (FRAMEKEY << 32)) */
|
||||
static TCGv_i64 gen_frame_scramble(void)
|
||||
|
||||
@@ -58,6 +58,18 @@ TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign);
|
||||
TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign);
|
||||
void gen_set_half(int N, TCGv result, TCGv src);
|
||||
void gen_set_half_i64(int N, TCGv_i64 result, TCGv src);
|
||||
typedef enum {
|
||||
HEX_ATOMIC_ADD,
|
||||
HEX_ATOMIC_AND,
|
||||
HEX_ATOMIC_OR,
|
||||
HEX_ATOMIC_XOR,
|
||||
HEX_ATOMIC_SWAP,
|
||||
} HexAtomicOp;
|
||||
|
||||
void gen_atomic4(DisasContext *ctx, TCGv dest, TCGv vaddr, TCGv src,
|
||||
HexAtomicOp operation);
|
||||
void gen_atomic8(DisasContext *ctx, TCGv_i64 dest, TCGv vaddr, TCGv_i64 src);
|
||||
void gen_vframecheck(DisasContext *ctx, TCGv vsp);
|
||||
void probe_noshuf_load(TCGv va, int s, int mi);
|
||||
void gen_gvec_sabsdiff_var(unsigned vece, TCGv_ptr dbase, uint32_t dofs,
|
||||
TCGv_ptr abase, uint32_t aofs,
|
||||
|
||||
@@ -60,6 +60,11 @@ DEF_HELPER_3(conv_df2ud_chop, i64, env, f64, i32)
|
||||
DEF_HELPER_3(conv_df2d_chop, s64, env, f64, i32)
|
||||
DEF_HELPER_4(sfadd, f32, env, f32, f32, i32)
|
||||
DEF_HELPER_4(sfsub, f32, env, f32, f32, i32)
|
||||
DEF_HELPER_4(vsfadd, i64, env, i64, i64, i32)
|
||||
DEF_HELPER_4(vsfsub, i64, env, i64, i64, i32)
|
||||
DEF_HELPER_4(vsfmpy, i64, env, i64, i64, i32)
|
||||
DEF_HELPER_5(vsffma, i64, env, i64, i64, i64, i32)
|
||||
DEF_HELPER_5(vsffms, i64, env, i64, i64, i64, i32)
|
||||
DEF_HELPER_4(sfcmpeq, s32, env, f32, f32, i32)
|
||||
DEF_HELPER_4(sfcmpgt, s32, env, f32, f32, i32)
|
||||
DEF_HELPER_4(sfcmpge, s32, env, f32, f32, i32)
|
||||
@@ -143,4 +148,5 @@ DEF_HELPER_2(resume, void, env, i32)
|
||||
DEF_HELPER_1(resched, void, env)
|
||||
DEF_HELPER_3(modify_ssr, void, env, i32, i32)
|
||||
DEF_HELPER_1(pending_interrupt, void, env)
|
||||
DEF_HELPER_2(tlbinvasid, void, env, i32)
|
||||
#endif
|
||||
@@ -48,6 +48,7 @@ static void set_ssr_ex_cause(CPUHexagonState *env, int ex, uint32_t cause)
|
||||
old = env->t_sreg[HEX_SREG_SSR];
|
||||
SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_EX, ex);
|
||||
SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_CAUSE, cause);
|
||||
SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_CFI, env->cfi_active);
|
||||
new = env->t_sreg[HEX_SREG_SSR];
|
||||
hexagon_modify_ssr(env, new, old);
|
||||
}
|
||||
@@ -373,6 +374,8 @@ static void hex_accept_int(CPUHexagonState *env, int int_num)
|
||||
env->threadId);
|
||||
|
||||
set_ssr_ex_cause(env, 1, HEX_CAUSE_INT0 | int_num);
|
||||
env->cfi_active = 0;
|
||||
env->cfi_updated = 0;
|
||||
set_elr(env, elr);
|
||||
env->gpr[HEX_REG_PC] = evb | (cs->exception_index << 2);
|
||||
}
|
||||
@@ -386,17 +389,19 @@ bool hex_check_interrupts(CPUHexagonState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
bool int_handled = false;
|
||||
bool ssr_ex = get_ssr_ex(env);
|
||||
bool ssr_ex;
|
||||
int max_ints = 32;
|
||||
bool schedcfgen;
|
||||
|
||||
BQL_LOCK_GUARD();
|
||||
|
||||
ssr_ex = get_ssr_ex(env);
|
||||
|
||||
/* Early exit if nothing pending */
|
||||
if (get_ipend(env) == 0) {
|
||||
restore_state(env, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
BQL_LOCK_GUARD();
|
||||
/* Only check priorities when schedcfgen is set */
|
||||
schedcfgen = get_schedcfgen(env);
|
||||
for (int i = 0; i < max_ints; i++) {
|
||||
|
||||
@@ -29,6 +29,11 @@ static inline void hex_log_tlbw(uint32_t index, uint64_t entry)
|
||||
index, entry);
|
||||
}
|
||||
|
||||
static void hex_tlb_flush_all(CPUState *cs)
|
||||
{
|
||||
tlb_flush_by_mmuidx_all_cpus_synced(cs, MMU_IDX_ALL);
|
||||
}
|
||||
|
||||
void hex_tlbw(CPUHexagonState *env, uint32_t index, uint64_t value)
|
||||
{
|
||||
uint32_t myidx = fTLB_NONPOW2WRAP(fTLB_IDXMASK(index));
|
||||
@@ -36,12 +41,24 @@ void hex_tlbw(CPUHexagonState *env, uint32_t index, uint64_t value)
|
||||
uint64_t old_entry = hexagon_tlb_write(tlb, myidx, value);
|
||||
bool old_entry_valid = extract64(old_entry, 63, 1);
|
||||
if (old_entry_valid && hexagon_cpu_mmu_enabled(env)) {
|
||||
CPUState *cs = env_cpu(env);
|
||||
tlb_flush_all_cpus_synced(cs);
|
||||
hex_tlb_flush_all(env_cpu(env));
|
||||
}
|
||||
hex_log_tlbw(myidx, value);
|
||||
}
|
||||
|
||||
void hex_tlb_invalidate_asid(CPUHexagonState *env, uint32_t asid)
|
||||
{
|
||||
HexagonTLBState *tlb = env_archcpu(env)->tlb;
|
||||
uint32_t invalidated = hexagon_tlb_invalidate_asid(tlb, asid);
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU,
|
||||
"tlbinvasid: asid 0x%02" PRIx32 ", %" PRIu32 " entries\n",
|
||||
asid, invalidated);
|
||||
if (invalidated && hexagon_cpu_mmu_enabled(env)) {
|
||||
hex_tlb_flush_all(env_cpu(env));
|
||||
}
|
||||
}
|
||||
|
||||
void hex_mmu_on(CPUHexagonState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
@@ -56,11 +73,12 @@ void hex_mmu_off(CPUHexagonState *env)
|
||||
tlb_flush(cs);
|
||||
}
|
||||
|
||||
void hex_mmu_mode_change(CPUHexagonState *env)
|
||||
void hex_mmu_asid_change(CPUHexagonState *env)
|
||||
{
|
||||
qemu_log_mask(CPU_LOG_MMU, "Hexagon mode change!\n");
|
||||
CPUState *cs = env_cpu(env);
|
||||
tlb_flush(cs);
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU, "Hexagon ASID change!\n");
|
||||
tlb_flush_by_mmuidx(cs, MMU_IDX_ALL);
|
||||
}
|
||||
|
||||
bool hex_tlb_find_match(CPUHexagonState *env, uint32_t VA,
|
||||
|
||||
@@ -13,10 +13,11 @@
|
||||
#include "monitor/hmp.h"
|
||||
|
||||
extern void hex_tlbw(CPUHexagonState *env, uint32_t index, uint64_t value);
|
||||
extern void hex_tlb_invalidate_asid(CPUHexagonState *env, uint32_t asid);
|
||||
extern uint32_t hex_tlb_lookup(CPUHexagonState *env, uint32_t ssr, uint32_t VA);
|
||||
extern void hex_mmu_on(CPUHexagonState *env);
|
||||
extern void hex_mmu_off(CPUHexagonState *env);
|
||||
extern void hex_mmu_mode_change(CPUHexagonState *env);
|
||||
extern void hex_mmu_asid_change(CPUHexagonState *env);
|
||||
extern bool hex_tlb_find_match(CPUHexagonState *env, uint32_t VA,
|
||||
MMUAccessType access_type, hwaddr *PA, int *prot,
|
||||
uint64_t *size, int32_t *excp, int mmu_idx);
|
||||
|
||||
@@ -77,6 +77,8 @@ enum {
|
||||
HEX_REG_QEMU_PKT_CNT = 52,
|
||||
HEX_REG_QEMU_INSN_CNT = 53,
|
||||
HEX_REG_QEMU_HVX_CNT = 54,
|
||||
HEX_REG_VFRAMELIMIT = 60,
|
||||
HEX_REG_VSP = 61,
|
||||
HEX_REG_UTIMERLO = 62,
|
||||
HEX_REG_UTIMERHI = 63,
|
||||
};
|
||||
|
||||
+111
-57
@@ -28,6 +28,7 @@
|
||||
#include "semihosting/console.h"
|
||||
#include "semihosting/syscalls.h"
|
||||
#include "semihosting/guestfd.h"
|
||||
#include "semihosting/uaccess.h"
|
||||
#include "system/runstate.h"
|
||||
|
||||
/* non-arm-compatible semihosting calls */
|
||||
@@ -168,14 +169,18 @@ static void init_semihosting_guestfds(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void do_preload(CPUHexagonState *env, target_ulong swi_info, bool load)
|
||||
static bool do_preload(CPUHexagonState *env, target_ulong swi_info)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
uint32_t addr, count;
|
||||
uintptr_t retaddr = 0;
|
||||
|
||||
hexagon_read_memory(env, swi_info + 4, 4, &addr, retaddr);
|
||||
hexagon_read_memory(env, swi_info + 8, 4, &count, retaddr);
|
||||
if (get_user_u32(addr, swi_info + 4) ||
|
||||
get_user_u32(count, swi_info + 8)) {
|
||||
return false;
|
||||
}
|
||||
hexagon_peek_memory_range(env, addr, count, retaddr);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Hexagon semihosting errno values */
|
||||
@@ -366,6 +371,10 @@ static void coredump(CPUHexagonState *env)
|
||||
fprintf(f, "0x%x, Stack limit check error",
|
||||
HEX_CAUSE_STACK_LIMIT);
|
||||
break;
|
||||
case HEX_CAUSE_VECTOR_STACK_OVERFLOW:
|
||||
fprintf(f, "0x%x, Vector stack overflow",
|
||||
HEX_CAUSE_VECTOR_STACK_OVERFLOW);
|
||||
break;
|
||||
case HEX_CAUSE_FPTRAP_CAUSE_BADFLOAT:
|
||||
fprintf(f, "0x%x, Floating-Point: Execution of Floating-Point "
|
||||
"instruction resulted in exception",
|
||||
@@ -429,7 +438,10 @@ static void sim_handle_trap0(CPUHexagonState *env)
|
||||
* the input address. The contents of that buffer will be
|
||||
* directed to the SWI interface.
|
||||
*/
|
||||
do_preload(env, swi_info, (what_swi == HEX_SYS_WRITE));
|
||||
if (!do_preload(env, swi_info)) {
|
||||
semi_cb(cs, -1, EFAULT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* ARM-compat semihosting SWI numbers are all <= 0x31.
|
||||
@@ -461,31 +473,28 @@ static void sim_handle_trap0(CPUHexagonState *env)
|
||||
|
||||
case HEX_SYS_OPEN:
|
||||
{
|
||||
char filename[BUFSIZ];
|
||||
char *filename;
|
||||
target_ulong physical_filename_addr;
|
||||
unsigned int filemode;
|
||||
int length;
|
||||
uint32_t filename_len;
|
||||
size_t filename_size;
|
||||
int real_openmode;
|
||||
int ret, err = 0;
|
||||
int i = 0;
|
||||
|
||||
hexagon_read_memory(env, swi_info, 4, &physical_filename_addr, retaddr);
|
||||
hexagon_read_memory(env, swi_info + 4, 4, &filemode, retaddr);
|
||||
hexagon_read_memory(env, swi_info + 8, 4, &length, retaddr);
|
||||
|
||||
if (length >= BUFSIZ) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: filename too large (%d)\n",
|
||||
__func__, length);
|
||||
semi_cb(cs, -1, ENAMETOOLONG);
|
||||
break;
|
||||
if (get_user_u32(physical_filename_addr, swi_info) ||
|
||||
get_user_u32(filemode, swi_info + 4) ||
|
||||
get_user_u32(filename_len, swi_info + 8)) {
|
||||
goto do_fault;
|
||||
}
|
||||
|
||||
do {
|
||||
hexagon_read_memory(env, physical_filename_addr + i, 1,
|
||||
&filename[i], retaddr);
|
||||
i++;
|
||||
} while (filename[i - 1]);
|
||||
/* The ABI length excludes the filename's terminating NUL. */
|
||||
filename_size = (size_t)filename_len + 1;
|
||||
filename = lock_user(VERIFY_READ, physical_filename_addr,
|
||||
filename_size, true);
|
||||
if (!filename || filename[filename_len] != '\0') {
|
||||
unlock_user(filename, physical_filename_addr, 0);
|
||||
goto do_fault;
|
||||
}
|
||||
|
||||
/* convert ARM ANGEL filemode into host filemode */
|
||||
if (filemode < ARRAY_SIZE(angel_to_host_filemode_table)) {
|
||||
@@ -494,6 +503,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid OPEN mode: %u\n",
|
||||
__func__, filemode);
|
||||
unlock_user(filename, physical_filename_addr, 0);
|
||||
semi_cb(cs, -1, EINVAL);
|
||||
break;
|
||||
}
|
||||
@@ -513,6 +523,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
|
||||
ret = guestfd;
|
||||
}
|
||||
}
|
||||
unlock_user(filename, physical_filename_addr, 0);
|
||||
semi_cb(cs, ret, err);
|
||||
}
|
||||
break;
|
||||
@@ -531,7 +542,9 @@ static void sim_handle_trap0(CPUHexagonState *env)
|
||||
case HEX_SYS_ISTTY:
|
||||
{
|
||||
int fd;
|
||||
hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
|
||||
if (get_user_u32(fd, swi_info)) {
|
||||
goto do_fault;
|
||||
}
|
||||
semi_cb(cs, isatty(fd), 0);
|
||||
}
|
||||
break;
|
||||
@@ -540,8 +553,10 @@ static void sim_handle_trap0(CPUHexagonState *env)
|
||||
{
|
||||
int fd;
|
||||
target_ulong off;
|
||||
hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
|
||||
hexagon_read_memory(env, swi_info + 4, 4, &off, retaddr);
|
||||
if (get_user_u32(fd, swi_info) ||
|
||||
get_user_u32(off, swi_info + 4)) {
|
||||
goto do_fault;
|
||||
}
|
||||
semihost_sys_lseek(env_cpu(env), common_semi_ftell_cb, fd, off,
|
||||
GDB_SEEK_SET);
|
||||
}
|
||||
@@ -553,20 +568,23 @@ static void sim_handle_trap0(CPUHexagonState *env)
|
||||
struct stat st_buf;
|
||||
uint8_t *st_bufptr = (uint8_t *)&sys_stat;
|
||||
int rc, err = 0;
|
||||
char filename[BUFSIZ];
|
||||
char *filename;
|
||||
target_ulong physical_filename_addr;
|
||||
target_ulong statBufferAddr;
|
||||
hexagon_read_memory(env, swi_info, 4, &physical_filename_addr, retaddr);
|
||||
if (get_user_u32(physical_filename_addr, swi_info) ||
|
||||
get_user_u32(statBufferAddr, swi_info + 4)) {
|
||||
goto do_fault;
|
||||
}
|
||||
|
||||
if (what_swi == HEX_SYS_STAT) {
|
||||
int i = 0;
|
||||
do {
|
||||
hexagon_read_memory(env, physical_filename_addr + i, 1,
|
||||
&filename[i], retaddr);
|
||||
i++;
|
||||
} while ((i < BUFSIZ) && filename[i - 1]);
|
||||
filename = lock_user_string(physical_filename_addr);
|
||||
if (!filename) {
|
||||
semi_cb(cs, -1, EFAULT);
|
||||
break;
|
||||
}
|
||||
rc = stat(filename, &st_buf);
|
||||
err = errno;
|
||||
unlock_user(filename, physical_filename_addr, 0);
|
||||
} else {
|
||||
int fd = physical_filename_addr;
|
||||
GuestFD *gf = get_guestfd(fd);
|
||||
@@ -590,8 +608,6 @@ static void sim_handle_trap0(CPUHexagonState *env)
|
||||
sys_stat.mtime = cpu_to_le32(st_buf.st_mtime);
|
||||
sys_stat.ctime = cpu_to_le32(st_buf.st_ctime);
|
||||
}
|
||||
hexagon_read_memory(env, swi_info + 4, 4, &statBufferAddr, retaddr);
|
||||
|
||||
for (int i = 0; i < sizeof(sys_stat); i++) {
|
||||
hexagon_write_memory(env, statBufferAddr + i, 1, st_bufptr[i],
|
||||
retaddr);
|
||||
@@ -604,33 +620,34 @@ static void sim_handle_trap0(CPUHexagonState *env)
|
||||
{
|
||||
int fd;
|
||||
off_t size_limit;
|
||||
hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
|
||||
hexagon_read_memory(env, swi_info + 4, 8, &size_limit, retaddr);
|
||||
if (get_user_u32(fd, swi_info) ||
|
||||
get_user_u64(size_limit, swi_info + 4)) {
|
||||
goto do_fault;
|
||||
}
|
||||
semihost_sys_ftruncate(cs, semi_cb, fd, size_limit);
|
||||
}
|
||||
break;
|
||||
|
||||
case HEX_SYS_ACCESS:
|
||||
{
|
||||
char filename[BUFSIZ];
|
||||
char *filename;
|
||||
uint32_t FileNameAddr;
|
||||
uint32_t BufferMode;
|
||||
int rc;
|
||||
|
||||
int i = 0;
|
||||
|
||||
hexagon_read_memory(env, swi_info, 4, &FileNameAddr, retaddr);
|
||||
do {
|
||||
hexagon_read_memory(env, FileNameAddr + i, 1, &filename[i],
|
||||
retaddr);
|
||||
i++;
|
||||
} while ((i < BUFSIZ) && (filename[i - 1]));
|
||||
filename[i] = 0;
|
||||
|
||||
hexagon_read_memory(env, swi_info + 4, 4, &BufferMode, retaddr);
|
||||
int rc, err;
|
||||
|
||||
if (get_user_u32(FileNameAddr, swi_info) ||
|
||||
get_user_u32(BufferMode, swi_info + 4)) {
|
||||
goto do_fault;
|
||||
}
|
||||
filename = lock_user_string(FileNameAddr);
|
||||
if (!filename) {
|
||||
semi_cb(cs, -1, EFAULT);
|
||||
break;
|
||||
}
|
||||
rc = access(filename, BufferMode);
|
||||
semi_cb(cs, rc, rc == 0 ? 0 : errno);
|
||||
err = errno;
|
||||
unlock_user(filename, FileNameAddr, 0);
|
||||
semi_cb(cs, rc, rc == 0 ? 0 : err);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -641,8 +658,10 @@ static void sim_handle_trap0(CPUHexagonState *env)
|
||||
uint32_t BufferSize;
|
||||
uint32_t rc = 0, err = 0;
|
||||
|
||||
hexagon_read_memory(env, swi_info, 4, &BufferAddr, retaddr);
|
||||
hexagon_read_memory(env, swi_info + 4, 4, &BufferSize, retaddr);
|
||||
if (get_user_u32(BufferAddr, swi_info) ||
|
||||
get_user_u32(BufferSize, swi_info + 4)) {
|
||||
goto do_fault;
|
||||
}
|
||||
|
||||
if (!getcwd(cwdPtr, PATH_MAX)) {
|
||||
err = errno;
|
||||
@@ -676,7 +695,9 @@ static void sim_handle_trap0(CPUHexagonState *env)
|
||||
case HEX_SYS_FTELL:
|
||||
{
|
||||
int fd;
|
||||
hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
|
||||
if (get_user_u32(fd, swi_info)) {
|
||||
goto do_fault;
|
||||
}
|
||||
semihost_sys_lseek(cs, common_semi_ftell_cb, fd, 0, GDB_SEEK_CUR);
|
||||
}
|
||||
break;
|
||||
@@ -720,6 +741,11 @@ static void sim_handle_trap0(CPUHexagonState *env)
|
||||
"unknown swi request: 0x%" PRIx32 "\n",
|
||||
(uint32_t)what_swi);
|
||||
semi_cb(cs, -1, ENOSYS);
|
||||
break;
|
||||
|
||||
do_fault:
|
||||
semi_cb(cs, -1, EFAULT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,7 +779,17 @@ void hexagon_cpu_do_interrupt(CPUState *cs)
|
||||
env->llsc_addr = ~0;
|
||||
|
||||
ssr = env->t_sreg[HEX_SREG_SSR];
|
||||
if (GET_SSR_FIELD(SSR_EX, ssr) == 0) {
|
||||
SET_SSR_FIELD(env, SSR_CFI, env->cfi_active);
|
||||
}
|
||||
env->cfi_active = 0;
|
||||
env->cfi_updated = 0;
|
||||
|
||||
if (GET_SSR_FIELD(SSR_EX, ssr) == 1) {
|
||||
/*
|
||||
* Double exception: keep the SSR.CFI value saved by the first
|
||||
* exception, which a later rte would need to restore.
|
||||
*/
|
||||
if (cpu->globalregs) {
|
||||
hexagon_globalreg_write(cpu->globalregs, HEX_SREG_DIAG,
|
||||
env->cause_code, env->threadId);
|
||||
@@ -777,6 +813,11 @@ void hexagon_cpu_do_interrupt(CPUState *cs)
|
||||
set_addresses(env, 4, cs->exception_index);
|
||||
break;
|
||||
|
||||
case HEX_EVENT_TRAP2:
|
||||
hexagon_ssr_set_cause(env, env->cause_code);
|
||||
set_addresses(env, 4, cs->exception_index);
|
||||
break;
|
||||
|
||||
case HEX_EVENT_TLB_MISS_X:
|
||||
switch (env->cause_code) {
|
||||
case HEX_CAUSE_TLBMISSX_CAUSE_NORMAL:
|
||||
@@ -846,13 +887,13 @@ void hexagon_cpu_do_interrupt(CPUState *cs)
|
||||
case HEX_EVENT_DEBUG:
|
||||
hexagon_ssr_set_cause(env, env->cause_code);
|
||||
set_addresses(env, 0, cs->exception_index);
|
||||
qemu_log_mask(LOG_UNIMP, "single-step exception is not handled\n");
|
||||
break;
|
||||
|
||||
case HEX_EVENT_PRECISE:
|
||||
switch (env->cause_code) {
|
||||
case HEX_CAUSE_FETCH_NO_XPAGE:
|
||||
case HEX_CAUSE_FETCH_NO_UPAGE:
|
||||
case HEX_CAUSE_CFI_VIOLATION:
|
||||
case HEX_CAUSE_PRIV_NO_READ:
|
||||
case HEX_CAUSE_PRIV_NO_UREAD:
|
||||
case HEX_CAUSE_PRIV_NO_WRITE:
|
||||
@@ -883,6 +924,7 @@ void hexagon_cpu_do_interrupt(CPUState *cs)
|
||||
case HEX_CAUSE_NO_COPROC_ENABLE:
|
||||
case HEX_CAUSE_NO_COPROC2_ENABLE:
|
||||
case HEX_CAUSE_UNSUPPORTED_HVX_64B:
|
||||
case HEX_CAUSE_VECTOR_STACK_OVERFLOW:
|
||||
case HEX_CAUSE_REG_WRITE_CONFLICT:
|
||||
case HEX_CAUSE_VWCTRL_WINDOW_MISS:
|
||||
hexagon_ssr_set_cause(env, env->cause_code);
|
||||
@@ -963,7 +1005,19 @@ void register_trap_exception(CPUHexagonState *env, int traptype, int imm,
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
cs->exception_index = (traptype == 0) ? HEX_EVENT_TRAP0 : HEX_EVENT_TRAP1;
|
||||
switch (traptype) {
|
||||
case 0:
|
||||
cs->exception_index = HEX_EVENT_TRAP0;
|
||||
break;
|
||||
case 1:
|
||||
cs->exception_index = HEX_EVENT_TRAP1;
|
||||
break;
|
||||
case 2:
|
||||
cs->exception_index = HEX_EVENT_TRAP2;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index);
|
||||
|
||||
env->cause_code = imm;
|
||||
|
||||
@@ -50,6 +50,7 @@ SlotMask find_iclass_slots(Opcode opcode, int itype)
|
||||
} else if (GET_ATTRIB(opcode, A_RESTRICT_NOSLOT1)) {
|
||||
return SLOTS_0;
|
||||
} else if ((opcode == J2_trap0) ||
|
||||
(opcode == J2_trap2) ||
|
||||
(opcode == Y2_isync) ||
|
||||
(opcode == J2_pause)) {
|
||||
return SLOTS_2;
|
||||
|
||||
@@ -161,6 +161,7 @@ STRING_LIT \"(\\.|[^"\\])*\"
|
||||
"fFRAME_SCRAMBLE" |
|
||||
"fFRAME_UNSCRAMBLE" { return FSCR; }
|
||||
"fFRAMECHECK" { return FCHK; }
|
||||
"fVFRAMECHECK" { return VFCHK; }
|
||||
"Constant_extended" { return CONSTEXT; }
|
||||
"fCL1_"{DIGIT} { return LOCNT; }
|
||||
"fbrev" { return BREV; }
|
||||
@@ -329,6 +330,13 @@ STRING_LIT \"(\\.|[^"\\])*\"
|
||||
yylval->rvalue.bit_width = 32;
|
||||
yylval->rvalue.signedness = UNSIGNED;
|
||||
return REG; }
|
||||
"VSP" { yylval->rvalue.type = REGISTER;
|
||||
yylval->rvalue.reg.type = GENERAL_PURPOSE;
|
||||
yylval->rvalue.reg.id = HEX_REG_VSP;
|
||||
yylval->rvalue.reg.bit_width = 32;
|
||||
yylval->rvalue.bit_width = 32;
|
||||
yylval->rvalue.signedness = UNSIGNED;
|
||||
return REG; }
|
||||
"fREAD_FP()" |
|
||||
"FP" { yylval->rvalue.type = REGISTER;
|
||||
yylval->rvalue.reg.type = GENERAL_PURPOSE;
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
%token IN INAME VAR
|
||||
%token ABS CROUND ROUND CIRCADD COUNTONES INC DEC ANDA ORA XORA PLUSPLUS ASL
|
||||
%token ASR LSR EQ NEQ LTE GTE MIN MAX ANDL FOR ICIRC IF MUN FSCR FCHK SXT
|
||||
%token ASR LSR EQ NEQ LTE GTE MIN MAX ANDL FOR ICIRC IF MUN FSCR FCHK VFCHK SXT
|
||||
%token ZXT CONSTEXT LOCNT BREV SIGN LOAD STORE PC LPCFG
|
||||
%token LOAD_CANCEL STORE_CANCEL CANCEL IDENTITY ROTL INSBITS SETBITS EXTRANGE
|
||||
%token CAST4_8U FAIL CARRY_FROM_ADD ADDSAT64 LSBNEW
|
||||
@@ -398,6 +398,7 @@ assign_statement : lvalue '=' rvalue
|
||||
;
|
||||
|
||||
control_statement : frame_check
|
||||
| vframe_check
|
||||
| cancel_statement
|
||||
| if_statement
|
||||
| for_statement
|
||||
@@ -409,6 +410,12 @@ frame_check : FCHK '(' rvalue ',' rvalue ')' ';'
|
||||
}
|
||||
;
|
||||
|
||||
vframe_check : VFCHK '(' rvalue ',' rvalue ')' ';'
|
||||
{
|
||||
gen_vframecheck(c, &@1, &$3);
|
||||
}
|
||||
;
|
||||
|
||||
cancel_statement : LOAD_CANCEL
|
||||
{
|
||||
gen_load_cancel(c, &@1);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "hex_regs.h"
|
||||
#include "idef-parser.h"
|
||||
#include "parser-helpers.h"
|
||||
#include "idef-parser.tab.h"
|
||||
@@ -1313,6 +1314,11 @@ void gen_write_reg(Context *c, YYLTYPE *locp, HexValue *reg, HexValue *value)
|
||||
yyassert(c, locp, reg->type == REGISTER, "reg must be a register!");
|
||||
value_m = gen_rvalue_truncate(c, locp, &value_m);
|
||||
value_m = rvalue_materialize(c, locp, &value_m);
|
||||
if (reg->reg.id == HEX_REG_VSP) {
|
||||
OUT(c, locp, "tcg_gen_mov_tl(hex_gpr[HEX_REG_VSP], ", &value_m,
|
||||
");\n");
|
||||
return;
|
||||
}
|
||||
OUT(c,
|
||||
locp,
|
||||
"tcg_gen_mov_tl(get_result_gpr(ctx, ", ®->reg.id, "), ",
|
||||
@@ -1740,6 +1746,14 @@ void gen_framecheck(Context *c, YYLTYPE *locp, HexValue *addr, HexValue *ea)
|
||||
OUT(c, locp, "gen_framecheck(ctx, ", &addr_m, ", ", &ea_m, ");\n");
|
||||
}
|
||||
|
||||
void gen_vframecheck(Context *c, YYLTYPE *locp, HexValue *addr)
|
||||
{
|
||||
HexValue addr_m = rvalue_materialize(c, locp, addr);
|
||||
|
||||
addr_m = gen_rvalue_truncate(c, locp, &addr_m);
|
||||
OUT(c, locp, "gen_vframecheck(ctx, ", &addr_m, ");\n");
|
||||
}
|
||||
|
||||
void gen_load(Context *c, YYLTYPE *locp, HexValue *width,
|
||||
HexSignedness signedness, HexValue *ea, HexValue *dst)
|
||||
{
|
||||
@@ -1989,7 +2003,7 @@ HexValue gen_rvalue_fscr(Context *c, YYLTYPE *locp, HexValue *value)
|
||||
*value = gen_rvalue_extend(c, locp, value);
|
||||
OUT(c, locp, "gen_read_reg(", &frame_key, ", HEX_REG_FRAMEKEY);\n");
|
||||
OUT(c, locp, "tcg_gen_concat_i32_i64(",
|
||||
&key, ", ", &frame_key, ", ", &frame_key, ");\n");
|
||||
&key, ", tcg_constant_tl(0), ", &frame_key, ");\n");
|
||||
OUT(c, locp, "tcg_gen_xor_i64(", &res, ", ", value, ", ", &key, ");\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -296,6 +296,7 @@ void gen_cancel(Context *c, YYLTYPE *locp);
|
||||
void gen_load_cancel(Context *c, YYLTYPE *locp);
|
||||
|
||||
void gen_framecheck(Context *c, YYLTYPE *locp, HexValue *addr, HexValue *ea);
|
||||
void gen_vframecheck(Context *c, YYLTYPE *locp, HexValue *addr);
|
||||
|
||||
void gen_load(Context *c, YYLTYPE *locp, HexValue *size,
|
||||
HexSignedness signedness, HexValue *ea, HexValue *dst);
|
||||
|
||||
@@ -241,6 +241,9 @@ Q6INSN(A2_minup,"Rdd32=minu(Rtt32,Rss32)",ATTRIBS(A_ARCHV3),
|
||||
Q6INSN(A2_nop,"nop",ATTRIBS(A_IT_NOP),
|
||||
"Nop (32-bit encoding)",
|
||||
fHIDE( { } ))
|
||||
Q6INSN(A2_nop_rb,"nop_rb",ATTRIBS(A_IT_NOP,A_RESTRICT_TARGET),
|
||||
"Restricted branch nop target",
|
||||
fHIDE( { } ))
|
||||
|
||||
|
||||
Q6INSN(A4_ext,"immext(#u26:6)",ATTRIBS(A_IT_EXTENDER),
|
||||
|
||||
@@ -37,6 +37,19 @@ Q6INSN(J2_jumpr,"jumpr Rs32",ATTRIBS(A_JINDIR), "indirect unconditional jump",
|
||||
Q6INSN(J2_jumprh,"jumprh Rs32",ATTRIBS(A_JINDIR, A_HINTED_COF), "indirect unconditional jump",
|
||||
{fJUMPR(RsN,RsV,COF_TYPE_JUMPR);})
|
||||
|
||||
Q6INSN(J2_jumpr_rb,"jumpr_rb Rs32",ATTRIBS(A_JINDIR),
|
||||
"restricted indirect unconditional jump",
|
||||
{fJUMPR(RsN,RsV,COF_TYPE_JUMPR);})
|
||||
Q6INSN(J2_jumprh_rb,"jumprh_rb Rs32",ATTRIBS(A_JINDIR, A_HINTED_COF),
|
||||
"restricted hinted indirect unconditional jump",
|
||||
{fJUMPR(RsN,RsV,COF_TYPE_JUMPR);})
|
||||
|
||||
#define OLDCOND_JUMP_RB(TAG,OPER,OPER2,ATTRIB,DESCR,SEMANTICS) \
|
||||
Q6INSN(TAG##t_rb,"if (Pu4) "OPER":nt "OPER2,ATTRIB,DESCR,{fBRANCH_SPECULATE_STALL(fLSBOLD(PuV),,SPECULATE_NOT_TAKEN,12,0); if (fLSBOLD(PuV)) { SEMANTICS; }}) \
|
||||
Q6INSN(TAG##f_rb,"if (!Pu4) "OPER":nt "OPER2,ATTRIB,DESCR,{fBRANCH_SPECULATE_STALL(fLSBOLDNOT(PuV),,SPECULATE_NOT_TAKEN,12,0); if (fLSBOLDNOT(PuV)) { SEMANTICS; }}) \
|
||||
Q6INSN(TAG##tpt_rb,"if (Pu4) "OPER":t "OPER2,ATTRIB,DESCR,{fBRANCH_SPECULATE_STALL(fLSBOLD(PuV),,SPECULATE_TAKEN,12,0); if (fLSBOLD(PuV)) { SEMANTICS; }}) \
|
||||
Q6INSN(TAG##fpt_rb,"if (!Pu4) "OPER":t "OPER2,ATTRIB,DESCR,{fBRANCH_SPECULATE_STALL(fLSBOLDNOT(PuV),,SPECULATE_TAKEN,12,0); if (fLSBOLDNOT(PuV)) { SEMANTICS; }})
|
||||
|
||||
#define OLDCOND_JUMP(TAG,OPER,OPER2,ATTRIB,DESCR,SEMANTICS) \
|
||||
Q6INSN(TAG##t,"if (Pu4) "OPER":nt "OPER2,ATTRIB,DESCR,{fBRANCH_SPECULATE_STALL(fLSBOLD(PuV),,SPECULATE_NOT_TAKEN,12,0); if (fLSBOLD(PuV)) { SEMANTICS; }}) \
|
||||
Q6INSN(TAG##f,"if (!Pu4) "OPER":nt "OPER2,ATTRIB,DESCR,{fBRANCH_SPECULATE_STALL(fLSBOLDNOT(PuV),,SPECULATE_NOT_TAKEN,12,0); if (fLSBOLDNOT(PuV)) { SEMANTICS; }}) \
|
||||
@@ -48,6 +61,9 @@ fIMMEXT(riV);fPCALIGN(riV); fBRANCH(fREAD_PC()+riV,COF_TYPE_JUMP);)
|
||||
|
||||
OLDCOND_JUMP(J2_jumpr,"jumpr","Rs32",ATTRIBS(A_JINDIROLD),"indirect conditional jump",
|
||||
fJUMPR(RsN,RsV,COF_TYPE_JUMPR);)
|
||||
OLDCOND_JUMP_RB(J2_jumpr,"jumpr_rb","Rs32",ATTRIBS(A_JINDIROLD),
|
||||
"restricted indirect conditional jump",
|
||||
fJUMPR(RsN,RsV,COF_TYPE_JUMPR);)
|
||||
|
||||
#define NEWCOND_JUMP(TAG,OPER,OPER2,ATTRIB,DESCR,SEMANTICS)\
|
||||
Q6INSN(TAG##tnew,"if (Pu4.new) "OPER":nt "OPER2,ATTRIB,DESCR,{fBRANCH_SPECULATE_STALL(fLSBNEW(PuN),, SPECULATE_NOT_TAKEN , 12,0)} {if(fLSBNEW(PuN)){SEMANTICS;}})\
|
||||
@@ -61,6 +77,17 @@ fIMMEXT(riV); fPCALIGN(riV); fBRANCH(fREAD_PC()+riV,COF_TYPE_JUMPNEW);)
|
||||
NEWCOND_JUMP(J2_jumpr,"jumpr","Rs32",ATTRIBS(A_JINDIRNEW,A_ARCHV3),"indirect conditional jump",
|
||||
fJUMPR(RsN,RsV,COF_TYPE_JUMPR);)
|
||||
|
||||
#define NEWCOND_JUMP_RB(TAG,OPER,OPER2,ATTRIB,DESCR,SEMANTICS) \
|
||||
Q6INSN(TAG##tnew_rb,"if (Pu4.new) "OPER":nt "OPER2,ATTRIB,DESCR,{fBRANCH_SPECULATE_STALL(fLSBNEW(PuN),, SPECULATE_NOT_TAKEN , 12,0)} {if(fLSBNEW(PuN)){SEMANTICS;}}) \
|
||||
Q6INSN(TAG##fnew_rb,"if (!Pu4.new) "OPER":nt "OPER2,ATTRIB,DESCR,{fBRANCH_SPECULATE_STALL(fLSBNEWNOT(PuN),, SPECULATE_NOT_TAKEN , 12,0)} {if(fLSBNEWNOT(PuN)){SEMANTICS;}}) \
|
||||
Q6INSN(TAG##tnewpt_rb,"if (Pu4.new) "OPER":t "OPER2,ATTRIB,DESCR,{fBRANCH_SPECULATE_STALL(fLSBNEW(PuN),, SPECULATE_TAKEN , 12,0)} {if(fLSBNEW(PuN)){SEMANTICS;}}) \
|
||||
Q6INSN(TAG##fnewpt_rb,"if (!Pu4.new) "OPER":t "OPER2,ATTRIB,DESCR,{fBRANCH_SPECULATE_STALL(fLSBNEWNOT(PuN),, SPECULATE_TAKEN , 12,0)} {if(fLSBNEWNOT(PuN)){SEMANTICS;}})
|
||||
|
||||
NEWCOND_JUMP_RB(J2_jumpr,"jumpr_rb","Rs32",
|
||||
ATTRIBS(A_JINDIRNEW,A_ARCHV3),
|
||||
"restricted indirect conditional jump",
|
||||
fJUMPR(RsN,RsV,COF_TYPE_JUMPR);)
|
||||
|
||||
|
||||
|
||||
Q6INSN(J4_hintjumpr,"hintjr(Rs32)",ATTRIBS(A_JINDIR),"hint indirect conditional jump",
|
||||
@@ -202,6 +229,17 @@ Q6INSN(J2_callrf,"if (!Pu4) callr Rs32",ATTRIBS(CINDIR_STD),"indirect conditiona
|
||||
Q6INSN(J2_callrh,"callrh Rs32",ATTRIBS(CINDIR_STD, A_HINTED_COF), "hinted indirect unconditional call",
|
||||
{ fCALLR(RsV); })
|
||||
|
||||
Q6INSN(J2_callr_rb,"callr_rb Rs32",ATTRIBS(CINDIR_STD),
|
||||
"restricted indirect unconditional call", { fCALLR(RsV); })
|
||||
Q6INSN(J2_callrh_rb,"callrh_rb Rs32",ATTRIBS(CINDIR_STD, A_HINTED_COF),
|
||||
"restricted hinted indirect unconditional call", { fCALLR(RsV); })
|
||||
Q6INSN(J2_callrt_rb,"if (Pu4) callr_rb Rs32",ATTRIBS(CINDIR_STD),
|
||||
"restricted indirect conditional call if true",
|
||||
{if (fLSBOLD(PuV)) { fCALLR(RsV); }})
|
||||
Q6INSN(J2_callrf_rb,"if (!Pu4) callr_rb Rs32",ATTRIBS(CINDIR_STD),
|
||||
"restricted indirect conditional call if false",
|
||||
{if (fLSBOLDNOT(PuV)) { fCALLR(RsV); }})
|
||||
|
||||
|
||||
|
||||
/*********************************************/
|
||||
|
||||
@@ -406,8 +406,28 @@ DEF_ENC32(R6_release_at_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --0011dd")
|
||||
DEF_ENC32(R6_release_st_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --1011dd")
|
||||
|
||||
DEF_EXT_SPACE(EXTRACTW, ICLASS_LD" 001 0 000 iiiii PP0iiiii 001iiiii")
|
||||
DEF_ENC32(Y2_dcfetchbo, ICLASS_LD" 010 0 000 sssss PP0--iii iiiiiiii")
|
||||
DEF_ENC32(Y2_dcfetchbo, "10010100000sssssPP000iiiiiiiiiii")
|
||||
DEF_ENC32(Y4_dcfetch_multi,"10010100000sssssPP001ttttt------")
|
||||
DEF_ENC32(Y2_dcfetchbo_nt,"10010100000sssssPP10-iiiiiiiiiii")
|
||||
DEF_ENC32(V2_vallocframe_imm,"01100000100-----PP001----iiiiiii")
|
||||
DEF_ENC32(V2_vallocframe_reg,"01100000100sssssPP010-----------")
|
||||
DEF_ENC32(V2_vdeallocframe_imm,"01101010100-----PP001----iiiiiii")
|
||||
DEF_ENC32(V2_vdeallocframe_reg,"01101001010sssssPP010-----------")
|
||||
DEF_ENC32(J2_callr_rb,"01010000001sssssPP--------------")
|
||||
DEF_ENC32(J2_callrh_rb,"01010000010sssssPP--------------")
|
||||
DEF_ENC32(J2_callrt_rb,"01010001100sssssPP----uu--------")
|
||||
DEF_ENC32(J2_callrf_rb,"01010001101sssssPP----uu--------")
|
||||
DEF_ENC32(J2_jumpr_rb,"01010010000sssssPP--------------")
|
||||
DEF_ENC32(J2_jumprh_rb,"01010010010sssssPP--------------")
|
||||
DEF_ENC32(J2_jumprt_rb,"01010011110sssssPP-00-uu--------")
|
||||
DEF_ENC32(J2_jumprf_rb,"01010011111sssssPP-00-uu--------")
|
||||
DEF_ENC32(J2_jumprtpt_rb,"01010011110sssssPP-10-uu--------")
|
||||
DEF_ENC32(J2_jumprfpt_rb,"01010011111sssssPP-10-uu--------")
|
||||
DEF_ENC32(J2_jumprtnew_rb,"01010011110sssssPP-01-uu--------")
|
||||
DEF_ENC32(J2_jumprfnew_rb,"01010011111sssssPP-01-uu--------")
|
||||
DEF_ENC32(J2_jumprtnewpt_rb,"01010011110sssssPP-11-uu--------")
|
||||
DEF_ENC32(J2_jumprfnewpt_rb,"01010011111sssssPP-11-uu--------")
|
||||
DEF_ENC32(J2_trap2,"0101010011------PP-iiiii---iii--")
|
||||
|
||||
|
||||
|
||||
@@ -508,6 +528,7 @@ DEF_ENC32(S2_pstorerdf_pi_nt,"10101010110xxxxxPP1ttttt0iiii1vv")
|
||||
/* x bus/cache */
|
||||
/* x store/cache */
|
||||
DEF_ENC32(S2_allocframe, ICLASS_ST" 000 01 00xxxxx PP000iii iiiiiiii")
|
||||
DEF_ENC32(S2_allocframe_rb,ICLASS_ST" 000 01 00xxxxx PP100iii iiiiiiii")
|
||||
DEF_ENC32(Y5_l2locka, ICLASS_ST" 000 01 11sssss PP1----- ------dd")
|
||||
DEF_ENC32(Y2_dczeroa, ICLASS_ST" 000 01 10sssss PP0----- --------")
|
||||
DEF_ENC32(Y2_dczeroa_nt,"10100000110sssssPP1-------------")
|
||||
@@ -1179,9 +1200,14 @@ MPY_ENC(A6_vminub_RdP, "1010","ddddd","0","1","1","1","ee")
|
||||
DEF_FIELDROW_DESC32(ICLASS_M" 1011 -------- PP------ --------","[#11] Reserved")
|
||||
MPY_ENC(F2_sfadd, "1011","ddddd","0","0","0","0","00")
|
||||
MPY_ENC(F2_sfsub, "1011","ddddd","0","0","0","0","01")
|
||||
DEF_ENC32(F7_vsfadd, "11101011000sssssPP0ttttt010ddddd")
|
||||
DEF_ENC32(F7_vsfsub, "11101011000sssssPP0ttttt011ddddd")
|
||||
MPY_ENC(F2_sfmax, "1011","ddddd","0","0","0","1","00")
|
||||
MPY_ENC(F2_sfmin, "1011","ddddd","0","0","0","1","01")
|
||||
MPY_ENC(F2_sfmpy, "1011","ddddd","0","0","1","0","00")
|
||||
DEF_ENC32(F7_vsfmpy, "11101011010sssssPP0ttttt001ddddd")
|
||||
DEF_ENC32(F7_vsffma, "11101011010sssssPP0ttttt010xxxxx")
|
||||
DEF_ENC32(F7_vsffms, "11101011010sssssPP0ttttt011xxxxx")
|
||||
MPY_ENC(F2_sffixupn, "1011","ddddd","0","0","1","1","00")
|
||||
MPY_ENC(F2_sffixupd, "1011","ddddd","0","0","1","1","01")
|
||||
MPY_ENC(F2_sfrecipa, "1011","ddddd","1","1","1","1","ee")
|
||||
@@ -1401,7 +1427,8 @@ DEF_ENC32(C2_cmoveif, ICLASS_ALU2op" 1110 1uu0iiii PP0iiiii iiiddddd")
|
||||
|
||||
|
||||
DEF_FIELDROW_DESC32( ICLASS_ALU2op" 1111 -------- PP------ --------","[#15] nop")
|
||||
DEF_ENC32(A2_nop, ICLASS_ALU2op" 1111 -------- PP------ --------")
|
||||
DEF_ENC32(A2_nop, ICLASS_ALU2op" 1111 0------- PP------ --------")
|
||||
DEF_ENC32(A2_nop_rb, ICLASS_ALU2op" 1111 1------- PP------ --------")
|
||||
|
||||
|
||||
|
||||
@@ -1895,6 +1922,18 @@ SH_RRR_ENC(S2_cabacdecbin, "0001","11-","-","11-","ddddd") /* implicit P0 w
|
||||
|
||||
|
||||
DEF_FIELDROW_DESC32(ICLASS_S3op" 0010 -------- PP------ --------","[#2] Rdd=(Rss,Rtt,Pu)")
|
||||
DEF_ENC32(AM_addw_aq, "10010000000sssssPP1ttttt001ddddd")
|
||||
DEF_ENC32(AM_addw_rl, "10010000000sssssPP1ttttt010ddddd")
|
||||
DEF_ENC32(AM_andw_aq, "10010000000sssssPP1ttttt101ddddd")
|
||||
DEF_ENC32(AM_andw_rl, "10010000000sssssPP1ttttt110ddddd")
|
||||
DEF_ENC32(AM_orw_aq, "10010000110sssssPP0ttttt001ddddd")
|
||||
DEF_ENC32(AM_orw_rl, "10010000110sssssPP0ttttt010ddddd")
|
||||
DEF_ENC32(AM_xorw_aq, "10010000110sssssPP0ttttt101ddddd")
|
||||
DEF_ENC32(AM_xorw_rl, "10010000110sssssPP0ttttt110ddddd")
|
||||
DEF_ENC32(AM_swapw_aq, "10010000110sssssPP1ttttt001ddddd")
|
||||
DEF_ENC32(AM_swapw_rl, "10010000110sssssPP1ttttt010ddddd")
|
||||
DEF_ENC32(AM_swapd_aq, "10010000110sssssPP1ttttt101ddddd")
|
||||
DEF_ENC32(AM_swapd_rl, "10010000110sssssPP1ttttt110ddddd")
|
||||
SH_RRR_ENC(S2_valignrb, "0010","0--","-","-uu","ddddd")
|
||||
SH_RRR_ENC(S2_vsplicerb, "0010","100","-","-uu","ddddd")
|
||||
SH_RRR_ENC(A4_addp_c, "0010","110","-","-xx","ddddd")
|
||||
|
||||
@@ -71,6 +71,7 @@ DEF_ENC_SUBINSN(SS2_storebi0, SUBINSN_S2, "100 10ssssiiii")
|
||||
DEF_ENC_SUBINSN(SS2_storebi1, SUBINSN_S2, "100 11ssssiiii")
|
||||
|
||||
DEF_ENC_SUBINSN(SS2_allocframe, SUBINSN_S2, "111 0iiiii----")
|
||||
DEF_ENC_SUBINSN(SS2_allocframe_rb,SUBINSN_S2, "111 1iiiii----")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -51,6 +51,55 @@ Q6INSN(F2_sffms,"Rx32-=sfmpy(Rs32,Rt32)",ATTRIBS(),
|
||||
"Floating-Point Fused Multiply Add",
|
||||
{ RxV=fUNFLOAT(fFMAF(-fFLOAT(RsV),fFLOAT(RtV),fFLOAT(RxV))); })
|
||||
|
||||
Q6INSN(F7_vsfadd,"Rdd32=vsfadd(Rss32,Rtt32)",ATTRIBS(),
|
||||
"Vector Floating-Point Add",
|
||||
{
|
||||
fSETWORD(0,RddV,fUNFLOAT(fFLOAT(fGETUWORD(0,RssV)) +
|
||||
fFLOAT(fGETUWORD(0,RttV))));
|
||||
fSETWORD(1,RddV,fUNFLOAT(fFLOAT(fGETUWORD(1,RssV)) +
|
||||
fFLOAT(fGETUWORD(1,RttV))));
|
||||
})
|
||||
|
||||
Q6INSN(F7_vsfsub,"Rdd32=vsfsub(Rss32,Rtt32)",ATTRIBS(),
|
||||
"Vector Floating-Point Subtract",
|
||||
{
|
||||
fSETWORD(0,RddV,fUNFLOAT(fFLOAT(fGETUWORD(0,RssV)) -
|
||||
fFLOAT(fGETUWORD(0,RttV))));
|
||||
fSETWORD(1,RddV,fUNFLOAT(fFLOAT(fGETUWORD(1,RssV)) -
|
||||
fFLOAT(fGETUWORD(1,RttV))));
|
||||
})
|
||||
|
||||
Q6INSN(F7_vsfmpy,"Rdd32=vsfmpy(Rss32,Rtt32)",ATTRIBS(),
|
||||
"Vector Floating-Point Multiply",
|
||||
{
|
||||
fSETWORD(0,RddV,fUNFLOAT(fSFMPY(fFLOAT(fGETUWORD(0,RssV)),
|
||||
fFLOAT(fGETUWORD(0,RttV)))));
|
||||
fSETWORD(1,RddV,fUNFLOAT(fSFMPY(fFLOAT(fGETUWORD(1,RssV)),
|
||||
fFLOAT(fGETUWORD(1,RttV)))));
|
||||
})
|
||||
|
||||
Q6INSN(F7_vsffma,"Rxx32+=vsfmpy(Rss32,Rtt32)",ATTRIBS(),
|
||||
"Vector Floating-Point Fused Multiply Add",
|
||||
{
|
||||
fSETWORD(0,RxxV,fUNFLOAT(fFMAF(fFLOAT(fGETUWORD(0,RssV)),
|
||||
fFLOAT(fGETUWORD(0,RttV)),
|
||||
fFLOAT(fGETUWORD(0,RxxV)))));
|
||||
fSETWORD(1,RxxV,fUNFLOAT(fFMAF(fFLOAT(fGETUWORD(1,RssV)),
|
||||
fFLOAT(fGETUWORD(1,RttV)),
|
||||
fFLOAT(fGETUWORD(1,RxxV)))));
|
||||
})
|
||||
|
||||
Q6INSN(F7_vsffms,"Rxx32-=vsfmpy(Rss32,Rtt32)",ATTRIBS(),
|
||||
"Vector Floating-Point Fused Multiply Subtract",
|
||||
{
|
||||
fSETWORD(0,RxxV,fUNFLOAT(fFMAF(-fFLOAT(fGETUWORD(0,RssV)),
|
||||
fFLOAT(fGETUWORD(0,RttV)),
|
||||
fFLOAT(fGETUWORD(0,RxxV)))));
|
||||
fSETWORD(1,RxxV,fUNFLOAT(fFMAF(-fFLOAT(fGETUWORD(1,RssV)),
|
||||
fFLOAT(fGETUWORD(1,RttV)),
|
||||
fFLOAT(fGETUWORD(1,RxxV)))));
|
||||
})
|
||||
|
||||
Q6INSN(F2_sffma_lib,"Rx32+=sfmpy(Rs32,Rt32):lib",ATTRIBS(),
|
||||
"Floating-Point Fused Multiply Add for Library Routines",
|
||||
{ fFPSETROUND_NEAREST(); fHIDE(int infinp; int infminusinf; size4s_t tmp;)
|
||||
|
||||
@@ -135,7 +135,8 @@ STD_ST_AMODES(storerhnew, "Nt8.new", "memh","Store Half integer",ATTRIBS(A_REGWR
|
||||
|
||||
Q6INSN(S2_allocframe,"allocframe(Rx32,#u11:3):raw", ATTRIBS(A_REGWRSIZE_8B,A_MEMSIZE_8B,A_STORE,A_RESTRICT_SLOT0ONLY), "Allocate stack frame",
|
||||
{ fEA_RI(RxV,-8); fSTORE(1,8,EA,fFRAME_SCRAMBLE((fCAST8_8u(fREAD_LR()) << 32) | fCAST4_4u(fREAD_FP()))); fWRITE_FP(EA); fFRAMECHECK(EA-uiV,EA); RxV = EA-uiV; })
|
||||
|
||||
Q6INSN(S2_allocframe_rb,"allocframe_rb(Rx32,#u11:3):raw", ATTRIBS(A_REGWRSIZE_8B,A_MEMSIZE_8B,A_STORE,A_RESTRICT_SLOT0ONLY,A_RESTRICT_TARGET), "Allocate stack frame",
|
||||
{ fEA_RI(RxV,-8); fSTORE(1,8,EA,fFRAME_SCRAMBLE((fCAST8_8u(fREAD_LR()) << 32) | fCAST4_4u(fREAD_FP()))); fWRITE_FP(EA); fFRAMECHECK(EA-uiV,EA); RxV = EA-uiV; })
|
||||
#define A_RETURN A_RESTRICT_COF_MAX1,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOSLOT1_STORE,A_RET_TYPE,A_DEALLOCRET
|
||||
|
||||
/**** Load Acquire Store Release Instructions****/
|
||||
@@ -156,6 +157,19 @@ Q6INSN(S4_stored_rl_at_vi,"memd_rl(Rs32):at=Rtt32",ATTRIBS(A_REGWRSIZE_8B,A_RELE
|
||||
Q6INSN(S2_storew_rl_st_vi,"memw_rl(Rs32):st=Rt32",ATTRIBS(A_REGWRSIZE_4B,A_RELEASE,A_VTCM_ALLBANK_ACCESS,A_RLS_INNER,A_RLS_SAME_THREAD,A_RESTRICT_NOPACKET,A_MEMSIZE_4B,A_STORE,A_RESTRICT_SLOT0ONLY),"Store Release Word", { fEA_REG(RsV); fSTORE(1,4,EA,RtV); })
|
||||
Q6INSN(S4_stored_rl_st_vi,"memd_rl(Rs32):st=Rtt32",ATTRIBS(A_REGWRSIZE_8B,A_RELEASE,A_VTCM_ALLBANK_ACCESS,A_RLS_INNER,A_RLS_SAME_THREAD,A_RESTRICT_NOPACKET,A_MEMSIZE_8B,A_STORE,A_RESTRICT_SLOT0ONLY),"Store Release Double integer", { fEA_REG(RsV); fSTORE(1,8,EA,RttV); })
|
||||
|
||||
Q6INSN(AM_addw_aq,"Rd32=atomw_add(Rs32,Rt32):aq",ATTRIBS(A_REGWRSIZE_4B,A_MEMSIZE_4B,A_ATOMIC,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"Atomic add word acquire",{ fEA_REG(RsV); fATOMIC_LDST(4,RdV,EA,RtV,0,*EA+RtV); })
|
||||
Q6INSN(AM_addw_rl,"Rd32=atomw_add(Rs32,Rt32):rl",ATTRIBS(A_REGWRSIZE_4B,A_MEMSIZE_4B,A_ATOMIC,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"Atomic add word release",{ fEA_REG(RsV); fATOMIC_LDST(4,RdV,EA,RtV,0,*EA+RtV); })
|
||||
Q6INSN(AM_andw_aq,"Rd32=atomw_and(Rs32,Rt32):aq",ATTRIBS(A_REGWRSIZE_4B,A_MEMSIZE_4B,A_ATOMIC,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"Atomic and word acquire",{ fEA_REG(RsV); fATOMIC_LDST(4,RdV,EA,RtV,1,*EA&RtV); })
|
||||
Q6INSN(AM_andw_rl,"Rd32=atomw_and(Rs32,Rt32):rl",ATTRIBS(A_REGWRSIZE_4B,A_MEMSIZE_4B,A_ATOMIC,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"Atomic and word release",{ fEA_REG(RsV); fATOMIC_LDST(4,RdV,EA,RtV,1,*EA&RtV); })
|
||||
Q6INSN(AM_orw_aq,"Rd32=atomw_or(Rs32,Rt32):aq",ATTRIBS(A_REGWRSIZE_4B,A_MEMSIZE_4B,A_ATOMIC,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"Atomic or word acquire",{ fEA_REG(RsV); fATOMIC_LDST(4,RdV,EA,RtV,2,*EA|RtV); })
|
||||
Q6INSN(AM_orw_rl,"Rd32=atomw_or(Rs32,Rt32):rl",ATTRIBS(A_REGWRSIZE_4B,A_MEMSIZE_4B,A_ATOMIC,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"Atomic or word release",{ fEA_REG(RsV); fATOMIC_LDST(4,RdV,EA,RtV,2,*EA|RtV); })
|
||||
Q6INSN(AM_xorw_aq,"Rd32=atomw_xor(Rs32,Rt32):aq",ATTRIBS(A_REGWRSIZE_4B,A_MEMSIZE_4B,A_ATOMIC,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"Atomic xor word acquire",{ fEA_REG(RsV); fATOMIC_LDST(4,RdV,EA,RtV,3,*EA^RtV); })
|
||||
Q6INSN(AM_xorw_rl,"Rd32=atomw_xor(Rs32,Rt32):rl",ATTRIBS(A_REGWRSIZE_4B,A_MEMSIZE_4B,A_ATOMIC,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"Atomic xor word release",{ fEA_REG(RsV); fATOMIC_LDST(4,RdV,EA,RtV,3,*EA^RtV); })
|
||||
Q6INSN(AM_swapw_aq,"Rd32=atomw_swap(Rs32,Rt32):aq",ATTRIBS(A_REGWRSIZE_4B,A_MEMSIZE_4B,A_ATOMIC,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"Atomic swap word acquire",{ fEA_REG(RsV); fATOMIC_LDST(4,RdV,EA,RtV,4,RtV); })
|
||||
Q6INSN(AM_swapw_rl,"Rd32=atomw_swap(Rs32,Rt32):rl",ATTRIBS(A_REGWRSIZE_4B,A_MEMSIZE_4B,A_ATOMIC,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"Atomic swap word release",{ fEA_REG(RsV); fATOMIC_LDST(4,RdV,EA,RtV,4,RtV); })
|
||||
Q6INSN(AM_swapd_aq,"Rdd32=atomd_swap(Rs32,Rtt32):aq",ATTRIBS(A_REGWRSIZE_8B,A_MEMSIZE_8B,A_ATOMIC,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"Atomic swap double word acquire",{ fEA_REG(RsV); fATOMIC_LDST(8,RddV,EA,RttV,4,RttV); })
|
||||
Q6INSN(AM_swapd_rl,"Rdd32=atomd_swap(Rs32,Rtt32):rl",ATTRIBS(A_REGWRSIZE_8B,A_MEMSIZE_8B,A_ATOMIC,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"Atomic swap double word release",{ fEA_REG(RsV); fATOMIC_LDST(8,RddV,EA,RttV,4,RttV); })
|
||||
|
||||
Q6INSN(L2_deallocframe,"Rdd32=deallocframe(Rs32):raw", ATTRIBS(A_REGWRSIZE_8B,A_MEMSIZE_8B,A_LOAD,A_DEALLOCFRAME), "Deallocate stack frame",
|
||||
{ fHIDE(size8u_t tmp;) fEA_REG(RsV);
|
||||
fLOAD(1,8,u,EA,tmp);
|
||||
|
||||
@@ -1404,6 +1404,11 @@ DEF_MACRO(fLOAD_LOCKED,
|
||||
(A_LOAD,A_MEMLIKE)
|
||||
)
|
||||
|
||||
DEF_MACRO(fATOMIC_LDST,
|
||||
{ },
|
||||
(A_LOAD,A_STORE,A_MEMLIKE)
|
||||
)
|
||||
|
||||
DEF_MACRO(fSTORE,
|
||||
{ MEM_STORE##SIZE(thread,EA,SRC,insn); },
|
||||
(A_STORE,A_MEMLIKE)
|
||||
@@ -1958,6 +1963,11 @@ DEF_MACRO(fDCFETCH,
|
||||
(A_MEMLIKE)
|
||||
)
|
||||
|
||||
DEF_MACRO(fDCFETCH_MULTI,
|
||||
{ },
|
||||
(A_MEMLIKE)
|
||||
)
|
||||
|
||||
DEF_MACRO(fICINVA,
|
||||
/* */,
|
||||
(A_ICINVA)
|
||||
|
||||
@@ -147,3 +147,5 @@ Q6INSN(SS2_storebi1, "memb(Rs16+#u4:0)=#1", ATTRIBS(A_MEMSIZE_1B,A_STORE,A_SUB
|
||||
|
||||
Q6INSN(SS2_allocframe,"allocframe(#u5:3)", ATTRIBS(A_REGWRSIZE_8B,A_SUBINSN,A_MEMSIZE_8B,A_STORE,A_RESTRICT_SLOT0ONLY), "Allocate stack frame",
|
||||
{ fEA_RI(fREAD_SP(),-8); fSTORE(1,8,EA,fFRAME_SCRAMBLE((fCAST8_8u(fREAD_LR()) << 32) | fCAST4_4u(fREAD_FP()))); fWRITE_FP(EA); fFRAMECHECK(EA-uiV,EA); fWRITE_SP(EA-uiV); })
|
||||
Q6INSN(SS2_allocframe_rb,"allocframe_rb(#u5:3)", ATTRIBS(A_REGWRSIZE_8B,A_SUBINSN,A_MEMSIZE_8B,A_STORE,A_RESTRICT_SLOT0ONLY,A_RESTRICT_TARGET), "Allocate stack frame",
|
||||
{ fEA_RI(fREAD_SP(),-8); fSTORE(1,8,EA,fFRAME_SCRAMBLE((fCAST8_8u(fREAD_LR()) << 32) | fCAST4_4u(fREAD_FP()))); fWRITE_FP(EA); fFRAMECHECK(EA-uiV,EA); fWRITE_SP(EA-uiV); })
|
||||
@@ -48,6 +48,9 @@ Q6INSN(J2_trap1,"trap1(Rx32,#u8)",ATTRIBS(A_COF,A_NOTE_NOPACKET,A_RESTRICT_NOPAC
|
||||
fVIRTINSN_SPSWAP(uiV,RxV);
|
||||
})
|
||||
|
||||
Q6INSN(J2_trap2,"trap2(#u8)",ATTRIBS(A_COF,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),
|
||||
"Trap to Operating System", { fTRAP(2,uiV); })
|
||||
|
||||
Q6INSN(J2_pause,"pause(#u8)",ATTRIBS(A_COF,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),
|
||||
"Enter low-power state for #u8 cycles",{fPAUSE(uiV);})
|
||||
|
||||
@@ -241,6 +244,12 @@ Q6INSN(Y6_dmresume,"dmresume(Rs32)",ATTRIBS(A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,
|
||||
|
||||
Q6INSN(Y2_dcfetchbo,"dcfetch(Rs32+#u11:3)",ATTRIBS(A_RESTRICT_PREFERSLOT0,A_DCFETCH,A_RESTRICT_NOSLOT1_STORE),"Data Cache Prefetch",{fEA_RI(RsV,uiV); fDCFETCH(EA);})
|
||||
Q6INSN(Y2_dcfetchbo_nt,"dcfetch(Rs32+#u11:3):nt",ATTRIBS(A_NA_NT,A_RESTRICT_PREFERSLOT0,A_DCFETCH,A_RESTRICT_NOSLOT1_STORE),"Data Cache Prefetch",{fEA_RI(RsV,uiV); fDCFETCH(EA);})
|
||||
|
||||
Q6INSN(V2_vallocframe_imm,"vallocframe(#u7:0)",ATTRIBS(A_RESTRICT_NOPACKET),"Allocate vector stack frame",{ fVFRAMECHECK(VSP - (uiV << 11), VSP); })
|
||||
Q6INSN(V2_vallocframe_reg,"vallocframe(Rs32)",ATTRIBS(A_RESTRICT_NOPACKET),"Allocate vector stack frame",{ fVFRAMECHECK(VSP - (RsV << 11), VSP); })
|
||||
Q6INSN(V2_vdeallocframe_imm,"vdeallocframe(#u7:0)",ATTRIBS(A_RESTRICT_NOPACKET),"Deallocate vector stack frame",{ VSP = VSP + (uiV << 11); })
|
||||
Q6INSN(V2_vdeallocframe_reg,"vdeallocframe(Rs32)",ATTRIBS(A_RESTRICT_NOPACKET),"Deallocate vector stack frame",{ VSP = VSP + (RsV << 11); })
|
||||
Q6INSN(Y4_dcfetch_multi,"dcfetch_multi(Rs32,Rt32)",ATTRIBS(A_RESTRICT_PREFERSLOT0,A_DCFETCH,A_RESTRICT_NOSLOT1_STORE),"Data Cache Prefetch",{fEA_REG(RsV); fDCFETCH_MULTI(EA,fEXTRACTU_BITS(RtV,10,0));})
|
||||
Q6INSN(Y2_dckill,"dckill",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_DCFLUSHOP),"Data Cache Invalidate",{fDCKILL();})
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ static int hexagon_cpu_post_load(void *opaque, int version_id)
|
||||
|
||||
const VMStateDescription vmstate_hexagon_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 2,
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 2,
|
||||
.post_load = hexagon_cpu_post_load,
|
||||
.fields = (const VMStateField[]) {
|
||||
@@ -37,6 +37,7 @@ const VMStateDescription vmstate_hexagon_cpu = {
|
||||
VMSTATE_UINT32(env.cause_code, HexagonCPU),
|
||||
VMSTATE_UNUSED(sizeof(uint64_t)),
|
||||
VMSTATE_UINT32(env.imprecise_exception, HexagonCPU),
|
||||
VMSTATE_UINT32_V(env.cfi_active, HexagonCPU, 3),
|
||||
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
|
||||
@@ -423,6 +423,18 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
|
||||
#define fCAST8S_16S(A) (int128_exts64(A))
|
||||
#define fCAST16S_8S(A) (int128_getlo(A))
|
||||
|
||||
#define fSET_CFI(CFI_VALUE) \
|
||||
do { \
|
||||
TCGLabel *skip_cfi_reset = gen_new_label(); \
|
||||
tcg_gen_movcond_i32(TCG_COND_NE, hex_cfi_active_log, hex_cfi_updated, \
|
||||
tcg_constant_i32(1), tcg_constant_i32(0), \
|
||||
hex_cfi_active_log); \
|
||||
tcg_gen_movi_i32(hex_cfi_updated, 1); \
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, CFI_VALUE, 0, skip_cfi_reset); \
|
||||
tcg_gen_movi_i32(hex_cfi_active_log, 1); \
|
||||
gen_set_label(skip_cfi_reset); \
|
||||
} while (0)
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
#define fEA_RI(REG, IMM) tcg_gen_addi_tl(EA, REG, IMM)
|
||||
#define fEA_RRs(REG, REG2, SCALE) \
|
||||
|
||||
@@ -721,6 +721,11 @@ static int64_t legacy_round_n(FloatParts64 parts, int exp, int frac, int adj,
|
||||
}
|
||||
|
||||
if (midpoint) {
|
||||
/*
|
||||
* The legacy add/multiply result is at most one bit above exp,
|
||||
* making shift at least 41.
|
||||
*/
|
||||
g_assert(shift >= 41);
|
||||
threshold = UINT64_C(3) << (shift - 3);
|
||||
if (low <= threshold) {
|
||||
return base + 1;
|
||||
|
||||
@@ -926,6 +926,79 @@ float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV,
|
||||
return RdV;
|
||||
}
|
||||
|
||||
uint64_t HELPER(vsfadd)(CPUHexagonState *env, uint64_t RssV, uint64_t RttV,
|
||||
uint32_t pkt_need_commit)
|
||||
{
|
||||
uint64_t RddV;
|
||||
float32 lo, hi;
|
||||
|
||||
arch_fpop_start(env);
|
||||
lo = float32_add(RssV, RttV, &env->fp_status);
|
||||
hi = float32_add(RssV >> 32, RttV >> 32, &env->fp_status);
|
||||
arch_fpop_end(env, pkt_need_commit);
|
||||
RddV = lo | ((uint64_t)hi << 32);
|
||||
return RddV;
|
||||
}
|
||||
|
||||
uint64_t HELPER(vsfsub)(CPUHexagonState *env, uint64_t RssV, uint64_t RttV,
|
||||
uint32_t pkt_need_commit)
|
||||
{
|
||||
uint64_t RddV;
|
||||
float32 lo, hi;
|
||||
|
||||
arch_fpop_start(env);
|
||||
lo = float32_sub(RssV, RttV, &env->fp_status);
|
||||
hi = float32_sub(RssV >> 32, RttV >> 32, &env->fp_status);
|
||||
arch_fpop_end(env, pkt_need_commit);
|
||||
RddV = lo | ((uint64_t)hi << 32);
|
||||
return RddV;
|
||||
}
|
||||
|
||||
uint64_t HELPER(vsfmpy)(CPUHexagonState *env, uint64_t RssV, uint64_t RttV,
|
||||
uint32_t pkt_need_commit)
|
||||
{
|
||||
uint64_t RddV;
|
||||
float32 lo, hi;
|
||||
|
||||
arch_fpop_start(env);
|
||||
lo = float32_mul(RssV, RttV, &env->fp_status);
|
||||
hi = float32_mul(RssV >> 32, RttV >> 32, &env->fp_status);
|
||||
arch_fpop_end(env, pkt_need_commit);
|
||||
RddV = lo | ((uint64_t)hi << 32);
|
||||
return RddV;
|
||||
}
|
||||
|
||||
uint64_t HELPER(vsffma)(CPUHexagonState *env, uint64_t RxxV, uint64_t RssV,
|
||||
uint64_t RttV, uint32_t pkt_need_commit)
|
||||
{
|
||||
uint64_t RddV;
|
||||
float32 lo, hi;
|
||||
|
||||
arch_fpop_start(env);
|
||||
lo = float32_muladd(RssV, RttV, RxxV, 0, &env->fp_status);
|
||||
hi = float32_muladd(RssV >> 32, RttV >> 32, RxxV >> 32, 0,
|
||||
&env->fp_status);
|
||||
arch_fpop_end(env, pkt_need_commit);
|
||||
RddV = lo | ((uint64_t)hi << 32);
|
||||
return RddV;
|
||||
}
|
||||
|
||||
uint64_t HELPER(vsffms)(CPUHexagonState *env, uint64_t RxxV, uint64_t RssV,
|
||||
uint64_t RttV, uint32_t pkt_need_commit)
|
||||
{
|
||||
uint64_t RddV;
|
||||
float32 lo, hi;
|
||||
|
||||
arch_fpop_start(env);
|
||||
lo = float32_muladd(RssV, RttV, RxxV, float_muladd_negate_product,
|
||||
&env->fp_status);
|
||||
hi = float32_muladd(RssV >> 32, RttV >> 32, RxxV >> 32,
|
||||
float_muladd_negate_product, &env->fp_status);
|
||||
arch_fpop_end(env, pkt_need_commit);
|
||||
RddV = lo | ((uint64_t)hi << 32);
|
||||
return RddV;
|
||||
}
|
||||
|
||||
int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV,
|
||||
uint32_t pkt_need_commit)
|
||||
{
|
||||
@@ -1613,26 +1686,30 @@ void HELPER(raise_stack_overflow)(CPUHexagonState *env, uint32_t slot,
|
||||
void HELPER(ciad)(CPUHexagonState *env, uint32_t mask)
|
||||
{
|
||||
uint32_t iad;
|
||||
uint32_t was_set;
|
||||
HexagonCPU *cpu;
|
||||
|
||||
BQL_LOCK_GUARD();
|
||||
cpu = env_archcpu(env);
|
||||
if (cpu->cfg.hex_def->hex_version >= HEX_VER_V81) {
|
||||
iad = hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IAD,
|
||||
env->threadId) & ~mask;
|
||||
hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IAD, iad,
|
||||
env->threadId);
|
||||
was_set = iad & mask;
|
||||
hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IAD, iad & ~mask,
|
||||
env->threadId);
|
||||
} else {
|
||||
uint32_t ipendad =
|
||||
hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
|
||||
env->threadId);
|
||||
|
||||
fSET_FIELD(ipendad, IPENDAD_IAD,
|
||||
fGET_FIELD(ipendad, IPENDAD_IAD) & ~mask);
|
||||
iad = fGET_FIELD(ipendad, IPENDAD_IAD);
|
||||
was_set = iad & mask;
|
||||
fSET_FIELD(ipendad, IPENDAD_IAD, iad & ~mask);
|
||||
hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IPENDAD,
|
||||
ipendad, env->threadId);
|
||||
}
|
||||
l2vic_clear_interrupt(cpu->l2vic);
|
||||
/* Only an interrupt that was taken, or set with siad, can be cleared */
|
||||
l2vic_clear_interrupt(cpu->l2vic, was_set);
|
||||
hex_interrupt_update(env);
|
||||
}
|
||||
|
||||
@@ -1663,6 +1740,12 @@ void HELPER(siad)(CPUHexagonState *env, uint32_t mask)
|
||||
hex_interrupt_update(env);
|
||||
}
|
||||
|
||||
void HELPER(tlbinvasid)(CPUHexagonState *env, uint32_t RsV)
|
||||
{
|
||||
BQL_LOCK_GUARD();
|
||||
hex_tlb_invalidate_asid(env, extract32(RsV, 20, 7));
|
||||
}
|
||||
|
||||
void HELPER(swi)(CPUHexagonState *env, uint32_t mask)
|
||||
{
|
||||
BQL_LOCK_GUARD();
|
||||
|
||||
@@ -171,7 +171,8 @@ void snprint_a_pkt_disas(GString *buf, Packet *pkt, uint32_t *words,
|
||||
}
|
||||
|
||||
g_string_append(buf, "\t");
|
||||
if (opcode_supported(pkt->insn[i].opcode, cfg->hex_def)) {
|
||||
if (opcode_supported(pkt->insn[i].opcode, cfg->hex_def) &&
|
||||
encoding_supported(pkt->insn[i].opcode, words[i], cfg->hex_def)) {
|
||||
snprintinsn(buf, &(pkt->insn[i]));
|
||||
} else {
|
||||
g_string_append(buf, "<invalid>");
|
||||
|
||||
@@ -95,6 +95,7 @@ DEF_REG_FIELD(SYSCFG_L2GCA, 31, 1)
|
||||
/* SSR fields */
|
||||
DEF_REG_FIELD(SSR_CAUSE, 0, 8)
|
||||
DEF_REG_FIELD(SSR_ASID, 8, 7)
|
||||
DEF_REG_FIELD(SSR_CFI, 15, 1)
|
||||
DEF_REG_FIELD(SSR_UM, 16, 1)
|
||||
DEF_REG_FIELD(SSR_EX, 17, 1)
|
||||
DEF_REG_FIELD(SSR_IE, 18, 1)
|
||||
|
||||
@@ -643,21 +643,6 @@ static const struct tag_rev_info tag_rev_info[XX_LAST_OPCODE] = {
|
||||
[Y2_dcfetchbo_nt] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
|
||||
[Y2_dczeroa_nt] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
|
||||
|
||||
[Y2_tlbpp] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
|
||||
[V6_valign4] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqhf] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqhf_and] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqhf_or] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqhf_xor] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqsf] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqsf_and] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqsf_or] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqsf_xor] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_vconv_h_hf_rnd] = {
|
||||
.introduced = HEX_VER_V81, .removed = HEX_VER_NONE
|
||||
},
|
||||
|
||||
[V6_get_qfext] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
|
||||
[V6_get_qfext_oracc] = {
|
||||
.introduced = HEX_VER_V79, .removed = HEX_VER_NONE
|
||||
@@ -671,7 +656,6 @@ static const struct tag_rev_info tag_rev_info[XX_LAST_OPCODE] = {
|
||||
.introduced = HEX_VER_V79, .removed = HEX_VER_NONE
|
||||
},
|
||||
[V6_vabs_qf32_sf] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
|
||||
[V6_vconv_bf_qf32] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_vconv_qf16_hf] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
|
||||
[V6_vconv_qf16_qf16] = {
|
||||
.introduced = HEX_VER_V79, .removed = HEX_VER_NONE
|
||||
@@ -698,6 +682,72 @@ static const struct tag_rev_info tag_rev_info[XX_LAST_OPCODE] = {
|
||||
[V6_vneg_qf32_sf] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
|
||||
[V6_vsub_hf_mix] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
|
||||
[V6_vsub_sf_mix] = { .introduced = HEX_VER_V79, .removed = HEX_VER_NONE },
|
||||
|
||||
[Y2_tlbpp] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
|
||||
[V6_valign4] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqhf] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqhf_and] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqhf_or] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqhf_xor] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqsf] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqsf_and] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqsf_or] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_veqsf_xor] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
[V6_vconv_h_hf_rnd] = {
|
||||
.introduced = HEX_VER_V81, .removed = HEX_VER_NONE
|
||||
},
|
||||
[V6_vconv_bf_qf32] = { .introduced = HEX_VER_V81, .removed = HEX_VER_NONE },
|
||||
|
||||
[V2_vallocframe_imm] = { .introduced = HEX_VER_V83,
|
||||
.removed = HEX_VER_NONE },
|
||||
[V2_vallocframe_reg] = { .introduced = HEX_VER_V83,
|
||||
.removed = HEX_VER_NONE },
|
||||
[V2_vdeallocframe_imm] = { .introduced = HEX_VER_V83,
|
||||
.removed = HEX_VER_NONE },
|
||||
[V2_vdeallocframe_reg] = { .introduced = HEX_VER_V83,
|
||||
.removed = HEX_VER_NONE },
|
||||
[J2_callr_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_callrh_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_callrt_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_callrf_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_jumpr_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_jumprh_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_jumprt_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_jumprf_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_jumprtpt_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_jumprfpt_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_jumprtnew_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_jumprfnew_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_jumprtnewpt_rb] = { .introduced = HEX_VER_V83,
|
||||
.removed = HEX_VER_NONE },
|
||||
[J2_jumprfnewpt_rb] = { .introduced = HEX_VER_V83,
|
||||
.removed = HEX_VER_NONE },
|
||||
[S2_allocframe_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[SS2_allocframe_rb] = { .introduced = HEX_VER_V83,
|
||||
.removed = HEX_VER_NONE },
|
||||
[A2_nop_rb] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[J2_trap2] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[F7_vsfadd] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[F7_vsfsub] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[F7_vsfmpy] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[F7_vsffma] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
[F7_vsffms] = { .introduced = HEX_VER_V83, .removed = HEX_VER_NONE },
|
||||
|
||||
[Y4_dcfetch_multi] = { .introduced = HEX_VER_V85,
|
||||
.removed = HEX_VER_NONE },
|
||||
[AM_addw_aq] = { .introduced = HEX_VER_V85, .removed = HEX_VER_NONE },
|
||||
[AM_addw_rl] = { .introduced = HEX_VER_V85, .removed = HEX_VER_NONE },
|
||||
[AM_andw_aq] = { .introduced = HEX_VER_V85, .removed = HEX_VER_NONE },
|
||||
[AM_andw_rl] = { .introduced = HEX_VER_V85, .removed = HEX_VER_NONE },
|
||||
[AM_orw_aq] = { .introduced = HEX_VER_V85, .removed = HEX_VER_NONE },
|
||||
[AM_orw_rl] = { .introduced = HEX_VER_V85, .removed = HEX_VER_NONE },
|
||||
[AM_swapd_aq] = { .introduced = HEX_VER_V85, .removed = HEX_VER_NONE },
|
||||
[AM_swapd_rl] = { .introduced = HEX_VER_V85, .removed = HEX_VER_NONE },
|
||||
[AM_swapw_aq] = { .introduced = HEX_VER_V85, .removed = HEX_VER_NONE },
|
||||
[AM_swapw_rl] = { .introduced = HEX_VER_V85, .removed = HEX_VER_NONE },
|
||||
[AM_xorw_aq] = { .introduced = HEX_VER_V85, .removed = HEX_VER_NONE },
|
||||
[AM_xorw_rl] = { .introduced = HEX_VER_V85, .removed = HEX_VER_NONE },
|
||||
};
|
||||
|
||||
#endif /* HEXAGON_TAG_ARCH_TABLE_H */
|
||||
+111
-1
@@ -68,6 +68,9 @@ TCGv hex_imprecise_exception;
|
||||
TCGv hex_vstore_addr[VSTORES_MAX];
|
||||
TCGv hex_vstore_size[VSTORES_MAX];
|
||||
TCGv hex_vstore_pending[VSTORES_MAX];
|
||||
TCGv_i32 hex_cfi_active;
|
||||
TCGv_i32 hex_cfi_active_log;
|
||||
TCGv_i32 hex_cfi_updated;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
TCGv_ptr hex_hvx_ptr;
|
||||
#endif
|
||||
@@ -136,7 +139,7 @@ intptr_t ctx_tmp_vreg_off(DisasContext *ctx, int regnum,
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void gen_precise_exception(int cause, uint32_t PC)
|
||||
void gen_precise_exception(int cause, uint32_t PC)
|
||||
{
|
||||
tcg_gen_movi_i32(hex_cause_code, cause);
|
||||
gen_helper_raise_exception(tcg_env, tcg_constant_i32(HEX_EVENT_PRECISE),
|
||||
@@ -175,10 +178,48 @@ static void gen_goto_tb(DisasContext *ctx, unsigned tb_slot_idx,
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/*
|
||||
* Raise the single-step debug event once the packet has retired. PC
|
||||
* already holds the address of the next packet, which becomes ELR.
|
||||
*/
|
||||
static void gen_singlestep_exception(DisasContext *ctx)
|
||||
{
|
||||
tcg_gen_movi_i32(hex_cause_code, HEX_CAUSE_DEBUG_SINGLESTEP);
|
||||
gen_helper_raise_exception(tcg_env,
|
||||
tcg_constant_i32(HEX_EVENT_DEBUG),
|
||||
hex_gpr[HEX_REG_PC]);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static void gen_end_tb_singlestep(DisasContext *ctx)
|
||||
{
|
||||
TCGv pc = hex_gpr[HEX_REG_PC];
|
||||
|
||||
if (ctx->branch_cond == TCG_COND_ALWAYS) {
|
||||
tcg_gen_movi_tl(pc, ctx->branch_dest);
|
||||
} else if (ctx->branch_cond != TCG_COND_NEVER) {
|
||||
tcg_gen_movcond_tl(ctx->branch_cond, pc, ctx->branch_taken,
|
||||
tcg_constant_tl(1), tcg_constant_tl(ctx->next_PC),
|
||||
tcg_constant_tl(ctx->branch_dest));
|
||||
} else if (!ctx->pkt.pkt_has_cof) {
|
||||
tcg_gen_movi_tl(pc, ctx->next_PC);
|
||||
}
|
||||
gen_singlestep_exception(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void gen_end_tb(DisasContext *ctx)
|
||||
{
|
||||
gen_exec_counters(ctx);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (ctx->ss_active) {
|
||||
gen_end_tb_singlestep(ctx);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ctx->branch_cond != TCG_COND_NEVER) {
|
||||
if (ctx->branch_cond != TCG_COND_ALWAYS) {
|
||||
TCGLabel *skip = gen_new_label();
|
||||
@@ -442,6 +483,45 @@ static void mark_implicit_reg_write(DisasContext *ctx, int attrib, int rnum)
|
||||
}
|
||||
}
|
||||
|
||||
static bool pkt_legal_cfi_target(const Packet *pkt)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pkt->num_insns; i++) {
|
||||
if (GET_ATTRIB(pkt->insn[i].opcode, A_RESTRICT_TARGET) ||
|
||||
pkt->insn[i].opcode == Y2_break ||
|
||||
(pkt->insn[i].opcode == J2_trap0 &&
|
||||
pkt->insn[i].immed[0] == 0xdb)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void gen_cfi_check(DisasContext *ctx)
|
||||
{
|
||||
TCGLabel *skip;
|
||||
|
||||
if (ctx->hex_def->hex_version < HEX_VER_V83 ||
|
||||
pkt_legal_cfi_target(&ctx->pkt)) {
|
||||
return;
|
||||
}
|
||||
|
||||
skip = gen_new_label();
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, hex_cfi_active, 0, skip);
|
||||
gen_precise_exception(HEX_CAUSE_CFI_VIOLATION, ctx->pkt.pc);
|
||||
gen_set_label(skip);
|
||||
}
|
||||
|
||||
static void gen_cfi_target_update(DisasContext *ctx)
|
||||
{
|
||||
if (ctx->hex_def->hex_version >= HEX_VER_V83 &&
|
||||
pkt_legal_cfi_target(&ctx->pkt)) {
|
||||
tcg_gen_movi_i32(hex_cfi_active_log, 0);
|
||||
tcg_gen_movi_i32(hex_cfi_updated, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_implicit_usr_write(DisasContext *ctx, int attrib)
|
||||
{
|
||||
uint16_t opcode = ctx->insn->opcode;
|
||||
@@ -569,6 +649,7 @@ static void clear_pkt_ctx(DisasContext *ctx)
|
||||
ctx->reg_log_idx = 0;
|
||||
bitmap_zero(ctx->regs_written, TOTAL_PER_THREAD_REGS);
|
||||
bitmap_zero(ctx->predicated_regs, TOTAL_PER_THREAD_REGS);
|
||||
ctx->implicit_usr_write = false;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
ctx->greg_log_idx = 0;
|
||||
bitmap_zero(ctx->gregs_written, NUM_GREGS);
|
||||
@@ -710,6 +791,9 @@ static void gen_start_packet(DisasContext *ctx)
|
||||
tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->next_PC);
|
||||
}
|
||||
|
||||
gen_cfi_target_update(ctx);
|
||||
gen_cfi_check(ctx);
|
||||
|
||||
/* Preload the predicated registers into get_result_gpr(ctx, i) */
|
||||
if (ctx->need_commit &&
|
||||
!bitmap_empty(ctx->predicated_regs, TOTAL_PER_THREAD_REGS)) {
|
||||
@@ -1231,6 +1315,14 @@ static void gen_commit_packet(DisasContext *ctx)
|
||||
gen_helper_probe_pkt_scalar_store_s0(tcg_env, args_tcgv);
|
||||
}
|
||||
|
||||
if (ctx->hex_def->hex_version >= HEX_VER_V83) {
|
||||
/* A restricted branch commits before a faulting store in its packet. */
|
||||
tcg_gen_movcond_i32(TCG_COND_NE, hex_cfi_active, hex_cfi_updated,
|
||||
tcg_constant_i32(0), hex_cfi_active_log,
|
||||
hex_cfi_active);
|
||||
tcg_gen_movi_i32(hex_cfi_updated, 0);
|
||||
}
|
||||
|
||||
process_store_log(ctx);
|
||||
|
||||
gen_reg_writes(ctx);
|
||||
@@ -1336,6 +1428,12 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase,
|
||||
FIELD_EX32(hex_flags, TB_FLAGS, HVX_COPROC_ENABLED);
|
||||
ctx->hvx_check_emitted = false;
|
||||
ctx->cpu_mode = FIELD_EX32(hex_flags, TB_FLAGS, CPU_MODE);
|
||||
ctx->ss_active = FIELD_EX32(hex_flags, TB_FLAGS, SS_ACTIVE);
|
||||
if (ctx->ss_active) {
|
||||
/* Step one packet, and let endloop0 branch within the packet */
|
||||
ctx->base.max_insns = 1;
|
||||
ctx->is_tight_loop = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1403,6 +1501,12 @@ static void hexagon_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
||||
case DISAS_TOO_MANY:
|
||||
gen_exec_counters(ctx);
|
||||
tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->base.pc_next);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (ctx->ss_active) {
|
||||
gen_singlestep_exception(ctx);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
break;
|
||||
case DISAS_NORETURN:
|
||||
@@ -1468,6 +1572,12 @@ void hexagon_translate_init(void)
|
||||
}
|
||||
hex_new_value_usr = tcg_global_mem_new(tcg_env,
|
||||
offsetof(CPUHexagonState, new_value_usr), "new_value_usr");
|
||||
hex_cfi_active = tcg_global_mem_new_i32(tcg_env,
|
||||
offsetof(CPUHexagonState, cfi_active), "cfi_active");
|
||||
hex_cfi_active_log = tcg_global_mem_new_i32(tcg_env,
|
||||
offsetof(CPUHexagonState, cfi_active_log), "cfi_active_log");
|
||||
hex_cfi_updated = tcg_global_mem_new_i32(tcg_env,
|
||||
offsetof(CPUHexagonState, cfi_updated), "cfi_updated");
|
||||
|
||||
for (i = 0; i < NUM_PREGS; i++) {
|
||||
hex_pred[i] = tcg_global_mem_new(tcg_env,
|
||||
|
||||
@@ -46,6 +46,7 @@ typedef struct DisasContext {
|
||||
bool implicit_usr_write;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
uint32_t cpu_mode;
|
||||
bool ss_active;
|
||||
int greg_log[GREG_WRITES_MAX];
|
||||
int greg_log_idx;
|
||||
DECLARE_BITMAP(gregs_written, NUM_GREGS);
|
||||
@@ -364,6 +365,10 @@ extern TCGv_i64 hex_llsc_val_i64;
|
||||
extern TCGv hex_vstore_addr[VSTORES_MAX];
|
||||
extern TCGv hex_vstore_size[VSTORES_MAX];
|
||||
extern TCGv hex_vstore_pending[VSTORES_MAX];
|
||||
extern TCGv_i32 hex_cfi_active;
|
||||
extern TCGv_i32 hex_cfi_active_log;
|
||||
extern TCGv_i32 hex_cfi_updated;
|
||||
void gen_precise_exception(int cause, uint32_t pc);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#define hex_hvx_ptr tcg_env
|
||||
#define HEX_HVX_OFFSET(member) offsetof(CPUHexagonState, hvx_ctx.member)
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
tests_hexagon_system_thorough = [
|
||||
'arch_tests',
|
||||
'qcom_dsp_firmware',
|
||||
'systests',
|
||||
'minivm',
|
||||
]
|
||||
|
||||
test_hexagon_timeouts = {
|
||||
'qcom_dsp_firmware': 240,
|
||||
'systests': 180,
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Boot the production DSP firmware on the Qualcomm DSP machines
|
||||
#
|
||||
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
from qemu_test import QemuSystemTest, Asset, skipUntrustedTest
|
||||
from qemu_test import wait_for_console_pattern
|
||||
|
||||
|
||||
class QcomDspFirmwareTest(QemuSystemTest):
|
||||
"""Base class: the firmware is the ELF that -kernel starts running."""
|
||||
|
||||
MACHINE = None
|
||||
ASSET_FIRMWARE = None
|
||||
MILESTONE = 'Entering main() ...'
|
||||
|
||||
def boot_firmware(self):
|
||||
self.set_machine(self.MACHINE)
|
||||
firmware = self.ASSET_FIRMWARE.fetch()
|
||||
|
||||
self.vm.set_console(semihosting=True)
|
||||
self.vm.add_args('-kernel', firmware)
|
||||
self.vm.launch()
|
||||
wait_for_console_pattern(self, 'QURT kernel started',
|
||||
failure_message='Fatal Error')
|
||||
wait_for_console_pattern(self, self.MILESTONE,
|
||||
failure_message='Fatal Error')
|
||||
self.vm.kill()
|
||||
|
||||
|
||||
@skipUntrustedTest()
|
||||
class Qcs6490CdspFirmwareTest(QcomDspFirmwareTest):
|
||||
MACHINE = 'qcs6490-cdsp'
|
||||
|
||||
ASSET_FIRMWARE = Asset(
|
||||
'https://gitlab.com/kernel-firmware/linux-firmware/-/raw/'
|
||||
'20261019/qcom/qcm6490/cdsp.mbn',
|
||||
'43e9c89e15ee82daf83214cae34006a8515fddf9db7f645f5eff4b8e3c4ebb64')
|
||||
|
||||
def test_qcs6490_cdsp_firmware(self):
|
||||
self.boot_firmware()
|
||||
|
||||
|
||||
@skipUntrustedTest()
|
||||
class Sa8775pCdspFirmwareTest(QcomDspFirmwareTest):
|
||||
MACHINE = 'sa8775p-cdsp'
|
||||
ASSET_FIRMWARE = Asset(
|
||||
'https://gitlab.com/kernel-firmware/linux-firmware/-/raw/'
|
||||
'20261019/qcom/sa8775p/cdsp0.mbn',
|
||||
'1d9d8cd1e913b0d3b49a77b4e962564ab481193e6a5697c8f06406b3fd85a8fc')
|
||||
|
||||
def test_sa8775p_cdsp_firmware(self):
|
||||
self.boot_firmware()
|
||||
|
||||
|
||||
@skipUntrustedTest()
|
||||
class Sc8480xpNsp0FirmwareTest(QcomDspFirmwareTest):
|
||||
MACHINE = 'sc8480xp-nsp0'
|
||||
ASSET_FIRMWARE = Asset(
|
||||
'https://gitlab.com/kernel-firmware/linux-firmware/-/raw/'
|
||||
'20261019/qcom/glymur/cdsp.mbn',
|
||||
'7b22f33ae273d3dfc5f741a967831e7d4fd79ad141e6a1ecee17509eac207109')
|
||||
|
||||
def test_sc8480xp_nsp0_firmware(self):
|
||||
self.boot_firmware()
|
||||
|
||||
|
||||
@skipUntrustedTest()
|
||||
class Sa8797pNsp0FirmwareTest(QcomDspFirmwareTest):
|
||||
MACHINE = 'sa8797p-nsp0'
|
||||
ASSET_FIRMWARE = Asset(
|
||||
'https://gitlab.com/kernel-firmware/linux-firmware/-/raw/'
|
||||
'20261019/qcom/nord/cdsp.mbn',
|
||||
'410e7ca3b340e80835e464545a218d9376310a09f24bc87de40bc25f7f5e3240')
|
||||
|
||||
def test_sa8797p_nsp0_firmware(self):
|
||||
self.boot_firmware()
|
||||
|
||||
|
||||
@skipUntrustedTest()
|
||||
class Sm8975NspFirmwareTest(QcomDspFirmwareTest):
|
||||
MACHINE = 'sm8975-nsp'
|
||||
MILESTONE = 'QURT root task started'
|
||||
ASSET_FIRMWARE = Asset(
|
||||
'https://gitlab.com/kernel-firmware/linux-firmware/-/raw/'
|
||||
'20261019/qcom/hawi/cdsp.mbn',
|
||||
'7373952413c141fc636aa933ab0c71e7be1d10f5f7dd36be5374827b253c3db5')
|
||||
|
||||
def test_sm8975_nsp_firmware(self):
|
||||
self.boot_firmware()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
QemuSystemTest.main()
|
||||
@@ -111,5 +111,8 @@ class SysTestsStandaloneTests(QemuSystemTest):
|
||||
def test_lock_verify(self):
|
||||
self.run_exit_zero("lock_verify")
|
||||
|
||||
def test_single_step(self):
|
||||
self.run_exit_zero("single_step")
|
||||
|
||||
if __name__ == "__main__":
|
||||
QemuSystemTest.main()
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "libqtest-single.h"
|
||||
#include "hw/hexagon/hexagon.h"
|
||||
|
||||
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_v79na_1.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_v81dgb_1.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_v81qa_1.h.inc"
|
||||
|
||||
typedef struct {
|
||||
const char *machine;
|
||||
const struct hexagon_machine_config *cfg;
|
||||
uint32_t subsystem_base;
|
||||
} HexagonMachineCfg;
|
||||
|
||||
static const HexagonMachineCfg hexagon_machines[] = {
|
||||
{ "V66G_1024", &v66g_1024, 0 },
|
||||
{ "V68N_1024", &v68n_1024, 0 },
|
||||
{ "V79NA_1", &v79na_1, 0 },
|
||||
{ "V81DGB_1", &v81dgb_1, 0 },
|
||||
{ "V81QA_1", &v81qa_1, 0 },
|
||||
{ "V81QA_1", &v81qa_1, 0xfca00000 },
|
||||
};
|
||||
|
||||
static void test_config_table(gconstpointer data)
|
||||
{
|
||||
const HexagonMachineCfg *mc = data;
|
||||
uint64_t subsystem_base;
|
||||
uint32_t subsystem_base_entry;
|
||||
g_autofree char *args;
|
||||
|
||||
if (mc->subsystem_base) {
|
||||
args = g_strdup_printf("-machine %s,subsystem-base=0x%x", mc->machine,
|
||||
mc->subsystem_base);
|
||||
} else {
|
||||
args = g_strdup_printf("-machine %s", mc->machine);
|
||||
}
|
||||
|
||||
qtest_start(args);
|
||||
|
||||
subsystem_base_entry = readl(mc->cfg->cfgbase +
|
||||
offsetof(union hexagon_config_table,
|
||||
subsystem_base));
|
||||
subsystem_base = (uint64_t)subsystem_base_entry << 16;
|
||||
g_assert_cmphex(subsystem_base, ==,
|
||||
mc->subsystem_base ?: mc->cfg->csr_base);
|
||||
writel(subsystem_base + HEXAGON_L2VIC_OFFSET + 0x200, 1);
|
||||
g_assert_cmphex(readl(subsystem_base + HEXAGON_L2VIC_OFFSET + 0x100),
|
||||
==, 1);
|
||||
g_assert_cmphex(readl(subsystem_base + HEXAGON_QTIMER_OFFSET + 0x10),
|
||||
==, 19200000);
|
||||
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hexagon_machines); i++) {
|
||||
const HexagonMachineCfg *mc = &hexagon_machines[i];
|
||||
g_autofree char *path = g_strdup_printf("/config/%s/%x", mc->machine,
|
||||
mc->subsystem_base);
|
||||
|
||||
qtest_add_data_func(path, mc, test_config_table);
|
||||
}
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
@@ -11,6 +11,11 @@
|
||||
|
||||
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_sm8975_nsp.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc"
|
||||
|
||||
/* L2VIC register offsets exercised by this test */
|
||||
#define L2VIC_INT_ENABLEn 0x100 /* Read/Write */
|
||||
@@ -45,6 +50,11 @@ typedef struct {
|
||||
static const L2VICMachineCfg l2vic_machines[] = {
|
||||
{ "virt", &v68n_1024 },
|
||||
{ "V66G_1024", &v66g_1024 },
|
||||
{ "qcs6490-cdsp", &qcs6490_cdsp },
|
||||
{ "sa8775p-cdsp", &SA8775P_cdsp0 },
|
||||
{ "sc8480xp-nsp0", &sc8480xp_nsp0 },
|
||||
{ "sa8797p-nsp0", &sa8797p_nsp0 },
|
||||
{ "sm8975-nsp", &sm8975_nsp },
|
||||
};
|
||||
|
||||
static uint32_t l2vic_read32(uint64_t base, uint32_t offset)
|
||||
|
||||
@@ -321,7 +321,9 @@ qtests_riscv64 = ['riscv-csr-test'] + \
|
||||
['k230-ddr-test', 'k230-wdt-test', 'k230-gsdma-test', 'k230-decomp-gzip-test'] : []) + \
|
||||
['milkv-duo-test']
|
||||
|
||||
qtests_hexagon = ['boot-serial-test', 'l2vic-test', 'qct-qtimer-test']
|
||||
qtests_hexagon = ['boot-serial-test', 'hexagon-config-test', 'l2vic-test',
|
||||
'qcom-dsp-test',
|
||||
'qct-qtimer-test']
|
||||
|
||||
qos_test_ss = ss.source_set()
|
||||
qos_test_ss.add(
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* QTest for what the Qualcomm DSP machines have in common: the console and
|
||||
* the virtio-mmio transports.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "libqtest.h"
|
||||
#include "libqtest-single.h"
|
||||
#include "hw/hexagon/hexagon.h"
|
||||
#include "hw/hexagon/machine_cfg_sm8975_nsp.h.inc"
|
||||
|
||||
#define QCOM_DSP_UART_BASE 0x37000000
|
||||
#define QCOM_DSP_VIRTIO_BASE 0x37010000
|
||||
#define QCOM_DSP_VIRTIO_STRIDE 0x1000
|
||||
#define QCOM_DSP_VIRTIO_COUNT 8
|
||||
|
||||
#define PL011_UARTPERIPHID0 0xfe0
|
||||
#define PL011_PERIPHID0 0x11
|
||||
|
||||
#define VIRTIO_MMIO_MAGIC_VALUE 0x000
|
||||
#define VIRTIO_MMIO_DEVICE_ID 0x008
|
||||
#define VIRTIO_MAGIC 0x74726976 /* "virt" */
|
||||
|
||||
static const char *const qcom_dsp_machines[] = {
|
||||
"qcs6490-cdsp",
|
||||
"sa8775p-cdsp",
|
||||
"sc8480xp-nsp0",
|
||||
"sa8797p-nsp0",
|
||||
"sm8975-nsp",
|
||||
};
|
||||
|
||||
static void test_console(const void *machine)
|
||||
{
|
||||
g_autofree char *args = g_strdup_printf("-machine %s",
|
||||
(const char *)machine);
|
||||
|
||||
qtest_start(args);
|
||||
g_assert_cmphex(readl(QCOM_DSP_UART_BASE + PL011_UARTPERIPHID0), ==,
|
||||
PL011_PERIPHID0);
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
static void test_virtio_slots(const void *machine)
|
||||
{
|
||||
g_autofree char *args = g_strdup_printf("-machine %s",
|
||||
(const char *)machine);
|
||||
|
||||
qtest_start(args);
|
||||
for (int i = 0; i < QCOM_DSP_VIRTIO_COUNT; i++) {
|
||||
uint64_t base = QCOM_DSP_VIRTIO_BASE + i * QCOM_DSP_VIRTIO_STRIDE;
|
||||
|
||||
g_assert_cmphex(readl(base + VIRTIO_MMIO_MAGIC_VALUE), ==,
|
||||
VIRTIO_MAGIC);
|
||||
/* No backend is attached, so the transport is empty. */
|
||||
g_assert_cmpuint(readl(base + VIRTIO_MMIO_DEVICE_ID), ==, 0);
|
||||
}
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
/* A drive is attached to a virtio transport without any -device. */
|
||||
static void test_default_drive(const void *machine)
|
||||
{
|
||||
g_autofree char *args = g_strdup_printf(
|
||||
"-machine %s -drive if=virtio,file=null-co://,format=raw",
|
||||
(const char *)machine);
|
||||
int found = 0;
|
||||
|
||||
qtest_start(args);
|
||||
for (int i = 0; i < QCOM_DSP_VIRTIO_COUNT; i++) {
|
||||
uint64_t base = QCOM_DSP_VIRTIO_BASE + i * QCOM_DSP_VIRTIO_STRIDE;
|
||||
|
||||
/* virtio-blk is device ID 2 */
|
||||
found += readl(base + VIRTIO_MMIO_DEVICE_ID) == 2;
|
||||
}
|
||||
g_assert_cmpint(found, ==, 1);
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
static void test_tcm(const void *unused)
|
||||
{
|
||||
uint64_t base = (uint64_t)sm8975_nsp.cfgtable.l2tcm_base << 16;
|
||||
|
||||
qtest_start("-machine sm8975-nsp");
|
||||
writel(base, 0xdeadbeef);
|
||||
writel(base + sm8975_nsp.l2tcm_size - 4, 0xcafef00d);
|
||||
g_assert_cmphex(readl(base), ==, 0xdeadbeef);
|
||||
g_assert_cmphex(readl(base + sm8975_nsp.l2tcm_size - 4), ==, 0xcafef00d);
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(qcom_dsp_machines); i++) {
|
||||
const char *name = qcom_dsp_machines[i];
|
||||
g_autofree char *path = NULL;
|
||||
|
||||
path = g_strdup_printf("/qcom-dsp/%s/console", name);
|
||||
qtest_add_data_func(path, name, test_console);
|
||||
path = g_strdup_printf("/qcom-dsp/%s/virtio-slots", name);
|
||||
qtest_add_data_func(path, name, test_virtio_slots);
|
||||
path = g_strdup_printf("/qcom-dsp/%s/default-drive", name);
|
||||
qtest_add_data_func(path, name, test_default_drive);
|
||||
}
|
||||
|
||||
qtest_add_data_func("/qcom-dsp/sm8975-nsp/tcm", NULL, test_tcm);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
@@ -12,6 +12,11 @@
|
||||
|
||||
#include "hw/hexagon/machine_cfg_v68n_1024.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_v66g_1024.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_qcs6490_cdsp.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_sm8975_nsp.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_sa8797p_nsp0.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_sc8480xp_nsp0.h.inc"
|
||||
#include "hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc"
|
||||
|
||||
#define QTIMER_DEFAULT_FREQ_HZ 19200000ULL
|
||||
|
||||
@@ -342,6 +347,11 @@ typedef struct {
|
||||
static const QtimerMachineCfg qtimer_machines[] = {
|
||||
{ "virt", &v68n_1024 },
|
||||
{ "V66G_1024", &v66g_1024 },
|
||||
{ "qcs6490-cdsp", &qcs6490_cdsp },
|
||||
{ "sa8775p-cdsp", &SA8775P_cdsp0 },
|
||||
{ "sc8480xp-nsp0", &sc8480xp_nsp0 },
|
||||
{ "sa8797p-nsp0", &sa8797p_nsp0 },
|
||||
{ "sm8975-nsp", &sm8975_nsp },
|
||||
};
|
||||
|
||||
static void test_qtimer_on_machine(gconstpointer data)
|
||||
|
||||
@@ -109,6 +109,43 @@ static inline int64_t atomic_dec64(int64_t *x)
|
||||
return old;
|
||||
}
|
||||
|
||||
static uint32_t v85_atomic_inc(uint32_t *counter)
|
||||
{
|
||||
uint32_t old_val;
|
||||
|
||||
asm volatile("r0 = %0\n"
|
||||
"r1 = %1\n"
|
||||
"r2 = #1\n"
|
||||
".word 0x9001e220\n" /* r0 = atomw_add(r1,r2):aq */
|
||||
"%0 = r0\n"
|
||||
: "=r"(old_val)
|
||||
: "r"(counter)
|
||||
: "r0", "r1", "r2");
|
||||
return old_val;
|
||||
}
|
||||
|
||||
static uint64_t v85_atomic_swap64(uint64_t *addr, uint64_t val)
|
||||
{
|
||||
asm volatile("r1:0 = %0\n"
|
||||
"r2 = %1\n"
|
||||
".word 0x90c2e0a0\n" /* r1:0 = atomd_swap(r2,r1:0):aq */
|
||||
"%0 = r1:0\n"
|
||||
: "+r"(val)
|
||||
: "r"(addr)
|
||||
: "r0", "r1", "r2");
|
||||
return val;
|
||||
}
|
||||
|
||||
static void v85_dcfetch_multi(const void *addr)
|
||||
{
|
||||
asm volatile("r0 = %0\n"
|
||||
"r1 = #0\n"
|
||||
".word 0x9400c840\n" /* dcfetch_multi(r0,r1) */
|
||||
:
|
||||
: "r"(addr)
|
||||
: "r0", "r1", "memory");
|
||||
}
|
||||
|
||||
#define LOOP_CNT 1000
|
||||
volatile int32_t tick32 = 1; /* Using volatile because we are testing atomics */
|
||||
volatile int64_t tick64 = 1; /* Using volatile because we are testing atomics */
|
||||
@@ -159,10 +196,84 @@ void test_pthread(void)
|
||||
check64(tick64, 1);
|
||||
}
|
||||
|
||||
static void test_v85_swap64(void)
|
||||
{
|
||||
#define INITIAL_V1 0xffffffffffffffff
|
||||
#define INITIAL_V2 0x1111111111111111
|
||||
|
||||
uint64_t v1 = INITIAL_V1;
|
||||
uint64_t v2 = INITIAL_V2;
|
||||
|
||||
v2 = v85_atomic_swap64(&v1, v2);
|
||||
check64(v1, INITIAL_V2);
|
||||
check64(v2, INITIAL_V1);
|
||||
|
||||
v2 = v85_atomic_swap64(&v1, v2);
|
||||
check64(v1, INITIAL_V1);
|
||||
check64(v2, INITIAL_V2);
|
||||
|
||||
#undef INITIAL_V1
|
||||
#undef INITIAL_V2
|
||||
}
|
||||
|
||||
#define V85_ROUNDS 1000
|
||||
#define V85_THREADS 10
|
||||
static uint32_t v85_global_counter = 1;
|
||||
static uint32_t v85_started_threads;
|
||||
|
||||
static void *v85_counter_thread(void *arg)
|
||||
{
|
||||
uint32_t previous;
|
||||
|
||||
v85_atomic_inc(&v85_started_threads);
|
||||
while (v85_started_threads != V85_THREADS) {
|
||||
asm volatile("pause(#0)");
|
||||
}
|
||||
previous = 0;
|
||||
for (int i = 0; i < V85_ROUNDS; i++) {
|
||||
uint32_t current = v85_atomic_inc(&v85_global_counter);
|
||||
|
||||
if (current <= previous) {
|
||||
printf("ERROR: counter is not strictly growing. "
|
||||
"Before: %" PRIu32 ", Now: %" PRIu32 "\n",
|
||||
previous, current);
|
||||
err = 1;
|
||||
return arg;
|
||||
}
|
||||
previous = current;
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
static void test_v85_race(void)
|
||||
{
|
||||
pthread_t tids[V85_THREADS];
|
||||
|
||||
for (int i = 0; i < V85_THREADS; i++) {
|
||||
pthread_create(&tids[i], NULL, v85_counter_thread, NULL);
|
||||
}
|
||||
for (int i = 0; i < V85_THREADS; i++) {
|
||||
pthread_join(tids[i], NULL);
|
||||
}
|
||||
check32(v85_global_counter, 1 + V85_THREADS * V85_ROUNDS);
|
||||
}
|
||||
|
||||
static void test_v85_inc32(void)
|
||||
{
|
||||
uint32_t counter = UINT32_MAX;
|
||||
|
||||
check32(v85_atomic_inc(&counter), UINT32_MAX);
|
||||
check32(counter, 0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_reservations();
|
||||
test_pthread();
|
||||
v85_dcfetch_multi(&v85_global_counter);
|
||||
test_v85_swap64();
|
||||
test_v85_race();
|
||||
test_v85_inc32();
|
||||
puts(err ? "FAIL" : "PASS");
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
.text
|
||||
valid_tgt:
|
||||
.word 0x7f80c000 /* nop_rb */
|
||||
jumpr r2
|
||||
|
||||
invalid_tgt:
|
||||
nop
|
||||
jumpr r2
|
||||
|
||||
valid_call_tgt:
|
||||
.word 0x7f80c000 /* nop_rb */
|
||||
jumpr r31
|
||||
|
||||
invalid_call_tgt:
|
||||
nop
|
||||
jumpr r31
|
||||
|
||||
.macro set_pred reg, id
|
||||
r4 = \id
|
||||
r3 = xor(\reg, r4)
|
||||
p0 = !cmp.eq(r3, #0)
|
||||
.endm
|
||||
|
||||
.macro set_pred_in_packet reg, id
|
||||
r4 = \id
|
||||
r3 = xor(\reg, r4)
|
||||
.word 0x75034010 /* { p0 = !cmp.eq(r3, #0) */
|
||||
.endm
|
||||
|
||||
/*
|
||||
* r0: nonzero for a valid target, zero for an invalid target
|
||||
* r1: test case number
|
||||
*/
|
||||
.global run_test_case
|
||||
run_test_case:
|
||||
r5 = r31
|
||||
p1 = cmp.eq(r0, #1)
|
||||
if (p1) r0 = #valid_tgt
|
||||
if (!p1) r0 = #invalid_tgt
|
||||
r2 = #return
|
||||
|
||||
set_pred r1, #0
|
||||
.word 0x53e0c000 /* if (!p0) jumpr_rb:nt r0 */
|
||||
|
||||
set_pred r1, #1
|
||||
.word 0x53e0d000 /* if (!p0) jumpr_rb:t r0 */
|
||||
|
||||
set_pred_in_packet r1, #2
|
||||
.word 0x53e0c800 /* if (!p0.new) jumpr_rb:nt r0 } */
|
||||
|
||||
set_pred_in_packet r1, #3
|
||||
.word 0x53e0d800 /* if (!p0.new) jumpr_rb:t r0 } */
|
||||
|
||||
p0 = cmp.eq(r1, #4)
|
||||
.word 0x53c0c000 /* if (p0) jumpr_rb:nt r0 */
|
||||
|
||||
p0 = cmp.eq(r1, #5)
|
||||
.word 0x53c0d000 /* if (p0) jumpr_rb:t r0 */
|
||||
|
||||
.word 0x750140c0 /* { p0 = cmp.eq(r1, #6) */
|
||||
.word 0x53c0c800 /* if (p0.new) jumpr_rb:nt r0 } */
|
||||
|
||||
.word 0x750140e0 /* { p0 = cmp.eq(r1, #7) */
|
||||
.word 0x53c0d800 /* if (p0.new) jumpr_rb:t r0 } */
|
||||
|
||||
p0 = cmp.eq(r1, #9)
|
||||
if (p0) jump callr_case
|
||||
p0 = cmp.eq(r1, #10)
|
||||
if (p0) jump callrh_case
|
||||
p0 = cmp.eq(r1, #11)
|
||||
if (p0) jump callrt_case
|
||||
p0 = cmp.eq(r1, #12)
|
||||
if (p0) jump callrf_case
|
||||
|
||||
.word 0x5200c000 /* jumpr_rb r0 */
|
||||
|
||||
callr_case:
|
||||
if (p1) r0 = #valid_call_tgt
|
||||
if (!p1) r0 = #invalid_call_tgt
|
||||
.word 0x5020c000 /* callr_rb r0 */
|
||||
jump return
|
||||
|
||||
callrh_case:
|
||||
if (p1) r0 = #valid_call_tgt
|
||||
if (!p1) r0 = #invalid_call_tgt
|
||||
.word 0x5040c000 /* callrh_rb r0 */
|
||||
jump return
|
||||
|
||||
callrt_case:
|
||||
if (p1) r0 = #valid_call_tgt
|
||||
if (!p1) r0 = #invalid_call_tgt
|
||||
p0 = cmp.eq(r0, r0)
|
||||
.word 0x5180c000 /* if (p0) callr_rb r0 */
|
||||
jump return
|
||||
|
||||
callrf_case:
|
||||
if (p1) r0 = #valid_call_tgt
|
||||
if (!p1) r0 = #invalid_call_tgt
|
||||
p0 = cmp.eq(r0, #0)
|
||||
.word 0x51a0c000 /* if (!p0) callr_rb r0 */
|
||||
jump return
|
||||
|
||||
return:
|
||||
jumpr r5
|
||||
|
||||
/* jumpr_rb r31 is a return, not a restricted branch. */
|
||||
.global run_jumpr_rb_lr_test
|
||||
run_jumpr_rb_lr_test:
|
||||
.word 0x521fc000 /* jumpr_rb r31 */
|
||||
|
||||
/* A target marker and restricted branch in the same packet. */
|
||||
.global run_jumpr_rb_nop_rb_test
|
||||
run_jumpr_rb_nop_rb_test:
|
||||
r0 = #1f
|
||||
.word 0x7f804000 /* { nop_rb */
|
||||
.word 0x5200c000 /* jumpr_rb r0 } */
|
||||
1:
|
||||
nop
|
||||
|
||||
/* A trap0(#0xdb) landing pad: the syscall must not leave CFI armed. */
|
||||
.global run_trap0_target_test
|
||||
run_trap0_target_test:
|
||||
r5 = r31
|
||||
r6 = #172 /* __NR_getpid */
|
||||
r0 = #1f
|
||||
.word 0x5200c000 /* jumpr_rb r0 */
|
||||
1:
|
||||
trap0(#0xdb)
|
||||
nop
|
||||
jumpr r5
|
||||
|
||||
/*
|
||||
* callr_rb r31 remains restricted: it must branch to a landing pad even
|
||||
* though it overwrites r31 with its return address.
|
||||
*/
|
||||
.global run_callr_rb_lr_test
|
||||
run_callr_rb_lr_test:
|
||||
r2 = r31
|
||||
p0 = cmp.eq(r0, #1)
|
||||
if (p0) r31 = #valid_callr_rb_lr_tgt
|
||||
if (!p0) r31 = #invalid_callr_rb_lr_tgt
|
||||
.word 0x503fc000 /* callr_rb r31 */
|
||||
jumpr r2
|
||||
|
||||
valid_callr_rb_lr_tgt:
|
||||
.word 0x7f80c000 /* nop_rb */
|
||||
jumpr r31
|
||||
|
||||
invalid_callr_rb_lr_tgt:
|
||||
nop
|
||||
jumpr r31
|
||||
|
||||
/*
|
||||
* Enter each restricted allocframe instruction with CFI active. The
|
||||
* following ordinary instructions show that the restricted target reset it.
|
||||
*/
|
||||
.global run_allocframe_test
|
||||
run_allocframe_test:
|
||||
r0 = #allocframe_rb_reg
|
||||
r2 = #allocframe_rb_duplex
|
||||
.word 0x5200c000 /* jumpr_rb r0 */
|
||||
|
||||
allocframe_rb_reg:
|
||||
.word 0xa09de000 /* allocframe_rb(r29, #0):raw */
|
||||
deallocframe
|
||||
nop
|
||||
jumpr r2
|
||||
|
||||
allocframe_rb_duplex:
|
||||
.word 0x70003e00 /* r0 = r0; allocframe_rb(#0) */
|
||||
deallocframe
|
||||
nop
|
||||
jumpr r31
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef CFI_TGTS_H
|
||||
#define CFI_TGTS_H
|
||||
|
||||
#define CFI_TEST_CASES 13
|
||||
|
||||
void run_test_case(int valid, int test_case);
|
||||
void run_callr_rb_lr_test(int valid);
|
||||
void run_jumpr_rb_lr_test(void);
|
||||
void run_jumpr_rb_nop_rb_test(void);
|
||||
void run_trap0_target_test(void);
|
||||
void run_allocframe_test(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Test a restricted branch interrupted by a data TLB miss.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <assert.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
static sigjmp_buf cfi_jmp;
|
||||
static volatile sig_atomic_t sigsegv_count;
|
||||
static volatile sig_atomic_t sigill_count;
|
||||
static void *target;
|
||||
|
||||
static void *landing_pad(int valid_target)
|
||||
{
|
||||
void *pad;
|
||||
|
||||
asm volatile(
|
||||
"p0 = cmp.eq(%[valid_target], #1)\n\t"
|
||||
"if (p0) %[pad] = ##valid_cfi_tlb_target\n\t"
|
||||
"if (!p0) %[pad] = ##invalid_cfi_tlb_target\n\t"
|
||||
: [pad] "=r"(pad) : [valid_target] "r"(valid_target) : "p0");
|
||||
return pad;
|
||||
}
|
||||
|
||||
static __attribute__((noinline)) void run_cfi_tlb_test(int valid_target)
|
||||
{
|
||||
asm volatile(
|
||||
"p0 = cmp.eq(%[valid_target], #1)\n\t"
|
||||
"if (p0) r0 = ##valid_cfi_tlb_target\n\t"
|
||||
"if (!p0) r0 = ##invalid_cfi_tlb_target\n\t"
|
||||
"r1 = #0\n\t"
|
||||
"r2 = #0\n\t"
|
||||
".word 0x52004000\n\t" /* { jumpr_rb r0 */
|
||||
".word 0xa181c200\n\t" /* memw(r1 + #0) = r2 } */
|
||||
"valid_cfi_tlb_target:\n\t"
|
||||
".word 0x7f80c000\n\t" /* nop_rb */
|
||||
"jump 1f\n\t"
|
||||
"invalid_cfi_tlb_target:\n\t"
|
||||
"nop\n\t"
|
||||
"1:\n\t"
|
||||
: : [valid_target] "r"(valid_target)
|
||||
: "r0", "r1", "r2", "p0", "memory");
|
||||
}
|
||||
|
||||
static void handle_sigsegv(int sig, siginfo_t *info, void *context)
|
||||
{
|
||||
ucontext_t *uc = context;
|
||||
|
||||
assert(sig == SIGSEGV);
|
||||
sigsegv_count++;
|
||||
uc->uc_mcontext.pc = (unsigned long)target;
|
||||
}
|
||||
|
||||
static void handle_sigill(int sig, siginfo_t *info, void *context)
|
||||
{
|
||||
assert(sig == SIGILL);
|
||||
sigill_count++;
|
||||
siglongjmp(cfi_jmp, 1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct sigaction action;
|
||||
|
||||
action.sa_sigaction = handle_sigsegv;
|
||||
sigemptyset(&action.sa_mask);
|
||||
action.sa_flags = SA_SIGINFO;
|
||||
assert(sigaction(SIGSEGV, &action, NULL) == 0);
|
||||
|
||||
action.sa_sigaction = handle_sigill;
|
||||
sigemptyset(&action.sa_mask);
|
||||
action.sa_flags = SA_SIGINFO;
|
||||
assert(sigaction(SIGILL, &action, NULL) == 0);
|
||||
|
||||
target = landing_pad(1);
|
||||
run_cfi_tlb_test(1);
|
||||
assert(sigsegv_count == 1);
|
||||
assert(sigill_count == 0);
|
||||
|
||||
target = landing_pad(0);
|
||||
if (sigsetjmp(cfi_jmp, 1) == 0) {
|
||||
run_cfi_tlb_test(0);
|
||||
abort();
|
||||
}
|
||||
assert(sigsegv_count == 2);
|
||||
assert(sigill_count == 1);
|
||||
|
||||
puts("PASS");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Test v83 restricted indirect control-flow forms and restricted targets.
|
||||
*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cfi_tgts.h"
|
||||
|
||||
static sigjmp_buf cfi_jmp;
|
||||
static volatile sig_atomic_t cfi_signal;
|
||||
|
||||
static void handle_sigill(int sig, siginfo_t *info, void *context)
|
||||
{
|
||||
assert(sig == SIGILL);
|
||||
cfi_signal = sig;
|
||||
siglongjmp(cfi_jmp, 1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct sigaction action;
|
||||
int i;
|
||||
|
||||
action.sa_sigaction = handle_sigill;
|
||||
sigemptyset(&action.sa_mask);
|
||||
action.sa_flags = SA_SIGINFO;
|
||||
assert(sigaction(SIGILL, &action, NULL) == 0);
|
||||
|
||||
for (i = 0; i < CFI_TEST_CASES; i++) {
|
||||
run_test_case(1, i);
|
||||
}
|
||||
|
||||
for (i = 0; i < CFI_TEST_CASES; i++) {
|
||||
cfi_signal = 0;
|
||||
if (sigsetjmp(cfi_jmp, 1) == 0) {
|
||||
run_test_case(0, i);
|
||||
abort();
|
||||
}
|
||||
assert(cfi_signal == SIGILL);
|
||||
}
|
||||
|
||||
run_jumpr_rb_lr_test();
|
||||
|
||||
cfi_signal = 0;
|
||||
if (sigsetjmp(cfi_jmp, 1) == 0) {
|
||||
run_jumpr_rb_nop_rb_test();
|
||||
abort();
|
||||
}
|
||||
assert(cfi_signal == SIGILL);
|
||||
|
||||
run_trap0_target_test();
|
||||
|
||||
run_callr_rb_lr_test(1);
|
||||
|
||||
cfi_signal = 0;
|
||||
if (sigsetjmp(cfi_jmp, 1) == 0) {
|
||||
run_callr_rb_lr_test(0);
|
||||
abort();
|
||||
}
|
||||
assert(cfi_signal == SIGILL);
|
||||
|
||||
run_allocframe_test();
|
||||
|
||||
puts("PASS");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -122,6 +122,13 @@ TRY_FUNC(v79_dczeroa_nt,
|
||||
TRY_FUNC(v79_dcfetchbo_nt,
|
||||
".word 0x9402e000 /* dcfetch(r2+#0):nt */\n")
|
||||
|
||||
TRY_FUNC(v83_callr_rb,
|
||||
".word 0x5020c000 /* callr_rb r0 */\n")
|
||||
TRY_FUNC(v83_nop_rb,
|
||||
".word 0x7f80c000 /* nop_rb */\n")
|
||||
TRY_FUNC(v83_vsfadd,
|
||||
".word 0xeb02c440 /* r1:0 = vsfadd(r3:2, r5:4) */\n")
|
||||
|
||||
TRY_FUNC(v79hvx_vmerge_qf,
|
||||
".word 0x1f01e0e2 /* v2 = vmerge(v0.x, v1.w) */\n")
|
||||
|
||||
@@ -165,6 +172,9 @@ int main(void)
|
||||
assert(try_v79_pstorerif_pi_nt() == SIGILL);
|
||||
assert(try_v79_dczeroa_nt() == SIGILL);
|
||||
assert(try_v79_dcfetchbo_nt() == SIGILL);
|
||||
assert(try_v83_callr_rb() == SIGILL);
|
||||
assert(try_v83_nop_rb() == SIGILL);
|
||||
assert(try_v83_vsfadd() == SIGILL);
|
||||
|
||||
assert(try_v79hvx_vmerge_qf() == SIGILL);
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright(c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int err;
|
||||
|
||||
#include "hex_test.h"
|
||||
|
||||
/*
|
||||
* allocframe pushes {LR, FP}, scrambling LR with FRAMEKEY. Return through
|
||||
* dealloc_return and report the FP that it restores.
|
||||
*/
|
||||
static inline uint32_t frame_roundtrip(uint32_t key, uint32_t fp)
|
||||
{
|
||||
uint32_t fp_back, saved_fp, saved_lr;
|
||||
|
||||
asm volatile("%[saved_fp] = r30\n\t"
|
||||
"%[saved_lr] = r31\n\t"
|
||||
"framekey = %[key]\n\t"
|
||||
"r30 = %[fp]\n\t"
|
||||
"r31 = ##1f\n\t"
|
||||
"allocframe(#0)\n\t"
|
||||
"r31 = #0\n\t"
|
||||
"dealloc_return\n\t"
|
||||
"1:\n\t"
|
||||
"%[fp_back] = r30\n\t"
|
||||
"framekey = %[zero]\n\t"
|
||||
"r30 = %[saved_fp]\n\t"
|
||||
"r31 = %[saved_lr]\n"
|
||||
: [fp_back] "=&r"(fp_back),
|
||||
[saved_fp] "=&r"(saved_fp), [saved_lr] "=&r"(saved_lr)
|
||||
: [key] "r"(key), [fp] "r"(fp), [zero] "r"(0)
|
||||
: "memory", "framekey");
|
||||
return fp_back;
|
||||
}
|
||||
|
||||
static void check_frame(uint32_t key, uint32_t fp)
|
||||
{
|
||||
check32(frame_roundtrip(key, fp), fp);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
check_frame(0, 0x1234fff0);
|
||||
check_frame(0xf21f20a0, 0x1234fff0);
|
||||
|
||||
puts(err ? "FAIL" : "PASS");
|
||||
return err;
|
||||
}
|
||||
@@ -89,6 +89,25 @@ static int test_invalid_nonduplex(void)
|
||||
return sig;
|
||||
}
|
||||
|
||||
/* L4_loadw_phys bit 7 was reserved beginning with v83. */
|
||||
static int test_v83_loadw_phys_reserved_bit(void)
|
||||
{
|
||||
int sig;
|
||||
|
||||
asm volatile(
|
||||
"r0 = #0\n"
|
||||
"r1 = ##1f\n"
|
||||
"memw(%1) = r1\n"
|
||||
".word 0x9200e080\n" /* r0 = memw_phys(r0, r0), bit 7 = 1 */
|
||||
"1:\n"
|
||||
"%0 = r0\n"
|
||||
: "=r"(sig)
|
||||
: "r"(&resume_pc)
|
||||
: "r0", "r1", "memory");
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct sigaction act;
|
||||
@@ -100,6 +119,7 @@ int main()
|
||||
|
||||
assert(test_invalid_duplex() == SIGILL);
|
||||
assert(test_invalid_nonduplex() == SIGILL);
|
||||
assert(test_v83_loadw_phys_reserved_bit() == SIGILL);
|
||||
|
||||
puts("PASS");
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
@@ -25,8 +25,20 @@ foreach t: tcg_tests['multiarch-linux-user']['tests']
|
||||
endforeach
|
||||
|
||||
tests += {
|
||||
'atomics.c': {'cflags': cflags},
|
||||
# The cross assembler does not know v85; v85 instructions in atomics.c
|
||||
# are encoded with .word directives.
|
||||
'atomics.c': {'cflags': cflags, 'qemu_args': ['-cpu', 'v85']},
|
||||
'brev.c': {'cflags': cflags},
|
||||
# The cross assembler does not know v83; cfi_tlb.c uses raw encodings.
|
||||
'cfi_tlb.c': {
|
||||
'cflags': cflags,
|
||||
'qemu_args': ['-cpu', 'v85'],
|
||||
},
|
||||
# The cross assembler does not know v83; cfi_tgts.S uses raw encodings.
|
||||
'cfi_user.c': {
|
||||
'cflags': [cflags, files('cfi_tgts.S')],
|
||||
'qemu_args': ['-cpu', 'v85'],
|
||||
},
|
||||
# Compile for v66 so that the ELF selects a v66 CPU; the test then
|
||||
# exercises revision gating by executing a v68 .word instruction.
|
||||
'check_rev_gating.c': {
|
||||
@@ -57,7 +69,7 @@ tests += {
|
||||
'cflags': [cflags, '-mhvx', '-Wno-gnu-folding-constant',
|
||||
files('hvx_histogram_row.S')]
|
||||
},
|
||||
'invalid-encoding.c': {'cflags': cflags},
|
||||
'invalid-encoding.c': {'cflags': cflags, 'qemu_args': ['-cpu', 'v85']},
|
||||
'invalid-slots.c': {'cflags': cflags},
|
||||
'icinva.c': {'cflags': cflags},
|
||||
'load_align.c': {'cflags': cflags},
|
||||
@@ -68,6 +80,7 @@ tests += {
|
||||
'overflow.c': {'cflags': cflags, 'exe_name': 'hex-overflow'},
|
||||
'preg_alias.c': {'cflags': cflags},
|
||||
'dual_stores.c': {'cflags': cflags},
|
||||
'framekey.c': {'cflags': cflags},
|
||||
'multi_result.c': {'cflags': cflags},
|
||||
'mem_noshuf.c': {'cflags': cflags},
|
||||
'mem_noshuf_exception.c': {'cflags': cflags},
|
||||
@@ -106,6 +119,8 @@ tests += {
|
||||
'test_vpmpyh.S': {'cflags': asmflags},
|
||||
'test_vspliceb.S': {'cflags': asmflags},
|
||||
'test_vwhist.c': {'cflags': [cflags, '-mhvx']},
|
||||
# The cross assembler does not know trap2; the test uses its raw encoding.
|
||||
'trap2.c': {'cflags': cflags, 'qemu_args': ['-cpu', 'v85']},
|
||||
'unaligned_pc.c': {'cflags': cflags},
|
||||
'unaligned_data.c': {'cflags': cflags},
|
||||
'usr.c': {
|
||||
@@ -117,6 +132,12 @@ tests += {
|
||||
'v69_hvx.c': {'cflags': [cflags, '-mhvx', '-Wno-unused-function', '-mv69']},
|
||||
'v73_scalar.c': {'cflags': [cflags, '-Wno-unused-function', '-mv73']},
|
||||
'v79_scalar.c': {'cflags': [cflags, '-Wno-unused-function', '-mv79']},
|
||||
'v83_scalar_fp.c': {'cflags': [cflags, '-mv67'],
|
||||
'qemu_args': ['-cpu', 'v85']},
|
||||
# The cross assembler does not know v83; the vallocframe instructions in
|
||||
# this test are encoded with .word directives.
|
||||
'vallocframe.c': {'cflags': [cflags, '-mv67', '-O2'],
|
||||
'qemu_args': ['-cpu', 'v85']},
|
||||
'valid-slots.c': {'cflags': cflags},
|
||||
'vector_add_int.c': {'cflags': [cflags, '-mhvx', '-fvectorize']},
|
||||
}
|
||||
|
||||
Loaded 100 of 103 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user