Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

draft: support for hexagon VM #88

Draft
wants to merge 3 commits into
base: hexagon_sysemu_20_dec_2023
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 186 additions & 0 deletions docs/system/hexagon/hvm.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
Hexagon Virtual Machine
=======================

The hexagon virtual machine is a hypervisor that can partition a single
Hexagon DSP among multiple guest operating systems, and abstracts the
specific details of a DSP architectural revision for the sake of consistency
among generations.

The ``virt`` machine has Hexagon VM emulation enabled by default.

Events
------

The guest operating system should register the Guest Event Vector Base
via the ``vmsetvec`` virtual instruction at system startup. The vector table
and handlers are determined by the guest OS.

Guests return from event handlers with ``vmrte``. This instruction will restore
the mode (user versus guest), interrupt enable state, PC, SP.

.. list-table:: Event types
:header-rows: 1

* - Number
- Name
- Description
- Maskable
- Detail
* - 0
- Reserved
-
-
-
* - 1
- Machine check event
- unrecoverable VM state
- No
- execution terminates if unhandled
* - 2
- General exception
- internal hardware or software exception
- No
-
* - 3-4
- Reserved
-
-
-
* - 5
- ``trap0``
- ``trap0`` instruction
- No
-
* - 6
- Reserved
-
-
-
* - 7
- Interrupt
- external interrupts
- Yes
- increasing interrupt numbers have descending priority

Startup
-------
In order to transition to user-mode, the guest OS must set the ``UM`` bit in
the guest status register and specify the address to start executing in
user mode in the guest event link register.

Virtual Instructions
--------------------

.. list-table:: Virtual Instructions
:header-rows: 1

* - Instruction
- Behavior
- Operand
- Input
- Output
* - vmversion
- returns the VM version
- 0x0
- requested VM version
- provided VM version
androm3da marked this conversation as resolved.
Show resolved Hide resolved
* - vmrte
- return from event
- 0x1
- Event info in g3:0
- N/A
* - vmsetvec
- set event vector
- 0x2
- r0 is set to vector table addr
- r0 is 0 on success, 1 otherwise
* - vmsetie
- set interrupt enabled
- 0x3
- r0 is set to 1 to enable, 0 to disable
- previous IE bit is stored as LSB of r0
* - vmgetie
- get interrupt enabled
- 0x4
- N/A
- current IE bit is stored as LSB of r0
* - vmintop
- interrupt operation
- 0x5
- r0 = Interrupt Op, r1-r4: Depends on Op
- r0 - value depends on operation
* - vmclrmap
- clear virtual memory map
- 0xa
- r0 = Interrupt Op, r1-r4: Depends on Op
- r0 - value depends on operation
* - vmnewmap
- set new virtual memory map
- 0xb
- r0 contains logical address of new segment table, r1 = type of translations: 0 indicates a logical address of a zero-terminated linear list, 1 indicates a set of page tables.
- r0 contains 0 on success, otherwise negative error code
* - vmcache
- VM cache control: not modeled
- 0xd
- r0 contains the operation to be performed, r1 = Starting virtual address, r2 contains the length in bytes
- r0 contains 0 on success, otherwise -1. Cache behavior is not modeled so this operation always succeeds.
* - vmgettime
- Get virtual machine time
- 0xe
- N/A
- r0 contains the least significant 32 bits of timestamp, r1 contains the most significant 32 bits of timestamp
* - vmsettime
- Set virtual machine time
- 0xf
- r0 contains the least significant 32 bits of timestamp, r1 contains the most significant 32 bits of timestamp
- N/A
* - vmwait
- wait for interrupt
- 0x10
- N/A
- r0 contains the interrupt number of the interrupt waking the guest
* - vmyield
- voluntarily yield VM task
- 0x11
- N/A
- N/A
* - vmstart
- Create new virtual processor instance
- 0x12
- r0 contains the starting execution address, r1 contains the starting stack pointer
- r0 contains the Virtual processor number of new virtual processor on success, otherwise -1
* - vmstop
- terminate current virtual processor instance
- 0x13
- N/A
- N/A
* - vmvpid
- get the virtual processor ID
- 0x14
- N/A
- r0 contains the virtual processor number of virtual processor executing the instruction
* - vmsetregs
- Set guest registers
- 0x15
- r0-3 hold g0-3 values
- N/A
* - vmgetregs
- Get guest registers
- 0x16
- N/A
- r0-3 hold g0-3 values
* - vmtimerop
- perform an operation on a system timer
- 0x18
- getfreq = 0
getres = 1
gettime = 2
gettimeout = 3
settimeout = 4
deltatimeout = 5
- TBD
* - vmgetinfo
- Get system info
- 0x1a
- Index of the system info parameter: FIXME another table
- value of the indicated system info parameter
1 change: 1 addition & 0 deletions hw/hexagon/hexagon_testboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev,
CPUHexagonState *env = &cpu->env;
qemu_register_reset(do_cpu_reset, cpu);

qdev_prop_set_bit(DEVICE(cpu), "hexagon-vm", true);
qdev_prop_set_uint32(DEVICE(cpu), "thread-count", machine->smp.cpus);
qdev_prop_set_uint32(DEVICE(cpu), "config-table-addr",
cfgExtensions->cfgbase);
Expand Down
7 changes: 7 additions & 0 deletions target/hexagon/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ static Property hexagon_cpu_properties[] = {
DEFINE_PROP_BOOL("isdben-dfd-enable", HexagonCPU, isdben_dfd_enable, false),
DEFINE_PROP_BOOL("isdben-trusted", HexagonCPU, isdben_trusted, false),
DEFINE_PROP_BOOL("isdben-secure", HexagonCPU, isdben_secure, false),
DEFINE_PROP_BOOL("hexagon-vm", HexagonCPU, hexagon_vm, false),
DEFINE_PROP_STRING("dump-json-reg-file", HexagonCPU, dump_json_file),
#endif
DEFINE_PROP_UINT32("dsp-rev", HexagonCPU, rev_reg, 0),
Expand Down Expand Up @@ -571,11 +572,17 @@ static void hexagon_restore_state_to_opc(CPUState *cs,
#if !defined(CONFIG_USER_ONLY)
void hexagon_cpu_soft_reset(CPUHexagonState *env)
{
CPUState *cs = env_cpu(env);
HexagonCPU *cpu = HEXAGON_CPU(cs);
ARCH_SET_SYSTEM_REG(env, HEX_SREG_SSR, 0);
hexagon_ssr_set_cause(env, HEX_CAUSE_RESET);

target_ulong evb = ARCH_GET_SYSTEM_REG(env, HEX_SREG_EVB);
ARCH_SET_THREAD_REG(env, HEX_REG_PC, evb);

if (cpu->hexagon_vm) {
ARCH_SET_SYSTEM_REG(env, HEX_SREG_IMASK, 0xffffffff);
}
}
#endif

Expand Down
1 change: 1 addition & 0 deletions target/hexagon/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ struct ArchCPU {
bool isdben_dfd_enable;
bool isdben_trusted;
bool isdben_secure;
bool hexagon_vm;
#endif
uint32_t rev_reg;
bool lldb_compat;
Expand Down
2 changes: 2 additions & 0 deletions target/hexagon/gen_tcg.h
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,8 @@
do { RsV = RsV; } while (0)
#define fGEN_TCG_Y2_icinva(SHORTCODE) \
do { RsV = RsV; } while (0)
#define fGEN_TCG_J2_trap1(SHORTCODE) \
do { (void) uiV; } while (0)
#else
/* data/insn cache ops can raise exceptions */
#define fGEN_TCG_CACHEOP(HELPER) \
Expand Down
5 changes: 5 additions & 0 deletions target/hexagon/gen_tcg_sys.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,9 @@
tcg_gen_extrh_i64_i32(ctx->t_sreg_new_value[HEX_SREG_SGP1], tmp); \
} while (0)

#define fGEN_TCG_J2_trap1(SHORTCODE) \
do { \
gen_vminst(ctx, uiV); \
} while (0)

#endif
98 changes: 98 additions & 0 deletions target/hexagon/genptr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1870,5 +1870,103 @@ static void gen_vtcm_memcpy(DisasContext *ctx, TCGv dst, TCGv src, TCGv size)
gen_set_label(finish);
}

#if !defined(CONFIG_USER_ONLY)
enum hex_virt_opc {
HEX_VIRT_VMVERSION = 0x00,
HEX_VIRT_VMRETURN = 0x01,
HEX_VIRT_VMSETVEC = 0x02,
HEX_VIRT_VMSETIE = 0x03,
HEX_VIRT_VMGETIE = 0x04,
HEX_VIRT_VMINTOP = 0x05,
HEX_VIRT_VMCLRMAP = 0x0A,
HEX_VIRT_VMNEWMAP = 0x0B,
HEX_VIRT_VMCACHECTL = 0x0D,
HEX_VIRT_VMGETTIME = 0x0E,
HEX_VIRT_VMSETTIME = 0x0F,
HEX_VIRT_VMWAIT = 0x10,
HEX_VIRT_VMYIELD = 0x11,
HEX_VIRT_VMSTART = 0x12,
HEX_VIRT_VMSTOP = 0x13,
HEX_VIRT_VMVMPID = 0x14,
HEX_VIRT_VMSETREGS = 0x15,
HEX_VIRT_VMGETREGS = 0x16,
HEX_VIRT_VMTIMEROP = 0x18,
HEX_VIRT_VMPMUCTRL = 0x19,
HEX_VIRT_VMGETINFO = 0x1A,
};

#include "hex_vm.c.inc"

static void gen_vminst(DisasContext *ctx, int operand)
{
if (!ctx->has_hexagon_vm) {
/* FIXME: raise an exception instead? */
return;
}

/* TODO: when swapping guest/user, must exchange GOSP, R29... */
switch (operand) {
case HEX_VIRT_VMVERSION:
gen_vmversion();
break;
case HEX_VIRT_VMSETREGS:
gen_vmsetregs();
break;
case HEX_VIRT_VMGETREGS:
gen_vmgetregs();
break;
case HEX_VIRT_VMSETIE:
gen_vmsetie();
break;
case HEX_VIRT_VMGETIE:
gen_vmgetie();
break;
case HEX_VIRT_VMVMPID:
gen_vmvpid();
break;
case HEX_VIRT_VMCACHECTL:
gen_vmcache();
break;
case HEX_VIRT_VMSTOP:
gen_vmstop();
break;
case HEX_VIRT_VMYIELD:
gen_vmyield();
break;
case HEX_VIRT_VMGETTIME:
gen_vmgettime();
break;
case HEX_VIRT_VMRETURN:
gen_vmrte();
break;
case HEX_VIRT_VMCLRMAP:
gen_vmclrmap();
break;
case HEX_VIRT_VMNEWMAP:
gen_vmnewmap();
break;
case HEX_VIRT_VMSETVEC:
gen_vmsetvec();
break;
case HEX_VIRT_VMINTOP:
gen_vmintop();
break;
case HEX_VIRT_VMGETINFO:
gen_vmgetinfo();
break;
case HEX_VIRT_VMTIMEROP:
gen_vmtimerop();
break;


default:
/* FIXME: Invalid packet exception? */
fprintf(stderr, "Unknown VM instruction 0x%08x\n", operand);
g_assert_not_reached();
break;
}
}
#endif

#include "tcg_funcs_generated.c.inc"
#include "tcg_func_table_generated.c.inc"
4 changes: 4 additions & 0 deletions target/hexagon/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ DEF_HELPER_2(nmi, void, env, i32)
DEF_HELPER_3(setprio, void, env, i32, i32)
DEF_HELPER_2(start, void, env, i32)
DEF_HELPER_1(stop, void, env)

DEF_HELPER_4(vmnewmap, void, env, i32, i32, i32)
DEF_HELPER_2(vmgetinfo, i32, env, i32)
#endif

DEF_HELPER_5(check_vtcm_memcpy, void, env, i32, i32, i32, i32)
Expand Down Expand Up @@ -148,6 +151,7 @@ DEF_HELPER_2(greg_read, i32, env, i32)
DEF_HELPER_2(greg_read_pair, i64, env, i32)
DEF_HELPER_1(inc_gcycle_xt, void, env)
DEF_HELPER_3(modify_ssr, void, env, i32, i32)
DEF_HELPER_2(modify_syscfg, void, env, i32)
DEF_HELPER_1(pending_interrupt, void, env)
DEF_HELPER_3(raise_stack_overflow, void, env, i32, i32)
DEF_HELPER_1(resched, void, env)
Expand Down
Loading