diff options
author | Marvin Borner | 2021-03-21 14:31:08 +0100 |
---|---|---|
committer | Marvin Borner | 2021-03-21 14:31:08 +0100 |
commit | 3d0c30e6697b2b6ae77a03adefa2a8b81ebe4d92 (patch) | |
tree | aaa59a9fa43ddf50dafcc89bf979fb20de351941 /kernel | |
parent | 09c3bdb186868204cb03d457244e05e12eb685d6 (diff) |
Cleaner shared memory implementation
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/features/mm.c | 188 | ||||
-rw-r--r-- | kernel/features/proc.c | 15 | ||||
-rw-r--r-- | kernel/features/syscall.c | 17 | ||||
-rw-r--r-- | kernel/inc/mm.h | 5 | ||||
-rw-r--r-- | kernel/inc/proc.h | 1 |
5 files changed, 117 insertions, 109 deletions
diff --git a/kernel/features/mm.c b/kernel/features/mm.c index 7e0d62a..d01c978 100644 --- a/kernel/features/mm.c +++ b/kernel/features/mm.c @@ -373,81 +373,106 @@ void *memory_alloc_identity(struct page_dir *dir, u32 flags) } } - return 0; + print("Memory allocation error!\n"); + return NULL; } -#define SHARED_MEMORY_MAX 128 -struct shared_memory { +// TODO: Free by address instead of vrange (combine with shmem map?) +void memory_free(struct page_dir *dir, struct memory_range vrange) +{ + assert(PAGE_ALIGNED(vrange.base) && PAGE_ALIGNED(vrange.size)); + + for (u32 i = 0; i < vrange.size / PAGE_SIZE; i++) { + u32 vaddr = vrange.base + i * PAGE_SIZE; + if (virtual_present(dir, vaddr)) { + struct memory_range page_prange = + memory_range(virtual_to_physical(dir, vaddr), PAGE_SIZE); + struct memory_range page_vrange = memory_range(vaddr, PAGE_SIZE); + physical_free(page_prange); + virtual_free(dir, page_vrange); + } + } +} + +void memory_map_identity(struct page_dir *dir, struct memory_range prange, u32 flags) +{ + assert(PAGE_ALIGNED(prange.base) && PAGE_ALIGNED(prange.size)); + + physical_set_used(prange); + virtual_map(dir, prange, prange.base, flags); + if (flags & MEMORY_CLEAR) + memset((void *)prange.base, 0, prange.size); +} + +struct memory_object { u32 id; u32 refs; - u8 used; + u8 shared; struct memory_range prange; }; -static struct shared_memory shmem[SHARED_MEMORY_MAX] = { 0 }; -res memory_shalloc(struct page_dir *dir, u32 size, u32 *id, u32 flags) +struct memory_proc_link { + struct memory_object *obj; + struct memory_range vrange; +}; +static struct list *memory_objects = NULL; +res memory_sys_alloc(struct page_dir *dir, u32 size, u32 *addr, u32 *id, u8 shared) { - if (!id || !memory_valid(id)) + if (!addr || !memory_valid(addr) || !id || !memory_valid(id)) return -EFAULT; - *id = 0; + size = PAGE_ALIGN_UP(size); - u32 slot = SHARED_MEMORY_MAX + 1; - - for (u32 i = 0; i < SHARED_MEMORY_MAX; i++) { - if (!shmem[i].used) { - slot = i; - break; - } - } - - if (slot >= SHARED_MEMORY_MAX) + u32 vaddr = (u32)memory_alloc(dir, size, MEMORY_CLEAR | MEMORY_USER); + if (!vaddr) return -ENOMEM; - void *addr = memory_alloc(dir, size, flags); - if (!addr) - return -ENOMEM; + struct memory_object *obj = zalloc(sizeof(*obj)); + obj->id = rdrand() + 1; + obj->prange = memory_range(virtual_to_physical(dir, vaddr), size); + obj->refs = 1; + obj->shared = shared; + list_add(memory_objects, obj); - // TODO: Verify that shid isn't used already - // TODO: Check for colliding prange - u32 shid = rdseed() + 1; - shmem[slot].id = shid; - shmem[slot].used = 1; - shmem[slot].prange = memory_range(virtual_to_physical(dir, (u32)addr), size); + struct memory_proc_link *link = zalloc(sizeof(*link)); + link->obj = obj; + link->vrange = memory_range(vaddr, size); + list_add(proc_current()->memory, link); - *id = shid; + *addr = vaddr; + *id = obj->id; return EOK; } -static struct shared_memory memory_shresolve_range(struct memory_range prange) -{ - for (u32 i = 0; i < SHARED_MEMORY_MAX; i++) { - if (!shmem[i].used) - continue; - - struct memory_range shrange = shmem[i].prange; - if (prange.base < shrange.base + shrange.size && - prange.base + prange.size > shrange.base) - return shmem[i]; - } - - return (struct shared_memory){ 0 }; -} - -static struct shared_memory memory_shresolve_id(u32 shid) +res memory_sys_free(struct page_dir *dir, u32 addr) { - for (u32 i = 0; i < SHARED_MEMORY_MAX; i++) { - if (!shmem[i].used) - continue; + if (!addr || !memory_valid((void *)addr)) + return -EFAULT; - if (shmem[i].id == shid) - return shmem[i]; + struct list *links = proc_current()->memory; + struct node *iterator = links->head; + while (iterator) { + struct memory_proc_link *link = iterator->data; + if (link->vrange.base == addr) { + virtual_free(dir, link->vrange); + link->obj->refs--; + if (link->obj->refs == 0) { + list_remove(memory_objects, + list_first_data(memory_objects, link->obj)); + physical_free(link->obj->prange); + free(link->obj); + } + list_remove(links, list_first_data(links, link)); + free(link); + return EOK; + } + iterator = iterator->next; } - return (struct shared_memory){ 0 }; + return -ENOENT; } -res memory_shaccess(struct page_dir *dir, u32 shid, u32 *addr, u32 *size) +res memory_sys_shaccess(struct page_dir *dir, u32 id, u32 *addr, u32 *size) { if (!addr || !memory_valid(addr) || !size || !memory_valid(size)) return -EFAULT; @@ -455,54 +480,31 @@ res memory_shaccess(struct page_dir *dir, u32 shid, u32 *addr, u32 *size) *addr = 0; *size = 0; - struct shared_memory sh = memory_shresolve_id(shid); - struct memory_range prange = sh.prange; - if (sh.used == 0 || prange.base == 0 || prange.size == 0) - return -ENOENT; + struct node *iterator = memory_objects->head; + while (iterator) { + struct memory_object *obj = iterator->data; + if (obj->id == id) { + if (!obj->shared) + return -EACCES; - sh.refs++; + obj->refs++; + struct memory_range shrange = + virtual_alloc(dir, obj->prange, MEMORY_CLEAR | MEMORY_USER); - struct memory_range shrange = virtual_alloc(dir, prange, MEMORY_CLEAR | MEMORY_USER); - *addr = shrange.base; - *size = shrange.size; + *addr = shrange.base; + *size = shrange.size; - return EOK; -} - -// TODO: Free by address instead of vrange (combine with shmem map?) -void memory_free(struct page_dir *dir, struct memory_range vrange) -{ - assert(PAGE_ALIGNED(vrange.base) && PAGE_ALIGNED(vrange.size)); - - struct memory_range prange = - memory_range(virtual_to_physical(dir, vrange.base), vrange.size); - struct shared_memory sh = memory_shresolve_range(prange); - if (sh.used != 0 && sh.refs > 1) { - panic("Freeing busy memory!\n"); - return; - } - /* sh.used = 0; */ + struct memory_proc_link *link = zalloc(sizeof(*link)); + link->obj = obj; + link->vrange = shrange; + list_add(proc_current()->memory, link); - for (u32 i = 0; i < vrange.size / PAGE_SIZE; i++) { - u32 vaddr = vrange.base + i * PAGE_SIZE; - if (virtual_present(dir, vaddr)) { - struct memory_range page_prange = - memory_range(virtual_to_physical(dir, vaddr), PAGE_SIZE); - struct memory_range page_vrange = memory_range(vaddr, PAGE_SIZE); - physical_free(page_prange); - virtual_free(dir, page_vrange); + return EOK; } + iterator = iterator->next; } -} -void memory_map_identity(struct page_dir *dir, struct memory_range prange, u32 flags) -{ - assert(PAGE_ALIGNED(prange.base) && PAGE_ALIGNED(prange.size)); - - physical_set_used(prange); - virtual_map(dir, prange, prange.base, flags); - if (flags & MEMORY_CLEAR) - memset((void *)prange.base, 0, prange.size); + return -ENOENT; } void memory_switch_dir(struct page_dir *dir) @@ -627,4 +629,6 @@ void memory_install(struct mem_info *mem_info, struct vid_info *vid_info) memory_switch_dir(&kernel_dir); paging_enable(); + + memory_objects = list_new(); } diff --git a/kernel/features/proc.c b/kernel/features/proc.c index 88c477f..624a835 100644 --- a/kernel/features/proc.c +++ b/kernel/features/proc.c @@ -140,15 +140,21 @@ void proc_exit(struct proc *proc, s32 status) iterator = iterator->next; } + assert(found); + if (memcmp(proc, current->data, sizeof(*proc)) == 0) current = NULL; - if (found) - printf("Process %s (%d) exited with status %d (%s)\n", - proc->name[0] ? proc->name : "UNKNOWN", proc->pid, status, - status == 0 ? "success" : "error"); + printf("Process %s (%d) exited with status %d (%s)\n", + proc->name[0] ? proc->name : "UNKNOWN", proc->pid, status, + status == 0 ? "success" : "error"); + stack_destroy(proc->messages); + list_destroy(proc->memory); // TODO: Decrement memory ref links virtual_destroy_dir(proc->page_dir); + + free(proc); + proc_clear_quantum(); // TODO: Add quantum to each process struct? // The caller has to yield itself @@ -250,6 +256,7 @@ struct proc *proc_make(enum proc_priv priv) proc->pid = current_pid++; proc->priv = priv; proc->messages = stack_new(); + proc->memory = list_new(); proc->state = PROC_RUNNING; if (priv == PROC_PRIV_KERNEL) diff --git a/kernel/features/syscall.c b/kernel/features/syscall.c index 48a5850..44caff8 100644 --- a/kernel/features/syscall.c +++ b/kernel/features/syscall.c @@ -29,22 +29,17 @@ static void syscall_handler(struct regs *r) break; } case SYS_ALLOC: { - r->eax = (u32)memory_alloc(proc_current()->page_dir, PAGE_ALIGN_UP(r->ebx), - MEMORY_CLEAR | MEMORY_USER); + r->eax = (u32)memory_sys_alloc(proc_current()->page_dir, r->ebx, (u32 *)r->ecx, + (u32 *)r->edx, (u8)r->esi); break; } - case SYS_SHALLOC: { - r->eax = memory_shalloc(proc_current()->page_dir, PAGE_ALIGN_UP(r->ebx), - (u32 *)r->ecx, MEMORY_CLEAR | MEMORY_USER); + case SYS_FREE: { + r->eax = memory_sys_free(proc_current()->page_dir, r->ebx); break; } case SYS_SHACCESS: { - r->eax = memory_shaccess(proc_current()->page_dir, r->ebx, (u32 *)r->ecx, - (u32 *)r->edx); - break; - } - case SYS_FREE: { - memory_free(proc_current()->page_dir, memory_range(r->ebx, r->ecx)); + r->eax = memory_sys_shaccess(proc_current()->page_dir, r->ebx, (u32 *)r->ecx, + (u32 *)r->edx); break; } case SYS_STAT: { diff --git a/kernel/inc/mm.h b/kernel/inc/mm.h index 5e49aa7..ae4e962 100644 --- a/kernel/inc/mm.h +++ b/kernel/inc/mm.h @@ -117,8 +117,9 @@ u8 memory_is_user(u32 addr); u8 memory_valid(const void *addr); // User interface -res memory_shalloc(struct page_dir *dir, u32 size, u32 *id, u32 flags); -res memory_shaccess(struct page_dir *dir, u32 shid, u32 *addr, u32 *size); +res memory_sys_alloc(struct page_dir *dir, u32 size, u32 *addr, u32 *id, u8 shared); +res memory_sys_free(struct page_dir *dir, u32 addr); +res memory_sys_shaccess(struct page_dir *dir, u32 id, u32 *addr, u32 *size); void memory_install(struct mem_info *mem_info, struct vid_info *vid_info); diff --git a/kernel/inc/proc.h b/kernel/inc/proc.h index c946116..eb972d3 100644 --- a/kernel/inc/proc.h +++ b/kernel/inc/proc.h @@ -56,6 +56,7 @@ struct proc { struct proc_wait wait; // dev_id enum proc_state state; struct stack *messages; + struct list *memory; }; void scheduler(struct regs *regs); |