fixed a subtle bug in shm; added a bunch of utilities to test it
This commit is contained in:
parent
d5d302134c
commit
45903b204b
@ -43,6 +43,7 @@ typedef struct image {
|
||||
uintptr_t stack; /* Process kernel stack */
|
||||
uintptr_t user_stack; /* User stack */
|
||||
uintptr_t start;
|
||||
uintptr_t shm_heap;
|
||||
} image_t;
|
||||
|
||||
/* Resizable descriptor table */
|
||||
|
@ -368,3 +368,5 @@ typedef struct {
|
||||
void handle_signal(process_t *, signal_t *);
|
||||
|
||||
#endif
|
||||
|
||||
void validate(void * ptr);
|
||||
|
@ -101,7 +101,9 @@ static shm_chunk_t * create_chunk (shm_node_t * parent, size_t size) {
|
||||
uint32_t index = first_frame();
|
||||
set_frame(index * 0x1000);
|
||||
chunk->frames[i] = index;
|
||||
// kprintf("Using frame 0x%x for chunk[%d] (name=%s)\n", index, i, parent->name);
|
||||
#if 0
|
||||
kprintf("Using frame #%d for chunk[%d] (name=%s)\n", index, i, parent->name);
|
||||
#endif
|
||||
}
|
||||
|
||||
return chunk;
|
||||
@ -113,7 +115,7 @@ static int release_chunk (shm_chunk_t * chunk) {
|
||||
|
||||
/* Does the chunk need to be freed? */
|
||||
if (chunk->ref_count < 1) {
|
||||
// kprintf("[kernel] [shm] Freeing chunk with name %s\n", chunk->parent->name);
|
||||
kprintf("[shm] Freeing chunk with name %s\n", chunk->parent->name);
|
||||
|
||||
/* First, free the frames used by this chunk */
|
||||
for (uint32_t i = 0; i < chunk->num_frames; i++) {
|
||||
@ -135,19 +137,18 @@ static int release_chunk (shm_chunk_t * chunk) {
|
||||
|
||||
/* Mapping and Unmapping */
|
||||
|
||||
static uintptr_t proc_sbrk(int size, process_t * proc) {
|
||||
uintptr_t ret = proc->image.heap;
|
||||
uintptr_t i_ret = ret;
|
||||
while (ret % 0x1000) {
|
||||
ret++;
|
||||
static uintptr_t proc_sbrk(uint32_t num_pages, process_t * proc) {
|
||||
uintptr_t initial = proc->image.shm_heap;
|
||||
assert(!(initial & 0xFFF) && "shm_heap not page-aligned!");
|
||||
|
||||
if (initial % 0x1000) {
|
||||
initial += 0x1000 - (initial % 0x1000);
|
||||
proc->image.shm_heap = initial;
|
||||
}
|
||||
proc->image.heap += (ret - i_ret) + size;
|
||||
while (proc->image.heap > proc->image.heap_actual) {
|
||||
proc->image.heap_actual += 0x1000;
|
||||
assert(proc->image.heap_actual % 0x1000 == 0);
|
||||
alloc_frame(get_page(proc->image.heap_actual, 1, current_directory), 0, 1);
|
||||
}
|
||||
return ret;
|
||||
proc->image.shm_heap += num_pages * 0x1000;
|
||||
assert(!(proc->image.shm_heap & 0xFFF) && "math is wrong, dumbass");
|
||||
|
||||
return initial;
|
||||
}
|
||||
|
||||
static void * map_in (shm_chunk_t * chunk, process_t * proc) {
|
||||
@ -164,12 +165,16 @@ static void * map_in (shm_chunk_t * chunk, process_t * proc) {
|
||||
uintptr_t new_vpage = proc_sbrk(1, proc);
|
||||
assert(new_vpage % 0x1000 == 0);
|
||||
|
||||
page_t * page = get_page(new_vpage, 0, proc->thread.page_directory);
|
||||
page_t * page = get_page(new_vpage, 1, proc->thread.page_directory);
|
||||
assert(page && "Page not allocated by sys_sbrk?");
|
||||
|
||||
alloc_frame(page, 0, 1);
|
||||
page->frame = chunk->frames[i];
|
||||
mapping->vaddrs[i] = new_vpage;
|
||||
// kprintf("[kernel] [shm] mapping vaddr 0x%x --> %x\n", new_vpage, page->frame);
|
||||
|
||||
#if 0
|
||||
kprintf("[kernel] [shm] mapping vaddr 0x%x --> #%d\n", new_vpage, page->frame);
|
||||
#endif
|
||||
}
|
||||
|
||||
list_insert(proc->shm_mappings, mapping);
|
||||
@ -182,6 +187,7 @@ static void * map_in (shm_chunk_t * chunk, process_t * proc) {
|
||||
|
||||
|
||||
void * shm_obtain (char * path, size_t size) {
|
||||
validate(path);
|
||||
spin_lock(&bsl);
|
||||
process_t * proc = (process_t *)current_process;
|
||||
|
||||
@ -279,3 +285,50 @@ void shm_release_all (process_t * proc) {
|
||||
|
||||
spin_unlock(&bsl);
|
||||
}
|
||||
|
||||
|
||||
/* XXX: oh god don't use this */
|
||||
|
||||
#if 0
|
||||
void shm_debug_frame (uintptr_t vaddr) {
|
||||
uintptr_t vframe = vaddr / 0x1000;
|
||||
uintptr_t pframe, paddr;
|
||||
|
||||
kprintf("[kernel] Inspecting user page 0x%x\n", vframe * 0x1000);
|
||||
|
||||
uintptr_t table_index = vframe / 1024;
|
||||
|
||||
if (!current_directory->tables[table_index]) {
|
||||
kprintf("[kernel] Page does not exist!\n");
|
||||
return;
|
||||
} else {
|
||||
|
||||
// Where is the vaddr pointing to?
|
||||
page_t * page = ¤t_directory->tables[table_index]->pages[vframe % 1024];
|
||||
pframe = page->frame;
|
||||
paddr = pframe * 0x1000;
|
||||
|
||||
kprintf("[kernel] Refers to physical frame #%d (present=%d rw=%d user=%d accessed=%d dirty=%d)\n", page->frame, page->present, page->rw, page->user, page->accessed, page->dirty);
|
||||
|
||||
#if 0
|
||||
// Map the page into kernel memory. Oh god.
|
||||
assert((heap_end % 0x1000 == 0) && "Kernel heap not page-aligned!");
|
||||
|
||||
uintptr_t address = heap_end;
|
||||
heap_end += 0x1000;
|
||||
page_t * kpage = get_page(address, 1, kernel_directory);
|
||||
kpage->frame = pframe;
|
||||
alloc_frame(kpage, 0, 1);
|
||||
#endif
|
||||
|
||||
// Read it out...
|
||||
#if 0
|
||||
kprintf("[kernel] Data in frame: ");
|
||||
for (int i = 0; i < 0x1000; i++) {
|
||||
kprintf("%c", ((char *)vaddr)[i]);
|
||||
}
|
||||
kprintf("\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -171,6 +171,7 @@ process_t * spawn_init() {
|
||||
init->image.stack = initial_esp + 1;
|
||||
init->image.user_stack = 0;
|
||||
init->image.size = 0;
|
||||
init->image.shm_heap = 0x20000000; /* Yeah, a bit of a hack. */
|
||||
|
||||
/* Process is not finished */
|
||||
init->finished = 0;
|
||||
@ -242,6 +243,7 @@ process_t * spawn_process(volatile process_t * parent) {
|
||||
proc->image.size = parent->image.size;
|
||||
proc->image.stack = kvmalloc(KERNEL_STACK_SIZE) + KERNEL_STACK_SIZE;
|
||||
proc->image.user_stack = parent->image.user_stack;
|
||||
proc->image.shm_heap = 0x20000000; /* Yeah, a bit of a hack. */
|
||||
|
||||
assert(proc->image.stack && "Failed to allocate kernel stack for new process.");
|
||||
|
||||
|
91
userspace/shmcrash.c
Normal file
91
userspace/shmcrash.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
DEFN_SYSCALL2(shm_obtain, 35, char *, int)
|
||||
DEFN_SYSCALL1(shm_release, 36, char *)
|
||||
|
||||
|
||||
int main_server(volatile char *shm);
|
||||
int main_client(volatile char *shm);
|
||||
|
||||
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: expected argument\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("(This should fork and the child process (but not the parent) should segfault)\n");
|
||||
|
||||
volatile char * shm = (char *)syscall_shm_obtain(argv[1], 27);
|
||||
if (shm == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pid = getpid();
|
||||
uint32_t f = fork();
|
||||
if (getpid() != pid) {
|
||||
// Child: client
|
||||
return main_client(shm);
|
||||
} else {
|
||||
// Parent: server
|
||||
return main_server(shm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main_server(volatile char *shm) {
|
||||
char c;
|
||||
volatile char *s;
|
||||
|
||||
/*
|
||||
* Now put some things into the memory for the
|
||||
* other process to read.
|
||||
*/
|
||||
s = shm;
|
||||
|
||||
for (c = 'a'; c <= 'z'; c++)
|
||||
*s++ = c;
|
||||
*s = '\0';
|
||||
|
||||
|
||||
/*
|
||||
* Finally, we wait until the other process
|
||||
* changes the first character of our memory
|
||||
* to '*', indicating that it has read what
|
||||
* we put there.
|
||||
*/
|
||||
while (*shm != '*') {}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main_client(volatile char *shm) {
|
||||
int shmid;
|
||||
volatile char *s;
|
||||
|
||||
/*
|
||||
* Now read what the server put in the memory.
|
||||
*/
|
||||
while (*shm != 'a');
|
||||
for (s = shm; *s != '\0'; s++)
|
||||
printf("%c", *s);
|
||||
printf("\n");
|
||||
|
||||
/*
|
||||
* Finally, change the first character of the
|
||||
* segment to '*', indicating we have read
|
||||
* the segment.
|
||||
*/
|
||||
*shm = '*';
|
||||
|
||||
return 0;
|
||||
}
|
30
userspace/shmcrash2.c
Normal file
30
userspace/shmcrash2.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
DEFN_SYSCALL2(shm_obtain, 35, char *, int)
|
||||
DEFN_SYSCALL1(shm_release, 36, char *)
|
||||
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: expected argument\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("(this should not crash; but the kernel should free the shm block)\n");
|
||||
|
||||
volatile char * shm = (char *)syscall_shm_obtain(argv[1], 0x1000);
|
||||
if (shm == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
char * args[] = {"/bin/echo", "exec'd to echo\n", NULL};
|
||||
execve(args[0], args, NULL);
|
||||
|
||||
return 5;
|
||||
}
|
55
userspace/shmtest2.c
Normal file
55
userspace/shmtest2.c
Normal file
@ -0,0 +1,55 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
DEFN_SYSCALL2(shm_obtain, 35, char *, int)
|
||||
|
||||
#define KEY "shm_test3.mem"
|
||||
#define MAGIC 111
|
||||
|
||||
int client_proc(uint32_t size) {
|
||||
volatile unsigned char * mem = (volatile unsigned char *)syscall_shm_obtain(KEY, size);
|
||||
|
||||
while (mem[0] != MAGIC) {}
|
||||
mem[0] = (uint8_t)(MAGIC + 1);
|
||||
|
||||
for (uint32_t i = 1; i < size; i++) {
|
||||
if (mem[i] != (unsigned char)i) {
|
||||
printf("Verification at 0x%x (i=%d) failed; expected=%d got=%d\n", &mem[i], i, (uint8_t)i, mem[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Client: verification passed. Exiting.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int server_proc(uint32_t size) {
|
||||
volatile unsigned char * mem = (volatile unsigned char *)syscall_shm_obtain(KEY, size);
|
||||
|
||||
for (uint32_t i = 1; i < size; i++) {
|
||||
mem[i] = (unsigned char)i;
|
||||
}
|
||||
mem[0] = MAGIC;
|
||||
printf("Server: Written memory space.\n");
|
||||
|
||||
while (mem[0] == MAGIC) {}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
if (argc < 2) {
|
||||
printf("usage: %s [size]\n", argv[0]);
|
||||
}
|
||||
|
||||
int size = atoi(argv[1]);
|
||||
|
||||
if (!fork()) {
|
||||
return server_proc(size);
|
||||
} else {
|
||||
return client_proc(size);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user