| /* | |
| * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) | |
| * | |
| * SPDX-License-Identifier: BSD-2-Clause | |
| */ | |
| #pragma once | |
| #include <autoconf.h> | |
| #include <capdl_loader_app/gen_config.h> | |
| #include <sel4/types.h> | |
| #include <sel4utils/mapping.h> | |
| #include <limits.h> | |
| #include <stdbool.h> | |
| #include <stdlib.h> | |
| #include <utils/util.h> | |
| #define CDL_VM_CacheEnabled seL4_ARCH_Default_VMAttributes | |
| #define CDL_VM_CacheDisabled seL4_ARCH_Uncached_VMAttributes | |
| #if defined(CONFIG_ARCH_ARM) | |
| /* ARM does not support write through */ | |
| #define CDL_VM_WriteThrough CDL_VM_CacheDisabled | |
| /* Note that this is the number of bits translated by the PT | |
| * not the size of the actual PT object */ | |
| #elif defined(CONFIG_ARCH_X86) | |
| #define CDL_VM_WriteThrough seL4_X86_WriteThrough | |
| #endif | |
| /* Binary CapDL representation -- capdl.h */ | |
| /* CapRights: Access rights of capabilities | |
| * This type is used internally by capDL, and doesn't | |
| * reflect the representation of cap rights in the kernel api. | |
| */ | |
| typedef enum { | |
| CDL_CanWrite = BIT(0), | |
| CDL_CanRead = BIT(1), | |
| CDL_CanGrant = BIT(2), | |
| CDL_CanGrantReply = BIT(3), | |
| CDL_AllRights = (BIT(0) | BIT(1) | BIT(2) | BIT(3)), | |
| } CDL_CapRights; | |
| /* ObjectID: index into the objects array */ | |
| typedef seL4_Word CDL_ObjID; | |
| #define INVALID_OBJ_ID ((CDL_ObjID)-1) | |
| /* IRQ number: Hardware IRQ number */ | |
| typedef seL4_Word CDL_IRQ; | |
| /* Core id */ | |
| typedef seL4_Word CDL_Core; | |
| /* Capability: */ | |
| typedef enum { | |
| CDL_NullCap, | |
| CDL_UntypedCap, | |
| CDL_EPCap, | |
| CDL_NotificationCap, | |
| CDL_ReplyCap, | |
| CDL_MasterReplyCap, | |
| CDL_CNodeCap, | |
| CDL_TCBCap, | |
| CDL_IRQControlCap, | |
| CDL_IRQHandlerCap, | |
| CDL_FrameCap, | |
| CDL_PTCap, | |
| CDL_PDCap, | |
| CDL_PML4Cap, | |
| CDL_PDPTCap, | |
| CDL_PUDCap, | |
| CDL_PGDCap, | |
| CDL_ASIDControlCap, | |
| CDL_ASIDPoolCap, | |
| #if defined(CONFIG_ARCH_X86) | |
| CDL_IOPortsCap, | |
| CDL_IOSpaceCap, | |
| #endif | |
| #if defined(CONFIG_ARCH_ARM) | |
| CDL_ARMIOSpaceCap, | |
| CDL_SIDCap, | |
| CDL_CBCap, | |
| #endif | |
| #if defined(CONFIG_ARM_HYPERVISOR_SUPPORT) || defined(CONFIG_VTX) | |
| CDL_VCPUCap, | |
| #endif | |
| CDL_SCCap, | |
| CDL_SchedControlCap, | |
| CDL_RTReplyCap, | |
| CDL_DomainCap, | |
| } CDL_CapType; | |
| #define CDL_CapData_Badge 0 | |
| #define CDL_CapData_Guard 1 | |
| #define CDL_CapData_Raw 2 | |
| typedef struct { | |
| union { | |
| struct { | |
| seL4_Word guard_bits: 18; /* guards have an 18-bit value */ | |
| seL4_Word guard_size: | |
| seL4_WordBits - 18; | |
| }; | |
| seL4_Word badge; | |
| seL4_Word data; | |
| }; | |
| unsigned tag: 2; /* One of CDL_CapData_* */ | |
| } PACKED CDL_CapData; | |
| typedef struct { | |
| CDL_ObjID obj_id; | |
| CDL_CapData data; | |
| CDL_IRQ irq; | |
| CDL_ObjID mapping_container_id; | |
| seL4_Word mapping_slot; | |
| seL4_CPtr mapped_frame_cap; | |
| /* This type tag actually has a more specific type, but we force it to be represented as a | |
| * uint8_t to compress the size of this struct in memory. | |
| */ | |
| /* CDL_CapType */ uint8_t type; | |
| /* The following map to more specific seL4 types, but the seL4 types are padded to word size, | |
| * wasting space. This padding is necessary for ABI compatibility, but we have no such | |
| * requirements here and can instead reduce the in-memory size of specs by packing these fields | |
| * into fewer bits. | |
| */ | |
| /* seL4_ARCH_VMAttributes */ unsigned vm_attribs: 3; | |
| /* bool */ unsigned is_orig: 1; | |
| /* seL4_CapRights */ unsigned rights: | |
| seL4_CapRightsBits; | |
| } PACKED CDL_Cap; | |
| /* CapMap: is just an array of cap slots, position of the slot and cap */ | |
| typedef struct { | |
| seL4_Word slot; | |
| CDL_Cap cap; | |
| } PACKED CDL_CapSlot; | |
| typedef struct { | |
| seL4_Word num; | |
| CDL_CapSlot *slot; | |
| } CDL_CapMap; | |
| /* ObjMap: is just an array of object slots */ | |
| typedef struct { | |
| seL4_Word slot; | |
| CDL_ObjID id; | |
| } CDL_ObjSlot; | |
| typedef struct { | |
| seL4_Word num; | |
| CDL_ObjSlot *slot; | |
| } CDL_ObjMap; | |
| /* KernelObject: */ | |
| typedef enum { | |
| CDL_Endpoint = seL4_EndpointObject, | |
| CDL_Notification = seL4_NotificationObject, | |
| CDL_TCB = seL4_TCBObject, | |
| CDL_CNode = seL4_CapTableObject, | |
| CDL_Untyped = seL4_UntypedObject, | |
| #if defined(CONFIG_ARCH_ARM) | |
| CDL_PT = seL4_ARM_PageTableObject, | |
| CDL_PD = seL4_ARM_PageDirectoryObject, | |
| CDL_Frame = seL4_ARM_SmallPageObject, | |
| #ifdef CONFIG_ARCH_AARCH64 | |
| CDL_PUD = seL4_ARM_PageUpperDirectoryObject, | |
| CDL_PGD = seL4_ARM_PageGlobalDirectoryObject, | |
| #endif | |
| #ifdef CONFIG_ARM_HYPERVISOR_SUPPORT | |
| CDL_VCPU = seL4_ARM_VCPUObject, | |
| #endif | |
| #ifdef CONFIG_VTX | |
| CDL_VCPU = seL4_X86_VCPUObject, | |
| #endif | |
| #elif defined(CONFIG_ARCH_X86) | |
| CDL_PT = seL4_X86_PageTableObject, | |
| CDL_PD = seL4_X86_PageDirectoryObject, | |
| CDL_Frame = seL4_X86_4K, | |
| #ifdef CONFIG_ARCH_X86_64 | |
| CDL_PML4 = seL4_X64_PML4Object, | |
| CDL_PDPT = seL4_X86_PDPTObject, | |
| #endif | |
| #endif | |
| CDL_ASIDPool = seL4_ObjectTypeCount + 1, | |
| CDL_Interrupt = seL4_ObjectTypeCount + 2, | |
| #if defined(CONFIG_ARCH_X86) | |
| CDL_IOPorts = seL4_ObjectTypeCount + 3, | |
| CDL_IODevice = seL4_ObjectTypeCount + 4, | |
| #endif | |
| #ifdef CONFIG_KERNEL_MCS | |
| CDL_SchedContext = seL4_SchedContextObject, | |
| CDL_RTReply = seL4_ReplyObject, | |
| #else | |
| CDL_SchedContext = seL4_ObjectTypeCount + 5, | |
| CDL_RTReply = seL4_ObjectTypeCount + 6, | |
| #endif | |
| #if defined(CONFIG_ARCH_X86) | |
| CDL_IOAPICInterrupt = seL4_ObjectTypeCount + 7, | |
| CDL_MSIInterrupt = seL4_ObjectTypeCount + 8, | |
| #endif | |
| #if defined(CONFIG_ARCH_ARM) | |
| CDL_ARMIODevice = seL4_ObjectTypeCount + 9, | |
| CDL_ARMInterrupt = seL4_ObjectTypeCount + 11, | |
| CDL_SID = seL4_ObjectTypeCount + 12, | |
| CDL_CB = seL4_ObjectTypeCount + 13, | |
| #endif | |
| #ifdef CONFIG_ARCH_RISCV | |
| CDL_Frame = seL4_RISCV_4K_Page, | |
| CDL_PT = seL4_RISCV_PageTableObject, | |
| /* We use this hack to distiguish a PageTableObject that is used as a root vspace | |
| * as parts of the loader assume that the root vspace object types are unique | |
| */ | |
| CDL_PT_ROOT_ALIAS = seL4_ObjectTypeCount + 10, | |
| #endif | |
| } CDL_ObjectType; | |
| #ifdef CONFIG_ARCH_AARCH64 | |
| #if defined(CONFIG_ARM_HYPERVISOR_SUPPORT) && defined(CONFIG_ARM_PA_SIZE_BITS_40) | |
| #define CDL_TOP_LEVEL_PD CDL_PUD | |
| #define CDL_PT_NUM_LEVELS 3 | |
| #else | |
| #define CDL_TOP_LEVEL_PD CDL_PGD | |
| #define CDL_PT_NUM_LEVELS 4 | |
| #define CDL_PT_LEVEL_1_MAP seL4_ARM_PageUpperDirectory_Map | |
| #endif | |
| #define CDL_PT_LEVEL_1_IndexBits seL4_PUDIndexBits | |
| #define CDL_PT_LEVEL_2_MAP seL4_ARM_PageDirectory_Map | |
| #define CDL_PT_LEVEL_2_IndexBits seL4_PageDirIndexBits | |
| #define CDL_PT_LEVEL_3_MAP seL4_ARM_PageTable_Map | |
| #define CDL_PT_LEVEL_3_IndexBits seL4_PageTableIndexBits | |
| #elif CONFIG_ARCH_X86_64 | |
| #define CDL_TOP_LEVEL_PD CDL_PML4 | |
| #define CDL_PT_LEVEL_1_MAP seL4_X86_PDPT_Map | |
| #define CDL_PT_LEVEL_1_IndexBits seL4_PDPTIndexBits | |
| #define CDL_PT_LEVEL_2_MAP seL4_X86_PageDirectory_Map | |
| #define CDL_PT_LEVEL_2_IndexBits seL4_PageDirIndexBits | |
| #define CDL_PT_LEVEL_3_MAP seL4_X86_PageTable_Map | |
| #define CDL_PT_LEVEL_3_IndexBits seL4_PageTableIndexBits | |
| #define CDL_PT_NUM_LEVELS 4 | |
| #elif CONFIG_ARCH_RISCV | |
| #define CDL_TOP_LEVEL_PD CDL_PT_ROOT_ALIAS | |
| #define CDL_PT_LEVEL_0_MAP seL4_RISCV_PageTable_Map | |
| #define CDL_PT_LEVEL_0_IndexBits seL4_PageTableIndexBits | |
| #define CDL_PT_LEVEL_1_MAP seL4_RISCV_PageTable_Map | |
| #define CDL_PT_LEVEL_1_IndexBits seL4_PageTableIndexBits | |
| #define CDL_PT_LEVEL_2_MAP seL4_RISCV_PageTable_Map | |
| #define CDL_PT_LEVEL_2_IndexBits seL4_PageTableIndexBits | |
| #define CDL_PT_LEVEL_3_MAP seL4_RISCV_PageTable_Map | |
| #define CDL_PT_LEVEL_3_IndexBits seL4_PageTableIndexBits | |
| #define CDL_PT_NUM_LEVELS CONFIG_PT_LEVELS | |
| #else | |
| #define CDL_TOP_LEVEL_PD CDL_PD | |
| #define CDL_PT_NUM_LEVELS 2 | |
| #endif | |
| typedef struct { | |
| bool has_untyped_memory; | |
| } CDL_CNodeExtraInfo; | |
| typedef struct { | |
| uint8_t priority; | |
| uint8_t max_priority; | |
| uint8_t affinity; | |
| uint8_t domain; | |
| seL4_Word pc; | |
| seL4_Word sp; | |
| const char *elf_name; | |
| const seL4_Word *init; | |
| seL4_Word init_sz; | |
| seL4_CPtr fault_ep; | |
| seL4_Word ipcbuffer_addr; | |
| bool resume; | |
| } CDL_TCBExtraInfo; | |
| typedef struct { | |
| uint64_t period; | |
| uint64_t budget; | |
| seL4_Word data; | |
| } CDL_SCExtraInfo; | |
| typedef struct { | |
| uint8_t bank; | |
| } CDL_CBExtraInfo; | |
| typedef struct { | |
| int ioapic; | |
| int ioapic_pin; | |
| int level; | |
| int polarity; | |
| } CDL_IOAPICIRQExtraInfo; | |
| typedef struct { | |
| int handle; | |
| int pci_bus; | |
| int pci_dev; | |
| int pci_fun; | |
| } CDL_MSIIRQExtraInfo; | |
| typedef struct { | |
| int trigger; | |
| int target; | |
| } CDL_ARMIRQExtraInfo; | |
| typedef enum { | |
| CDL_FrameFill_None = 0, | |
| CDL_FrameFill_BootInfo, | |
| CDL_FrameFill_FileData, | |
| } CDL_FrameFillType_t; | |
| typedef enum { | |
| CDL_FrameFill_BootInfo_Padding = SEL4_BOOTINFO_HEADER_FDT, | |
| CDL_FrameFill_BootInfo_X86_VBE = SEL4_BOOTINFO_HEADER_X86_VBE, | |
| CDL_FrameFill_BootInfo_X86_MBMMAP = SEL4_BOOTINFO_HEADER_X86_MBMMAP, | |
| CDL_FrameFill_BootInfo_X86_ACPI_RSDP = SEL4_BOOTINFO_HEADER_X86_ACPI_RSDP, | |
| CDL_FrameFill_BootInfo_X86_Framebuffer = SEL4_BOOTINFO_HEADER_X86_FRAMEBUFFER, | |
| CDL_FrameFill_BootInfo_X86_TSC_Freq = SEL4_BOOTINFO_HEADER_X86_TSC_FREQ, | |
| CDL_FrameFill_BootInfo_FDT = SEL4_BOOTINFO_HEADER_FDT, | |
| CDL_FrameFill_BootInfo_BootInfo = SEL4_BOOTINFO_HEADER_BOOTINFO | |
| } CDL_FrameFill_BootInfoEnum_t; | |
| typedef struct { | |
| CDL_FrameFill_BootInfoEnum_t type; | |
| size_t src_offset; | |
| } CDL_FrameFill_BootInfoType_t; | |
| typedef struct { | |
| char *filename; | |
| size_t file_offset; | |
| } CDL_FrameFill_FileDataType_t; | |
| typedef struct { | |
| CDL_FrameFillType_t type; | |
| size_t dest_offset; | |
| size_t dest_len; | |
| union { | |
| CDL_FrameFill_BootInfoType_t bi_type; | |
| CDL_FrameFill_FileDataType_t file_data_type; | |
| }; | |
| } CDL_FrameFill_Element_t; | |
| typedef struct { | |
| CDL_FrameFill_Element_t fill[CONFIG_CAPDL_LOADER_FILLS_PER_FRAME]; | |
| seL4_Word paddr; | |
| } CDL_FrameExtraInfo; | |
| typedef struct { | |
| #ifdef CONFIG_DEBUG_BUILD | |
| const char *name; /* textual ObjID from the capDL spec */ | |
| #endif | |
| CDL_CapMap slots; | |
| union { | |
| CDL_CNodeExtraInfo cnode_extra; | |
| CDL_TCBExtraInfo tcb_extra; | |
| CDL_SCExtraInfo sc_extra; | |
| CDL_CBExtraInfo cb_extra; | |
| CDL_IOAPICIRQExtraInfo ioapicirq_extra; | |
| CDL_MSIIRQExtraInfo msiirq_extra; | |
| CDL_ARMIRQExtraInfo armirq_extra; | |
| CDL_FrameExtraInfo frame_extra; | |
| seL4_Word paddr; /* Physical address; only relevant for untyped objects. */ | |
| seL4_Word asid_high; /* for ASID pools */ | |
| struct { | |
| seL4_Word start; | |
| seL4_Word end; | |
| }; | |
| }; | |
| CDL_ObjectType type; | |
| /* The configuration for IO ports on x86 is currently overloaded into the | |
| * size_bits parameter. */ | |
| uint32_t size_bits; | |
| } PACKED CDL_Object; | |
| typedef struct { | |
| /* The untyped that the children should be derived from */ | |
| CDL_ObjID untyped; | |
| /* Number of children to derive from this untyped */ | |
| seL4_Word num; | |
| /* Children to derive from this untyped */ | |
| CDL_ObjID *children; | |
| } CDL_UntypedDerivation; | |
| /* CapDLModel: is described by a map from ObjectIDs (array index) to Objects */ | |
| typedef struct { | |
| seL4_Word num; | |
| CDL_Object *objects; | |
| seL4_Word num_irqs; | |
| CDL_ObjID *irqs; | |
| seL4_Word num_untyped; | |
| CDL_UntypedDerivation *untyped; | |
| /* Array from ASID slot number to ASID pool object. | |
| NB: asid_slots[0] is unused, so the array size is one larger | |
| than the number of slots being allocated. | |
| Slot 0 is unused because it is the root thread's ASID slot, | |
| which the loader uses for loading other component VSpaces. */ | |
| seL4_Word num_asid_slots; | |
| CDL_ObjID *asid_slots; | |
| } CDL_Model; | |
| /* helper functions ---------------------------------------------------------------------------- */ | |
| #define CDL_TCB_CTable_Slot 0 | |
| #define CDL_TCB_VTable_Slot 1 | |
| #define CDL_TCB_Reply_Slot 2 | |
| #define CDL_TCB_Caller_Slot 3 | |
| #define CDL_TCB_IPCBuffer_Slot 4 | |
| #define CDL_TCB_FaultEP_Slot 5 | |
| #define CDL_TCB_SC_Slot 6 | |
| #define CDL_TCB_TemporalFaultEP_Slot 7 | |
| #if defined(CONFIG_ARM_HYPERVISOR_SUPPORT) || defined(CONFIG_VTX) | |
| #define CDL_TCB_VCPU_SLOT 8 | |
| #endif | |
| #define CDL_CapData_MakeGuard(x, y) \ | |
| { .tag = CDL_CapData_Guard, .guard_bits = (y), .guard_size = (x) } | |
| static inline CDL_CapType CDL_Cap_Type(CDL_Cap *cap) | |
| { | |
| return cap->type; | |
| } | |
| static inline CDL_CapData CDL_Cap_Data(CDL_Cap *cap) | |
| { | |
| return cap->data; | |
| } | |
| static inline seL4_ARCH_VMAttributes CDL_Cap_VMAttributes(CDL_Cap *cap) | |
| { | |
| return cap->vm_attribs; | |
| } | |
| static inline CDL_ObjID CDL_Cap_ObjID(CDL_Cap *cap) | |
| { | |
| return cap->obj_id; | |
| } | |
| static inline CDL_CapRights CDL_Cap_Rights(CDL_Cap *cap) | |
| { | |
| return cap->rights; | |
| } | |
| static inline CDL_IRQ CDL_Cap_IRQ(CDL_Cap *cap) | |
| { | |
| return cap->irq; | |
| } | |
| static inline bool CDL_Cap_IsOrig(CDL_Cap *cap) | |
| { | |
| return cap->is_orig; | |
| } | |
| static inline seL4_Word CDL_CapSlot_Slot(CDL_CapSlot *cap_slot) | |
| { | |
| return cap_slot->slot; | |
| } | |
| static inline CDL_Cap *CDL_CapSlot_Cap(CDL_CapSlot *cap_slot) | |
| { | |
| return &cap_slot->cap; | |
| } | |
| static inline seL4_Word CDL_ObjSlot_Slot(CDL_ObjSlot *obj_slot) | |
| { | |
| return obj_slot->slot; | |
| } | |
| static inline CDL_ObjID CDL_ObjSlot_ObjID(CDL_ObjSlot *obj_slot) | |
| { | |
| return obj_slot->id; | |
| } | |
| /* Returns the sel4utils representation of a CDL_Cap's rights */ | |
| static inline seL4_CapRights_t CDL_seL4_Cap_Rights(CDL_Cap *cap) | |
| { | |
| return seL4_CapRights_new(!!(cap->rights & CDL_CanGrantReply), | |
| !!(cap->rights & CDL_CanGrant), | |
| !!(cap->rights & CDL_CanRead), | |
| !!(cap->rights & CDL_CanWrite)); | |
| } | |
| static inline const char *CDL_Obj_Name(CDL_Object *obj) | |
| { | |
| #ifdef CONFIG_DEBUG_BUILD | |
| if (obj->name == NULL) { | |
| return "<unnamed>"; | |
| } else { | |
| return obj->name; | |
| } | |
| #else | |
| return "<unnamed>"; | |
| #endif | |
| } | |
| static inline CDL_ObjectType CDL_Obj_Type(CDL_Object *obj) | |
| { | |
| return obj->type; | |
| } | |
| static inline seL4_Word CDL_Obj_SizeBits(CDL_Object *obj) | |
| { | |
| return obj->size_bits; | |
| } | |
| static inline seL4_Word CDL_Obj_Paddr(CDL_Object *obj) | |
| { | |
| switch (obj->type) { | |
| case CDL_Frame: | |
| return obj->frame_extra.paddr; | |
| case CDL_Untyped: | |
| return obj->paddr; | |
| default: | |
| return 0; | |
| } | |
| } | |
| static inline seL4_Word CDL_Obj_NumSlots(CDL_Object *obj) | |
| { | |
| return obj->slots.num; | |
| } | |
| static inline CDL_CapSlot *CDL_Obj_GetSlot(CDL_Object *obj, seL4_Word i) | |
| { | |
| return &obj->slots.slot[i]; | |
| } | |
| static inline seL4_Word CDL_TCB_IPCBuffer_Addr(CDL_Object *obj) | |
| { | |
| return obj->tcb_extra.ipcbuffer_addr; | |
| } | |
| static inline uint8_t CDL_TCB_Priority(CDL_Object *obj) | |
| { | |
| return obj->tcb_extra.priority; | |
| } | |
| static inline uint8_t CDL_CB_Bank(CDL_Object *obj) | |
| { | |
| return obj->cb_extra.bank; | |
| } | |
| static inline uint8_t CDL_TCB_MaxPriority(CDL_Object *obj) | |
| { | |
| return obj->tcb_extra.max_priority; | |
| } | |
| static inline uint8_t CDL_TCB_Affinity(CDL_Object *obj) | |
| { | |
| return obj->tcb_extra.affinity; | |
| } | |
| static inline uint32_t CDL_TCB_Domain(CDL_Object *obj) | |
| { | |
| return obj->tcb_extra.domain; | |
| } | |
| static inline seL4_Word CDL_TCB_PC(CDL_Object *obj) | |
| { | |
| return obj->tcb_extra.pc; | |
| } | |
| static inline seL4_Word CDL_TCB_SP(CDL_Object *obj) | |
| { | |
| return obj->tcb_extra.sp; | |
| } | |
| static inline const char *CDL_TCB_ElfName(CDL_Object *obj) | |
| { | |
| return obj->tcb_extra.elf_name; | |
| } | |
| static inline uint64_t CDL_SC_Period(CDL_Object *obj) | |
| { | |
| return obj->sc_extra.period; | |
| } | |
| static inline uint64_t CDL_SC_Budget(CDL_Object *obj) | |
| { | |
| return obj->sc_extra.budget; | |
| } | |
| static inline seL4_Word CDL_SC_Data(CDL_Object *obj) | |
| { | |
| return obj->sc_extra.data; | |
| } |