Code: Select all
void move_stack(void *new_stack_start, u32int size) {
u32int i;
// Allocate space
for (i = (u32int) new_stack_start; i >= ((u32int) new_stack_start - size); i -= 0x1000) {
alloc_frame(get_page(i, 1, current_directory), 0, 1);
}
// Flush TLB (?)
u32int pd_addr;
asm volatile ("mov %%cr3, %0" : "=r" (pd_addr));
asm volatile ("mov %0, %%cr3" : : "r" (pd_addr));
// Get the old stack/base pointers
u32int old_esp, old_ebp;
asm volatile ("mov %%esp, %0" : "=r" (old_esp));
asm volatile ("mov %%ebp, %0" : "=r" (old_ebp));
// Get stack offset
u32int off = (u32int) new_stack_start - initial_esp;
// New stack/base pointers
u32int new_esp = old_esp + off;
u32int new_ebp = old_ebp + off;
memcpy((void *) new_esp, (void *) old_esp, initial_esp - old_esp); // here it faults
/* Here we have to look for pushed EBP values to change them to point to the new stack.
This algorithm assumes that any value that points into the old stack is a pushed EBP,
meaning that it'll mess up any local variables or function parameters that are in
that range.
*/
for (i = (u32int) new_stack_start; i > ((u32int) new_stack_start - size); i -= 4) {
u32int tmp = *(u32int*)i;
if ((old_esp < tmp) && (tmp < initial_esp)) {
tmp += off;
u32int *tmp2 = (u32int *)i;
*tmp2 = tmp;
}
}
asm volatile ("mov %0, %%esp" : : "r" (new_esp));
asm volatile ("mov %0, %%ebp" : : "r" (new_ebp));
}