Skip to content

Commit

Permalink
draft: support for Hexagon VM
Browse files Browse the repository at this point in the history
Status: boots linux kernel up to setup_command_line() before panic

Hacks:
* vmnewmap call not implemented (does get invoked by linux)
* vmyield call not implemented (does get invoked by linux)
* trap0 not quite right (not _yet_ invoked by linux)

Signed-off-by: Brian Cain <[email protected]>
  • Loading branch information
androm3da committed May 2, 2024
1 parent 2ad908f commit 3204331
Show file tree
Hide file tree
Showing 16 changed files with 1,054 additions and 1 deletion.
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
* - 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
- 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 @@ -127,6 +127,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 @@ -573,11 +574,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 @@ -1862,5 +1862,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"
1 change: 1 addition & 0 deletions target/hexagon/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,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

0 comments on commit 3204331

Please sign in to comment.