Commit e208d597 authored by An N Tran's avatar An N Tran :speech_balloon:
Browse files

Add grading scripts

parent f671ab23
No related merge requests found
Showing with 269 additions and 7 deletions
+269 -7
...@@ -38,6 +38,8 @@ ifneq ($(NOGDB),1) ...@@ -38,6 +38,8 @@ ifneq ($(NOGDB),1)
QEMUGDB ?= -gdb tcp::12949 QEMUGDB ?= -gdb tcp::12949
endif endif
NO_SLOWDOWN = 0
TICK_LIMIT = 0
# Sets of object files # Sets of object files
...@@ -62,7 +64,7 @@ PROCESS_LINKER_FILES = build/process.ld ...@@ -62,7 +64,7 @@ PROCESS_LINKER_FILES = build/process.ld
# How to make object files # How to make object files
# #
$(OBJDIR)/kernel.ko: kernel.c $(KERNELBUILDSTAMPS) $(OBJDIR)/kernel.ko: kernel.c $(KERNELBUILDSTAMPS)
$(call cxxcompile,$(KERNELCXXFLAGS) -O1 -DWEENSYOS_KERNEL -c $< -o $@,COMPILE $<) $(call cxxcompile,$(KERNELCXXFLAGS) -DTICK_LIMIT=$(TICK_LIMIT) -O1 -DWEENSYOS_KERNEL -c $< -o $@,COMPILE $<)
$(OBJDIR)/util.ko: util.c $(KERNELBUILDSTAMPS) $(OBJDIR)/util.ko: util.c $(KERNELBUILDSTAMPS)
$(call cxxcompile,$(KERNELCXXFLAGS) -O1 -DWEENSYOS_KERNEL -c $< -o $@,COMPILE $<) $(call cxxcompile,$(KERNELCXXFLAGS) -O1 -DWEENSYOS_KERNEL -c $< -o $@,COMPILE $<)
...@@ -81,7 +83,7 @@ $(OBJDIR)/bootentry.o: $(OBJDIR)/%.o: \ ...@@ -81,7 +83,7 @@ $(OBJDIR)/bootentry.o: $(OBJDIR)/%.o: \
$(call assemble,-Os -fomit-frame-pointer -c $< -o $@,ASSEMBLE $<) $(call assemble,-Os -fomit-frame-pointer -c $< -o $@,ASSEMBLE $<)
$(OBJDIR)/%.uo: %.cc $(BUILDSTAMPS) $(OBJDIR)/%.uo: %.cc $(BUILDSTAMPS)
$(call cxxcompile,$(CXXFLAGS) -O1 -DWEENSYOS_PROCESS -c $< -o $@,COMPILE $<) $(call cxxcompile,$(CXXFLAGS) -DNO_SLOWDOWN=$(NO_SLOWDOWN) -O1 -DWEENSYOS_PROCESS -c $< -o $@,COMPILE $<)
$(OBJDIR)/%.uo: %.S $(OBJDIR)/u-asm.h $(BUILDSTAMPS) $(OBJDIR)/%.uo: %.S $(OBJDIR)/u-asm.h $(BUILDSTAMPS)
$(call assemble,-O2 -c $< -o $@,ASSEMBLE $<) $(call assemble,-O2 -c $< -o $@,ASSEMBLE $<)
...@@ -169,6 +171,8 @@ run-gdb-report: ...@@ -169,6 +171,8 @@ run-gdb-report:
@if test "$(QEMUGDB)" = "-gdb tcp::12949"; then echo '* Run `gdb -x build/weensyos.gdb` to connect gdb to qemu.' 1>&2; fi @if test "$(QEMUGDB)" = "-gdb tcp::12949"; then echo '* Run `gdb -x build/weensyos.gdb` to connect gdb to qemu.' 1>&2; fi
run-graphic: $(QEMUIMAGEFILES) check-qemu run-gdb-report run-graphic: $(QEMUIMAGEFILES) check-qemu run-gdb-report
$(call run,$(QEMU_PRELOAD) $(QEMU) $(QEMUOPT) $(QEMUGDB) $(QEMUIMG),QEMU $<) $(call run,$(QEMU_PRELOAD) $(QEMU) $(QEMUOPT) $(QEMUGDB) $(QEMUIMG),QEMU $<)
run-nographic: $(QEMUIMAGEFILES) check-qemu
$(call run,$(QEMU_PRELOAD) $(QEMU) $(QEMUOPT) -nographic $(QEMUIMG),QEMU $<)
run-console: $(QEMUIMAGEFILES) check-qemu-console run-gdb-report run-console: $(QEMUIMAGEFILES) check-qemu-console run-gdb-report
$(call run,$(QEMU) $(QEMUOPT) -curses $(QEMUGDB) $(QEMUIMG),QEMU $<) $(call run,$(QEMU) $(QEMUOPT) -curses $(QEMUGDB) $(QEMUIMG),QEMU $<)
run-monitor: $(QEMUIMAGEFILES) check-qemu run-monitor: $(QEMUIMAGEFILES) check-qemu
...@@ -182,6 +186,7 @@ run-gdb-console: $(QEMUIMAGEFILES) check-qemu-console ...@@ -182,6 +186,7 @@ run-gdb-console: $(QEMUIMAGEFILES) check-qemu-console
$(call run,$(QEMU) $(QEMUOPT) -curses -gdb tcp::12949 $(QEMUIMG),QEMU $<) $(call run,$(QEMU) $(QEMUOPT) -curses -gdb tcp::12949 $(QEMUIMG),QEMU $<)
run-$(RUNSUFFIX): run run-$(RUNSUFFIX): run
run-nographic-$(RUNSUFFIX): run-nographic
run-graphic-$(RUNSUFFIX): run-graphic run-graphic-$(RUNSUFFIX): run-graphic
run-console-$(RUNSUFFIX): run-console run-console-$(RUNSUFFIX): run-console
run-monitor-$(RUNSUFFIX): run-monitor run-monitor-$(RUNSUFFIX): run-monitor
...@@ -189,6 +194,16 @@ run-gdb-$(RUNSUFFIX): run-gdb ...@@ -189,6 +194,16 @@ run-gdb-$(RUNSUFFIX): run-gdb
run-gdb-graphic-$(RUNSUFFIX): run-gdb-graphic run-gdb-graphic-$(RUNSUFFIX): run-gdb-graphic
run-gdb-console-$(RUNSUFFIX): run-gdb-console run-gdb-console-$(RUNSUFFIX): run-gdb-console
# Tests
test1: clean
$(call run,rm log.txt > /dev/null 2>&1;$(MAKE) run-nographic TICK_LIMIT=500 NO_SLOWDOWN=1 > /dev/null 2>&1; python3 test_script.py -s 1)
test2: clean
$(call run,rm log.txt > /dev/null 2>&1;$(MAKE) run-nographic TICK_LIMIT=500 NO_SLOWDOWN=1 > /dev/null 2>&1; python3 test_script.py -s 2)
test3: clean
$(call run,rm log.txt > /dev/null 2>&1;$(MAKE) run-nographic TICK_LIMIT=500 NO_SLOWDOWN=1 > /dev/null 2>&1; python3 test_script.py -s 3)
test4: clean
$(call run,rm log.txt > /dev/null 2>&1;$(MAKE) run-nographic TICK_LIMIT=500 NO_SLOWDOWN=1 > /dev/null 2>&1; python3 test_script.py -s 4)
# Kill all my qemus # Kill all my qemus
kill: kill:
-killall -u $$(whoami) $(QEMU) -killall -u $$(whoami) $(QEMU)
......
#include "kernel.hh" #include "kernel.hh"
#include "k-vmiter.hh" #include "k-vmiter.hh"
#include "util.h"
// k-memviewer.cc // k-memviewer.cc
// //
...@@ -134,6 +135,8 @@ void memusage::page_error(uintptr_t pa, const char* desc, int pid) const { ...@@ -134,6 +135,8 @@ void memusage::page_error(uintptr_t pa, const char* desc, int pid) const {
log_printf(fmt, pa, desc, pid); log_printf(fmt, pa, desc, pid);
} }
static memusage global_mu;
uint16_t memusage::symbol_at(uintptr_t pa) const { uint16_t memusage::symbol_at(uintptr_t pa) const {
bool is_reserved = reserved_physical_address(pa); bool is_reserved = reserved_physical_address(pa);
bool is_kernel = !is_reserved && !allocatable_physical_address(pa); bool is_kernel = !is_reserved && !allocatable_physical_address(pa);
...@@ -226,14 +229,12 @@ static void console_memviewer_virtual(memusage& mu, proc* vmp) { ...@@ -226,14 +229,12 @@ static void console_memviewer_virtual(memusage& mu, proc* vmp) {
} }
} }
void console_memviewer(proc* vmp) { void console_memviewer(proc* vmp) {
// Process 0 must never be used. // Process 0 must never be used.
assert(ptable[0].state == P_FREE); assert(ptable[0].state == P_FREE);
// track physical memory // track physical memory
static memusage mu; global_mu.refresh();
mu.refresh();
// print physical memory // print physical memory
console_printf(CPOS(0, 32), 0x0F00, "PHYSICAL MEMORY\n"); console_printf(CPOS(0, 32), 0x0F00, "PHYSICAL MEMORY\n");
...@@ -242,11 +243,49 @@ void console_memviewer(proc* vmp) { ...@@ -242,11 +243,49 @@ void console_memviewer(proc* vmp) {
if (pn % 64 == 0) { if (pn % 64 == 0) {
console_printf(CPOS(1 + pn/64, 3), 0x0F00, "0x%06X ", pn << 12); console_printf(CPOS(1 + pn/64, 3), 0x0F00, "0x%06X ", pn << 12);
} }
console[CPOS(1 + pn/64, 12 + pn%64)] = mu.symbol_at(pn * PAGESIZE); console[CPOS(1 + pn/64, 12 + pn%64)] = global_mu.symbol_at(pn * PAGESIZE);
} }
// print virtual memory // print virtual memory
if (vmp) { if (vmp) {
console_memviewer_virtual(mu, vmp); console_memviewer_virtual(global_mu, vmp);
}
}
// Dumps to the log file same information as memshow_physical
void memdump_physical(void) {
log_printf("PHYSICAL MEMORY DUMP\n");
for (uintptr_t pa = 0; pa < MEMSIZE_PHYSICAL; pa += PAGESIZE) {
log_printf("%c", global_mu.symbol_at(pa));
} }
log_printf("\n");
} }
void memdump_virtual(memusage& mu, proc* vmp) {
log_printf("VIRTUAL MEMORY FOR PROCESS %u\n", vmp->pid);
for (vmiter it(vmp);
it.va() < memusage::max_view_va;
it += PAGESIZE) {
if (!it.present()) {
log_printf("._");
} else {
log_printf("%c", global_mu.symbol_at(it.pa()));
if (it.user()) {
log_printf("u");
} else {
log_printf("_");
}
}
}
log_printf("\n");
}
void memdump_virtual_all() {
for (uint32_t pid = 0; pid < NPROC; pid++) {
if (ptable[pid].state != P_FREE) {
memdump_virtual(global_mu, &ptable[pid]);
}
}
}
\ No newline at end of file
...@@ -47,6 +47,9 @@ void exception(regstate* regs); ...@@ -47,6 +47,9 @@ void exception(regstate* regs);
uintptr_t syscall(regstate* regs); uintptr_t syscall(regstate* regs);
void memshow(); void memshow();
extern void memdump_virtual(x86_64_pagetable* pagetable, const char* name);
extern void memdump_virtual_all(void);
extern void memdump_physical(void);
// kernel_start(command) // kernel_start(command)
// Initialize the hardware and processes and start running. The `command` // Initialize the hardware and processes and start running. The `command`
...@@ -203,6 +206,12 @@ void exception(regstate* regs) { ...@@ -203,6 +206,12 @@ void exception(regstate* regs) {
console_show_cursor(cursorpos); console_show_cursor(cursorpos);
if (regs->reg_intno != INT_PF || (regs->reg_errcode & PFERR_USER)) { if (regs->reg_intno != INT_PF || (regs->reg_errcode & PFERR_USER)) {
memshow(); memshow();
if (TICK_LIMIT != 0 && ticks >= TICK_LIMIT) {
memdump_physical();
memdump_virtual_all();
poweroff();
}
} }
// If Control-C was typed, exit the virtual machine. // If Control-C was typed, exit the virtual machine.
......
...@@ -25,7 +25,11 @@ void process_main() { ...@@ -25,7 +25,11 @@ void process_main() {
// Allocate heap pages until (1) hit the stack (out of address space) // Allocate heap pages until (1) hit the stack (out of address space)
// or (2) allocation fails (out of physical memory). // or (2) allocation fails (out of physical memory).
while (true) { while (true) {
#if !NO_SLOWDOWN
if (rand(0, ALLOC_SLOWDOWN - 1) < p) { if (rand(0, ALLOC_SLOWDOWN - 1) < p) {
#else
for (int i = 0; i < p; i++) {
#endif
if (heap_top == stack_bottom if (heap_top == stack_bottom
|| sys_page_alloc(heap_top) < 0) { || sys_page_alloc(heap_top) < 0) {
break; break;
......
...@@ -56,7 +56,11 @@ void process_main() { ...@@ -56,7 +56,11 @@ void process_main() {
stack_bottom = (uint8_t*) round_down((uintptr_t) rdrsp() - 1, PAGESIZE); stack_bottom = (uint8_t*) round_down((uintptr_t) rdrsp() - 1, PAGESIZE);
while (true) { while (true) {
#if !NO_SLOWDOWN
if (rand(0, ALLOC_SLOWDOWN - 1) < p) { if (rand(0, ALLOC_SLOWDOWN - 1) < p) {
#else
for (int i = 0; i < p; i++) {
#endif
if (heap_top == stack_bottom if (heap_top == stack_bottom
|| sys_page_alloc(heap_top) < 0) { || sys_page_alloc(heap_top) < 0) {
break; break;
......
from collections import namedtuple, defaultdict
import argparse
import os.path
parser = argparse.ArgumentParser(description="Grade Project04a")
parser.add_argument("-s", "--stage", type=int, choices=[1,2,3,4], required=True, help="Grade this stage")
args = parser.parse_args()
KERNEL_BOUNDARY = 256
PM_SIZE = 512
VM_SIZE = 768
if not os.path.isfile("log.txt"):
print("No output from run, did code compile?")
exit(1)
def print_page_info(pg, owner, usable):
print(f" Page #: {pg} | Owner: {owner} | User-accessible: {usable}")
def parse_physical_dump(s: str):
return [a for a in s]
def parse_virtual_dump(s: str) :
return [(a, b == "u") for (a, b) in zip(s[::2], s[1::2])]
def confirm_physical_exhausted(pm):
# Checks that physical address space is exhausted
if any(filter(lambda x: x == ".", pm)):
print("FAIL: The entirety of physical memory needs to be allocated")
print(" This error was thrown because your physical memory")
print(" not allocate physical frames from 0x0 to 0x200000,")
print(" which it should if stage 4 was correctly implemented.")
exit(1)
def confirm_virtual_allocation(pm):
# Checks that physical address space is being used up for virtual allocation
for i in range(0, KERNEL_BOUNDARY + 64 * 2 + 7):
if pm[i] == ".":
print("FAIL: Virtual allocation is not allocating enough")
print(" This error was thrown because your physical memory")
print(" not allocate physical frames from 0x0 to 0x187000,")
print(" which it should if stage 3 was correctly implemented.")
exit(1)
def confirm_kernel_isolation(vm):
# Checks that all of the virtual address spaces have it such that
# kernel"s addresses are not accessible from any of the processes
# (except for the CGA block). Also check that the CGA page is accessible
# from all processes.
for i, (p, u) in enumerate(vm):
if i == 184:
if p != "C" or not u:
print("FAIL: Console memory must be accessible by user process")
print(" This error was thrown because your virtual address")
print(" block at 0xB8000 did not point to the console or")
print(" it was not mapped as usable by the user process.")
print_page_info(i, p, u)
exit(1)
elif i < KERNEL_BOUNDARY and u:
print("FAIL: Kernel memory must not be accessible by user process")
print(" This error was thrown because your virtual address")
print(" blocks below the kernel boundary was marked as accessible")
print(" by the user process.")
print_page_info(i, p, u)
exit(1)
elif p == "." and u:
print("FAIL: Unmapped page is accessible")
print_page_info(i, p, u)
exit(1)
def confirm_process_isolation(vm, pid):
# Check that beyond the kernel memory map, processes only pages mapped
# for itself.
for i in range(KERNEL_BOUNDARY, VM_SIZE):
(p, u) = vm[i]
if p != "." and (p != pid or not u):
print(f"FAIL: Process memory is not properly isolated for process {pid}")
print(" This error was thrown because your virtual address")
print(f" blocks for the process {pid} below the kernel boundary")
print(f" was owned by someone else other than the process {pid}.")
print_page_info(i, p, u)
exit(1)
def confirm_overlap(vms):
# Check that there is overlap in virtual address spaces
def check_overlap(vm1, vm2):
for ((a, _), (b, _)) in zip(vm1, vm2):
if a != "." and b != "." and a != b:
return True
return False
if not any(check_overlap(vma, vmb) for vma in vms for vmb in vms if vma is not vmb):
print("FAIL: Virtual memory pages did not overlap")
print(" This error was thrown because your virtual address blocks")
print(" blocks below the kernel boundary did not overlap with")
print(" other virtual address blocks of other processes, which it")
print(" should if stage 4 was completed successfully.")
exit(1)
def confirm_frequency(vcs):
if vcs[0] >= vcs[1] or vcs[1] >= vcs[2] or vcs[2] >= vcs[3]:
print("FAIL: Unexpected virtual mapped page frequency")
print(" This error was thrown because your virtual address blocks")
print(" allocated for PID 1, 2, 3, 4 did not have it such that")
print(" count1 < count2 < count3 < count4")
exit(1)
def count_physical_pages_owners(pm):
m = dict()
for p in pm:
if p in m:
m[p] += 1
else:
m[p] = 1
return m
def count_virtual_pages(vm, pid):
count = 0
for i in range(KERNEL_BOUNDARY, VM_SIZE):
(p, u) = vm[i]
if p == pid:
count += 1
return count
def confirm_counts(pcount, vmc, pid, delta):
if vmc != pcount[pid] - delta:
print(f"WARNING: number of pages mapped for virtual ({pcount[pid] - delta}) and physical ({vmc}) do not match for process {pid}")
print(f" NOTE: This may fail if you have implemented a later stage than the one you are testing for")
# make NO_SLOWDOWN=1 TICK_LIMIT=100 run
with open("log.txt") as f:
lines = [line.rstrip("\n") for line in f.readlines()]
# parsing
assert lines[0] == "Starting WeensyOS"
assert lines[1] == "PHYSICAL MEMORY DUMP"
pm = parse_physical_dump(lines[2])
assert lines[3] == "VIRTUAL MEMORY FOR PROCESS 1"
vm1 = parse_virtual_dump(lines[4])
assert lines[5] == "VIRTUAL MEMORY FOR PROCESS 2"
vm2 = parse_virtual_dump(lines[6])
assert lines[7] == "VIRTUAL MEMORY FOR PROCESS 3"
vm3 = parse_virtual_dump(lines[8])
assert lines[9] == "VIRTUAL MEMORY FOR PROCESS 4"
vm4 = parse_virtual_dump(lines[10])
pcount = count_physical_pages_owners(pm)
vm1c = count_virtual_pages(vm1, "1")
vm2c = count_virtual_pages(vm2, "2")
vm3c = count_virtual_pages(vm3, "3")
vm4c = count_virtual_pages(vm4, "4")
if args.stage == 1:
confirm_counts(pcount, vm1c, "1", 0)
confirm_counts(pcount, vm2c, "2", 0)
confirm_counts(pcount, vm3c, "3", 0)
confirm_counts(pcount, vm4c, "4", 0)
elif args.stage == 2 or args.stage == 3:
confirm_counts(pcount, vm1c, "1", 4)
confirm_counts(pcount, vm2c, "2", 4)
confirm_counts(pcount, vm3c, "3", 4)
confirm_counts(pcount, vm4c, "4", 4)
elif args.stage == 4:
confirm_counts(pcount, vm1c, "1", 5)
confirm_counts(pcount, vm2c, "2", 5)
confirm_counts(pcount, vm3c, "3", 5)
confirm_counts(pcount, vm4c, "4", 5)
# checking
if args.stage >= 1:
print("Checking stage 1...")
confirm_kernel_isolation(vm1)
confirm_kernel_isolation(vm2)
confirm_kernel_isolation(vm3)
confirm_kernel_isolation(vm4)
if args.stage >= 2:
print("Checking stage 2...")
confirm_process_isolation(vm1, "1")
confirm_process_isolation(vm2, "2")
confirm_process_isolation(vm3, "3")
confirm_process_isolation(vm4, "4")
if args.stage >= 3:
print("Checking stage 3...")
confirm_virtual_allocation(pm)
if args.stage >= 4:
print("Checking stage 4...")
confirm_physical_exhausted(pm)
confirm_overlap([vm1, vm2, vm3, vm4])
# confirm_frequency([vm1c, vm2c, vm3c, vm4c])
print(f"Tests up to stage {args.stage} passed!")
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment