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:
Richard Henderson committed 2026-10-27 11:41:22 -05:00
commit 9b77fa7a4f
103 files changed
+4349 -474

No files matched your search

+6
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
+265
View File
@@ -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);
}
}
+9 -5
View File
@@ -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
View File
@@ -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)
+18
View File
@@ -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,
+65
View File
@@ -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,
},
};
+5 -1
View File
@@ -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,
},
};
+56
View File
@@ -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,
},
};
+55
View File
@@ -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,
},
};
+73
View File
@@ -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,
},
};
+34
View File
@@ -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,
},
};
+50
View File
@@ -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,
},
};
+51
View File
@@ -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,
},
};
+7
View File
@@ -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}
+410
View File
@@ -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)
+64
View File
@@ -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)
+59
View File
@@ -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)
+68
View File
@@ -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)
+90
View File
@@ -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)
+102
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+3
View File
@@ -267,3 +267,6 @@ config SOPHGO_CV1800B_CLK
bool
source macio/Kconfig
config QCOM_QDSP6SS_CLK
bool
+3
View File
@@ -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'))
+208
View File
@@ -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)
+65
View File
@@ -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 */
+16 -2
View File
@@ -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;
+2
View File
@@ -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,
+81
View File
@@ -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 */
-6
View File
@@ -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)
+10 -4
View File
@@ -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 */
+15
View File
@@ -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 */
+14
View File
@@ -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:
+10
View File
@@ -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);
+8
View File
@@ -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)
+2
View File
@@ -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,
+1 -1
View File
@@ -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)
+2
View File
@@ -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", "", "")
+4
View File
@@ -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
View File
@@ -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)
+12
View File
@@ -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,
+3
View File
@@ -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,
+8 -58
View File
@@ -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 */
-2
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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
+3 -1
View File
@@ -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
View File
@@ -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)
+9
View File
@@ -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)
+91
View File
@@ -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)
+12
View File
@@ -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,
+6
View File
@@ -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
+8 -3
View File
@@ -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++) {
+23 -5
View File
@@ -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,
+2 -1
View File
@@ -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);
+2
View File
@@ -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
View File
@@ -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;
+1
View File
@@ -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;
+8 -1
View File
@@ -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);
+15 -1
View File
@@ -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->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);
+3
View File
@@ -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),
+38
View File
@@ -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); }})
/*********************************************/
+41 -2
View File
@@ -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----")
+49
View File
@@ -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;)
+15 -1
View File
@@ -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);
+10
View File
@@ -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)
+2
View File
@@ -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); })
+9
View File
@@ -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();})
+2 -1
View File
@@ -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()
},
+12
View File
@@ -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) \
+5
View File
@@ -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;
+88 -5
View File
@@ -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();
+2 -1
View File
@@ -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>");
+1
View File
@@ -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)
+66 -16
View File
@@ -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
View File
@@ -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,
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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()
+78
View File
@@ -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();
}
+10
View File
@@ -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)
+3 -1
View File
@@ -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(
+113
View File
@@ -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();
}
+10
View File
@@ -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)
+111
View File
@@ -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;
}
+178
View File
@@ -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
+18
View File
@@ -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
+99
View File
@@ -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;
}
+73
View File
@@ -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;
}
+10
View File
@@ -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);
+54
View File
@@ -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;
}
+20
View File
@@ -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;
+23 -2
View File
@@ -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