| /* |
| * Copyright 2014, NICTA |
| * |
| * This software may be distributed and modified according to the terms of |
| * the BSD 2-Clause license. Note that NO WARRANTY is provided. |
| * See "LICENSE_BSD2.txt" for details. |
| * |
| * @TAG(NICTA_BSD) |
| */ |
| |
| #ifndef __VKA_OBJECT_H__ |
| #define __VKA_OBJECT_H__ |
| |
| #include <assert.h> |
| #include <vka/vka.h> |
| #include <vka/kobject_t.h> |
| #include <stdio.h> |
| #include <utils/util.h> |
| |
| /* |
| * A wrapper to hold all the allocation information for an 'object' |
| * An object here is just combination of cptr and untyped allocation |
| * The type and size of the allocation is also stored to make free |
| * more convenient. |
| */ |
| |
| typedef struct vka_object { |
| seL4_CPtr cptr; |
| uint32_t ut; |
| seL4_Word type; |
| seL4_Word size_bits; |
| } vka_object_t; |
| |
| /* |
| * Generic object allocator used by functions below, can also be used directly |
| */ |
| static inline int |
| vka_alloc_object(vka_t *vka, seL4_Word type, seL4_Word size_bits, vka_object_t *result) |
| { |
| seL4_CPtr cptr; |
| uint32_t ut; |
| int error; |
| cspacepath_t path; |
| |
| if ( (error = vka_cspace_alloc(vka, &cptr)) != 0) { |
| return error; |
| } |
| |
| vka_cspace_make_path(vka, cptr, &path); |
| if ( (error = vka_utspace_alloc(vka, &path, type, size_bits, &ut)) != 0) { |
| ZF_LOGE("Failed to allocate object of size %lu, error %d\n", BIT(size_bits), error); |
| vka_cspace_free(vka, cptr); |
| return error; |
| } |
| result->cptr = cptr; |
| result->ut = ut; |
| result->type = type; |
| result->size_bits = size_bits; |
| return 0; |
| } |
| |
| /* convenient wrapper that throws away the vka_object_t and just returns the cptr - |
| * note you cannot use this if you intend to free the object */ |
| static inline seL4_CPtr vka_alloc_object_leaky(vka_t *vka, seL4_Word type, seL4_Word size_bits) WARN_UNUSED_RESULT; |
| static inline seL4_CPtr |
| vka_alloc_object_leaky(vka_t *vka, seL4_Word type, seL4_Word size_bits) |
| { |
| vka_object_t result = {.cptr = 0, .ut = 0, .type = 0, size_bits = 0}; |
| return vka_alloc_object(vka, type, size_bits, &result) == -1 ? 0 : result.cptr; |
| } |
| |
| static inline void |
| vka_free_object(vka_t *vka, vka_object_t *object) |
| { |
| cspacepath_t path; |
| |
| vka_cspace_make_path(vka, object->cptr, &path); |
| if (path.capPtr == 0) { |
| ZF_LOGE("Failed to create cspace path to object"); |
| return; |
| } |
| |
| /* ignore any errors */ |
| seL4_CNode_Delete(path.root, path.capPtr, path.capDepth); |
| |
| vka_cspace_free(vka, object->cptr); |
| vka_utspace_free(vka, object->type, object->size_bits, object->ut); |
| } |
| |
| static inline uintptr_t |
| vka_object_paddr(vka_t *vka, vka_object_t *object) |
| { |
| return vka_utspace_paddr(vka, object->ut, object->type, object->size_bits); |
| } |
| |
| /* Convenience wrappers for allocating objects */ |
| static inline int vka_alloc_untyped(vka_t *vka, uint32_t size_bits, vka_object_t *result) |
| { |
| return vka_alloc_object(vka, seL4_UntypedObject, size_bits, result); |
| } |
| static inline int vka_alloc_tcb(vka_t *vka, vka_object_t *result) |
| { |
| return vka_alloc_object(vka, seL4_TCBObject, seL4_TCBBits, result); |
| } |
| static inline int vka_alloc_endpoint(vka_t *vka, vka_object_t *result) |
| { |
| return vka_alloc_object(vka, seL4_EndpointObject, seL4_EndpointBits, result); |
| } |
| |
| static inline int vka_alloc_notification(vka_t *vka, vka_object_t *result) |
| { |
| return vka_alloc_object(vka, seL4_NotificationObject, seL4_NotificationBits, result); |
| } |
| |
| /* @deprecated use vka_alloc_notification */ |
| static inline int DEPRECATED("Use vka_alloc_notification") |
| vka_alloc_async_endpoint(vka_t *vka, vka_object_t *result) |
| { |
| return vka_alloc_notification(vka, result); |
| } |
| static inline int vka_alloc_cnode_object(vka_t *vka, uint32_t slot_bits, vka_object_t *result) |
| { |
| return vka_alloc_object(vka, seL4_CapTableObject, slot_bits, result); |
| } |
| |
| /* For arch specific allocations we call upon kobject to avoid code duplication */ |
| static inline int vka_alloc_frame(vka_t *vka, uint32_t size_bits, vka_object_t *result) |
| { |
| return vka_alloc_object(vka, kobject_get_type(KOBJECT_FRAME, size_bits), size_bits, result); |
| } |
| |
| static inline int vka_alloc_page_directory(vka_t *vka, vka_object_t *result) |
| { |
| return vka_alloc_object(vka, kobject_get_type(KOBJECT_PAGE_DIRECTORY, 0), seL4_PageDirBits, result); |
| } |
| |
| static inline int vka_alloc_page_table(vka_t *vka, vka_object_t *result) |
| { |
| return vka_alloc_object(vka, kobject_get_type(KOBJECT_PAGE_TABLE, 0), seL4_PageTableBits, result); |
| } |
| |
| #ifdef CONFIG_CACHE_COLORING |
| |
| static inline int vka_alloc_kernel_image(vka_t *vka, vka_object_t *result) |
| { |
| return vka_alloc_object(vka, kobject_get_type(KOBJECT_KERNEL_IMAGE, 0), seL4_KernelImageBits, result); |
| } |
| |
| |
| #endif |
| |
| |
| /* Implement a kobject interface */ |
| static inline int vka_alloc_kobject(vka_t *vka, kobject_t type, seL4_Word size_bits, |
| vka_object_t *result) |
| { |
| return vka_alloc_object(vka, kobject_get_type(type, size_bits), size_bits, result); |
| } |
| |
| |
| /* leaky versions of the object allocation functions - throws away the kobject_t */ |
| |
| #define LEAKY(name) \ |
| static inline seL4_CPtr vka_alloc_##name##_leaky(vka_t *vka) WARN_UNUSED_RESULT; \ |
| static inline seL4_CPtr vka_alloc_##name##_leaky(vka_t *vka) \ |
| {\ |
| vka_object_t object;\ |
| if (vka_alloc_##name(vka, &object) != 0) {\ |
| return 0;\ |
| }\ |
| return object.cptr;\ |
| } |
| |
| LEAKY(tcb) |
| LEAKY(endpoint) |
| LEAKY(notification) |
| LEAKY(page_directory) |
| LEAKY(page_table) |
| |
| static inline DEPRECATED("use vka_alloc_notification_leaky") seL4_CPtr |
| vka_alloc_async_endpoint_leaky(vka_t *vka) |
| { |
| return vka_alloc_notification_leaky(vka); |
| } |
| |
| |
| #define LEAKY_SIZE_BITS(name) \ |
| static inline seL4_CPtr vka_alloc_##name##_leaky(vka_t *vka, uint32_t size_bits) WARN_UNUSED_RESULT; \ |
| static inline seL4_CPtr vka_alloc_##name##_leaky(vka_t *vka, uint32_t size_bits) \ |
| {\ |
| vka_object_t object;\ |
| if (vka_alloc_##name(vka, size_bits, &object) != 0) {\ |
| return 0;\ |
| }\ |
| return object.cptr;\ |
| } |
| |
| LEAKY_SIZE_BITS(untyped) |
| LEAKY_SIZE_BITS(frame) |
| LEAKY_SIZE_BITS(cnode_object) |
| |
| #include <vka/arch/object.h> |
| |
| /* The name of the object that defines a vspace root can vary, this provides |
| * an abstraction for code that doesn't want to care about the type and |
| * just wants whatever object fills this role */ |
| static inline int vka_alloc_vspace_root(vka_t *vka, vka_object_t *result) |
| { |
| #ifdef CONFIG_PAE_PAGING |
| return vka_alloc_pdpt(vka, result); |
| #else |
| return vka_alloc_page_directory(vka, result); |
| #endif |
| } |
| |
| /* |
| * Get the size (in bits) of the untyped memory required to create an object of |
| * the given size. |
| */ |
| static inline unsigned long |
| vka_get_object_size(seL4_Word objectType, seL4_Word objectSize) |
| { |
| switch (objectType) { |
| /* Generic objects. */ |
| case seL4_UntypedObject: |
| return objectSize; |
| case seL4_TCBObject: |
| return seL4_TCBBits; |
| case seL4_EndpointObject: |
| return seL4_EndpointBits; |
| case seL4_NotificationObject: |
| return seL4_NotificationBits; |
| case seL4_CapTableObject: |
| return (seL4_SlotBits + objectSize); |
| #ifdef CONFIG_CACHE_COLORING |
| case seL4_KernelImageObject: |
| return seL4_KernelImageBits; |
| #endif |
| default: |
| return vka_arch_get_object_size(objectType); |
| } |
| } |
| |
| #endif /* __VKA_OBJECT_H__ */ |