AArch64 EL2 hypervisor for QEMU virt that boots at EL2
1#include "hv/arch.h"
2#include "hv/log.h"
3#include "hv/psci.h"
4#include "hv/string.h"
5#include "hv/uart.h"
6
7#define PSCI32_VERSION 0x84000000ull
8#define PSCI32_CPU_SUSPEND 0x84000001ull
9#define PSCI32_CPU_OFF 0x84000002ull
10#define PSCI32_CPU_ON 0x84000003ull
11#define PSCI32_AFFINITY_INFO 0x84000004ull
12#define PSCI32_SYSTEM_OFF 0x84000008ull
13#define PSCI32_SYSTEM_RESET 0x84000009ull
14#define PSCI32_FEATURES 0x8400000aull
15#define PSCI64_CPU_SUSPEND 0xc4000001ull
16#define PSCI64_CPU_ON 0xc4000003ull
17#define PSCI64_AFFINITY_INFO 0xc4000004ull
18
19#define PSCI_RET_SUCCESS 0ull
20#define PSCI_RET_NOT_SUPPORTED UINT64_MAX
21#define PSCI_RET_INVALID_PARAMETERS (~0ull - 1ull)
22#define PSCI_RET_DENIED (~0ull - 2ull)
23
24static uint64_t g_calls;
25static uint64_t g_denied_cpu_on;
26static uint64_t g_last_function;
27
28static void log_psci(struct vcpu *vcpu, uint64_t fid, uint64_t ret)
29{
30 struct log_event ev;
31 hv_memset(&ev, 0, sizeof(ev));
32 ev.kind = LOG_HVC;
33 ev.vcpu = vcpu != (struct vcpu *)0 ? vcpu->id : UINT64_MAX;
34 ev.operand = fid;
35 ev.result = ret;
36 ev.reason = 320u;
37 ev.name = "psci";
38 log_event_commit(&ev);
39}
40
41bool psci_handle_call(struct vcpu *vcpu, uint64_t function_id)
42{
43 uint64_t ret = PSCI_RET_NOT_SUPPORTED;
44
45 if (vcpu == (struct vcpu *)0) {
46 return false;
47 }
48
49 g_calls++;
50 g_last_function = function_id;
51 switch (function_id) {
52 case PSCI32_VERSION:
53 ret = 0x00010001ull;
54 break;
55 case PSCI32_FEATURES: {
56 uint64_t query = vcpu_read_gpr(vcpu, 1u);
57 if (query == PSCI32_VERSION || query == PSCI32_FEATURES ||
58 query == PSCI32_AFFINITY_INFO || query == PSCI64_AFFINITY_INFO ||
59 query == PSCI32_SYSTEM_OFF || query == PSCI32_SYSTEM_RESET) {
60 ret = PSCI_RET_SUCCESS;
61 }
62 break;
63 }
64 case PSCI32_AFFINITY_INFO:
65 case PSCI64_AFFINITY_INFO:
66 ret = PSCI_RET_SUCCESS;
67 break;
68 case PSCI32_CPU_SUSPEND:
69 case PSCI64_CPU_SUSPEND:
70 ret = PSCI_RET_DENIED;
71 break;
72 case PSCI32_CPU_ON:
73 case PSCI64_CPU_ON:
74 g_denied_cpu_on++;
75 ret = PSCI_RET_DENIED;
76 break;
77 case PSCI32_CPU_OFF:
78 ret = PSCI_RET_DENIED;
79 break;
80 case PSCI32_SYSTEM_OFF:
81 case PSCI32_SYSTEM_RESET:
82 log_psci(vcpu, function_id, PSCI_RET_SUCCESS);
83 uart_puts("psci power request function=");
84 uart_put_hex64(function_id);
85 uart_puts("; halting\n");
86 arch_halt();
87 default:
88 ret = PSCI_RET_NOT_SUPPORTED;
89 break;
90 }
91
92 vcpu_write_gpr(vcpu, 0u, ret);
93 log_psci(vcpu, function_id, ret);
94 arch_advance_guest_pc(vcpu);
95 return true;
96}
97
98void psci_dump(void)
99{
100 uart_puts("psci calls=");
101 uart_put_dec64(g_calls);
102 uart_puts(" denied_cpu_on=");
103 uart_put_dec64(g_denied_cpu_on);
104 uart_puts(" last=");
105 uart_put_hex64(g_last_function);
106 uart_puts("\n");
107}