1223486Shselasky/* 2223486Shselasky * Copyright 2014, General Dynamics C4 Systems 3223486Shselasky * 4223486Shselasky * SPDX-License-Identifier: GPL-2.0-only 5223486Shselasky */ 6223486Shselasky 7223486Shselasky#pragma once 8223486Shselasky 9223486Shselasky#include <config.h> 10223486Shselasky#include <assert.h> 11223486Shselasky#include <util.h> 12223486Shselasky#include <sel4/macros.h> 13223486Shselasky#include <api/types.h> 14223486Shselasky#include <arch/types.h> 15223486Shselasky#include <arch/object/structures_gen.h> 16223486Shselasky#include <arch/machine/hardware.h> 17223486Shselasky#include <arch/machine/registerset.h> 18223486Shselasky 19223486Shselaskytypedef struct arch_tcb { 20223486Shselasky /* saved user-level context of thread (72 bytes) */ 21223486Shselasky user_context_t tcbContext; 22223486Shselasky#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT 23223486Shselasky /* Pointer to associated VCPU. NULL if not associated. 24223486Shselasky * tcb->tcbVCPU->vcpuTCB == tcb. */ 25223486Shselasky struct vcpu *tcbVCPU; 26223486Shselasky#endif 27223486Shselasky} arch_tcb_t; 28223486Shselasky 29223486Shselaskyenum vm_rights { 30228975Suqs VMNoAccess = 0, 31223486Shselasky VMKernelOnly = 1, 32223486Shselasky VMReadOnly = 2, 33223486Shselasky VMReadWrite = 3 34223486Shselasky}; 35223486Shselaskytypedef word_t vm_rights_t; 36223534Shselasky 37223534Shselaskytypedef pde_t vspace_root_t; 38223534Shselasky 39223486Shselasky#define seL4_PGDEntryBits 3 40223486Shselasky#define seL4_PGDIndexBits 2 41223486Shselasky#define seL4_PGDBits 5 42223534Shselasky 43223534Shselasky#define PGDE_SIZE_BITS seL4_PGDEntryBits 44223534Shselasky#define PDE_SIZE_BITS seL4_PageDirEntryBits 45223486Shselasky#define PTE_SIZE_BITS seL4_PageTableEntryBits 46223486Shselasky#define PGD_INDEX_BITS seL4_PGDIndexBits 47223486Shselasky#define PD_INDEX_BITS seL4_PageDirIndexBits 48223486Shselasky#define PT_INDEX_BITS seL4_PageTableIndexBits 49223486Shselasky#define VCPU_SIZE_BITS seL4_VCPUBits 50223486Shselasky 51223534Shselasky/* Generate a vcpu_t pointer from a vcpu block reference */ 52223534Shselasky#define VCPU_PTR(r) ((struct vcpu *)(r)) 53223486Shselasky#define VCPU_REF(p) ((unsigned int)(p)) 54223486Shselasky 55223486Shselasky#define PDE_PTR(r) ((pde_t *)(r)) 56223486Shselasky#define PDE_REF(p) ((unsigned int)p) 57223486Shselasky 58223486Shselasky#define PDE_PTR_PTR(r) ((pde_t **)r) 59223486Shselasky 60223486Shselasky#define PD_PTR(r) ((pde_t *)(r)) 61223534Shselasky#define PD_REF(p) ((unsigned int)p) 62223534Shselasky 63223534Shselasky/* Page directory entries (PDEs) */ 64223534Shselaskyenum pde_type { 65223534Shselasky PDEInvalid = 0, 66223534Shselasky PDECoarse = 1, 67223534Shselasky PDEMapping = 2 68223486Shselasky}; 69223534Shselaskytypedef word_t pde_type_t; 70223486Shselasky 71223486Shselasky#define PTE_PTR(r) ((pte_t *)r) 72223486Shselasky#define PTE_REF(p) ((unsigned int)p) 73223486Shselasky 74223534Shselasky#define PT_PTR(r) ((pte_t *)r) 75223534Shselasky#define PT_REF(p) ((unsigned int)p) 76223534Shselasky 77223534Shselasky/* LPAE */ 78223534Shselasky#define PGD_SIZE_BITS seL4_PGDBits 79223534Shselasky#define LPAE_PGDE_PTR(r) ((lpae_pde_t *)(r)) 80223534Shselasky#define LPAE_PGDE_REF(p) ((unsigned int)p) 81223534Shselasky#define LPAE_PGDE_PTR_PTR(r) ((lpae_pde_t **)r) 82223534Shselasky#define LPAE_PGD_PTR(r) ((lpae_pde_t *)(r)) 83223534Shselasky#define LPAE_PGD_REF(p) ((unsigned int)p) 84223534Shselasky 85223534Shselasky#define LPAE_PTE_PTR(r) ((lpae_pte_t *)r) 86223534Shselasky#define LPAE_PTE_REF(p) ((unsigned int)p) 87223534Shselasky 88223534Shselasky#define LPAE_PT_PTR(r) ((lpae_pte_t *)r) 89223534Shselasky#define LPAE_PT_REF(p) ((unsigned int)p) 90223534Shselasky 91223534Shselaskystruct asid_pool { 92223534Shselasky pde_t *array[BIT(asidLowBits)]; 93223534Shselasky}; 94223534Shselasky 95223534Shselaskytypedef struct asid_pool asid_pool_t; 96223534Shselasky 97223534Shselasky#define ASID_POOL_PTR(r) ((asid_pool_t *)r) 98223534Shselasky#define ASID_POOL_REF(p) ((unsigned int)p) 99223534Shselasky 100223534Shselasky#define HW_ASID_SIZE_BITS 1 101223534Shselasky 102223486Shselasky#define ASID_POOL_INDEX_BITS seL4_ASIDPoolIndexBits 103223534Shselasky#define ASID_BITS (asidHighBits+asidLowBits) 104223534Shselasky 105223534Shselasky#define nASIDPools BIT(asidHighBits) 106223534Shselasky 107223534Shselasky#define ASID_LOW(a) (a & MASK(asidLowBits)) 108223534Shselasky#define ASID_HIGH(a) ((a >> asidLowBits) & MASK(asidHighBits)) 109223534Shselasky 110223534Shselaskystatic inline cap_t CONST cap_small_frame_cap_set_capFMappedASID(cap_t cap, word_t asid) 111223486Shselasky{ 112223534Shselasky cap = cap_small_frame_cap_set_capFMappedASIDLow(cap, 113223486Shselasky asid & MASK(asidLowBits)); 114223486Shselasky return cap_small_frame_cap_set_capFMappedASIDHigh(cap, 115223486Shselasky (asid >> asidLowBits) & MASK(asidHighBits)); 116223486Shselasky} 117223486Shselasky 118223486Shselaskystatic inline word_t CONST cap_small_frame_cap_get_capFMappedASID(cap_t cap) 119223534Shselasky{ 120223486Shselasky return (cap_small_frame_cap_get_capFMappedASIDHigh(cap) << asidLowBits) + 121223486Shselasky cap_small_frame_cap_get_capFMappedASIDLow(cap); 122223534Shselasky} 123223486Shselasky 124223486Shselaskystatic inline cap_t CONST cap_frame_cap_set_capFMappedASID(cap_t cap, word_t asid) 125223486Shselasky{ 126 cap = cap_frame_cap_set_capFMappedASIDLow(cap, 127 asid & MASK(asidLowBits)); 128 return cap_frame_cap_set_capFMappedASIDHigh(cap, 129 (asid >> asidLowBits) & MASK(asidHighBits)); 130} 131 132static inline word_t CONST cap_frame_cap_get_capFMappedASID(cap_t cap) 133{ 134 return (cap_frame_cap_get_capFMappedASIDHigh(cap) << asidLowBits) + 135 cap_frame_cap_get_capFMappedASIDLow(cap); 136} 137 138static inline word_t CONST generic_frame_cap_get_capFMappedASID(cap_t cap) 139{ 140 cap_tag_t ctag; 141 142 ctag = cap_get_capType(cap); 143 144 assert(ctag == cap_small_frame_cap || 145 ctag == cap_frame_cap); 146 147 if (ctag == cap_small_frame_cap) { 148 return cap_small_frame_cap_get_capFMappedASID(cap); 149 } else { 150 return cap_frame_cap_get_capFMappedASID(cap); 151 } 152} 153 154static inline cap_t CONST generic_frame_cap_set_capFMappedAddress(cap_t cap, word_t asid, word_t addr) 155{ 156 cap_tag_t ctag; 157 158 ctag = cap_get_capType(cap); 159 assert(ctag == cap_small_frame_cap || 160 ctag == cap_frame_cap); 161 162 if (ctag == cap_small_frame_cap) { 163 cap = cap_small_frame_cap_set_capFMappedASID(cap, asid); 164 cap = cap_small_frame_cap_set_capFMappedAddress(cap, addr); 165 return cap; 166 } else { 167 cap = cap_frame_cap_set_capFMappedASID(cap, asid); 168 cap = cap_frame_cap_set_capFMappedAddress(cap, addr); 169 return cap; 170 } 171} 172 173static inline void generic_frame_cap_ptr_set_capFMappedAddress(cap_t *cap_ptr, word_t asid, 174 word_t addr) 175{ 176 *cap_ptr = generic_frame_cap_set_capFMappedAddress(*cap_ptr, asid, addr); 177} 178 179static inline vm_rights_t CONST generic_frame_cap_get_capFVMRights(cap_t cap) 180{ 181 cap_tag_t ctag; 182 183 ctag = cap_get_capType(cap); 184 assert(ctag == cap_small_frame_cap || 185 ctag == cap_frame_cap); 186 187 switch (ctag) { 188 case cap_small_frame_cap: 189 return cap_small_frame_cap_get_capFVMRights(cap); 190 191 case cap_frame_cap: 192 return cap_frame_cap_get_capFVMRights(cap); 193 194 default: 195 return VMNoAccess; 196 } 197} 198 199static inline word_t CONST generic_frame_cap_get_capFBasePtr(cap_t cap) 200{ 201 cap_tag_t ctag; 202 203 ctag = cap_get_capType(cap); 204 assert(ctag == cap_small_frame_cap || 205 ctag == cap_frame_cap); 206 207 switch (ctag) { 208 case cap_small_frame_cap: 209 return cap_small_frame_cap_get_capFBasePtr(cap); 210 211 case cap_frame_cap: 212 return cap_frame_cap_get_capFBasePtr(cap); 213 214 default: 215 return 0; 216 } 217} 218 219static inline word_t CONST generic_frame_cap_get_capFSize(cap_t cap) 220{ 221 cap_tag_t ctag; 222 223 ctag = cap_get_capType(cap); 224 assert(ctag == cap_small_frame_cap || 225 ctag == cap_frame_cap); 226 227 switch (ctag) { 228 case cap_small_frame_cap: 229 return ARMSmallPage; 230 231 case cap_frame_cap: 232 return cap_frame_cap_get_capFSize(cap); 233 234 default: 235 return 0; 236 } 237} 238 239static inline word_t CONST generic_frame_cap_get_capFIsMapped(cap_t cap) 240{ 241 return generic_frame_cap_get_capFMappedASID(cap) != 0; 242} 243 244static inline word_t CONST generic_frame_cap_get_capFMappedAddress(cap_t cap) 245{ 246 cap_tag_t ctag; 247 248 ctag = cap_get_capType(cap); 249 assert(ctag == cap_small_frame_cap || 250 ctag == cap_frame_cap); 251 252 if (ctag == cap_small_frame_cap) { 253 return cap_small_frame_cap_get_capFMappedAddress(cap); 254 } else { 255 return cap_frame_cap_get_capFMappedAddress(cap); 256 } 257} 258 259static inline word_t CONST generic_frame_cap_get_capFIsDevice(cap_t cap) 260{ 261 cap_tag_t ctag; 262 263 ctag = cap_get_capType(cap); 264 assert(ctag == cap_small_frame_cap || 265 ctag == cap_frame_cap); 266 267 if (ctag == cap_small_frame_cap) { 268 return cap_small_frame_cap_get_capFIsDevice(cap); 269 } else { 270 return cap_frame_cap_get_capFIsDevice(cap); 271 } 272} 273 274static inline word_t CONST cap_get_archCapSizeBits(cap_t cap) 275{ 276 cap_tag_t ctag; 277 278 ctag = cap_get_capType(cap); 279 280 switch (ctag) { 281 case cap_small_frame_cap: 282 case cap_frame_cap: 283 return pageBitsForSize(generic_frame_cap_get_capFSize(cap)); 284 285 case cap_page_table_cap: 286 return seL4_PageTableBits; 287 288 case cap_page_directory_cap: 289 return seL4_PageDirBits; 290 291 case cap_asid_pool_cap: 292 return seL4_ASIDPoolBits; 293 294 case cap_asid_control_cap: 295 return 0; 296 297#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT 298 case cap_vcpu_cap: 299 return VCPU_SIZE_BITS; 300#endif 301#ifdef CONFIG_TK1_SMMU 302 case cap_io_page_table_cap: 303 return seL4_IOPageTableBits; 304#endif 305 306 default: 307 /* Unreachable, but GCC can't figure that out */ 308 return 0; 309 } 310} 311 312static inline bool_t CONST cap_get_archCapIsPhysical(cap_t cap) 313{ 314 cap_tag_t ctag; 315 316 ctag = cap_get_capType(cap); 317 318 switch (ctag) { 319 320 case cap_small_frame_cap: 321 return true; 322 323 case cap_frame_cap: 324 return true; 325 326 case cap_page_table_cap: 327 return true; 328 329 case cap_page_directory_cap: 330 return true; 331 332 case cap_asid_pool_cap: 333 return true; 334 335 case cap_asid_control_cap: 336 return false; 337 338#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT 339 case cap_vcpu_cap: 340 return true; 341#endif 342 343#ifdef CONFIG_TK1_SMMU 344 case cap_io_page_table_cap: 345 return true; 346#endif 347 348 default: 349 /* Unreachable, but GCC can't figure that out */ 350 return false; 351 } 352} 353 354static inline void *CONST cap_get_archCapPtr(cap_t cap) 355{ 356 cap_tag_t ctag; 357 358 ctag = cap_get_capType(cap); 359 360 switch (ctag) { 361 362 case cap_small_frame_cap: 363 case cap_frame_cap: 364 return (void *)(generic_frame_cap_get_capFBasePtr(cap)); 365 366 case cap_page_table_cap: 367 return PT_PTR(cap_page_table_cap_get_capPTBasePtr(cap)); 368 369 case cap_page_directory_cap: 370 return PD_PTR(cap_page_directory_cap_get_capPDBasePtr(cap)); 371 372 case cap_asid_pool_cap: 373 return ASID_POOL_PTR(cap_asid_pool_cap_get_capASIDPool(cap)); 374 375 case cap_asid_control_cap: 376 return NULL; 377 378#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT 379 case cap_vcpu_cap: 380 return VCPU_PTR(cap_vcpu_cap_get_capVCPUPtr(cap)); 381#endif 382 383#ifdef CONFIG_TK1_SMMU 384 case cap_io_page_table_cap: 385 return (void *)(cap_io_page_table_cap_get_capIOPTBasePtr(cap)); 386#endif 387 388 default: 389 /* Unreachable, but GCC can't figure that out */ 390 return NULL; 391 } 392} 393 394#ifndef CONFIG_ARM_HYPERVISOR_SUPPORT 395/* We need to supply different type getters for the bitfield generated PTE type 396 * because there is an implicit third type that PTEs can be. If the type bit is 397 * set but the reserved bit is not set, the type of the PTE is invalid, not a 398 * large PTE. 399 */ 400enum { pte_pte_invalid = 2 }; 401 402static inline word_t CONST pte_get_pteType(pte_t pte) 403{ 404 if (pte_get_pteSize(pte) == pte_pte_small) { 405 return pte_pte_small; 406 } else if (pte_pte_large_get_reserved(pte) == 1) { 407 return pte_pte_large; 408 } else { 409 return pte_pte_invalid; 410 } 411} 412 413static inline word_t PURE pte_ptr_get_pteType(pte_t *pte_ptr) 414{ 415 if (pte_ptr_get_pteSize(pte_ptr) == pte_pte_small) { 416 return pte_pte_small; 417 } else if (pte_pte_large_ptr_get_reserved(pte_ptr) == 1) { 418 return pte_pte_large; 419 } else { 420 return pte_pte_invalid; 421 } 422} 423#endif /* CONFIG_ARM_HYPERVISOR_SUPPORT */ 424 425