1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <sel4vm/guest_vm.h>
8#include <sel4vm/boot.h>
9#include <sel4vm/guest_irq_controller.h>
10
11#include <sel4vmmplatsupport/guest_vcpu_util.h>
12#include <sel4vmmplatsupport/arch/guest_vcpu_fault.h>
13#include <sel4vmmplatsupport/arch/irq_defs.h>
14
15#include <libfdt.h>
16#include <fdtgen.h>
17
18#define MAX_CPU_NAME_LENGTH 8
19
20#define FDT_OP(op)                                      \
21    do {                                                \
22        int err = (op);                                 \
23        ZF_LOGF_IF(err < 0, "FDT operation failed");    \
24    } while(0)                                          \
25
26static void vppi_event_ack(vm_vcpu_t *vcpu, int irq, void *cookie)
27{
28    seL4_Error err = seL4_ARM_VCPU_AckVPPI(vcpu->vcpu.cptr, (seL4_Word)irq);
29    if (err) {
30        ZF_LOGE("Failed to ACK VPPI: VCPU VPPIAck invocation failed");
31    }
32}
33
34static void sgi_ack(vm_vcpu_t *vcpu, int irq, void *cookie) {}
35
36vm_vcpu_t *create_vmm_plat_vcpu(vm_t *vm, int priority)
37{
38    int err;
39    vm_vcpu_t *vm_vcpu = vm_create_vcpu(vm, priority);
40    if (vm_vcpu == NULL) {
41        ZF_LOGE("Failed to create platform vcpu");
42        return NULL;
43    }
44    err = vm_register_unhandled_vcpu_fault_callback(vm_vcpu, vmm_handle_arm_vcpu_exception, NULL);
45    if (err) {
46        ZF_LOGE("Failed to register vcpu platform fault callback handlers");
47        return NULL;
48    }
49    err = vm_register_irq(vm_vcpu, PPI_VTIMER_IRQ, &vppi_event_ack, NULL);
50    if (err == -1) {
51        ZF_LOGE("Failed to register vcpu virtual time irq");
52        return NULL;
53    }
54
55    err = vm_register_irq(vm_vcpu, SGI_RESCHEDULE_IRQ, &sgi_ack, NULL);
56    if (err == -1) {
57        ZF_LOGE("Failed to register vcpu sgi 0 irq");
58        return NULL;
59    }
60
61    err = vm_register_irq(vm_vcpu, SGI_FUNC_CALL, &sgi_ack, NULL);
62    if (err == -1) {
63        ZF_LOGE("Failed to register vcpu sgi 1 irq");
64        return NULL;
65    }
66
67    return vm_vcpu;
68}
69
70static int generate_psci_node(void *fdt, int root_offset)
71{
72    int psci_node = fdt_add_subnode(fdt, root_offset, "psci");
73    if (psci_node < 0) {
74        return psci_node;
75    }
76    FDT_OP(fdt_appendprop_u32(fdt, psci_node, "cpu_off", 0x84000002));
77    FDT_OP(fdt_appendprop_u32(fdt, psci_node, "cpu_on", 0xc4000003));
78    FDT_OP(fdt_appendprop_u32(fdt, psci_node, "cpu_suspend", 0xc4000001));
79    FDT_OP(fdt_appendprop_string(fdt, psci_node, "method", "smc"));
80    FDT_OP(fdt_appendprop_string(fdt, psci_node, "compatible", "arm,psci-1.0"));
81    FDT_OP(fdt_appendprop_string(fdt, psci_node, "status", "okay"));
82    return 0;
83}
84
85int fdt_generate_plat_vcpu_node(vm_t *vm, void *fdt)
86{
87    int root_offset = fdt_path_offset(fdt, "/");
88    int cpu_node = fdt_add_subnode(fdt, root_offset, "cpus");
89    if (cpu_node < 0) {
90        return cpu_node;
91    }
92    FDT_OP(fdt_appendprop_u32(fdt, cpu_node, "#address-cells", 0x1));
93    FDT_OP(fdt_appendprop_u32(fdt, cpu_node, "#size-cells", 0x0));
94    for (int i = 0; i < vm->num_vcpus; i++) {
95        vm_vcpu_t *vcpu = vm->vcpus[i];
96        char cpu_name[MAX_CPU_NAME_LENGTH];
97        snprintf(cpu_name, MAX_CPU_NAME_LENGTH, "cpu@%x", vcpu->vcpu_id);
98        int sub_cpu_node = fdt_add_subnode(fdt, cpu_node, cpu_name);
99        if (sub_cpu_node < 0) {
100            return sub_cpu_node;
101        }
102        FDT_OP(fdt_appendprop_string(fdt, sub_cpu_node, "device_type", "cpu"));
103        FDT_OP(fdt_appendprop_string(fdt, sub_cpu_node, "compatible", PLAT_CPU_COMPAT));
104        FDT_OP(fdt_appendprop_u32(fdt, sub_cpu_node, "reg", vcpu->vcpu_id));
105        if (vm->num_vcpus > 1) {
106            FDT_OP(fdt_appendprop_string(fdt, sub_cpu_node, "enable-method", "psci"));
107        }
108    }
109    int ret = 0;
110    if (vm->num_vcpus > 1) {
111        ret = generate_psci_node(fdt, root_offset);
112    }
113    return 0;
114}
115