fixed a subtle bug in shm; added a bunch of utilities to test it

This commit is contained in:
Markus Schober 2012-02-10 22:13:31 -06:00
parent d5d302134c
commit 45903b204b
8 changed files with 250 additions and 16 deletions

View File

@ -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 */

View File

@ -368,3 +368,5 @@ typedef struct {
void handle_signal(process_t *, signal_t *);
#endif
void validate(void * ptr);

View File

@ -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 = &current_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

View File

@ -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
View 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
View 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
View 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);
}
}