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