changeset 0:ed10291ff195

first commit
author mir3636
date Sun, 06 Jan 2019 19:27:03 +0900
parents
children 3945d35281a0
files LICENSE Makefile README connect.gdb debug.sh include/arm.h include/buf.h include/defs.h include/elf.h include/fcntl.h include/file.h include/fs.h include/fvp.h include/mailbox.h include/memlayout.h include/mmu.h include/param.h include/proc.h include/spinlock.h include/stat.h include/syscall.h include/traps.h include/types.h include/user.h kernel.ld loader.S loader.ld makefile-armgcc qemu.log run-debug.sh source/LICENSE source/bio.c source/console.c source/entry.S source/exception.S source/exec.c source/file.c source/font.bin source/font1.bin source/fs.c source/fs.img source/initcode source/kalloc.c source/log.c source/mailbox.c source/main.c source/memide.c source/mmu.c source/pipe.c source/proc.c source/spinlock.c source/string.c source/syscall.c source/sysfile.c source/sysproc.c source/timer.c source/trap.c source/uart.c source/uart_pl011.c source/vm.c uprogs/LICENSE uprogs/Makefile uprogs/README uprogs/arm.h uprogs/buf.h uprogs/cat.c uprogs/defs.h uprogs/echo.c uprogs/elf.h uprogs/fcntl.h uprogs/file.h uprogs/forktest.c uprogs/fs.h uprogs/grep.c uprogs/init.c uprogs/initcode.S uprogs/kill.c uprogs/ln.c uprogs/ls.c uprogs/memlayout.h uprogs/mkdir.c uprogs/mkfs.c uprogs/mmu.h uprogs/param.h uprogs/printf.c uprogs/proc.h uprogs/rm.c uprogs/sh.c uprogs/spinlock.h uprogs/stat.h uprogs/stressfs.c uprogs/syscall.h uprogs/traps.h uprogs/types.h uprogs/ulib.c uprogs/umalloc.c uprogs/user.h uprogs/usertests.c uprogs/usys.S uprogs/wc.c uprogs/zombie.c xv6-guide.pdf
diffstat 101 files changed, 11261 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,30 @@
+The xv6 RPI2 port software is:
+
+Copyright (c) 2017
+Zhiyi Huang, University of Otago
+Alex Bradbury, University of Cambridge
+Alex Chadwick, University of Cambridge
+Theo Markettos, University of Cambridge
+Robert Mullins, University of Cambridge
+Robert N. M. Watson, University of Cambridge
+
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,149 @@
+UNAME := $(shell uname -m)
+
+ifeq ($(UNAME), x86_64)
+	# set FVP as default on x86_64 systems	
+	hw?=rpi2
+	TOOLCHAIN?=~/gcc-arm-none-eabi-5_4-2016q3/bin/arm-none-eabi-
+else
+	# RPI reports 'uname -m' as: armv7l
+	hw?=rpi2
+endif
+
+# PHYSTART  : start of memory (RAM)
+# PHYSIZE   : size of memory
+# KERNBASE  : address of high memory schema
+# MMIO_PA   : physical address of peripherals (MMIO)
+# MMIO_VA   : virtal address of peripherals
+# MMIO_SIZE : size of peripherals
+# PERIPHBASE: virtal address of PERIPHBASE[39:15]
+
+ifeq ($(hw), fvp)
+	PHYSTART  = 0x80000000
+	PHYSIZE   = 0x08000000
+	KERNBASE  = 0xC0000000
+	MMIO_PA   = 0x1C000000
+	MMIO_VA   = 0xD0000000
+	MMIO_SIZE = 0x04000000
+	PERIPHBASE= 0xDF000000
+	CFLAGS    =   -ffreestanding -nostdlib -nostartfiles -O0 -Wall -MD -ggdb -Wall -mcpu=cortex-a9 -mfloat-abi=hard -fno-short-enums -I include
+	#CFLAGS    =   -ffreestanding -nostdlib -nostartfiles -O2 -Wall -MD -ggdb -Wall -mcpu=cortex-a9 -mfloat-abi=hard -fno-short-enums -I include
+	TARGET    = fvp.img
+	CC_OPTIONS = -DFVP
+else ifeq ($(hw), rpi1)
+	PHYSTART  = 0x00000000
+	# PHYSIZE set to 128mb
+	PHYSIZE   = 0x08000000
+	KERNBASE  = 0x80000000
+	MMIO_PA   = 0x20000000
+	MMIO_VA   = 0xD0000000
+	MMIO_SIZE = 0x01000000
+	PERIPHBASE= 0xDF000000
+	#CFLAGS   = -fno-pic -static -Wno-packed-bitfield-compat -fno-builtin -fno-strict-aliasing -fshort-wchar -O2 -Wall -MD -ggdb -Werror -fno-omit-frame-pointer -fno-stack-protector -Wa,-march=armv6 -Wa,-mcpu=arm1176jzf-s -mfloat-abi=hard -fno-short-enums -I include
+	CFLAGS    =   -ffreestanding -nostdlib -nostartfiles -O2 -Wall -MD -ggdb -Wall -mcpu=arm1176jzf-s -mfloat-abi=hard -fno-short-enums -I include
+	TARGET    = kernel.img
+	CC_OPTIONS = -DRPI1
+else ifeq ($(hw), rpi2)
+	 PHYSTART = 0x00000000
+	# PHYSIZE set to 256mb
+	PHYSIZE   = 0x10000000
+	KERNBASE  = 0x80000000
+	MMIO_PA   = 0x3F000000
+	MMIO_VA   = 0xD0000000
+	MMIO_SIZE = 0x01000000
+	PERIPHBASE= 0xDF000000
+	CFLAGS    = -ffreestanding -nostdlib -nostartfiles -O2 -Wall -MD -ggdb -Wall -mcpu=cortex-a7 -mfloat-abi=hard -fno-short-enums -I include 
+	TARGET    = kernel7.bin
+	CC_OPTIONS = -DRPI2
+else
+$(error Hardware (hw) should be fvp, rpi1 or rpi2, eg. make hw=rpi2)
+endif
+
+
+K_PDX_BASE=$(shell printf "0x%X\n" $$(( $(PHYSTART) + 0x4000 )) )
+K_PTX_BASE=$(shell printf "0x%X\n" $$(( $(PHYSTART) + 0x3000 )) )
+OFFSET=0x8000
+PHYSOFFSET=$(shell printf "0x%X\n" $$(( $(PHYSTART) + $(OFFSET) )) )
+KERNOFFSET=$(shell printf "0x%X\n" $$(( $(KERNBASE) + $(OFFSET) )) )
+
+CC_OPTIONS += -DPHYSTART=$(PHYSTART) -DPHYSIZE=$(PHYSIZE) -DKERNBASE=$(KERNBASE) -DMMIO_PA=$(MMIO_PA) -DMMIO_VA=$(MMIO_VA) -DMMIO_SIZE=$(MMIO_SIZE) -DPERIPHBASE=$(PERIPHBASE)
+CC_OPTIONS += -DK_PDX_BASE=$(K_PDX_BASE) -DK_PTX_BASE=$(K_PTX_BASE) -DPHYSOFFSET=$(PHYSOFFSET) -DKERNOFFSET=$(KERNOFFSET)
+
+LD_OPTIONS = --defsym=PHYSTART=$(PHYSTART) --defsym=PHYSIZE=$(PHYSIZE) --defsym=KERNBASE=$(KERNBASE) --defsym=MMIO_PA=$(MMIO_PA) --defsym=MMIO_VA=$(MMIO_VA) --defsym=MMIO_SIZE=$(MMIO_SIZE) --defsym=PERIPHBASE=$(PERIPHBASE) 
+LD_OPTIONS += --defsym=K_PDX_BASE=$(K_PDX_BASE) --defsym=K_PTX_BASE=$(K_PTX_BASE) --defsym=PHYSOFFSET=$(PHYSOFFSET) --defsym=KERNOFFSET=$(KERNOFFSET)
+
+# Build directory
+BUILD=build/
+# Sources directory.
+SOURCE=source/
+# Generated listing file.
+LIBRARIES=
+
+# The names of all object files that must be generated. Deduced from the 
+# assembly code files in source.
+ASM_OBJECTS = $(patsubst $(SOURCE)%.S,$(BUILD)%.o,$(wildcard $(SOURCE)*.S))
+
+C_OBJECTS = $(patsubst $(SOURCE)%.c,$(BUILD)%.o,$(wildcard $(SOURCE)*.c))
+
+# Rule to make everything.
+all : $(TARGET)
+	
+# Rule to make the elf file.
+$(TARGET): $(ASM_OBJECTS) $(C_OBJECTS) kernel.ld
+	$(TOOLCHAIN)ld $(ASM_OBJECTS) $(C_OBJECTS) -L. $(patsubst %,-l %,$(LIBRARIES)) $(LD_OPTIONS) -Map kernel.map -o $(BUILD)kernel.elf -T kernel.ld
+	$(TOOLCHAIN)objdump -d $(BUILD)kernel.elf > kernel.list
+	$(TOOLCHAIN)objcopy $(BUILD)kernel.elf -O binary $(TARGET)
+
+# Build ASM files
+$(BUILD)%.o: $(SOURCE)%.S $(BUILD)
+	$(TOOLCHAIN)gcc -c $(CFLAGS) $(CC_OPTIONS) -I source $< -o $@
+
+# Build C files
+$(BUILD)%.o: $(SOURCE)%.c $(BUILD)
+	$(TOOLCHAIN)gcc -c $(CFLAGS) $(CC_OPTIONS) $<  -o $@
+
+loader: loader.S kernel7.bin
+	$(TOOLCHAIN)gcc -c loader.S -o loader.elf -fpic -ffreestanding -nostdlib -nostartfiles -O0 -Wall -ggdb -Wall -mcpu=cortex-a7 -mfloat-abi=hard -fno-short-enums -o loader.o
+	$(TOOLCHAIN)ld loader.o -o loader.elf -T loader.ld
+	#$(TOOLCHAIN)objdump -D loader.elf > loader.list
+	$(TOOLCHAIN)objcopy loader.elf -O binary kernel7.img
+	-rm loader.elf  loader.o
+
+$(BUILD):
+	mkdir $@
+
+.PHONY: report
+report:
+	@echo 'Hardware  :' $(hw)
+	@echo 'TARGET    :' $(TARGET)
+	@echo 'PHYSTART  :' $(PHYSTART)
+	@echo 'PHYSIZE   :' $(PHYSIZE)
+	
+	@echo 'K_PDX_BASE:' $(K_PDX_BASE)
+	@echo 'K_PTX_BASE:' $(K_PTX_BASE)
+	@echo 'PHYSOFFSET:' $(PHYSOFFSET)
+	
+	@echo 'KERNBASE  :' $(KERNBASE)
+	@echo 'KERNOFFSET:' $(KERNOFFSET)
+
+	@echo 'MMIO_PA   :' $(MMIO_PA)
+	@echo 'MMIO_SIZE :' $(MMIO_SIZE)
+	@echo 'MMIO_VA   :' $(MMIO_VA)
+	@echo 'PERIPHBASE:' $(PERIPHBASE)
+	
+	@echo 'CFLAGS    :' $(CFLAGS)
+	@echo 'CC_OPTIONS:' $(CC_OPTIONS)
+	@echo 'LD_OPTIONS:' $(LD_OPTIONS)
+
+.PHONY: install
+install:
+	cp kernel*.img /media/$(USER)/boot/
+	sync
+	umount /media/$(USER)/*
+	
+# Rule to clean files.
+clean : 
+	-rm -rf $(BUILD)
+	-rm -f *.img
+	-rm -f *.bin
+	-rm -f kernel.list
+	-rm -f kernel.map
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,65 @@
+xv6_rpi2_port is based on MIT xv6 (http://pdos.csail.mit.edu/6.828/2012/v6.html).
+It is ported from x86 to armv6 and then to armv7 in Raspberry Pi (RPI2/3). 
+The rpi port follows the coding style of xv6 as much as possible to hide the architectural
+differences between x86 and armv6/armv7. The port is not for multiprocessor yet
+though RPI2/3 has four cores.
+
+ACKNOWLEDGEMENTS
+
+xv6_rpi2_port is inspired by MIT xv6 and Alex Chadwick's Baking Pi 
+Tutorials (http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/).
+Most architecture-independent code is directly from MIT xv6 though sometimes
+minor adjustments were done to explicitly initialize data structures.
+Some C code such as the GPU driver is based on the understanding of 
+Alex Chadwick's assembly code. 
+
+Some code for mmu and trap handling is based on the understanding of the
+Plan 9 bcm port (http://plan9.bell-labs.com/sources/plan9/sys/src/9/bcm/),
+though the assembly code was completely rewritten. 
+David Welch's RPI code (https://github.com/dwelch67/raspberrypi) is also
+inspiring for trap handling and uart driver.
+
+Mahdi Amiri Kordestany (mahdi@cs.otago.ac.nz) ported xv6 from RPI1 to
+RPI2/3.
+
+If you spot errors or suggest improvements, please send email to
+Zhiyi Huang (hzy@cs.otago.ac.nz).
+
+Building xv6_rpi2_port:
+
+Suppose you have checked out the source with:
+
+$ git clone https://github.com/zhiyihuang/xv6_rpi2_port.git
+
+On an RPI2/3 installed with Raspbian, type 'make loader' to make 'kernel7.img'.
+
+Copy 'kernel7.img' to /boot with a different name:
+# cp kernel7.img /boot/kernel-xv6.img
+
+Comment out the old entry 'kernel=' and add a new entry
+'kernel=kernel-xv6.img' to /boot/config.txt.
+
+Add the following into /boot/config.txt:
+
+kernel_old=1
+disable_commandline_tags=1
+enable_uart=1
+
+
+Reboot the machine.
+
+The USB keyboard is not working yet. The only way to input into
+the console is to use the mini UART (serial port). You can use a 
+USB to TTL Serial Cable to connect the mini UART to a virtual terminal.
+You may use minicom or CoolTerm to create the virtual terminal.
+You have to open the lid to connect the cable to the GPIO pins (14 and 15) 
+of the Pi. 
+
+Building xv6 user programs and FS (You don't need this step if you
+don't change the user programs):
+
+cd uprogs
+make 
+
+copy 'initcode' and 'fs.img' to the directory 'source'
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/connect.gdb	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,2 @@
+symbol build/kernel.elf
+target remote tcp::1234
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debug.sh	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,2 @@
+#!/bin/sh
+arm-none-eabi-gdb -x connect.gdb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/arm.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,72 @@
+/*****************************************************************
+*       arm.h
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+
+
+#define PSR_MODE_USR		0x00000010 
+#define PSR_MODE_FIQ		0x00000011
+#define PSR_MODE_IRQ		0x00000012
+#define PSR_MODE_SVC		0x00000013
+#define PSR_MODE_MON		0x00000016
+#define PSR_MODE_ABT		0x00000017
+#define PSR_MODE_UND		0x0000001B
+#define PSR_MODE_SYS		0x0000001F
+#define PSR_MASK		0x0000001F
+#define USER_MODE		0x0
+
+#define PSR_DISABLE_IRQ		0x00000080
+#define PSR_DISABLE_FIQ		0x00000040
+
+#define PSR_V			0x10000000
+#define PSR_C			0x20000000
+#define PSR_Z			0x40000000
+#define PSR_N			0x80000000
+
+
+static inline uint
+inw(uint addr)
+{
+    uint data;
+
+    asm volatile("ldr %0,[%1]" : "=r"(data) : "r"(addr));
+    return data;
+}
+
+static inline void
+outw(uint addr, uint data)
+{
+    asm volatile("str %1,[%0]" : : "r"(addr), "r"(data));
+}
+
+
+// Layout of the trap frame built on the stack
+// by exception.s, and passed to trap().
+struct trapframe {
+  uint sp; // user mode sp
+  uint r0;
+  uint r1; 
+  uint r2;
+  uint r3;
+  uint r4;
+  uint r5;
+  uint r6;
+  uint r7;
+  uint r8;
+  uint r9;
+  uint r10;
+  uint r11;
+  uint r12;
+  uint r13;
+  uint r14;
+  uint trapno;
+  uint ifar; // Instruction Fault Address Register (IFAR)
+  uint cpsr;
+  uint spsr; // saved cpsr from the trapped/interrupted mode
+  uint pc; // return address of the interrupted code
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/buf.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,13 @@
+struct buf {
+  int flags;
+  uint dev;
+  uint sector;
+  struct buf *prev; // LRU cache list
+  struct buf *next;
+  struct buf *qnext; // disk queue
+  uchar data[512];
+};
+#define B_BUSY  0x1  // buffer is locked by some process
+#define B_VALID 0x2  // buffer has been read from disk
+#define B_DIRTY 0x4  // buffer needs to be written to disk
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/defs.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,233 @@
+struct buf;
+struct context;
+struct file;
+struct inode;
+struct pipe;
+struct proc;
+struct spinlock;
+struct stat;
+struct superblock;
+
+void OkLoop(void);
+void NotOkLoop(void);
+
+// mmu.c
+void mmuinit0(void);
+void mmuinit1(void);
+void barriers(void);
+void dsb_barrier(void);
+void flush_tlb(void);
+void flush_dcache_all(void);
+void flush_dcache(uint va1, uint va2);
+void flush_idcache(void);
+void set_pgtbase(uint base);
+
+// bio.c
+void            binit(void);
+struct buf*     bread(uint, uint);
+void            brelse(struct buf*);
+void            bwrite(struct buf*);
+
+// console.c
+void            consoleinit(void);
+void            cprintf(char*, ...);
+void            consoleintr(int(*)(void));
+void            panic(char*) __attribute__((noreturn));
+void		drawcharacter(u8, uint, uint);
+void		gpuputc(uint);
+void		gpuinit(void);
+
+
+// fs.c
+void            readsb(int dev, struct superblock *sb);
+int             dirlink(struct inode*, char*, uint);
+struct inode*   dirlookup(struct inode*, char*, uint*);
+struct inode*   ialloc(uint, short);
+struct inode*   idup(struct inode*);
+void            iinit(void);
+void            ilock(struct inode*);
+void            iput(struct inode*);
+void            iunlock(struct inode*);
+void            iunlockput(struct inode*);
+void            iupdate(struct inode*);
+int             namecmp(const char*, const char*);
+struct inode*   namei(char*);
+struct inode*   nameiparent(char*, char*);
+int             readi(struct inode*, char*, uint, uint);
+void            stati(struct inode*, struct stat*);
+int             writei(struct inode*, char*, uint, uint);
+
+
+// ide.c
+void            ideinit(void);
+void            ideintr(void);
+void            iderw(struct buf*);
+
+// exec.c
+int             exec(char*, char**);
+
+// file.c
+struct file*    filealloc(void);
+void            fileclose(struct file*);
+struct file*    filedup(struct file*);
+void            fileinit(void);
+int             fileread(struct file*, char*, int n);
+int             filestat(struct file*, struct stat*);
+int             filewrite(struct file*, char*, int n);
+
+
+// fs.c
+void            readsb(int dev, struct superblock *sb);
+int             dirlink(struct inode*, char*, uint);
+struct inode*   dirlookup(struct inode*, char*, uint*);
+struct inode*   ialloc(uint, short);
+struct inode*   idup(struct inode*);
+void            iinit(void);
+void            ilock(struct inode*);
+void            iput(struct inode*);
+void            iunlock(struct inode*);
+void            iunlockput(struct inode*);
+void            iupdate(struct inode*);
+int             namecmp(const char*, const char*);
+struct inode*   namei(char*);
+struct inode*   nameiparent(char*, char*);
+int             readi(struct inode*, char*, uint, uint);
+void            stati(struct inode*, struct stat*);
+int             writei(struct inode*, char*, uint, uint);
+
+// kalloc.c
+char*           kalloc(void);
+void            kfree(char*);
+void            kinit1(void*, void*);
+void            kinit2(void*, void*);
+
+
+// log.c
+void            initlog(void);
+void            log_write(struct buf*);
+void            begin_trans();
+void            commit_trans();
+
+// pipe.c
+int             pipealloc(struct file**, struct file**);
+void            pipeclose(struct pipe*, int);
+int             piperead(struct pipe*, char*, int);
+int             pipewrite(struct pipe*, char*, int);
+
+//PAGEBREAK: 16
+// proc.c
+struct proc*    copyproc(struct proc*);
+void            exit(void);
+int             fork(void);
+int             growproc(int);
+int             kill(int);
+void            pinit(void);
+void            procdump(void);
+void            scheduler(void) __attribute__((noreturn));
+void            sched(void);
+void            sleep(void*, struct spinlock*);
+void            userinit(void);
+int             wait(void);
+void            wakeup(void*);
+void            yield(void);
+
+
+// swtch.S
+void            swtch(struct context**, struct context*);
+
+// syscall.c
+int             argint(int, int*);
+int             argptr(int, char**, int);
+int             argstr(int, char**);
+int             fetchint(uint, int*);
+int             fetchstr(uint, char**);
+void            syscall(void);
+
+void kvmalloc(void);
+
+
+int UsbInitialise(void);
+void KeyboardUpdate(void);
+char KeyboardGetChar(void);
+uint KeyboardCount(void);
+uint KeyboardGetAddress(uint);
+struct KeyboardLeds KeyboardGetLedSupport(uint);
+
+// spinlock.c
+void            acquire(struct spinlock*);
+void            getcallerpcs(void*, uint*);
+int             holding(struct spinlock*);
+void            initlock(struct spinlock*, char*);
+void            release(struct spinlock*);
+void            pushcli(void);
+void            popcli(void);
+
+// string.c
+int             memcmp(const void*, const void*, uint);
+void*           memmove(void*, const void*, uint);
+void*           memset(void*, int, uint);
+char*           safestrcpy(char*, const char*, int);
+int             strlen(const char*);
+int             strncmp(const char*, const char*, uint);
+char*           strncpy(char*, const char*, int);
+uint 		div(uint n, uint d);
+
+// syscall.c
+int             argint(int, int*);
+int             argptr(int, char**, int);
+int             argstr(int, char**);
+int             fetchint(uint, int*);
+int             fetchstr(uint, char**);
+void            syscall(void);
+
+// timer.c
+void		timer3init(void);
+void		timer3intr(void);
+unsigned long long getsystemtime(void);
+void		delay(uint);
+
+// trap.c
+void            tvinit(void);
+void		sti(void);
+void		cli(void);
+void 		disable_intrs(void);
+void 		enable_intrs(void);
+extern uint     ticks;
+extern struct spinlock tickslock;
+uint		readcpsr(void);
+
+// uart.c
+void            uartinit(void);
+void            miniuartintr(void);
+void            uartputc(uint);
+void		setgpiofunc(uint, uint);
+void		setgpioval(uint, uint);
+
+// vm.c
+void            seginit(void);
+void            kvmalloc(void);
+void            vmenable(void);
+pde_t*          setupkvm(void);
+char*           uva2ka(pde_t*, char*);
+int             allocuvm(pde_t*, uint, uint);
+int             deallocuvm(pde_t*, uint, uint);
+void            freevm(pde_t*);
+void            inituvm(pde_t*, char*, uint);
+int             loaduvm(pde_t*, char*, struct inode*, uint, uint);
+pde_t*          copyuvm(pde_t*, uint);
+void            switchuvm(struct proc*);
+void            switchkvm(void);
+int             copyout(pde_t*, uint, void*, uint);
+void            clearpteu(pde_t *pgdir, char *uva);
+
+// mailbox.c
+uint readmailbox(u8);
+void writemailbox(uint *, u8);
+void create_request(volatile uint *mbuf, uint tag, uint buflen, uint len, uint *data);
+void mailboxinit(void);
+
+
+
+// number of elements in fixed-size array
+#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/elf.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,42 @@
+// Format of an ELF executable file
+
+#define ELF_MAGIC 0x464C457FU  // "\x7FELF" in little endian
+
+// File header
+struct elfhdr {
+  uint magic;  // must equal ELF_MAGIC
+  uchar elf[12];
+  ushort type;
+  ushort machine;
+  uint version;
+  uint entry;
+  uint phoff;
+  uint shoff;
+  uint flags;
+  ushort ehsize;
+  ushort phentsize;
+  ushort phnum;
+  ushort shentsize;
+  ushort shnum;
+  ushort shstrndx;
+};
+
+// Program section header
+struct proghdr {
+  uint type;
+  uint off;
+  uint vaddr;
+  uint paddr;
+  uint filesz;
+  uint memsz;
+  uint flags;
+  uint align;
+};
+
+// Values for Proghdr type
+#define ELF_PROG_LOAD           1
+
+// Flag bits for Proghdr flags
+#define ELF_PROG_FLAG_EXEC      1
+#define ELF_PROG_FLAG_WRITE     2
+#define ELF_PROG_FLAG_READ      4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/fcntl.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,4 @@
+#define O_RDONLY  0x000
+#define O_WRONLY  0x001
+#define O_RDWR    0x002
+#define O_CREATE  0x200
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/file.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,38 @@
+struct file {
+  enum { FD_NONE, FD_PIPE, FD_INODE } type;
+  int ref; // reference count
+  char readable;
+  char writable;
+  struct pipe *pipe;
+  struct inode *ip;
+  uint off;
+};
+
+
+// in-memory copy of an inode
+struct inode {
+  uint dev;           // Device number
+  uint inum;          // Inode number
+  int ref;            // Reference count
+  int flags;          // I_BUSY, I_VALID
+
+  short type;         // copy of disk inode
+  short major;
+  short minor;
+  short nlink;
+  uint size;
+  uint addrs[NDIRECT+1];
+};
+#define I_BUSY 0x1
+#define I_VALID 0x2
+
+// table mapping major device number to
+// device functions
+struct devsw {
+  int (*read)(struct inode*, char*, int);
+  int (*write)(struct inode*, char*, int);
+};
+
+extern struct devsw devsw[];
+
+#define CONSOLE 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/fs.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,55 @@
+// On-disk file system format. 
+// Both the kernel and user programs use this header file.
+
+// Block 0 is unused.
+// Block 1 is super block.
+// Blocks 2 through sb.ninodes/IPB hold inodes.
+// Then free bitmap blocks holding sb.size bits.
+// Then sb.nblocks data blocks.
+// Then sb.nlog log blocks.
+
+#define ROOTINO 1  // root i-number
+#define BSIZE 512  // block size
+
+// File system super block
+struct superblock {
+  uint size;         // Size of file system image (blocks)
+  uint nblocks;      // Number of data blocks
+  uint ninodes;      // Number of inodes.
+  uint nlog;         // Number of log blocks
+};
+
+#define NDIRECT 12
+#define NINDIRECT (BSIZE / sizeof(uint))
+#define MAXFILE (NDIRECT + NINDIRECT)
+
+// On-disk inode structure
+struct dinode {
+  short type;           // File type
+  short major;          // Major device number (T_DEV only)
+  short minor;          // Minor device number (T_DEV only)
+  short nlink;          // Number of links to inode in file system
+  uint size;            // Size of file (bytes)
+  uint addrs[NDIRECT+1];   // Data block addresses
+};
+
+// Inodes per block.
+#define IPB           (BSIZE / sizeof(struct dinode))
+
+// Block containing inode i
+#define IBLOCK(i)     ((i) / IPB + 2)
+
+// Bitmap bits per block
+#define BPB           (BSIZE*8)
+
+// Block containing bit for block b
+#define BBLOCK(b, ninodes) (b/BPB + (ninodes)/IPB + 3)
+
+// Directory is a file containing a sequence of dirent structures.
+#define DIRSIZ 14
+
+struct dirent {
+  ushort inum;
+  char name[DIRSIZ];
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/fvp.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,41 @@
+/*
+ * fvp.h
+ *
+ *  Created on: Dec 2, 2016
+ *      Author: Mahdi Amiri
+ */
+
+#ifndef FVP_H
+#define FVP_H
+#define FVP_PL011_BASE	(MMIO_VA + 0x90000)
+#define FVP_PL011_UARTDR	FVP_PL011_BASE			// Data register
+#define FVP_PL011_UARTFR 	(FVP_PL011_BASE+0x18)	// Flag register
+#define FVP_PL011_UARTFR_TXFF	(1 << 5)		// Transmit FIFO full @ UARTFR
+#define FVP_PL011_UARTFR_RXFE	(1 << 4)		// Receive FIFO empty @ UARTFR
+#define FVP_PL011_UARTCR	(FVP_PL011_BASE+0x30)	// Control register
+#define FVP_PL011_UARTCR_UARTEN	1				// UART enable @ UARTCR
+#define FVP_PL011_UARTCR_TXE	(1<<8)			// Transmit enable @ UARTCR
+#define FVP_PL011_UARTCR_RXE	(1<<9)			// Receive enable @ UARTCR
+#define FVP_PL011_UARTIMSC (FVP_PL011_BASE+0x38)	// Interrupt mask set/clear register
+#define FVP_PL011_UARTIMSC_RXIM (1<<4)			// Receive interrupt mask.
+
+//#define FVP_GLOBAL_TIMER_BASE	((uint) &__va_private_start + 0x0200 )
+#define FVP_GLOBAL_TIMER_BASE	(MMIO_VA + 0x110000)
+#define FVP_TIMER1_LOAD			FVP_GLOBAL_TIMER_BASE
+#define FVP_TIMER1_VALUE		( FVP_GLOBAL_TIMER_BASE	+ 0x4 )
+#define FVP_TIMER1_CNTL			( FVP_GLOBAL_TIMER_BASE	+ 0x8 )
+#define FVP_TIMER1_INT_CTRL		( FVP_GLOBAL_TIMER_BASE	+ 0xC )
+#define FVP_TIMER1_RIS			( FVP_GLOBAL_TIMER_BASE	+ 0x10 )
+#define FVP_TIMER1_MIS			( FVP_GLOBAL_TIMER_BASE	+ 0x14 )
+#define FVP_TIMER1_BGL			( FVP_GLOBAL_TIMER_BASE	+ 0x18 )
+
+#define ARM_GLOBAL_TIMER_BASE		((uint) &__va_private_start + 0x0200 )
+#define ARM_GLOBAL_TIMER_VALUE_LO	ARM_GLOBAL_TIMER_BASE				// Load Register
+#define ARM_GLOBAL_TIMER_VALUE_HI	( ARM_GLOBAL_TIMER_BASE	+ 0x4 )		// Value
+#define ARM_GLOBAL_TIMER_CNTL		( ARM_GLOBAL_TIMER_BASE	+ 0x8 )		// Value
+#define ARM_GLOBAL_TIMER_INT_STATUS	( ARM_GLOBAL_TIMER_BASE	+ 0xC )		// Value
+#define ARM_GLOBAL_TIMER_CMP_LO	( ARM_GLOBAL_TIMER_BASE	+ 0x10 )	// Value
+#define ARM_GLOBAL_TIMER_CMP_HI	( ARM_GLOBAL_TIMER_BASE	+ 0x14 )	// Value
+#define ARM_GLOBAL_TIMER_AUTO_INC	( ARM_GLOBAL_TIMER_BASE	+ 0x18 )	// Value
+
+#endif /* FVP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/mailbox.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,38 @@
+#define MAILBOX_BASE	(MMIO_VA+0x00B880)
+
+#define MPI_REQUEST 		0x00000000
+#define MPI_RESPONSE_OK		0x80000000
+#define MPI_RESPONSE_ERR	0x80000001
+
+#define POS_OVERALL_LENGTH	0
+#define POS_RV			1
+#define POS_TAG			2
+
+#define POS_TAG_ID		0
+#define POS_TAG_BUFLEN		1
+#define POS_TAG_DATALEN		2
+#define POS_TAG_DATA		3
+
+
+#define MB_HEADER_LENGTH 2
+#define TAG_HEADER_LENGTH 3
+
+/* to be extended */
+#define MPI_TAG_GET_FIRMWARE		0x00000001
+#define MPI_TAG_GET_BOARD_MODEL		0x00010001
+#define MPI_TAG_GET_BOARD_REVISION	0x00010002
+#define MPI_TAG_GET_MAC_ADDRESS		0x00010003
+#define MPI_TAG_GET_BOARD_SERIAL	0x00010004
+#define MPI_TAG_GET_ARM_MEMORY		0x00010005
+#define MPI_TAG_GET_VC_MEMORY		0x00010006
+#define MPI_TAG_GET_CLOCKS		0x00010007
+#define MPI_TAG_GET_COMMANDLINE		0x00050001
+#define MPI_TAG_GET_DMA_CHANNELS	0x00060001
+#define MPI_TAG_GET_POWER_STATE		0x00020001
+#define MPI_TAG_SET_POWER_STATE		0x00028001
+#define MPI_TAG_GET_TIMING		0x00020002
+#define MPI_TAG_GET_FIRMWARE		0x00000001
+#define MPI_TAG_GET_CLOCK_STATE		0x00030001
+#define MPI_TAG_SET_CLOCK_STATE		0x00038001
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/memlayout.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,28 @@
+/*****************************************************************
+*       memlayout.h
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+
+// Memory layout
+
+#define PHYSTOP         (PHYSTART+PHYSIZE)
+
+#define USERBOUND 	0x40000000        // maximum user space due to one page pgd
+#define GPUMEMBASE	0x40000000
+#define GPUMEMSIZE	(1024*MBYTE)
+
+#define TVSIZE          0x1000
+
+static inline uint v2p(void *a) { return ((uint) (a))  - (KERNBASE-PHYSTART); }
+static inline void *p2v(uint a) { return (void *) ((a) + (KERNBASE-PHYSTART)); }
+
+#define V2P(a) (((uint) (a)) - (KERNBASE-PHYSTART))
+#define P2V(a) (((void *) (a)) + (KERNBASE-PHYSTART))
+
+#define V2P_WO(x) ((x) - (KERNBASE-PHYSTART))    // same as V2P, but without casts
+#define P2V_WO(x) ((x) + (KERNBASE-PHYSTART))    // same as V2P, but without casts
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/mmu.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,86 @@
+/*****************************************************************
+*       mmu.h
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+#define MBYTE		0x100000
+//Makefile #define K_PDX_BASE	0x4000
+//Makefile #define K_PTX_BASE	0x3000
+
+#define CACHELINESIZE   32
+
+/*
+ * page table entries.
+*/
+
+#define UNMAPPED	0x00000000
+
+#define COARSE		(0<<4|1)
+#define SECTION		(0<<4|2)
+
+#define LARGE		0x00000001
+#define SMALL		0x00000002
+#define BUFFERED	0x00000004
+#define CACHED		0x00000008
+#define APX		1 << 9
+#define SHAREABLE       1 << 10
+#define nG		1 << 11  // non-global
+#define XN		0x1      // execute never
+#define DOMAIN0		0
+
+#define NOACCESS	0
+#define K_RW		1
+#define U_AP		2
+#define U_RW		3
+
+#define ACCESS_PERM(n, v)	(((v) & 3) << (((n) * 2) + 4))
+#define PDX_AP(ap)		(ACCESS_PERM(3, (ap)))
+#define PTX_AP(ap) 		(ACCESS_PERM(3, (ap)) | ACCESS_PERM(2, (ap)) \
+				| ACCESS_PERM(1, (ap)) | ACCESS_PERM(0, (ap)))
+
+#define HVECTORS        0xffff0000
+
+// A virtual address 'la' has a three-part structure as follows:
+//
+// +--------12------+-------8--------+---------12----------+
+// | Page Directory |   Page Table   | Offset within Page  |
+// |      Index     |      Index     |                     |
+// +----------------+----------------+---------------------+
+//  \--- PDX(va) --/ \--- PTX(va) --/
+
+// page directory index
+#define PDX(va)         (((uint)(va) >> PDXSHIFT) & 0xFFF)
+
+// page table index
+#define PTX(va)         (((uint)(va) >> PTXSHIFT) & 0xFF)
+
+// construct virtual address from indexes and offset
+#define PGADDR(d, t, o) ((uint)((d) << PDXSHIFT | (t) << PTXSHIFT | (o)))
+
+// Address in page table or page directory entry
+#define PTE_ADDR(pte)   ((uint)(pte) & ~0xFFF)
+#define PTE_FLAGS(pte)  ((uint)(pte) &  0xFFF)
+
+// Page directory and page table constants.
+#define NPDENTRIES      1024    // # directory entries per page directory
+#define NPTENTRIES      1024    // # PTEs per page table
+#define PGSIZE          4096    // bytes mapped by a page
+
+#define PGSHIFT         12      // log2(PGSIZE)
+#define PTXSHIFT        12      // offset of PTX in a linear address
+#define PDXSHIFT        20      // offset of PDX in a linear address
+
+
+#define PGROUNDUP(sz)  (((sz)+PGSIZE-1) & ~(PGSIZE-1))
+#define PGROUNDDOWN(a) (((a)) & ~(PGSIZE-1))
+
+#define PGDIR_BASE	P2V(K_PDX_BASE)
+
+#define KVMPDXATTR       DOMAIN0|PDX_AP(U_RW)|SECTION|CACHED|BUFFERED
+
+#define UVMPDXATTR 	DOMAIN0|COARSE
+#define UVMPTXATTR	(PTX_AP(U_RW)^APX)|CACHED|BUFFERED|SMALL
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/param.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,12 @@
+#define NPROC        64  // maximum number of processes
+#define KSTACKSIZE 4096  // size of per-process kernel stack
+#define NCPU          8  // maximum number of CPUs
+#define NOFILE       16  // open files per process
+#define NFILE       100  // open files per system
+#define NBUF         10  // size of disk block cache
+#define NINODE       50  // maximum number of active i-nodes
+#define NDEV         10  // maximum major device number
+#define ROOTDEV       1  // device number of file system root disk
+#define MAXARG       32  // max exec arguments
+#define LOGSIZE      10  // max data sectors in on-disk log
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/proc.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,91 @@
+/*****************************************************************
+*       proc.h
+*       adapted from MIT xv6 by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+
+// Segments in proc->gdt.
+#define NSEGS     7
+
+// Per-CPU state
+struct cpu {
+  uchar id;                    // Local APIC ID; index into cpus[] below
+  struct context *scheduler;   // swtch() here to enter scheduler
+  volatile uint started;       // Has the CPU started?
+  int ncli;                    // Depth of pushcli nesting.
+  int intena;                  // Were interrupts enabled before pushcli?
+  
+  // Cpu-local storage variables; see below
+  struct cpu *cpu;
+  struct proc *proc;           // The currently-running process.
+};
+
+struct cpu cpus[NCPU];
+//extern int ncpu;
+
+// Per-CPU variables, holding pointers to the
+// current cpu and to the current process.
+// The asm suffix tells gcc to use "%gs:0" to refer to cpu
+// and "%gs:4" to refer to proc.  seginit sets up the
+// %gs segment register so that %gs refers to the memory
+// holding those two variables in the local cpu's struct cpu.
+// This is similar to how thread-local variables are implemented
+// in thread libraries such as Linux pthreads.
+//extern struct cpu *cpu asm("%gs:0");       // &cpus[cpunum()]
+//extern struct proc *proc asm("%gs:4");     // cpus[cpunum()].proc
+
+#define curr_cpu (&cpus[0])
+#define curr_proc   (cpus[0].proc)
+
+//PAGEBREAK: 17
+// Saved registers for kernel context switches.
+// Don't need to save all the segment registers (%cs, etc),
+// because they are constant across kernel contexts.
+// Don't need to save %eax, %ecx, %edx, because the
+// x86 convention is that the caller has saved them.
+// Contexts are stored at the bottom of the stack they
+// describe; the stack pointer is the address of the context.
+// The layout of the context matches the layout of the stack in swtch.S
+// at the "Switch stacks" comment. Switch doesn't save eip explicitly,
+// but it is on the stack and allocproc() manipulates it.
+struct context {
+  uint r4;
+  uint r5;
+  uint r6;
+  uint r7;
+  uint r8;
+  uint r9;
+  uint r10;
+  uint r11;
+  uint r12;
+  uint lr;
+  uint pc;
+};
+
+enum procstate { UNUSED=0, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
+
+// Per-process state
+struct proc {
+  uint sz;                     // Size of process memory (bytes)
+  pde_t* pgdir;                // Page table
+  char *kstack;                // Bottom of kernel stack for this process
+  enum procstate state;        // Process state
+  volatile int pid;            // Process ID
+  struct proc *parent;         // Parent process
+  struct trapframe *tf;        // Trap frame for current syscall
+  struct context *context;     // swtch() here to run process
+  void *chan;                  // If non-zero, sleeping on chan
+  int killed;                  // If non-zero, have been killed
+  struct file *ofile[NOFILE];  // Open files
+  struct inode *cwd;           // Current directory
+  char name[16];               // Process name (debugging)
+};
+
+// Process memory is laid out contiguously, low addresses first:
+//   text
+//   original data and bss
+//   fixed-size stack
+//   expandable heap
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/spinlock.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,11 @@
+// Mutual exclusion lock.
+struct spinlock {
+  uint locked;       // Is the lock held?
+
+  // For debugging:
+  char *name;        // Name of lock.
+  struct cpu *cpu;   // The cpu holding the lock.
+  uint pcs[10];      // The call stack (an array of program counters)
+                     // that locked the lock.
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/stat.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,11 @@
+#define T_DIR  1   // Directory
+#define T_FILE 2   // File
+#define T_DEV  3   // Device
+
+struct stat {
+  short type;  // Type of file
+  int dev;     // File system's disk device
+  uint ino;    // Inode number
+  short nlink; // Number of links to file
+  uint size;   // Size of file in bytes
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/syscall.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,22 @@
+// System call numbers
+#define SYS_fork    1
+#define SYS_exit    2
+#define SYS_wait    3
+#define SYS_pipe    4
+#define SYS_read    5
+#define SYS_kill    6
+#define SYS_exec    7
+#define SYS_fstat   8
+#define SYS_chdir   9
+#define SYS_dup    10
+#define SYS_getpid 11
+#define SYS_sbrk   12
+#define SYS_sleep  13
+#define SYS_uptime 14
+#define SYS_open   15
+#define SYS_write  16
+#define SYS_mknod  17
+#define SYS_unlink 18
+#define SYS_link   19
+#define SYS_mkdir  20
+#define SYS_close  21
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/traps.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,21 @@
+/*****************************************************************
+*       traps.h
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+
+// These are arbitrarily chosen, but with care not to overlap
+// processor defined exceptions or interrupt vectors.
+#define T_SYSCALL	0x40	// system call
+#define T_IRQ		0x80	// interrupt
+#define T_UND		0x01	// undefined instruction
+#define T_PABT		0x02	// prefetch abort
+#define T_DABT		0x04	// data abort
+
+#define IRQ_TIMER3	3
+#define IRQ_MINIUART	29
+
+#define INT_REGS_BASE 	(MMIO_VA+0xB200)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/types.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,53 @@
+/*****************************************************************
+*       types.h
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+typedef unsigned long long u64;
+
+typedef unsigned int   uint;
+typedef unsigned short ushort;
+typedef unsigned char  uchar;
+typedef uint pde_t;
+typedef uint pte_t;
+
+
+/* trap vectors layout at virtual 
+address HVECTORS (and KZERO(0x80000000), doubled mapped).*/
+typedef struct Vpage0 {
+        void    (*vectors[8])(void);
+        uint     vtable[8];
+} Vpage0;
+
+
+/* ARM interrupt control registers */
+typedef struct intctrlregs {
+        uint  armpending;
+        uint  gpupending[2];
+        uint  fiqctrl;
+        uint  gpuenable[2];
+        uint  armenable;
+        uint  gpudisable[2];
+        uint  armdisable;
+} intctrlregs;
+
+struct framebufdescription {
+	uint width; //width
+	uint height; // height
+	uint v_width; // virtual width
+	uint v_height; // virtual height
+	uint pitch; // GPU pitch
+	uint depth; // bit depth
+	uint x;
+	uint y;
+	uint fbp; //GPU framebuffer pointer
+	uint fbs; // GPU framebuffer size
+};
+
+typedef struct framebufdescription FBI;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/user.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,38 @@
+struct stat;
+
+// system calls
+int fork(void);
+int exit(void) __attribute__((noreturn));
+int wait(void);
+int pipe(int*);
+int write(int, void*, int);
+int read(int, void*, int);
+int close(int);
+int kill(int);
+int exec(char*, char**);
+int open(char*, int);
+int mknod(char*, short, short);
+int unlink(char*);
+int fstat(int fd, struct stat*);
+int link(char*, char*);
+int mkdir(char*);
+int chdir(char*);
+int dup(int);
+int getpid(void);
+char* sbrk(int);
+int sleep(int);
+int uptime(void);
+
+// ulib.c
+int stat(char*, struct stat*);
+char* strcpy(char*, char*);
+void *memmove(void*, void*, int);
+char* strchr(const char*, char c);
+int strcmp(const char*, const char*);
+void printf(int, char*, ...);
+char* gets(char*, int max);
+uint strlen(char*);
+void* memset(void*, int, uint);
+void* malloc(uint);
+void free(void*);
+int atoi(const char*);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel.ld	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,71 @@
+/******************************************************************************
+*	kernel.ld
+*	 by Alex Chadwick
+*
+*	A linker script for generation of raspberry pi kernel images.
+******************************************************************************/
+ENTRY(_start)
+
+PHYSOFFSET  = DEFINED(PHYSOFFSET)  ? PHYSOFFSET  : 0x80008000;
+KERNOFFSET  = DEFINED(KERNOFFSET)  ? KERNOFFSET  : 0xC0008000;
+SHIFT		= KERNOFFSET - PHYSOFFSET; 
+
+SECTIONS {
+	/* Link the kernel at this address: "." means the current address */
+	/* Must be equal to KERNLINK */
+	
+	/*
+	* First and formost we need the .init section, containing the code to 
+	* be run first. We allow room for the ATAGs and stack and conform to 
+	* the bootloader's expectation by putting this code at 0x8000.
+	*/
+	
+	.init PHYSOFFSET : {
+		*(.init)
+	}
+	
+	. = ALIGN(0x100);
+	INIT_END = .;
+	. = . + SHIFT;
+	
+	/* 
+	* Next we put the rest of the code.
+	*/
+	
+	 .text : AT (INIT_END) {  
+		*.c.o(.text)
+		*(.text .stub .text.*)
+	}
+
+	/*
+	* read-only data
+	*/
+	.rodata : {
+		*(.rodata .rodata.*)
+	}
+
+	/* Adjust the address for the data segment to the next page */
+	. = ALIGN(0x1000);
+	
+	/* 
+	* Next we put the data.
+	*/
+	.data : {
+		*(.data)
+		*.c.o(*)
+	}
+
+	.bss : {
+		*(.bss)
+	}
+
+	PROVIDE(end = .);
+
+	/*
+	* Finally comes everything else. A fun trick here is to put all other 
+	* sections into this section, which will be discarded by default.
+	*/
+	/DISCARD/ : {
+		*(.eh_frame .note.GNU-stack)
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loader.S	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,43 @@
+/*
+ * loader.S
+ *
+ *  Created on: Feb 11, 2017
+ *      Author: Mahdi Amiri
+ */
+
+	.text
+	.globl _start
+_start:
+	b loader_start  /* branch to the code */
+	b loader_sleep	// undefined
+	b loader_sleep	// svc
+	b loader_sleep	// prefetch
+	b loader_sleep	// abort
+	b loader_sleep	// hypervisor
+	b loader_sleep	// irq
+	b loader_sleep	// fiq
+
+	.balign 4
+loader_sleep:
+	wfi
+	b loader_sleep
+
+loader_start:
+	// Switch to SVC mode, all interrupts disabled
+	.set PSR_MODE_SVC, 0x13
+	.set PSR_MODE_IRQ_DISABLED, (1<<7)
+	.set PSR_MODE_FIQ_DISABLED, (1<<6)
+	msr	cpsr_c, #(PSR_MODE_SVC + PSR_MODE_FIQ_DISABLED + PSR_MODE_IRQ_DISABLED)
+
+	// Set all CPUs to wait except the primary CPU
+	mrc p15, 0, r0, c0, c0, 5
+	ands r0, r0, #0x03
+	bne loader_sleep
+
+	mov pc, #0x8000
+
+	.data
+	.align 4
+_data_start:
+	.incbin "kernel7.bin"
+_data_end:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loader.ld	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,9 @@
+ENTRY(_start)
+SECTIONS {
+	.text 0x0 : {
+		 * (.text);
+		 }
+	.data 0x8000 :	{
+		 * (.data); 
+		}
+	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile-armgcc	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,149 @@
+UNAME := $(shell uname -m)
+
+ifeq ($(UNAME), x86_64)
+	# set FVP as default on x86_64 systems	
+	hw?=rpi2
+	TOOLCHAIN?=/Users/mitsuki/workspace/gcc/cross/bin/arm-none-eabi-
+else
+	# RPI reports 'uname -m' as: armv7l
+	hw?=rpi2
+endif
+
+# PHYSTART  : start of memory (RAM)
+# PHYSIZE   : size of memory
+# KERNBASE  : address of high memory schema
+# MMIO_PA   : physical address of peripherals (MMIO)
+# MMIO_VA   : virtal address of peripherals
+# MMIO_SIZE : size of peripherals
+# PERIPHBASE: virtal address of PERIPHBASE[39:15]
+
+ifeq ($(hw), fvp)
+	PHYSTART  = 0x80000000
+	PHYSIZE   = 0x08000000
+	KERNBASE  = 0xC0000000
+	MMIO_PA   = 0x1C000000
+	MMIO_VA   = 0xD0000000
+	MMIO_SIZE = 0x04000000
+	PERIPHBASE= 0xDF000000
+	CFLAGS    =   -ffreestanding -nostdlib -nostartfiles -O0 -Wall -MD -ggdb -Wall -mcpu=cortex-a9 -mfloat-abi=hard -fno-short-enums -I include
+	#CFLAGS    =   -ffreestanding -nostdlib -nostartfiles -O2 -Wall -MD -ggdb -Wall -mcpu=cortex-a9 -mfloat-abi=hard -fno-short-enums -I include
+	TARGET    = fvp.img
+	CC_OPTIONS = -DFVP
+else ifeq ($(hw), rpi1)
+	PHYSTART  = 0x00000000
+	# PHYSIZE set to 128mb
+	PHYSIZE   = 0x08000000
+	KERNBASE  = 0x80000000
+	MMIO_PA   = 0x20000000
+	MMIO_VA   = 0xD0000000
+	MMIO_SIZE = 0x01000000
+	PERIPHBASE= 0xDF000000
+	#CFLAGS   = -fno-pic -static -Wno-packed-bitfield-compat -fno-builtin -fno-strict-aliasing -fshort-wchar -O2 -Wall -MD -ggdb -Werror -fno-omit-frame-pointer -fno-stack-protector -Wa,-march=armv6 -Wa,-mcpu=arm1176jzf-s -mfloat-abi=hard -fno-short-enums -I include
+	CFLAGS    =   -ffreestanding -nostdlib -nostartfiles -O2 -Wall -MD -ggdb -Wall -mcpu=arm1176jzf-s -mfloat-abi=hard -fno-short-enums -I include
+	TARGET    = kernel.img
+	CC_OPTIONS = -DRPI1
+else ifeq ($(hw), rpi2)
+	 PHYSTART = 0x00000000
+	# PHYSIZE set to 256mb
+	PHYSIZE   = 0x10000000
+	KERNBASE  = 0x80000000
+	MMIO_PA   = 0x3F000000
+	MMIO_VA   = 0xD0000000
+	MMIO_SIZE = 0x01000000
+	PERIPHBASE= 0xDF000000
+	CFLAGS    = -ffreestanding -nostdlib -nostartfiles -O2 -Wall -MD -ggdb -Wall -mcpu=cortex-a7 -mfloat-abi=hard -fno-short-enums -I include 
+	TARGET    = kernel7.bin
+	CC_OPTIONS = -DRPI2
+else
+$(error Hardware (hw) should be fvp, rpi1 or rpi2, eg. make hw=rpi2)
+endif
+
+
+K_PDX_BASE=$(shell printf "0x%X\n" $$(( $(PHYSTART) + 0x4000 )) )
+K_PTX_BASE=$(shell printf "0x%X\n" $$(( $(PHYSTART) + 0x3000 )) )
+OFFSET=0x8000
+PHYSOFFSET=$(shell printf "0x%X\n" $$(( $(PHYSTART) + $(OFFSET) )) )
+KERNOFFSET=$(shell printf "0x%X\n" $$(( $(KERNBASE) + $(OFFSET) )) )
+
+CC_OPTIONS += -DPHYSTART=$(PHYSTART) -DPHYSIZE=$(PHYSIZE) -DKERNBASE=$(KERNBASE) -DMMIO_PA=$(MMIO_PA) -DMMIO_VA=$(MMIO_VA) -DMMIO_SIZE=$(MMIO_SIZE) -DPERIPHBASE=$(PERIPHBASE)
+CC_OPTIONS += -DK_PDX_BASE=$(K_PDX_BASE) -DK_PTX_BASE=$(K_PTX_BASE) -DPHYSOFFSET=$(PHYSOFFSET) -DKERNOFFSET=$(KERNOFFSET)
+
+LD_OPTIONS = --defsym=PHYSTART=$(PHYSTART) --defsym=PHYSIZE=$(PHYSIZE) --defsym=KERNBASE=$(KERNBASE) --defsym=MMIO_PA=$(MMIO_PA) --defsym=MMIO_VA=$(MMIO_VA) --defsym=MMIO_SIZE=$(MMIO_SIZE) --defsym=PERIPHBASE=$(PERIPHBASE) 
+LD_OPTIONS += --defsym=K_PDX_BASE=$(K_PDX_BASE) --defsym=K_PTX_BASE=$(K_PTX_BASE) --defsym=PHYSOFFSET=$(PHYSOFFSET) --defsym=KERNOFFSET=$(KERNOFFSET)
+
+# Build directory
+BUILD=build/
+# Sources directory.
+SOURCE=source/
+# Generated listing file.
+LIBRARIES=
+
+# The names of all object files that must be generated. Deduced from the 
+# assembly code files in source.
+ASM_OBJECTS = $(patsubst $(SOURCE)%.S,$(BUILD)%.o,$(wildcard $(SOURCE)*.S))
+
+C_OBJECTS = $(patsubst $(SOURCE)%.c,$(BUILD)%.o,$(wildcard $(SOURCE)*.c))
+
+# Rule to make everything.
+all : $(TARGET)
+	
+# Rule to make the elf file.
+$(TARGET): $(ASM_OBJECTS) $(C_OBJECTS) kernel.ld
+	$(TOOLCHAIN)ld $(ASM_OBJECTS) $(C_OBJECTS) -L. $(patsubst %,-l %,$(LIBRARIES)) $(LD_OPTIONS) -Map kernel.map -o $(BUILD)kernel.elf -T kernel.ld
+	$(TOOLCHAIN)objdump -d $(BUILD)kernel.elf > kernel.list
+	$(TOOLCHAIN)objcopy $(BUILD)kernel.elf -O binary $(TARGET)
+
+# Build ASM files
+$(BUILD)%.o: $(SOURCE)%.S $(BUILD)
+	$(TOOLCHAIN)gcc -c $(CFLAGS) $(CC_OPTIONS) -I source $< -o $@
+
+# Build C files
+$(BUILD)%.o: $(SOURCE)%.c $(BUILD)
+	$(TOOLCHAIN)gcc -c $(CFLAGS) $(CC_OPTIONS) $<  -o $@
+
+loader: loader.S kernel7.bin
+	$(TOOLCHAIN)gcc -c loader.S -o loader.elf -fpic -ffreestanding -nostdlib -nostartfiles -O0 -Wall -ggdb -Wall -mcpu=cortex-a7 -mfloat-abi=hard -fno-short-enums -o loader.o
+	$(TOOLCHAIN)ld loader.o -o loader.elf -T loader.ld
+	#$(TOOLCHAIN)objdump -D loader.elf > loader.list
+	$(TOOLCHAIN)objcopy loader.elf -O binary kernel7.img
+	-rm loader.elf  loader.o
+
+$(BUILD):
+	mkdir $@
+
+.PHONY: report
+report:
+	@echo 'Hardware  :' $(hw)
+	@echo 'TARGET    :' $(TARGET)
+	@echo 'PHYSTART  :' $(PHYSTART)
+	@echo 'PHYSIZE   :' $(PHYSIZE)
+	
+	@echo 'K_PDX_BASE:' $(K_PDX_BASE)
+	@echo 'K_PTX_BASE:' $(K_PTX_BASE)
+	@echo 'PHYSOFFSET:' $(PHYSOFFSET)
+	
+	@echo 'KERNBASE  :' $(KERNBASE)
+	@echo 'KERNOFFSET:' $(KERNOFFSET)
+
+	@echo 'MMIO_PA   :' $(MMIO_PA)
+	@echo 'MMIO_SIZE :' $(MMIO_SIZE)
+	@echo 'MMIO_VA   :' $(MMIO_VA)
+	@echo 'PERIPHBASE:' $(PERIPHBASE)
+	
+	@echo 'CFLAGS    :' $(CFLAGS)
+	@echo 'CC_OPTIONS:' $(CC_OPTIONS)
+	@echo 'LD_OPTIONS:' $(LD_OPTIONS)
+
+.PHONY: install
+install:
+	cp kernel*.img /media/$(USER)/boot/
+	sync
+	umount /media/$(USER)/*
+	
+# Rule to clean files.
+clean : 
+	-rm -rf $(BUILD)
+	-rm -f *.img
+	-rm -f *.bin
+	-rm -f kernel.list
+	-rm -f kernel.map
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/run-debug.sh	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,2 @@
+#!/bin/sh
+qemu-system-arm -M versatilepb -m 128 -cpu arm1176 -nographic -singlestep -d exec,cpu,guest_errors -D qemu.log -kernel build/kernel.elf -s -S
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/LICENSE	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,24 @@
+The xv6 software is:
+
+Copyright (c) 2006-2009 Frans Kaashoek, Robert Morris, Russ Cox,
+                        Massachusetts Institute of Technology
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/bio.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,141 @@
+// Buffer cache.
+//
+// The buffer cache is a linked list of buf structures holding
+// cached copies of disk block contents.  Caching disk blocks
+// in memory reduces the number of disk reads and also provides
+// a synchronization point for disk blocks used by multiple processes.
+// 
+// Interface:
+// * To get a buffer for a particular disk block, call bread.
+// * After changing buffer data, call bwrite to write it to disk.
+// * When done with the buffer, call brelse.
+// * Do not use the buffer after calling brelse.
+// * Only one process at a time can use a buffer,
+//     so do not keep them longer than necessary.
+// 
+// The implementation uses three state flags internally:
+// * B_BUSY: the block has been returned from bread
+//     and has not been passed back to brelse.  
+// * B_VALID: the buffer data has been read from the disk.
+// * B_DIRTY: the buffer data has been modified
+//     and needs to be written to disk.
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "spinlock.h"
+#include "buf.h"
+
+struct {
+  struct spinlock lock;
+  struct buf buf[NBUF];
+
+  // Linked list of all buffers, through prev/next.
+  // head.next is most recently used.
+  struct buf head;
+} bcache;
+
+void
+binit(void)
+{
+  struct buf *b;
+
+  memset(&bcache, 0, sizeof(bcache));
+  initlock(&bcache.lock, "bcache");
+
+//PAGEBREAK!
+  // Create linked list of buffers
+  bcache.head.prev = &bcache.head;
+  bcache.head.next = &bcache.head;
+  for(b = bcache.buf; b < bcache.buf+NBUF; b++){
+    b->next = bcache.head.next;
+    b->prev = &bcache.head;
+    b->dev = -1;
+    bcache.head.next->prev = b;
+    bcache.head.next = b;
+  }
+}
+
+// Look through buffer cache for sector on device dev.
+// If not found, allocate fresh block.
+// In either case, return B_BUSY buffer.
+static struct buf*
+bget(uint dev, uint sector)
+{
+  struct buf *b;
+
+  acquire(&bcache.lock);
+
+ loop:
+  // Is the sector already cached?
+  for(b = bcache.head.next; b != &bcache.head; b = b->next){
+    if(b->dev == dev && b->sector == sector){
+      if(!(b->flags & B_BUSY)){
+        b->flags |= B_BUSY;
+        release(&bcache.lock);
+        return b;
+      }
+      sleep(b, &bcache.lock);
+      goto loop;
+    }
+  }
+
+  // Not cached; recycle some non-busy and clean buffer.
+  for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
+    if((b->flags & B_BUSY) == 0 && (b->flags & B_DIRTY) == 0){
+      b->dev = dev;
+      b->sector = sector;
+      b->flags = B_BUSY;
+      release(&bcache.lock);
+      return b;
+    }
+  }
+  panic("bget: no buffers");
+  return 0;
+}
+
+// Return a B_BUSY buf with the contents of the indicated disk sector.
+struct buf*
+bread(uint dev, uint sector)
+{
+  struct buf *b;
+
+  b = bget(dev, sector);
+  if(!(b->flags & B_VALID))
+    iderw(b);
+  return b;
+}
+
+// Write b's contents to disk.  Must be B_BUSY.
+void
+bwrite(struct buf *b)
+{
+  if((b->flags & B_BUSY) == 0)
+    panic("bwrite");
+  b->flags |= B_DIRTY;
+  iderw(b);
+}
+
+// Release a B_BUSY buffer.
+// Move to the head of the MRU list.
+void
+brelse(struct buf *b)
+{
+  if((b->flags & B_BUSY) == 0)
+    panic("brelse");
+
+  acquire(&bcache.lock);
+
+  b->next->prev = b->prev;
+  b->prev->next = b->next;
+  b->next = bcache.head.next;
+  b->prev = &bcache.head;
+  bcache.head.next->prev = b;
+  bcache.head.next = b;
+
+  b->flags &= ~B_BUSY;
+  wakeup(b);
+
+  release(&bcache.lock);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/console.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,535 @@
+/*****************************************************************
+ *       console.c
+ *       adapted from MIT xv6 by Zhiyi Huang, hzy@cs.otago.ac.nz
+ *       University of Otago
+ *
+ ********************************************************************/
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "traps.h"
+#include "spinlock.h"
+#include "fs.h"
+#include "file.h"
+#include "memlayout.h"
+#include "mmu.h"
+#include "proc.h"
+#include "arm.h"
+
+#define BACKSPACE 0x100
+
+static int panicked = 0;
+
+static struct {
+	struct spinlock lock;
+	int locking;
+} cons;
+
+
+uint cursor_x=0, cursor_y=0;
+uint frameheight=1024, framewidth=1280, framedepth=16;
+uint fontheight=16, fontwidth=8;
+FBI fbinfo __attribute__ ((aligned (16), nocommon));
+
+extern volatile uint *mailbuffer;
+extern u8 font[];
+static uint gpucolour=0xffff;
+
+void setgpucolour(u16 c)
+{
+	gpucolour = c;
+}
+
+
+
+uint initframebuf(uint width, uint height, uint depth)
+{
+  
+
+	fbinfo.width = width;
+	fbinfo.height = height;
+	fbinfo.v_width = width;
+	fbinfo.v_height = height;
+	fbinfo.pitch = 0;
+	fbinfo.depth = depth;
+	fbinfo.x = 0;
+	fbinfo.y = 0;
+	fbinfo.fbp = 0;
+	fbinfo.fbs = 0;
+	writemailbox((uint *)&fbinfo, 1);
+	return readmailbox(1);
+}
+
+#define INPUT_BUF 128
+struct {
+	struct spinlock lock;
+	char buf[INPUT_BUF];
+	uint r;  // Read index
+	uint w;  // Write index
+	uint e;  // Edit index
+} input;
+
+int
+consolewrite(struct inode *ip, char *buf, int n)
+{
+	int i;
+
+	//  cprintf("consolewrite is called: ip=%x buf=%x, n=%x", ip, buf, n);
+	iunlock(ip);
+	acquire(&cons.lock);
+	for(i = 0; i < n; i++){
+#if defined (RPI1)
+		gpuputc(buf[i] & 0xff);
+		uartputc(buf[i] & 0xff);
+#elif defined (RPI2)
+		gpuputc(buf[i] & 0xff);
+		uartputc(buf[i] & 0xff);
+#elif defined (FVP)
+		uartputc_fvp(buf[i] & 0xff);
+#endif
+
+	}
+	release(&cons.lock);
+	ilock(ip);
+
+	return n;
+}
+
+
+void drawpixel(uint x, uint y)
+{
+	u16 *addr;
+
+	if(x >= framewidth || y >= frameheight) return;
+	addr = (u16 *) fbinfo.fbp;
+	addr += y*framewidth + x;
+	*addr = gpucolour;
+	return;
+}
+
+
+void drawcursor(uint x, uint y)
+{
+	u8 row, bit;
+
+	for(row=0; row<15; row++)
+		for(bit=0; bit<8; bit++)
+			drawpixel(x+bit, y+row);
+}
+
+void drawcharacter(u8 c, uint x, uint y)
+{
+	u8 *faddr;
+	u8 row, bit, bits;
+	uint tv;
+
+	if(c > 127) return;
+	tv = ((uint)c) << 4;
+	faddr = font + tv;
+	for(row=0; row<15; row++){
+		bits = *(faddr+row);
+		for(bit=0; bit<8; bit++){
+			if((bits>>bit) & 1) drawpixel(x+bit, y+row);
+		}
+	}
+
+}
+
+//static void
+void
+gpuputc(uint c)
+{
+	#if defined (RPI1) || defined (RPI2)
+
+	if(fbinfo.fbp == 0) return;
+
+	if(c=='\n'){
+		cursor_x = 0;
+		cursor_y += fontheight;
+		if(cursor_y >= frameheight) {
+			memmove((u8 *)fbinfo.fbp, (u8 *)fbinfo.fbp+framewidth*fontheight*2, (frameheight - fontheight)*framewidth*2);
+			cursor_y = frameheight - fontheight;
+			setgpucolour(0);
+			while(cursor_x < framewidth) {
+				drawcursor(cursor_x, cursor_y);
+				cursor_x = cursor_x + fontwidth;
+			}
+			setgpucolour(0xffff);
+			cursor_x = 0;
+		}
+	} else if(c == BACKSPACE) {
+		if (cursor_x > 0) {
+			cursor_x -= fontwidth;
+			setgpucolour(0);
+			drawcursor(cursor_x, cursor_y);
+			setgpucolour(0xffff);
+		}
+	} else {
+		setgpucolour(0);
+		drawcursor(cursor_x, cursor_y);
+		setgpucolour(0xffff);
+		if(c!=' ') drawcharacter(c, cursor_x, cursor_y);
+		cursor_x = cursor_x + fontwidth;
+		if(cursor_x >= framewidth) {
+			cursor_x = 0;
+			cursor_y += fontheight;
+			if(cursor_y >= frameheight) {
+				memmove((u8 *)fbinfo.fbp, (u8 *)fbinfo.fbp+framewidth*fontheight*2, (frameheight - fontheight)*framewidth*2);
+				cursor_y = frameheight - fontheight;
+				setgpucolour(0);
+				while(cursor_x < framewidth) {
+					drawcursor(cursor_x, cursor_y);
+					cursor_x = cursor_x + fontwidth;
+				}
+				setgpucolour(0xffff);
+				cursor_x = 0;
+			}
+		}
+	}
+	#endif
+
+}
+
+
+static void
+printint(int xx, int base, int sign)
+{
+	static u8 digits[] = "0123456789abcdef";
+	u8 buf[16];
+	int i;
+	uint x, y, b;
+
+	if(sign && (sign = xx < 0))
+		x = -xx;
+	else
+		x = xx;
+
+	b = base;
+	i = 0;
+	do{
+		y = div(x, b);
+		buf[i++] = digits[x - y * b];
+	}while((x = y) != 0);
+
+	if(sign)
+		buf[i++] = '-';
+
+	while(--i >= 0){
+		#if defined (RPI1)
+		gpuputc(buf[i]);
+		uartputc(buf[i]);
+		#elif defined (RPI2)
+		gpuputc(buf[i]);
+		uartputc(buf[i]);
+		#elif defined (FVP)
+		uartputc_fvp(buf[i]);
+		#endif
+	}
+}
+
+
+// Print to the console. only understands %d, %x, %p, %s.
+void
+cprintf(char *fmt, ...)
+{
+	int i, c;
+	int locking;
+	uint *argp;
+	char *s;
+
+	locking = cons.locking;
+	if(locking)
+		acquire(&cons.lock);
+
+	if (fmt == 0)
+		panic("null fmt");
+
+	argp = (uint *)(void*)(&fmt + 1);
+	for(i = 0; (c = fmt[i] & 0xff) != 0; i++){
+		if(c != '%'){
+			#if defined (RPI1)
+			gpuputc(c);
+			uartputc(c);
+			#elif defined (RPI2)
+			gpuputc(c);
+			uartputc(c);
+			#elif defined (FVP)
+			uartputc_fvp(c);
+			#endif
+			continue;
+		}
+		c = fmt[++i] & 0xff;
+		if(c == 0)
+			break;
+		switch(c){
+		case 'd':
+			printint(*argp++, 10, 1);
+			break;
+		case 'x':
+		case 'p':
+			printint(*argp++, 16, 0);
+			break;
+		case 's':
+			if((s = (char*)*argp++) == 0)
+				s = "(null)";
+			for(; *s; s++){
+				#if defined (RPI1)
+				gpuputc(*s);
+				uartputc(*s);
+				#elif defined (RPI2)
+				gpuputc(*s);
+				uartputc(*s);
+				#elif defined (FVP)
+				uartputc_fvp(*s);
+				#endif
+			}
+			break;
+		case '%':
+			#if defined (RPI1)
+			gpuputc('%');
+			uartputc('%');
+			#elif defined (RPI2)
+			gpuputc('%');
+			uartputc('%');
+			#elif defined (FVP)
+			uartputc_fvp('%');
+			#endif
+			break;
+		default:
+			// Print unknown % sequence to draw attention.
+			#if defined (RPI1)
+			gpuputc('%');
+			uartputc('%');
+			gpuputc(c);
+			uartputc(c);
+			#elif defined (RPI2)
+			gpuputc('%');
+			uartputc('%');
+			gpuputc(c);
+			uartputc(c);
+			#elif defined (FVP)
+			uartputc_fvp('%');
+			uartputc_fvp(c);
+			#endif
+			break;
+		}
+	}
+	if(locking)
+		release(&cons.lock);
+}
+
+void
+panic(char *s)
+{
+	int i;
+	uint pcs[10];
+
+	cprintf("cpu%d: panic: ", 0);
+	cprintf(s);
+	cprintf("\n");
+	getcallerpcs(&s, pcs);
+	for(i=0; i<10; i++)
+		cprintf(" %p", pcs[i]);
+	panicked = 1; // freeze other CPU
+
+	for(;;)
+		;
+}
+
+#define C(x)  ((x)-'@')  // Control-x
+
+void
+consputc(int c)
+{
+	if(panicked){
+		cli();
+		for(;;)
+			;
+	}
+
+	if(c == BACKSPACE){
+		//#if defined (RPI1)
+		gpuputc('\b'); gpuputc(' '); gpuputc('\b');
+		//#endif
+		uartputc('\b'); uartputc(' '); uartputc('\b');
+	} else if(c == C('D')) {
+		//#if defined (RPI1)
+		gpuputc('^'); gpuputc('D');
+		//#endif
+		uartputc('^'); uartputc('D');
+	} else {
+		//#if defined (RPI1)
+		gpuputc(c);
+		//#endif
+		uartputc(c);
+	}
+}
+
+
+void
+consoleintr(int (*getc)(void))
+{
+	int c;
+
+	acquire(&input.lock);
+	while((c = getc()) >= 0){
+		switch(c){
+		case C('P'):  // Process listing.
+    		  procdump();
+		break;
+		case C('U'):  // Kill line.
+    		  while(input.e != input.w &&
+    				  input.buf[(input.e-1) % INPUT_BUF] != '\n'){
+    			  input.e--;
+    			  consputc(BACKSPACE);
+    		  }
+		break;
+		case C('H'): case '\x7f':  // Backspace
+			if(input.e != input.w){
+				input.e--;
+				consputc(BACKSPACE);
+			}
+			break;
+		default:
+			if(c != 0 && input.e-input.r < INPUT_BUF){
+				if(c == 0xa) break;
+				c = (c == 0xd) ? '\n' : c;
+				input.buf[input.e++ % INPUT_BUF] = c;
+				consputc(c);
+				if(c == '\n' || c == C('D') || input.e == input.r+INPUT_BUF){
+					input.w = input.e;
+					wakeup(&input.r);
+				}
+			}
+			break;
+		}
+	}
+	release(&input.lock);
+}
+
+int
+consoleread(struct inode *ip, char *dst, int n)
+{
+	uint target;
+	int c;
+
+	//cprintf("inside consoleread\n");
+	iunlock(ip);
+	target = n;
+	acquire(&input.lock);
+	while(n > 0){
+		while(input.r == input.w){
+			if(curr_proc->killed){
+				release(&input.lock);
+				ilock(ip);
+				return -1;
+			}
+			sleep(&input.r, &input.lock);
+		}
+		c = input.buf[input.r++ % INPUT_BUF];
+		if(c == C('D')){  // EOF
+			if(n < target){
+				// Save ^D for next time, to make sure
+				// caller gets a 0-byte result.
+				input.r--;
+			}
+			break;
+		}
+		*dst++ = c;
+		--n;
+		if(c == '\n')
+			break;
+	}
+	release(&input.lock);
+	ilock(ip);
+
+	return target - n;
+}
+
+void gpuinit()
+{
+	#if defined (RPI1) || defined (RPI2)
+	uint fbinforesp;
+	fbinforesp = initframebuf(framewidth, frameheight, framedepth);
+	if(fbinforesp != 0){
+		fbinfo.fbp = 0;
+		cprintf("Failed to initialize GPU framebuffer!\n");
+		return;
+	}
+
+	// convert the address into ARM space and then to the ARM VM space for the whole physical address space
+	fbinfo.fbp = (fbinfo.fbp & 0x3fffffff) + 0x40000000;
+	//cprintf("The frame buffer pointer is %x\n", fbinfo.fbp);
+        #endif
+
+
+/**************************************************
+**** The following mailbox code for setting up GPU framebuffer also works   ***
+**** This may be a better way to set up the framebuffer but left for future extension **
+
+  create_request(mailbuffer, 0x40003, 8, 0, 0); //get physical buffer width/height
+  writemailbox((uint *)mailbuffer, 8);
+  readmailbox(8);
+  if(mailbuffer[1] != 0x80000000) cprintf("error readmailbox: %x\n", 0x40003);
+  cprintf("physical width/height are %d %d\n", mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH], mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH+1]);
+
+  create_request(mailbuffer, 0x40005, 8, 0, 0); //get display depth
+  writemailbox((uint *)mailbuffer, 8);
+  readmailbox(8);
+  if(mailbuffer[1] != 0x80000000) cprintf("error readmailbox: %x\n", 0x40005);
+  cprintf("The depth of the display is %d\n", mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH]);
+
+  mb_data[0] = 1280; mb_data[1] = 1024;
+  create_request(mailbuffer, 0x48004, 8, 2, mb_data); //set virtual buffer width/height
+  writemailbox((uint *)mailbuffer, 8);
+  readmailbox(8);
+  if(mailbuffer[1] != 0x80000000) cprintf("error readmailbox: %x\n", 0x48004);
+  cprintf("The virtual width/height are %d %d\n", mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH], mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH+1]);
+
+  mb_data[0] = 0; mb_data[1] = 0;
+  create_request(mailbuffer, 0x48009, 8, 2, mb_data); //set virtual offset
+  writemailbox((uint *)mailbuffer, 8);
+  readmailbox(8);
+  if(mailbuffer[1] != 0x80000000) cprintf("error readmailbox: %x\n", 0x48009);
+  cprintf("The virtual offsets are %d %d\n", mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH], mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH+1]);
+
+  mb_data[0] = 0;
+  create_request(mailbuffer, 0x40001, 8, 1, mb_data); //allocate buffer
+  writemailbox((uint *)mailbuffer, 8);
+  readmailbox(8);
+  if(mailbuffer[1] != 0x80000000) cprintf("error readmailbox: %x\n", 0x40001);
+  cprintf("The buffer base address and size are %x %x\n", mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH], mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH+1]);
+  fb = (u32 *)(0x40000000 + mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH]);
+
+  create_request(mailbuffer, 0x40008, 8, 0, 0); //get pitch
+  writemailbox((uint *)mailbuffer, 8);
+  readmailbox(8);
+  if(mailbuffer[1] != 0x80000000) cprintf("error readmailbox: %x\n", 0x40008);
+  cprintf("The depth of the display is %d\n", mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH]);
+
+for (i=0; i< 2000; i++) fb[i] =0xffffffff;
+
+*****************/
+
+}
+
+
+void consoleinit(void)
+{
+
+	fbinfo.fbp = 0;
+	initlock(&cons.lock, "console");
+	memset(&input, 0, sizeof(input));
+	initlock(&input.lock, "input");
+
+	memset(devsw, 0, sizeof(struct devsw)*NDEV);
+	devsw[CONSOLE].write = consolewrite;
+	devsw[CONSOLE].read = consoleread;
+	cons.locking = 1;
+	panicked = 0; // must initialize in code since the compiler does not
+
+	cursor_x=cursor_y=0;
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/entry.S	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,312 @@
+/*****************************************************************
+*	entry.s
+*	by Zhiyi Huang, hzy@cs.otago.ac.nz
+*	University of Otago
+*
+********************************************************************/
+
+.section .init, "ax"
+.globl _start
+_start:
+	b boot_reset
+	b boot_sleep	// undefined
+	b boot_sleep	// svc
+	b boot_sleep	// prefetch
+	b boot_sleep	// abort
+	b boot_sleep	// hypervisor
+	b boot_sleep	// irq
+	b boot_sleep	// fiq
+
+	.balign 4
+boot_sleep:
+	wfe
+	b boot_sleep
+
+boot_reset:
+	// Switch to SVC mode, all interrupts disabled
+	.set PSR_MODE_SVC, 0x13
+	.set PSR_MODE_IRQ_DISABLED, (1<<7)
+	.set PSR_MODE_FIQ_DISABLED, (1<<6)
+	msr	cpsr_c, #(PSR_MODE_SVC + PSR_MODE_FIQ_DISABLED + PSR_MODE_IRQ_DISABLED)
+
+	// Disable caches, MMU, and flow prediction
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #(0x1 << 12)	// Disable instruction cache
+	bic	r0, r0, #(0x1 << 11)	// Disable flow prediction
+	bic	r0, r0, #(0x1 <<  2)	// Disable data cache
+	bic	r0, r0, #0x1			// Disable MMU
+	mcr	p15, 0, r0, c1, c0, 0
+
+	// Enable ACTLR.SMP bit
+	mrc	p15, 0, r0, c1, c0, 1
+	orr	r0, r0, #(1 << 6)
+	mcr	p15, 0, r0, c1, c0, 1
+
+	// Invalidate TLB and branch prediction caches.
+	mov	r0,#0
+	mcr	p15, 0, r0, c8, c7, 0	// Invalidate unified TLB
+	mcr	p15, 0, r0, c7, c5, 6	// Invalidate BPIALL
+
+	// Update ARM vector address (early binding for debug)
+	ldr	r0, =_start
+	mcr	p15, 0, r0, c12, c0, 0	// VBAR
+
+	// Cache invalidation for older Cortex-A
+	// Note: Cortex-A7 (RPI2) does not need this part.
+	// Invalidate l1 instruction cache
+	mrc p15, 1, r0, c0, c0, 1
+	tst r0, #0x3
+	mov r0, #0
+	mcrne p15, 0, r0, c7, c5, 0
+
+	// Invalidate data/unified caches
+	mrc p15, 1, r0, c0, c0, 1
+	ands r3, r0, #0x07000000
+	mov r3, r3, lsr #23
+	beq finished
+
+	mov r10, #0
+loop1:
+	add r2, r10, r10, lsr #1
+	mov r1, r0, lsr r2
+	and r1, r1, #7
+	cmp r1, #2
+	blt skip
+
+	mcr p15, 2, r10, c0, c0, 0
+	isb
+	mrc p15, 1, r1, c0, c0, 0
+	and r2, r1, #7
+	add r2, r2, #4
+	ldr r4, =0x3ff
+	ands r4, r4, r1, lsr #3
+	clz r5, r4
+	ldr r7, =0x7fff
+	ands r7, r7, r1, lsr #13
+loop2:
+	mov r9, r4
+
+loop3:
+	orr r11, r10, r9, lsl r5
+	orr r11, r11, r7, lsl r2
+	mcr p15, 0, r11, c7, c6,2
+	subs r9, r9, #1
+	bge loop3
+	subs r7, r7, #1
+	bge loop2
+
+skip:
+	add r10, r10, #2
+	cmp r3, r10
+	bgt loop1
+finished:
+
+	// MMU configurations
+	// Activate TTBR0 by TTBCR reg
+	mov	r0,#0x0
+	mcr	p15, 0, r0, c2, c0, 2
+
+	// Set master translation table address (TTBR0)
+	ldr	r0,=K_PDX_BASE
+	mov	r1, #0x08
+	orr	r1,r1,#0x40
+	orr	r0,r0,r1
+	mcr	p15, 0, r0, c2, c0, 0
+
+	// Set depricated ARM domains
+	mrc	p15, 0, r0, c3, c0, 0
+	ldr	r0, =0x55555555
+	mcr	p15, 0, r0, c3, c0, 0
+
+	// Set all CPUs to wait except the primary CPU
+	mrc p15, 0, r0, c0, c0, 5
+	ands r0, r0, #0x03
+	wfene
+	bne mp_continue
+
+	// MMU Phase 1
+	// Create master translation table (page directory index)
+mmu_phase1:
+
+	ldr	r0,=K_PDX_BASE
+	ldr	r1,=0xfff
+	ldr	r2,=0
+
+pagetable_invalidate:
+	str	r2, [r0, r1, lsl#2]
+	subs r1, r1, #1
+	bpl	pagetable_invalidate
+
+	// Page table attribute
+	// 0x14406= 0b0010 100 01 0 0000 0 01 10
+	// 0x14c06= 0b0010 100 11 0 0000 0 01 10
+	// 0x15c06= 0b0010 101 11 0 0000 0 01 10
+	//            ZGSA-TEX-AP-I-DOMN-X-CB-10
+
+	//ldr	r2,=0x14c06		//Inner cache
+	//ldr	r2,=0x15c06 	//Outer cache
+	ldr	r2,=0x14406
+
+	// Map __pa_init_start to __pa_init_start address
+	ldr	r1,=PHYSTART
+	lsr	r1, #20
+	orr	r3, r2, r1, lsl#20
+	str	r3, [r0, r1, lsl#2]
+
+	// Map __va_kernel_start to __pa_init_start address
+	ldr	r1,=PHYSTART
+	lsr	r1, #20
+	orr	r3, r2, r1, lsl#20
+	ldr	r1,=KERNBASE
+	lsr	r1, #20
+	str	r3, [r0, r1, lsl#2]
+
+	// Map device MMIO (just GPIO for LED debug)
+	ldr	r2,=0xc16	//device template
+	ldr	r1,=(MMIO_PA+0x200000)
+	lsr	r1, #20
+	orr	r3, r2, r1, lsl#20
+	ldr	r1,=(MMIO_VA+0x200000)
+	lsr	r1, #20
+	str	r3, [r0, r1, lsl#2]
+
+	// All processors will start from here after waiting:
+mp_continue:
+	ldr sp, =(KERNBASE+0x3000)
+	// Enable I/D$, MMU, and flow prediction.
+	dsb
+	ldr r1,=_pagingstart
+	mrc	p15, 0, r0, c1, c0, 0
+	orr r0, r0,	#(0x1 << 13)		// High vector
+	//orr	r0, r0, #(0x1 << 12)	// Enable I$
+	//orr	r0, r0, #(0x1 << 11)	// Enable flow prediction
+	//orr	r0, r0, #(0x1 <<  2)	// Enable D$
+	orr	r0, r0, #0x1				// Enable MMU
+	mcr	p15, 0, r0, c1, c0, 0
+	bx r1
+
+	.section .text
+.global _pagingstart
+_pagingstart:
+	bl cmain  /* call C functions now */
+	bl NotOkLoop
+
+.global acknowledge
+acknowledge:
+	//Turn on the LED
+	ldr r2,=MMIO_VA
+	add r2,r2,#0x200000
+	//Function select
+	mov r3,#1
+
+	#ifdef RPI1
+	lsl r3,#18			//Pi1 ACT LED: GPIO#16 (GPFSEL1)
+	str r3,[r2,#0x4]
+	mov r3,#1
+	lsl r3,#16
+	str r3,[r2,#0x28]	//Pi1 (GPCLR0)
+	#endif
+
+	#ifdef RPI2
+	lsl r3,#21			//Pi2 ACT LED: GPIO#47 (GPFSEL4)
+	str r3,[r2,#0x10]
+	mov r3,#1
+	lsl r3,#15
+	str r3,[r2,#0x20] //Pi2 (GPSET1)
+	#endif
+
+	bx lr
+
+.global dsb_barrier
+dsb_barrier:
+	#ifdef RPI1
+	mov r0, #0
+	mcr p15, 0, r0, c7, c10, 4
+	#else
+	dsb
+	isb
+	#endif
+	bx lr
+.global flush_dcache_all
+flush_dcache_all:
+	#ifdef RPI1
+	mov r0, #0
+	mcr p15, 0, r0, c7, c10, 4 /* dsb */
+	mov r0, #0
+	mcr p15, 0, r0, c7, c14, 0 /* invalidate d-cache */
+	#else
+	dsb
+	isb
+	#endif
+	bx lr
+.global flush_idcache
+flush_idcache:
+	#ifdef RPI1
+	mov r0, #0
+	mcr p15, 0, r0, c7, c10, 4 /* dsb */
+	mov r0, #0
+	mcr p15, 0, r0, c7, c14, 0 /* invalidate d-cache */
+	mov r0, #0
+	mcr p15, 0, r0, c7, c5, 0 /* invalidate i-cache */
+	#else
+	dsb
+	isb
+	#endif
+	bx lr
+.global flush_tlb
+flush_tlb:
+	#ifdef RPI1
+	mov r0, #0
+	mcr p15, 0, r0, c8, c7, 0
+	mcr p15, 0, r0, c7, c10, 4
+	#else
+	dsb
+	isb
+	mov	r0,#0
+	mcr	p15, 0, r0, c8, c7, 0	// Invalidate unified TLB
+	mcr	p15, 0, r0, c7, c5, 6	// Invalidate BPIALL
+	dsb
+	isb
+	#endif
+	bx lr
+.global flush_dcache /* flush a range of data cache flush_dcache(va1, va2) */
+flush_dcache:
+	#ifdef RPI1
+	mcrr p15, 0, r0, r1, c14
+	#else
+	dsb
+	isb
+	#endif
+	bx lr
+
+.global set_pgtbase /* set the page table base set_pgtbase(base) */
+set_pgtbase:
+	mcr p15, 0, r0, c2, c0
+	bx lr
+
+.global getsystemtime
+getsystemtime:
+	ldr r0, =(MMIO_VA+0x003004) /* addr of the time-stamp lower 32 bits */
+	ldrd r0, r1, [r0]
+	bx lr
+
+.section .data
+
+.align 4
+.globl font
+font:
+	.incbin "/Users/mitsuki/workspace/os/xv6_rpi2_port/source/font1.bin"
+
+.align 4
+.global _binary_initcode_start
+_binary_initcode_start:
+	.incbin "/Users/mitsuki/workspace/os/xv6_rpi2_port/source/initcode"
+.global _binary_initcode_end
+_binary_initcode_end:
+
+.align 4
+.global _binary_fs_img_start
+_binary_fs_img_start:
+        .incbin "/Users/mitsuki/workspace/os/xv6_rpi2_port/source/fs.img"
+.global _binary_fs_img_end
+_binary_fs_img_end:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/exception.S	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,226 @@
+/*****************************************************************
+*       exception.s
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+.align 4
+.section .text
+
+.global vectors
+vectors:
+	ldr pc, reset_handler 
+	ldr pc, undefintr_handler
+	ldr pc, swi_handler
+	ldr pc, prefetch_handler
+	ldr pc, data_handler
+	ldr pc, unused_handler
+	ldr pc, irq_handler
+	ldr pc, fiq_handler
+reset_handler:
+	.word hang    /* reset, in svc mode already */
+undefintr_handler:
+	.word do_und      /* undefined instruction */
+swi_handler:
+	.word do_svc    /* SWI & SVC */
+prefetch_handler:
+	.word do_pabt      /* prefetch abort */
+data_handler:
+	.word do_dabt     /* data abort */
+unused_handler:
+	.word hang      /* reserved */
+irq_handler:
+	.word do_irq    /* IRQ */
+fiq_handler:
+	.word hang    /* FIQ */
+
+hang:
+        bl NotOkLoop;
+	b hang
+do_svc:
+	push {lr}
+        mrs lr, spsr
+        push {lr}
+        mrs lr, cpsr
+        push {lr}
+        mrc p15, 0, lr, c6, c0, 2  /* read Instruction Fault Address Register (IFAR) */
+        push {lr}
+        mov lr, #0x40
+        push {lr}
+	STMFD sp, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14}
+	sub sp, sp, #60
+	mov r0, sp   /* save sp */
+	STMFD r0, {r13}^   /* save user mode sp */
+	mov r1, r1 /* three nops after STM with user mode banked registers */
+	mov r1, r1
+	mov r1, r1
+	mov sp, r0  /* restore sp */
+	sub sp, sp, #4
+	mov r0, sp
+	bl trap
+
+.global trapret
+trapret:
+	mov r0, sp /* save sp in case it is changed to sp_usr after the following LDMFD instruction */
+	LDMFD r0, {r13}^ /* restore user mode sp */
+	mov r1, r1  /* three nops after LDMFD */
+	mov r1, r1
+	mov r1, r1
+	mov sp, r0  /* restore sp */
+	add sp, sp, #4
+	LDMFD sp, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12}
+	add sp, sp, #72
+	pop {lr}
+        msr spsr, lr
+	pop {lr}
+	movs pc, lr  /* subs pc,lr,#0 */
+
+do_und:
+	STMFD sp, {r0-r4}
+	mov r0, #0x01
+	b _switchtosvc
+
+do_pabt:
+	STMFD sp, {r0-r4}
+	mov r0, #0x02
+	b _switchtosvc
+
+do_dabt:
+	STMFD sp, {r0-r4}
+	mov r0, #0x04
+	b _switchtosvc
+
+do_irq:
+	STMFD sp, {r0-r4}
+	mov r0, #0x80
+	b _switchtosvc
+_switchtosvc:
+	mrs r1, spsr
+	sub r2, lr, #4
+	mov r3, sp
+	mrs lr, cpsr
+	bic lr, #0x0000001F /* PSR_MASK */
+	orr lr, #0x00000080 /* PSR_DISABLE_IRQ */
+	orr lr, #0x00000013 /* PSR_MODE_SVC */
+	msr cpsr, lr /* switch to svc */
+	push {r2}
+	push {r1}
+	mrs r1, cpsr
+	push {r1}
+        mrc p15, 0, r1, c6, c0, 2  /* read Instruction Fault Address Register (I
+FAR) */
+        push {r1}
+        push {r0}
+	sub r1, r3, #20
+	LDMFD r1, {r0-r4}
+	STMFD sp, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14}
+	sub sp, sp, #60
+        mov r0, sp   /* save sp */
+        STMFD r0, {r13}^    /* save user mode sp */
+        mov r1, r1 /* three nops after STM with user mode banked registers */
+        mov r1, r1
+        mov r1, r1
+        mov sp, r0  /* restore sp */
+        sub sp, sp, #4
+        mov r0, sp
+
+	bl trap
+
+	mov r0, sp
+	add r0, #76
+	LDMIA r0, {r1}
+	mov r2, r1
+	and r2, #0xf
+	cmp r2, #0
+	beq _backtouser
+	msr cpsr, r1
+        add sp, #4
+	LDMFD sp, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12}
+	add sp, sp, #56
+	pop {r14}
+	add sp, sp, #16
+	pop {pc}
+
+_backtouser:
+	mov r0, sp /* save sp in case it is changed to sp_usr after the following LDMFD instruction */
+	LDMFD r0, {r13}^ /* restore user mode sp */
+	mov r1, r1  /* three nops after LDMFD */
+	mov r1, r1
+	mov r1, r1
+	mov sp, r0  /* restore sp */
+	add sp, sp, #4
+	LDMIA sp, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12}
+	add sp, sp, #72
+	pop {lr}
+	msr spsr, lr
+	pop {lr}
+	movs pc, lr  /* subs pc,lr,#0 */
+
+
+.global set_mode_sp
+set_mode_sp:
+	mrs r2, cpsr
+	msr cpsr_c,r1
+	mov sp, r0
+	mrs r0, cpsr
+	orr r0, #0x00000080 /* PSR_DISABLE_IRQ */
+	orr r0, #0x00000040 /* PSR_DISABLE_FIQ */
+	msr cpsr, r0
+	msr cpsr_c, r2
+	bx lr
+
+.global readcpsr
+readcpsr:
+	mrs r0, cpsr
+	bx lr
+
+.global cli
+cli:
+        mrs r0, cpsr
+        orr r0, #0x00000080 /* PSR_DISABLE_IRQ */
+        msr cpsr, r0
+        bx lr
+
+.global sti
+sti:
+	mrs r0, cpsr
+	bic r0, r0, #0x00000080 /* PSR_DISABLE_IRQ */
+	msr cpsr, r0
+	bx lr
+
+.global swtch
+swtch:
+	push {lr}  /* save the return address */
+	push {lr}
+	/* save old callee-save registers */
+	push {r12}
+	push {r11}
+	push {r10}
+	push {r9}
+	push {r8}
+	push {r7}
+	push {r6}
+	push {r5}
+	push {r4}
+
+	/* switch stacks */
+	str sp, [r0]
+	mov sp, r1
+
+	/* load new callee-save registers */
+	pop {r4}
+	pop {r5}
+	pop {r6}
+	pop {r7}
+	pop {r8}
+	pop {r9}
+	pop {r10}
+	pop {r11}
+	pop {r12}
+
+	/* return to previously saved pc */
+	pop {lr}
+	pop {pc}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/exec.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,104 @@
+#include "types.h"
+#include "param.h"
+#include "memlayout.h"
+#include "mmu.h"
+#include "proc.h"
+#include "defs.h"
+#include "arm.h"
+#include "elf.h"
+
+int
+exec(char *path, char **argv)
+{
+  char *last;
+  int i, off;
+  uint argc, sz, sp, ustack[3+MAXARG+1];
+  struct elfhdr elf;
+  struct inode *ip;
+  struct proghdr ph;
+  pde_t *pgdir, *oldpgdir;
+
+  if((ip = namei(path)) == 0)
+    return -1;
+  ilock(ip);
+  pgdir = 0;
+
+  // Check ELF header
+  if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))
+    goto bad;
+  if(elf.magic != ELF_MAGIC)
+    goto bad;
+
+  if((pgdir = setupkvm()) == 0)
+    goto bad;
+  // Load program into memory.
+  sz = 0;
+  for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
+    if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph))
+      goto bad;
+    if(ph.type != ELF_PROG_LOAD)
+      continue;
+    if(ph.memsz < ph.filesz)
+      goto bad;
+    if((sz = allocuvm(pgdir, sz, ph.vaddr + ph.memsz)) == 0)
+      goto bad;
+    if(loaduvm(pgdir, (char*)ph.vaddr, ip, ph.off, ph.filesz) < 0)
+      goto bad;
+  }
+  iunlockput(ip);
+  ip = 0;
+
+  // Allocate two pages at the next page boundary.
+  // Make the first inaccessible.  Use the second as the user stack.
+  sz = PGROUNDUP(sz);
+  if((sz = allocuvm(pgdir, sz, sz + 2*PGSIZE)) == 0)
+    goto bad;
+  clearpteu(pgdir, (char*)(sz - 2*PGSIZE));
+  sp = sz;
+  // Push argument strings, prepare rest of stack in ustack.
+  for(argc = 0; argv[argc]; argc++) {
+    if(argc >= MAXARG)
+      goto bad;
+    sp = (sp - (strlen(argv[argc]) + 1)) & ~3;
+    if(copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
+      goto bad;
+    ustack[3+argc] = sp;
+  }
+  ustack[3+argc] = 0;
+
+//cprintf("Exec is called argc=%d sz=%x\n", argc, sz);
+
+  ustack[0] = 0xffffffff;  // fake return PC
+  ustack[1] = argc;
+  ustack[2] = sp - (argc+1)*4;  // argv pointer
+
+  sp -= (3+argc+1) * 4;
+  if(copyout(pgdir, sp, ustack, (3+argc+1)*4) < 0)
+    goto bad;
+
+  // Save program name for debugging.
+/*  for(last=s=path; *s; s++)
+    if(*s == '/')
+      last = s+1;*/
+  last = argv[0];
+  safestrcpy(curr_proc->name, last, sizeof(curr_proc->name));
+
+  // Commit to the user image.
+  oldpgdir = curr_proc->pgdir;
+  curr_proc->pgdir = pgdir;
+  curr_proc->sz = sz;
+  curr_proc->tf->pc = elf.entry;  // main
+  curr_proc->tf->sp = sp;
+  curr_proc->tf->r0 = ustack[1];
+  curr_proc->tf->r1 = ustack[2];
+  switchuvm(curr_proc);
+  freevm(oldpgdir);
+  return 0;
+
+ bad:
+  if(pgdir)
+    freevm(pgdir);
+  if(ip)
+    iunlockput(ip);
+  return -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/file.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,162 @@
+//
+// File descriptors
+//
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "fs.h"
+#include "file.h"
+#include "spinlock.h"
+
+struct devsw devsw[NDEV];
+struct {
+  struct spinlock lock;
+  struct file file[NFILE];
+} ftable;
+
+void
+fileinit(void)
+{
+  memset(&ftable, 0, sizeof(ftable));
+  initlock(&ftable.lock, "ftable");
+}
+
+// Allocate a file structure.
+struct file*
+filealloc(void)
+{
+  struct file *f;
+
+  acquire(&ftable.lock);
+  for(f = ftable.file; f < ftable.file + NFILE; f++){
+    if(f->ref == 0){
+      f->ref = 1;
+      release(&ftable.lock);
+      return f;
+    }
+  }
+  release(&ftable.lock);
+  return 0;
+}
+
+// Increment ref count for file f.
+struct file*
+filedup(struct file *f)
+{
+  acquire(&ftable.lock);
+  if(f->ref < 1)
+    panic("filedup");
+  f->ref++;
+  release(&ftable.lock);
+  return f;
+}
+
+// Close file f.  (Decrement ref count, close when reaches 0.)
+void
+fileclose(struct file *f)
+{
+  struct file ff;
+
+  acquire(&ftable.lock);
+  if(f->ref < 1)
+    panic("fileclose");
+  if(--f->ref > 0){
+    release(&ftable.lock);
+    return;
+  }
+  ff = *f;
+  f->ref = 0;
+  f->type = FD_NONE;
+  release(&ftable.lock);
+  
+  if(ff.type == FD_PIPE)
+    pipeclose(ff.pipe, ff.writable);
+  else if(ff.type == FD_INODE){
+    begin_trans();
+    iput(ff.ip);
+    commit_trans();
+  }
+}
+
+// Get metadata about file f.
+int
+filestat(struct file *f, struct stat *st)
+{
+  if(f->type == FD_INODE){
+    ilock(f->ip);
+    stati(f->ip, st);
+    iunlock(f->ip);
+    return 0;
+  }
+  return -1;
+}
+
+// Read from file f.
+int
+fileread(struct file *f, char *addr, int n)
+{
+  int r;
+
+  if(f->readable == 0)
+    return -1;
+  if(f->type == FD_PIPE)
+    return piperead(f->pipe, addr, n);
+  if(f->type == FD_INODE){
+    ilock(f->ip);
+//cprintf("inside fileread\n");
+    if((r = readi(f->ip, addr, f->off, n)) > 0)
+      f->off += r;
+//cprintf("inside fileread: after readi rv=%x\n", r);
+    iunlock(f->ip);
+    return r;
+  }
+  panic("fileread");
+  return -1;
+}
+
+//PAGEBREAK!
+// Write to file f.
+int
+filewrite(struct file *f, char *addr, int n)
+{
+  int r;
+
+  if(f->writable == 0)
+    return -1;
+//cprintf("inside filewrite\n");
+  if(f->type == FD_PIPE)
+    return pipewrite(f->pipe, addr, n);
+  if(f->type == FD_INODE){
+    // write a few blocks at a time to avoid exceeding
+    // the maximum log transaction size, including
+    // i-node, indirect block, allocation blocks,
+    // and 2 blocks of slop for non-aligned writes.
+    // this really belongs lower down, since writei()
+    // might be writing a device like the console.
+    int max = ((LOGSIZE-1-1-2) / 2) * 512;
+    int i = 0;
+    while(i < n){
+      int n1 = n - i;
+      if(n1 > max)
+        n1 = max;
+
+      begin_trans();
+      ilock(f->ip);
+      if ((r = writei(f->ip, addr + i, f->off, n1)) > 0)
+        f->off += r;
+      iunlock(f->ip);
+      commit_trans();
+
+      if(r < 0)
+        break;
+      if(r != n1)
+        panic("short filewrite");
+      i += r;
+    }
+    return i == n ? n : -1;
+  }
+  panic("filewrite");
+  return -1;
+}
+
Binary file source/font.bin has changed
Binary file source/font1.bin has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/fs.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,656 @@
+// File system implementation.  Five layers:
+//   + Blocks: allocator for raw disk blocks.
+//   + Log: crash recovery for multi-step updates.
+//   + Files: inode allocator, reading, writing, metadata.
+//   + Directories: inode with special contents (list of other inodes!)
+//   + Names: paths like /usr/rtm/xv6/fs.c for convenient naming.
+//
+// This file contains the low-level file system manipulation 
+// routines.  The (higher-level) system call implementations
+// are in sysfile.c.
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "stat.h"
+#include "mmu.h"
+#include "proc.h"
+#include "spinlock.h"
+#include "buf.h"
+#include "fs.h"
+#include "file.h"
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+static void itrunc(struct inode*);
+
+// Read the super block.
+void
+readsb(int dev, struct superblock *sb)
+{
+  struct buf *bp;
+  
+  bp = bread(dev, 1);
+  memmove(sb, bp->data, sizeof(*sb));
+  brelse(bp);
+}
+
+// Zero a block.
+static void
+bzero(int dev, int bno)
+{
+  struct buf *bp;
+  
+  bp = bread(dev, bno);
+  memset(bp->data, 0, BSIZE);
+  log_write(bp);
+  brelse(bp);
+}
+
+// Blocks. 
+
+// Allocate a zeroed disk block.
+static uint
+balloc(uint dev)
+{
+  int b, bi, m;
+  struct buf *bp;
+  struct superblock sb;
+
+  bp = 0;
+  readsb(dev, &sb);
+  for(b = 0; b < sb.size; b += BPB){
+    bp = bread(dev, BBLOCK(b, sb.ninodes));
+    for(bi = 0; bi < BPB && b + bi < sb.size; bi++){
+      m = 1 << (bi % 8);
+      if((bp->data[bi/8] & m) == 0){  // Is block free?
+        bp->data[bi/8] |= m;  // Mark block in use.
+        log_write(bp);
+        brelse(bp);
+        bzero(dev, b + bi);
+        return b + bi;
+      }
+    }
+    brelse(bp);
+  }
+  panic("balloc: out of blocks");
+  return -1;
+}
+
+// Free a disk block.
+static void
+bfree(int dev, uint b)
+{
+  struct buf *bp;
+  struct superblock sb;
+  int bi, m;
+
+  readsb(dev, &sb);
+  bp = bread(dev, BBLOCK(b, sb.ninodes));
+  bi = b % BPB;
+  m = 1 << (bi % 8);
+  if((bp->data[bi/8] & m) == 0)
+    panic("freeing free block");
+  bp->data[bi/8] &= ~m;
+  log_write(bp);
+  brelse(bp);
+}
+
+// Inodes.
+//
+// An inode describes a single unnamed file.
+// The inode disk structure holds metadata: the file's type,
+// its size, the number of links referring to it, and the
+// list of blocks holding the file's content.
+//
+// The inodes are laid out sequentially on disk immediately after
+// the superblock. Each inode has a number, indicating its
+// position on the disk.
+//
+// The kernel keeps a cache of in-use inodes in memory
+// to provide a place for synchronizing access
+// to inodes used by multiple processes. The cached
+// inodes include book-keeping information that is
+// not stored on disk: ip->ref and ip->flags.
+//
+// An inode and its in-memory represtative go through a
+// sequence of states before they can be used by the
+// rest of the file system code.
+//
+// * Allocation: an inode is allocated if its type (on disk)
+//   is non-zero. ialloc() allocates, iput() frees if
+//   the link count has fallen to zero.
+//
+// * Referencing in cache: an entry in the inode cache
+//   is free if ip->ref is zero. Otherwise ip->ref tracks
+//   the number of in-memory pointers to the entry (open
+//   files and current directories). iget() to find or
+//   create a cache entry and increment its ref, iput()
+//   to decrement ref.
+//
+// * Valid: the information (type, size, &c) in an inode
+//   cache entry is only correct when the I_VALID bit
+//   is set in ip->flags. ilock() reads the inode from
+//   the disk and sets I_VALID, while iput() clears
+//   I_VALID if ip->ref has fallen to zero.
+//
+// * Locked: file system code may only examine and modify
+//   the information in an inode and its content if it
+//   has first locked the inode. The I_BUSY flag indicates
+//   that the inode is locked. ilock() sets I_BUSY,
+//   while iunlock clears it.
+//
+// Thus a typical sequence is:
+//   ip = iget(dev, inum)
+//   ilock(ip)
+//   ... examine and modify ip->xxx ...
+//   iunlock(ip)
+//   iput(ip)
+//
+// ilock() is separate from iget() so that system calls can
+// get a long-term reference to an inode (as for an open file)
+// and only lock it for short periods (e.g., in read()).
+// The separation also helps avoid deadlock and races during
+// pathname lookup. iget() increments ip->ref so that the inode
+// stays cached and pointers to it remain valid.
+//
+// Many internal file system functions expect the caller to
+// have locked the inodes involved; this lets callers create
+// multi-step atomic operations.
+
+struct {
+  struct spinlock lock;
+  struct inode inode[NINODE];
+} icache;
+
+void
+iinit(void)
+{
+  memset(&icache, 0, sizeof(icache));
+  initlock(&icache.lock, "icache");
+}
+
+static struct inode* iget(uint dev, uint inum);
+
+//PAGEBREAK!
+// Allocate a new inode with the given type on device dev.
+// A free inode has a type of zero.
+struct inode*
+ialloc(uint dev, short type)
+{
+  int inum;
+  struct buf *bp;
+  struct dinode *dip;
+  struct superblock sb;
+
+  readsb(dev, &sb);
+
+  for(inum = 1; inum < sb.ninodes; inum++){
+    bp = bread(dev, IBLOCK(inum));
+    dip = (struct dinode*)bp->data + inum%IPB;
+    if(dip->type == 0){  // a free inode
+      memset(dip, 0, sizeof(*dip));
+      dip->type = type;
+      log_write(bp);   // mark it allocated on the disk
+      brelse(bp);
+      return iget(dev, inum);
+    }
+    brelse(bp);
+  }
+  panic("ialloc: no inodes");
+  return 0;
+}
+
+// Copy a modified in-memory inode to disk.
+void
+iupdate(struct inode *ip)
+{
+  struct buf *bp;
+  struct dinode *dip;
+
+  bp = bread(ip->dev, IBLOCK(ip->inum));
+  dip = (struct dinode*)bp->data + ip->inum%IPB;
+  dip->type = ip->type;
+  dip->major = ip->major;
+  dip->minor = ip->minor;
+  dip->nlink = ip->nlink;
+  dip->size = ip->size;
+  memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
+  log_write(bp);
+  brelse(bp);
+}
+
+// Find the inode with number inum on device dev
+// and return the in-memory copy. Does not lock
+// the inode and does not read it from disk.
+static struct inode*
+iget(uint dev, uint inum)
+{
+  struct inode *ip, *empty;
+
+  acquire(&icache.lock);
+
+  // Is the inode already cached?
+  empty = 0;
+  for(ip = &icache.inode[0]; ip < &icache.inode[NINODE]; ip++){
+    if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){
+      ip->ref++;
+      release(&icache.lock);
+      return ip;
+    }
+    if(empty == 0 && ip->ref == 0)    // Remember empty slot.
+      empty = ip;
+  }
+
+  // Recycle an inode cache entry.
+  if(empty == 0)
+    panic("iget: no inodes");
+
+  ip = empty;
+  ip->dev = dev;
+  ip->inum = inum;
+  ip->ref = 1;
+  ip->flags = 0;
+  release(&icache.lock);
+
+  return ip;
+}
+
+// Increment reference count for ip.
+// Returns ip to enable ip = idup(ip1) idiom.
+struct inode*
+idup(struct inode *ip)
+{
+  acquire(&icache.lock);
+  ip->ref++;
+  release(&icache.lock);
+  return ip;
+}
+
+// Lock the given inode.
+// Reads the inode from disk if necessary.
+void
+ilock(struct inode *ip)
+{
+  struct buf *bp;
+  struct dinode *dip;
+
+  if(ip == 0 || ip->ref < 1)
+    panic("ilock");
+
+  acquire(&icache.lock);
+  while(ip->flags & I_BUSY)
+    sleep(ip, &icache.lock);
+  ip->flags |= I_BUSY;
+  release(&icache.lock);
+
+  if(!(ip->flags & I_VALID)){
+    bp = bread(ip->dev, IBLOCK(ip->inum));
+    dip = (struct dinode*)bp->data + ip->inum%IPB;
+    ip->type = dip->type;
+    ip->major = dip->major;
+    ip->minor = dip->minor;
+    ip->nlink = dip->nlink;
+    ip->size = dip->size;
+    memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));
+    brelse(bp);
+    ip->flags |= I_VALID;
+    if(ip->type == 0)
+      panic("ilock: no type");
+  }
+}
+
+// Unlock the given inode.
+void
+iunlock(struct inode *ip)
+{
+  if(ip == 0 || !(ip->flags & I_BUSY) || ip->ref < 1)
+    panic("iunlock");
+
+  acquire(&icache.lock);
+  ip->flags &= ~I_BUSY;
+  wakeup(ip);
+  release(&icache.lock);
+}
+
+// Drop a reference to an in-memory inode.
+// If that was the last reference, the inode cache entry can
+// be recycled.
+// If that was the last reference and the inode has no links
+// to it, free the inode (and its content) on disk.
+void
+iput(struct inode *ip)
+{
+  acquire(&icache.lock);
+  if(ip->ref == 1 && (ip->flags & I_VALID) && ip->nlink == 0){
+    // inode has no links: truncate and free inode.
+    if(ip->flags & I_BUSY)
+      panic("iput busy");
+    ip->flags |= I_BUSY;
+    release(&icache.lock);
+    itrunc(ip);
+    ip->type = 0;
+    iupdate(ip);
+    acquire(&icache.lock);
+    ip->flags = 0;
+    wakeup(ip);
+  }
+  ip->ref--;
+  release(&icache.lock);
+}
+
+// Common idiom: unlock, then put.
+void
+iunlockput(struct inode *ip)
+{
+  iunlock(ip);
+  iput(ip);
+}
+
+//PAGEBREAK!
+// Inode content
+//
+// The content (data) associated with each inode is stored
+// in blocks on the disk. The first NDIRECT block numbers
+// are listed in ip->addrs[].  The next NINDIRECT blocks are 
+// listed in block ip->addrs[NDIRECT].
+
+// Return the disk block address of the nth block in inode ip.
+// If there is no such block, bmap allocates one.
+static uint
+bmap(struct inode *ip, uint bn)
+{
+  uint addr, *a;
+  struct buf *bp;
+
+  if(bn < NDIRECT){
+    if((addr = ip->addrs[bn]) == 0)
+      ip->addrs[bn] = addr = balloc(ip->dev);
+    return addr;
+  }
+  bn -= NDIRECT;
+
+  if(bn < NINDIRECT){
+    // Load indirect block, allocating if necessary.
+    if((addr = ip->addrs[NDIRECT]) == 0)
+      ip->addrs[NDIRECT] = addr = balloc(ip->dev);
+    bp = bread(ip->dev, addr);
+    a = (uint*)bp->data;
+    if((addr = a[bn]) == 0){
+      a[bn] = addr = balloc(ip->dev);
+      log_write(bp);
+    }
+    brelse(bp);
+    return addr;
+  }
+
+  panic("bmap: out of range");
+  return -1;
+}
+
+// Truncate inode (discard contents).
+// Only called when the inode has no links
+// to it (no directory entries referring to it)
+// and has no in-memory reference to it (is
+// not an open file or current directory).
+static void
+itrunc(struct inode *ip)
+{
+  int i, j;
+  struct buf *bp;
+  uint *a;
+
+  for(i = 0; i < NDIRECT; i++){
+    if(ip->addrs[i]){
+      bfree(ip->dev, ip->addrs[i]);
+      ip->addrs[i] = 0;
+    }
+  }
+  
+  if(ip->addrs[NDIRECT]){
+    bp = bread(ip->dev, ip->addrs[NDIRECT]);
+    a = (uint*)bp->data;
+    for(j = 0; j < NINDIRECT; j++){
+      if(a[j])
+        bfree(ip->dev, a[j]);
+    }
+    brelse(bp);
+    bfree(ip->dev, ip->addrs[NDIRECT]);
+    ip->addrs[NDIRECT] = 0;
+  }
+
+  ip->size = 0;
+  iupdate(ip);
+}
+
+// Copy stat information from inode.
+void
+stati(struct inode *ip, struct stat *st)
+{
+  st->dev = ip->dev;
+  st->ino = ip->inum;
+  st->type = ip->type;
+  st->nlink = ip->nlink;
+  st->size = ip->size;
+}
+
+//PAGEBREAK!
+// Read data from inode.
+int
+readi(struct inode *ip, char *dst, uint off, uint n)
+{
+  uint tot, m;
+  struct buf *bp;
+
+  if(ip->type == T_DEV){
+    if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].read)
+      return -1;
+//cprintf("inside readi\n");
+    return devsw[ip->major].read(ip, dst, n);
+  }
+
+  if(off > ip->size || off + n < off)
+    return -1;
+  if(off + n > ip->size)
+    n = ip->size - off;
+
+  for(tot=0; tot<n; tot+=m, off+=m, dst+=m){
+    bp = bread(ip->dev, bmap(ip, off/BSIZE));
+    m = min(n - tot, BSIZE - off%BSIZE);
+    memmove(dst, bp->data + off%BSIZE, m);
+    brelse(bp);
+  }
+  return n;
+}
+
+// PAGEBREAK!
+// Write data to inode.
+int
+writei(struct inode *ip, char *src, uint off, uint n)
+{
+  uint tot, m;
+  struct buf *bp;
+//cprintf("inside writei: type=%x major=%x, func addr: %x\n", ip->type, ip->major, devsw[ip->major].write);
+  if(ip->type == T_DEV){
+    if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write)
+      return -1;
+//cprintf("before calling consolewrite: major=%x, func addr: %x\n", ip->major, devsw[ip->major].write);
+    return devsw[ip->major].write(ip, src, n);
+  }
+
+  if(off > ip->size || off + n < off)
+    return -1;
+  if(off + n > MAXFILE*BSIZE)
+    return -1;
+
+  for(tot=0; tot<n; tot+=m, off+=m, src+=m){
+    bp = bread(ip->dev, bmap(ip, off/BSIZE));
+    m = min(n - tot, BSIZE - off%BSIZE);
+    memmove(bp->data + off%BSIZE, src, m);
+    log_write(bp);
+    brelse(bp);
+  }
+
+  if(n > 0 && off > ip->size){
+    ip->size = off;
+    iupdate(ip);
+  }
+  return n;
+}
+
+//PAGEBREAK!
+// Directories
+
+int
+namecmp(const char *s, const char *t)
+{
+  return strncmp(s, t, DIRSIZ);
+}
+
+// Look for a directory entry in a directory.
+// If found, set *poff to byte offset of entry.
+struct inode*
+dirlookup(struct inode *dp, char *name, uint *poff)
+{
+  uint off, inum;
+  struct dirent de;
+
+  if(dp->type != T_DIR)
+    panic("dirlookup not DIR");
+
+  for(off = 0; off < dp->size; off += sizeof(de)){
+    if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
+      panic("dirlink read");
+    if(de.inum == 0)
+      continue;
+    if(namecmp(name, de.name) == 0){
+      // entry matches path element
+      if(poff)
+        *poff = off;
+      inum = de.inum;
+      return iget(dp->dev, inum);
+    }
+  }
+
+  return 0;
+}
+
+// Write a new directory entry (name, inum) into the directory dp.
+int
+dirlink(struct inode *dp, char *name, uint inum)
+{
+  int off;
+  struct dirent de;
+  struct inode *ip;
+
+  // Check that name is not present.
+  if((ip = dirlookup(dp, name, 0)) != 0){
+    iput(ip);
+    return -1;
+  }
+
+  // Look for an empty dirent.
+  for(off = 0; off < dp->size; off += sizeof(de)){
+    if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
+      panic("dirlink read");
+    if(de.inum == 0)
+      break;
+  }
+
+  strncpy(de.name, name, DIRSIZ);
+  de.inum = inum;
+  if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
+    panic("dirlink");
+  
+  return 0;
+}
+
+//PAGEBREAK!
+// Paths
+
+// Copy the next path element from path into name.
+// Return a pointer to the element following the copied one.
+// The returned path has no leading slashes,
+// so the caller can check *path=='\0' to see if the name is the last one.
+// If no name to remove, return 0.
+//
+// Examples:
+//   skipelem("a/bb/c", name) = "bb/c", setting name = "a"
+//   skipelem("///a//bb", name) = "bb", setting name = "a"
+//   skipelem("a", name) = "", setting name = "a"
+//   skipelem("", name) = skipelem("////", name) = 0
+//
+static char*
+skipelem(char *path, char *name)
+{
+  char *s;
+  int len;
+
+  while(*path == '/')
+    path++;
+  if(*path == 0)
+    return 0;
+  s = path;
+  while(*path != '/' && *path != 0)
+    path++;
+  len = path - s;
+  if(len >= DIRSIZ)
+    memmove(name, s, DIRSIZ);
+  else {
+    memmove(name, s, len);
+    name[len] = 0;
+  }
+  while(*path == '/')
+    path++;
+  return path;
+}
+
+// Look up and return the inode for a path name.
+// If parent != 0, return the inode for the parent and copy the final
+// path element into name, which must have room for DIRSIZ bytes.
+static struct inode*
+namex(char *path, int nameiparent, char *name)
+{
+  struct inode *ip, *next;
+
+  if(*path == '/')
+    ip = iget(ROOTDEV, ROOTINO);
+  else
+    ip = idup(curr_proc->cwd);
+
+  while((path = skipelem(path, name)) != 0){
+    ilock(ip);
+    if(ip->type != T_DIR){
+      iunlockput(ip);
+      return 0;
+    }
+    if(nameiparent && *path == '\0'){
+      // Stop one level early.
+      iunlock(ip);
+      return ip;
+    }
+    if((next = dirlookup(ip, name, 0)) == 0){
+      iunlockput(ip);
+      return 0;
+    }
+    iunlockput(ip);
+    ip = next;
+  }
+  if(nameiparent){
+    iput(ip);
+    return 0;
+  }
+  return ip;
+}
+
+struct inode*
+namei(char *path)
+{
+  char name[DIRSIZ];
+  return namex(path, 0, name);
+}
+
+struct inode*
+nameiparent(char *path, char *name)
+{
+  return namex(path, 1, name);
+}
Binary file source/fs.img has changed
Binary file source/initcode has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/kalloc.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,95 @@
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "memlayout.h"
+#include "mmu.h"
+#include "spinlock.h"
+
+void freerange(void *vstart, void *vend);
+extern char end[]; // first address after kernel loaded from ELF file
+extern unsigned int pm_size;
+
+struct run {
+  struct run *next;
+};
+
+struct {
+  struct spinlock lock;
+  int use_lock;
+  struct run *freelist;
+} kmem;
+
+// Initialization happens in two phases.
+// 1. main() calls kinit1() while still using entrypgdir to place just
+// the pages mapped by entrypgdir on free list.
+// 2. main() calls kinit2() with the rest of the physical pages
+// after installing a full page table that maps them on all cores.
+void
+kinit1(void *vstart, void *vend)
+{
+  pm_size = 0x400*0x400*32; // assume at least 32 MB physical memory
+  initlock(&kmem.lock, "kmem");
+  kmem.use_lock = 0;
+  kmem.freelist = 0;
+  freerange(vstart, vend);
+}
+
+void
+kinit2(void *vstart, void *vend)
+{
+  freerange(vstart, vend);
+  kmem.use_lock = 1;
+}
+
+void
+freerange(void *vstart, void *vend)
+{
+  char *p;
+  p = (char*)PGROUNDUP((uint)vstart);
+  for(; p + PGSIZE <= (char*)vend; p += PGSIZE)
+    kfree(p);
+}
+
+//PAGEBREAK: 21
+// Free the page of physical memory pointed at by v,
+// which normally should have been returned by a
+// call to kalloc().  (The exception is when
+// initializing the allocator; see kinit above.)
+void
+kfree(char *v)
+{
+  struct run *r;
+  if((uint)v % PGSIZE || v < end || v2p(v) >= pm_size)
+    panic("kfree");
+
+  // Fill with junk to catch dangling refs.
+  memset(v, 1, PGSIZE);
+
+  if(kmem.use_lock)
+    acquire(&kmem.lock);
+  r = (struct run*)v;
+  r->next = kmem.freelist;
+  kmem.freelist = r;
+  if(kmem.use_lock)
+    release(&kmem.lock);
+}
+
+// Allocate one 4096-byte page of physical memory.
+// Returns a pointer that the kernel can use.
+// Returns 0 if the memory cannot be allocated.
+char*
+kalloc(void)
+{
+  struct run *r;
+
+  if(kmem.use_lock)
+    acquire(&kmem.lock);
+  r = kmem.freelist;
+  if(r)
+    kmem.freelist = r->next;
+  if(kmem.use_lock)
+    release(&kmem.lock);
+  return (char*)r;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/log.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,186 @@
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "spinlock.h"
+#include "fs.h"
+#include "buf.h"
+
+// Simple logging. Each system call that might write the file system
+// should be surrounded with begin_trans() and commit_trans() calls.
+//
+// The log holds at most one transaction at a time. Commit forces
+// the log (with commit record) to disk, then installs the affected
+// blocks to disk, then erases the log. begin_trans() ensures that
+// only one system call can be in a transaction; others must wait.
+// 
+// Allowing only one transaction at a time means that the file
+// system code doesn't have to worry about the possibility of
+// one transaction reading a block that another one has modified,
+// for example an i-node block.
+//
+// Read-only system calls don't need to use transactions, though
+// this means that they may observe uncommitted data. I-node and
+// buffer locks prevent read-only calls from seeing inconsistent data.
+//
+// The log is a physical re-do log containing disk blocks.
+// The on-disk log format:
+//   header block, containing sector #s for block A, B, C, ...
+//   block A
+//   block B
+//   block C
+//   ...
+// Log appends are synchronous.
+
+// Contents of the header block, used for both the on-disk header block
+// and to keep track in memory of logged sector #s before commit.
+struct logheader {
+  int n;   
+  int sector[LOGSIZE];
+};
+
+struct log {
+  struct spinlock lock;
+  int start;
+  int size;
+  int busy; // a transaction is active
+  int dev;
+  struct logheader lh;
+};
+struct log log;
+
+static void recover_from_log(void);
+
+void
+initlog(void)
+{
+  if (sizeof(struct logheader) >= BSIZE)
+    panic("initlog: too big logheader");
+
+  struct superblock sb;
+  memset(&log, 0, sizeof(log));
+  initlock(&log.lock, "log");
+  readsb(ROOTDEV, &sb);
+  log.start = sb.size - sb.nlog;
+  log.size = sb.nlog;
+  log.dev = ROOTDEV;
+  recover_from_log();
+}
+
+// Copy committed blocks from log to their home location
+static void 
+install_trans(void)
+{
+  int tail;
+
+  for (tail = 0; tail < log.lh.n; tail++) {
+    struct buf *lbuf = bread(log.dev, log.start+tail+1); // read log block
+    struct buf *dbuf = bread(log.dev, log.lh.sector[tail]); // read dst
+    memmove(dbuf->data, lbuf->data, BSIZE);  // copy block to dst
+    bwrite(dbuf);  // write dst to disk
+    brelse(lbuf); 
+    brelse(dbuf);
+  }
+}
+
+// Read the log header from disk into the in-memory log header
+static void
+read_head(void)
+{
+  struct buf *buf = bread(log.dev, log.start);
+  struct logheader *lh = (struct logheader *) (buf->data);
+  int i;
+  log.lh.n = lh->n;
+  for (i = 0; i < log.lh.n; i++) {
+    log.lh.sector[i] = lh->sector[i];
+  }
+  brelse(buf);
+}
+
+// Write in-memory log header to disk.
+// This is the true point at which the
+// current transaction commits.
+static void
+write_head(void)
+{
+  struct buf *buf = bread(log.dev, log.start);
+  struct logheader *hb = (struct logheader *) (buf->data);
+  int i;
+  hb->n = log.lh.n;
+  for (i = 0; i < log.lh.n; i++) {
+    hb->sector[i] = log.lh.sector[i];
+  }
+  bwrite(buf);
+  brelse(buf);
+}
+
+static void
+recover_from_log(void)
+{
+  read_head();      
+  install_trans(); // if committed, copy from log to disk
+  log.lh.n = 0;
+  write_head(); // clear the log
+}
+
+void
+begin_trans(void)
+{
+  acquire(&log.lock);
+  while (log.busy) {
+    sleep(&log, &log.lock);
+  }
+  log.busy = 1;
+  release(&log.lock);
+}
+
+void
+commit_trans(void)
+{
+  if (log.lh.n > 0) {
+    write_head();    // Write header to disk -- the real commit
+    install_trans(); // Now install writes to home locations
+    log.lh.n = 0; 
+    write_head();    // Erase the transaction from the log
+  }
+  
+  acquire(&log.lock);
+  log.busy = 0;
+  wakeup(&log);
+  release(&log.lock);
+}
+
+// Caller has modified b->data and is done with the buffer.
+// Append the block to the log and record the block number, 
+// but don't write the log header (which would commit the write).
+// log_write() replaces bwrite(); a typical use is:
+//   bp = bread(...)
+//   modify bp->data[]
+//   log_write(bp)
+//   brelse(bp)
+void
+log_write(struct buf *b)
+{
+  int i;
+
+  if (log.lh.n >= LOGSIZE || log.lh.n >= log.size - 1)
+    panic("too big a transaction");
+  if (!log.busy)
+    panic("write outside of trans");
+
+  for (i = 0; i < log.lh.n; i++) {
+    if (log.lh.sector[i] == b->sector)   // log absorbtion?
+      break;
+  }
+  log.lh.sector[i] = b->sector;
+  struct buf *lbuf = bread(b->dev, log.start+i+1);
+  memmove(lbuf->data, b->data, BSIZE);
+  bwrite(lbuf);
+  brelse(lbuf);
+  if (i == log.lh.n)
+    log.lh.n++;
+  b->flags |= B_DIRTY; // XXX prevent eviction
+}
+
+//PAGEBREAK!
+// Blank page.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/mailbox.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,94 @@
+/*****************************************************************
+*       mailbox.c
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "traps.h"
+#include "spinlock.h"
+#include "fs.h"
+#include "file.h"
+#include "memlayout.h"
+#include "mmu.h"
+#include "proc.h"
+#include "arm.h"
+#include "mailbox.h"
+
+/* Note: for more tags refer to 
+https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */
+
+
+void
+create_request(volatile uint *mbuf, uint tag, uint buflen, uint len, uint *data) 
+{
+    int i;
+    volatile uint *tag_info;
+    uint nw, tag_len, total_len;
+
+    tag_info = mbuf + POS_TAG;
+
+    tag_info[POS_TAG_ID] = tag;
+    tag_info[POS_TAG_BUFLEN] = buflen;
+    tag_info[POS_TAG_DATALEN] = len & 0x7FFFFFFF;
+
+    nw = buflen >> 2;
+
+    if (!data)
+        for (i = 0; i < nw; ++i) tag_info[POS_TAG_DATA + i] = 0;
+    else
+        for (i = 0; i < nw; ++i) tag_info[POS_TAG_DATA + i] = data[i];
+
+    tag_info[POS_TAG_DATA+nw] = 0; // indicate end of tag
+
+    tag_len = mbuf[MB_HEADER_LENGTH + POS_TAG_BUFLEN];
+    total_len = (MB_HEADER_LENGTH*4) + (TAG_HEADER_LENGTH*4) + tag_len + 4;
+
+    mbuf[POS_OVERALL_LENGTH] = total_len;
+    mbuf[POS_RV] = MPI_REQUEST;
+
+}
+
+volatile uint *mailbuffer;
+
+void mailboxinit()
+{
+mailbuffer = (uint *)kalloc();
+}
+
+uint
+readmailbox(u8 channel)
+{
+	uint x, y, z;
+
+again:
+	while ((inw(MAILBOX_BASE+24) & 0x40000000) != 0);
+	x = inw(MAILBOX_BASE);
+	z = x & 0xf; y = (uint)(channel & 0xf);
+	if(z != y) goto again;
+
+	return x&0xfffffff0;
+}
+
+void
+writemailbox(uint *addr, u8 channel)
+{
+	uint x, y, a;
+
+	a = (uint)addr;
+	a -= KERNBASE;   /* convert to ARM physical address */
+	a += 0xc0000000; /* convert to VC address space */
+	x = a & 0xfffffff0;
+	y = x | (uint)(channel & 0xf);
+
+	flush_dcache_all();
+
+	while ((inw(MAILBOX_BASE+24) & 0x80000000) != 0);
+	//while ((inw(MAILBOX_BASE+0x38) & 0x80000000) != 0);
+	outw(MAILBOX_BASE+32, y);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/main.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,112 @@
+/*****************************************************************
+*       main.c
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "memlayout.h"
+#include "mmu.h"
+#include "proc.h"
+#include "arm.h"
+#include "mailbox.h"
+
+extern char end[]; // first address after kernel loaded from ELF file
+extern pde_t *kpgdir;
+extern volatile uint *mailbuffer;
+extern unsigned int pm_size;
+
+void OkLoop()
+{
+   setgpiofunc(18, 1); // gpio 18 for Ok Led, set as an output
+   while(1){
+        setgpioval(18, 0);
+        delay(2000000);
+        setgpioval(18, 1);
+        delay(2000000);
+   }
+}
+
+void NotOkLoop()
+{
+   setgpiofunc(18, 1); // gpio 18 for Ok Led, set as an output
+   while(1){
+        setgpioval(18, 0);
+        delay(500000);
+        setgpioval(18, 1);
+        delay(500000);
+   }
+}
+
+unsigned int getpmsize()
+{
+    create_request(mailbuffer, MPI_TAG_GET_ARM_MEMORY, 8, 0, 0);
+    writemailbox((uint *)mailbuffer, 8);
+    readmailbox(8);
+    if(mailbuffer[1] != 0x80000000) cprintf("Error readmailbox: %x\n", MPI_TAG_GET_ARM_MEMORY);
+    return mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH+1];
+}
+
+void machinit(void)
+{
+    memset(cpus, 0, sizeof(struct cpu)*NCPU);
+}
+
+
+void enableirqminiuart(void);
+
+uint mb_data[10];
+
+int cmain()
+{
+  mmuinit0();
+  machinit();
+
+  #if defined (RPI1) || defined (RPI2)
+  uartinit();
+  #elif defined (FVP)
+  uartinit_fvp();
+  #endif
+
+  dsb_barrier();
+
+  consoleinit();
+  cprintf("\nHello World from xv6\n");
+
+  kinit1(end, P2V((8*1024*1024)+PHYSTART)); 
+  // collect some free space (8 MB) for imminent use
+  // the physical space below 0x8000 is reserved for PGDIR and kernel stack
+  kpgdir=p2v(K_PDX_BASE);
+
+  mailboxinit();
+
+  pm_size = getpmsize();
+  cprintf("ARM memory is %x\n", pm_size);
+  
+  mmuinit1();
+  gpuinit();
+  pinit();
+  tvinit();
+  cprintf("it is ok after tvinit\n");
+  binit();
+cprintf("it is ok after binit\n");
+  fileinit();
+cprintf("it is ok after fileinit\n");
+  iinit();
+cprintf("it is ok after iinit\n");
+  ideinit();
+cprintf("it is ok after ideinit\n");
+  kinit2(P2V((8*1024*1024)+PHYSTART), P2V(pm_size));
+cprintf("it is ok after kinit2\n");
+  userinit();
+cprintf("it is ok after userinit\n");
+  timer3init();
+cprintf("it is ok after timer3init\n");
+  scheduler();
+  NotOkLoop();
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/memide.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,58 @@
+// Fake IDE disk; stores blocks in memory.
+// Useful for running kernel without scratch disk.
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "mmu.h"
+#include "proc.h"
+#include "arm.h"
+#include "traps.h"
+#include "spinlock.h"
+#include "buf.h"
+
+extern uchar _binary_fs_img_start[], _binary_fs_img_end[];
+
+static int disksize;
+static uchar *memdisk;
+
+void
+ideinit(void)
+{
+  memdisk = _binary_fs_img_start;
+  disksize = div(((uint)_binary_fs_img_end - (uint)_binary_fs_img_start), 512);
+}
+
+// Interrupt handler.
+void
+ideintr(void)
+{
+  // no-op
+}
+
+// Sync buf with disk. 
+// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
+// Else if B_VALID is not set, read buf from disk, set B_VALID.
+void
+iderw(struct buf *b)
+{
+  uchar *p;
+
+  if(!(b->flags & B_BUSY))
+    panic("iderw: buf not busy");
+  if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
+    panic("iderw: nothing to do");
+  if(b->dev != 1)
+    panic("iderw: request not for disk 1");
+  if(b->sector >= disksize)
+    panic("iderw: sector out of range");
+
+  p = memdisk + b->sector*512;
+  
+  if(b->flags & B_DIRTY){
+    b->flags &= ~B_DIRTY;
+    memmove(p, b->data, 512);
+  } else
+    memmove(b->data, p, 512);
+  b->flags |= B_VALID;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/mmu.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,120 @@
+/*****************************************************************
+ *       mmu.c
+ *       by Zhiyi Huang, hzy@cs.otago.ac.nz
+ *       University of Otago
+ *
+ ********************************************************************/
+
+
+#include "types.h"
+#include "defs.h"
+#include "memlayout.h"
+#include "mmu.h"
+
+unsigned int pm_size;
+
+void mmuinit0(void)
+{
+	pde_t *l1;
+	pte_t *l2;
+	uint pa, va;
+
+	// diable mmu
+	// use inline assembly here as there is a limit on 
+	// branch distance after mmu is disabled
+	//	asm volatile("mrc p15, 0, r1, c1, c0, 0\n\t"
+	//		"bic r1,r1,#0x00000004\n\t"	// 2:  Disable data cache
+	//		"bic r1,r1,#0x00001000\n\t" // 12: Disable instruction cache
+	//		"bic r1,r1,#0x00000800\n\t" // 11: Disable branch prediction
+	//		"bic r1,r1,#0x00000001\n\t" // 0:  Disable MMU
+	//		"mcr p15, 0, r1, c1, c0, 0\n\t"
+	//		"mov r0, #0\n\t"
+	//		"mcr p15, 0, r0, c7, c7, 0\n\t" // Invalidate Both Caches (only for ARM11)
+	//		"mcr p15, 0, r0, c8, c7, 0\n\t" // Invalidate Unified TLB
+	//		::: "r0", "r1", "cc", "memory");
+
+
+	//for(p=(uint *)0x2000; p<(uint *)0x8000; p++) *p = 0;
+
+	l1 = (pde_t *) K_PDX_BASE;
+	l2 = (pte_t *) K_PTX_BASE;
+
+	// map all of ram at KERNBASE
+	va = KERNBASE + MBYTE;
+	for(pa = PHYSTART + MBYTE; pa < PHYSTART+PHYSIZE; pa += MBYTE){
+		l1[PDX(va)] = pa|DOMAIN0|PDX_AP(K_RW)|SECTION|CACHED|BUFFERED;
+		va += MBYTE;
+	}
+
+	// identity map first MB of ram so mmu can be enabled
+	//l1[PDX(PHYSTART)] = PHYSTART|DOMAIN0|PDX_AP(K_RW)|SECTION|CACHED|BUFFERED;
+
+	// map IO region
+	va = MMIO_VA;
+	for(pa = MMIO_PA; pa < MMIO_PA+MMIO_SIZE; pa += MBYTE){
+		l1[PDX(va)] = pa|DOMAIN0|PDX_AP(K_RW)|SECTION;
+		va += MBYTE;
+	}
+
+	// map GPU memory
+	va = GPUMEMBASE;
+	for(pa = 0; pa < (uint)GPUMEMSIZE; pa += MBYTE){
+		l1[PDX(va)] = pa|DOMAIN0|PDX_AP(K_RW)|SECTION;
+		va += MBYTE;
+	}
+
+	// double map exception vectors at top of virtual memory
+	va = HVECTORS;
+	l1[PDX(va)] = (uint)l2|DOMAIN0|COARSE;
+	l2[PTX(va)] = PHYSTART|PTX_AP(K_RW)|SMALL;
+
+	//	asm volatile("mov r1, #1\n\t"
+	//                "mcr p15, 0, r1, c3, c0\n\t"
+	//                "mov r1, #0x4000\n\t"
+	//                "mcr p15, 0, r1, c2, c0\n\t"
+	//                "mrc p15, 0, r0, c1, c0, 0\n\t"
+	//                "mov r1, #0x00002000\n\t" // 13: Enable High exception vectors
+	//                "orr r1, #0x00000004\n\t" // 2:  Enable data cache
+	//                "orr r1, #0x00001000\n\t" // 12: Enable instruction cache
+	//                "orr r1, #0x00000001\n\t" // 0:  Enable MMU
+	//                "orr r0, r1\n\t"
+	//                "mcr p15, 0, r0, c1, c0, 0\n\t"
+	//                "mov r1, #1\n\t"
+	//                "mcr p15, 0, r1, c15, c12, 0\n\t" // Read Performance Monitor Control Register (ARM11)?
+	//                ::: "r0", "r1", "cc", "memory");
+
+}
+
+void
+mmuinit1(void)
+{
+	pde_t *l1;
+	uint va1, va2;
+	uint pa, va;
+
+	l1 = (pde_t*)(K_PDX_BASE);
+
+
+	// map the rest of RAM after PHYSTART+PHYSIZE
+        va = KERNBASE + PHYSIZE;
+        for(pa = PHYSTART + PHYSIZE; pa < PHYSTART+pm_size; pa += MBYTE){
+                l1[PDX(va)] = pa|DOMAIN0|PDX_AP(K_RW)|SECTION|CACHED|BUFFERED;
+                va += MBYTE;
+        }
+
+
+	// undo identity map of first MB of ram
+	l1[PDX(PHYSTART)] = 0;
+
+	// drain write buffer; writeback data cache range [va, va+n]
+	va1 = (uint)&l1[PDX(PHYSTART)];
+	va2 = va1 + sizeof(pde_t);
+	va1 = va1 & ~((uint)CACHELINESIZE-1);
+	va2 = va2 & ~((uint)CACHELINESIZE-1);
+	flush_dcache(va1, va2);
+
+	// invalidate TLB; DSB barrier used
+	flush_tlb();
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/pipe.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,121 @@
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "mmu.h"
+#include "proc.h"
+#include "fs.h"
+#include "file.h"
+#include "spinlock.h"
+
+#define PIPESIZE 512
+
+struct pipe {
+  struct spinlock lock;
+  char data[PIPESIZE];
+  uint nread;     // number of bytes read
+  uint nwrite;    // number of bytes written
+  int readopen;   // read fd is still open
+  int writeopen;  // write fd is still open
+};
+
+int
+pipealloc(struct file **f0, struct file **f1)
+{
+  struct pipe *p;
+
+  p = 0;
+  *f0 = *f1 = 0;
+  if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)
+    goto bad;
+  if((p = (struct pipe*)kalloc()) == 0)
+    goto bad;
+  memset(p, 0, PGSIZE);
+  p->readopen = 1;
+  p->writeopen = 1;
+  p->nwrite = 0;
+  p->nread = 0;
+  initlock(&p->lock, "pipe");
+  (*f0)->type = FD_PIPE;
+  (*f0)->readable = 1;
+  (*f0)->writable = 0;
+  (*f0)->pipe = p;
+  (*f1)->type = FD_PIPE;
+  (*f1)->readable = 0;
+  (*f1)->writable = 1;
+  (*f1)->pipe = p;
+  return 0;
+
+//PAGEBREAK: 20
+ bad:
+  if(p)
+    kfree((char*)p);
+  if(*f0)
+    fileclose(*f0);
+  if(*f1)
+    fileclose(*f1);
+  return -1;
+}
+
+void
+pipeclose(struct pipe *p, int writable)
+{
+  acquire(&p->lock);
+  if(writable){
+    p->writeopen = 0;
+    wakeup(&p->nread);
+  } else {
+    p->readopen = 0;
+    wakeup(&p->nwrite);
+  }
+  if(p->readopen == 0 && p->writeopen == 0){
+    release(&p->lock);
+    kfree((char*)p);
+  } else
+    release(&p->lock);
+}
+
+//PAGEBREAK: 40
+int
+pipewrite(struct pipe *p, char *addr, int n)
+{
+  int i;
+
+  acquire(&p->lock);
+  for(i = 0; i < n; i++){
+    while(p->nwrite == p->nread + PIPESIZE){  //DOC: pipewrite-full
+      if(p->readopen == 0 || curr_proc->killed){
+        release(&p->lock);
+        return -1;
+      }
+      wakeup(&p->nread);
+      sleep(&p->nwrite, &p->lock);  //DOC: pipewrite-sleep
+    }
+    p->data[p->nwrite++ % PIPESIZE] = addr[i];
+  }
+  wakeup(&p->nread);  //DOC: pipewrite-wakeup1
+  release(&p->lock);
+  return n;
+}
+
+int
+piperead(struct pipe *p, char *addr, int n)
+{
+  int i;
+
+  acquire(&p->lock);
+  while(p->nread == p->nwrite && p->writeopen){  //DOC: pipe-empty
+    if(curr_proc->killed){
+      release(&p->lock);
+      return -1;
+    }
+    sleep(&p->nread, &p->lock); //DOC: piperead-sleep
+  }
+  for(i = 0; i < n; i++){  //DOC: piperead-copy
+    if(p->nread == p->nwrite)
+      break;
+    addr[i] = p->data[p->nread++ % PIPESIZE];
+  }
+  wakeup(&p->nwrite);  //DOC: piperead-wakeup
+  release(&p->lock);
+  return i;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/proc.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,453 @@
+/*****************************************************************
+*       proc.c
+*       adapted from MIT xv6 by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "memlayout.h"
+#include "mmu.h"
+#include "arm.h"
+#include "proc.h"
+#include "spinlock.h"
+
+struct {
+  struct spinlock lock;
+  struct proc proc[NPROC];
+} ptable;
+
+static struct proc *initproc;
+
+int first_sched = 1;
+int nextpid = 1;
+extern void forkret(void);
+extern void trapret(void);
+
+static void wakeup1(void *chan);
+
+void
+pinit(void)
+{
+  memset(&ptable, 0, sizeof(ptable));
+  initlock(&ptable.lock, "ptable");
+
+}
+
+//PAGEBREAK: 32
+// Look in the process table for an UNUSED proc.
+// If found, change state to EMBRYO and initialize
+// state required to run in the kernel.
+// Otherwise return 0.
+static struct proc*
+allocproc(void)
+{
+  struct proc *p;
+  char *sp;
+
+  acquire(&ptable.lock);
+  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
+    if(p->state == UNUSED)
+      goto found;
+  release(&ptable.lock);
+  return 0;
+
+found:
+  p->state = EMBRYO;
+  p->pid = nextpid++;
+  release(&ptable.lock);
+
+  // Allocate kernel stack.
+  if((p->kstack = kalloc()) == 0){
+    p->state = UNUSED;
+    return 0;
+  }
+  memset(p->kstack, 0, PGSIZE);
+  sp = p->kstack + KSTACKSIZE;
+  
+  // Leave room for trap frame.
+  sp -= sizeof *p->tf;
+  p->tf = (struct trapframe*)sp;
+  
+  // Set up new context to start executing at forkret,
+  // which returns to trapret.
+
+  sp -= sizeof *p->context;
+  p->context = (struct context*)sp;
+  memset(p->context, 0, sizeof *p->context);
+  p->context->pc = (uint)forkret;
+  p->context->lr = (uint)trapret;
+
+  return p;
+}
+
+//PAGEBREAK: 32
+// Set up first user process.
+void
+userinit(void)
+{
+  struct proc *p;
+  extern char _binary_initcode_start[], _binary_initcode_end[];
+  uint _binary_initcode_size;
+
+  _binary_initcode_size = (uint)_binary_initcode_end - (uint)_binary_initcode_start;
+  p = allocproc();
+//cprintf("after allocproc: initcode start: %x end %x\n", _binary_initcode_start, _binary_initcode_end);
+  initproc = p;
+//cprintf("initproc is %x\n", initproc);
+  if((p->pgdir = setupkvm()) == 0)
+    panic("userinit: out of memory?");
+//cprintf("after setupkvm\n");
+  inituvm(p->pgdir, _binary_initcode_start, _binary_initcode_size);
+//cprintf("after initkvm\n");
+  p->sz = PGSIZE;
+  memset(p->tf, 0, sizeof(*p->tf));
+  p->tf->spsr = 0x10;
+  p->tf->sp = PGSIZE;
+  p->tf->pc = 0;  // beginning of initcode.S
+
+  safestrcpy(p->name, "initcode", sizeof(p->name));
+  p->cwd = namei("/");
+
+  p->state = RUNNABLE;
+}
+
+// Grow current process's memory by n bytes.
+// Return 0 on success, -1 on failure.
+int
+growproc(int n)
+{
+  uint sz;
+
+  sz = curr_proc->sz;
+  if(n > 0){
+    if((sz = allocuvm(curr_proc->pgdir, sz, sz + n)) == 0)
+      return -1;
+  } else if(n < 0){
+    if((sz = deallocuvm(curr_proc->pgdir, sz, sz + n)) == 0)
+      return -1;
+  }
+  curr_proc->sz = sz;
+  switchuvm(curr_proc);
+  return 0;
+}
+
+// Create a new process copying p as the parent.
+// Sets up stack to return as if from system call.
+// Caller must set state of returned proc to RUNNABLE.
+int
+fork(void)
+{
+  int i, pid;
+  struct proc *np;
+
+  // Allocate process.
+  if((np = allocproc()) == 0)
+    return -1;
+
+  // Copy process state from p.
+  if((np->pgdir = copyuvm(curr_proc->pgdir, curr_proc->sz)) == 0){
+    kfree(np->kstack);
+    np->kstack = 0;
+    np->state = UNUSED;
+    return -1;
+  }
+  np->sz = curr_proc->sz;
+  np->parent = curr_proc;
+  *np->tf = *curr_proc->tf;
+
+  // Clear r0 so that fork returns 0 in the child.
+  np->tf->r0 = 0;
+
+  for(i = 0; i < NOFILE; i++)
+    if(curr_proc->ofile[i])
+      np->ofile[i] = filedup(curr_proc->ofile[i]);
+  np->cwd = idup(curr_proc->cwd);
+ 
+  pid = np->pid;
+  np->state = RUNNABLE;
+  safestrcpy(np->name, curr_proc->name, sizeof(curr_proc->name));
+  return pid;
+}
+
+// Exit the current process.  Does not return.
+// An exited process remains in the zombie state
+// until its parent calls wait() to find out it exited.
+void
+exit(void)
+{
+  struct proc *p;
+  int fd;
+
+  if(curr_proc == initproc)
+    panic("init exiting");
+
+  // Close all open files.
+  for(fd = 0; fd < NOFILE; fd++){
+    if(curr_proc->ofile[fd]){
+      fileclose(curr_proc->ofile[fd]);
+      curr_proc->ofile[fd] = 0;
+    }
+  }
+
+  iput(curr_proc->cwd);
+  curr_proc->cwd = 0;
+
+  acquire(&ptable.lock);
+
+  // Parent might be sleeping in wait().
+  wakeup1(curr_proc->parent);
+
+  // Pass abandoned children to init.
+  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+    if(p->parent == curr_proc){
+      p->parent = initproc;
+      if(p->state == ZOMBIE)
+        wakeup1(initproc);
+    }
+  }
+
+  // Jump into the scheduler, never to return.
+  curr_proc->state = ZOMBIE;
+  sched();
+  panic("zombie exit");
+}
+
+// Wait for a child process to exit and return its pid.
+// Return -1 if this process has no children.
+int
+wait(void)
+{
+  struct proc *p;
+  int havekids, pid;
+
+  acquire(&ptable.lock);
+  for(;;){
+    // Scan through table looking for zombie children.
+    havekids = 0;
+    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+      if(p->parent != curr_proc)
+        continue;
+      havekids = 1;
+      if(p->state == ZOMBIE){
+        // Found one.
+        pid = p->pid;
+        kfree(p->kstack);
+        p->kstack = 0;
+        freevm(p->pgdir);
+        p->state = UNUSED;
+        p->pid = 0;
+        p->parent = 0;
+        p->name[0] = 0;
+        p->killed = 0;
+        release(&ptable.lock);
+        return pid;
+      }
+    }
+
+    // No point waiting if we don't have any children.
+    if(!havekids || curr_proc->killed){
+      release(&ptable.lock);
+      return -1;
+    }
+//cprintf("inside wait before calling sleep\n");
+    // Wait for children to exit.  (See wakeup1 call in proc_exit.)
+    sleep(curr_proc, &ptable.lock);  //DOC: wait-sleep
+  }
+}
+
+//PAGEBREAK: 42
+// Per-CPU process scheduler.
+// Each CPU calls scheduler() after setting itself up.
+// Scheduler never returns.  It loops, doing:
+//  - choose a process to run
+//  - swtch to start running that process
+//  - eventually that process transfers control
+//      via swtch back to the scheduler.
+void
+scheduler(void)
+{
+  struct proc *p;
+
+  for(;;){
+    // Enable interrupts on this processor.
+    //cprintf("before enabling interrupts\n");
+    if(first_sched) first_sched = 0;
+    else sti();
+
+    // Loop over process table looking for process to run.
+    acquire(&ptable.lock);
+    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+      if(p->state != RUNNABLE)
+        continue;
+
+      // Switch to chosen process.  It is the process's job
+      // to release ptable.lock and then reacquire it
+      // before jumping back to us.
+      curr_proc = p;
+//cprintf("before switching page table\n");
+      switchuvm(p);
+      p->state = RUNNING;
+//cprintf("after switching page table\n");
+
+      swtch(&curr_cpu->scheduler, curr_proc->context);
+
+      switchkvm();
+
+      // Process is done running for now.
+      // It should have changed its p->state before coming back.
+      curr_proc = 0;
+    }
+    release(&ptable.lock);
+
+  }
+}
+
+// Enter scheduler.  Must hold only ptable.lock
+// and have changed proc->state.
+void
+sched(void)
+{
+  int intena;
+
+  if(!holding(&ptable.lock))
+    panic("sched ptable.lock");
+  if(curr_cpu->ncli != 1)
+    panic("sched locks");
+  if(curr_proc->state == RUNNING)
+    panic("sched running");
+  if(!(readcpsr()&PSR_DISABLE_IRQ))
+    panic("sched interruptible");
+  intena = curr_cpu->intena;
+  swtch(&curr_proc->context, curr_cpu->scheduler);
+  curr_cpu->intena = intena;
+}
+
+// Give up the CPU for one scheduling round.
+void
+yield(void)
+{
+  acquire(&ptable.lock);  //DOC: yieldlock
+  curr_proc->state = RUNNABLE;
+  sched();
+  release(&ptable.lock);
+}
+
+// A fork child's very first scheduling by scheduler()
+// will swtch here.  "Return" to user space.
+void
+forkret(void)
+{
+  static int first = 1;
+  // Still holding ptable.lock from scheduler.
+  release(&ptable.lock);
+
+  if (first) {
+    // Some initialization functions must be run in the context
+    // of a regular process (e.g., they call sleep), and thus cannot 
+    // be run from main().
+    first = 0;
+    initlog();
+  }
+//cprintf("inside forkret\n");
+  
+  // Return to "caller", actually trapret (see allocproc).
+}
+
+// Atomically release lock and sleep on chan.
+// Reacquires lock when awakened.
+void
+sleep(void *chan, struct spinlock *lk)
+{
+  if(curr_proc == 0)
+    panic("sleep");
+
+  if(lk == 0)
+    panic("sleep without lk");
+
+  // Must acquire ptable.lock in order to
+  // change p->state and then call sched.
+  // Once we hold ptable.lock, we can be
+  // guaranteed that we won't miss any wakeup
+  // (wakeup runs with ptable.lock locked),
+  // so it's okay to release lk.
+  if(lk != &ptable.lock){  //DOC: sleeplock0
+    acquire(&ptable.lock);  //DOC: sleeplock1
+    release(lk);
+  }
+
+  // Go to sleep.
+  curr_proc->chan = chan;
+  curr_proc->state = SLEEPING;
+//cprintf("inside sleep before calling sched\n");
+  sched();
+
+  // Tidy up.
+  curr_proc->chan = 0;
+
+  // Reacquire original lock.
+  if(lk != &ptable.lock){  //DOC: sleeplock2
+    release(&ptable.lock);
+    acquire(lk);
+  }
+}
+
+//PAGEBREAK!
+// Wake up all processes sleeping on chan.
+// The ptable lock must be held.
+static void
+wakeup1(void *chan)
+{
+  struct proc *p;
+
+  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
+    if(p->state == SLEEPING && p->chan == chan)
+      p->state = RUNNABLE;
+}
+
+// Wake up all processes sleeping on chan.
+void
+wakeup(void *chan)
+{
+  acquire(&ptable.lock);
+  wakeup1(chan);
+  release(&ptable.lock);
+}
+
+// Kill the process with the given pid.
+// Process won't exit until it returns
+// to user space (see trap in trap.c).
+int
+kill(int pid)
+{
+  struct proc *p;
+
+  acquire(&ptable.lock);
+  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+    if(p->pid == pid){
+      p->killed = 1;
+      // Wake process from sleep if necessary.
+      if(p->state == SLEEPING)
+        p->state = RUNNABLE;
+      release(&ptable.lock);
+      return 0;
+    }
+  }
+  release(&ptable.lock);
+  return -1;
+}
+
+//PAGEBREAK: 36
+// Print a process listing to console.  For debugging.
+// Runs when user types ^P on console.
+// No lock to avoid wedging a stuck machine further.
+void
+procdump(void)
+{
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/spinlock.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,105 @@
+/*****************************************************************
+*       spinlock.c
+*       adapted from MIT xv6 by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "arm.h"
+#include "memlayout.h"
+#include "mmu.h"
+#include "proc.h"
+#include "spinlock.h"
+
+void
+initlock(struct spinlock *lk, char *name)
+{
+  lk->name = name;
+  lk->locked = 0;
+  lk->cpu = 0;
+}
+
+// Acquire the lock.
+// Loops (spins) until the lock is acquired.
+// Holding a lock for a long time may cause
+// other CPUs to waste time spinning to acquire it.
+void
+acquire(struct spinlock *lk)
+{
+  pushcli(); // disable interrupts to avoid deadlock.
+  if(holding(lk)){
+    cprintf("lock name: %s, locked: %d, cpu: %x CPSR: %x\n", lk->name, lk->locked, lk->cpu, readcpsr());
+    panic("acquire");
+  }
+
+  lk->locked = 1;
+
+  // Record info about lock acquisition for debugging.
+  lk->cpu = curr_cpu;
+}
+
+// Release the lock.
+void
+release(struct spinlock *lk)
+{
+
+  if(!holding(lk))
+    panic("release");
+
+  lk->pcs[0] = 0;
+  lk->cpu = 0;
+
+  lk->locked = 0;
+  popcli();
+}
+
+// Record the current call stack in pcs[] by following the %ebp chain.
+void
+getcallerpcs(void *v, uint pcs[])
+{
+}
+
+
+// Check whether this cpu is holding the lock.
+int
+holding(struct spinlock *lock)
+{
+int rv;
+  rv = lock->locked && lock->cpu == curr_cpu;
+/*  if(rv){
+    cprintf("The held lock: %s, locked: %d, cpu: %x\n", lock->name, lock->locked, lock->cpu);
+  }*/
+  return rv;
+}
+
+
+// Pushcli/popcli are like cli/sti except that they are matched:
+// it takes two popcli to undo two pushcli.  Also, if interrupts
+// are off, then pushcli, popcli leaves them off.
+
+void
+pushcli(void)
+{
+  uint cpsr;
+  cpsr = readcpsr();
+  cli();
+  if(curr_cpu->ncli++ == 0)
+    curr_cpu->intena = (cpsr & PSR_DISABLE_IRQ) ? 0: 1;
+}
+
+void
+popcli(void)
+{
+  if(!(readcpsr()&PSR_DISABLE_IRQ))
+    panic("popcli - interruptible");
+  if(--curr_cpu->ncli < 0)
+    panic("popcli");
+  if(curr_cpu->ncli == 0 && curr_cpu->intena)
+    sti();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/string.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,148 @@
+/*****************************************************************
+*       string.c
+*       adapted from MIT xv6 by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+#include "types.h"
+
+void*
+memsetw(int *dst, int c, uint n)
+{
+  int *p=dst;
+  uint rc=n;
+
+  while (rc-- > 0) *p++ = c;
+  return (void *)p;
+}
+
+void*
+memsetb(char *dst, int c, uint n)
+{
+  char *p=dst; 
+  uint rc=n;
+
+  while (rc-- > 0) *p++ = c;
+  return (void *)p;
+}
+
+
+void*
+memset(void *dst, int c, uint n)
+{
+  if ((int)dst%4 == 0 && n%4 == 0){
+    c &= 0xFF;
+    return memsetw((int *)dst, (c<<24)|(c<<16)|(c<<8)|c, n/4);
+  } else
+    return memsetb((char *)dst, c, n);
+}
+
+int
+memcmp(const void *v1, const void *v2, uint n)
+{
+  const u8 *s1, *s2;
+  
+  s1 = v1;
+  s2 = v2;
+  while(n-- > 0){
+    if(*s1 != *s2)
+      return *s1 - *s2;
+    s1++, s2++;
+  }
+
+  return 0;
+}
+
+void*
+memmove(void *dst, const void *src, uint n)
+{
+  const char *s;
+  char *d;
+
+  s = src;
+  d = dst;
+  if(s < d && s + n > d){
+    s += n;
+    d += n;
+    while(n-- > 0)
+      *--d = *--s;
+  } else
+    while(n-- > 0)
+      *d++ = *s++;
+
+  return dst;
+}
+
+// memcpy exists to placate GCC.  Use memmove.
+void*
+memcpy(void *dst, const void *src, uint n)
+{
+  return memmove(dst, src, n);
+}
+
+int
+strncmp(const char *p, const char *q, uint n)
+{
+  while(n > 0 && *p && *p == *q)
+    n--, p++, q++;
+  if(n == 0)
+    return 0;
+  return (u8)*p - (u8)*q;
+}
+
+char*
+strncpy(char *s, const char *t, int n)
+{
+  char *os;
+  
+  os = s;
+  while(n-- > 0 && (*s++ = *t++) != 0)
+    ;
+  while(n-- > 0)
+    *s++ = 0;
+  return os;
+}
+
+// Like strncpy but guaranteed to NUL-terminate.
+char*
+safestrcpy(char *s, const char *t, int n)
+{
+  char *os;
+  
+  os = s;
+  if(n <= 0)
+    return os;
+  while(--n > 0 && (*s++ = *t++) != 0)
+    ;
+  *s = 0;
+  return os;
+}
+
+int
+strlen(const char *s)
+{
+  int n;
+
+  for(n = 0; s[n]; n++)
+    ;
+  return n;
+}
+
+uint div(uint n, uint d)  // long division
+{
+    uint q=0, r=0;
+    int i;
+
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+        if(r >= d) {
+            r = r - d;
+            q = q | (1 << i);
+        }
+    }
+    return q;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/syscall.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,152 @@
+/*****************************************************************
+*       syscall.c
+*       adapted from MIT xv6 by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "memlayout.h"
+#include "mmu.h"
+#include "proc.h"
+#include "arm.h"
+#include "syscall.h"
+
+// User code makes a system call with INT T_SYSCALL.
+// System call number in %eax.
+// Arguments on the stack, from the user call to the C
+// library system call function. The saved user %esp points
+// to a saved program counter, and then the first argument.
+
+// Fetch the int at addr from the current process.
+int
+fetchint(uint addr, int *ip)
+{
+  if(addr >= curr_proc->sz || addr+4 > curr_proc->sz)
+    return -1;
+  *ip = *(int*)(addr);
+  return 0;
+}
+
+// Fetch the nul-terminated string at addr from the current process.
+// Doesn't actually copy the string - just sets *pp to point at it.
+// Returns length of string, not including nul.
+int
+fetchstr(uint addr, char **pp)
+{
+  char *s, *ep;
+
+  if(addr >= curr_proc->sz)
+    return -1;
+  *pp = (char*)addr;
+  ep = (char*)curr_proc->sz;
+  for(s = *pp; s < ep; s++)
+    if(*s == 0)
+      return s - *pp;
+  return -1;
+}
+
+// Fetch the nth 32-bit system call argument.
+int
+argint(int n, int *ip)
+{
+  return fetchint(curr_proc->tf->sp + 4*n, ip);
+}
+
+// Fetch the nth word-sized system call argument as a pointer
+// to a block of memory of size n bytes.  Check that the pointer
+// lies within the process address space.
+int
+argptr(int n, char **pp, int size)
+{
+  int i;
+  
+  if(argint(n, &i) < 0)
+    return -1;
+  if((uint)i >= curr_proc->sz || (uint)i+size > curr_proc->sz)
+    return -1;
+  *pp = (char*)i;
+  return 0;
+}
+
+// Fetch the nth word-sized system call argument as a string pointer.
+// Check that the pointer is valid and the string is nul-terminated.
+// (There is no shared writable memory, so the string can't change
+// between this check and being used by the kernel.)
+int
+argstr(int n, char **pp)
+{
+  int addr;
+  if(argint(n, &addr) < 0)
+    return -1;
+  return fetchstr(addr, pp);
+}
+
+extern int sys_chdir(void);
+extern int sys_close(void);
+extern int sys_dup(void);
+extern int sys_exec(void);
+extern int sys_exit(void);
+extern int sys_fork(void);
+extern int sys_fstat(void);
+extern int sys_getpid(void);
+extern int sys_kill(void);
+extern int sys_link(void);
+extern int sys_mkdir(void);
+extern int sys_mknod(void);
+extern int sys_open(void);
+extern int sys_pipe(void);
+extern int sys_read(void);
+extern int sys_sbrk(void);
+extern int sys_sleep(void);
+extern int sys_unlink(void);
+extern int sys_wait(void);
+extern int sys_write(void);
+extern int sys_uptime(void);
+
+static int (*syscalls[])(void) = {
+[SYS_fork]    sys_fork,
+[SYS_exit]    sys_exit,
+[SYS_wait]    sys_wait,
+[SYS_pipe]    sys_pipe,
+[SYS_read]    sys_read,
+[SYS_kill]    sys_kill,
+[SYS_exec]    sys_exec,
+[SYS_fstat]   sys_fstat,
+[SYS_chdir]   sys_chdir,
+[SYS_dup]     sys_dup,
+[SYS_getpid]  sys_getpid,
+[SYS_sbrk]    sys_sbrk,
+[SYS_sleep]   sys_sleep,
+[SYS_uptime]  sys_uptime,
+[SYS_open]    sys_open,
+[SYS_write]   sys_write,
+[SYS_mknod]   sys_mknod,
+[SYS_unlink]  sys_unlink,
+[SYS_link]    sys_link,
+[SYS_mkdir]   sys_mkdir,
+[SYS_close]   sys_close,
+};
+
+void
+syscall(void)
+{
+  int num;
+
+  num = curr_proc->tf->r0;
+  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
+//    cprintf("\n%d %s: sys call %d syscall address %x\n",
+//            curr_proc->pid, curr_proc->name, num, syscalls[num]);
+
+    if(num == SYS_exec) {
+	if(syscalls[num]() == -1) curr_proc->tf->r0 = -1;
+    } else curr_proc->tf->r0 = syscalls[num]();
+  } else {
+    cprintf("%d %s: unknown sys call %d\n",
+            curr_proc->pid, curr_proc->name, num);
+    curr_proc->tf->r0 = -1;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/sysfile.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,426 @@
+//
+// File-system system calls.
+// Mostly argument checking, since we don't trust
+// user code, and calls into file.c and fs.c.
+//
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "stat.h"
+#include "mmu.h"
+#include "proc.h"
+#include "fs.h"
+#include "file.h"
+#include "fcntl.h"
+
+// Fetch the nth word-sized system call argument as a file descriptor
+// and return both the descriptor and the corresponding struct file.
+static int
+argfd(int n, int *pfd, struct file **pf)
+{
+  int fd;
+  struct file *f;
+
+  if(argint(n, &fd) < 0)
+    return -1;
+  if(fd < 0 || fd >= NOFILE || (f=curr_proc->ofile[fd]) == 0)
+    return -1;
+  if(pfd)
+    *pfd = fd;
+  if(pf)
+    *pf = f;
+  return 0;
+}
+
+// Allocate a file descriptor for the given file.
+// Takes over file reference from caller on success.
+static int
+fdalloc(struct file *f)
+{
+  int fd;
+
+  for(fd = 0; fd < NOFILE; fd++){
+    if(curr_proc->ofile[fd] == 0){
+      curr_proc->ofile[fd] = f;
+      return fd;
+    }
+  }
+  return -1;
+}
+
+int
+sys_dup(void)
+{
+  struct file *f;
+  int fd;
+  
+  if(argfd(0, 0, &f) < 0)
+    return -1;
+  if((fd=fdalloc(f)) < 0)
+    return -1;
+  filedup(f);
+  return fd;
+}
+
+int
+sys_read(void)
+{
+  struct file *f;
+  int n;
+  char *p;
+
+  if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
+    return -1;
+  return fileread(f, p, n);
+}
+
+int
+sys_write(void)
+{
+  struct file *f;
+  int n;
+  char *p;
+
+  if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
+    return -1;
+//cprintf("inside sys_write\n");
+  return filewrite(f, p, n);
+}
+
+int
+sys_close(void)
+{
+  int fd;
+  struct file *f;
+  
+  if(argfd(0, &fd, &f) < 0)
+    return -1;
+  curr_proc->ofile[fd] = 0;
+  fileclose(f);
+  return 0;
+}
+
+int
+sys_fstat(void)
+{
+  struct file *f;
+  struct stat *st;
+  
+  if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
+    return -1;
+  return filestat(f, st);
+}
+
+// Create the path new as a link to the same inode as old.
+int
+sys_link(void)
+{
+  char name[DIRSIZ], *new, *old;
+  struct inode *dp, *ip;
+
+  if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
+    return -1;
+  if((ip = namei(old)) == 0)
+    return -1;
+
+  begin_trans();
+
+  ilock(ip);
+  if(ip->type == T_DIR){
+    iunlockput(ip);
+    commit_trans();
+    return -1;
+  }
+
+  ip->nlink++;
+  iupdate(ip);
+  iunlock(ip);
+
+  if((dp = nameiparent(new, name)) == 0)
+    goto bad;
+  ilock(dp);
+  if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
+    iunlockput(dp);
+    goto bad;
+  }
+  iunlockput(dp);
+  iput(ip);
+
+  commit_trans();
+
+  return 0;
+
+bad:
+  ilock(ip);
+  ip->nlink--;
+  iupdate(ip);
+  iunlockput(ip);
+  commit_trans();
+  return -1;
+}
+
+// Is the directory dp empty except for "." and ".." ?
+static int
+isdirempty(struct inode *dp)
+{
+  int off;
+  struct dirent de;
+
+  for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
+    if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
+      panic("isdirempty: readi");
+    if(de.inum != 0)
+      return 0;
+  }
+  return 1;
+}
+
+//PAGEBREAK!
+int
+sys_unlink(void)
+{
+  struct inode *ip, *dp;
+  struct dirent de;
+  char name[DIRSIZ], *path;
+  uint off;
+
+  if(argstr(0, &path) < 0)
+    return -1;
+  if((dp = nameiparent(path, name)) == 0)
+    return -1;
+
+  begin_trans();
+
+  ilock(dp);
+
+  // Cannot unlink "." or "..".
+  if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
+    goto bad;
+
+  if((ip = dirlookup(dp, name, &off)) == 0)
+    goto bad;
+  ilock(ip);
+
+  if(ip->nlink < 1)
+    panic("unlink: nlink < 1");
+  if(ip->type == T_DIR && !isdirempty(ip)){
+    iunlockput(ip);
+    goto bad;
+  }
+
+  memset(&de, 0, sizeof(de));
+  if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
+    panic("unlink: writei");
+  if(ip->type == T_DIR){
+    dp->nlink--;
+    iupdate(dp);
+  }
+  iunlockput(dp);
+
+  ip->nlink--;
+  iupdate(ip);
+  iunlockput(ip);
+
+  commit_trans();
+
+  return 0;
+
+bad:
+  iunlockput(dp);
+  commit_trans();
+  return -1;
+}
+
+static struct inode*
+create(char *path, short type, short major, short minor)
+{
+  uint off;
+  struct inode *ip, *dp;
+  char name[DIRSIZ];
+
+  if((dp = nameiparent(path, name)) == 0)
+    return 0;
+  ilock(dp);
+
+  if((ip = dirlookup(dp, name, &off)) != 0){
+    iunlockput(dp);
+    ilock(ip);
+    if(type == T_FILE && ip->type == T_FILE)
+      return ip;
+    iunlockput(ip);
+    return 0;
+  }
+
+  if((ip = ialloc(dp->dev, type)) == 0)
+    panic("create: ialloc");
+
+  ilock(ip);
+  ip->major = major;
+  ip->minor = minor;
+  ip->nlink = 1;
+  iupdate(ip);
+
+  if(type == T_DIR){  // Create . and .. entries.
+    dp->nlink++;  // for ".."
+    iupdate(dp);
+    // No ip->nlink++ for ".": avoid cyclic ref count.
+    if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
+      panic("create dots");
+  }
+
+  if(dirlink(dp, name, ip->inum) < 0)
+    panic("create: dirlink");
+
+  iunlockput(dp);
+
+  return ip;
+}
+
+int
+sys_open(void)
+{
+  char *path;
+  int fd, omode;
+  struct file *f;
+  struct inode *ip;
+
+  if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
+    return -1;
+  if(omode & O_CREATE){
+    begin_trans();
+    ip = create(path, T_FILE, 0, 0);
+    commit_trans();
+    if(ip == 0)
+      return -1;
+  } else {
+    if((ip = namei(path)) == 0)
+      return -1;
+    ilock(ip);
+    if(ip->type == T_DIR && omode != O_RDONLY){
+      iunlockput(ip);
+      return -1;
+    }
+  }
+
+  if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
+    if(f)
+      fileclose(f);
+    iunlockput(ip);
+    return -1;
+  }
+  iunlock(ip);
+
+  f->type = FD_INODE;
+  f->ip = ip;
+  f->off = 0;
+  f->readable = !(omode & O_WRONLY);
+  f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
+  return fd;
+}
+
+int
+sys_mkdir(void)
+{
+  char *path;
+  struct inode *ip;
+
+  begin_trans();
+  if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){
+    commit_trans();
+    return -1;
+  }
+  iunlockput(ip);
+  commit_trans();
+  return 0;
+}
+
+int
+sys_mknod(void)
+{
+  struct inode *ip;
+  char *path;
+  int len;
+  int major, minor;
+  
+  begin_trans();
+  if((len=argstr(0, &path)) < 0 ||
+     argint(1, &major) < 0 ||
+     argint(2, &minor) < 0 ||
+     (ip = create(path, T_DEV, major, minor)) == 0){
+    commit_trans();
+    return -1;
+  }
+  iunlockput(ip);
+  commit_trans();
+  return 0;
+}
+
+int
+sys_chdir(void)
+{
+  char *path;
+  struct inode *ip;
+
+  if(argstr(0, &path) < 0 || (ip = namei(path)) == 0)
+    return -1;
+  ilock(ip);
+  if(ip->type != T_DIR){
+    iunlockput(ip);
+    return -1;
+  }
+  iunlock(ip);
+  iput(curr_proc->cwd);
+  curr_proc->cwd = ip;
+  return 0;
+}
+
+int
+sys_exec(void)
+{
+  char *path, *argv[MAXARG];
+  int i;
+  uint uargv, uarg;
+
+  if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0){
+    return -1;
+  }
+  memset(argv, 0, sizeof(char *)*MAXARG);
+  for(i=0;; i++){
+    if(i >= NELEM(argv))
+      return -1;
+    if(fetchint(uargv+4*i, (int*)&uarg) < 0)
+      return -1;
+    if(uarg == 0){
+      argv[i] = 0;
+      break;
+    }
+    if(fetchstr(uarg, &argv[i]) < 0)
+      return -1;
+  }
+  return exec(path, argv);
+}
+
+int
+sys_pipe(void)
+{
+  int *fd;
+  struct file *rf, *wf;
+  int fd0, fd1;
+
+  if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0)
+    return -1;
+  if(pipealloc(&rf, &wf) < 0)
+    return -1;
+  fd0 = -1;
+  if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
+    if(fd0 >= 0)
+      curr_proc->ofile[fd0] = 0;
+    fileclose(rf);
+    fileclose(wf);
+    return -1;
+  }
+  fd[0] = fd0;
+  fd[1] = fd1;
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/sysproc.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,90 @@
+#include "types.h"
+#include "arm.h"
+#include "defs.h"
+#include "param.h"
+#include "memlayout.h"
+#include "mmu.h"
+#include "proc.h"
+
+int
+sys_fork(void)
+{
+  return fork();
+}
+
+int
+sys_exit(void)
+{
+  exit();
+  return 0;  // not reached
+}
+
+int
+sys_wait(void)
+{
+  return wait();
+}
+
+int
+sys_kill(void)
+{
+  int pid;
+
+  if(argint(0, &pid) < 0)
+    return -1;
+  return kill(pid);
+}
+
+int
+sys_getpid(void)
+{
+  return curr_proc->pid;
+}
+
+int
+sys_sbrk(void)
+{
+  int addr;
+  int n;
+
+  if(argint(0, &n) < 0)
+    return -1;
+  addr = curr_proc->sz;
+  if(growproc(n) < 0)
+    return -1;
+  return addr;
+}
+
+int
+sys_sleep(void)
+{
+  int n;
+  uint ticks0;
+  
+  if(argint(0, &n) < 0)
+    return -1;
+  acquire(&tickslock);
+  ticks0 = ticks;
+  while(ticks - ticks0 < n){
+    if(curr_proc->killed){
+      release(&tickslock);
+      return -1;
+    }
+    sleep(&ticks, &tickslock);
+  }
+  release(&tickslock);
+  return 0;
+}
+
+// return how many clock tick interrupts have occurred
+// since start.
+int
+sys_uptime(void)
+{
+  uint xticks;
+  
+  acquire(&tickslock);
+  xticks = ticks;
+  release(&tickslock);
+  return xticks;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/timer.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,81 @@
+/*****************************************************************
+*       timer.c
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+// The System Timer peripheral
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "memlayout.h"
+#include "proc.h"
+#include "traps.h"
+#include "arm.h"
+#include "spinlock.h"
+
+#define TIMER_REGS_BASE		(MMIO_VA+0x003000)
+#define CONTROL_STATUS		0x0 // control/status
+#define COUNTER_LO		0x4 // the time-stamp lower 32 bits
+#define COUNTER_HI		0x8 // the time-stamp higher 32 bits
+#define COMPARE0		0xc  // compare 0
+#define COMPARE1                0x10 // compare 1
+#define COMPARE2                0x14 // compare 2
+#define COMPARE3                0x18 // compare 3
+
+#define TIMER_FREQ		10000  // interrupt 100 times/sec.
+
+void 
+enabletimer3irq(void)
+{
+        intctrlregs *ip;
+
+        ip = (intctrlregs *)INT_REGS_BASE;
+        ip->gpuenable[0] |= 1 << IRQ_TIMER3; // enable the system timer3 irq
+}
+
+
+void 
+timer3init(void)
+{
+uint v;
+
+	enabletimer3irq();
+
+	v = inw(TIMER_REGS_BASE+COUNTER_LO);
+	v += TIMER_FREQ;
+
+	outw(TIMER_REGS_BASE+COMPARE3, v);
+	ticks = 0;
+}
+
+void 
+timer3intr(void)
+{
+uint v;
+//cprintf("timer3 interrupt: %x\n", inw(TIMER_REGS_BASE+CONTROL_STATUS));
+	outw(TIMER_REGS_BASE+CONTROL_STATUS, (1 << IRQ_TIMER3)); // clear timer3 irq
+
+	ticks++;
+	wakeup(&ticks);
+
+	// reset the value of compare3
+	v=inw(TIMER_REGS_BASE+COUNTER_LO);
+	v += TIMER_FREQ;
+	outw(TIMER_REGS_BASE+COMPARE3, v);
+}
+
+void
+delay(uint m)
+{
+	unsigned long long t;
+
+	if(m == 0) return;
+
+	t = getsystemtime() + m;
+	while(t != getsystemtime());
+
+	return;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/trap.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,197 @@
+/*****************************************************************
+*       trap.c
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "memlayout.h"
+#include "mmu.h"
+#include "proc.h"
+#include "arm.h"
+#include "traps.h"
+#include "spinlock.h"
+
+extern u8 *vectors;
+
+void cprintf(char*, ...);
+void dsb_barrier(void);
+void flush_idcache(void);
+void *memmove(void *dst, const void *src, uint n);
+void set_mode_sp(char *, uint);
+
+struct spinlock tickslock;
+uint ticks;
+
+void enable_intrs(void)
+{
+        intctrlregs *ip;
+
+        ip = (intctrlregs *)INT_REGS_BASE;
+        ip->gpuenable[0] |= 1 << 29;   // enable the miniuart through Aux
+        //ip->gpuenable[1] |= 1 << 25; // enable uart
+        ip->armenable |= 1 << 0;       // enable the system timer
+}
+
+
+void disable_intrs(void)
+{
+        intctrlregs *ip;
+        int disable;
+
+        ip = (intctrlregs *)INT_REGS_BASE;
+        disable = ~0;
+        ip->gpudisable[0] = disable;
+        ip->gpudisable[1] = disable;
+        ip->armdisable = disable;
+        ip->fiqctrl = 0;
+}
+
+
+void tvinit(void)
+{
+	uint *d, *s;
+	char *ptr;
+
+	/* initialize the exception vectors */
+	d = (uint *)HVECTORS;
+	s = (uint *)&vectors;
+	memmove(d, s, sizeof(Vpage0));
+
+	/* cacheuwbinv(); drain write buffer and prefetch buffer
+	 * writeback and invalidate data cache
+	 * invalidate instruction cache
+	 */
+	dsb_barrier();
+	flush_idcache();
+	ptr = kalloc();
+	memset(ptr, 0, PGSIZE);
+	set_mode_sp(ptr+4096, 0xD1);/* fiq mode, fiq and irq are disabled */
+
+	ptr = kalloc();
+	memset(ptr, 0, PGSIZE);
+	set_mode_sp(ptr+4096, 0xD2);/* irq mode, fiq and irq are disabled */
+	ptr = kalloc();
+	memset(ptr, 0, PGSIZE);
+	set_mode_sp(ptr+4096, 0xDB);/* undefined mode, fiq and irq are disabled */
+	ptr = kalloc();
+	memset(ptr, 0, PGSIZE);
+	set_mode_sp(ptr+4096, 0xD7);/*  abort mode, fiq and irq are disabled */
+	ptr = kalloc();
+	memset(ptr, 0, PGSIZE);
+	set_mode_sp(ptr+4096, 0xD6);/* secure monitor mode, fiq and irq are disabled */
+	ptr = kalloc();
+	memset(ptr, 0, PGSIZE);
+	set_mode_sp(ptr+4096, 0xDF);/* system mode, fiq and irq are disabled */
+
+	dsb_barrier();
+}
+
+void trap_oops(struct trapframe *tf)
+{
+
+cprintf("trapno: %x, spsr: %x, sp: %x, pc: %x cpsr: %x ifar: %x\n", tf->trapno, tf->spsr, tf->sp, tf->pc, tf->cpsr, tf->ifar);
+cprintf("Saved registers: r0: %x, r1: %x, r2: %x, r3: %x, r4: %x, r5: %x\n", tf->r0, tf->r1, tf->r2, tf->r3, tf->r4, tf->r5);
+cprintf("More registers: r6: %x, r7: %x, r8: %x, r9: %x, r10: %x, r11: %x, r12: %x\n", tf->r6, tf->r7, tf->r8, tf->r9, tf->r10, tf->r11, tf->r12);
+
+//NotOkLoop();
+}
+
+void handle_irq(struct trapframe *tf)
+{
+	intctrlregs *ip;
+
+/*cprintf("trapno: %x, spsr: %x, sp: %x, lr: %x cpsr: %x ifar: %x\n", tf->trapno, tf->spsr, tf->sp, tf->pc, tf->cpsr, tf->ifar);
+cprintf("Saved registers: r0: %x, r1: %x, r2: %x, r3: %x, r4: %x, r5: %x, r6: %x\n", tf->r0, tf->r1, tf->r2, tf->r3, tf->r4, tf->r5, tf->r6);
+cprintf("More registers: r6: %x, r7: %x, r8: %x, r9: %x, r10: %x, r11: %x, r12: %x, r13: %x, r14: %x\n", tf->r7, tf->r8, tf->r9, tf->r10, tf->r11, tf->r12, tf->r13, tf->r14);
+*/
+	ip = (intctrlregs *)INT_REGS_BASE;
+	while(ip->gpupending[0] || ip->gpupending[1] || ip->armpending){
+	    if(ip->gpupending[0] & (1 << 3)) {
+		timer3intr();
+	    }
+	    if(ip->gpupending[0] & (1 << 29)) {
+		miniuartintr();
+	    }
+	}
+
+}
+
+
+//PAGEBREAK: 41
+void
+trap(struct trapframe *tf)
+{
+	intctrlregs *ip;
+	uint istimer;
+
+//cprintf("Trap %d from cpu %d eip %x (cr2=0x%x)\n",
+//              tf->trapno, curr_cpu->id, tf->eip, 0);
+  //trap_oops(tf);
+  if(tf->trapno == T_SYSCALL){
+    if(curr_proc->killed)
+      exit();
+    curr_proc->tf = tf;
+    syscall();
+    if(curr_proc->killed)
+      exit();
+    return;
+  }
+
+  istimer = 0;
+  switch(tf->trapno){
+  case T_IRQ:
+	ip = (intctrlregs *)INT_REGS_BASE;
+	while(ip->gpupending[0] || ip->gpupending[1] || ip->armpending){
+	    if(ip->gpupending[0] & (1 << IRQ_TIMER3)) {
+		istimer = 1;
+		timer3intr();
+	    }
+	    if(ip->gpupending[0] & (1 << IRQ_MINIUART)) {
+		miniuartintr();
+	    }
+	}
+
+	break;
+  default:
+    if(curr_proc == 0 || (tf->spsr & 0xF) != USER_MODE){
+      // In kernel, it must be our mistake.
+      cprintf("unexpected trap %d from cpu %d addr %x spsr %x cpsr %x ifar %x\n",
+              tf->trapno, curr_cpu->id, tf->pc, tf->spsr, tf->cpsr, tf->ifar);
+      panic("trap");
+    }
+    // In user space, assume process misbehaved.
+    cprintf("pid %d %s: trap %d on cpu %d "
+            "addr 0x%x spsr 0x%x cpsr 0x%x ifar 0x%x--kill proc\n",
+            curr_proc->pid, curr_proc->name, tf->trapno, curr_cpu->id, tf->pc,
+            tf->spsr, tf->cpsr, tf->ifar);
+    curr_proc->killed = 1;
+  }
+
+  // Force process exit if it has been killed and is in user space.
+  // (If it is still executing in the kernel, let it keep running
+  // until it gets to the regular system call return.)
+
+//cprintf("Proc pointer: %d\n", curr_proc);
+  if(curr_proc){
+        if(curr_proc->killed && (tf->spsr&0xF) == USER_MODE)
+                exit();
+
+  // Force process to give up CPU on clock tick.
+  // If interrupts were on while locks held, would need to check nlock.
+        if(curr_proc->state == RUNNING && istimer)
+                yield();
+
+  // Check if the process has been killed since we yielded
+        if(curr_proc->killed && (tf->spsr&0xF) == USER_MODE)
+                exit();
+  }
+
+//cprintf("Proc pointer: %d after\n", curr_proc);
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/uart.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,137 @@
+/*****************************************************************
+*       uart.c
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+
+#include "types.h"
+#include "defs.h"
+#include "memlayout.h"
+#include "traps.h"
+#include "arm.h"
+
+#define GPFSEL0			(MMIO_VA+0x200000)
+#define GPFSEL1			(MMIO_VA+0x200004)
+#define GPFSEL2			(MMIO_VA+0x200008)
+#define GPFSEL3			(MMIO_VA+0x20000C)
+#define	GPFSEL4			(MMIO_VA+0x200010)
+#define	GPFSEL5			(MMIO_VA+0x200014)
+#define GPSET0  		(MMIO_VA+0x20001C)
+#define GPSET1			(MMIO_VA+0x200020)
+#define GPCLR0  		(MMIO_VA+0x200028)
+#define GPCLR1			(MMIO_VA+0x20002C)
+#define GPPUD       	(MMIO_VA+0x200094)
+#define GPPUDCLK0   	(MMIO_VA+0x200098)
+#define GPPUDCLK1		(MMIO_VA+0x20009C)
+
+#define AUX_IRQ			(MMIO_VA+0x215000)
+#define AUX_ENABLES     (MMIO_VA+0x215004)
+#define AUX_MU_IO_REG   (MMIO_VA+0x215040)
+#define AUX_MU_IER_REG  (MMIO_VA+0x215044)
+#define AUX_MU_IIR_REG  (MMIO_VA+0x215048)
+#define AUX_MU_LCR_REG  (MMIO_VA+0x21504C)
+#define AUX_MU_MCR_REG  (MMIO_VA+0x215050)
+#define AUX_MU_LSR_REG  (MMIO_VA+0x215054)
+#define AUX_MU_MSR_REG  (MMIO_VA+0x215058)
+#define AUX_MU_SCRATCH  (MMIO_VA+0x21505C)
+#define AUX_MU_CNTL_REG (MMIO_VA+0x215060)
+#define AUX_MU_STAT_REG (MMIO_VA+0x215064)
+#define AUX_MU_BAUD_REG (MMIO_VA+0x215068)
+
+void
+setgpioval(uint pin, uint val)
+{
+	uint sel, ssel, rsel, shift;
+
+	if(pin > 53) return;
+	if(pin >= 32) sel = 1; else sel = 0;
+	ssel = GPSET0 + (sel << 2);
+	rsel = GPCLR0 + (sel << 2);
+	if(sel) shift = (pin - 32) & 0x1f;
+	else shift = pin & 0x1f;
+	if(val == 0) outw(rsel, 1<<shift);
+	else outw(ssel, 1<<shift);
+}
+
+
+void
+setgpiofunc(uint pin, uint func)
+{
+	uint sel, data, shift;
+
+	if(pin > 53) return;
+	sel = 0;
+	while (pin > 10) {
+	    pin = pin - 10;
+	    sel++;
+	}
+	sel = (sel << 2) + GPFSEL0;
+	data = inw(sel);
+	shift = pin + (pin << 1);
+	data &= ~(7 << shift);
+	outw(sel, data);
+	data |= func << shift;
+	outw(sel, data);
+}
+
+
+void 
+uartputc(uint c)
+{
+	if(c=='\n') {
+		while(1) if(inw(AUX_MU_LSR_REG) & 0x20) break;
+		outw(AUX_MU_IO_REG, 0x0d); // add CR before LF
+	}
+	while(1) if(inw(AUX_MU_LSR_REG) & 0x20) break;
+	outw(AUX_MU_IO_REG, c);
+}
+
+static int
+uartgetc(void)
+{
+	if(inw(AUX_MU_LSR_REG)&0x1) return inw(AUX_MU_IO_REG);
+	else return -1;
+}
+
+void 
+enableirqminiuart(void)
+{
+        intctrlregs *ip;
+
+        ip = (intctrlregs *)INT_REGS_BASE;
+        ip->gpuenable[0] |= (1 << 29);   // enable the miniuart through Aux
+}
+
+
+void
+miniuartintr(void)
+{
+  consoleintr(uartgetc);
+}
+
+void 
+uartinit(void)
+{
+	outw(AUX_ENABLES, 1);
+	outw(AUX_MU_CNTL_REG, 0);
+	outw(AUX_MU_LCR_REG, 0x3);
+	outw(AUX_MU_MCR_REG, 0);
+	outw(AUX_MU_IER_REG, 0x1);
+	outw(AUX_MU_IIR_REG, 0xC7);
+	outw(AUX_MU_BAUD_REG, 270); // (250,000,000/(115200*8))-1 = 270
+
+	setgpiofunc(14, 2); // gpio 14, alt 5
+	setgpiofunc(15, 2); // gpio 15, alt 5
+
+	outw(GPPUD, 0);
+	delay(10);
+	outw(GPPUDCLK0, (1 << 14) | (1 << 15) );
+	delay(10);
+	outw(GPPUDCLK0, 0);
+
+	outw(AUX_MU_CNTL_REG, 3);
+	enableirqminiuart();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/uart_pl011.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,49 @@
+/*
+ * pl011.c
+ *
+ *  Created on: Nov 20, 2016
+ *      Author: Mahdi Amiri
+ */
+#include <fvp.h>
+#include <types.h>
+#include <defs.h>
+
+uint uart_lock; //Mutex lock
+
+void uartinit_fvp(){
+	/* Enable pl011 interrupts */
+	*(volatile uint*) FVP_PL011_UARTIMSC = FVP_PL011_UARTIMSC_RXIM;
+
+	/* Enable pl011 controller */
+	*(volatile uint*) FVP_PL011_UARTCR =
+			*(volatile uint*) FVP_PL011_UARTCR | FVP_PL011_UARTCR_UARTEN | FVP_PL011_UARTCR_TXE | FVP_PL011_UARTCR_RXE;
+	//outw(UARTCR,inw(UARTCR) | UARTCR_UARTEN | UARTCR_TXE | UARTCR_RXE);
+	//enable_irq(37,1);
+	uart_lock=0;						// Open Mutex lock
+}
+
+void uartputc_fvp(uint c)
+{
+	if(c=='\n') {
+		/* Wait until the buffer is empty */
+		while (*(volatile uint*)(FVP_PL011_UARTFR) & (FVP_PL011_UARTFR_TXFF));
+		//while (inw(UARTFR) & UARTFR_TXFF);
+		/* Put the character into the register */
+		*(volatile uint*) FVP_PL011_UARTDR = 0x0d;
+		//outw(UARTDR , c);
+	}
+	while (*(volatile uint*)(FVP_PL011_UARTFR) & (FVP_PL011_UARTFR_TXFF));
+	*(volatile uint*) FVP_PL011_UARTDR = c;
+
+
+}
+
+uint uartgetc_fvp()
+{
+    /* Wait until the buffer is empty */
+	while (*(volatile uint*)(FVP_PL011_UARTFR) & (FVP_PL011_UARTFR_RXFE));
+	//while (inw(UARTFR) & UARTFR_RXFE);
+    /* Put the character into the register */
+    return *(volatile uint*) FVP_PL011_UARTDR;
+    //outw(UARTDR , c);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/vm.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,419 @@
+/*****************************************************************
+*       vm.c
+*       adapted from MIT xv6 by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+
+#include "param.h"
+#include "types.h"
+#include "defs.h"
+#include "arm.h"
+#include "memlayout.h"
+#include "mmu.h"
+#include "proc.h"
+#include "elf.h"
+
+extern char data[];  // defined by kernel.ld
+extern char end[];  // defined by kernel.ld
+extern unsigned int pm_size;
+
+pde_t *kpgdir;  // for use in scheduler()
+
+// Return the address of the PTE in page table pgdir
+// that corresponds to virtual address va.  If alloc!=0,
+// create any required page table pages.
+static pte_t *
+walkpgdir(pde_t *pgdir, const void *va, uint l1attr, int alloc)
+{
+  pde_t *pde;
+  pte_t *pgtab;
+
+  pde = &pgdir[PDX(va)];
+  if((uint)*pde != 0){
+    pgtab = (pte_t*)p2v(PTE_ADDR(*pde));
+  } else {
+    if(!alloc || (pgtab = (pte_t*)kalloc()) == 0)
+      return 0;
+    // Make sure all those PTE_P bits are zero.
+    memset(pgtab, 0, PGSIZE);
+    // The permissions here are overly generous, but they can
+    // be further restricted by the permissions in the page table 
+    // entries, if necessary.
+    *pde = v2p(pgtab) | l1attr;
+//cprintf("the pde value is %x\n", (uint)*pde);
+  }
+  return &pgtab[PTX(va)];
+}
+
+// Create PTEs for virtual addresses starting at va that refer to
+// physical addresses starting at pa. va and size might not
+// be page-aligned.
+static int
+mappages(pde_t *pgdir, void *va, uint size, uint pa, uint l1attr, uint l2attr)
+{
+  char *a, *last;
+  pte_t *pte;
+  
+  a = (char*)PGROUNDDOWN((uint)va);
+  last = (char*)PGROUNDDOWN(((uint)va) + size - 1);
+
+//cprintf("size= %x a=%x last= %x pa=%x\n", size, a, last, pa);
+
+  if((SECTION & l1attr) != 0){// for 1 MB pages
+	for(;;){
+	    if(a > last) break;
+	    if((uint)pgdir[PDX(a)] != 0) panic("remap");
+	    pgdir[PDX(a)] = pa | l1attr;
+//cprintf("The pgdir entry: %x value: %x a=%x last= %x\n", PDX(a), pgdir[PDX(a)], a, last);
+	    a += MBYTE;
+	    pa += MBYTE;
+	}
+  } else if((COARSE & l1attr) != 0){// for 4kB pages
+	for(;;){
+	//cprintf("The pgdir is %x value: %x a=%x last= %x\n", pgdir+PDX(a), pgdir[PDX(a)], a, last);
+	    if((pte = walkpgdir(pgdir, a, l1attr, 1)) == 0)
+		return -1;
+	    if((uint)*pte != 0) panic("remap");
+	    *pte = pa | l2attr;
+//cprintf("The pte value is %x, the pde values is %x\n", (uint)*pte, pgdir[PDX(a)]);
+	    if(a == last) break;
+	    a += PGSIZE;
+	    pa += PGSIZE;
+	}
+  } else panic("Unknown page attribute");
+  return 0;
+}
+
+// There is one page table per process, plus one that's used when
+// a CPU is not running any process (kpgdir). The kernel uses the
+// current process's page table during system calls and interrupts;
+// page protection bits prevent user code from using the kernel's
+// mappings.
+// 
+// setupkvm() and exec() set up every page table like this:
+//
+//   0..KERNBASE: user memory (text+data+stack+heap), mapped to
+//                phys memory allocated by the kernel
+//   KERNBASE..KERNBASE+EXTMEM: mapped to 0..EXTMEM (for I/O space)
+//   KERNBASE+EXTMEM..data: mapped to EXTMEM..V2P(data)
+//                for the kernel's instructions and r/o data
+//   data..KERNBASE+PHYSTOP: mapped to V2P(data)..PHYSTOP, 
+//                                  rw data + free physical memory
+//   0xfe000000..0: mapped direct (devices such as ioapic)
+//
+// The kernel allocates physical memory for its heap and for user memory
+// between V2P(end) and the end of physical memory (PHYSTOP)
+// (directly addressable from end..P2V(PHYSTOP)).
+
+// This table defines the kernel's mappings, which are present in
+// every process's page table.
+static struct kmap {
+  void *virt;
+  uint phys_start;
+  uint phys_end;
+  uint l1attr;
+  uint l2attr;
+} kmap[] = {
+ { (void*)KERNBASE, PHYSTART, PHYSTOP, DOMAIN0|PDX_AP(U_RW)|SECTION|CACHED|BUFFERED, 0},
+ { (void*)MMIO_VA, MMIO_PA, MMIO_PA+MMIO_SIZE, DOMAIN0|PDX_AP(U_RW)|SECTION, 0},
+ { (void*)HVECTORS, PHYSTART, PHYSTART+TVSIZE, DOMAIN0|COARSE, PTX_AP(K_RW)|SMALL},
+};
+
+// Set up kernel part of a page table. 
+// However, since the kernel part is shared, only the user part
+// of the pgd is allocated (one page only for simplicity, so user space
+// is now limited to 1GB
+pde_t*
+setupkvm(void)
+{
+  pde_t *pgdir;
+
+  if((pgdir = (pde_t*)kalloc()) == 0)
+    return 0;
+//cprintf("inside setupkvm: pgdir=%x\n", pgdir);
+  memset(pgdir, 0, PGSIZE);
+//cprintf("after memset\n", pgdir);
+  return pgdir;
+}
+
+
+// Set up kernel part of a page table.
+pde_t*
+setupkvm_new(void)
+{
+  pde_t *pgdir;
+  struct kmap *k;
+
+/*  if((pgdir = (pde_t*)kalloc()) == 0)
+    return 0;*/
+
+  pgdir = kpgdir;
+  memset(pgdir, 0, 4*PGSIZE);
+  if (p2v(pm_size) > (void*)MMIO_VA)
+    panic("PHYSTOP (pm_size) too high");
+  k = kmap; k->phys_end = pm_size;
+  for(k = kmap; k < &kmap[NELEM(kmap)]; k++)
+    if(mappages(pgdir, k->virt, k->phys_end - k->phys_start, 
+                (uint)k->phys_start, k->l1attr, k->l2attr) < 0)
+      return 0;
+  return pgdir;
+}
+
+// Allocate one page table for the machine for the kernel address
+// space for scheduler processes.
+void
+kvmalloc(void)
+{
+  kpgdir = setupkvm_new();
+  switchkvm();
+}
+
+// Switch h/w page table register to the kernel-only page table,
+// for when no process is running.
+void
+switchkvm(void)
+{
+// do nothing here as the same pgdir is shared between kernel and user;
+// will see if the user portion of the pgdir should be removed.
+}
+
+void
+switchkvm_new(void)
+{
+  dsb_barrier();
+  flush_idcache();
+  //cprintf("The phy pgtbase address is %x\n", (uint)v2p(kpgdir));
+  set_pgtbase((uint)v2p(kpgdir));   // switch to the kernel page table
+  //cprintf("after set_pgtbase\n");
+  dsb_barrier();
+  flush_tlb();
+  //cprintf("after flush_tlb\n");
+}
+
+// Switch TSS and h/w page table to correspond to process p.
+void
+switchuvm(struct proc *p)
+{
+  pushcli();
+  //cpu->ts.esp0 = (uint)proc->kstack + KSTACKSIZE;
+  if(p->pgdir == 0)
+    panic("switchuvm: no pgdir");
+//cprintf("before copying uvm to kvm kpgdir=%x the first entry: %x\n", kpgdir, kpgdir[0]);
+  memmove((void *)kpgdir, (void *)p->pgdir, PGSIZE);  // switch to new user address space
+  flush_idcache();
+  flush_tlb();
+  popcli();
+}
+
+
+// Load the initcode into address 0 of pgdir.
+// sz must be less than a page.
+void
+inituvm(pde_t *pgdir, char *init, uint sz)
+{
+  char *mem;
+
+  if(sz >= PGSIZE)
+    panic("inituvm: more than a page");
+  mem = kalloc();
+  memset(mem, 0, PGSIZE);
+//cprintf("inituvm: page is allocated at %x\n", mem);
+  mappages(pgdir, 0, PGSIZE, v2p(mem), UVMPDXATTR, UVMPTXATTR);
+  //mappages(pgdir, 0, PGSIZE, v2p(mem), UVMPDXATTR, 0xdfe);
+
+  memmove(mem, init, sz);
+}
+
+// Load a program segment into pgdir.  addr must be page-aligned
+// and the pages from addr to addr+sz must already be mapped.
+int
+loaduvm(pde_t *pgdir, char *addr, struct inode *ip, uint offset, uint sz)
+{
+  uint i, pa, n;
+  pte_t *pte;
+
+  if((uint) addr % PGSIZE != 0)
+    panic("loaduvm: addr must be page aligned");
+  if((uint)addr + sz > USERBOUND)
+    panic("loaduvm: user address space exceeds the allowed space (> 0x80000000)");
+  for(i = 0; i < sz; i += PGSIZE){
+    if((pte = walkpgdir(pgdir, addr+i, UVMPDXATTR, 0)) == 0)
+      panic("loaduvm: address should exist");
+    pa = PTE_ADDR(*pte);
+    if(sz - i < PGSIZE)
+      n = sz - i;
+    else
+      n = PGSIZE;
+    if(readi(ip, p2v(pa), offset+i, n) != n)
+      return -1;
+  }
+  return 0;
+}
+
+// Allocate page tables and physical memory to grow process from oldsz to
+// newsz, which need not be page aligned.  Returns new size or 0 on error.
+int
+allocuvm(pde_t *pgdir, uint oldsz, uint newsz)
+{
+  char *mem;
+  uint a;
+
+  if(newsz >= USERBOUND)
+    return 0;
+  if(newsz < oldsz)
+    return oldsz;
+
+  a = PGROUNDUP(oldsz);
+  for(; a < newsz; a += PGSIZE){
+    mem = kalloc();
+    if(mem == 0){
+      cprintf("allocuvm out of memory\n");
+      deallocuvm(pgdir, newsz, oldsz);
+      return 0;
+    }
+    memset(mem, 0, PGSIZE);
+    mappages(pgdir, (char*)a, PGSIZE, v2p(mem), UVMPDXATTR, UVMPTXATTR);
+    //mappages(pgdir, (char*)a, PGSIZE, v2p(mem), UVMPDXATTR, 0xdfe);
+  }
+  return newsz;
+}
+
+// Deallocate user pages to bring the process size from oldsz to
+// newsz.  oldsz and newsz need not be page-aligned, nor does newsz
+// need to be less than oldsz.  oldsz can be larger than the actual
+// process size.  Returns the new process size.
+int
+deallocuvm(pde_t *pgdir, uint oldsz, uint newsz)
+{
+  pte_t *pte;
+  uint a, pa;
+
+  if(newsz >= oldsz)
+    return oldsz;
+
+  a = PGROUNDUP(newsz);
+  for(; a  < oldsz; a += PGSIZE){
+    pte = walkpgdir(pgdir, (char*)a, UVMPDXATTR, 0);
+    if(!pte)
+      a += (NPTENTRIES - 1) * PGSIZE;
+    else if(*pte != 0){
+      pa = PTE_ADDR(*pte);
+      if(pa == 0)
+        panic("kfree");
+      char *v = p2v(pa);
+      kfree(v);
+      *pte = 0;
+    }
+  }
+  return newsz;
+}
+
+// Free a page table and all the physical memory pages
+// in the user part.
+void
+freevm(pde_t *pgdir)
+{
+  uint i;
+
+  if(pgdir == 0)
+    panic("freevm: no pgdir");
+  deallocuvm(pgdir, USERBOUND, 0);
+  for(i = 0; i < NPDENTRIES; i++){
+    if((uint)pgdir[i] != 0){
+      char * v = p2v(PTE_ADDR(pgdir[i]));
+      kfree(v);
+    }
+  }
+  kfree((char*)pgdir);
+}
+
+// Clear PTE_U on a page. Used to create an inaccessible
+// page beneath the user stack.
+void
+clearpteu(pde_t *pgdir, char *uva)
+{
+  pte_t *pte;
+
+  pte = walkpgdir(pgdir, uva, UVMPDXATTR, 0);
+  if(pte == 0)
+    panic("clearpteu");
+  *pte &= ~PTX_AP(U_AP);
+}
+
+// Given a parent process's page table, create a copy
+// of it for a child.
+pde_t*
+copyuvm(pde_t *pgdir, uint sz)
+{
+  pde_t *d;
+  pte_t *pte;
+  uint pa, i, flags;
+  char *mem;
+
+  if((d = setupkvm()) == 0)
+    return 0;
+  for(i = 0; i < sz; i += PGSIZE){
+    if((pte = walkpgdir(pgdir, (void *) i, UVMPDXATTR, 0)) == 0)
+      panic("copyuvm: pte should exist");
+    if((uint)*pte == 0)
+      panic("copyuvm: page not present");
+    pa = PTE_ADDR(*pte);
+    flags = PTE_FLAGS(*pte);
+    if((mem = kalloc()) == 0)
+      goto bad;
+    memmove(mem, (char*)p2v(pa), PGSIZE);
+    if(mappages(d, (void*)i, PGSIZE, v2p(mem), UVMPDXATTR, flags) < 0)
+      goto bad;
+  }
+  return d;
+
+bad:
+  freevm(d);
+  return 0;
+}
+
+//PAGEBREAK!
+// Map user virtual address to kernel address.
+char*
+uva2ka(pde_t *pgdir, char *uva)
+{
+  pte_t *pte;
+
+  pte = walkpgdir(pgdir, uva, UVMPDXATTR, 0);
+  if((uint)*pte == 0)
+    return 0;
+  if(((uint)*pte & PTX_AP(U_AP)) == 0)
+    return 0;
+  return (char*)p2v(PTE_ADDR(*pte));
+}
+
+// Copy len bytes from p to user address va in page table pgdir.
+// Most useful when pgdir is not the current page table.
+// uva2ka ensures this only works for PTE_U pages.
+int
+copyout(pde_t *pgdir, uint va, void *p, uint len)
+{
+  char *buf, *pa0;
+  uint n, va0;
+
+  buf = (char*)p;
+  while(len > 0){
+    va0 = (uint)PGROUNDDOWN(va);
+    pa0 = uva2ka(pgdir, (char*)va0);
+    if(pa0 == 0)
+      return -1;
+    n = PGSIZE - (va - va0);
+    if(n > len)
+      n = len;
+    memmove(pa0 + (va - va0), buf, n);
+    len -= n;
+    buf += n;
+    va = va0 + PGSIZE;
+  }
+  return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/LICENSE	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,24 @@
+The xv6 software is:
+
+Copyright (c) 2006-2009 Frans Kaashoek, Robert Morris, Russ Cox,
+                        Massachusetts Institute of Technology
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/Makefile	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,71 @@
+# Cross-compiling (e.g., on Mac OS X)
+#TOOLPREFIX = i386-jos-elf-
+# Using native tools (e.g., on X86 Linux)
+#TOOLPREFIX = ~/gcc-arm-none-eabi-5_4-2016q3/bin/arm-none-eabi-
+
+
+# The intermediate directory for compiled object files.
+BUILD = build/
+
+CC = $(TOOLPREFIX)gcc
+AS = $(TOOLPREFIX)as
+LD = $(TOOLPREFIX)ld
+OBJCOPY = $(TOOLPREFIX)objcopy
+OBJDUMP = $(TOOLPREFIX)objdump
+#CFLAGS := -fno-pic -static -fno-builtin -fno-strict-aliasing -fshort-wchar -O2 -Wall -MD -ggdb -Werror -fno-omit-frame-pointer -fno-stack-protector -Wa,-march=armv6 -Wa,-mcpu=arm1176jzf-s
+CFLAGS := -fno-pic -static -fno-builtin -fno-strict-aliasing -fshort-wchar -O2 -Wall -MD -ggdb -Werror -fno-omit-frame-pointer -fno-stack-protector -march=armv7-a
+
+all: mkfs initcode fs.img
+
+initcode: initcode.S
+	$(CC) $(CFLAGS) -nostdinc -I. -c initcode.S
+	$(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o
+	$(OBJCOPY) -S -O binary initcode.out initcode
+	$(OBJDUMP) -S initcode.o > initcode.asm
+
+
+ULIB = ulib.o usys.o printf.o umalloc.o
+	
+_%: %.o $(ULIB)
+	$(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $@ $^
+	$(OBJDUMP) -S $@ > $*.asm
+	$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym
+
+_forktest: forktest.o $(ULIB)
+	# forktest has less library code linked in - needs to be small
+	# in order to be able to max out the proc table.
+	$(LD) $(LDFLAGS) -N -e main -Ttext 0 -o _forktest forktest.o ulib.o usys.o
+	$(OBJDUMP) -S _forktest > forktest.asm
+
+mkfs: mkfs.c ../include/fs.h
+	gcc -o mkfs mkfs.c
+	#gcc -Werror -Wall -o mkfs mkfs.c
+
+# Prevent deletion of intermediate files, e.g. cat.o, after first build, so
+# that disk image changes after first build are persistent until clean.  More
+# details:
+# http://www.gnu.org/software/make/manual/html_node/Chained-Rules.html
+.PRECIOUS: %.o
+
+UPROGS=\
+        _cat\
+        _echo\
+        _forktest\
+        _grep\
+        _init\
+        _kill\
+        _ln\
+        _ls\
+        _mkdir\
+        _rm\
+        _sh\
+        _stressfs\
+        _usertests\
+        _wc\
+        _zombie\
+
+fs.img: mkfs README $(UPROGS)
+	./mkfs fs.img README $(UPROGS)
+
+clean:
+	rm -f *.o *.d *.asm *.sym fs.img mkfs initcode initcode.out $(UPROGS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/README	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,50 @@
+xv6 is a re-implementation of Dennis Ritchie's and Ken Thompson's Unix
+Version 6 (v6).  xv6 loosely follows the structure and style of v6,
+but is implemented for a modern x86-based multiprocessor using ANSI C.
+
+ACKNOWLEDGMENTS
+
+xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer
+to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14,
+2000)). See also http://pdos.csail.mit.edu/6.828/2012/v6.html, which
+provides pointers to on-line resources for v6.
+
+xv6 borrows code from the following sources:
+    JOS (asm.h, elf.h, mmu.h, bootasm.S, ide.c, console.c, and others)
+    Plan 9 (entryother.S, mp.h, mp.c, lapic.c)
+    FreeBSD (ioapic.c)
+    NetBSD (console.c)
+
+The following people have made contributions:
+    Russ Cox (context switching, locking)
+    Cliff Frey (MP)
+    Xiao Yu (MP)
+    Nickolai Zeldovich
+    Austin Clements
+
+In addition, we are grateful for the patches contributed by Greg
+Price, Yandong Mao, and Hitoshi Mitake.
+
+The code in the files that constitute xv6 is
+Copyright 2006-2012 Frans Kaashoek, Robert Morris, and Russ Cox.
+
+ERROR REPORTS
+
+If you spot errors or have suggestions for improvement, please send
+email to Frans Kaashoek and Robert Morris (kaashoek,rtm@csail.mit.edu). 
+
+BUILDING AND RUNNING XV6
+
+To build xv6 on an x86 ELF machine (like Linux or FreeBSD), run "make".
+On non-x86 or non-ELF machines (like OS X, even on x86), you will
+need to install a cross-compiler gcc suite capable of producing x86 ELF
+binaries.  See http://pdos.csail.mit.edu/6.828/2012/tools.html.
+Then run "make TOOLPREFIX=i386-jos-elf-".
+
+To run xv6, you can use the Bochs or QEMU PC simulators. Bochs makes
+debugging easier, but QEMU is much faster. To run in Bochs, run "make
+bochs" and then type "c" at the bochs prompt. To run in QEMU, run
+"make qemu".
+
+To create a typeset version of the code, run "make xv6.pdf".  This
+requires the "mpage" utility.  See http://www.mesa.nl/pub/mpage/.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/arm.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,25 @@
+//PAGEBREAK: 36
+// Layout of the trap frame built on the stack by the
+// hardware and by trapasm.S, and passed to trap().
+struct trapframe {
+  uint trapno;
+  uint spsr; // saved cpsr from the trapped/interrupted mode
+  uint ifar; // Instruction Fault Address Register (IFAR)
+  uint cpsr;
+  uint sp; // user mode sp
+  uint lr;  // return address of the interrupted code
+  uint r12;
+  uint r11; 
+  uint r10;
+  uint r9;
+  uint r8;
+  uint r7;
+  uint r6;
+  uint r5;
+  uint r4;
+  uint r3;
+  uint r2;
+  uint r1;
+  uint r0;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/buf.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,13 @@
+struct buf {
+  int flags;
+  uint dev;
+  uint sector;
+  struct buf *prev; // LRU cache list
+  struct buf *next;
+  struct buf *qnext; // disk queue
+  uchar data[512];
+};
+#define B_BUSY  0x1  // buffer is locked by some process
+#define B_VALID 0x2  // buffer has been read from disk
+#define B_DIRTY 0x4  // buffer needs to be written to disk
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/cat.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,38 @@
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+
+char buf[512];
+
+void
+cat(int fd)
+{
+  int n;
+  while((n = read(fd, buf, sizeof(buf))) > 0)
+    write(1, buf, n);
+  if(n < 0){
+    printf(1, "cat: read error\n");
+    exit();
+  }
+}
+
+int
+main(int argc, char *argv[])
+{
+  int fd, i;
+
+  if(argc <= 1){
+    cat(0);
+    exit();
+  }
+
+  for(i = 1; i < argc; i++){
+    if((fd = open(argv[i], 0)) < 0){
+      printf(1, "cat: cannot open %s\n", argv[i]);
+      exit();
+    }
+    cat(fd);
+    close(fd);
+  }
+  exit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/defs.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,208 @@
+struct buf;
+struct context;
+struct file;
+struct inode;
+struct pipe;
+struct proc;
+struct spinlock;
+struct stat;
+struct superblock;
+
+void OkLoop(void);
+void NotOkLoop(void);
+
+void uart_putc(u32);
+void cprintf(char*, ...);
+void SetGpio(u32, u32);
+void SetGpioFunction(u32, u32);
+void Wait(u32);
+void consoleinit(void);
+void uart_init(void);
+void mmuinit1(void);
+void barriers(void);
+void dsb_barrier(void);
+void flush_tlb(void);
+void flush_dcache(u32 va1, u32 va2);
+void flush_idcache(void);
+void set_pgtbase(u32 base);
+
+// bio.c
+void            binit(void);
+struct buf*     bread(uint, uint);
+void            brelse(struct buf*);
+void            bwrite(struct buf*);
+
+// fs.c
+void            readsb(int dev, struct superblock *sb);
+int             dirlink(struct inode*, char*, uint);
+struct inode*   dirlookup(struct inode*, char*, uint*);
+struct inode*   ialloc(uint, short);
+struct inode*   idup(struct inode*);
+void            iinit(void);
+void            ilock(struct inode*);
+void            iput(struct inode*);
+void            iunlock(struct inode*);
+void            iunlockput(struct inode*);
+void            iupdate(struct inode*);
+int             namecmp(const char*, const char*);
+struct inode*   namei(char*);
+struct inode*   nameiparent(char*, char*);
+int             readi(struct inode*, char*, uint, uint);
+void            stati(struct inode*, struct stat*);
+int             writei(struct inode*, char*, uint, uint);
+
+
+// ide.c
+void            ideinit(void);
+void            ideintr(void);
+void            iderw(struct buf*);
+
+// exec.c
+int             exec(char*, char**);
+
+// file.c
+struct file*    filealloc(void);
+void            fileclose(struct file*);
+struct file*    filedup(struct file*);
+void            fileinit(void);
+int             fileread(struct file*, char*, int n);
+int             filestat(struct file*, struct stat*);
+int             filewrite(struct file*, char*, int n);
+
+
+// fs.c
+void            readsb(int dev, struct superblock *sb);
+int             dirlink(struct inode*, char*, uint);
+struct inode*   dirlookup(struct inode*, char*, uint*);
+struct inode*   ialloc(uint, short);
+struct inode*   idup(struct inode*);
+void            iinit(void);
+void            ilock(struct inode*);
+void            iput(struct inode*);
+void            iunlock(struct inode*);
+void            iunlockput(struct inode*);
+void            iupdate(struct inode*);
+int             namecmp(const char*, const char*);
+struct inode*   namei(char*);
+struct inode*   nameiparent(char*, char*);
+int             readi(struct inode*, char*, uint, uint);
+void            stati(struct inode*, struct stat*);
+int             writei(struct inode*, char*, uint, uint);
+
+// kalloc.c
+char*           kalloc(void);
+void            kfree(char*);
+void            kinit1(void*, void*);
+void            kinit2(void*, void*);
+
+
+// log.c
+void            initlog(void);
+void            log_write(struct buf*);
+void            begin_trans();
+void            commit_trans();
+
+// pipe.c
+int             pipealloc(struct file**, struct file**);
+void            pipeclose(struct pipe*, int);
+int             piperead(struct pipe*, char*, int);
+int             pipewrite(struct pipe*, char*, int);
+
+//PAGEBREAK: 16
+// proc.c
+struct proc*    copyproc(struct proc*);
+void            exit(void);
+int             fork(void);
+int             growproc(int);
+int             kill(int);
+void            pinit(void);
+void            procdump(void);
+void            scheduler(void) __attribute__((noreturn));
+void            sched(void);
+void            sleep(void*, struct spinlock*);
+void            userinit(void);
+int             wait(void);
+void            wakeup(void*);
+void            yield(void);
+
+
+// swtch.S
+void            swtch(struct context**, struct context*);
+
+// syscall.c
+int             argint(int, int*);
+int             argptr(int, char**, int);
+int             argstr(int, char**);
+int             fetchint(uint, int*);
+int             fetchstr(uint, char**);
+void            syscall(void);
+
+void kvmalloc(void);
+
+
+void drawCharacter(u8, u32, u32);
+int UsbInitialise(void);
+void KeyboardUpdate(void);
+char KeyboardGetChar(void);
+void gpuputc(u32);
+u32 KeyboardCount(void);
+u32 KeyboardGetAddress(u32);
+struct KeyboardLeds KeyboardGetLedSupport(u32);
+
+void panic(char *s);
+
+// spinlock.c
+void            acquire(struct spinlock*);
+void            getcallerpcs(void*, uint*);
+int             holding(struct spinlock*);
+void            initlock(struct spinlock*, char*);
+void            release(struct spinlock*);
+void            pushcli(void);
+void            popcli(void);
+
+// string.c
+int             memcmp(const void*, const void*, uint);
+void*           memmove(void*, const void*, uint);
+void*           memset(void*, int, uint);
+char*           safestrcpy(char*, const char*, int);
+int             strlen(const char*);
+int             strncmp(const char*, const char*, uint);
+char*           strncpy(char*, const char*, int);
+u32 		div(u32 n, u32 d);
+
+// syscall.c
+int             argint(int, int*);
+int             argptr(int, char**, int);
+int             argstr(int, char**);
+int             fetchint(uint, int*);
+int             fetchstr(uint, char**);
+void            syscall(void);
+
+// trap.c
+void            trap_init(void);
+extern uint     ticks;
+extern struct spinlock tickslock;
+
+
+// vm.c
+void            seginit(void);
+void            kvmalloc(void);
+void            vmenable(void);
+pde_t*          setupkvm(void);
+char*           uva2ka(pde_t*, char*);
+int             allocuvm(pde_t*, uint, uint);
+int             deallocuvm(pde_t*, uint, uint);
+void            freevm(pde_t*);
+void            inituvm(pde_t*, char*, uint);
+int             loaduvm(pde_t*, char*, struct inode*, uint, uint);
+pde_t*          copyuvm(pde_t*, uint);
+void            switchuvm(struct proc*);
+void            switchkvm(void);
+int             copyout(pde_t*, uint, void*, uint);
+void            clearpteu(pde_t *pgdir, char *uva);
+
+
+
+// number of elements in fixed-size array
+#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/echo.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,13 @@
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+
+int
+main(int argc, char *argv[])
+{
+  int i;
+
+  for(i = 1; i < argc; i++)
+    printf(1, "%s%s", argv[i], i+1 < argc ? " " : "\n");
+  exit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/elf.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,42 @@
+// Format of an ELF executable file
+
+#define ELF_MAGIC 0x464C457FU  // "\x7FELF" in little endian
+
+// File header
+struct elfhdr {
+  uint magic;  // must equal ELF_MAGIC
+  uchar elf[12];
+  ushort type;
+  ushort machine;
+  uint version;
+  uint entry;
+  uint phoff;
+  uint shoff;
+  uint flags;
+  ushort ehsize;
+  ushort phentsize;
+  ushort phnum;
+  ushort shentsize;
+  ushort shnum;
+  ushort shstrndx;
+};
+
+// Program section header
+struct proghdr {
+  uint type;
+  uint off;
+  uint vaddr;
+  uint paddr;
+  uint filesz;
+  uint memsz;
+  uint flags;
+  uint align;
+};
+
+// Values for Proghdr type
+#define ELF_PROG_LOAD           1
+
+// Flag bits for Proghdr flags
+#define ELF_PROG_FLAG_EXEC      1
+#define ELF_PROG_FLAG_WRITE     2
+#define ELF_PROG_FLAG_READ      4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/fcntl.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,4 @@
+#define O_RDONLY  0x000
+#define O_WRONLY  0x001
+#define O_RDWR    0x002
+#define O_CREATE  0x200
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/file.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,38 @@
+struct file {
+  enum { FD_NONE, FD_PIPE, FD_INODE } type;
+  int ref; // reference count
+  char readable;
+  char writable;
+  struct pipe *pipe;
+  struct inode *ip;
+  uint off;
+};
+
+
+// in-memory copy of an inode
+struct inode {
+  uint dev;           // Device number
+  uint inum;          // Inode number
+  int ref;            // Reference count
+  int flags;          // I_BUSY, I_VALID
+
+  short type;         // copy of disk inode
+  short major;
+  short minor;
+  short nlink;
+  uint size;
+  uint addrs[NDIRECT+1];
+};
+#define I_BUSY 0x1
+#define I_VALID 0x2
+
+// table mapping major device number to
+// device functions
+struct devsw {
+  int (*read)(struct inode*, char*, int);
+  int (*write)(struct inode*, char*, int);
+};
+
+extern struct devsw devsw[];
+
+#define CONSOLE 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/forktest.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,56 @@
+// Test that fork fails gracefully.
+// Tiny executable so that the limit can be filling the proc table.
+
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+
+#define N  1000
+
+void
+printf(int fd, char *s, ...)
+{
+  write(fd, s, strlen(s));
+}
+
+void
+forktest(void)
+{
+  int n, pid;
+
+  printf(1, "fork test\n");
+
+  for(n=0; n<N; n++){
+    pid = fork();
+    if(pid < 0)
+      break;
+    if(pid == 0)
+      exit();
+  }
+  
+  if(n == N){
+    printf(1, "fork claimed to work N times!\n", N);
+    exit();
+  }
+  
+  for(; n > 0; n--){
+    if(wait() < 0){
+      printf(1, "wait stopped early\n");
+      exit();
+    }
+  }
+  
+  if(wait() != -1){
+    printf(1, "wait got too many\n");
+    exit();
+  }
+  
+  printf(1, "fork test OK\n");
+}
+
+int
+main(void)
+{
+  forktest();
+  exit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/fs.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,55 @@
+// On-disk file system format. 
+// Both the kernel and user programs use this header file.
+
+// Block 0 is unused.
+// Block 1 is super block.
+// Blocks 2 through sb.ninodes/IPB hold inodes.
+// Then free bitmap blocks holding sb.size bits.
+// Then sb.nblocks data blocks.
+// Then sb.nlog log blocks.
+
+#define ROOTINO 1  // root i-number
+#define BSIZE 512  // block size
+
+// File system super block
+struct superblock {
+  uint size;         // Size of file system image (blocks)
+  uint nblocks;      // Number of data blocks
+  uint ninodes;      // Number of inodes.
+  uint nlog;         // Number of log blocks
+};
+
+#define NDIRECT 12
+#define NINDIRECT (BSIZE / sizeof(uint))
+#define MAXFILE (NDIRECT + NINDIRECT)
+
+// On-disk inode structure
+struct dinode {
+  short type;           // File type
+  short major;          // Major device number (T_DEV only)
+  short minor;          // Minor device number (T_DEV only)
+  short nlink;          // Number of links to inode in file system
+  uint size;            // Size of file (bytes)
+  uint addrs[NDIRECT+1];   // Data block addresses
+};
+
+// Inodes per block.
+#define IPB           (BSIZE / sizeof(struct dinode))
+
+// Block containing inode i
+#define IBLOCK(i)     ((i) / IPB + 2)
+
+// Bitmap bits per block
+#define BPB           (BSIZE*8)
+
+// Block containing bit for block b
+#define BBLOCK(b, ninodes) (b/BPB + (ninodes)/IPB + 3)
+
+// Directory is a file containing a sequence of dirent structures.
+#define DIRSIZ 14
+
+struct dirent {
+  ushort inum;
+  char name[DIRSIZ];
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/grep.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,106 @@
+// Simple grep.  Only supports ^ . * $ operators.
+
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+
+char buf[1024];
+int match(char*, char*);
+
+void
+grep(char *pattern, int fd)
+{
+  int n, m;
+  char *p, *q;
+  
+  m = 0;
+  while((n = read(fd, buf+m, sizeof(buf)-m)) > 0){
+    m += n;
+    p = buf;
+    while((q = strchr(p, '\n')) != 0){
+      *q = 0;
+      if(match(pattern, p)){
+        *q = '\n';
+        write(1, p, q+1 - p);
+      }
+      p = q+1;
+    }
+    if(p == buf)
+      m = 0;
+    if(m > 0){
+      m -= p - buf;
+      memmove(buf, p, m);
+    }
+  }
+}
+
+int
+main(int argc, char *argv[])
+{
+  int fd, i;
+  char *pattern;
+  
+  if(argc <= 1){
+    printf(2, "usage: grep pattern [file ...]\n");
+    exit();
+  }
+  pattern = argv[1];
+  
+  if(argc <= 2){
+    grep(pattern, 0);
+    exit();
+  }
+
+  for(i = 2; i < argc; i++){
+    if((fd = open(argv[i], 0)) < 0){
+      printf(1, "grep: cannot open %s\n", argv[i]);
+      exit();
+    }
+    grep(pattern, fd);
+    close(fd);
+  }
+  exit();
+}
+
+// Regexp matcher from Kernighan & Pike,
+// The Practice of Programming, Chapter 9.
+
+int matchhere(char*, char*);
+int matchstar(int, char*, char*);
+
+int
+match(char *re, char *text)
+{
+  if(re[0] == '^')
+    return matchhere(re+1, text);
+  do{  // must look at empty string
+    if(matchhere(re, text))
+      return 1;
+  }while(*text++ != '\0');
+  return 0;
+}
+
+// matchhere: search for re at beginning of text
+int matchhere(char *re, char *text)
+{
+  if(re[0] == '\0')
+    return 1;
+  if(re[1] == '*')
+    return matchstar(re[0], re+2, text);
+  if(re[0] == '$' && re[1] == '\0')
+    return *text == '\0';
+  if(*text!='\0' && (re[0]=='.' || re[0]==*text))
+    return matchhere(re+1, text+1);
+  return 0;
+}
+
+// matchstar: search for c*re at beginning of text
+int matchstar(int c, char *re, char *text)
+{
+  do{  // a * matches zero or more instances
+    if(matchhere(re, text))
+      return 1;
+  }while(*text!='\0' && (*text++==c || c=='.'));
+  return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/init.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,37 @@
+// init: The initial user-level program
+
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+#include "fcntl.h"
+
+char *argv[] = { "sh", 0 };
+
+int
+main(void)
+{
+  int pid, wpid;
+
+  if(open("console", O_RDWR) < 0){
+    mknod("console", 1, 1);
+    open("console", O_RDWR);
+  }
+  dup(0);  // stdout
+  dup(0);  // stderr
+
+  for(;;){
+    printf(1, "init: starting sh\n");
+    pid = fork();
+    if(pid < 0){
+      printf(1, "init: fork failed\n");
+      exit();
+    }
+    if(pid == 0){
+      exec("sh", argv);
+      printf(1, "init: exec sh failed\n");
+      exit();
+    }
+    while((wpid=wait()) >= 0 && wpid != pid)
+      printf(1, "zombie!\n");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/initcode.S	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,37 @@
+# Initial process execs /init.
+
+#include "syscall.h"
+#include "traps.h"
+
+
+# exec(init, argv)
+.globl start
+start:
+  push {lr}
+  ldr r0, =argv
+  push {r0}
+  ldr r0, =init
+  push {r0}
+  mov r0, #SYS_exec
+  swi #T_SYSCALL
+  pop {lr}
+  pop {lr}
+  pop {lr}
+  bx lr
+
+# for(;;) exit();
+exit:
+  mov r11, #SYS_exit
+  swi #T_SYSCALL
+  bl exit
+
+# char init[] = "/init\0";
+init:
+  .string "/init\0"
+
+# char *argv[] = { init, 0 };
+.p2align 2
+argv:
+  .long init
+  .long 0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/kill.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,17 @@
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+
+int
+main(int argc, char **argv)
+{
+  int i;
+
+  if(argc < 1){
+    printf(2, "usage: kill pid...\n");
+    exit();
+  }
+  for(i=1; i<argc; i++)
+    kill(atoi(argv[i]));
+  exit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/ln.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,15 @@
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+
+int
+main(int argc, char *argv[])
+{
+  if(argc != 3){
+    printf(2, "Usage: ln old new\n");
+    exit();
+  }
+  if(link(argv[1], argv[2]) < 0)
+    printf(2, "link %s %s: failed\n", argv[1], argv[2]);
+  exit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/ls.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,85 @@
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+#include "fs.h"
+
+char*
+fmtname(char *path)
+{
+  static char buf[DIRSIZ+1];
+  char *p;
+  
+  // Find first character after last slash.
+  for(p=path+strlen(path); p >= path && *p != '/'; p--)
+    ;
+  p++;
+  
+  // Return blank-padded name.
+  if(strlen(p) >= DIRSIZ)
+    return p;
+  memmove(buf, p, strlen(p));
+  memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));
+  return buf;
+}
+
+void
+ls(char *path)
+{
+  char buf[512], *p;
+  int fd;
+  struct dirent de;
+  struct stat st;
+  
+  if((fd = open(path, 0)) < 0){
+    printf(2, "ls: cannot open %s\n", path);
+    return;
+  }
+  
+  if(fstat(fd, &st) < 0){
+    printf(2, "ls: cannot stat %s\n", path);
+    close(fd);
+    return;
+  }
+  
+  switch(st.type){
+  case T_FILE:
+    printf(1, "%s %d %d %d\n", fmtname(path), st.type, st.ino, st.size);
+    break;
+  
+  case T_DIR:
+    if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
+      printf(1, "ls: path too long\n");
+      break;
+    }
+    strcpy(buf, path);
+    p = buf+strlen(buf);
+    *p++ = '/';
+    while(read(fd, &de, sizeof(de)) == sizeof(de)){
+      if(de.inum == 0)
+        continue;
+      memmove(p, de.name, DIRSIZ);
+      p[DIRSIZ] = 0;
+      if(stat(buf, &st) < 0){
+        printf(1, "ls: cannot stat %s\n", buf);
+        continue;
+      }
+      printf(1, "%s %d %d %d\n", fmtname(buf), st.type, st.ino, st.size);
+    }
+    break;
+  }
+  close(fd);
+}
+
+int
+main(int argc, char *argv[])
+{
+  int i;
+
+  if(argc < 2){
+    ls(".");
+    exit();
+  }
+  for(i=1; i<argc; i++)
+    ls(argv[i]);
+  exit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/memlayout.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,18 @@
+// Memory layout
+
+// Key addresses for address space layout (see kmap in vm.c for layout)
+#define KERNBASE 0x80000000         // First kernel virtual address
+#define USERBOUND 0x40000000        // maximum user space due to one page pgd
+
+#define MACHADDR        (KERNBASE+0x2000)
+#define TVSIZE          0x1000
+
+static inline uint v2p(void *a) { return ((uint) (a))  - KERNBASE; }
+static inline void *p2v(uint a) { return (void *) ((a) + KERNBASE); }
+
+#define V2P(a) (((uint) (a)) - KERNBASE)
+#define P2V(a) (((void *) (a)) + KERNBASE)
+
+#define V2P_WO(x) ((x) - KERNBASE)    // same as V2P, but without casts
+#define P2V_WO(x) ((x) + KERNBASE)    // same as V2P, but without casts
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/mkdir.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,23 @@
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+
+int
+main(int argc, char *argv[])
+{
+  int i;
+
+  if(argc < 2){
+    printf(2, "Usage: mkdir files...\n");
+    exit();
+  }
+
+  for(i = 1; i < argc; i++){
+    if(mkdir(argv[i]) < 0){
+      printf(2, "mkdir: %s failed to create\n", argv[i]);
+      break;
+    }
+  }
+
+  exit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/mkfs.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,298 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define stat xv6_stat  // avoid clash with host struct stat
+#include "types.h"
+#include "fs.h"
+#include "stat.h"
+#include "param.h"
+
+#define _static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0)
+
+int nblocks = 985;
+int nlog = LOGSIZE;
+int ninodes = 200;
+int size = 1024;
+
+int fsfd;
+struct superblock sb;
+char zeroes[512];
+uint freeblock;
+uint usedblocks;
+uint bitblocks;
+uint freeinode = 1;
+
+void balloc(int);
+void wsect(uint, void*);
+void winode(uint, struct dinode*);
+void rinode(uint inum, struct dinode *ip);
+void rsect(uint sec, void *buf);
+uint ialloc(ushort type);
+void iappend(uint inum, void *p, int n);
+
+// convert to intel byte order
+ushort
+xshort(ushort x)
+{
+  ushort y;
+  uchar *a = (uchar*)&y;
+  a[0] = x;
+  a[1] = x >> 8;
+  return y;
+}
+
+uint
+xint(uint x)
+{
+  uint y;
+  uchar *a = (uchar*)&y;
+  a[0] = x;
+  a[1] = x >> 8;
+  a[2] = x >> 16;
+  a[3] = x >> 24;
+  return y;
+}
+
+int
+main(int argc, char *argv[])
+{
+  int i, cc, fd;
+  uint rootino, inum, off;
+  struct dirent de;
+  char buf[512];
+  struct dinode din;
+
+
+  _static_assert(sizeof(int) == 4, "Integers must be 4 bytes!");
+
+  if(argc < 2){
+    fprintf(stderr, "Usage: mkfs fs.img files...\n");
+    exit(1);
+  }
+
+  assert((512 % sizeof(struct dinode)) == 0);
+  assert((512 % sizeof(struct dirent)) == 0);
+
+  fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
+  if(fsfd < 0){
+    perror(argv[1]);
+    exit(1);
+  }
+
+  sb.size = xint(size);
+  sb.nblocks = xint(nblocks); // so whole disk is size sectors
+  sb.ninodes = xint(ninodes);
+  sb.nlog = xint(nlog);
+
+  bitblocks = size/(512*8) + 1;
+  usedblocks = ninodes / IPB + 3 + bitblocks;
+  freeblock = usedblocks;
+
+  printf("used %d (bit %d ninode %zu) free %u log %u total %d\n", usedblocks,
+         bitblocks, ninodes/IPB + 1, freeblock, nlog, nblocks+usedblocks+nlog);
+
+  assert(nblocks + usedblocks + nlog == size);
+
+  for(i = 0; i < nblocks + usedblocks + nlog; i++)
+    wsect(i, zeroes);
+
+  memset(buf, 0, sizeof(buf));
+  memmove(buf, &sb, sizeof(sb));
+  wsect(1, buf);
+
+  rootino = ialloc(T_DIR);
+  assert(rootino == ROOTINO);
+
+  bzero(&de, sizeof(de));
+  de.inum = xshort(rootino);
+  strcpy(de.name, ".");
+  iappend(rootino, &de, sizeof(de));
+
+  bzero(&de, sizeof(de));
+  de.inum = xshort(rootino);
+  strcpy(de.name, "..");
+  iappend(rootino, &de, sizeof(de));
+
+  for(i = 2; i < argc; i++){
+    assert(index(argv[i], '/') == 0);
+
+    if((fd = open(argv[i], 0)) < 0){
+      perror(argv[i]);
+      exit(1);
+    }
+    
+    // Skip leading _ in name when writing to file system.
+    // The binaries are named _rm, _cat, etc. to keep the
+    // build operating system from trying to execute them
+    // in place of system binaries like rm and cat.
+    if(argv[i][0] == '_')
+      ++argv[i];
+
+    inum = ialloc(T_FILE);
+
+    bzero(&de, sizeof(de));
+    de.inum = xshort(inum);
+    strncpy(de.name, argv[i], DIRSIZ);
+    iappend(rootino, &de, sizeof(de));
+
+    while((cc = read(fd, buf, sizeof(buf))) > 0)
+      iappend(inum, buf, cc);
+
+    close(fd);
+  }
+
+  // fix size of root inode dir
+  rinode(rootino, &din);
+  off = xint(din.size);
+  off = ((off/BSIZE) + 1) * BSIZE;
+  din.size = xint(off);
+  winode(rootino, &din);
+
+  balloc(usedblocks);
+
+  exit(0);
+}
+
+void
+wsect(uint sec, void *buf)
+{
+  if(lseek(fsfd, sec * 512L, 0) != sec * 512L){
+    perror("lseek");
+    exit(1);
+  }
+  if(write(fsfd, buf, 512) != 512){
+    perror("write");
+    exit(1);
+  }
+}
+
+uint
+i2b(uint inum)
+{
+  return (inum / IPB) + 2;
+}
+
+void
+winode(uint inum, struct dinode *ip)
+{
+  char buf[512];
+  uint bn;
+  struct dinode *dip;
+
+  bn = i2b(inum);
+  rsect(bn, buf);
+  dip = ((struct dinode*)buf) + (inum % IPB);
+  *dip = *ip;
+  wsect(bn, buf);
+}
+
+void
+rinode(uint inum, struct dinode *ip)
+{
+  char buf[512];
+  uint bn;
+  struct dinode *dip;
+
+  bn = i2b(inum);
+  rsect(bn, buf);
+  dip = ((struct dinode*)buf) + (inum % IPB);
+  *ip = *dip;
+}
+
+void
+rsect(uint sec, void *buf)
+{
+  if(lseek(fsfd, sec * 512L, 0) != sec * 512L){
+    perror("lseek");
+    exit(1);
+  }
+  if(read(fsfd, buf, 512) != 512){
+    perror("read");
+    exit(1);
+  }
+}
+
+uint
+ialloc(ushort type)
+{
+  uint inum = freeinode++;
+  struct dinode din;
+
+  bzero(&din, sizeof(din));
+  din.type = xshort(type);
+  din.nlink = xshort(1);
+  din.size = xint(0);
+  winode(inum, &din);
+  return inum;
+}
+
+void
+balloc(int used)
+{
+  uchar buf[512];
+  int i;
+
+  printf("balloc: first %d blocks have been allocated\n", used);
+  assert(used < 512*8);
+  bzero(buf, 512);
+  for(i = 0; i < used; i++){
+    buf[i/8] = buf[i/8] | (0x1 << (i%8));
+  }
+  printf("balloc: write bitmap block at sector %zu\n", ninodes/IPB + 3);
+  wsect(ninodes / IPB + 3, buf);
+}
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+void
+iappend(uint inum, void *xp, int n)
+{
+  char *p = (char*)xp;
+  uint fbn, off, n1;
+  struct dinode din;
+  char buf[512];
+  uint indirect[NINDIRECT];
+  uint x;
+
+  rinode(inum, &din);
+
+  off = xint(din.size);
+  while(n > 0){
+    fbn = off / 512;
+    assert(fbn < MAXFILE);
+    if(fbn < NDIRECT){
+      if(xint(din.addrs[fbn]) == 0){
+        din.addrs[fbn] = xint(freeblock++);
+        usedblocks++;
+      }
+      x = xint(din.addrs[fbn]);
+    } else {
+      if(xint(din.addrs[NDIRECT]) == 0){
+        // printf("allocate indirect block\n");
+        din.addrs[NDIRECT] = xint(freeblock++);
+        usedblocks++;
+      }
+      // printf("read indirect block\n");
+      rsect(xint(din.addrs[NDIRECT]), (char*)indirect);
+      if(indirect[fbn - NDIRECT] == 0){
+        indirect[fbn - NDIRECT] = xint(freeblock++);
+        usedblocks++;
+        wsect(xint(din.addrs[NDIRECT]), (char*)indirect);
+      }
+      x = xint(indirect[fbn-NDIRECT]);
+    }
+    n1 = min(n, (fbn + 1) * 512 - off);
+    rsect(x, buf);
+    bcopy(p, buf + off - (fbn * 512), n1);
+    wsect(x, buf);
+    n -= n1;
+    off += n1;
+    p += n1;
+  }
+  din.size = xint(off);
+  winode(inum, &din);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/mmu.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,86 @@
+#define MByte 0x100000
+#define L1 0x4000
+#define L2 0x3000
+
+#define CACHELINESIZE   32
+
+#define FEXT(d, o, w)   (((d)>>(o)) & ((1<<(w))-1))
+#define L1X(va)         FEXT((va), 20, 12)
+#define L2X(va)         FEXT((va), 12, 8)
+
+/*
+ * page table entries.
+*/
+
+#define Mbz             (0<<4)
+#define Fault           0x00000000              /* L[12] pte: unmapped */
+
+#define Coarse          (Mbz|1)                 /* L1 */
+#define Section         (Mbz|2)                 /* L1 1MB */
+#define Fine            (Mbz|3)                 /* L1 */
+
+#define Large           0x00000001              /* L2 64KB */
+#define Small           0x00000002              /* L2 4KB */
+#define Tiny            0x00000003              /* L2 1KB: not in v7 */
+#define Buffered        0x00000004              /* L[12]: write-back not -thru */
+#define Cached          0x00000008              /* L[12] */
+#define Dom0            0
+
+#define Noaccess        0                       /* AP, DAC */
+#define Krw             1                       /* AP */
+/* armv7 deprecates AP[2] == 1 & AP[1:0] == 2 (Uro), prefers 3 (new in v7) */
+#define Uro             2                       /* AP */
+#define Urw             3                       /* AP */
+#define Client          1                       /* DAC */
+#define Manager         3                       /* DAC */
+
+#define F(v, o, w)      (((v) & ((1<<(w))-1))<<(o))
+#define AP(n, v)        F((v), ((n)*2)+4, 2)
+#define L1AP(ap)        (AP(3, (ap)))
+#define L2AP(ap) (AP(3, (ap))|AP(2, (ap))|AP(1, (ap))|AP(0, (ap))) /* pre-armv7 */
+#define DAC(n, v)       F((v), (n)*2, 2)
+
+#define HVECTORS        0xffff0000
+
+// A virtual address 'la' has a three-part structure as follows:
+//
+// +--------12------+-------8--------+---------12----------+
+// | Page Directory |   Page Table   | Offset within Page  |
+// |      Index     |      Index     |                     |
+// +----------------+----------------+---------------------+
+//  \--- PDX(va) --/ \--- PTX(va) --/
+
+// page directory index
+#define PDX(va)         (((uint)(va) >> PDXSHIFT) & 0xFFF)
+
+// page table index
+#define PTX(va)         (((uint)(va) >> PTXSHIFT) & 0xFF)
+
+// construct virtual address from indexes and offset
+#define PGADDR(d, t, o) ((uint)((d) << PDXSHIFT | (t) << PTXSHIFT | (o)))
+
+// Address in page table or page directory entry
+#define PTE_ADDR(pte)   ((uint)(pte) & ~0xFFF)
+#define PTE_FLAGS(pte)  ((uint)(pte) &  0xFFF)
+
+// Page directory and page table constants.
+#define NPDENTRIES      1024    // # directory entries per page directory
+#define NPTENTRIES      1024    // # PTEs per page table
+#define PGSIZE          4096    // bytes mapped by a page
+
+#define PGSHIFT         12      // log2(PGSIZE)
+#define PTXSHIFT        12      // offset of PTX in a linear address
+#define PDXSHIFT        20      // offset of PDX in a linear address
+
+
+#define PGROUNDUP(sz)  (((sz)+PGSIZE-1) & ~(PGSIZE-1))
+#define PGROUNDDOWN(a) (((a)) & ~(PGSIZE-1))
+
+#define PGDIR_BASE  P2V(L1)
+
+#define KVML1ATTR       Dom0|L1AP(Urw)|Section|Cached|Buffered
+
+#define UVML1ATTR 	Dom0|Coarse
+#define UVML2ATTR	L2AP(Urw)|Cached|Buffered|Small
+
+#define USER_MODE 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/param.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,12 @@
+#define NPROC        64  // maximum number of processes
+#define KSTACKSIZE 4096  // size of per-process kernel stack
+#define NCPU          8  // maximum number of CPUs
+#define NOFILE       16  // open files per process
+#define NFILE       100  // open files per system
+#define NBUF         10  // size of disk block cache
+#define NINODE       50  // maximum number of active i-nodes
+#define NDEV         10  // maximum major device number
+#define ROOTDEV       1  // device number of file system root disk
+#define MAXARG       32  // max exec arguments
+#define LOGSIZE      10  // max data sectors in on-disk log
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/printf.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,103 @@
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+
+static void
+putc(int fd, char c)
+{
+  write(fd, &c, 1);
+}
+
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+    int i;
+
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+        if(r >= d) {
+            r = r - d;
+            q = q | (1 << i);
+        }
+    }
+    return q;
+}
+
+static void
+printint(int fd, int xx, int base, int sgn)
+{
+  static char digits[] = "0123456789ABCDEF";
+  char buf[16];
+  int i, neg;
+  uint x, y, b;
+
+  neg = 0;
+  if(sgn && xx < 0){
+    neg = 1;
+    x = -xx;
+  } else {
+    x = xx;
+  }
+
+  b = base;
+  i = 0;
+  do{
+    y = div(x, b);
+    buf[i++] = digits[x - y * b];
+  }while((x = y) != 0);
+  if(neg)
+    buf[i++] = '-';
+
+  while(--i >= 0)
+    putc(fd, buf[i]);
+}
+
+// Print to the given fd. Only understands %d, %x, %p, %s.
+void
+printf(int fd, char *fmt, ...)
+{
+  char *s;
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+    c = fmt[i] & 0xff;
+    if(state == 0){
+      if(c == '%'){
+        state = '%';
+      } else {
+        putc(fd, c);
+      }
+    } else if(state == '%'){
+      if(c == 'd'){
+        printint(fd, *ap, 10, 1);
+        ap++;
+      } else if(c == 'x' || c == 'p'){
+        printint(fd, *ap, 16, 0);
+        ap++;
+      } else if(c == 's'){
+        s = (char*)*ap;
+        ap++;
+        if(s == 0)
+          s = "(null)";
+        while(*s != 0){
+          putc(fd, *s);
+          s++;
+        }
+      } else if(c == 'c'){
+        putc(fd, *ap);
+        ap++;
+      } else if(c == '%'){
+        putc(fd, c);
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+        putc(fd, c);
+      }
+      state = 0;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/proc.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,82 @@
+// Segments in proc->gdt.
+#define NSEGS     7
+
+// Per-CPU state
+struct cpu {
+  uchar id;                    // Local APIC ID; index into cpus[] below
+  struct context *scheduler;   // swtch() here to enter scheduler
+  volatile uint started;       // Has the CPU started?
+  int ncli;                    // Depth of pushcli nesting.
+  int intena;                  // Were interrupts enabled before pushcli?
+  
+  // Cpu-local storage variables; see below
+  struct cpu *cpu;
+  struct proc *proc;           // The currently-running process.
+};
+
+struct cpu cpus[NCPU];
+//extern int ncpu;
+
+// Per-CPU variables, holding pointers to the
+// current cpu and to the current process.
+// The asm suffix tells gcc to use "%gs:0" to refer to cpu
+// and "%gs:4" to refer to proc.  seginit sets up the
+// %gs segment register so that %gs refers to the memory
+// holding those two variables in the local cpu's struct cpu.
+// This is similar to how thread-local variables are implemented
+// in thread libraries such as Linux pthreads.
+//extern struct cpu *cpu asm("%gs:0");       // &cpus[cpunum()]
+//extern struct proc *proc asm("%gs:4");     // cpus[cpunum()].proc
+
+#define curr_cpu (&cpus[0])
+#define curr_proc   (cpus[0].proc)
+
+//PAGEBREAK: 17
+// Saved registers for kernel context switches.
+// Don't need to save all the segment registers (%cs, etc),
+// because they are constant across kernel contexts.
+// Don't need to save %eax, %ecx, %edx, because the
+// x86 convention is that the caller has saved them.
+// Contexts are stored at the bottom of the stack they
+// describe; the stack pointer is the address of the context.
+// The layout of the context matches the layout of the stack in swtch.S
+// at the "Switch stacks" comment. Switch doesn't save eip explicitly,
+// but it is on the stack and allocproc() manipulates it.
+struct context {
+  uint r4;
+  uint r5;
+  uint r6;
+  uint r7;
+  uint r8;
+  uint r9;
+  uint r10;
+  uint r11;
+  uint r12;
+  uint lr;
+  uint pc;
+};
+
+enum procstate { UNUSED=0, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
+
+// Per-process state
+struct proc {
+  uint sz;                     // Size of process memory (bytes)
+  pde_t* pgdir;                // Page table
+  char *kstack;                // Bottom of kernel stack for this process
+  enum procstate state;        // Process state
+  volatile int pid;            // Process ID
+  struct proc *parent;         // Parent process
+  struct trapframe *tf;        // Trap frame for current syscall
+  struct context *context;     // swtch() here to run process
+  void *chan;                  // If non-zero, sleeping on chan
+  int killed;                  // If non-zero, have been killed
+  struct file *ofile[NOFILE];  // Open files
+  struct inode *cwd;           // Current directory
+  char name[16];               // Process name (debugging)
+};
+
+// Process memory is laid out contiguously, low addresses first:
+//   text
+//   original data and bss
+//   fixed-size stack
+//   expandable heap
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/rm.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,23 @@
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+
+int
+main(int argc, char *argv[])
+{
+  int i;
+
+  if(argc < 2){
+    printf(2, "Usage: rm files...\n");
+    exit();
+  }
+
+  for(i = 1; i < argc; i++){
+    if(unlink(argv[i]) < 0){
+      printf(2, "rm: %s failed to delete\n", argv[i]);
+      break;
+    }
+  }
+
+  exit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/sh.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,494 @@
+// Shell.
+
+#include "types.h"
+#include "user.h"
+#include "fcntl.h"
+
+// Parsed command representation
+#define EXEC  1
+#define REDIR 2
+#define PIPE  3
+#define LIST  4
+#define BACK  5
+
+#define MAXARGS 10
+
+struct cmd {
+  int type;
+};
+
+struct execcmd {
+  int type;
+  char *argv[MAXARGS];
+  char *eargv[MAXARGS];
+};
+
+struct redircmd {
+  int type;
+  struct cmd *cmd;
+  char *file;
+  char *efile;
+  int mode;
+  int fd;
+};
+
+struct pipecmd {
+  int type;
+  struct cmd *left;
+  struct cmd *right;
+};
+
+struct listcmd {
+  int type;
+  struct cmd *left;
+  struct cmd *right;
+};
+
+struct backcmd {
+  int type;
+  struct cmd *cmd;
+};
+
+int fork1(void);  // Fork but panics on failure.
+void panic(char*);
+struct cmd *parsecmd(char*);
+
+// Execute cmd.  Never returns.
+void
+runcmd(struct cmd *cmd)
+{
+  int p[2];
+  struct backcmd *bcmd;
+  struct execcmd *ecmd;
+  struct listcmd *lcmd;
+  struct pipecmd *pcmd;
+  struct redircmd *rcmd;
+
+  if(cmd == 0)
+    exit();
+  
+  switch(cmd->type){
+  default:
+    panic("runcmd");
+
+  case EXEC:
+    ecmd = (struct execcmd*)cmd;
+    if(ecmd->argv[0] == 0)
+      exit();
+    exec(ecmd->argv[0], ecmd->argv);
+    printf(2, "exec %s failed\n", ecmd->argv[0]);
+    break;
+
+  case REDIR:
+    rcmd = (struct redircmd*)cmd;
+    close(rcmd->fd);
+    if(open(rcmd->file, rcmd->mode) < 0){
+      printf(2, "open %s failed\n", rcmd->file);
+      exit();
+    }
+    runcmd(rcmd->cmd);
+    break;
+
+  case LIST:
+    lcmd = (struct listcmd*)cmd;
+    if(fork1() == 0)
+      runcmd(lcmd->left);
+    wait();
+    runcmd(lcmd->right);
+    break;
+
+  case PIPE:
+    pcmd = (struct pipecmd*)cmd;
+    if(pipe(p) < 0)
+      panic("pipe");
+    if(fork1() == 0){
+      close(1);
+      dup(p[1]);
+      close(p[0]);
+      close(p[1]);
+      runcmd(pcmd->left);
+    }
+    if(fork1() == 0){
+      close(0);
+      dup(p[0]);
+      close(p[0]);
+      close(p[1]);
+      runcmd(pcmd->right);
+    }
+    close(p[0]);
+    close(p[1]);
+    wait();
+    wait();
+    break;
+    
+  case BACK:
+    bcmd = (struct backcmd*)cmd;
+    if(fork1() == 0)
+      runcmd(bcmd->cmd);
+    break;
+  }
+  exit();
+}
+
+int
+getcmd(char *buf, int nbuf)
+{
+  printf(2, "$ ");
+  memset(buf, 0, nbuf);
+  gets(buf, nbuf);
+  if(buf[0] == 0) // EOF
+    return -1;
+  return 0;
+}
+
+int
+main(void)
+{
+  static char buf[100];
+  int fd;
+  
+  // Assumes three file descriptors open.
+  while((fd = open("console", O_RDWR)) >= 0){
+    if(fd >= 3){
+      close(fd);
+      break;
+    }
+  }
+  
+  // Read and run input commands.
+  while(getcmd(buf, sizeof(buf)) >= 0){
+    if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
+      // Clumsy but will have to do for now.
+      // Chdir has no effect on the parent if run in the child.
+      buf[strlen(buf)-1] = 0;  // chop \n
+      if(chdir(buf+3) < 0)
+        printf(2, "cannot cd %s\n", buf+3);
+      continue;
+    }
+    if(fork1() == 0)
+      runcmd(parsecmd(buf));
+    wait();
+  }
+  exit();
+}
+
+void
+panic(char *s)
+{
+  printf(2, "%s\n", s);
+  exit();
+}
+
+int
+fork1(void)
+{
+  int pid;
+  
+  pid = fork();
+  if(pid == -1)
+    panic("fork");
+  return pid;
+}
+
+//PAGEBREAK!
+// Constructors
+
+struct cmd*
+execcmd(void)
+{
+  struct execcmd *cmd;
+
+  cmd = malloc(sizeof(*cmd));
+  memset(cmd, 0, sizeof(*cmd));
+  cmd->type = EXEC;
+  return (struct cmd*)cmd;
+}
+
+struct cmd*
+redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
+{
+  struct redircmd *cmd;
+
+  cmd = malloc(sizeof(*cmd));
+  memset(cmd, 0, sizeof(*cmd));
+  cmd->type = REDIR;
+  cmd->cmd = subcmd;
+  cmd->file = file;
+  cmd->efile = efile;
+  cmd->mode = mode;
+  cmd->fd = fd;
+  return (struct cmd*)cmd;
+}
+
+struct cmd*
+pipecmd(struct cmd *left, struct cmd *right)
+{
+  struct pipecmd *cmd;
+
+  cmd = malloc(sizeof(*cmd));
+  memset(cmd, 0, sizeof(*cmd));
+  cmd->type = PIPE;
+  cmd->left = left;
+  cmd->right = right;
+  return (struct cmd*)cmd;
+}
+
+struct cmd*
+listcmd(struct cmd *left, struct cmd *right)
+{
+  struct listcmd *cmd;
+
+  cmd = malloc(sizeof(*cmd));
+  memset(cmd, 0, sizeof(*cmd));
+  cmd->type = LIST;
+  cmd->left = left;
+  cmd->right = right;
+  return (struct cmd*)cmd;
+}
+
+struct cmd*
+backcmd(struct cmd *subcmd)
+{
+  struct backcmd *cmd;
+
+  cmd = malloc(sizeof(*cmd));
+  memset(cmd, 0, sizeof(*cmd));
+  cmd->type = BACK;
+  cmd->cmd = subcmd;
+  return (struct cmd*)cmd;
+}
+//PAGEBREAK!
+// Parsing
+
+char whitespace[] = " \t\r\n\v";
+char symbols[] = "<|>&;()";
+
+int
+gettoken(char **ps, char *es, char **q, char **eq)
+{
+  char *s;
+  int ret;
+  
+  s = *ps;
+  while(s < es && strchr(whitespace, *s))
+    s++;
+  if(q)
+    *q = s;
+  ret = *s;
+  switch(*s){
+  case 0:
+    break;
+  case '|':
+  case '(':
+  case ')':
+  case ';':
+  case '&':
+  case '<':
+    s++;
+    break;
+  case '>':
+    s++;
+    if(*s == '>'){
+      ret = '+';
+      s++;
+    }
+    break;
+  default:
+    ret = 'a';
+    while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
+      s++;
+    break;
+  }
+  if(eq)
+    *eq = s;
+  
+  while(s < es && strchr(whitespace, *s))
+    s++;
+  *ps = s;
+  return ret;
+}
+
+int
+peek(char **ps, char *es, char *toks)
+{
+  char *s;
+  
+  s = *ps;
+  while(s < es && strchr(whitespace, *s))
+    s++;
+  *ps = s;
+  return *s && strchr(toks, *s);
+}
+
+struct cmd *parseline(char**, char*);
+struct cmd *parsepipe(char**, char*);
+struct cmd *parseexec(char**, char*);
+struct cmd *nulterminate(struct cmd*);
+
+struct cmd*
+parsecmd(char *s)
+{
+  char *es;
+  struct cmd *cmd;
+
+  es = s + strlen(s);
+  cmd = parseline(&s, es);
+  peek(&s, es, "");
+  if(s != es){
+    printf(2, "leftovers: %s\n", s);
+    panic("syntax");
+  }
+  nulterminate(cmd);
+  return cmd;
+}
+
+struct cmd*
+parseline(char **ps, char *es)
+{
+  struct cmd *cmd;
+
+  cmd = parsepipe(ps, es);
+  while(peek(ps, es, "&")){
+    gettoken(ps, es, 0, 0);
+    cmd = backcmd(cmd);
+  }
+  if(peek(ps, es, ";")){
+    gettoken(ps, es, 0, 0);
+    cmd = listcmd(cmd, parseline(ps, es));
+  }
+  return cmd;
+}
+
+struct cmd*
+parsepipe(char **ps, char *es)
+{
+  struct cmd *cmd;
+
+  cmd = parseexec(ps, es);
+  if(peek(ps, es, "|")){
+    gettoken(ps, es, 0, 0);
+    cmd = pipecmd(cmd, parsepipe(ps, es));
+  }
+  return cmd;
+}
+
+struct cmd*
+parseredirs(struct cmd *cmd, char **ps, char *es)
+{
+  int tok;
+  char *q, *eq;
+
+  while(peek(ps, es, "<>")){
+    tok = gettoken(ps, es, 0, 0);
+    if(gettoken(ps, es, &q, &eq) != 'a')
+      panic("missing file for redirection");
+    switch(tok){
+    case '<':
+      cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
+      break;
+    case '>':
+      cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
+      break;
+    case '+':  // >>
+      cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
+      break;
+    }
+  }
+  return cmd;
+}
+
+struct cmd*
+parseblock(char **ps, char *es)
+{
+  struct cmd *cmd;
+
+  if(!peek(ps, es, "("))
+    panic("parseblock");
+  gettoken(ps, es, 0, 0);
+  cmd = parseline(ps, es);
+  if(!peek(ps, es, ")"))
+    panic("syntax - missing )");
+  gettoken(ps, es, 0, 0);
+  cmd = parseredirs(cmd, ps, es);
+  return cmd;
+}
+
+struct cmd*
+parseexec(char **ps, char *es)
+{
+  char *q, *eq;
+  int tok, argc;
+  struct execcmd *cmd;
+  struct cmd *ret;
+  
+  if(peek(ps, es, "("))
+    return parseblock(ps, es);
+
+  ret = execcmd();
+  cmd = (struct execcmd*)ret;
+
+  argc = 0;
+  ret = parseredirs(ret, ps, es);
+  while(!peek(ps, es, "|)&;")){
+    if((tok=gettoken(ps, es, &q, &eq)) == 0)
+      break;
+    if(tok != 'a')
+      panic("syntax");
+    cmd->argv[argc] = q;
+    cmd->eargv[argc] = eq;
+    argc++;
+    if(argc >= MAXARGS)
+      panic("too many args");
+    ret = parseredirs(ret, ps, es);
+  }
+  cmd->argv[argc] = 0;
+  cmd->eargv[argc] = 0;
+  return ret;
+}
+
+// NUL-terminate all the counted strings.
+struct cmd*
+nulterminate(struct cmd *cmd)
+{
+  int i;
+  struct backcmd *bcmd;
+  struct execcmd *ecmd;
+  struct listcmd *lcmd;
+  struct pipecmd *pcmd;
+  struct redircmd *rcmd;
+
+  if(cmd == 0)
+    return 0;
+  
+  switch(cmd->type){
+  case EXEC:
+    ecmd = (struct execcmd*)cmd;
+    for(i=0; ecmd->argv[i]; i++)
+      *ecmd->eargv[i] = 0;
+    break;
+
+  case REDIR:
+    rcmd = (struct redircmd*)cmd;
+    nulterminate(rcmd->cmd);
+    *rcmd->efile = 0;
+    break;
+
+  case PIPE:
+    pcmd = (struct pipecmd*)cmd;
+    nulterminate(pcmd->left);
+    nulterminate(pcmd->right);
+    break;
+    
+  case LIST:
+    lcmd = (struct listcmd*)cmd;
+    nulterminate(lcmd->left);
+    nulterminate(lcmd->right);
+    break;
+
+  case BACK:
+    bcmd = (struct backcmd*)cmd;
+    nulterminate(bcmd->cmd);
+    break;
+  }
+  return cmd;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/spinlock.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,11 @@
+// Mutual exclusion lock.
+struct spinlock {
+  uint locked;       // Is the lock held?
+
+  // For debugging:
+  char *name;        // Name of lock.
+  struct cpu *cpu;   // The cpu holding the lock.
+  uint pcs[10];      // The call stack (an array of program counters)
+                     // that locked the lock.
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/stat.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,11 @@
+#define T_DIR  1   // Directory
+#define T_FILE 2   // File
+#define T_DEV  3   // Device
+
+struct stat {
+  short type;  // Type of file
+  int dev;     // File system's disk device
+  uint ino;    // Inode number
+  short nlink; // Number of links to file
+  uint size;   // Size of file in bytes
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/stressfs.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,49 @@
+// Demonstrate that moving the "acquire" in iderw after the loop that
+// appends to the idequeue results in a race.
+
+// For this to work, you should also add a spin within iderw's
+// idequeue traversal loop.  Adding the following demonstrated a panic
+// after about 5 runs of stressfs in QEMU on a 2.1GHz CPU:
+//    for (i = 0; i < 40000; i++)
+//      asm volatile("");
+
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+#include "fs.h"
+#include "fcntl.h"
+
+int
+main(int argc, char *argv[])
+{
+  int fd, i;
+  char path[] = "stressfs0";
+  char data[512];
+
+  printf(1, "stressfs starting\n");
+  memset(data, 'a', sizeof(data));
+
+  for(i = 0; i < 4; i++)
+    if(fork() > 0)
+      break;
+
+  printf(1, "write %d\n", i);
+
+  path[8] += i;
+  fd = open(path, O_CREATE | O_RDWR);
+  for(i = 0; i < 20; i++)
+//    printf(fd, "%d\n", i);
+    write(fd, data, sizeof(data));
+  close(fd);
+
+  printf(1, "read\n");
+
+  fd = open(path, O_RDONLY);
+  for (i = 0; i < 20; i++)
+    read(fd, data, sizeof(data));
+  close(fd);
+
+  wait();
+  
+  exit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/syscall.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,22 @@
+// System call numbers
+#define SYS_fork    1
+#define SYS_exit    2
+#define SYS_wait    3
+#define SYS_pipe    4
+#define SYS_read    5
+#define SYS_kill    6
+#define SYS_exec    7
+#define SYS_fstat   8
+#define SYS_chdir   9
+#define SYS_dup    10
+#define SYS_getpid 11
+#define SYS_sbrk   12
+#define SYS_sleep  13
+#define SYS_uptime 14
+#define SYS_open   15
+#define SYS_write  16
+#define SYS_mknod  17
+#define SYS_unlink 18
+#define SYS_link   19
+#define SYS_mkdir  20
+#define SYS_close  21
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/traps.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,15 @@
+// These are arbitrarily chosen, but with care not to overlap
+// processor defined exceptions or interrupt vectors.
+#define T_SYSCALL       64      // system call
+#define T_DEFAULT      500      // catchall
+
+#define T_IRQ0          32      // IRQ 0 corresponds to int T_IRQ
+
+#define IRQ_TIMER        0
+#define IRQ_KBD          1
+#define IRQ_COM1         4
+#define IRQ_IDE         14
+#define IRQ_ERROR       19
+#define IRQ_SPURIOUS    31
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/types.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,86 @@
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+typedef unsigned long long u64;
+
+typedef unsigned int   uint;
+typedef unsigned short ushort;
+typedef unsigned char  uchar;
+typedef uint pde_t;
+typedef uint pte_t;
+
+
+/* trap vectors layout at virtual 
+address HVECTORS (and KZERO(0x80000000), doubled mapped).*/
+typedef struct Vpage0 {
+        void    (*vectors[8])(void);
+        u32     vtable[8];
+} Vpage0;
+
+
+/* interrupt control registers */
+typedef struct Intregs {
+        u32  ARMpending;
+        u32  GPUpending[2];
+        u32  FIQctl;
+        u32  GPUenable[2];
+        u32  ARMenable;
+        u32  GPUdisable[2];
+        u32  ARMdisable;
+} Intregs;
+
+
+typedef struct Mach
+{
+        int     machno;                 /* physical id of processor */
+
+        int     flushmmu;               /* flush current proc mmu state */
+
+        /* stats */
+        int     tlbfault;
+        int     tlbpurge;
+        int     pfault;
+        int     cs;
+        int     syscall;
+        int     load;
+        int     intr;
+        int     lastintr;
+        int     ilockdepth;
+
+
+        int     cpumhz;
+        /* vfp2 or vfp3 fpu */
+        int     havefp;
+        int     havefpvalid;
+        int     fpon;
+        int     fpconfiged;
+        int     fpnregs;
+        int     fppid;                  /* pid of last fault */
+        int     fpcnt;                  /* how many consecutive at that addr */
+
+        /* save areas for exceptions, hold R0-R4 */
+        u32  sfiq[5];
+        u32  sirq[5];
+        u32  sund[5];
+        u32  sabt[5];
+        u32  smon[5];                /* probably not needed */
+        u32  ssys[5];
+
+        int     stack[1];
+} Mach;
+
+
+struct framebufferdescription {
+	u32 width; //width
+	u32 height; // height
+	u32 v_width; // virtual width
+	u32 v_height; // virtual height
+	u32 pitch; // GPU pitch
+	u32 depth; // bit depth
+	u32 x;
+	u32 y;
+	u32 fbp; //GPU framebuffer pointer
+	u32 fbs; // GPU framebuffer size
+};
+
+typedef struct framebufferdescription FBI;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/ulib.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,108 @@
+#include "types.h"
+#include "stat.h"
+#include "fcntl.h"
+#include "user.h"
+#include "arm.h"
+
+char*
+strcpy(char *s, char *t)
+{
+  char *os;
+
+  os = s;
+  while((*s++ = *t++) != 0)
+    ;
+  return os;
+}
+
+int
+strcmp(const char *p, const char *q)
+{
+  while(*p && *p == *q)
+    p++, q++;
+  return (uchar)*p - (uchar)*q;
+}
+
+uint
+strlen(char *s)
+{
+  int n;
+
+  for(n = 0; s[n]; n++)
+    ;
+  return n;
+}
+
+void*
+memset(void *dst, int c, uint n)
+{
+  char *p=dst;
+  u32 rc=n;
+
+  while (rc-- > 0) *p++ = c;
+  return (void *)p;
+}
+
+char*
+strchr(const char *s, char c)
+{
+  for(; *s; s++)
+    if(*s == c)
+      return (char*)s;
+  return 0;
+}
+
+char*
+gets(char *buf, int max)
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+    cc = read(0, &c, 1);
+    if(cc < 1)
+      break;
+    buf[i++] = c;
+    if(c == '\n' || c == '\r')
+      break;
+  }
+  buf[i] = '\0';
+  return buf;
+}
+
+int
+stat(char *n, struct stat *st)
+{
+  int fd;
+  int r;
+
+  fd = open(n, O_RDONLY);
+  if(fd < 0)
+    return -1;
+  r = fstat(fd, st);
+  close(fd);
+  return r;
+}
+
+int
+atoi(const char *s)
+{
+  int n;
+
+  n = 0;
+  while('0' <= *s && *s <= '9')
+    n = n*10 + *s++ - '0';
+  return n;
+}
+
+void*
+memmove(void *vdst, void *vsrc, int n)
+{
+  char *dst, *src;
+  
+  dst = vdst;
+  src = vsrc;
+  while(n-- > 0)
+    *dst++ = *src++;
+  return vdst;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/umalloc.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,90 @@
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+#include "param.h"
+
+// Memory allocator by Kernighan and Ritchie,
+// The C programming Language, 2nd ed.  Section 8.7.
+
+typedef long Align;
+
+union header {
+  struct {
+    union header *ptr;
+    uint size;
+  } s;
+  Align x;
+};
+
+typedef union header Header;
+
+static Header base;
+static Header *freep;
+
+void
+free(void *ap)
+{
+  Header *bp, *p;
+
+  bp = (Header*)ap - 1;
+  for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
+    if(p >= p->s.ptr && (bp > p || bp < p->s.ptr))
+      break;
+  if(bp + bp->s.size == p->s.ptr){
+    bp->s.size += p->s.ptr->s.size;
+    bp->s.ptr = p->s.ptr->s.ptr;
+  } else
+    bp->s.ptr = p->s.ptr;
+  if(p + p->s.size == bp){
+    p->s.size += bp->s.size;
+    p->s.ptr = bp->s.ptr;
+  } else
+    p->s.ptr = bp;
+  freep = p;
+}
+
+static Header*
+morecore(uint nu)
+{
+  char *p;
+  Header *hp;
+
+  if(nu < 4096)
+    nu = 4096;
+  p = sbrk(nu * sizeof(Header));
+  if(p == (char*)-1)
+    return 0;
+  hp = (Header*)p;
+  hp->s.size = nu;
+  free((void*)(hp + 1));
+  return freep;
+}
+
+void*
+malloc(uint nbytes)
+{
+  Header *p, *prevp;
+  uint nunits;
+
+  nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
+  if((prevp = freep) == 0){
+    base.s.ptr = freep = prevp = &base;
+    base.s.size = 0;
+  }
+  for(p = prevp->s.ptr; ; prevp = p, p = p->s.ptr){
+    if(p->s.size >= nunits){
+      if(p->s.size == nunits)
+        prevp->s.ptr = p->s.ptr;
+      else {
+        p->s.size -= nunits;
+        p += p->s.size;
+        p->s.size = nunits;
+      }
+      freep = prevp;
+      return (void*)(p + 1);
+    }
+    if(p == freep)
+      if((p = morecore(nunits)) == 0)
+        return 0;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/user.h	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,38 @@
+struct stat;
+
+// system calls
+int fork(void);
+int exit(void) __attribute__((noreturn));
+int wait(void);
+int pipe(int*);
+int write(int, void*, int);
+int read(int, void*, int);
+int close(int);
+int kill(int);
+int exec(char*, char**);
+int open(char*, int);
+int mknod(char*, short, short);
+int unlink(char*);
+int fstat(int fd, struct stat*);
+int link(char*, char*);
+int mkdir(char*);
+int chdir(char*);
+int dup(int);
+int getpid(void);
+char* sbrk(int);
+int sleep(int);
+int uptime(void);
+
+// ulib.c
+int stat(char*, struct stat*);
+char* strcpy(char*, char*);
+void *memmove(void*, void*, int);
+char* strchr(const char*, char c);
+int strcmp(const char*, const char*);
+void printf(int, char*, ...);
+char* gets(char*, int max);
+uint strlen(char*);
+void* memset(void*, int, uint);
+void* malloc(uint);
+void free(void*);
+int atoi(const char*);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/usertests.c	Sun Jan 06 19:27:03 2019 +0900
@@ -0,0 +1,1678 @@
+#include "param.h"
+#include "types.h"
+#include "stat.h"
+#include "user.h"
+#include "fs.h"
+#include "fcntl.h"
+#include "syscall.h"
+#include "traps.h"
+#include "memlayout.h"
+
+char buf[8192];
+char name[3];
+char *echoargv[] = { "echo", "ALL", "TESTS", "PASSED", 0 };
+int stdout = 1;
+
+// simple file system tests
+
+void
+opentest(void)
+{
+  int fd;
+
+  printf(stdout, "open test\n");
+  fd = open("echo", 0);
+  if(fd < 0){
+    printf(stdout, "open echo failed!\n");
+    exit();
+  }
+  close(fd);
+  fd = open("doesnotexist", 0);
+  if(fd >= 0){
+    printf(stdout, "open doesnotexist succeeded!\n");
+    exit();
+  }
+  printf(stdout, "open test ok\n");
+}
+
+void
+writetest(void)
+{
+  int fd;
+  int i;
+
+  printf(stdout, "small file test\n");
+  fd = open("small", O_CREATE|O_RDWR);
+  if(fd >= 0){
+    printf(stdout, "creat small succeeded; ok\n");
+  } else {
+    printf(stdout, "error: creat small failed!\n");
+    exit();
+  }
+  for(i = 0; i < 100; i++){
+    if(write(fd, "aaaaaaaaaa", 10) != 10){
+      printf(stdout, "error: write aa %d new file failed\n", i);
+      exit();
+    }
+    if(write(fd, "bbbbbbbbbb", 10) != 10){
+      printf(stdout, "error: write bb %d new file failed\n", i);
+      exit();
+    }
+  }
+  printf(stdout, "writes ok\n");
+  close(fd);
+  fd = open("small", O_RDONLY);
+  if(fd >= 0){
+    printf(stdout, "open small succeeded ok\n");
+  } else {
+    printf(stdout, "error: open small failed!\n");
+    exit();
+  }
+  i = read(fd, buf, 2000);
+  if(i == 2000){
+    printf(stdout, "read succeeded ok\n");
+  } else {
+    printf(stdout, "read failed\n");
+    exit();
+  }
+  close(fd);
+
+  if(unlink("small") < 0){
+    printf(stdout, "unlink small failed\n");
+    exit();
+  }
+  printf(stdout, "small file test ok\n");
+}
+
+void
+writetest1(void)
+{
+  int i, fd, n;
+
+  printf(stdout, "big files test\n");
+
+  fd = open("big", O_CREATE|O_RDWR);
+  if(fd < 0){
+    printf(stdout, "error: creat big failed!\n");
+    exit();
+  }
+
+  for(i = 0; i < MAXFILE; i++){
+    ((int*)buf)[0] = i;
+    if(write(fd, buf, 512) != 512){
+      printf(stdout, "error: write big file failed\n", i);
+      exit();
+    }
+  }
+
+  close(fd);
+
+  fd = open("big", O_RDONLY);
+  if(fd < 0){
+    printf(stdout, "error: open big failed!\n");
+    exit();
+  }
+
+  n = 0;
+  for(;;){
+    i = read(fd, buf, 512);
+    if(i == 0){
+      if(n == MAXFILE - 1){
+        printf(stdout, "read only %d blocks from big", n);
+        exit();
+      }
+      break;
+    } else if(i != 512){
+      printf(stdout, "read failed %d\n", i);
+      exit();
+    }
+    if(((int*)buf)[0] != n){
+      printf(stdout, "read content of block %d is %d\n",
+             n, ((int*)buf)[0]);
+      exit();
+    }
+    n++;
+  }
+  close(fd);
+  if(unlink("big") < 0){
+    printf(stdout, "unlink big failed\n");
+    exit();
+  }
+  printf(stdout, "big files ok\n");
+}
+
+void
+createtest(void)
+{
+  int i, fd;
+
+  printf(stdout, "many creates, followed by unlink test\n");
+
+  name[0] = 'a';
+  name[2] = '\0';
+  for(i = 0; i < 52; i++){
+    name[1] = '0' + i;
+    fd = open(name, O_CREATE|O_RDWR);
+    close(fd);
+  }
+  name[0] = 'a';
+  name[2] = '\0';
+  for(i = 0; i < 52; i++){
+    name[1] = '0' + i;
+    unlink(name);
+  }
+  printf(stdout, "many creates, followed by unlink; ok\n");
+}
+
+void dirtest(void)
+{
+  printf(stdout, "mkdir test\n");
+
+  if(mkdir("dir0") < 0){
+    printf(stdout, "mkdir failed\n");
+    exit();
+  }
+
+  if(chdir("dir0") < 0){
+    printf(stdout, "chdir dir0 failed\n");
+    exit();
+  }
+
+  if(chdir("..") < 0){
+    printf(stdout, "chdir .. failed\n");
+    exit();
+  }
+
+  if(unlink("dir0") < 0){
+    printf(stdout, "unlink dir0 failed\n");
+    exit();
+  }
+  printf(stdout, "mkdir test\n");
+}
+
+void
+exectest(void)
+{
+  printf(stdout, "exec test\n");
+  if(exec("echo", echoargv) < 0){
+    printf(stdout, "exec echo failed\n");
+    exit();
+  }
+}
+
+// simple fork and pipe read/write
+
+void
+pipe1(void)
+{
+  int fds[2], pid;
+  int seq, i, n, cc, total;
+
+  if(pipe(fds) != 0){
+    printf(1, "pipe() failed\n");
+    exit();
+  }
+  pid = fork();
+  seq = 0;
+  if(pid == 0){
+    close(fds[0]);
+    for(n = 0; n < 5; n++){
+      for(i = 0; i < 1033; i++)
+        buf[i] = seq++;
+      if(write(fds[1], buf, 1033) != 1033){
+        printf(1, "pipe1 oops 1\n");
+        exit();
+      }
+    }
+    exit();
+  } else if(pid > 0){
+    close(fds[1]);
+    total = 0;
+    cc = 1;
+    while((n = read(fds[0], buf, cc)) > 0){
+      for(i = 0; i < n; i++){
+        if((buf[i] & 0xff) != (seq++ & 0xff)){
+          printf(1, "pipe1 oops 2\n");
+          return;
+        }
+      }
+      total += n;
+      cc = cc * 2;
+      if(cc > sizeof(buf))
+        cc = sizeof(buf);
+    }
+    if(total != 5 * 1033){
+      printf(1, "pipe1 oops 3 total %d\n", total);
+      exit();
+    }
+    close(fds[0]);
+    wait();
+  } else {
+    printf(1, "fork() failed\n");
+    exit();
+  }
+  printf(1, "pipe1 ok\n");
+}
+
+// meant to be run w/ at most two CPUs
+void
+preempt(void)
+{
+  int pid1, pid2, pid3;
+  int pfds[2];
+
+  printf(1, "preempt: ");
+  pid1 = fork();
+  if(pid1 == 0)
+    for(;;)
+      ;
+
+  pid2 = fork();
+  if(pid2 == 0)
+    for(;;)
+      ;
+
+  pipe(pfds);
+  pid3 = fork();
+  if(pid3 == 0){
+    close(pfds[0]);
+    if(write(pfds[1], "x", 1) != 1)
+      printf(1, "preempt write error");
+    close(pfds[1]);
+    for(;;)
+      ;
+  }
+
+  close(pfds[1]);
+  if(read(pfds[0], buf, sizeof(buf)) != 1){
+    printf(1, "preempt read error");
+    return;
+  }
+  close(pfds[0]);
+  printf(1, "kill... ");
+  kill(pid1);
+  kill(pid2);
+  kill(pid3);
+  printf(1, "wait... ");
+  wait();
+  wait();
+  wait();
+  printf(1, "preempt ok\n");
+}
+
+// try to find any races between exit and wait
+void
+exitwait(void)
+{
+  int i, pid;
+
+  for(i = 0; i < 100; i++){
+    pid = fork();
+    if(pid < 0){
+      printf(1, "fork failed\n");
+      return;
+    }
+    if(pid){
+      if(wait() != pid){
+        printf(1, "wait wrong pid\n");
+        return;
+      }
+    } else {
+      exit();
+    }
+  }
+  printf(1, "exitwait ok\n");
+}
+
+void
+mem(void)
+{
+  void *m1, *m2;
+  int pid, ppid;
+
+  printf(1, "mem test\n");
+  ppid = getpid();
+  if((pid = fork()) == 0){
+    m1 = 0;
+    while((m2 = malloc(10001)) != 0){
+      *(char**)m2 = m1;
+      m1 = m2;
+    }
+    while(m1){
+      m2 = *(char**)m1;
+      free(m1);
+      m1 = m2;
+    }
+    m1 = malloc(1024*20);
+    if(m1 == 0){
+      printf(1, "couldn't allocate mem?!!\n");
+      kill(ppid);
+      exit();
+    }
+    free(m1);
+    printf(1, "mem ok\n");
+    exit();
+  } else {
+    wait();
+  }
+}
+
+// More file system tests
+
+// two processes write to the same file descriptor
+// is the offset shared? does inode locking work?
+void
+sharedfd(void)
+{
+  int fd, pid, i, n, nc, np;
+  char buf[10];
+
+  printf(1, "sharedfd test\n");
+
+  unlink("sharedfd");
+  fd = open("sharedfd", O_CREATE|O_RDWR);
+  if(fd < 0){
+    printf(1, "fstests: cannot open sharedfd for writing");
+    return;
+  }
+  pid = fork();
+  memset(buf, pid==0?'c':'p', sizeof(buf));
+  for(i = 0; i < 1000; i++){
+    if(write(fd, buf, sizeof(buf)) != sizeof(buf)){
+      printf(1, "fstests: write sharedfd failed\n");
+      break;
+    }
+  }
+  if(pid == 0)
+    exit();
+  else
+    wait();
+  close(fd);
+  fd = open("sharedfd", 0);
+  if(fd < 0){
+    printf(1, "fstests: cannot open sharedfd for reading\n");
+    return;
+  }
+  nc = np = 0;
+  while((n = read(fd, buf, sizeof(buf))) > 0){
+    for(i = 0; i < sizeof(buf); i++){
+      if(buf[i] == 'c')
+        nc++;
+      if(buf[i] == 'p')
+        np++;
+    }
+  }
+  close(fd);
+  unlink("sharedfd");
+  if(nc == 10000 && np == 10000){
+    printf(1, "sharedfd ok\n");
+  } else {
+    printf(1, "sharedfd oops %d %d\n", nc, np);
+    exit();
+  }
+}
+
+// two processes write two different files at the same
+// time, to test block allocation.
+void
+twofiles(void)
+{
+  int fd, pid, i, j, n, total;
+  char *fname;
+
+  printf(1, "twofiles test\n");
+
+  unlink("f1");
+  unlink("f2");
+
+  pid = fork();
+  if(pid < 0){
+    printf(1, "fork failed\n");
+    exit();
+  }
+
+  fname = pid ? "f1" : "f2";
+  fd = open(fname, O_CREATE | O_RDWR);
+  if(fd < 0){
+    printf(1, "create failed\n");
+    exit();
+  }
+
+  memset(buf, pid?'p':'c', 512);
+  for(i = 0; i < 12; i++){
+    if((n = write(fd, buf, 500)) != 500){
+      printf(1, "write failed %d\n", n);
+      exit();
+    }
+  }
+  close(fd);
+  if(pid)
+    wait();
+  else
+    exit();
+
+  for(i = 0; i < 2; i++){
+    fd = open(i?"f1":"f2", 0);
+    total = 0;
+    while((n = read(fd, buf, sizeof(buf))) > 0){
+      for(j = 0; j < n; j++){
+        if(buf[j] != (i?'p':'c')){
+          printf(1, "wrong char\n");
+          exit();
+        }
+      }
+      total += n;
+    }
+    close(fd);
+    if(total != 12*500){
+      printf(1, "wrong length %d\n", total);
+      exit();
+    }
+  }
+
+  unlink("f1");
+  unlink("f2");
+
+  printf(1, "twofiles ok\n");
+}
+
+// two processes create and delete different files in same directory
+void
+createdelete(void)
+{
+  enum { N = 20 };
+  int pid, i, fd;
+  char name[32];
+
+  printf(1, "createdelete test\n");
+  pid = fork();
+  if(pid < 0){
+    printf(1, "fork failed\n");
+    exit();
+  }
+
+  name[0] = pid ? 'p' : 'c';
+  name[2] = '\0';
+  for(i = 0; i < N; i++){
+    name[1] = '0' + i;
+    fd = open(name, O_CREATE | O_RDWR);
+    if(fd < 0){
+      printf(1, "create failed\n");
+      exit();
+    }
+    close(fd);
+    if(i > 0 && (i % 2 ) == 0){
+      name[1] = '0' + (i / 2);
+      if(unlink(name) < 0){
+        printf(1, "unlink failed\n");
+        exit();
+      }
+    }
+  }
+
+  if(pid==0)
+    exit();
+  else
+    wait();
+
+  for(i = 0; i < N; i++){
+    name[0] = 'p';
+    name[1] = '0' + i;
+    fd = open(name, 0);
+    if((i == 0 || i >= N/2) && fd < 0){
+      printf(1, "oops createdelete %s didn't exist\n", name);
+      exit();
+    } else if((i >= 1 && i < N/2) && fd >= 0){
+      printf(1, "oops createdelete %s did exist\n", name);
+      exit();
+    }
+    if(fd >= 0)
+      close(fd);
+
+    name[0] = 'c';
+    name[1] = '0' + i;
+    fd = open(name, 0);
+    if((i == 0 || i >= N/2) && fd < 0){
+      printf(1, "oops createdelete %s didn't exist\n", name);
+      exit();
+    } else if((i >= 1 && i < N/2) && fd >= 0){
+      printf(1, "oops createdelete %s did exist\n", name);
+      exit();
+    }
+    if(fd >= 0)
+      close(fd);
+  }
+
+  for(i = 0; i < N; i++){
+    name[0] = 'p';
+    name[1] = '0' + i;
+    unlink(name);
+    name[0] = 'c';
+    unlink(name);
+  }
+
+  printf(1, "createdelete ok\n");
+}
+
+// can I unlink a file and still read it?
+void
+unlinkread(void)
+{
+  int fd, fd1;
+
+  printf(1, "unlinkread test\n");
+  fd = open("unlinkread", O_CREATE | O_RDWR);
+  if(fd < 0){
+    printf(1, "create unlinkread failed\n");
+    exit();
+  }
+  write(fd, "hello", 5);
+  close(fd);
+
+  fd = open("unlinkread", O_RDWR);
+  if(fd < 0){
+    printf(1, "open unlinkread failed\n");
+    exit();
+  }
+  if(unlink("unlinkread") != 0){
+    printf(1, "unlink unlinkread failed\n");
+    exit();
+  }
+
+  fd1 = open("unlinkread", O_CREATE | O_RDWR);
+  write(fd1, "yyy", 3);
+  close(fd1);
+
+  if(read(fd, buf, sizeof(buf)) != 5){
+    printf(1, "unlinkread read failed");
+    exit();
+  }
+  if(buf[0] != 'h'){
+    printf(1, "unlinkread wrong data\n");
+    exit();
+  }
+  if(write(fd, buf, 10) != 10){
+    printf(1, "unlinkread write failed\n");
+    exit();
+  }
+  close(fd);
+  unlink("unlinkread");
+  printf(1, "unlinkread ok\n");
+}
+
+void
+linktest(void)
+{
+  int fd;
+
+  printf(1, "linktest\n");
+
+  unlink("lf1");
+  unlink("lf2");
+
+  fd = open("lf1", O_CREATE|O_RDWR);
+  if(fd < 0){
+    printf(1, "create lf1 failed\n");
+    exit();
+  }
+  if(write(fd, "hello", 5) != 5){
+    printf(1, "write lf1 failed\n");
+    exit();
+  }
+  close(fd);
+
+  if(link("lf1", "lf2") < 0){
+    printf(1, "link lf1 lf2 failed\n");
+    exit();
+  }
+  unlink("lf1");
+
+  if(open("lf1", 0) >= 0){
+    printf(1, "unlinked lf1 but it is still there!\n");
+    exit();
+  }
+
+  fd = open("lf2", 0);
+  if(fd < 0){
+    printf(1, "open lf2 failed\n");
+    exit();
+  }
+  if(read(fd, buf, sizeof(buf)) != 5){
+    printf(1, "read lf2 failed\n");
+    exit();
+  }
+  close(fd);
+
+  if(link("lf2", "lf2") >= 0){
+    printf(1, "link lf2 lf2 succeeded! oops\n");
+    exit();
+  }
+
+  unlink("lf2");
+  if(link("lf2", "lf1") >= 0){
+    printf(1, "link non-existant succeeded! oops\n");
+    exit();
+  }
+
+  if(link(".", "lf1") >= 0){
+    printf(1, "link . lf1 succeeded! oops\n");
+    exit();
+  }
+
+  printf(1, "linktest ok\n");
+}
+
+// test concurrent create/link/unlink of the same file
+void
+concreate(void)
+{
+  char file[3];
+  int i, pid, n, fd;
+  char fa[40];
+  struct {
+    ushort inum;
+    char name[14];
+  } de;
+
+  printf(1, "concreate test\n");
+  file[0] = 'C';
+  file[2] = '\0';
+  for(i = 0; i < 40; i++){
+    file[1] = '0' + i;
+    unlink(file);
+    pid = fork();
+    if(pid && (i % 3) == 1){
+      link("C0", file);
+    } else if(pid == 0 && (i % 5) == 1){
+      link("C0", file);
+    } else {
+      fd = open(file, O_CREATE | O_RDWR);
+      if(fd < 0){
+        printf(1, "concreate create %s failed\n", file);
+        exit();
+      }
+      close(fd);
+    }
+    if(pid == 0)
+      exit();
+    else
+      wait();
+  }
+
+  memset(fa, 0, sizeof(fa));
+  fd = open(".", 0);
+  n = 0;
+  while(read(fd, &de, sizeof(de)) > 0){
+    if(de.inum == 0)
+      continue;
+    if(de.name[0] == 'C' && de.name[2] == '\0'){
+      i = de.name[1] - '0';
+      if(i < 0 || i >= sizeof(fa)){
+        printf(1, "concreate weird file %s\n", de.name);
+        exit();
+      }
+      if(fa[i]){
+        printf(1, "concreate duplicate file %s\n", de.name);
+        exit();
+      }
+      fa[i] = 1;
+      n++;
+    }
+  }
+  close(fd);
+
+  if(n != 40){
+    printf(1, "concreate not enough files in directory listing\n");
+    exit();
+  }
+
+  for(i = 0; i < 40; i++){
+    file[1] = '0' + i;
+    pid = fork();
+    if(pid < 0){
+      printf(1, "fork failed\n");
+      exit();
+    }
+    if(((i % 3) == 0 && pid == 0) ||
+       ((i % 3) == 1 && pid != 0)){
+      close(open(file, 0));
+      close(open(file, 0));
+      close(open(file, 0));
+      close(open(file, 0));
+    } else {
+      unlink(file);
+      unlink(file);
+      unlink(file);
+      unlink(file);
+    }
+    if(pid == 0)
+      exit();
+    else
+      wait();
+  }
+
+  printf(1, "concreate ok\n");
+}
+
+// another concurrent link/unlink/create test,
+// to look for deadlocks.
+void
+linkunlink()
+{
+  int pid, i;
+
+  printf(1, "linkunlink test\n");
+
+  unlink("x");
+  pid = fork();
+  if(pid < 0){
+    printf(1, "fork failed\n");
+    exit();
+  }
+
+  unsigned int x = (pid ? 1 : 97);
+  for(i = 0; i < 100; i++){
+    x = x * 1103515245 + 12345;
+    if((x % 3) == 0){
+      close(open("x", O_RDWR | O_CREATE));
+    } else if((x % 3) == 1){
+      link("cat", "x");
+    } else {
+      unlink("x");
+    }
+  }
+
+  if(pid)
+    wait();
+  else 
+    exit();
+
+  printf(1, "linkunlink ok\n");
+}
+
+// directory that uses indirect blocks
+void
+bigdir(void)
+{
+  int i, fd;
+  char name[10];
+
+  printf(1, "bigdir test\n");
+  unlink("bd");
+
+  fd = open("bd", O_CREATE);
+  if(fd < 0){
+    printf(1, "bigdir create failed\n");
+    exit();
+  }
+  close(fd);
+
+  for(i = 0; i < 500; i++){
+    name[0] = 'x';
+    name[1] = '0' + (i / 64);
+    name[2] = '0' + (i % 64);
+    name[3] = '\0';
+    if(link("bd", name) != 0){
+      printf(1, "bigdir link failed\n");
+      exit();
+    }
+  }
+
+  unlink("bd");
+  for(i = 0; i < 500; i++){
+    name[0] = 'x';
+    name[1] = '0' + (i / 64);
+    name[2] = '0' + (i % 64);
+    name[3] = '\0';
+    if(unlink(name) != 0){
+      printf(1, "bigdir unlink failed");
+      exit();
+    }
+  }
+
+  printf(1, "bigdir ok\n");
+}
+
+void
+subdir(void)
+{
+  int fd, cc;
+
+  printf(1, "subdir test\n");
+
+  unlink("ff");
+  if(mkdir("dd") != 0){
+    printf(1, "subdir mkdir dd failed\n");
+    exit();
+  }
+
+  fd = open("dd/ff", O_CREATE | O_RDWR);
+  if(fd < 0){
+    printf(1, "create dd/ff failed\n");
+    exit();
+  }
+  write(fd, "ff", 2);
+  close(fd);
+  
+  if(unlink("dd") >= 0){
+    printf(1, "unlink dd (non-empty dir) succeeded!\n");
+    exit();
+  }
+
+  if(mkdir("/dd/dd") != 0){
+    printf(1, "subdir mkdir dd/dd failed\n");
+    exit();
+  }
+
+  fd = open("dd/dd/ff", O_CREATE | O_RDWR);
+  if(fd < 0){
+    printf(1, "create dd/dd/ff failed\n");
+    exit();
+  }
+  write(fd, "FF", 2);
+  close(fd);
+
+  fd = open("dd/dd/../ff", 0);
+  if(fd < 0){
+    printf(1, "open dd/dd/../ff failed\n");
+    exit();
+  }
+  cc = read(fd, buf, sizeof(buf));
+  if(cc != 2 || buf[0] != 'f'){
+    printf(1, "dd/dd/../ff wrong content\n");
+    exit();
+  }
+  close(fd);
+
+  if(link("dd/dd/ff", "dd/dd/ffff") != 0){
+    printf(1, "link dd/dd/ff dd/dd/ffff failed\n");
+    exit();
+  }
+
+  if(unlink("dd/dd/ff") != 0){
+    printf(1, "unlink dd/dd/ff failed\n");
+    exit();
+  }
+  if(open("dd/dd/ff", O_RDONLY) >= 0){
+    printf(1, "open (unlinked) dd/dd/ff succeeded\n");
+    exit();
+  }
+
+  if(chdir("dd") != 0){
+    printf(1, "chdir dd failed\n");
+    exit();
+  }
+  if(chdir("dd/../../dd") != 0){
+    printf(1, "chdir dd/../../dd failed\n");
+    exit();
+  }
+  if(chdir("dd/../../../dd") != 0){
+    printf(1, "chdir dd/../../dd failed\n");
+    exit();
+  }
+  if(chdir("./..") != 0){
+    printf(1, "chdir ./.. failed\n");
+    exit();
+  }
+
+  fd = open("dd/dd/ffff", 0);
+  if(fd < 0){
+    printf(1, "open dd/dd/ffff failed\n");
+    exit();
+  }
+  if(read(fd, buf, sizeof(buf)) != 2){
+    printf(1, "read dd/dd/ffff wrong len\n");
+    exit();
+  }
+  close(fd);
+
+  if(open("dd/dd/ff", O_RDONLY) >= 0){
+    printf(1, "open (unlinked) dd/dd/ff succeeded!\n");
+    exit();
+  }
+
+  if(open("dd/ff/ff", O_CREATE|O_RDWR) >= 0){
+    printf(1, "create dd/ff/ff succeeded!\n");
+    exit();
+  }
+  if(open("dd/xx/ff", O_CREATE|O_RDWR) >= 0){
+    printf(1, "create dd/xx/ff succeeded!\n");
+    exit();
+  }
+  if(open("dd", O_CREATE) >= 0){
+    printf(1, "create dd succeeded!\n");
+    exit();
+  }
+  if(open("dd", O_RDWR) >= 0){
+    printf(1, "open dd rdwr succeeded!\n");
+    exit();
+  }
+  if(open("dd", O_WRONLY) >= 0){
+    printf(1, "open dd wronly succeeded!\n");
+    exit();
+  }
+  if(link("dd/ff/ff", "dd/dd/xx") == 0){
+    printf(1, "link dd/ff/ff dd/dd/xx succeeded!\n");
+    exit();
+  }
+  if(link("dd/xx/ff", "dd/dd/xx") == 0){
+    printf(1, "link dd/xx/ff dd/dd/xx succeeded!\n");
+    exit();
+  }
+  if(link("dd/ff", "dd/dd/ffff") == 0){
+    printf(1, "link dd/ff dd/dd/ffff succeeded!\n");
+    exit();
+  }
+  if(mkdir("dd/ff/ff") == 0){
+    printf(1, "mkdir dd/ff/ff succeeded!\n");
+    exit();
+  }
+  if(mkdir("dd/xx/ff") == 0){
+    printf(1, "mkdir dd/xx/ff succeeded!\n");
+    exit();
+  }
+  if(mkdir("dd/dd/ffff") == 0){
+    printf(1, "mkdir dd/dd/ffff succeeded!\n");
+    exit();
+  }
+  if(unlink("dd/xx/ff") == 0){
+    printf(1, "unlink dd/xx/ff succeeded!\n");
+    exit();
+  }
+  if(unlink("dd/ff/ff") == 0){
+    printf(1, "unlink dd/ff/ff succeeded!\n");
+    exit();
+  }
+  if(chdir("dd/ff") == 0){
+    printf(1, "chdir dd/ff succeeded!\n");
+    exit();
+  }
+  if(chdir("dd/xx") == 0){
+    printf(1, "chdir dd/xx succeeded!\n");
+    exit();
+  }
+
+  if(unlink("dd/dd/ffff") != 0){
+    printf(1, "unlink dd/dd/ff failed\n");
+    exit();
+  }
+  if(unlink("dd/ff") != 0){
+    printf(1, "unlink dd/ff failed\n");
+    exit();
+  }
+  if(unlink("dd") == 0){
+    printf(1, "unlink non-empty dd succeeded!\n");
+    exit();
+  }
+  if(unlink("dd/dd") < 0){
+    printf(1, "unlink dd/dd failed\n");
+    exit();
+  }
+  if(unlink("dd") < 0){
+    printf(1, "unlink dd failed\n");
+    exit();
+  }
+
+  printf(1, "subdir ok\n");
+}
+
+// test writes that are larger than the log.
+void
+bigwrite(void)
+{
+  int fd, sz;
+
+  printf(1, "bigwrite test\n");
+
+  unlink("bigwrite");
+  for(sz = 499; sz < 12*512; sz += 471){
+    fd = open("bigwrite", O_CREATE | O_RDWR);
+    if(fd < 0){
+      printf(1, "cannot create bigwrite\n");
+      exit();
+    }
+    int i;
+    for(i = 0; i < 2; i++){
+      int cc = write(fd, buf, sz);
+      if(cc != sz){
+        printf(1, "write(%d) ret %d\n", sz, cc);
+        exit();
+      }
+    }
+    close(fd);
+    unlink("bigwrite");
+  }
+
+  printf(1, "bigwrite ok\n");
+}
+
+void
+bigfile(void)
+{
+  int fd, i, total, cc;
+
+  printf(1, "bigfile test\n");
+
+  unlink("bigfile");
+  fd = open("bigfile", O_CREATE | O_RDWR);
+  if(fd < 0){
+    printf(1, "cannot create bigfile");
+    exit();
+  }
+  for(i = 0; i < 20; i++){
+    memset(buf, i, 600);
+    if(write(fd, buf, 600) != 600){
+      printf(1, "write bigfile failed\n");
+      exit();
+    }
+  }
+  close(fd);
+
+  fd = open("bigfile", 0);
+  if(fd < 0){
+    printf(1, "cannot open bigfile\n");
+    exit();
+  }
+  total = 0;
+  for(i = 0; ; i++){
+    cc = read(fd, buf, 300);
+    if(cc < 0){
+      printf(1, "read bigfile failed\n");
+      exit();
+    }
+    if(cc == 0)
+      break;
+    if(cc != 300){
+      printf(1, "short read bigfile\n");
+      exit();
+    }
+    if(buf[0] != i/2 || buf[299] != i/2){
+      printf(1, "read bigfile wrong data\n");
+      exit();
+    }
+    total += cc;
+  }
+  close(fd);
+  if(total != 20*600){
+    printf(1, "read bigfile wrong total\n");
+    exit();
+  }
+  unlink("bigfile");
+
+  printf(1, "bigfile test ok\n");
+}
+
+void
+fourteen(void)
+{
+  int fd;
+
+  // DIRSIZ is 14.
+  printf(1, "fourteen test\n");
+
+  if(mkdir("12345678901234") != 0){
+    printf(1, "mkdir 12345678901234 failed\n");
+    exit();
+  }
+  if(mkdir("12345678901234/123456789012345") != 0){
+    printf(1, "mkdir 12345678901234/123456789012345 failed\n");
+    exit();
+  }
+  fd = open("123456789012345/123456789012345/123456789012345", O_CREATE);
+  if(fd < 0){
+    printf(1, "create 123456789012345/123456789012345/123456789012345 failed\n");
+    exit();
+  }
+  close(fd);
+  fd = open("12345678901234/12345678901234/12345678901234", 0);
+  if(fd < 0){
+    printf(1, "open 12345678901234/12345678901234/12345678901234 failed\n");
+    exit();
+  }
+  close(fd);
+
+  if(mkdir("12345678901234/12345678901234") == 0){
+    printf(1, "mkdir 12345678901234/12345678901234 succeeded!\n");
+    exit();
+  }
+  if(mkdir("123456789012345/12345678901234") == 0){
+    printf(1, "mkdir 12345678901234/123456789012345 succeeded!\n");
+    exit();
+  }
+
+  printf(1, "fourteen ok\n");
+}
+
+void
+rmdot(void)
+{
+  printf(1, "rmdot test\n");
+  if(mkdir("dots") != 0){
+    printf(1, "mkdir dots failed\n");
+    exit();
+  }
+  if(chdir("dots") != 0){
+    printf(1, "chdir dots failed\n");
+    exit();
+  }
+  if(unlink(".") == 0){
+    printf(1, "rm . worked!\n");
+    exit();
+  }
+  if(unlink("..") == 0){
+    printf(1, "rm .. worked!\n");
+    exit();
+  }
+  if(chdir("/") != 0){
+    printf(1, "chdir / failed\n");
+    exit();
+  }
+  if(unlink("dots/.") == 0){
+    printf(1, "unlink dots/. worked!\n");
+    exit();
+  }
+  if(unlink("dots/..") == 0){
+    printf(1, "unlink dots/.. worked!\n");
+    exit();
+  }
+  if(unlink("dots") != 0){
+    printf(1, "unlink dots failed!\n");
+    exit();
+  }
+  printf(1, "rmdot ok\n");
+}
+
+void
+dirfile(void)
+{
+  int fd;
+
+  printf(1, "dir vs file\n");
+
+  fd = open("dirfile", O_CREATE);
+  if(fd < 0){
+    printf(1, "create dirfile failed\n");
+    exit();
+  }
+  close(fd);
+  if(chdir("dirfile") == 0){
+    printf(1, "chdir dirfile succeeded!\n");
+    exit();
+  }
+  fd = open("dirfile/xx", 0);
+  if(fd >= 0){
+    printf(1, "create dirfile/xx succeeded!\n");
+    exit();
+  }
+  fd = open("dirfile/xx", O_CREATE);
+  if(fd >= 0){
+    printf(1, "create dirfile/xx succeeded!\n");
+    exit();
+  }
+  if(mkdir("dirfile/xx") == 0){
+    printf(1, "mkdir dirfile/xx succeeded!\n");
+    exit();
+  }
+  if(unlink("dirfile/xx") == 0){
+    printf(1, "unlink dirfile/xx succeeded!\n");
+    exit();
+  }
+  if(link("README", "dirfile/xx") == 0){
+    printf(1, "link to dirfile/xx succeeded!\n");
+    exit();
+  }
+  if(unlink("dirfile") != 0){
+    printf(1, "unlink dirfile failed!\n");
+    exit();
+  }
+
+  fd = open(".", O_RDWR);
+  if(fd >= 0){
+    printf(1, "open . for writing succeeded!\n");
+    exit();
+  }
+  fd = open(".", 0);
+  if(write(fd, "x", 1) > 0){
+    printf(1, "write . succeeded!\n");
+    exit();
+  }
+  close(fd);
+
+  printf(1, "dir vs file OK\n");
+}
+
+// test that iput() is called at the end of _namei()
+void
+iref(void)
+{
+  int i, fd;
+
+  printf(1, "empty file name\n");
+
+  // the 50 is NINODE
+  for(i = 0; i < 50 + 1; i++){
+    if(mkdir("irefd") != 0){
+      printf(1, "mkdir irefd failed\n");
+      exit();
+    }
+    if(chdir("irefd") != 0){
+      printf(1, "chdir irefd failed\n");
+      exit();
+    }
+
+    mkdir("");
+    link("README", "");
+    fd = open("", O_CREATE);
+    if(fd >= 0)
+      close(fd);
+    fd = open("xx", O_CREATE);
+    if(fd >= 0)
+      close(fd);
+    unlink("xx");
+  }
+
+  chdir("/");
+  printf(1, "empty file name OK\n");
+}
+
+// test that fork fails gracefully
+// the forktest binary also does this, but it runs out of proc entries first.
+// inside the bigger usertests binary, we run out of memory first.
+void
+forktest(void)
+{
+  int n, pid;
+
+  printf(1, "fork test\n");
+
+  for(n=0; n<1000; n++){
+    pid = fork();
+    if(pid < 0)
+      break;
+    if(pid == 0)
+      exit();
+  }
+  
+  if(n == 1000){
+    printf(1, "fork claimed to work 1000 times!\n");
+    exit();
+  }
+  
+  for(; n > 0; n--){
+    if(wait() < 0){
+      printf(1, "wait stopped early\n");
+      exit();
+    }
+  }
+  
+  if(wait() != -1){
+    printf(1, "wait got too many\n");
+    exit();
+  }
+  
+  printf(1, "fork test OK\n");
+}
+
+void
+sbrktest(void)
+{
+  int fds[2], pid, pids[5], ppid;
+  char *a, *b, *c, *lastaddr, *oldbrk, *p, scratch;
+  uint amt;
+
+  printf(stdout, "sbrk test\n");
+  oldbrk = sbrk(0);
+
+  // can one sbrk() less than a page?
+  printf(stdout, "test #1 sbrk() less than a page?\n");
+  a = sbrk(0);
+  int i;
+  for(i = 0; i < 5000; i++){ 
+    b = sbrk(1);
+    if(b != a){
+      printf(stdout, "sbrk test failed %d %x %x\n", i, a, b);
+      exit();
+    }
+    *b = 1;
+    a = b + 1;
+  }
+  printf(stdout, "test #1 done.\n");
+
+  printf(stdout, "test #2 test fork?\n");
+  pid = fork();
+  if(pid < 0){
+    printf(stdout, "sbrk test fork failed\n");
+    exit();
+  }
+  printf(stdout, "test #2 done.\n");
+
+  printf(stdout, "test #3 post-fork.\n");
+  c = sbrk(1);
+  c = sbrk(1);
+  if(c != a + 1){
+    printf(stdout, "sbrk test failed post-fork\n");
+    exit();
+  }
+  if(pid == 0)
+    exit();
+  wait();
+  printf(stdout, "test #3 done.\n");
+
+  printf(stdout, "test #4 grow address space to something big.\n");
+  // can one grow address space to something big?
+  #define BIG (100*1024*1024)
+  a = sbrk(0);
+  amt = (BIG) - (uint)a;
+  p = sbrk(amt);
+  if (p != a) { 
+    printf(stdout, "sbrk test failed to grow big address space; enough phys mem?\n");
+    exit();
+  }
+  lastaddr = (char*) (BIG-1);
+  *lastaddr = 99;
+  printf(stdout, "test #4 done.\n");
+
+  printf(stdout, "test #5 de-allocate\n");
+  // can one de-allocate?
+  a = sbrk(0);
+  c = sbrk(-4096);
+  if(c == (char*)0xffffffff){
+    printf(stdout, "sbrk could not deallocate\n");
+    exit();
+  }
+  c = sbrk(0);
+  if(c != a - 4096){
+    printf(stdout, "sbrk deallocation produced wrong address, a %x c %x\n", a, c);
+    exit();
+  }
+  printf(stdout, "test #5 done.\n");
+
+  printf(stdout, "test #6 re-allocate page.\n");
+  // can one re-allocate that page?
+  a = sbrk(0);
+  c = sbrk(4096);
+  if(c != a || sbrk(0) != a + 4096){
+    printf(stdout, "sbrk re-allocation failed, a %x c %x\n", a, c);
+    exit();
+  }
+  if(*lastaddr == 99){
+    // should be zero
+    printf(stdout, "sbrk de-allocation didn't really deallocate\n");
+    exit();
+  }
+  printf(stdout, "test #6 done.\n");
+
+  printf(stdout, "test #7 downsize.\n");
+  a = sbrk(0);
+  c = sbrk(-(sbrk(0) - oldbrk));
+  if(c != a){
+    printf(stdout, "sbrk downsize failed, a %x c %x\n", a, c);
+    exit();
+  }
+  printf(stdout, "test #7 done.\n");
+
+  printf(stdout, "test #8 read the kernel's memory.\n");
+  // can we read the kernel's memory?
+  for(a = (char*)(KERNBASE); a < (char*) (KERNBASE+2000000); a += 50000){
+    ppid = getpid();
+    pid = fork();
+    if(pid < 0){
+      printf(stdout, "fork failed\n");
+      exit();
+    }
+    if(pid == 0){
+      printf(stdout, "oops could read %x = %x\n", a, *a);
+      kill(ppid);
+      exit();
+    }
+    wait();
+  }
+  printf(stdout, "test #8 done.\n");
+
+  printf(stdout, "test #9 clean up the last failed allocation\n");
+  // if we run the system out of memory, does it clean up the last
+  // failed allocation?
+  if(pipe(fds) != 0){
+    printf(1, "pipe() failed\n");
+    exit();
+  }
+  printf(stdout, "test #9 done.\n");
+
+  printf(stdout, "test #10 memory utilization 1.\n");
+  for(i = 0; i < sizeof(pids)/sizeof(pids[0]); i++){
+    if((pids[i] = fork()) == 0){
+      printf(stdout, "create pid:%d.\n",i);
+      // allocate a lot of memory
+      sbrk(BIG - (uint)sbrk(0));
+      write(fds[1], "x", 1);
+      // sit around until killed
+      for(;;) sleep(1000);
+    }
+    if(pids[i] != -1)
+      read(fds[0], &scratch, 1);
+  }
+  printf(stdout, "test #10 done.\n");
+
+  printf(stdout, "test #11 memory utilization 2.\n");
+  // if those failed allocations freed up the pages they did allocate,
+  // we'll be able to allocate here
+  c = sbrk(4096);
+  for(i = 0; i < sizeof(pids)/sizeof(pids[0]); i++){
+    if(pids[i] == -1)
+      continue;
+    kill(pids[i]);
+    wait();
+  }
+  printf(stdout, "test #11 done.\n");
+
+  printf(stdout, "test #12 leaked memory.\n");
+  if(c == (char*)0xffffffff){
+    printf(stdout, "failed sbrk leaked memory\n");
+    exit();
+  }
+  printf(stdout, "test #12 done.\n");
+
+  if(sbrk(0) > oldbrk)
+    sbrk(-(sbrk(0) - oldbrk));
+
+  printf(stdout, "sbrk test OK\n");
+}
+
+void
+validateint(int *p)
+{
+    sleep(*p);
+}
+
+void
+validatetest(void)
+{
+  int hi, pid;
+  uint p;
+
+  printf(stdout, "validate test\n");
+  hi = 1100*1024;
+
+  for(p = 0; p <= (uint)hi; p += 4096){
+    if((pid = fork()) == 0){
+      // try to crash the kernel by passing in a badly placed integer
+      validateint((int*)p);
+      exit();
+    }
+    sleep(0);
+    sleep(0);
+    kill(pid);
+    wait();
+
+    // try to crash the kernel by passing in a bad string pointer
+    if(link("nosuchfile", (char*)p) != -1){
+      printf(stdout, "link should not succeed\n");
+      exit();
+    }
+  }
+
+  printf(stdout, "validate ok\n");
+}
+
+// does unintialized data start out zero?
+char uninit[10000];
+void
+bsstest(void)
+{
+  int i;
+
+  printf(stdout, "bss test\n");
+  for(i = 0; i < sizeof(uninit); i++){
+    if(uninit[i] != '\0'){
+      printf(stdout, "bss test failed\n");
+      exit();
+    }
+  }
+  printf(stdout, "bss test ok\n");
+}
+
+// does exec return an error if the arguments
+// are larger than a page? or does it write
+// below the stack and wreck the instructions/data?
+void
+bigargtest(void)
+{
+  int pid, fd;
+
+  unlink("bigarg-ok");
+  pid = fork();
+  if(pid == 0){
+    static char *args[MAXARG];
+    int i;
+    for(i = 0; i < MAXARG-1; i++)
+      args[i] = "bigargs test: failed\n                                                                                                                                                                                                       ";
+    args[MAXARG-1] = 0;
+    printf(stdout, "bigarg test\n");
+    exec("echo", args);
+    printf(stdout, "bigarg test ok\n");
+    fd = open("bigarg-ok", O_CREATE);
+    close(fd);
+    exit();
+  } else if(pid < 0){
+    printf(stdout, "bigargtest: fork failed\n");
+    exit();
+  }
+  wait();
+  fd = open("bigarg-ok", 0);
+  if(fd < 0){
+    printf(stdout, "bigarg test failed!\n");
+    exit();
+  }
+  close(fd);
+  unlink("bigarg-ok");
+}
+
+// what happens when the file system runs out of blocks?
+// answer: balloc panics, so this test is not useful.
+void
+fsfull()
+{
+  int nfiles;
+  int fsblocks = 0;
+
+  printf(1, "fsfull test\n");
+
+  for(nfiles = 0; ; nfiles++){
+    char name[64];
+    name[0] = 'f';
+    name[1] = '0' + nfiles / 1000;
+    name[2] = '0' + (nfiles % 1000) / 100;
+    name[3] = '0' + (nfiles % 100) / 10;
+    name[4] = '0' + (nfiles % 10);
+    name[5] = '\0';
+    printf(1, "writing %s\n", name);
+    int fd = open(name, O_CREATE|O_RDWR);
+    if(fd < 0){
+      printf(1, "open %s failed\n", name);
+      break;
+    }
+    int total = 0;
+    while(1){
+      int cc = write(fd, buf, 512);
+      if(cc < 512)
+        break;
+      total += cc;
+      fsblocks++;
+    }
+    printf(1, "wrote %d bytes\n", total);
+    close(fd);
+    if(total == 0)