From dd8f773f10f4904889265a7e3db31b6abfd34057 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Wed, 29 Jul 2009 13:32:38 +0300 Subject: [PATCH] Some more progress on resource management and boot up. --- include/l4/generic/cap-types.h | 83 ++++++ include/l4/generic/capability.h | 177 +++++++++++++ include/l4/generic/container.h | 46 +++- include/l4/generic/resource.h | 51 ++++ include/l4/generic/space.h | 13 + include/l4/generic/tcb.h | 8 + include/l4/lib/memcache.h | 1 + src/generic/SConscript | 2 +- src/generic/bootm.c | 6 + src/generic/capability.c | 7 + src/generic/container.c | 92 ++++++- src/generic/kresource.c | 56 ----- src/generic/resource.c | 431 ++++++++++++++++++++++++++++++++ src/generic/space.c | 10 - src/generic/tcb.c | 6 - src/glue/arm/init.c | 1 + src/lib/memcache.c | 46 +++- 17 files changed, 950 insertions(+), 86 deletions(-) create mode 100644 include/l4/generic/cap-types.h create mode 100644 include/l4/generic/capability.h create mode 100644 include/l4/generic/resource.h create mode 100644 src/generic/capability.c delete mode 100644 src/generic/kresource.c create mode 100644 src/generic/resource.c diff --git a/include/l4/generic/cap-types.h b/include/l4/generic/cap-types.h new file mode 100644 index 0000000..6e208f1 --- /dev/null +++ b/include/l4/generic/cap-types.h @@ -0,0 +1,83 @@ +/* + * Types of capabilities and their operations + * + * Copyright (C) 2009 Bahadir Balban + */ +#ifndef __CAP_TYPES_H__ +#define __CAP_TYPES_H__ + +/* + * Capability types + */ +#define CAP_TYPE_MASK 0x0000FFFF +#define CAP_TYPE_TCTRL (1 << 0) +#define CAP_TYPE_EXREGS (1 << 1) +#define CAP_TYPE_MAP (1 << 2) +#define CAP_TYPE_IPC (1 << 3) +#define CAP_TYPE_SCHED (1 << 4) +#define CAP_TYPE_UMUTEX (1 << 5) +#define CAP_TYPE_QUANTITY (1 << 6) + +/* + * Resource types + */ +#define CAP_RTYPE_MASK 0xFFFF0000 +#define CAP_RTYPE_THREAD (1 << 16) +#define CAP_RTYPE_TGROUP (1 << 17) +#define CAP_RTYPE_SPACE (1 << 18) +#define CAP_RTYPE_CONTAINER (1 << 19) +#define CAP_RTYPE_UMUTEX (1 << 20) +#define CAP_RTYPE_VIRTMEM (1 << 21) +#define CAP_RTYPE_PHYSMEM (1 << 22) +#define CAP_RTYPE_CPUPOOL (1 << 23) +#define CAP_RTYPE_THREADPOOL (1 << 24) +#define CAP_RTYPE_SPACEPOOL (1 << 25) +#define CAP_RTYPE_MUTEXPOOL (1 << 27) +#define CAP_RTYPE_MEMPOOL (1 << 26) /* Do we need this ??? */ +/* + * Access permissions + */ + +/* Thread control capability */ +#define CAP_TCTRL_CREATE (1 << 0) +#define CAP_TCTRL_DESTROY (1 << 1) +#define CAP_TCTRL_SUSPEND (1 << 2) +#define CAP_TCTRL_RESUME (1 << 3) +#define CAP_TCTRL_RECYCLE (1 << 4) + +/* Exchange registers capability */ +#define CAP_EXREGS_RW_PAGER (1 << 0) +#define CAP_EXREGS_RW_UTCB (1 << 1) +#define CAP_EXREGS_RW_SP (1 << 2) +#define CAP_EXREGS_RW_PC (1 << 3) +#define CAP_EXREGS_RW_REGS (1 << 4) +#define CAP_EXREGS_RW_CPU (1 << 5) +#define CAP_EXREGS_RW_CPUTIME (1 << 6) + +/* Map capability */ +#define CAP_MAP_READ (1 << 0) +#define CAP_MAP_WRITE (1 << 1) +#define CAP_MAP_EXEC (1 << 2) +#define CAP_MAP_CACHED (1 << 3) +#define CAP_MAP_UNCACHED (1 << 4) +#define CAP_MAP_UNMAP (1 << 5) + +/* Ipc capability */ +#define CAP_IPC_SEND (1 << 0) +#define CAP_IPC_RECV (1 << 1) +#define CAP_IPC_SHORT (1 << 2) +#define CAP_IPC_FULL (1 << 3) +#define CAP_IPC_EXTENDED (1 << 4) +#define CAP_IPC_ASYNC (1 << 5) + +/* Userspace mutex capability */ +#define CAP_UMUTEX_LOCK (1 << 0) + +/* Capability control capability */ +#define CAP_CAP_SPLIT (1 << 0) +#define CAP_CAP_SPLICE (1 << 1) +#define CAP_CAP_REDUCE (1 << 2) +#define CAP_CAP_REVOKE (1 << 3) +#define CAP_CAP_GRANT (1 << 4) + +#endif /* __CAP_TYPES_H__ */ diff --git a/include/l4/generic/capability.h b/include/l4/generic/capability.h new file mode 100644 index 0000000..ae7a5eb --- /dev/null +++ b/include/l4/generic/capability.h @@ -0,0 +1,177 @@ +/* + * Codezero Capability Definitions + * + * Copyright (C) 2009 Bahadir Balban + */ +#ifndef __CAPABILITY_H__ +#define __CAPABILITY_H__ + +#include + +/* + * A capability is a unique representation of security + * qualifiers on a particular resource. + * + * In this structure: + * + * The capid denotes the unique capability ID. The resid denotes the unique ID + * of targeted resource. The owner denotes the unique ID of capability owner. + * This is almost always a thread ID. + * + * The type field contains two types: The capability type, and the targeted + * resource type. The targeted resouce type denotes what type of resource the + * capability is allowed to operate on. For example a thread, a thread group, + * an address space or a memory can be of this type. + * + * The capability type defines the general set of operations allowed on a + * particular resource. The resource type defines the type of resource that + * the capability is targeting. For example a capability type may be + * thread_control, exchange_registers, ipc, or map operations. A resource type + * may be such as a thread, a thread group, a virtual or physical memory + * region. + * + * There are also quantitative capability types. While their names denote + * quantitative objects such as memory, threads, and address spaces, these + * types actually define the quantitative operations available on those + * resources such as creation and deletion of a thread, allocation and + * deallocation of a memory region etc. + * + * The access field denotes the fine-grain operations available on a particular + * resource. The meaning of each bitfield differs according to the type of the + * capability. For example, for a capability type thread_control, the bitfields + * may mean suspend, resume, create, delete etc. + */ +struct capability { + struct link list; + + /* Capability identifiers */ + l4id_t capid; /* Unique capability ID */ + l4id_t resid; /* Targeted resource ID */ + l4id_t owner; /* Capability owner ID */ + unsigned int type; /* Capability and target resource type */ + + /* Capability limits/permissions */ + u32 access; /* Permitted operations */ + + /* Limits on the resource */ + unsigned long start; /* Resource start value */ + unsigned long end; /* Resource end value */ + unsigned long size; /* Resource size */ +}; + +struct cap_list { + int ncaps; + struct link caps; +}; + +#if 0 +/* Virtual memory space allocated to container */ +struct capability cap_virtmap = { + .capid = id_alloc(capids), + .resid = container_id, + .owner = pagerid, + .type = CAP_TYPE_VIRTMEM, + .access = 0, /* No access operations */ + .start = 0xF0000000, + .end = 0xF1000000, + .size = 0x1000000 +}; + +/* Physical memory space allocated to container */ +struct capability cap_physmap = { + .capid = id_alloc(capids), + .resid = container_id, + .owner = pagerid, + .type = CAP_TYPE_PHYSMEM, + .access = 0, /* No access operations */ + .start = 0x0, + .end = 0x1000000, + .size = 0x1000000 +}; + +/* IPC operations permitted on target thread */ +struct capability cap_ipc = { + .capid = id_alloc(capids), + .resid = target_tid, + .owner = tid, + .type = CAP_TYPE_IPC, + .access = CAP_IPC_SEND | CAP_IPC_RECV | CAP_IPC_FULL | CAP_IPC_SHORT | CAP_IPC_EXTENDED, + .start = 0xF0000000, + .end = 0xF1000000, + .size = 0x1000000 +}; + +/* Thread control operations permitted on target thread */ +struct capability cap_thread_control = { + .capid = id_alloc(capids), + .resid = target_tid, + .owner = pagerid, + .type = CAP_TYPE_THREAD_CONTROL, + .access = CAP_THREAD_SUSPEND | CAP_THREAD_RUN | CAP_THREAD_RECYCLE | CAP_THREAD_CREATE | CAP_THREAD_DESTROY, + .start = 0, + .end = 0, + .size = 0, +}; + +/* Exregs operations permitted on target thread */ +struct capability cap_exregs = { + .capid = id_alloc(capids), + .resid = target_tid, + .owner = pagerid, + .type = CAP_TYPE_EXREGS, + .access = CAP_EXREGS_RW_PAGER | CAP_EXREGS_RW_SP | CAP_EXREGS_RW_PC | CAP_EXREGS_RW_UTCB | CAP_EXREGS_RW_OTHERS, + .start = 0, + .end = 0, + .size = 0 +}; + +/* Number of threads allocated to container */ +struct capability cap_threads = { + .capid = id_alloc(capids), + .resid = container_id, + .owner = pagerid, + .type = CAP_TYPE_THREADS, + .access = 0, + .start = 0, + .end = 0, + .size = 256, +}; + +/* Number of spaces allocated to container */ +struct capability cap_spaces = { + .capid = id_alloc(capids), + .resid = container_id, + .owner = pagerid, + .type = CAP_TYPE_SPACES, + .access = 0, + .start = 0, + .end = 0, + .size = 128, +}; + +/* CPU time allocated to container */ +struct capability cap_cputime = { + .capid = id_alloc(capids), + .resid = container_id, + .owner = pagerid, + .type = CAP_TYPE_CPUTIME, + .access = 0, + .start = 0, + .end = 0, + .size = 55, /* Percentage */ +}; + +struct capability cap_cpuprio = { + .capid = id_alloc(capids), + .resid = container_id, + .owner = pagerid, + .type = CAP_TYPE_CPUPRIO, + .access = 0, + .start = 0, + .end = 0, + .size = 55, /* Priority No */ +}; + +#endif + +#endif /* __CAPABILITY_H__ */ diff --git a/include/l4/generic/container.h b/include/l4/generic/container.h index d5ff56f..9a0309a 100644 --- a/include/l4/generic/container.h +++ b/include/l4/generic/container.h @@ -9,11 +9,14 @@ #include #include #include +#include #include #include +#include +#include /* Container macro. No locks needed! */ -#define container (current->container) +#define this_container (current->container) struct container { /* Unique container id */ @@ -47,21 +50,48 @@ struct container { /* The array of containers present on the system */ extern struct container container[]; - -struct memdesc { +/* Compact, raw capability structure */ +struct cap_info { + unsigned int type; + u32 access; unsigned long start; unsigned long end; - unsigned int flags; + unsigned long size; }; -struct cinfo { - char cname[32]; +struct pager_info { unsigned long pager_lma; unsigned long pager_vma; unsigned long pager_size; - unsigned long total_memdesc; - struct memdesc memdesc[]; + /* Number of capabilities defined */ + int ncaps; + + /* + * Zero or more ipc caps, + * One or more thread pool caps, + * One or more space pool caps, + * One or more exregs caps, + * One or more tcontrol caps, + * One or more cputime caps, + * One or more physmem caps, + * One or more virtmem caps, + * Zero or more umutex caps, + */ + struct cap_info caps[]; }; +/* + * This auto-generated structure is + * used to create run-time containers + */ +struct container_info { + char *name; + int npagers; + struct pager_info pagers[]; +}; + +extern struct container_info cinfo[]; + #endif /* __CONTAINER_H__ */ + diff --git a/include/l4/generic/resource.h b/include/l4/generic/resource.h new file mode 100644 index 0000000..d86d73d --- /dev/null +++ b/include/l4/generic/resource.h @@ -0,0 +1,51 @@ +#ifndef __RESOURCES_H__ +#define __RESOURCES_H__ + +/* Number of containers defined at compile-time */ +#define CONTAINERS_TOTAL 1 + +#include + +struct boot_resources { + int nconts; + int ncaps; + int nids; + int nthreads; + int nspaces; + int npmds; + + /* Kernel resource usage */ + int nkpmds; + int nkpgds; + int nkmemcaps; +}; + + +struct kernel_container { + /* Physical memory caps, used/unused */ + struct cap_list physmem_used; + struct cap_list physmem_free; + + /* Virtual memory caps, used/unused */ + struct cap_list virtmem_used; + struct cap_list virtmem_free; + + /* Device memory caps, used/unused */ + struct cap_list devmem_used; + struct cap_list devmem_free; + + struct mem_cache *pgd_cache; + struct mem_cache *pmd_cache; + struct mem_cache *ktcb_cache; + struct mem_cache *address_space_cache; + struct mem_cache *umutex_cache; + struct mem_cache *cap_cache; + struct mem_cache *cont_cache; +}; + +extern struct kernel_container kernel_container; + +int init_system_resources(struct kernel_container *kcont, + struct boot_resources *bootres); + +#endif /* __RESOURCES_H__ */ diff --git a/include/l4/generic/space.h b/include/l4/generic/space.h index ca13fee..64cb97e 100644 --- a/include/l4/generic/space.h +++ b/include/l4/generic/space.h @@ -20,8 +20,10 @@ #if defined (__KERNEL__) +#include #include #include +#include #include INC_SUBARCH(mm.h) /* A simple page table with a reference count */ @@ -33,6 +35,17 @@ struct address_space { int ktcb_refs; }; +struct address_space_list { + struct link list; + + /* Lock for list add/removal */ + struct spinlock list_lock; + + /* Used when delete/creating spaces */ + struct mutex ref_lock; + int count; +}; + struct address_space *address_space_create(struct address_space *orig); void address_space_delete(struct address_space *space); void address_space_attach(struct ktcb *tcb, struct address_space *space); diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index 8ff4bcf..28f5904 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -121,6 +122,13 @@ union ktcb_union { }; +/* Hash table for all existing tasks */ +struct ktcb_list { + struct link list; + struct spinlock list_lock; + int count; +}; + /* * Each task is allocated a unique global id. A thread group can only belong to * a single leader, and every thread can only belong to a single thread group. diff --git a/include/l4/lib/memcache.h b/include/l4/lib/memcache.h index 73a1056..94e23a3 100644 --- a/include/l4/lib/memcache.h +++ b/include/l4/lib/memcache.h @@ -30,6 +30,7 @@ struct mem_cache { unsigned int *bitmap; }; +int mem_cache_bufsize(void *start, int struct_size, int nstructs, int aligned); void *mem_cache_zalloc(struct mem_cache *cache); void *mem_cache_alloc(struct mem_cache *cache); int mem_cache_free(struct mem_cache *cache, void *addr); diff --git a/src/generic/SConscript b/src/generic/SConscript index ba3615b..e04ada8 100644 --- a/src/generic/SConscript +++ b/src/generic/SConscript @@ -4,7 +4,7 @@ Import('env') # The set of source files associated with this SConscript file. -src_local = ['physmem.c', 'irq.c', 'scheduler.c', 'time.c', 'tcb.c', 'pgalloc.c', 'kmalloc.c', 'space.c', 'bootm.c'] +src_local = ['physmem.c', 'irq.c', 'scheduler.c', 'time.c', 'tcb.c', 'pgalloc.c', 'kmalloc.c', 'space.c', 'bootm.c', 'resource.c'] obj = env.Object(src_local) Return('obj') diff --git a/src/generic/bootm.c b/src/generic/bootm.c index 1472dbe..0fa4f82 100644 --- a/src/generic/bootm.c +++ b/src/generic/bootm.c @@ -28,6 +28,12 @@ void *alloc_bootmem(int size, int alignment) if (!is_aligned(cursor, alignment)) /* Align the cursor to alignment */ cursor = align_up(cursor, alignment); + /* Align to 4 byte by default */ + } else if (size >= 4) { + /* And cursor is not aligned */ + if (!is_aligned(cursor, 4)) + /* Align the cursor to alignment */ + cursor = align_up(cursor, 4); } /* Allocate from cursor */ diff --git a/src/generic/capability.c b/src/generic/capability.c new file mode 100644 index 0000000..c70e8e1 --- /dev/null +++ b/src/generic/capability.c @@ -0,0 +1,7 @@ +/* + * Capability checking for all system calls + * + * Copyright (C) 2009 Bahadir Balban + */ + + diff --git a/src/generic/container.c b/src/generic/container.c index 38f4f83..2a05ac1 100644 --- a/src/generic/container.c +++ b/src/generic/container.c @@ -1,11 +1,97 @@ /* * Containers defined for current build. * - * Copyright (C) 2009 B Labs Ltd. + * Copyright (C) 2009 Bahadir Balban */ -struct container container[] = { - .[0] = { 0 }, +struct container_info cinfo[] = { + .name = "Codezero POSIX Services", + .npagers = 1, + .pagers = { + .[0] = { + .pager_lma = 0x38000, + .pager_vma = 0xE0000000, + .pager_size = 0x96000, + .ncaps = 11, + .caps = { + .[0] = { + .type = CAP_TYPE_MAP | CAP_RTYPE_VIRTMEM, + .access = CAP_MAP_READ | CAP_MAP_WRITE + | CAP_MAP_EXEC | CAP_MAP_UNMAP, + .access = 0, + .start = 0xE0000000, + .end = 0xF0000000, + .size = 0x10000000, + }, + .[1] = { + .type = CAP_TYPE_MAP | CAP_RTYPE_VIRTMEM, + .access = CAP_MAP_READ | CAP_MAP_WRITE + | CAP_MAP_EXEC | CAP_MAP_UNMAP, + .start = 0x10000000, + .end = 0x20000000, + .size = 0x10000000, + }, + .[2] = { + .type = CAP_TYPE_MAP | CAP_RTYPE_VIRTMEM, + .access = CAP_MAP_READ | CAP_MAP_WRITE + | CAP_MAP_EXEC | CAP_MAP_UNMAP, + .access = 0, + .start = 0x20000000, + .end = 0x30000000, + .size = 0x10000000, + }, + .[3] = { + .type = CAP_TYPE_MAP | CAP_RTYPE_PHYSMEM, + .access = CAP_MAP_CACHED | CAP_MAP_UNCACHED + | CAP_MAP_READ | CAP_MAP_WRITE + | CAP_MAP_EXEC | CAP_MAP_UNMAP, + .start = 0x38000, + .end = 0x1000000, /* 16 MB */ + }, + .[4] = { + .type = CAP_TYPE_IPC | CAP_RTYPE_CONTAINER, + .access = CAP_IPC_SEND | CAP_IPC_RECV + | CAP_IPC_FULL | CAP_IPC_SHORT + | CAP_IPC_EXTENDED, + .start = 0, .end = 0, .size = 0, + }, + .[5] = { + .type = CAP_TYPE_TCTRL | CAP_RTYPE_CONTAINER, + .access = CAP_TCTRL_CREATE | CAP_TCTRL_DESTROY + | CAP_TCTRL_SUSPEND | CAP_TCTRL_RESUME + | CAP_TCTRL_RECYCLE, + .start = 0, .end = 0, .size = 0, + }, + .[6] = { + .type = CAP_TYPE_EXREGS | CAP_RTYPE_CONTAINER, + .access = CAP_EXREGS_RW_PAGER + | CAP_EXREGS_RW_UTCB | CAP_EXREGS_RW_SP + | CAP_EXREGS_RW_PC | CAP_EXREGS_RW_REGS, + .start = 0, .end = 0, .size = 0, + }, + .[7] = { + .type = CAP_TYPE_QUANTITY + | CAP_RTYPE_THREADPOOL, + .access = 0, .start = 0, .end = 0, + .size = 64, + }, + .[8] = { + .type = CAP_TYPE_QUANTITY | CAP_RTYPE_SPACEPOOL, + .access = 0, .start = 0, .end = 0, + .size = 64, + }, + .[9] = { + .type = CAP_TYPE_QUANTITY | CAP_RTYPE_CPUPOOL, + .access = 0, .start = 0, .end = 0, + .size = 50, /* Percentage */ + }, + .[10] = { + .type = CAP_TYPE_QUANTITY | CAP_RTYPE_MUTEXPOOL, + .access = 0, .start = 0, .end = 0, + .size = 100, + }, + }, + }, }, }; diff --git a/src/generic/kresource.c b/src/generic/kresource.c deleted file mode 100644 index 0582ceb..0000000 --- a/src/generic/kresource.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Initialize system resource management. - * - * Copyright (C) 2009 Bahadir Balban - */ - -/* - * Here are the steps used to initialize system resources: - * - * Check total physical memory - * Check container memory capabilities - * Find biggest unused physical memory region - * Calculate how much memory is used by all containers - * Initialize a slab-like allocator for all resources. - * Copy boot allocations to real allocations accounted to containers and kernel. - * E.g. initial page table may become page table of a container pager. - * First few pmds used belong to kernel usage, etc. - * Delete all boot memory and add it to physical memory pool. - */ - -#define MEM_FLAGS_VIRTUAL (1 << 0) -#define MEM_AREA_CACHED (1 << 1) - -struct mem_area { - struct link list; - l4id_t mid; - unsigned long start; - unsigned long end; - unsigned long npages; - unsigned long flags; -}; - - -void init_system_resources() -{ - struct mem_area *physmem = alloc_bootmem(sizeof(physmem), 4); - struct mem_area *kernel_used = alloc_bootmem(sizeof(physmem), 4); - - /* Initialize the first memory descriptor for total physical memory */ - physmem.start = PHYS_MEM_START; - physmem.end = PHYS_MEM_END; - physmem.mid = 0; - physmem.npages = (physmem.end - physmem.start) >> PAGE_BITS; - - /* Figure out current kernel usage */ - kernel_used.start = virt_to_phys(_kernel_start); - kernel_used.end = virt_to_phys(_kernel_end); - - /* Figure out each container's physical memory usage */ - for (int i = 0; i < containers->total; i++) { - } -} - - - - diff --git a/src/generic/resource.c b/src/generic/resource.c new file mode 100644 index 0000000..f634093 --- /dev/null +++ b/src/generic/resource.c @@ -0,0 +1,431 @@ +/* + * Initialize system resource management. + * + * Copyright (C) 2009 Bahadir Balban + */ + +#include +#include +#include +#include INC_GLUE(memory.h) +#include INC_ARCH(linker.h) + +struct kernel_container kernel_container; + +void cap_list_init(struct cap_list *clist) +{ + clist->ncaps = 0; + link_init(&clist->caps); +} + +void cap_list_add(struct cap_list *clist, struct capability *cap) +{ + list_add(&cap->list, &clist->caps); + clist->ncaps++; +} + +/* + * Initializes kernel caplists, and sets up total of physical + * and virtual memory as single capabilities of the kernel. + * They will then get split into caps of different lengths + * during the traversal of container capabilities. + */ +void setup_kernel_container(struct kernel_container *kcont) +{ + struct capability *physmem, *virtmem, *kernel_area; + + /* Initialize kernel capability lists */ + cap_list_init(&kcont->physmem_used); + cap_list_init(&kcont->physmem_free); + cap_list_init(&kcont->virtmem_used); + cap_list_init(&kcont->virtmem_free); + cap_list_init(&kcont->devmem_used); + cap_list_init(&kcont->devmem_free); + + /* Set up total physical memory as single capability */ + physmem = alloc_bootmem(sizeof(*physmem)); + physmem->start = __pfn(PHYS_MEM_START); + physmem->end = __pfn(PHYS_MEM_END); + link_init(&physmem->list); + cap_list_add(&kcont->physmem_free, physmem); + + /* Set up total virtual memory as single capability */ + virtmem = alloc_bootmem(sizeof(*virtmem)); + virtmem->start = __pfn(VIRT_MEM_START); + virtmem->end = __pfn(VIRT_MEM_END); + link_init(&virtmem->list); + cap_list_add(&kcont->virtmem_free, virtmem); + + /* Set up kernel used area as a single capability */ + kernel_area = alloc_bootmem(sizeof(*physmem)); + kernel_area->start = __pfn(virt_to_phys(_start_kernel)); + kernel_area->end = __pfn(virt_to_phys(_end_kernel)); + link_init(&kernel_area->list); + list_add(&kcont->physmem_used, kernel_area); + + /* Unmap kernel used area from free physical memory capabilities */ + memcap_unmap(&kcont->physmem_free, kernel_area->start, + kernel_area->end); + + /* TODO: + * Add all virtual memory areas used by the kernel + * e.g. kernel virtual area, syscall page, kip page, + * vectors page, timer, sysctl and uart device pages + */ +} + +/* + * This splits a capability, splitter region must be in + * the *middle* of original capability + */ +int memcap_split(struct capability *cap, struct cap_list *cap_list, + const unsigned long start, + const unsigned long end) +{ + struct capability *new; + + /* Allocate a capability first */ + new = alloc_bootmem(sizeof(*new)); + + /* + * Some sanity checks to show that splitter range does end up + * producing two smaller caps. + */ + BUG_ON(cap->start >= start || cap->end <= end); + + /* Update new and original caps */ + new->end = cap->end; + new->start = end; + cap->end = start; + new->access = cap->access; + + /* Add new one next to original cap */ + cap_list_add(new, cap_list); + + return 0; +} + +/* This shrinks the cap from *one* end only, either start or end */ +int memcap_shrink(struct capability *cap, struct cap_list *cap_list, + const unsigned long start, const unsigned long end) +{ + /* Shrink from the end */ + if (cap->start < start) { + BUG_ON(start >= cap->end); + cap->end = start; + + /* Shrink from the beginning */ + } else if (cap->end > end) { + BUG_ON(end <= cap->start); + cap->start = end; + } else + BUG(); + + return 0; +} + +int memcap_unmap_range(struct capability *cap, + struct cap_list *cap_list, + const unsigned long pfn_start, + const unsigned long pfn_end) +{ + /* Split needed? */ + if (cap->start < start && cap->end > end) + return memcap_split(cap, cap_list, start, end); + /* Shrink needed? */ + else if (((cap->start >= start) && (cap->end > end)) + || ((cap->start < start) && (cap->end <= end))) + return memcap_shrink(cap, cap_list, start, end); + /* Destroy needed? */ + else if ((cap->start >= start) && (cap->end <= end)) + /* Simply unlink it */ + list_remove(&cap->list); + else + BUG(); + + return 0; +} + +/* + * Unmaps given memory range from the list of capabilities + * by either shrinking, splitting or destroying the + * intersecting capability. Similar to do_munmap() + */ +int memcap_unmap(struct cap_list *cap_list, + const unsigned long unmap_start, + const unsigned long unmap_end) +{ + struct capability *cap, *n; + int err; + + list_foreach_removable_struct(cap, n, &cap_list->caps, list) { + /* Check for intersection */ + if (set_intersection(unmap_start, unmap_end, + cap->start, cap->end)) { + if ((err = memcap_unmap_range(cap, cap_list + unmap_start, + unmap_end))) { + return err; + } + /* Return 1 to indicate unmap occured */ + return 1; + } + } + return 0 +} + +/* + * Do all system accounting for this capability info + * structure that belongs to a container, such as + * count its resource requirements, remove its portion + * from global kernel capabilities etc. + */ +int process_cap_info(struct cap_info *cap, + struct boot_resources *bootres, + struct kernel_container *kcont) +{ + int ret; + + switch (cap->type & CAP_RTYPE_MASK) { + case CAP_RTYPE_THREADPOOL: + bootres->nthreads += cap->size; + break; + case CAP_RTYPE_SPACEPOOL: + bootres->nspaces += cap->size; + break; + case CAP_RTYPE_MUTEXPOOL: + bootres->nmutex += cap->size; + break; + case CAP_RTYPE_VIRTMEM: + bootres->npmds += + cap->size / PMD_MAP_SIZE; + if ((ret = memcap_unmap(&kcont->virtmem_free, + cap->start, cap->end))) { + if (ret < 0) + printk("FATAL: Insufficient boot memory " + "to split capability\n"); + if (ret > 0) + printf("FATAL: Memory capability range " + "overlaps with another one. " + "start=0x%x, end=0x%x\n", + __pfn_to_addr(cap->start), + __pfn_to_addr(cap->end)); + BUG(); + } + break; + case CAP_RTYPE_PHYSMEM: + if ((ret = memcap_unmap(&kcont->virtmem_free, + cap->start, cap->end))) { + if (ret < 0) + printk("FATAL: Insufficient boot memory " + "to split capability\n"); + if (ret > 0) + printf("FATAL: Memory capability range " + "overlaps with another one. " + "start=0x%x, end=0x%x\n", + __pfn_to_addr(cap->start), + __pfn_to_addr(cap->end)); + BUG(); + } + break; + } + return ret; +} + +/* + * Migrate any boot allocations to their relevant caches. + */ +void migrate_boot_resources(struct boot_resources *bootres, + struct kernel_container *kcont) +{ + /* Migrate boot page tables to new caches */ + migrate_page_tables(kcont); + + /* Migrate all boot-allocated capabilities */ + migrate_boot_caps(kcont); +} + +/* Delete all boot memory and add it to physical memory pool. */ +int free_boot_memory(struct kernel_container *kcont, + struct boot_resources *bootres) +{ + /* Trim kernel used memory memcap */ + memcap_unmap(&kcont->physical_used, _bootmem_start, _bootmem_end); + + /* Add it to unused physical memory */ + memcap_map(&kcont->physical_unused, _bootmem_start, _bootmem_end); +} + + +struct mem_cache *init_resource_cache(struct boot_resources *bootres, + struct kernel_container *kcont) +{ + struct capability *cap; + unsigned long bufsize; + + /* In all unused physical memory regions */ + list_foreach_struct(cap, &kcont->physical_unused, list) { + /* Get buffer size needed for cache */ + bufsize = mem_cache_bufsize(__pfn_to_addr(cap->start), + PGD_SIZE, bootres->nspaces, + aligned); + /* + * Check if memcap region size is enough to cover + * resource allocation + */ + if (__pfn_to_addr(cap->end - cap->start) >= bufsize) { + unsigned long virtual = + phys_to_virt(__pfn_to_addr(cap->start)); + /* + * Map the buffer as boot mapping if pmd caches + * are not initialized + */ + if (!kcont->pmd_cache) { + add_boot_mapping(__pfn_to_addr(cap->start), + virtual, bufsize, + MAP_SVC_RW_FLAGS); + } else { + add_mapping(__pfn_to_addr(cap->start), + virtual, bufsize, + MAP_SVC_RW_FLAGS); + } + /* Unmap area from memcap */ + memcap_unmap_range(cap, &kcont->physical_unused, + cap->start, cap->start + + __pfn(page_align_up((bufsize)))); + + /* TODO: Manipulate memcaps for virtual range??? */ + + /* Initialize the cache */ + return mem_cache_init(virtual, bufsize, PGD_SIZE, 1); + } + } + return 0; +} + +void create_containers(struct boot_resources *bootres, + struct kernel_container *kcont) +{ + +} + +void create_capabilities(struct boot_resources *bootres, + struct kernel_container *kcont) +{ + +} + +/* + * Make sure to count boot pmds, and kernel capabilities + * created in boot memory. + * + * Also total capabilities in the system + number of + * capabilities containers are allowed to create dynamically. + * + * Count the extra pgd + space needed in case all containers quit + */ +void init_resource_allocators(struct boot_resources *bootres, + struct kernel_container *kcont) +{ + struct mem_cache *cache; + + /* Initialise PGD cache */ + cache = init_resource_cache(bootres->nspaces, + PGD_SIZE, kcont, 1); + kcont->pgd_cache = cache; + + /* Initialise PMD cache */ + cache = init_resource_cache(bootres->npmds, + PMD_SIZE, kcont, 1); + cache->pmd_cache = cache; + + /* Initialise struct address_space cache */ + cache = init_resource_cache(bootres->nspaces, + sizeof(struct address_space), + kcont, 0); + cache->address_space_cache = cache; + + /* Initialise ktcb cache */ + cache = init_resource_cache(bootres->nthreads, + PAGE_SIZE, kcont, 1); + cache->ktcb_cache = cache; + + /* Initialise umutex cache */ + cache = init_resource_cache(bootres->numutex, + sizeof(struct mutex_queue), + kcont, 0); + cache->umutex_cache = cache; + + /* TODO: Initialize ID cache */ + + /* # of capabilities are now constant, create capabilities cache */ + + /* Initialise capability cache */ + cache = init_resource_cache(bootres->ncaps, /* FIXME: Count correctly */ + sizeof(struct capability), + kcont, 0); + cache->cap_cache = cache; + + /* Initialise container cache */ + cache = init_resource_cache(bootres->ncont, + sizeof(struct container), + kcont, 0); + cache->cont_cache = cache; + + /* Create system containers */ + create_containers(bootres, kcont); + + /* Create capabilities */ + create_capabilities(bootres, kcont); +} + +int init_boot_resources(struct boot_resources *bootres, struct kernel_container *kcont) +{ + struct cap_info *cap; + struct pager_info *pgr; + struct container_info *cont; + + setup_kernel_container(kcont); + + /* Number of containers known at compile-time */ + bootres->nconts = ncontainers; + + /* Traverse all containers */ + for (int i = 0; i < bootres->nconts; i++) { + /* Traverse all pagers */ + for (int j = 0; j < container[i]->npagers; j++) { + int ncaps = container[i].pager[j].ncaps; + + /* Count all capabilities */ + bootres->ncaps += ncaps; + + /* Count all resources */ + for (int k = 0; k < ncaps; k++) { + cap = container[i].pager[j].caps[k]; + proces_cap_info(cap); + } + } + } + + /* TODO: Count all ids needed to represent all */ + return 0; +} + +/* + * FIXME: Add error handling + */ +int init_system_resources(struct kernel_container *kcont) +{ + + struct boot_resources bootres; + + init_boot_resources(&bootres, &kcont); + + init_resource_allocators(&bootres, &kcont); + + free_boot_memory(bootres, kcont); +} + + + + diff --git a/src/generic/space.c b/src/generic/space.c index 1502bca..c14836c 100644 --- a/src/generic/space.c +++ b/src/generic/space.c @@ -15,16 +15,6 @@ #include #include -struct address_space_list { - struct link list; - - /* Lock for list add/removal */ - struct spinlock list_lock; - - /* Used when delete/creating spaces */ - struct mutex ref_lock; - int count; -}; static struct address_space_list address_space_list; diff --git a/src/generic/tcb.c b/src/generic/tcb.c index 0853486..c19464a 100644 --- a/src/generic/tcb.c +++ b/src/generic/tcb.c @@ -19,12 +19,6 @@ struct id_pool *thread_id_pool; struct id_pool *space_id_pool; -/* Hash table for all existing tasks */ -struct ktcb_list { - struct link list; - struct spinlock list_lock; - int count; -}; static struct ktcb_list ktcb_list; diff --git a/src/glue/arm/init.c b/src/glue/arm/init.c index 5ee86ba..303ce91 100644 --- a/src/glue/arm/init.c +++ b/src/glue/arm/init.c @@ -14,6 +14,7 @@ #include #include #include +#include #include INC_ARCH(linker.h) #include INC_ARCH(asm.h) #include INC_ARCH(bootdesc.h) diff --git a/src/lib/memcache.c b/src/lib/memcache.c index 5ac15aa..c2d9e67 100644 --- a/src/lib/memcache.c +++ b/src/lib/memcache.c @@ -90,12 +90,50 @@ out: return err; } -struct mem_cache *mem_cache_init(void *start, +/* + * Given a buffer start address, structure size, number of + * structs and alignment requirements, determines how much + * memory is needed from that starting address + */ +int mem_cache_bufsize(void *start, int struct_size, int nstructs, int aligned) +{ + unsigned long start_address = (unsigned long)start; + int total_bytes, bwords; + + /* Word alignment requirement */ + start_address = align_up(start_address, sizeof(int)); + + /* Total bytes to contain structures */ + total_bytes = struct_size * nstructs; + + /* Total words to contain bitmap */ + bwords = nstructs >> 5; + + /* An extra word if not a multiple of one word's bits */ + if (nstructs & 0x1F) + bwords++; + + /* Total bitmap bytes */ + bitmap_size = bwords * sizeof(int); + + /* Current would-be start address */ + start_address += bitmap_size + total_bytes + sizeof(struct mem_cache); + + /* Check alignment requirement */ + if (aligned) + start_address += align_up(start_address, struct_size); + + return start_address - (unsigned long)start; +} + +struct mem_cache *mem_cache_init(void *bufstart, int cache_size, int struct_size, unsigned int aligned) { - struct mem_cache *cache = start; + /* Align to nearest word boundary */ + void *start; + struct mem_cache *cache; unsigned int area_start; unsigned int *bitmap; int bwords_in_structs; @@ -103,6 +141,10 @@ struct mem_cache *mem_cache_init(void *start, int total; int bsize; + start = (void *)align_up(bufstart, sizeof(int)); + cache_size -= (int)start - (int)bufstart; + mem_cache = start; + if ((struct_size < 0) || (cache_size < 0) || ((unsigned long)start == ~(0))) { printk("Invalid parameters.\n");