diff --git a/include/l4/api/mutex.h b/include/l4/api/mutex.h index 7c2e0a1..8732a9c 100644 --- a/include/l4/api/mutex.h +++ b/include/l4/api/mutex.h @@ -33,9 +33,10 @@ struct mutex_queue_head { struct link list; struct mutex mutex_control_mutex; int count; -} mutex_queue_head; +}; + +void init_mutex_queue_head(struct mutex_queue_head *mqhead); -void init_mutex_queue_head(void); #endif #define L4_MUTEX_LOCK 0 diff --git a/include/l4/arch/arm/v5/mm.h b/include/l4/arch/arm/v5/mm.h index 154e1b5..f0d2dab 100644 --- a/include/l4/arch/arm/v5/mm.h +++ b/include/l4/arch/arm/v5/mm.h @@ -148,7 +148,8 @@ int copy_user_tables(struct address_space *new, struct address_space *orig); pgd_table_t *copy_page_tables(pgd_table_t *from); void remap_as_pages(void *vstart, void *vend); -void relocate_page_tables(void); +int pgd_count_pmds(pgd_table_t *pgd); +pgd_table_t *realloc_page_tables(void); void remove_section_mapping(unsigned long vaddr); void copy_pgds_by_vrange(pgd_table_t *to, pgd_table_t *from, diff --git a/include/l4/generic/cap-types.h b/include/l4/generic/cap-types.h index 6e208f1..944057c 100644 --- a/include/l4/generic/cap-types.h +++ b/include/l4/generic/cap-types.h @@ -32,8 +32,10 @@ #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 ??? */ +#define CAP_RTYPE_MUTEXPOOL (1 << 26) +#define CAP_RTYPE_MAPPOOL (1 << 27) /* For pmd spending */ +#define CAP_RTYPE_CAPPOOL (1 << 28) /* For new cap generation */ + /* * Access permissions */ @@ -61,6 +63,7 @@ #define CAP_MAP_CACHED (1 << 3) #define CAP_MAP_UNCACHED (1 << 4) #define CAP_MAP_UNMAP (1 << 5) +#define CAP_MAP_UTCB (1 << 6) /* Ipc capability */ #define CAP_IPC_SEND (1 << 0) diff --git a/include/l4/generic/capability.h b/include/l4/generic/capability.h index ae7a5eb..871a24d 100644 --- a/include/l4/generic/capability.h +++ b/include/l4/generic/capability.h @@ -14,21 +14,23 @@ * * 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 capid denotes the unique capability ID. + * The resid denotes the unique ID of targeted resource. + * The owner denotes the unique ID of the one and only 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 type field contains two types: + * - The capability type, + * - 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. + * particular resource. 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 @@ -64,6 +66,9 @@ struct cap_list { struct link caps; }; +void capability_init(struct capability *cap); +struct capability *capability_create(void); + #if 0 /* Virtual memory space allocated to container */ struct capability cap_virtmap = { diff --git a/include/l4/generic/container.h b/include/l4/generic/container.h index c6a9fd8..ba2921a 100644 --- a/include/l4/generic/container.h +++ b/include/l4/generic/container.h @@ -9,34 +9,47 @@ #include #include #include +#include #include #include #include #include #include +#define curcont (current->container) + +#define CONFIG_CONTAINER_NAMESIZE 64 +#define CONFIG_MAX_CAPS_USED 14 +#define CONFIG_MAX_PAGERS_USED 2 + /* Container macro. No locks needed! */ -#define this_container (current->container) + +struct pager { + struct ktcb *tcb; + unsigned long start_lma; + unsigned long start_vma; + unsigned long start_address; + unsigned long stack_address; + unsigned long memsize; + struct cap_list cap_list; +}; + struct container { - /* Unique container id */ - l4id_t cid; + l4id_t cid; /* Unique container id */ + int npagers; /* # of pagers */ + struct link list; /* List ref for containers */ + struct address_space_list space_list; /* List of address spaces */ + char name[CONFIG_CONTAINER_NAMESIZE]; /* Name of container */ + struct ktcb_list ktcb_list; /* List of threads */ + struct link pager_list; /* List of pagers */ - /* List of address spaces */ - struct address_space_list space_list; - - /* List of threads */ - struct ktcb_list ktcb_list; - - /* ID pools for threads and spaces */ - struct id_pool *thread_id_pool; + struct id_pool *thread_id_pool; /* Id pools for thread/spaces */ struct id_pool *space_id_pool; - /* Scheduling structs */ - struct scheduler scheduler; + struct scheduler scheduler; /* Scheduling structs */ - /* Mutex list for all userspace mutexes */ - struct mutex_queue_head mutex_queue_head; + struct mutex_queue_head mutex_queue_head; /* Userspace mutex list */ /* * Capabilities that apply to this container @@ -44,13 +57,10 @@ struct container { * Threads, address spaces, mutex queues, cpu share ... * Pagers possess these capabilities. */ - struct capability caps[5]; /* threadpool, spacepool, mutexpool, cpupool, mempool */ + /* threadpool, spacepool, mutexpool, cpupool, mempool */ + struct pager pager[CONFIG_MAX_PAGERS_USED]; }; - -#define CONFIG_MAX_CAPS_USED 11 -#define CONFIG_MAX_PAGERS_USED 2 - /* Compact, raw capability structure */ struct cap_info { unsigned int type; @@ -60,10 +70,13 @@ struct cap_info { unsigned long size; }; + struct pager_info { unsigned long pager_lma; unsigned long pager_vma; unsigned long pager_size; + unsigned long start_address; + unsigned long stack_address; /* Number of capabilities defined */ int ncaps; @@ -87,12 +100,22 @@ struct pager_info { * used to create run-time containers */ struct container_info { - char name[64]; + char name[CONFIG_CONTAINER_NAMESIZE]; int npagers; struct pager_info pager[CONFIG_MAX_PAGERS_USED]; }; extern struct container_info cinfo[]; +void kcont_insert_container(struct container *c, + struct kernel_container *kcont); + +struct container *container_create(void); + +int container_init_pagers(struct kernel_container *kcont, + pgd_table_t *current_pgd); + +int init_containers(struct kernel_container *kcont); + #endif /* __CONTAINER_H__ */ diff --git a/include/l4/generic/pgalloc.h b/include/l4/generic/pgalloc.h deleted file mode 100644 index 7cb501d..0000000 --- a/include/l4/generic/pgalloc.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __PGALLOC_H__ -#define __PGALLOC_H__ - -void *zalloc_page(void); -void *alloc_page(void); -void *alloc_pmd(void); -void *alloc_pgd(void); -int free_page(void *); -int free_pmd(void *); -int free_pgd(void *); - -int pgalloc_add_new_grant(unsigned long pfn, int npages); -void init_pgalloc(); - -#endif /* __PGALLOC_H__ */ diff --git a/include/l4/generic/resource.h b/include/l4/generic/resource.h index b40dca6..a0c1cae 100644 --- a/include/l4/generic/resource.h +++ b/include/l4/generic/resource.h @@ -1,10 +1,18 @@ +/* + * Description of resources on the system + * + * Copyright (C) 2009 Bahadir Balban + */ + #ifndef __RESOURCES_H__ #define __RESOURCES_H__ /* Number of containers defined at compile-time */ -#define TOTAL_CONTAINERS 1 +#define CONFIG_TOTAL_CONTAINERS 1 #include +#include +#include INC_SUBARCH(mm.h) struct boot_resources { int nconts; @@ -21,8 +29,30 @@ struct boot_resources { int nkmemcaps; }; +/* List of containers */ +struct container_head { + int ncont; + struct link list; +}; +/* + * Everything on the platform is described and stored + * in the structure below. + */ struct kernel_container { + l4id_t cid; + + /* System id pools */ + struct id_pool space_ids; + struct id_pool ktcb_ids; + struct id_pool resource_ids; + struct id_pool container_ids; + struct id_pool mutex_ids; + struct id_pool capability_ids; + + /* List of all containers */ + struct container_head containers; + /* Physical memory caps, used/unused */ struct cap_list physmem_used; struct cap_list physmem_free; @@ -38,7 +68,7 @@ struct kernel_container { struct mem_cache *pgd_cache; struct mem_cache *pmd_cache; struct mem_cache *ktcb_cache; - struct mem_cache *address_space_cache; + struct mem_cache *space_cache; struct mem_cache *mutex_cache; struct mem_cache *cap_cache; struct mem_cache *cont_cache; @@ -46,6 +76,22 @@ struct kernel_container { extern struct kernel_container kernel_container; +void free_pgd(void *addr); +void free_pmd(void *addr); +void free_space(void *addr); +void free_ktcb(void *addr); +void free_capability(void *addr); +void free_container(void *addr); +void free_user_mutex(void *addr); + +pgd_table_t *alloc_pgd(void); +pmd_table_t *alloc_pmd(void); +struct address_space *alloc_space(void); +struct ktcb *alloc_ktcb(void); +struct capability *alloc_capability(void); +struct container *alloc_container(void); +struct mutex_queue *alloc_user_mutex(void); + int init_system_resources(struct kernel_container *kcont); #endif /* __RESOURCES_H__ */ diff --git a/include/l4/generic/scheduler.h b/include/l4/generic/scheduler.h index 829e93c..038f5f0 100644 --- a/include/l4/generic/scheduler.h +++ b/include/l4/generic/scheduler.h @@ -45,6 +45,7 @@ struct runqueue { struct link task_list; /* List of tasks in rq */ unsigned int total; /* Total tasks */ }; + /* Contains per-container scheduling structures */ struct scheduler { struct runqueue sched_rq[SCHED_RQ_TOTAL]; @@ -55,6 +56,7 @@ struct scheduler { int prio_total; }; +void sched_init_runqueue(struct runqueue *rq); void sched_init_task(struct ktcb *task, int priority); void sched_prepare_sleep(void); void sched_suspend_sync(void); @@ -63,5 +65,6 @@ void sched_resume_sync(struct ktcb *task); void sched_resume_async(struct ktcb *task); void scheduler_start(void); void schedule(void); +void sched_init(struct scheduler *scheduler); #endif /* __SCHEDULER_H__ */ diff --git a/include/l4/generic/space.h b/include/l4/generic/space.h index 64cb97e..51c7efa 100644 --- a/include/l4/generic/space.h +++ b/include/l4/generic/space.h @@ -54,7 +54,7 @@ void address_space_add(struct address_space *space); void address_space_remove(struct address_space *space); void address_space_reference_lock(); void address_space_reference_unlock(); -void init_address_space_list(void); +void init_address_space_list(struct address_space_list *space_list); int check_access(unsigned long vaddr, unsigned long size, unsigned int flags, int page_in); #endif diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index 28f5904..ea7e732 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include INC_GLUE(memory.h) #include INC_GLUE(syscall.h) @@ -42,6 +42,8 @@ struct task_ids { l4id_t tgid; }; +struct container; + struct ktcb { /* User context */ task_context_t context; @@ -94,6 +96,9 @@ struct ktcb { /* Page table information */ struct address_space *space; + /* Container */ + struct container *container; + /* Fields for ipc rendezvous */ struct waitqueue_head wqh_recv; struct waitqueue_head wqh_send; @@ -121,7 +126,6 @@ union ktcb_union { char kstack[PAGE_SIZE]; }; - /* Hash table for all existing tasks */ struct ktcb_list { struct link list; @@ -157,7 +161,7 @@ void tcb_init(struct ktcb *tcb); struct ktcb *tcb_alloc_init(void); void tcb_delete(struct ktcb *tcb); -void init_ktcb_list(void); +void init_ktcb_list(struct ktcb_list *ktcb_list); void task_update_utcb(struct ktcb *cur, struct ktcb *next); int tcb_check_and_lazy_map_utcb(struct ktcb *task); diff --git a/include/l4/glue/arm/memory.h b/include/l4/glue/arm/memory.h index ae7cc24..bb403c6 100644 --- a/include/l4/glue/arm/memory.h +++ b/include/l4/glue/arm/memory.h @@ -121,5 +121,8 @@ pte_t virt_to_pte(unsigned long virtual); pte_t virt_to_pte_from_pgd(unsigned long virtual, pgd_table_t *pgd); unsigned long virt_to_phys_by_pgd(unsigned long vaddr, pgd_table_t *pgd); +struct ktcb; +void task_init_registers(struct ktcb *task, unsigned long pc); + #endif /* __GLUE_ARM_MEMORY_H__ */ diff --git a/include/l4/lib/idpool.h b/include/l4/lib/idpool.h index 619f237..62c9383 100644 --- a/include/l4/lib/idpool.h +++ b/include/l4/lib/idpool.h @@ -4,7 +4,17 @@ #include #include +/* One page size minus the structure fields */ +#define CONFIG_MAX_SYSTEM_IDS (1023*32) +#define SYSTEM_IDS_MAX (CONFIG_MAX_SYSTEM_IDS >> 5) + struct id_pool { + struct spinlock lock; + int nwords; + u32 bitmap[SYSTEM_IDS_MAX]; +}; + +struct id_pool_variable { struct spinlock lock; int nwords; u32 bitmap[]; diff --git a/src/api/mutex.c b/src/api/mutex.c index 34c6ff5..bc5fa31 100644 --- a/src/api/mutex.c +++ b/src/api/mutex.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -16,21 +17,22 @@ #include INC_ARCH(exception.h) #include INC_GLUE(memory.h) -void init_mutex_queue_head(void) +void init_mutex_queue_head(struct mutex_queue_head *mqhead) { - memset(&mutex_queue_head, 0, sizeof (mutex_queue_head)); - link_init(&mutex_queue_head.list); - mutex_init(&mutex_queue_head.mutex_control_mutex); -} -void mutex_queue_head_lock() -{ - mutex_lock(&mutex_queue_head.mutex_control_mutex); + memset(mqhead, 0, sizeof(*mqhead)); + link_init(&mqhead->list); + mutex_init(&mqhead->mutex_control_mutex); } -void mutex_queue_head_unlock() +void mutex_queue_head_lock(struct mutex_queue_head *mqhead) +{ + mutex_lock(&mqhead->mutex_control_mutex); +} + +void mutex_queue_head_unlock(struct mutex_queue_head *mqhead) { /* Async unlock because in some cases preemption may be disabled here */ - mutex_unlock_async(&mutex_queue_head.mutex_control_mutex); + mutex_unlock_async(&mqhead->mutex_control_mutex); } @@ -44,27 +46,28 @@ void mutex_queue_init(struct mutex_queue *mq, unsigned long physical) waitqueue_head_init(&mq->wqh_contenders); } -void mutex_control_add(struct mutex_queue *mq) +void mutex_control_add(struct mutex_queue_head *mqhead, struct mutex_queue *mq) { BUG_ON(!list_empty(&mq->list)); - list_insert(&mq->list, &mutex_queue_head.list); - mutex_queue_head.count++; + list_insert(&mq->list, &mqhead->list); + mqhead->count++; } -void mutex_control_remove(struct mutex_queue *mq) +void mutex_control_remove(struct mutex_queue_head *mqhead, struct mutex_queue *mq) { list_remove_init(&mq->list); - mutex_queue_head.count--; + mqhead->count--; } /* Note, this has ptr/negative error returns instead of ptr/zero. */ -struct mutex_queue *mutex_control_find(unsigned long mutex_physical) +struct mutex_queue *mutex_control_find(struct mutex_queue_head *mqhead, + unsigned long mutex_physical) { struct mutex_queue *mutex_queue; /* Find the mutex queue with this key */ - list_foreach_struct(mutex_queue, &mutex_queue_head.list, list) + list_foreach_struct(mutex_queue, &mqhead->list, list) if (mutex_queue->physical == mutex_physical) return mutex_queue; @@ -109,21 +112,22 @@ void mutex_control_delete(struct mutex_queue *mq) * until a wake up event occurs. If there is already an asleep * lock holder (i.e. unlocker) that is woken up and we return. */ -int mutex_control_lock(unsigned long mutex_address) +int mutex_control_lock(struct mutex_queue_head *mqhead, + unsigned long mutex_address) { struct mutex_queue *mutex_queue; - mutex_queue_head_lock(); + mutex_queue_head_lock(mqhead); /* Search for the mutex queue */ - if (!(mutex_queue = mutex_control_find(mutex_address))) { + if (!(mutex_queue = mutex_control_find(mqhead, mutex_address))) { /* Create a new one */ if (!(mutex_queue = mutex_control_create(mutex_address))) { - mutex_queue_head_unlock(); + mutex_queue_head_unlock(mqhead); return -ENOMEM; } /* Add the queue to mutex queue list */ - mutex_control_add(mutex_queue); + mutex_control_add(mqhead, mutex_queue); } else { /* See if there is a lock holder */ if (mutex_queue->wqh_holders.sleepers) { @@ -134,11 +138,11 @@ int mutex_control_lock(unsigned long mutex_address) wake_up(&mutex_queue->wqh_holders, WAKEUP_ASYNC); /* Since noone is left, delete the mutex queue */ - mutex_control_remove(mutex_queue); + mutex_control_remove(mqhead, mutex_queue); mutex_control_delete(mutex_queue); /* Release lock and return */ - mutex_queue_head_unlock(); + mutex_queue_head_unlock(mqhead); return 0; } @@ -150,7 +154,7 @@ int mutex_control_lock(unsigned long mutex_address) wait_on_prepare(&mutex_queue->wqh_contenders, &wq); /* Release lock */ - mutex_queue_head_unlock(); + mutex_queue_head_unlock(mqhead); /* Initiate prepared wait */ return wait_on_prepared_wait(); @@ -170,23 +174,24 @@ int mutex_control_lock(unsigned long mutex_address) * to acquire the mutex, waking up all of them increases the * chances that some thread may acquire it. */ -int mutex_control_unlock(unsigned long mutex_address) +int mutex_control_unlock(struct mutex_queue_head *mqhead, + unsigned long mutex_address) { struct mutex_queue *mutex_queue; - mutex_queue_head_lock(); + mutex_queue_head_lock(mqhead); /* Search for the mutex queue */ - if (!(mutex_queue = mutex_control_find(mutex_address))) { + if (!(mutex_queue = mutex_control_find(mqhead, mutex_address))) { /* No such mutex, create one and sleep on it */ if (!(mutex_queue = mutex_control_create(mutex_address))) { - mutex_queue_head_unlock(); + mutex_queue_head_unlock(mqhead); return -ENOMEM; } /* Add the queue to mutex queue list */ - mutex_control_add(mutex_queue); + mutex_control_add(mqhead, mutex_queue); /* Prepare to wait on the lock holders queue */ CREATE_WAITQUEUE_ON_STACK(wq, current); @@ -195,7 +200,7 @@ int mutex_control_unlock(unsigned long mutex_address) wait_on_prepare(&mutex_queue->wqh_holders, &wq); /* Release lock first */ - mutex_queue_head_unlock(); + mutex_queue_head_unlock(mqhead); /* Initiate prepared wait */ return wait_on_prepared_wait(); @@ -209,11 +214,11 @@ int mutex_control_unlock(unsigned long mutex_address) wake_up(&mutex_queue->wqh_contenders, WAKEUP_ASYNC); /* Since noone is left, delete the mutex queue */ - mutex_control_remove(mutex_queue); + mutex_control_remove(mqhead, mutex_queue); mutex_control_delete(mutex_queue); /* Release lock and return */ - mutex_queue_head_unlock(); + mutex_queue_head_unlock(mqhead); return 0; } @@ -238,15 +243,17 @@ int sys_mutex_control(unsigned long mutex_address, int mutex_op) /* Find and check physical address for virtual mutex address */ if (!(mutex_physical = virt_to_phys_by_pgd(mutex_address, - TASK_PGD(current)))) + TASK_PGD(current)))) return -EINVAL; switch (mutex_op) { case MUTEX_CONTROL_LOCK: - ret = mutex_control_lock(mutex_physical); + ret = mutex_control_lock(&curcont->mutex_queue_head, + mutex_physical); break; case MUTEX_CONTROL_UNLOCK: - ret = mutex_control_unlock(mutex_physical); + ret = mutex_control_unlock(&curcont->mutex_queue_head, + mutex_physical); break; default: printk("%s: Invalid operands\n", __FUNCTION__); @@ -256,4 +263,3 @@ int sys_mutex_control(unsigned long mutex_address, int mutex_op) return ret; } - diff --git a/src/api/syscall.c b/src/api/syscall.c index c55c276..243948e 100644 --- a/src/api/syscall.c +++ b/src/api/syscall.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -201,7 +201,7 @@ int sys_kmem_control(unsigned long pfn, int npages, int grant) return -EINVAL; /* Add the granted pages to the allocator */ - if (pgalloc_add_new_grant(pfn, npages)) + // if (pgalloc_add_new_grant(pfn, npages)) BUG(); } else /* Reclaim not implemented yet */ BUG(); diff --git a/src/api/thread.c b/src/api/thread.c index 095b710..41e3514 100644 --- a/src/api/thread.c +++ b/src/api/thread.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include INC_ARCH(asm.h) #include INC_SUBARCH(mm.h) @@ -334,7 +334,7 @@ int thread_create(struct task_ids *ids, unsigned int flags) out_err: /* Pre-mature tcb needs freeing by free_page */ - free_page(new); + free_ktcb(new); return err; } diff --git a/src/arch/arm/v5/mm.c b/src/arch/arm/v5/mm.c index 6f5d22f..638e269 100644 --- a/src/arch/arm/v5/mm.c +++ b/src/arch/arm/v5/mm.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include INC_SUBARCH(mm.h) #include INC_SUBARCH(mmu_ops.h) @@ -535,6 +536,16 @@ out_error: return -ENOMEM; } +int pgd_count_pmds(pgd_table_t *pgd) +{ + int npmd = 0; + + for (int i = 0; i < PGD_ENTRY_TOTAL; i++) + if ((pgd->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE) + npmd++; + return npmd; +} + /* * Allocates and copies all levels of page tables from one task to another. * Useful when forking. @@ -600,66 +611,56 @@ out_error: extern pmd_table_t *pmd_array; -#if 0 /* - * Moves the section mapped kspace that resides far apart from kernel as close - * as possible to the kernel image, and unmaps the old 1MB kspace section which - * is really largely unused. + * Jumps from boot page tables to tables allocated from the cache. */ -void relocate_page_tables(void) +pgd_table_t *realloc_page_tables(void) { - /* Adjust the end of kernel address to page table alignment. */ - unsigned long pt_new = align_up(_end_kernel, sizeof(pgd_table_t)); - unsigned long reloc_offset = (unsigned long)_start_kspace - pt_new; - unsigned long pt_area_size = (unsigned long)_end_kspace - - (unsigned long)_start_kspace; + pgd_table_t *pgd_new = alloc_pgd(); + pgd_table_t *pgd_old = &init_pgd; + pmd_table_t *orig, *pmd; - BUG_ON(reloc_offset & (SZ_1K - 1)) + /* Copy whole pgd entries */ + memcpy(pgd_new, pgd_old, sizeof(pgd_table_t)); - /* Map the new page table area into the current pgd table */ - add_mapping(virt_to_phys(pt_new), pt_new, pt_area_size, - MAP_IO_DEFAULT_FLAGS); + /* Allocate and copy all pmds */ + for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { + /* Detect a pmd entry */ + if ((pgd_old->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE) { + /* Allocate new pmd */ + if (!(pmd = alloc_pmd())) { + printk("FATAL: PMD allocation " + "failed during system initialization\n"); + BUG(); + } - /* Copy the entire kspace area, i.e. the pgd + static pmds. */ - memcpy((void *)pt_new, _start_kspace, pt_area_size); + /* Find original pmd */ + orig = (pmd_table_t *) + phys_to_virt((pgd_old->entry[i] & + PGD_COARSE_ALIGN_MASK)); - /* Update the only reference to current pgd table */ - TASK_PGD(current) = (pgd_table_t *)pt_new; + /* Copy original to new */ + memcpy(pmd, orig, sizeof(pmd_table_t)); - /* - * Since pmd's are also moved, update the pmd references in pgd by - * subtracting the relocation offset from each valid pmd entry. - * TODO: This would be best done within a helper function. - */ - for (int i = 0; i < PGD_ENTRY_TOTAL; i++) - /* If there's a coarse 2nd level entry */ - if ((TASK_PGD(current)->entry[i] & PGD_TYPE_MASK) - == PGD_TYPE_COARSE) - TASK_PGD(current)->entry[i] -= reloc_offset; - - /* Update the pmd array pointer. */ - pmd_array = (pmd_table_t *)((unsigned long)_start_pmd - reloc_offset); + /* Replace original pmd entry in pgd with new */ + pgd_new->entry[i] = (pgd_t)virt_to_phys(pmd); + pgd_new->entry[i] |= PGD_TYPE_COARSE; + } + } /* Switch the virtual memory system into new area */ arm_clean_invalidate_cache(); arm_drain_writebuffer(); arm_invalidate_tlb(); - arm_set_ttb(virt_to_phys(TASK_PGD(current))); + arm_set_ttb(virt_to_phys(pgd_new)); arm_invalidate_tlb(); - /* Unmap the old page table area */ - remove_section_mapping((unsigned long)&kspace); - - /* Update the page table markers to the new area. Any references would - * go to these markers. */ - __pt_start = pt_new; - __pt_end = pt_new + pt_area_size; - printk("%s: Initial page tables moved from 0x%x to 0x%x physical\n", - __KERNELNAME__, virt_to_phys(&kspace), - virt_to_phys(TASK_PGD(current))); + __KERNELNAME__, virt_to_phys(pgd_old), + virt_to_phys(pgd_new)); + + return pgd_new; } -#endif /* * Useful for upgrading to page-grained control over a section mapping: diff --git a/src/generic/SConscript b/src/generic/SConscript index ad87582..47043fc 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', 'resource.c', 'container.c'] +src_local = ['physmem.c', 'irq.c', 'scheduler.c', 'time.c', 'tcb.c', 'kmalloc.c', 'space.c', 'bootm.c', 'resource.c', 'container.c', 'capability.c'] obj = env.Object(src_local) Return('obj') diff --git a/src/generic/capability.c b/src/generic/capability.c index c70e8e1..0d40639 100644 --- a/src/generic/capability.c +++ b/src/generic/capability.c @@ -3,5 +3,21 @@ * * Copyright (C) 2009 Bahadir Balban */ +#include +#include +struct capability *capability_create(void) +{ + struct capability *cap = alloc_capability(); + + capability_init(cap); + + return cap; +} + +void capability_init(struct capability *cap) +{ + cap->capid = id_new(&kernel_container.capability_ids); + link_init(&cap->list); +} diff --git a/src/generic/container.c b/src/generic/container.c index c395f93..d55432a 100644 --- a/src/generic/container.c +++ b/src/generic/container.c @@ -4,8 +4,10 @@ * Copyright (C) 2009 Bahadir Balban */ #include +#include #include #include +#include #include INC_GLUE(memory.h) /* @@ -22,7 +24,7 @@ struct container_info cinfo[] = { .pager_lma = __pfn(0x38000), .pager_vma = __pfn(0xE0000000), .pager_size = __pfn(0x96000), - .ncaps = 11, + .ncaps = 14, .caps = { [0] = { .type = CAP_TYPE_MAP | CAP_RTYPE_VIRTMEM, @@ -51,6 +53,16 @@ struct container_info cinfo[] = { .size = __pfn(0x10000000), }, [3] = { + .type = CAP_TYPE_MAP | CAP_RTYPE_VIRTMEM, + .access = CAP_MAP_READ | CAP_MAP_WRITE + | CAP_MAP_EXEC | CAP_MAP_UNMAP + | CAP_MAP_UTCB, + .start = __pfn(0xF8000000), + .end = __pfn(0xF9000000), + .size = __pfn(0x1000000), + }, + + [4] = { .type = CAP_TYPE_MAP | CAP_RTYPE_PHYSMEM, .access = CAP_MAP_CACHED | CAP_MAP_UNCACHED | CAP_MAP_READ | CAP_MAP_WRITE @@ -58,51 +70,244 @@ struct container_info cinfo[] = { .start = __pfn(0x38000), .end = __pfn(0x1000000), /* 16 MB for all posix services */ }, - [4] = { + [5] = { .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] = { + [6] = { .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] = { + [7] = { .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] = { + [8] = { .type = CAP_TYPE_QUANTITY | CAP_RTYPE_THREADPOOL, .access = 0, .start = 0, .end = 0, .size = 64, }, - [8] = { + [9] = { .type = CAP_TYPE_QUANTITY | CAP_RTYPE_SPACEPOOL, .access = 0, .start = 0, .end = 0, .size = 64, }, - [9] = { + [10] = { .type = CAP_TYPE_QUANTITY | CAP_RTYPE_CPUPOOL, .access = 0, .start = 0, .end = 0, .size = 50, /* Percentage */ }, - [10] = { + [11] = { .type = CAP_TYPE_QUANTITY | CAP_RTYPE_MUTEXPOOL, .access = 0, .start = 0, .end = 0, .size = 100, }, + [12] = { + /* For pmd accounting */ + .type = CAP_TYPE_QUANTITY | CAP_RTYPE_MAPPOOL, + .access = 0, .start = 0, .end = 0, + /* Function of mem regions, nthreads etc. */ + .size = (64 * 30 + 100), + }, + [13] = { + /* For cap spliting, creating, etc. */ + .type = CAP_TYPE_QUANTITY | CAP_RTYPE_CAPPOOL, + .access = 0, .start = 0, .end = 0, + /* This may be existing caps X 2 etc. */ + .size = 30, + }, }, }, }, }, }; + +int container_init(struct container *c) +{ + /* Allocate new container id */ + c->cid = id_new(&kernel_container.container_ids); + + /* Init data structures */ + link_init(&c->pager_list); + init_address_space_list(&c->space_list); + init_ktcb_list(&c->ktcb_list); + init_mutex_queue_head(&c->mutex_queue_head); + + /* Init scheduler */ + sched_init(&c->scheduler); + + return 0; +} + +struct container *container_create(void) +{ + struct container *c = alloc_container(); + + container_init(c); + + return c; +} + +void kcont_insert_container(struct container *c, + struct kernel_container *kcont) +{ + list_insert(&c->list, &kcont->containers.list); + kcont->containers.ncont++; +} + +void task_setup_utcb(struct ktcb *task, struct pager *pager) +{ + struct capability *cap; + + /* Find a virtual memory capability with UTCB map permissions */ + list_foreach_struct(cap, &pager->cap_list.caps, list) { + if (((cap->type & CAP_RTYPE_MASK) == + CAP_RTYPE_VIRTMEM) && + (cap->access & CAP_MAP_UTCB)) { + /* Use first address slot as pager's utcb */ + task->utcb_address = __pfn_to_addr(cap->start); + } + } +} + +/* + * TODO: + * + * Create a purer address_space_create that takes + * flags for extra ops such as copying kernel tables, + * user tables of an existing pgd etc. + */ + +/* + * The first pager initialization is a special-case + * since it uses the current kernel pgd. + */ +int init_first_pager(struct pager *pager, + struct container *cont, + pgd_table_t *current_pgd) +{ + struct ktcb *task = tcb_alloc_init(); + struct address_space *space; + + /* Initialize ktcb */ + task_init_registers(task, pager->start_vma); + task_setup_utcb(task, pager); + + /* Allocate space structure */ + if (!(space = alloc_space())) + return -ENOMEM; + + /* Set up space id */ + space->spid = id_new(&kernel_container.space_ids); + + /* Initialize space structure */ + link_init(&space->list); + mutex_init(&space->lock); + space->pgd = current_pgd; + + task->space = space; + task->container = cont; + + /* Map the task's space */ + add_mapping_pgd(pager->start_lma, pager->start_vma, + page_align_up(pager->memsize), + MAP_USR_DEFAULT_FLAGS, TASK_PGD(task)); + + printk("Mapping %lu pages from 0x%lx to 0x%lx for %s\n", + __pfn(page_align_up(pager->memsize)), + pager->start_lma, pager->start_vma, cont->name); + + /* Initialize task scheduler parameters */ + sched_init_task(task, TASK_PRIO_PAGER); + + /* Give it a kick-start tick and make runnable */ + task->ticks_left = 1; + sched_resume_async(task); + + /* Container list that keeps all tasks */ + tcb_add(task); + + return 0; +} + + +/* + * Inspects pager parameters defined in the container, + * and sets up an execution environment for the pager. + * + * This involves setting up pager's ktcb, space, utcb, + * all ids, registers, and mapping its (perhaps) first + * few pages in order to make it runnable. + */ +int init_pager(struct pager *pager, struct container *cont) +{ + struct ktcb *task = tcb_alloc_init(); + + task_init_registers(task, pager->start_vma); + + task_setup_utcb(task, pager); + + task->space = address_space_create(0); + + task->container = cont; + + add_mapping_pgd(pager->start_lma, pager->start_vma, + page_align_up(pager->memsize), + MAP_USR_DEFAULT_FLAGS, TASK_PGD(task)); + + printk("Mapping %lu pages from 0x%lx to 0x%lx for %s\n", + __pfn(page_align_up(pager->memsize)), + pager->start_lma, pager->start_vma, cont->name); + + /* Initialize task scheduler parameters */ + sched_init_task(task, TASK_PRIO_PAGER); + + /* Give it a kick-start tick and make runnable */ + task->ticks_left = 1; + sched_resume_async(task); + + /* Container list that keeps all tasks */ + tcb_add(task); + + return 0; +} + +/* + * Initialize all containers with their initial set of tasks, + * spaces, scheduler parameters such that they can be started. + */ +int container_init_pagers(struct kernel_container *kcont, + pgd_table_t *current_pgd) +{ + struct container *cont; + struct pager *pager; + int pgidx = 0; + + list_foreach_struct(cont, &kcont->containers.list, list) { + for (int i = 0; i < cont->npagers; i++) { + pager = &cont->pager[i]; + + /* First pager initializes specially */ + if (pgidx == 0) + init_first_pager(pager, cont, + current_pgd); + else + init_pager(pager, cont); + pgidx++; + } + } + + return 0; +} + diff --git a/src/generic/kmalloc.c b/src/generic/kmalloc.c index 6cffd7e..bebac98 100644 --- a/src/generic/kmalloc.c +++ b/src/generic/kmalloc.c @@ -5,7 +5,7 @@ */ #include #include -#include +#include #include INC_GLUE(memory.h) /* Supports this many different kmalloc sizes */ @@ -36,117 +36,18 @@ void init_kmalloc() mutex_init(&km_pool.kmalloc_mutex); } -/* - * KMALLOC implementation: - * - * Allocates memory from mem_caches that it generates on-the-fly, - * for up to KMALLOC_POOLS_MAX different sizes. - */ -void *__kmalloc(int size) -{ - struct mem_cache *cache; - int right_sized_pool_idx = -1; - int index; - - BUG_ON(!size); /* It is a kernel bug if size is 0 */ - - for (int i = 0; i < km_pool.total; i++) { - /* Check if this pool has right size */ - if (km_pool.pool_head[i].cache_size == size) { - right_sized_pool_idx = i; - /* - * Found the pool, now see if any - * cache has available slots - */ - list_foreach_struct(cache, &km_pool.pool_head[i].cache_list, - list) { - if (cache->free) - return mem_cache_alloc(cache); - else - break; - } - } - } - - /* - * All pools are allocated and none has requested size - */ - if ((right_sized_pool_idx < 0) && - (km_pool.total == KMALLOC_POOLS_MAX - 1)) { - printk("kmalloc: Too many types of pool sizes requested. " - "Giving up.\n"); - BUG(); - } - - /* A pool exists with given size? (But no cache in it is free) */ - if (right_sized_pool_idx >= 0) - index = right_sized_pool_idx; - else /* No pool of this size, allocate new by incrementing total */ - index = km_pool.total++; - - /* Only allow up to page size */ - BUG_ON(size >= PAGE_SIZE); - BUG_ON(!(cache = mem_cache_init(alloc_page(), PAGE_SIZE, - size, 0))); - // printk("%s: Created new cache for size %d\n", __FUNCTION__, size); - list_insert(&cache->list, &km_pool.pool_head[index].cache_list); - km_pool.pool_head[index].occupied = 1; - km_pool.pool_head[index].total_caches++; - km_pool.pool_head[index].cache_size = size; - return mem_cache_alloc(cache); -} - void *kmalloc(int size) { - void *p; - - mutex_lock(&km_pool.kmalloc_mutex); - p = __kmalloc(size); - mutex_unlock(&km_pool.kmalloc_mutex); - return p; -} - -/* FIXME: - * Horrible complexity O(n^2) because we don't know which cache - * we're freeing from!!! But its simple. ;-) - */ -int __kfree(void *p) -{ - struct mem_cache *cache, *tmp; - - for (int i = 0; i < km_pool.total; i++) - list_foreach_removable_struct(cache, tmp, - &km_pool.pool_head[i].cache_list, - list) { - if (!mem_cache_free(cache, p)) { - if (mem_cache_is_empty(cache)) { - km_pool.pool_head[i].total_caches--; - list_remove(&cache->list); - free_page(cache); - /* - * Total remains the same but slot - * may have no caches left. - */ - } - return 0; - } - } - return -1; + return 0; } int kfree(void *p) { - int ret; - mutex_lock(&km_pool.kmalloc_mutex); - ret = __kfree(p); - mutex_unlock(&km_pool.kmalloc_mutex); - return ret; + return 0; } void *kzalloc(int size) { - void *p = kmalloc(size); - memset(p, 0, size); - return p; + return 0; } diff --git a/src/generic/pgalloc.c b/src/generic/pgalloc.c deleted file mode 100644 index 018ef55..0000000 --- a/src/generic/pgalloc.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Simple kernel memory allocator built on top of memcache - * implementation. - * - * Copyright (C) 2007 Bahadir Balban - */ -#include -#include -#include -#include -#include -#include -#include INC_GLUE(memory.h) - -/* FIXME: - * - * mem_cache_alloc() now has an interruptible mutex. - * All routines defined here should check returned errors. - */ - -#define PGALLOC_PGD_CACHE 0 -#define PGALLOC_PMD_CACHE 1 -#define PGALLOC_PG_CACHE 2 -#define PGALLOC_CACHE_TOTAL 3 - -/* The initial chunk of physical memory allocated before any pagers. */ -#define PGALLOC_INIT_GRANT SZ_1MB - -/* Covers 3 main types of memory needed by the kernel. */ -struct pgalloc { - struct link cache_list[3]; -}; -static struct pgalloc pgalloc; - -void pgalloc_add_new_cache(struct mem_cache *cache, int cidx) -{ - link_init(&cache->list); - BUG_ON(cidx >= PGALLOC_CACHE_TOTAL || cidx < 0); - list_insert(&cache->list, &pgalloc.cache_list[cidx]); -} - -void print_kmem_grant_params(grant_kmem_usage_t *params) -{ - printk("%s: %lu bytes physical memory granted.\n", __KERNELNAME__, params->total_size); - printk("%s: Possible kmem usage on this memory grant:\n", __KERNELNAME__); - printk("%s: PGDs: %lu, PMDs: %lu, TCBs: %lu, Extra: %lu bytes.\n", __KERNELNAME__, - params->total_pgds, params->total_pmds, params->total_tcbs, - params->extra); -} - -#define TASK_AVERAGE_SIZE SZ_16MB -#define TASK_AVERAGE_PMDS TASK_AVERAGE_SIZE / PMD_MAP_SIZE - -void calc_grant_kmem_usage(grant_kmem_usage_t *params, unsigned long total_size) -{ - /* Kmem usage per task */ - unsigned long task_avg_kmem_usage = PGD_SIZE + PMD_SIZE * 16 + PAGE_SIZE; - unsigned long total_tasks = total_size / task_avg_kmem_usage; - unsigned long extra = total_size - total_tasks * task_avg_kmem_usage; - - params->total_size = total_size; - params->total_tasks = total_tasks; - params->total_pgds = total_tasks; - params->total_pmds = total_tasks * 16; - params->total_tcbs = total_tasks; - params->extra = extra; - - print_kmem_grant_params(params); -} - - -int pgalloc_add_new_grant(unsigned long pfn, int npages) -{ - unsigned long physical = __pfn_to_addr(pfn); - void *virtual = (void *)phys_to_virt(physical); - struct mem_cache *pgd_cache, *pmd_cache, *pg_cache; - grant_kmem_usage_t params; - - /* First map the whole grant */ - add_mapping(physical, phys_to_virt(physical), __pfn_to_addr(npages), - MAP_SVC_RW_FLAGS); - - /* Calculate how to divide buffer into different caches */ - calc_grant_kmem_usage(¶ms, __pfn_to_addr(npages)); - - /* Create the caches, least alignment-needing, most, then others. */ - pmd_cache = mem_cache_init(virtual, params.total_pmds * PMD_SIZE, - PMD_SIZE, 1); - virtual += params.total_pmds * PMD_SIZE; - - pgd_cache = mem_cache_init(virtual, params.total_pgds * PGD_SIZE, - PGD_SIZE, 1); - virtual += params.total_pgds * PGD_SIZE; - - pg_cache = mem_cache_init(virtual, params.total_tcbs * PAGE_SIZE - + params.extra, PAGE_SIZE, 1); - - /* Add the caches */ - pgalloc_add_new_cache(pgd_cache, PGALLOC_PGD_CACHE); - pgalloc_add_new_cache(pmd_cache, PGALLOC_PMD_CACHE); - pgalloc_add_new_cache(pg_cache, PGALLOC_PG_CACHE); - - return 0; -} - -void init_pgalloc(void) -{ - int initial_grant = PGALLOC_INIT_GRANT; - - for (int i = 0; i < PGALLOC_CACHE_TOTAL; i++) - link_init(&pgalloc.cache_list[i]); - - /* Grant ourselves with an initial chunk of physical memory */ - physmem.free_cur = page_align_up(physmem.free_cur); - set_page_map(physmem.free_cur, __pfn(initial_grant), 1); - pgalloc_add_new_grant(__pfn(physmem.free_cur), __pfn(initial_grant)); - physmem.free_cur += initial_grant; - - /* Activate kmalloc */ - init_kmalloc(); -} - -void pgalloc_remove_cache(struct mem_cache *cache) -{ - list_remove_init(&cache->list); -} - -static inline void *pgalloc_from_cache(int cidx) -{ - struct mem_cache *cache, *n; - - list_foreach_removable_struct(cache, n, &pgalloc.cache_list[cidx], list) - if (mem_cache_total_empty(cache)) - return mem_cache_zalloc(cache); - return 0; -} - -int kfree_to_cache(int cidx, void *virtual) -{ - struct mem_cache *cache, *n; - - list_foreach_removable_struct(cache, n, &pgalloc.cache_list[cidx], list) - if (mem_cache_free(cache, virtual) == 0) - return 0; - return -1; -} - -void *alloc_page(void) -{ - return pgalloc_from_cache(PGALLOC_PG_CACHE); -} - -void *alloc_pmd(void) -{ - return pgalloc_from_cache(PGALLOC_PMD_CACHE); -} - -void *alloc_pgd(void) -{ - return pgalloc_from_cache(PGALLOC_PGD_CACHE); -} - -int free_page(void *v) -{ - return kfree_to_cache(PGALLOC_PG_CACHE, v); -} - -int free_pmd(void *v) -{ - return kfree_to_cache(PGALLOC_PMD_CACHE, v); -} - -int free_pgd(void *v) -{ - return kfree_to_cache(PGALLOC_PGD_CACHE, v); -} - -void *zalloc_page(void) -{ - void *p; - - if (!(p = alloc_page())) - return 0; - - memset(p, 0, PAGE_SIZE); - return p; -} - diff --git a/src/generic/physmem.c b/src/generic/physmem.c index 769ab5d..3cfcfd9 100644 --- a/src/generic/physmem.c +++ b/src/generic/physmem.c @@ -4,7 +4,7 @@ * Copyright (C) 2007 Bahadir Balban */ #include -#include +#include #include #include #include @@ -88,6 +88,6 @@ void physmem_init() void memory_init() { - init_pgalloc(); + //init_pgalloc(); } diff --git a/src/generic/resource.c b/src/generic/resource.c index e27bcb9..91b7dc7 100644 --- a/src/generic/resource.c +++ b/src/generic/resource.c @@ -3,7 +3,6 @@ * * Copyright (C) 2009 Bahadir Balban */ - #include #include #include @@ -16,6 +15,76 @@ struct kernel_container kernel_container; +pgd_table_t *alloc_pgd(void) +{ + return mem_cache_zalloc(kernel_container.pgd_cache); +} + +pmd_table_t *alloc_pmd(void) +{ + return mem_cache_zalloc(kernel_container.pmd_cache); +} + +struct address_space *alloc_space(void) +{ + return mem_cache_zalloc(kernel_container.space_cache); +} + +struct ktcb *alloc_ktcb(void) +{ + return mem_cache_zalloc(kernel_container.ktcb_cache); +} + +struct capability *alloc_capability(void) +{ + return mem_cache_zalloc(kernel_container.cap_cache); +} + +struct container *alloc_container(void) +{ + return mem_cache_zalloc(kernel_container.cont_cache); +} + +struct mutex_queue *alloc_user_mutex(void) +{ + return mem_cache_zalloc(kernel_container.mutex_cache); +} + +void free_pgd(void *addr) +{ + BUG_ON(mem_cache_free(kernel_container.pgd_cache, addr) < 0); +} + +void free_pmd(void *addr) +{ + BUG_ON(mem_cache_free(kernel_container.pmd_cache, addr) < 0); +} + +void free_space(void *addr) +{ + BUG_ON(mem_cache_free(kernel_container.space_cache, addr) < 0); +} + +void free_ktcb(void *addr) +{ + BUG_ON(mem_cache_free(kernel_container.ktcb_cache, addr) < 0); +} + +void free_capability(void *addr) +{ + BUG_ON(mem_cache_free(kernel_container.cap_cache, addr) < 0); +} + +void free_container(void *addr) +{ + BUG_ON(mem_cache_free(kernel_container.cont_cache, addr) < 0); +} + +void free_user_mutex(void *addr) +{ + BUG_ON(mem_cache_free(kernel_container.mutex_cache, addr) < 0); +} + void cap_list_init(struct cap_list *clist) { clist->ncaps = 0; @@ -78,6 +147,10 @@ int memcap_shrink(struct capability *cap, struct cap_list *cap_list, return 0; } +/* + * Given a single memory cap (that definitely overlaps) removes + * the portion of pfns specified by start/end. + */ int memcap_unmap_range(struct capability *cap, struct cap_list *cap_list, const unsigned long start, @@ -128,65 +201,6 @@ int memcap_unmap(struct cap_list *cap_list, return 1; } -/* - * 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: - /* Area size in pages divided by mapsize in pages */ - bootres->npmds += - cap->size / __pfn(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) - printk("FATAL: Memory capability range " - "overlaps with another one. " - "start=0x%lx, end=0x%lx\n", - __pfn_to_addr(cap->start), - __pfn_to_addr(cap->end)); - BUG(); - } - break; - case CAP_RTYPE_PHYSMEM: - if ((ret = memcap_unmap(&kcont->physmem_free, - cap->start, cap->end))) { - if (ret < 0) - printk("FATAL: Insufficient boot memory " - "to split capability\n"); - if (ret > 0) - printk("FATAL: Memory capability range " - "overlaps with another one. " - "start=0x%lx, end=0x%lx\n", - __pfn_to_addr(cap->start), - __pfn_to_addr(cap->end)); - BUG(); - } - break; - } - return ret; -} - /* * Migrate any boot allocations to their relevant caches. */ @@ -219,65 +233,28 @@ int free_boot_memory(struct boot_resources *bootres, return 0; } - -struct mem_cache *init_resource_cache(int nstruct, int struct_size, - struct kernel_container *kcont, - int aligned) -{ - struct capability *cap; - unsigned long bufsize; - - /* In all unused physical memory regions */ - list_foreach_struct(cap, &kcont->physmem_free.caps, list) { - /* Get buffer size needed for cache */ - bufsize = mem_cache_bufsize((void *)__pfn_to_addr(cap->start), - struct_size, nstruct, - 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->physmem_free, - cap->start, cap->start + - __pfn(page_align_up((bufsize)))); - - /* TODO: Manipulate memcaps for virtual range??? */ - - /* Initialize the cache */ - return mem_cache_init((void *)virtual, bufsize, - PGD_SIZE, 1); - } - } - return 0; -} - /* * 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. + * during the traversal of container capabilities, and memcache + * allocations. */ void init_kernel_container(struct kernel_container *kcont) { struct capability *physmem, *virtmem, *kernel_area; + /* Initialize system id pools */ + kcont->space_ids.nwords = SYSTEM_IDS_MAX; + kcont->ktcb_ids.nwords = SYSTEM_IDS_MAX; + kcont->resource_ids.nwords = SYSTEM_IDS_MAX; + kcont->container_ids.nwords = SYSTEM_IDS_MAX; + kcont->mutex_ids.nwords = SYSTEM_IDS_MAX; + kcont->capability_ids.nwords = SYSTEM_IDS_MAX; + + /* Get first container id for itself */ + kcont->cid = id_new(&kcont->container_ids); + /* Initialize kernel capability lists */ cap_list_init(&kcont->physmem_used); cap_list_init(&kcont->physmem_free); @@ -318,40 +295,164 @@ void init_kernel_container(struct kernel_container *kcont) */ } -void create_containers(struct boot_resources *bootres, - struct kernel_container *kcont) +/* + * Copies cinfo structures to real capabilities for each pager. + * + * FIXME: Check if pager has enough resources to create its caps. + */ +int copy_pager_info(struct pager *pager, struct pager_info *pinfo) { + struct capability *cap; + struct cap_info *cap_info; + pager->start_lma = pinfo->pager_lma; + pager->start_vma = pinfo->pager_vma; + pager->memsize = pinfo->pager_size; + + /* Copy all cinfo structures into real capabilities */ + for (int i = 0; i < pinfo->ncaps; i++) { + cap = capability_create(); + + cap_info = &pinfo->caps[i]; + + cap->type = cap_info->type; + cap->access = cap_info->access; + cap->start = cap_info->start; + cap->end = cap_info->end; + cap->size = cap_info->size; + + cap_list_insert(cap, &pager->cap_list); + } + return 0; } -void create_capabilities(struct boot_resources *bootres, - struct kernel_container *kcont) +/* + * Copies container info from a given compact container descriptor to + * a real container + */ +int copy_container_info(struct container *c, struct container_info *cinfo) +{ + strncpy(c->name, cinfo->name, CONFIG_CONTAINER_NAMESIZE); + c->npagers = cinfo->npagers; + + /* Copy capabilities */ + for (int i = 0; i < c->npagers; i++) + copy_pager_info(&c->pager[i], &cinfo->pager[i]); + return 0; +} + +/* + * Create real containers from compile-time created cinfo structures + */ +void setup_containers(struct boot_resources *bootres, + struct kernel_container *kcont) +{ + struct container *container; + pgd_table_t *current_pgd; + + /* + * Move to real page tables, accounted by + * pgds and pmds provided from the caches + */ + current_pgd = realloc_page_tables(); + + /* Create all containers but leave pagers */ + for (int i = 0; i < bootres->nconts; i++) { + /* Allocate & init container */ + container = container_create(); + + /* Fill in its information */ + copy_container_info(container, &cinfo[i]); + + /* Add it to kernel container list */ + kcont_insert_container(container, kcont); + } + + /* Initialize pagers */ + container_init_pagers(kcont, current_pgd); +} + +void setup_capabilities(struct boot_resources *bootres, + struct kernel_container *kcont) { } /* - * Make sure to count boot pmds, and kernel capabilities - * created in boot memory. + * Given a structure size and numbers, it initializes a memory cache + * using free memory available from free kernel memory capabilities. + */ +struct mem_cache *init_resource_cache(int nstruct, int struct_size, + struct kernel_container *kcont, + int aligned) +{ + struct capability *cap; + unsigned long bufsize; + + /* In all unused physical memory regions */ + list_foreach_struct(cap, &kcont->physmem_free.caps, list) { + /* Get buffer size needed for cache */ + bufsize = mem_cache_bufsize((void *)__pfn_to_addr(cap->start), + struct_size, nstruct, + 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, + page_align_up(bufsize), + MAP_SVC_RW_FLAGS); + } else { + add_mapping(__pfn_to_addr(cap->start), + virtual, page_align_up(bufsize), + MAP_SVC_RW_FLAGS); + } + /* Unmap area from memcap */ + memcap_unmap_range(cap, &kcont->physmem_free, + cap->start, cap->start + + __pfn(page_align_up((bufsize)))); + + /* TODO: Manipulate memcaps for virtual range??? */ + + /* Initialize the cache */ + return mem_cache_init((void *)virtual, bufsize, + struct_size, 1); + } + } + return 0; +} + +/* + * TODO: Initialize ID cache * - * 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 + * Given a kernel container and the set of boot resources required, + * initializes all memory caches for allocations. Once caches are + * initialized, earlier boot allocations are migrated to caches. */ void init_resource_allocators(struct boot_resources *bootres, struct kernel_container *kcont) { + /* + * An extra space reserved for kernel + * in case all containers quit + */ + bootres->nspaces++; + /* Initialise PGD cache */ kcont->pgd_cache = init_resource_cache(bootres->nspaces, PGD_SIZE, kcont, 1); - /* Initialise PMD cache */ - kcont->pmd_cache = init_resource_cache(bootres->npmds, - PMD_SIZE, kcont, 1); - /* Initialise struct address_space cache */ - kcont->address_space_cache = + kcont->space_cache = init_resource_cache(bootres->nspaces, sizeof(struct address_space), kcont, 0); @@ -364,33 +465,122 @@ void init_resource_allocators(struct boot_resources *bootres, kcont->mutex_cache = init_resource_cache(bootres->nmutex, sizeof(struct mutex_queue), kcont, 0); - /* TODO: Initialize ID cache */ - - /* Initialise capability cache */ - kcont->cap_cache = init_resource_cache(bootres->ncaps, /* FIXME: Count correctly */ - sizeof(struct capability), - kcont, 0); /* Initialise container cache */ kcont->cont_cache = init_resource_cache(bootres->nconts, sizeof(struct container), kcont, 0); - /* Create system containers */ - create_containers(bootres, kcont); + /* + * Add all caps used by the kernel + two extra in case + * more memcaps get split after cap cache init below. + */ + bootres->ncaps += kcont->virtmem_used.ncaps + + kcont->virtmem_free.ncaps + + kcont->physmem_used.ncaps + + kcont->physmem_free.ncaps + 2; - /* Create capabilities */ - create_capabilities(bootres, kcont); + /* Initialise capability cache */ + kcont->cap_cache = init_resource_cache(bootres->ncaps, + sizeof(struct capability), + kcont, 0); + + /* Count boot pmds used so far and add them */ + bootres->npmds += pgd_count_pmds(&init_pgd); + + /* + * Calculate maximum possible pmds + * that may be used during this pmd + * cache init and add them. + */ + bootres->npmds += ((bootres->npmds * PMD_SIZE) / PMD_MAP_SIZE); + if (!is_aligned(bootres->npmds * PMD_SIZE, PMD_MAP_SIZE)) + bootres->npmds++; + + /* Initialise PMD cache */ + kcont->pmd_cache = init_resource_cache(bootres->npmds, + PMD_SIZE, kcont, 1); + + } + +/* + * Do all system accounting for a given capability info + * structure that belongs to a container, such as + * count its resource requirements, remove its portion + * from global kernel resource 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_MAPPOOL: + /* Speficies how many pmds can be mapped */ + bootres->npmds += cap->size; + break; + case CAP_RTYPE_CAPPOOL: + /* Specifies how many new caps can be created */ + bootres->ncaps += cap->size; + break; + + case CAP_RTYPE_VIRTMEM: + 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) + printk("FATAL: Memory capability range " + "overlaps with another one. " + "start=0x%lx, end=0x%lx\n", + __pfn_to_addr(cap->start), + __pfn_to_addr(cap->end)); + BUG(); + } + break; + case CAP_RTYPE_PHYSMEM: + if ((ret = memcap_unmap(&kcont->physmem_free, + cap->start, cap->end))) { + if (ret < 0) + printk("FATAL: Insufficient boot memory " + "to split capability\n"); + if (ret > 0) + printk("FATAL: Memory capability range " + "overlaps with another one. " + "start=0x%lx, end=0x%lx\n", + __pfn_to_addr(cap->start), + __pfn_to_addr(cap->end)); + BUG(); + } + break; + } + return ret; } -int init_boot_resources(struct boot_resources *bootres, - struct kernel_container *kcont) +/* + * Initializes the kernel container by describing both virtual + * and physical memory. Then traverses cap_info structures + * to figure out resource requirements of containers. + */ +int setup_boot_resources(struct boot_resources *bootres, + struct kernel_container *kcont) { struct cap_info *cap; init_kernel_container(kcont); /* Number of containers known at compile-time */ - bootres->nconts = TOTAL_CONTAINERS; + bootres->nconts = CONFIG_TOTAL_CONTAINERS; /* Traverse all containers */ for (int i = 0; i < bootres->nconts; i++) { @@ -409,29 +599,34 @@ int init_boot_resources(struct boot_resources *bootres, } } - /* TODO: Count all ids needed to represent all */ return 0; } /* * FIXME: Add error handling + * + * Initializes all system resources and handling of those + * resources. First descriptions are done by allocating from + * boot memory, once memory caches are initialized, boot + * memory allocations are migrated over to caches. */ int init_system_resources(struct kernel_container *kcont) { - struct boot_resources bootres; memset(&bootres, 0, sizeof(bootres)); - init_boot_resources(&bootres, kcont); + setup_boot_resources(&bootres, kcont); init_resource_allocators(&bootres, kcont); - free_boot_memory(&bootres, kcont); + /* Create system containers */ + setup_containers(&bootres, kcont); + + /* Create capabilities */ + setup_capabilities(&bootres, kcont); return 0; } - - diff --git a/src/generic/scheduler.c b/src/generic/scheduler.c index b8761be..9c5b909 100644 --- a/src/generic/scheduler.c +++ b/src/generic/scheduler.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -23,9 +25,8 @@ #include INC_ARCH(exception.h) -static struct runqueue sched_rq[SCHED_RQ_TOTAL]; -static struct runqueue *rq_runnable, *rq_expired; -static int prio_total; /* Total priority of all tasks */ +//static struct runqueue *rq_runnable, *rq_expired; +//static int prio_total; /* Total priority of all tasks */ /* This is incremented on each irq or voluntarily by preempt_disable() */ extern unsigned int current_irq_nest_count; @@ -35,14 +36,14 @@ static int voluntary_preempt = 0; void sched_lock_runqueues(void) { - spin_lock(&sched_rq[0].lock); - spin_lock(&sched_rq[1].lock); + spin_lock(&curcont->scheduler.sched_rq[0].lock); + spin_lock(&curcont->scheduler.sched_rq[1].lock); } void sched_unlock_runqueues(void) { - spin_unlock(&sched_rq[0].lock); - spin_unlock(&sched_rq[1].lock); + spin_unlock(&curcont->scheduler.sched_rq[0].lock); + spin_unlock(&curcont->scheduler.sched_rq[1].lock); } int preemptive() @@ -105,17 +106,21 @@ void idle_task(void) while(1); } -void sched_init_runqueues(void) +void sched_init_runqueue(struct runqueue *rq) { - for (int i = 0; i < SCHED_RQ_TOTAL; i++) { - memset(&sched_rq[i], 0, sizeof(struct runqueue)); - link_init(&sched_rq[i].task_list); - spin_lock_init(&sched_rq[i].lock); - } + memset(rq, 0, sizeof(struct runqueue)); + link_init(&rq->task_list); + spin_lock_init(&rq->lock); +} - rq_runnable = &sched_rq[0]; - rq_expired = &sched_rq[1]; - prio_total = 0; +void sched_init(struct scheduler *scheduler) +{ + for (int i = 0; i < SCHED_RQ_TOTAL; i++) + sched_init_runqueue(&scheduler->sched_rq[i]); + + scheduler->rq_runnable = &scheduler->sched_rq[0]; + scheduler->rq_expired = &scheduler->sched_rq[1]; + scheduler->prio_total = 0; } /* Swap runnable and expired runqueues. */ @@ -123,13 +128,14 @@ static void sched_rq_swap_runqueues(void) { struct runqueue *temp; - BUG_ON(list_empty(&rq_expired->task_list)); - BUG_ON(rq_expired->total == 0); + BUG_ON(list_empty(&curcont->scheduler.rq_expired->task_list)); + BUG_ON(curcont->scheduler.rq_expired->total == 0); /* Queues are swapped and expired list becomes runnable */ - temp = rq_runnable; - rq_runnable = rq_expired; - rq_expired = temp; + temp = curcont->scheduler.rq_runnable; + curcont->scheduler.rq_runnable = + curcont->scheduler.rq_expired; + curcont->scheduler.rq_expired = temp; } /* Set policy on where to add tasks in the runqueue */ @@ -202,7 +208,9 @@ void sched_resume_sync(struct ktcb *task) { BUG_ON(task == current); task->state = TASK_RUNNABLE; - sched_rq_add_task(task, rq_runnable, RQ_ADD_FRONT); + sched_rq_add_task(task, + curcont->scheduler.rq_runnable, + RQ_ADD_FRONT); schedule(); } @@ -215,7 +223,7 @@ void sched_resume_sync(struct ktcb *task) void sched_resume_async(struct ktcb *task) { task->state = TASK_RUNNABLE; - sched_rq_add_task(task, rq_runnable, RQ_ADD_FRONT); + sched_rq_add_task(task, curcont->scheduler.rq_runnable, RQ_ADD_FRONT); } /* @@ -228,8 +236,8 @@ void sched_suspend_sync(void) sched_rq_remove_task(current); current->state = TASK_INACTIVE; current->flags &= ~TASK_SUSPENDING; - prio_total -= current->priority; - BUG_ON(prio_total <= 0); + curcont->scheduler.prio_total -= current->priority; + BUG_ON(curcont->scheduler.prio_total <= 0); preempt_enable(); /* Async wake up any waiters */ @@ -243,8 +251,8 @@ void sched_suspend_async(void) sched_rq_remove_task(current); current->state = TASK_INACTIVE; current->flags &= ~TASK_SUSPENDING; - prio_total -= current->priority; - BUG_ON(prio_total <= 0); + curcont->scheduler.prio_total -= current->priority; + BUG_ON(curcont->scheduler.prio_total <= 0); /* This will make sure we yield soon */ preempt_enable(); @@ -338,9 +346,13 @@ void schedule() if (current->state == TASK_RUNNABLE) { sched_rq_remove_task(current); if (current->ticks_left) - sched_rq_add_task(current, rq_runnable, RQ_ADD_BEHIND); + sched_rq_add_task(current, + curcont->scheduler.rq_runnable, + RQ_ADD_BEHIND); else - sched_rq_add_task(current, rq_expired, RQ_ADD_BEHIND); + sched_rq_add_task(current, + curcont->scheduler.rq_expired, + RQ_ADD_BEHIND); } /* @@ -352,14 +364,16 @@ void schedule() wake_up_task(current, WAKEUP_INTERRUPT); /* Determine the next task to be run */ - if (rq_runnable->total > 0) { - next = link_to_struct(rq_runnable->task_list.next, - struct ktcb, rq_list); + if (curcont->scheduler.rq_runnable->total > 0) { + next = link_to_struct( + curcont->scheduler.rq_runnable->task_list.next, + struct ktcb, rq_list); } else { - if (rq_expired->total > 0) { + if (curcont->scheduler.rq_expired->total > 0) { sched_rq_swap_runqueues(); - next = link_to_struct(rq_runnable->task_list.next, - struct ktcb, rq_list); + next = link_to_struct( + curcont->scheduler.rq_runnable->task_list.next, + struct ktcb, rq_list); } else { idle_task(); } @@ -367,7 +381,7 @@ void schedule() /* New tasks affect runqueue total priority. */ if (next->flags & TASK_RESUMING) { - prio_total += next->priority; + curcont->scheduler.prio_total += next->priority; next->flags &= ~TASK_RESUMING; } @@ -378,7 +392,7 @@ void schedule() * becomes runnable rather than all at once. It is done * every runqueue swap */ - sched_recalc_ticks(next, prio_total); + sched_recalc_ticks(next, curcont->scheduler.prio_total); next->ticks_left = next->ticks_assigned; } @@ -392,25 +406,11 @@ void schedule() } /* - * Initialise pager as runnable for first-ever scheduling, - * and start the scheduler. + * Start the timer and switch to current task + * for first-ever scheduling. */ void scheduler_start() { - /* Initialise runqueues */ - sched_init_runqueues(); - - /* Initialise scheduler fields of pager */ - sched_init_task(current, TASK_PRIO_PAGER); - - /* Add task to runqueue first */ - sched_rq_add_task(current, rq_runnable, RQ_ADD_FRONT); - - /* Give it a kick-start tick and make runnable */ - current->ticks_left = 1; - current->state = TASK_RUNNABLE; - - /* Start the timer and switch */ timer_start(); switch_to_user(current); } diff --git a/src/generic/space.c b/src/generic/space.c index c14836c..8f9b0b1 100644 --- a/src/generic/space.c +++ b/src/generic/space.c @@ -8,6 +8,7 @@ #include INC_ARCH(exception.h) #include INC_SUBARCH(mm.h) #include +#include #include #include #include @@ -16,25 +17,23 @@ #include -static struct address_space_list address_space_list; - -void init_address_space_list(void) +void init_address_space_list(struct address_space_list *space_list) { - memset(&address_space_list, 0, sizeof(address_space_list)); + memset(space_list, 0, sizeof(*space_list)); - mutex_init(&address_space_list.ref_lock); - spin_lock_init(&address_space_list.list_lock); - link_init(&address_space_list.list); + mutex_init(&space_list->ref_lock); + spin_lock_init(&space_list->list_lock); + link_init(&space_list->list); } void address_space_reference_lock() { - mutex_lock(&address_space_list.ref_lock); + mutex_lock(&curcont->space_list.ref_lock); } void address_space_reference_unlock() { - mutex_unlock(&address_space_list.ref_lock); + mutex_unlock(&curcont->space_list.ref_lock); } void address_space_attach(struct ktcb *tcb, struct address_space *space) @@ -47,33 +46,33 @@ struct address_space *address_space_find(l4id_t spid) { struct address_space *space; - spin_lock(&address_space_list.list_lock); - list_foreach_struct(space, &address_space_list.list, list) { + spin_lock(&curcont->space_list.list_lock); + list_foreach_struct(space, &curcont->space_list.list, list) { if (space->spid == spid) { - spin_unlock(&address_space_list.list_lock); + spin_unlock(&curcont->space_list.list_lock); return space; } } - spin_unlock(&address_space_list.list_lock); + spin_unlock(&curcont->space_list.list_lock); return 0; } void address_space_add(struct address_space *space) { - spin_lock(&address_space_list.list_lock); + spin_lock(&curcont->space_list.list_lock); BUG_ON(!list_empty(&space->list)); - list_insert(&space->list, &address_space_list.list); - BUG_ON(!++address_space_list.count); - spin_unlock(&address_space_list.list_lock); + list_insert(&space->list, &curcont->space_list.list); + BUG_ON(!++curcont->space_list.count); + spin_unlock(&curcont->space_list.list_lock); } void address_space_remove(struct address_space *space) { - spin_lock(&address_space_list.list_lock); + spin_lock(&curcont->space_list.list_lock); BUG_ON(list_empty(&space->list)); - BUG_ON(--address_space_list.count < 0); + BUG_ON(--curcont->space_list.count < 0); list_remove_init(&space->list); - spin_unlock(&address_space_list.list_lock); + spin_unlock(&curcont->space_list.list_lock); } /* Assumes address space reflock is already held */ @@ -98,12 +97,12 @@ struct address_space *address_space_create(struct address_space *orig) int err; /* Allocate space structure */ - if (!(space = kzalloc(sizeof(*space)))) + if (!(space = alloc_space())) return PTR_ERR(-ENOMEM); /* Allocate pgd */ if (!(pgd = alloc_pgd())) { - kfree(space); + free_space(space); return PTR_ERR(-ENOMEM); } @@ -120,7 +119,7 @@ struct address_space *address_space_create(struct address_space *orig) * is not allowed since spid field is used to indicate the space to * copy from. */ - space->spid = id_new(space_id_pool); + space->spid = id_new(&kernel_container.space_ids); /* If an original space is supplied */ if (orig) { diff --git a/src/generic/tcb.c b/src/generic/tcb.c index c19464a..30c14ac 100644 --- a/src/generic/tcb.c +++ b/src/generic/tcb.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -20,17 +21,18 @@ struct id_pool *thread_id_pool; struct id_pool *space_id_pool; -static struct ktcb_list ktcb_list; - -void init_ktcb_list(void) +void init_ktcb_list(struct ktcb_list *ktcb_list) { - memset(&ktcb_list, 0, sizeof(ktcb_list)); - spin_lock_init(&ktcb_list.list_lock); - link_init(&ktcb_list.list); + memset(ktcb_list, 0, sizeof(*ktcb_list)); + spin_lock_init(&ktcb_list->list_lock); + link_init(&ktcb_list->list); } void tcb_init(struct ktcb *new) { + new->tid = id_new(&kernel_container.ktcb_ids); + new->tgid = new->tid; + link_init(&new->task_list); mutex_init(&new->thread_control_lock); @@ -46,7 +48,7 @@ void tcb_init(struct ktcb *new) struct ktcb *tcb_alloc(void) { - return zalloc_page(); + return alloc_ktcb(); } struct ktcb *tcb_alloc_init(void) @@ -93,21 +95,21 @@ void tcb_delete(struct ktcb *tcb) id_del(thread_id_pool, tcb->tid); /* Free the tcb */ - free_page(tcb); + free_ktcb(tcb); } struct ktcb *tcb_find_by_space(l4id_t spid) { struct ktcb *task; - spin_lock(&ktcb_list.list_lock); - list_foreach_struct(task, &ktcb_list.list, task_list) { + spin_lock(&curcont->ktcb_list.list_lock); + list_foreach_struct(task, &curcont->ktcb_list.list, task_list) { if (task->space->spid == spid) { - spin_unlock(&ktcb_list.list_lock); + spin_unlock(&curcont->ktcb_list.list_lock); return task; } } - spin_unlock(&ktcb_list.list_lock); + spin_unlock(&curcont->ktcb_list.list_lock); return 0; } @@ -115,33 +117,33 @@ struct ktcb *tcb_find(l4id_t tid) { struct ktcb *task; - spin_lock(&ktcb_list.list_lock); - list_foreach_struct(task, &ktcb_list.list, task_list) { + spin_lock(&curcont->ktcb_list.list_lock); + list_foreach_struct(task, &curcont->ktcb_list.list, task_list) { if (task->tid == tid) { - spin_unlock(&ktcb_list.list_lock); + spin_unlock(&curcont->ktcb_list.list_lock); return task; } } - spin_unlock(&ktcb_list.list_lock); + spin_unlock(&curcont->ktcb_list.list_lock); return 0; } void tcb_add(struct ktcb *new) { - spin_lock(&ktcb_list.list_lock); + spin_lock(&curcont->ktcb_list.list_lock); BUG_ON(!list_empty(&new->task_list)); - BUG_ON(!++ktcb_list.count); - list_insert(&new->task_list, &ktcb_list.list); - spin_unlock(&ktcb_list.list_lock); + BUG_ON(!++curcont->ktcb_list.count); + list_insert(&new->task_list, &curcont->ktcb_list.list); + spin_unlock(&curcont->ktcb_list.list_lock); } void tcb_remove(struct ktcb *new) { - spin_lock(&ktcb_list.list_lock); + spin_lock(&curcont->ktcb_list.list_lock); BUG_ON(list_empty(&new->task_list)); - BUG_ON(--ktcb_list.count < 0); + BUG_ON(--curcont->ktcb_list.count < 0); list_remove_init(&new->task_list); - spin_unlock(&ktcb_list.list_lock); + spin_unlock(&curcont->ktcb_list.list_lock); } /* Offsets for ktcb fields that are accessed from assembler */ diff --git a/src/glue/arm/init.c b/src/glue/arm/init.c index 4b493f7..be41361 100644 --- a/src/glue/arm/init.c +++ b/src/glue/arm/init.c @@ -15,6 +15,7 @@ #include #include #include +#include #include INC_ARCH(linker.h) #include INC_ARCH(asm.h) #include INC_ARCH(bootdesc.h) @@ -256,6 +257,7 @@ void switch_to_user(struct ktcb *task) jump(task); } +#if 0 /* * Initialize the pager in the system. * @@ -328,6 +330,7 @@ void init_pager(char *name, struct task_ids *ids) /* Scheduler initialises the very first task itself */ } +#endif void init_tasks() { @@ -341,9 +344,9 @@ void init_tasks() ids.tgid = ids.tid; /* Initialise the global task and address space lists */ - init_ktcb_list(); - init_address_space_list(); - init_mutex_queue_head(); + //init_ktcb_list(); + //init_address_space_list(); + //init_mutex_queue_head(); printk("%s: Initialized. Starting %s as pager.\n", __KERNELNAME__, __PAGERNAME__); @@ -351,7 +354,7 @@ void init_tasks() * This must come last so that other tasks can copy its pgd before it * modifies it for its own specifics. */ - init_pager(__PAGERNAME__, &ids); + // init_pager(__PAGERNAME__, &ids); } void start_kernel(void) @@ -381,20 +384,14 @@ void start_kernel(void) /* Move the initial pgd into a more convenient place, mapped as pages. */ // relocate_page_tables(); - /* Evaluate system resources and set up resource pools */ - init_system_resources(&kernel_container); - - /* Initialise memory allocators */ - paging_init(); - /* Initialise kip and map for userspace access */ kip_init(); /* Initialise system call page */ syscall_init(); - /* Setup inittask's ktcb and push it to scheduler runqueue */ - init_tasks(); + /* Evaluate system resources and set up resource pools */ + init_system_resources(&kernel_container); /* Start the scheduler with available tasks in the runqueue */ scheduler_start(); diff --git a/src/glue/arm/memory.c b/src/glue/arm/memory.c index b24c399..0220093 100644 --- a/src/glue/arm/memory.c +++ b/src/glue/arm/memory.c @@ -39,6 +39,12 @@ unsigned int space_flags_to_ptflags(unsigned int flags) BUG(); return 0; } +void task_init_registers(struct ktcb *task, unsigned long pc) +{ + task->context.pc = (u32)pc; + task->context.spsr = ARM_MODE_USR; +} + /* Sets up struct page array and the physical memory descriptor. */ void paging_init(void) { diff --git a/src/lib/memcache.c b/src/lib/memcache.c index 0ab3e1f..2682bb3 100644 --- a/src/lib/memcache.c +++ b/src/lib/memcache.c @@ -126,6 +126,7 @@ int mem_cache_bufsize(void *start, int struct_size, int nstructs, int aligned) return start_address - (unsigned long)start; } +#if 0 struct mem_cache *mem_cache_init(void *bufstart, int cache_size, int struct_size, @@ -214,5 +215,92 @@ struct mem_cache *mem_cache_init(void *bufstart, return cache; } +#endif + +struct mem_cache *mem_cache_init(void *bufstart, int cache_size, + int struct_size, unsigned int aligned) +{ + void *start; + struct mem_cache *cache; + unsigned int area_start; + unsigned int *bitmap; + int bwords, total, bsize; + + /* Align to nearest word boundary */ + start = (void *)align_up(bufstart, sizeof(int)); + cache_size -= (int)start - (int)bufstart; + cache = start; + + if ((struct_size < 0) || (cache_size < 0) || + ((unsigned long)start == ~(0))) { + printk("Invalid parameters.\n"); + return 0; + } + + /* + * The cache definition itself is at the beginning. + * Skipping it to get to start of free memory. i.e. the cache. + */ + area_start = (unsigned long)start + sizeof(struct mem_cache); + cache_size -= sizeof(struct mem_cache); + + if (cache_size < struct_size) { + printk("Cache too small for given struct_size\n"); + return 0; + } + + /* Get how much bitmap words occupy */ + total = cache_size / struct_size; + bwords = total >> 5; /* Divide by 32 */ + if (total & 0x1F) { /* Remainder? */ + bwords++; /* Add one more word for remainder */ + } + bsize = bwords * 4; + + /* Reduce bitmap bytes from cache size */ + cache_size -= bsize; + + /* Recalculate total - it may or may not have changed */ + total = cache_size / struct_size; + + /* This should always catch too small caches */ + if (total <= 0) { + printk("Cache too small for given struct_size\n"); + return 0; + } + if (cache_size <= 0) { + printk("Cache too small for given struct_size\n"); + return 0; + } + + bitmap = (unsigned int *)area_start; + area_start = (unsigned int)(bitmap + bwords); + + if (aligned) { + unsigned int addr = area_start; + unsigned int addr_aligned = align_up(area_start, struct_size); + unsigned int diff = addr_aligned - addr; + + BUG_ON(diff >= struct_size); + cache_size -= diff; + + /* Recalculate total */ + total = cache_size / struct_size; + area_start = addr_aligned; + } + + link_init(&cache->list); + cache->start = area_start; + cache->end = area_start + cache_size; + cache->total = total; + cache->free = cache->total; + cache->struct_size = struct_size; + cache->bitmap = bitmap; + + mutex_init(&cache->mutex); + memset(cache->bitmap, 0, bwords*SZ_WORD); + + return cache; +}