Stack Growth

In project 2, the stack was a single page starting from the USER_STACK, and programs' executions were limited to this size. Now, if the stack grows past its current size, we allocate additional pages as necessary.

Allocate additional pages only if they "appear" to be stack accesses. Devise a heuristic that attempts to distinguish stack accesses from other accesses.

User programs are buggy if they write to the stack below the stack pointer, because typical real OSes may interrupt a process at any time to deliver a "signal," which modifies data on the stack. However, the x86-64 PUSH instruction checks access permissions before it adjusts the stack pointer, so it may cause a page fault 8 bytes below the stack pointer.

You will need to be able to obtain the current value of the user program's stack pointer. Within a system call or a page fault generated by a user program, you can retrieve it from the rsp member of the struct intr_frame passed to syscall_handler() or page_fault(), respectively. If you depend on page faults to detect invalid memory access, you will need to handle another case, where a page fault occurs in the kernel. Since the processor only saves the stack pointer when an exception causes a switch from user to kernel mode, reading rsp out of the struct intr_frame passed to page_fault() would yield an undefined value, not the user stack pointer. You will need to arrange another way, such as saving rsp into struct thread on the initial transition from user to kernel mode.

Implement stack growth functionalities. To implement this, you first modify vm_try_handle_fault in vm/vm.c to identify the stack growth. After identifying the stack growth, you should make a call to vm_stack_growth in vm/vm.c to grow the stack. Implement the vm_stack_growth.

bool vm_try_handle_fault (struct intr_frame *f, void *addr,
    bool user, bool write, bool not_present);

This function is called in page_fault in userprog/exception.c while handling the page fault exception. In this function, you need to check whether the page fault is a valid case for a stack growth or not. If you have confirmed that the fault can be handled with a stack growth, call vm_stack_growth with the faulted address.

void vm_stack_growth (void *addr);

Increases the stack size by allocating one or more anonymous pages so that addr is no longer a faulted address. Make sure you round down the addr to PGSIZE when handling the allocation.

Most Oses impose some absolute limit on stack size. Some OSes make the limit user-adjustable, e.g. with the ulimit command on many Unix systems. On many GNU/Linux systems, the default limit is 8 MB. For this project, you should limit the stack size to be 1MB at maximum.

Now, all the stack-growth test cases should be passed.

results matching ""

    No results matching ""