changeset 0:c450faca55f4

Init
author Tatsuki IHA <innparusu@cr.ie.u-ryukyu.ac.jp>
date Sun, 22 Oct 2017 18:25:39 +0900
parents
children d56c48888d7f
files Dockerfile LICENSE Makefile README docker-setup.md include/arm.h include/buf.h include/defs.h include/elf.h include/fcntl.h include/file.h include/fs.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 libcsud.a 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/keyboard.s 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/vm.c uprogs/LICENSE uprogs/Makefile uprogs/README uprogs/a.out uprogs/arm.h uprogs/buf.h uprogs/cat.asm uprogs/cat.c uprogs/cat.sym uprogs/defs.h uprogs/echo.asm uprogs/echo.c uprogs/echo.sym uprogs/elf.h uprogs/fcntl.h uprogs/file.h uprogs/forktest.asm uprogs/forktest.c uprogs/fs.h uprogs/grep.asm uprogs/grep.c uprogs/grep.sym uprogs/init.asm uprogs/init.c uprogs/init.sym uprogs/initcode uprogs/initcode.S uprogs/initcode.asm uprogs/initcode.out uprogs/kill.asm uprogs/kill.c uprogs/kill.sym uprogs/ln.asm uprogs/ln.c uprogs/ln.sym uprogs/ls.asm uprogs/ls.c uprogs/ls.sym uprogs/memlayout.h uprogs/mkdir.asm uprogs/mkdir.c uprogs/mkdir.sym uprogs/mkfs.c uprogs/mmu.h uprogs/param.h uprogs/printf.c uprogs/proc.h uprogs/rm.asm uprogs/rm.c uprogs/rm.sym uprogs/sh.asm uprogs/sh.c uprogs/sh.sym uprogs/spinlock.h uprogs/stat.h uprogs/stressfs.asm uprogs/stressfs.c uprogs/stressfs.sym uprogs/syscall.h uprogs/traps.h uprogs/types.h uprogs/ulib.c uprogs/umalloc.c uprogs/user.h uprogs/usertests.asm uprogs/usertests.c uprogs/usertests.sym uprogs/usys.S uprogs/usys.asm uprogs/usys_old.S uprogs/wc.asm uprogs/wc.c uprogs/wc.sym uprogs/zombie.asm uprogs/zombie.c uprogs/zombie.sym
diffstat 131 files changed, 47626 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Dockerfile	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,9 @@
+FROM phitek/qemu-arm
+RUN apt-get update -y
+RUN apt-get remove gdb -y
+RUN apt-get install gcc-arm-none-eabi gdb-arm-none-eabi qemu-system-arm mercurial -y
+WORKDIR /code
+RUN hg clone http://www.cr.ie.u-ryukyu.ac.jp/hg/Members/innparusu/xv6_rpi_port/
+WORKDIR /code/xv6_rpi_port/src
+RUN make
+CMD /bin/bash
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,30 @@
+The xv6 RPI port software is:
+
+Copyright (c) 2013-2014
+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 Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,77 @@
+###############################################################################
+#	makefile
+#	 by Alex Chadwick
+#
+#	A makefile script for generation of raspberry pi kernel images.
+###############################################################################
+
+# The toolchain to use. arm-none-eabi works, but there does exist 
+# arm-bcm2708-linux-gnueabi.
+#ARMGNU ?= arm-none-eabi
+
+# The intermediate directory for compiled object files.
+BUILD = build/
+
+# The directory in which source files are stored.
+SOURCE = source/
+
+# The name of the output file to generate.
+TARGET = kernel.img
+
+# The name of the assembler listing file to generate.
+LIST = kernel.list
+
+# The name of the map file to generate.
+MAP = kernel.map
+
+# The name of the linker script to use.
+LINKER = kernel.ld
+
+# The names of libraries to use.
+LIBRARIES := csud
+
+#CFLAGS := -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -Werror -fno-omit-frame-pointer -nostdinc -nostdlib -fno-stack-protector
+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 -I include
+
+CC := gcc
+
+# The names of all object files that must be generated. Deduced from the 
+# assembly code files in source.
+OBJECTS := $(patsubst $(SOURCE)%.s,$(BUILD)%.o,$(wildcard $(SOURCE)*.s))
+
+C_OBJS := $(patsubst $(SOURCE)%.c,$(BUILD)%.o,$(wildcard $(SOURCE)*.c))
+
+# Rule to make everything.
+all: $(TARGET) $(LIST)
+
+# Rule to remake everything. Does not include clean.
+#rebuild: all
+
+# Rule to make the listing file.
+$(LIST) : $(BUILD)output.elf
+	$(ARMGNU)-objdump -d $(BUILD)output.elf > $(LIST)
+
+# Rule to make the image file.
+$(TARGET) : $(BUILD)output.elf
+	$(ARMGNU)-objcopy $(BUILD)output.elf -O binary $(TARGET) 
+
+# Rule to make the elf file.
+$(BUILD)output.elf : $(OBJECTS) $(C_OBJS) $(LINKER)
+	$(ARMGNU)-ld --no-undefined $(OBJECTS) $(C_OBJS) -L. $(patsubst %,-l %,$(LIBRARIES)) -Map $(MAP) -o $(BUILD)output.elf -T $(LINKER)
+
+# Rule to make the object files.
+$(BUILD)%.o: $(SOURCE)%.s $(BUILD)
+	$(ARMGNU)-as -I $(SOURCE) $< -o $@
+
+$(BUILD)%.o: $(SOURCE)%.c $(BUILD)
+	$(CC) -c $(CFLAGS) $<  -o $@
+
+$(BUILD):
+	mkdir $@
+
+# Rule to clean files.
+clean : 
+	-rm -rf $(BUILD)
+	-rm -f $(TARGET)
+	-rm -f $(LIST)
+	-rm -f $(MAP)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,50 @@
+xv6_rpi_port is based on MIT xv6 (http://pdos.csail.mit.edu/6.828/2012/v6.html).
+It is ported from x86 to armv6 in Raspberry Pi (RPI). The rpi port follows
+the coding style of xv6 as much as possible to hide the architectural
+differences between x86 and armv6. The port is not for multiprocessor yet
+as RPI has only a single processor.
+
+ACKNOWLEDGEMENTS
+
+xv6_rpi_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.
+
+If you spot errors or suggest improvements, please send email to
+Zhiyi Huang (hzy@cs.otago.ac.nz).
+
+Building xv6_rpi_port:
+
+Suppose you have checked out the source with:
+
+$ git clone https://github.com/zhiyihuang/xv6_rpi_port.git
+
+On an RPI installed with Raspbian, type 'make' to make 'kernel.img'.
+
+Copy 'kernel.img' to /boot with a different name:
+# cp kernel.img /boot/kernel-xv6.img
+
+Comment out the entry 'kernel=kernel_36y.img' and add a new entry
+'kernel=kernel-xv6.img' to /boot/config.txt.
+
+Reboot the machine.
+
+Building xv6 user programs and FS (You don't need this step if you
+don't change the user programs):
+
+cd uprogs
+make initcode 
+make fs.img
+
+copy 'initcode' and 'fs.img' to the directory 'source'
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docker-setup.md	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,9 @@
+# xv6-rpi on Docker
+## build
+- ``$ docker build . --tag xv6-rpi``
+
+## run debug mode
+- ``$ docker run --privileged -it --name xv6 xv6-rpi ./run-debug.sh``
+
+## run gdb(up another process)
+- ``$ docker exec -it xv6 ./debug.sh``
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/arm.h	Sun Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,231 @@
+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 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);
+
+
+// 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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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/mailbox.h	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,38 @@
+#define MAILBOX_BASE	0xFE00B880
+
+#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 Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,37 @@
+/*****************************************************************
+*       memlayout.h
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+
+// Memory layout
+
+#define EXTMEM  	0x8000    /* start of kernel code */
+#define PHYSTOP         0xC000000  /* assuming 128M RAM; need a fix to find the true RAM size */
+#define DEVSPACE        0xFE000000      /* i/o registers */
+
+// Key addresses for address space layout (see kmap in vm.c for layout)
+#define KERNBASE 	0x80000000         // First kernel virtual address
+#define KERNLINK 	(KERNBASE+EXTMEM)  // Address where kernel is linked
+#define USERBOUND 	0x40000000        // maximum user space due to one page pgd
+#define GPUMEMBASE	0x40000000
+#define GPUMEMSIZE	(1024*MBYTE)
+
+#define PA_START 	0x0
+#define PHYSIO          0x20000000
+#define RAMSIZE         0xC000000
+#define IOSIZE          (16*MBYTE)
+#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/include/mmu.h	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,82 @@
+/*****************************************************************
+*       mmu.h
+*       by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+#define MBYTE		0x100000
+#define K_PDX_BASE	0x4000
+#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 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)|CACHED|BUFFERED|SMALL
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/param.h	Sun Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 	(DEVSPACE+0xB200)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/types.h	Sun Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,62 @@
+/******************************************************************************
+*	kernel.ld
+*	 by Alex Chadwick
+*
+*	A linker script for generation of raspberry pi kernel images.
+******************************************************************************/
+
+SECTIONS {
+        /* Link the kernel at this address: "." means the current address */
+        /* Must be equal to KERNLINK */
+        . = 0x80008000;
+
+
+	/*
+	* 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 0x80008000 : AT(0x8000) {
+		*(.init)
+	}
+	
+	/* 
+	* Next we put the rest of the code.
+	*/
+	.text : {
+		*.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)
+	}
+}
Binary file libcsud.a has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/LICENSE	Sun Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,411 @@
+/*****************************************************************
+*       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=768, framewidth=1024, framecolors=16;
+uint fontheight=16, fontwidth=8;
+FBI fbinfo __attribute__ ((aligned (16), nocommon));
+
+
+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++){
+    gpuputc(buf[i] & 0xff);
+    uartputc(buf[i] & 0xff);
+  }
+  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 = (u16 *) ((FBI *)FrameBufferInfo)->fbp;
+    addr += y*1024 + 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(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;
+	    }
+	}
+    }
+
+}
+
+
+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){
+    gpuputc(buf[i]);
+    uartputc(buf[i]);
+  }
+}
+
+
+// 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 != '%'){
+        gpuputc(c);
+	uartputc(c);
+      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++){
+        gpuputc(*s);
+	uartputc(*s);
+      }
+      break;
+    case '%':
+	gpuputc('%');
+	uartputc('%');
+      break;
+    default:
+      // Print unknown % sequence to draw attention.
+	gpuputc('%');
+	uartputc('%');
+	gpuputc(c);
+	uartputc(c);
+      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){
+    gpuputc('\b'); gpuputc(' '); gpuputc('\b');
+    uartputc('\b'); uartputc(' '); uartputc('\b');
+  } else if(c == C('D')) {
+    gpuputc('^'); gpuputc('D');
+    uartputc('^'); uartputc('D');
+  } else {
+    gpuputc(c);
+    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 consoleinit(void)
+{
+uint fbinfoaddr;
+
+  fbinfoaddr = initframebuf(framewidth, frameheight, framecolors);
+  if(fbinfoaddr != 0) NotOkLoop();
+
+  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 Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,104 @@
+/*****************************************************************
+*	entry.s
+*	by Zhiyi Huang, hzy@cs.otago.ac.nz
+*	University of Otago
+*
+********************************************************************/
+
+.section .init
+.globl _start
+_start:
+
+b entry  /* branch to the actual entry code */
+
+.section .data
+
+.align 4
+.globl font
+font:
+	.incbin "font1.bin"
+
+.align 4
+.global _binary_initcode_start
+_binary_initcode_start:
+	.incbin "initcode"
+.global _binary_initcode_end
+_binary_initcode_end:
+
+.align 4
+.global _binary_fs_img_start
+_binary_fs_img_start:
+        .incbin "fs.img"
+.global _binary_fs_img_end
+_binary_fs_img_end:
+
+
+.section .text
+
+entry:
+
+/* interrupts disabled, SVC mode by setting PSR_DISABLE_IRQ|PSR_DISABLE_FIQ|PSR_MODE_SVC */
+mov r1, #0x00000080 /* PSR_DISABLE_IRQ */
+orr r1, #0x00000040 /* PSR_DISABLE_FIQ */
+orr r1, #0x00000013 /* PSR_MODE_SVC */
+msr cpsr, r1
+
+mov sp, #0x3000 
+bl mmuinit0
+
+/* switch SP and PC into KZERO space */
+mov r1, sp
+add r1, #0x80000000
+mov sp, r1
+
+ldr r1, =_pagingstart
+bx r1
+
+.global _pagingstart
+_pagingstart:
+bl cmain  /* call C functions now */
+bl NotOkLoop
+
+.global dsb_barrier
+dsb_barrier:
+	mov r0, #0
+	mcr p15, 0, r0, c7, c10, 4
+	bx lr
+.global flush_dcache_all
+flush_dcache_all:
+	mov r0, #0
+	mcr p15, 0, r0, c7, c10, 4 /* dsb */
+	mov r0, #0
+	mcr p15, 0, r0, c7, c14, 0 /* invalidate d-cache */
+	bx lr
+.global flush_idcache
+flush_idcache:
+	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 */
+	bx lr
+.global flush_tlb
+flush_tlb:
+	mov r0, #0
+	mcr p15, 0, r0, c8, c7, 0
+	mcr p15, 0, r0, c7, c10, 4
+	bx lr
+.global flush_dcache /* flush a range of data cache flush_dcache(va1, va2) */
+flush_dcache:
+	mcrr p15, 0, r0, r1, c14
+	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, =0xFE003004 /* addr of the time-stamp lower 32 bits */
+	ldrd r0, r1, [r0]
+	bx lr
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/exception.s	Sun Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,94 @@
+#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
+
+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)
+{
+  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) >= PHYSTOP)
+    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/keyboard.s	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,210 @@
+/******************************************************************************
+*	keyboard.s
+*	 by Alex Chadwick
+*
+*	A sample assembly code implementation of the input01 operating system.
+*	See main.s for details.
+*
+*	keyboard.s contains code to do with the keyboard.
+******************************************************************************/
+
+.section .data
+/* NEW
+* The address of the keyboard we're reading from.
+* C++ Signautre: u32 KeyboardAddress;
+*/
+.align 2
+KeyboardAddress:
+	.int 0
+	
+/* NEW
+* The scan codes that were down before the current set on the keyboard.
+* C++ Signautre: u16* KeyboardOldDown;
+*/
+KeyboardOldDown:
+	.rept 6
+	.hword 0
+	.endr
+	
+/* NEW
+* KeysNoShift contains the ascii representations of the first 104 scan codes
+* when the shift key is up. Special keys are ignored.
+* C++ Signature: char* KeysNoShift;
+*/
+.align 3
+KeysNormal:
+	.byte 0x0, 0x0, 0x0, 0x0, 'a', 'b', 'c', 'd'
+	.byte 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'
+	.byte 'm', 'n', 'o', 'p', 'q', 'r', 's', 't'
+	.byte 'u', 'v', 'w', 'x', 'y', 'z', '1', '2'
+	.byte '3', '4', '5', '6', '7', '8', '9', '0'
+	.byte '\n', 0x0, '\b', '\t', ' ', '-', '=', '['
+	.byte ']', '\\', '#', ';', '\'', '`', ',', '.'
+	.byte '/', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+	.byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+	.byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+	.byte 0x0, 0x0, 0x0, 0x0, '/', '*', '-', '+'
+	.byte '\n', '1', '2', '3', '4', '5', '6', '7'
+	.byte '8', '9', '0', '.', '\\', 0x0, 0x0, '='
+	
+/* NEW
+* KeysShift contains the ascii representations of the first 104 scan codes
+* when the shift key is held. Special keys are ignored.
+* C++ Signature: char* KeysShift;
+*/
+.align 3
+KeysShift:
+	.byte 0x0, 0x0, 0x0, 0x0, 'A', 'B', 'C', 'D'
+	.byte 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L'
+	.byte 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'
+	.byte 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '"'
+	.byte '', '$', '%', '^', '&', '*', '(', ')'
+	.byte '\n', 0x0, '\b', '\t', ' ', '_', '+', '{'
+	.byte '}', '|', '~', ':', '@', '', '<', '>'
+	.byte '?', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+	.byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+	.byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+	.byte 0x0, 0x0, 0x0, 0x0, '/', '*', '-', '+'
+	.byte '\n', '1', '2', '3', '4', '5', '6', '7'
+	.byte '8', '9', '0', '.', '|', 0x0, 0x0, '='
+
+.section .text
+/* NEW
+* Updates the keyboard pressed and released data.
+* C++ Signature: void KeyboardUpdate();
+*/
+.globl KeyboardUpdate
+KeyboardUpdate:
+	push {r4,r5,lr}
+
+	kbd .req r4
+	ldr r0,=KeyboardAddress
+	ldr kbd,[r0]
+	
+	teq kbd,#0
+	bne haveKeyboard$
+
+getKeyboard$:
+	bl UsbCheckForChange
+	bl KeyboardCount
+	teq r0,#0	
+	ldreq r1,=KeyboardAddress
+	streq r0,[r1]
+	beq return$
+
+	mov r0,#0
+	bl KeyboardGetAddress
+	ldr r1,=KeyboardAddress
+	str r0,[r1]
+	teq r0,#0
+	beq return$
+	mov kbd,r0
+
+haveKeyboard$:
+	mov r5,#0
+
+	saveKeys$:
+		mov r0,kbd
+		mov r1,r5
+		bl KeyboardGetKeyDown
+
+		ldr r1,=KeyboardOldDown
+		add r1,r5,lsl #1
+		strh r0,[r1]
+		add r5,#1
+		cmp r5,#6
+		blt saveKeys$
+
+	mov r0,kbd
+	bl KeyboardPoll
+	teq r0,#0
+	bne getKeyboard$
+
+return$:
+	pop {r4,r5,pc} 
+	.unreq kbd
+	
+/* NEW
+* Returns r0=0 if a in r1 key was not pressed before the current scan, and r0
+* not 0 otherwise.
+* C++ Signature bool KeyWasDown(u16 scanCode)
+*/
+.globl KeyWasDown
+KeyWasDown:
+	ldr r1,=KeyboardOldDown
+	mov r2,#0
+
+	keySearch$:
+		ldrh r3,[r1]
+		teq r3,r0
+		moveq r0,#1
+		moveq pc,lr
+
+		add r1,#2
+		add r2,#1
+		cmp r2,#6
+		blt keySearch$
+
+	mov r0,#0
+	mov pc,lr
+	
+/* NEW
+* Returns the ascii character last typed on the keyboard, with r0=0 if no 
+* character was typed.
+* C++ Signature char KeyboardGetChar()
+*/
+.globl KeyboardGetChar
+KeyboardGetChar:	
+	ldr r0,=KeyboardAddress
+	ldr r1,[r0]
+	teq r1,#0
+	moveq r0,#0
+	moveq pc,lr
+
+	push {r4,r5,r6,lr}
+	
+	kbd .req r4
+	key .req r6
+
+	mov r4,r1	
+	mov r5,#0
+
+	keyLoop$:
+		mov r0,kbd
+		mov r1,r5
+		bl KeyboardGetKeyDown
+
+		teq r0,#0
+		beq keyLoopBreak$
+		
+		mov key,r0
+		bl KeyWasDown
+		teq r0,#0
+		bne keyLoopContinue$
+
+		cmp key,#104
+		bge keyLoopContinue$
+
+		mov r0,kbd
+		bl KeyboardGetModifiers
+
+		tst r0,#0b00100010
+		ldreq r0,=KeysNormal
+		ldrne r0,=KeysShift
+
+		ldrb r0,[r0,key]
+		teq r0,#0
+		bne keyboardGetCharReturn$
+
+	keyLoopContinue$:
+		add r5,#1
+		cmp r5,#6
+		blt keyLoop$
+		
+	keyLoopBreak$:
+	mov r0,#0		
+keyboardGetCharReturn$:
+	pop {r4,r5,r6,pc}
+	.unreq kbd
+	.unreq key
+	
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/log.c	Sun Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 */
+/* Note for Matthew: support more than one tag in buffer */
+
+
+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 += 0x40000000; /* convert to VC address space */
+	x = a & 0xfffffff0;
+	y = x | (uint)(channel & 0xf);
+
+	flush_dcache_all();
+
+	while ((inw(MAILBOX_BASE+24) & 0x80000000) != 0);
+	outw(MAILBOX_BASE+32, y);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/main.c	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,95 @@
+/*****************************************************************
+*       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 FBI fbinfo;
+extern volatile uint *mailbuffer;
+
+void OkLoop()
+{
+   setgpiofunc(16, 1); // gpio 16, set as an output
+   while(1){
+        setgpioval(16, 0);
+        delay(1000000);
+        setgpioval(16, 1);
+        delay(1000000);
+   }
+}
+
+void NotOkLoop()
+{
+   setgpiofunc(16, 1); // gpio 16, set as an output
+   while(1){
+        setgpioval(16, 0);
+        delay(100000);
+        setgpioval(16, 1);
+        delay(100000);
+   }
+}
+
+void machinit(void)
+{
+    memset(cpus, 0, sizeof(struct cpu)*NCPU);
+}
+
+
+void enableirqminiuart(void);
+
+int cmain()
+{
+
+  mmuinit1();
+  machinit();
+  uartinit();
+  dsb_barrier();
+  consoleinit();
+  cprintf("\nHello World from xv6\n");
+  kinit1(end, P2V(8*1024*1024));  // reserve 8 pages for PGDIR
+  kpgdir=p2v(K_PDX_BASE);
+
+  mailboxinit();
+  create_request(mailbuffer, MPI_TAG_GET_ARM_MEMORY, 8, 0, 0);
+  writemailbox((uint *)mailbuffer, 8);
+  readmailbox(8);
+  if(mailbuffer[1] != 0x80000000) cprintf("new error readmailbox\n");
+  else 
+cprintf("ARM memory is %x %x\n", mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH], mailbuffer[MB_HEADER_LENGTH + TAG_HEADER_LENGTH+1]);
+
+  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");
+  timer3init();
+  kinit2(P2V(8*1024*1024), P2V(PHYSTOP));
+cprintf("it is ok after kinit2\n");
+  userinit();
+cprintf("it is ok after userinit\n");
+  scheduler();
+
+
+  NotOkLoop();
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/memide.c	Sun Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,109 @@
+/*****************************************************************
+*       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"
+
+void mmuinit0(void)
+{
+        pde_t *l1;
+	pte_t *l2;
+        uint pa, va, *p;
+
+	// 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"
+		"bic r1,r1,#0x00001000\n\t"
+		"bic r1,r1,#0x00000800\n\t"
+		"bic r1,r1,#0x00000001\n\t"
+		"mcr p15, 0, r1, c1, c0, 0\n\t"
+		"mov r0, #0\n\t"
+		"mcr p15, 0, r0, c7, c7, 0\n\t"
+		"mcr p15, 0, r0, c8, c7, 0\n\t"
+		::: "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;
+	for(pa = PA_START; pa < PA_START+RAMSIZE; 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(PA_START)] = PA_START|DOMAIN0|PDX_AP(K_RW)|SECTION|CACHED|BUFFERED;
+
+        // map IO region
+        va = DEVSPACE;
+        for(pa = PHYSIO; pa < PHYSIO+IOSIZE; pa += MBYTE){
+                l1[PDX(va)] = pa|DOMAIN0|PDX_AP(K_RW)|SECTION;
+                va += MBYTE;
+        }
+
+	// map GPU memory
+	va = GPUMEMBASE;
+	for(pa = GPUMEMBASE; pa < (uint)GPUMEMBASE+(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)] = PA_START|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"
+                "orr r1, #0x00000004\n\t"
+                "orr r1, #0x00001000\n\t"
+                "orr r1, #0x00000001\n\t"
+		"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"
+                ::: "r0", "r1", "cc", "memory");
+
+}
+
+void
+mmuinit1(void)
+{
+        pde_t *l1;
+	uint va1, va2;
+
+        l1 = (pde_t*)(K_PDX_BASE);
+
+        // undo identity map of first MB of ram
+        l1[PDX(PA_START)] = 0;
+
+	// drain write buffer; writeback data cache range [va, va+n]
+	va1 = (uint)&l1[PDX(PA_START)];
+	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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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		0xFE003000
+#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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,135 @@
+/*****************************************************************
+*       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			0xFE200000
+#define GPFSEL1			0xFE200004
+#define GPFSEL2			0xFE200008
+#define GPFSEL3			0xFE20000C
+#define	GPFSEL4			0xFE200010
+#define	GPFSEL5			0xFE200014
+#define GPSET0  		0xFE20001C
+#define GPSET1			0xFE200020
+#define GPCLR0  		0xFE200028
+#define GPCLR1			0xFE20002C
+#define GPPUD       		0xFE200094
+#define GPPUDCLK0   		0xFE200098
+#define GPPUDCLK1		0xFE20009C
+
+#define AUX_IRQ			0xFE215000
+#define AUX_ENABLES     	0xFE215004
+#define AUX_MU_IO_REG   	0xFE215040
+#define AUX_MU_IER_REG  	0xFE215044
+#define AUX_MU_IIR_REG  	0xFE215048
+#define AUX_MU_LCR_REG  	0xFE21504C
+#define AUX_MU_MCR_REG  	0xFE215050
+#define AUX_MU_LSR_REG  	0xFE215054
+#define AUX_MU_MSR_REG  	0xFE215058
+#define AUX_MU_SCRATCH  	0xFE21505C
+#define AUX_MU_CNTL_REG 	0xFE215060
+#define AUX_MU_STAT_REG 	0xFE215064
+#define AUX_MU_BAUD_REG 	0xFE215068
+
+void
+setgpioval(uint func, uint val)
+{
+	uint sel, ssel, rsel;
+
+	if(func > 53) return;
+	sel = func >> 5;
+	ssel = GPSET0 + (sel << 2);
+	rsel = GPCLR0 + (sel << 2);
+	sel = func & 0x1f;
+	if(val == 0) outw(rsel, 1<<sel);
+	else outw(ssel, 1<<sel);
+}
+
+
+void
+setgpiofunc(uint func, uint alt)
+{
+	uint sel, data, shift;
+
+	if(func > 53) return;
+	sel = 0;
+	while (func > 10) {
+	    func = func - 10;
+	    sel++;
+	}
+	sel = (sel << 2) + GPFSEL0;
+	data = inw(sel);
+	shift = func + (func << 1);
+	data &= ~(7 << shift);
+	data |= alt << 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/vm.c	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,414 @@
+/*****************************************************************
+*       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
+
+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, PA_START, PHYSTOP, DOMAIN0|PDX_AP(U_RW)|SECTION|CACHED|BUFFERED, 0},
+ { (void*)DEVSPACE, PHYSIO, PHYSIO+IOSIZE, DOMAIN0|PDX_AP(U_RW)|SECTION, 0},
+ { (void*)HVECTORS, PA_START, PA_START+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(PHYSTOP) > (void*)DEVSPACE)
+    panic("PHYSTOP too high");
+  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);
+  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);
+  }
+  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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,67 @@
+# Cross-compiling (e.g., on Mac OS X)
+#TOOLPREFIX = i386-jos-elf-
+# Using native tools (e.g., on X86 Linux)
+TOOLPREFIX =
+
+
+# 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
+
+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 -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 fs.img mkfs $(UPROGS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/README	Sun Oct 22 18:25:39 2017 +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/.
Binary file uprogs/a.out has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/arm.h	Sun Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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.asm	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,1762 @@
+
+_cat:     file format elf32-littlearm
+
+
+Disassembly of section .text:
+
+00000000 <main>:
+int
+main(int argc, char *argv[])
+{
+  int fd, i;
+
+  if(argc <= 1){
+   0:	e3500001 	cmp	r0, #1
+  }
+}
+
+int
+main(int argc, char *argv[])
+{
+   4:	e92d49f8 	push	{r3, r4, r5, r6, r7, r8, fp, lr}
+   8:	e1a07000 	mov	r7, r0
+   c:	e28db01c 	add	fp, sp, #28
+    exit();
+  }
+}
+
+int
+main(int argc, char *argv[])
+  10:	c2814004 	addgt	r4, r1, #4
+  14:	c3a05001 	movgt	r5, #1
+{
+  int fd, i;
+
+  if(argc <= 1){
+  18:	da000012 	ble	68 <main+0x68>
+    cat(0);
+    exit();
+  }
+
+  for(i = 1; i < argc; i++){
+    if((fd = open(argv[i], 0)) < 0){
+  1c:	e5940000 	ldr	r0, [r4]
+  20:	e3a01000 	mov	r1, #0
+  24:	eb000137 	bl	508 <open>
+  28:	e1a06004 	mov	r6, r4
+  2c:	e2844004 	add	r4, r4, #4
+  30:	e2508000 	subs	r8, r0, #0
+  34:	ba000006 	blt	54 <main+0x54>
+      printf(1, "cat: cannot open %s\n", argv[i]);
+      exit();
+    }
+    cat(fd);
+  38:	eb00000e 	bl	78 <cat>
+  if(argc <= 1){
+    cat(0);
+    exit();
+  }
+
+  for(i = 1; i < argc; i++){
+  3c:	e2855001 	add	r5, r5, #1
+    if((fd = open(argv[i], 0)) < 0){
+      printf(1, "cat: cannot open %s\n", argv[i]);
+      exit();
+    }
+    cat(fd);
+    close(fd);
+  40:	e1a00008 	mov	r0, r8
+  44:	eb000108 	bl	46c <close>
+  if(argc <= 1){
+    cat(0);
+    exit();
+  }
+
+  for(i = 1; i < argc; i++){
+  48:	e1550007 	cmp	r5, r7
+  4c:	1afffff2 	bne	1c <main+0x1c>
+      exit();
+    }
+    cat(fd);
+    close(fd);
+  }
+  exit();
+  50:	eb0000c4 	bl	368 <exit>
+    exit();
+  }
+
+  for(i = 1; i < argc; i++){
+    if((fd = open(argv[i], 0)) < 0){
+      printf(1, "cat: cannot open %s\n", argv[i]);
+  54:	e3a00001 	mov	r0, #1
+  58:	e59f1014 	ldr	r1, [pc, #20]	; 74 <main+0x74>
+  5c:	e5962000 	ldr	r2, [r6]
+  60:	eb000213 	bl	8b4 <printf>
+      exit();
+  64:	eb0000bf 	bl	368 <exit>
+main(int argc, char *argv[])
+{
+  int fd, i;
+
+  if(argc <= 1){
+    cat(0);
+  68:	e3a00000 	mov	r0, #0
+  6c:	eb000001 	bl	78 <cat>
+    exit();
+  70:	eb0000bc 	bl	368 <exit>
+  74:	00000bb0 	.word	0x00000bb0
+
+00000078 <cat>:
+
+char buf[512];
+
+void
+cat(int fd)
+{
+  78:	e92d4818 	push	{r3, r4, fp, lr}
+  7c:	e1a04000 	mov	r4, r0
+  80:	e28db00c 	add	fp, sp, #12
+  int n;
+  while((n = read(fd, buf, sizeof(buf))) > 0)
+  84:	ea000002 	b	94 <cat+0x1c>
+    write(1, buf, n);
+  88:	e3a00001 	mov	r0, #1
+  8c:	e59f102c 	ldr	r1, [pc, #44]	; c0 <cat+0x48>
+  90:	eb0000e8 	bl	438 <write>
+
+void
+cat(int fd)
+{
+  int n;
+  while((n = read(fd, buf, sizeof(buf))) > 0)
+  94:	e3a02c02 	mov	r2, #512	; 0x200
+  98:	e1a00004 	mov	r0, r4
+  9c:	e59f101c 	ldr	r1, [pc, #28]	; c0 <cat+0x48>
+  a0:	eb0000d7 	bl	404 <read>
+  a4:	e2502000 	subs	r2, r0, #0
+  a8:	cafffff6 	bgt	88 <cat+0x10>
+    write(1, buf, n);
+  if(n < 0){
+  ac:	08bd8818 	popeq	{r3, r4, fp, pc}
+    printf(1, "cat: read error\n");
+  b0:	e3a00001 	mov	r0, #1
+  b4:	e59f1008 	ldr	r1, [pc, #8]	; c4 <cat+0x4c>
+  b8:	eb0001fd 	bl	8b4 <printf>
+    exit();
+  bc:	eb0000a9 	bl	368 <exit>
+  c0:	00000bf0 	.word	0x00000bf0
+  c4:	00000b9c 	.word	0x00000b9c
+
+000000c8 <strcpy>:
+#include "user.h"
+#include "arm.h"
+
+char*
+strcpy(char *s, char *t)
+{
+  c8:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+  char *os;
+
+  os = s;
+  while((*s++ = *t++) != 0)
+  cc:	e1a02000 	mov	r2, r0
+#include "user.h"
+#include "arm.h"
+
+char*
+strcpy(char *s, char *t)
+{
+  d0:	e28db000 	add	fp, sp, #0
+  char *os;
+
+  os = s;
+  while((*s++ = *t++) != 0)
+  d4:	e4d13001 	ldrb	r3, [r1], #1
+  d8:	e3530000 	cmp	r3, #0
+  dc:	e4c23001 	strb	r3, [r2], #1
+  e0:	1afffffb 	bne	d4 <strcpy+0xc>
+    ;
+  return os;
+}
+  e4:	e28bd000 	add	sp, fp, #0
+  e8:	e8bd0800 	pop	{fp}
+  ec:	e12fff1e 	bx	lr
+
+000000f0 <strcmp>:
+
+int
+strcmp(const char *p, const char *q)
+{
+  f0:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+  f4:	e28db000 	add	fp, sp, #0
+  while(*p && *p == *q)
+  f8:	e5d03000 	ldrb	r3, [r0]
+  fc:	e5d12000 	ldrb	r2, [r1]
+ 100:	e3530000 	cmp	r3, #0
+ 104:	1a000004 	bne	11c <strcmp+0x2c>
+ 108:	ea000005 	b	124 <strcmp+0x34>
+ 10c:	e5f03001 	ldrb	r3, [r0, #1]!
+ 110:	e3530000 	cmp	r3, #0
+ 114:	0a000006 	beq	134 <strcmp+0x44>
+ 118:	e5f12001 	ldrb	r2, [r1, #1]!
+ 11c:	e1530002 	cmp	r3, r2
+ 120:	0afffff9 	beq	10c <strcmp+0x1c>
+    p++, q++;
+  return (uchar)*p - (uchar)*q;
+}
+ 124:	e0620003 	rsb	r0, r2, r3
+ 128:	e28bd000 	add	sp, fp, #0
+ 12c:	e8bd0800 	pop	{fp}
+ 130:	e12fff1e 	bx	lr
+}
+
+int
+strcmp(const char *p, const char *q)
+{
+  while(*p && *p == *q)
+ 134:	e5d12001 	ldrb	r2, [r1, #1]
+ 138:	eafffff9 	b	124 <strcmp+0x34>
+
+0000013c <strlen>:
+  return (uchar)*p - (uchar)*q;
+}
+
+uint
+strlen(char *s)
+{
+ 13c:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 140:	e28db000 	add	fp, sp, #0
+  int n;
+
+  for(n = 0; s[n]; n++)
+ 144:	e5d03000 	ldrb	r3, [r0]
+ 148:	e3530000 	cmp	r3, #0
+ 14c:	01a00003 	moveq	r0, r3
+ 150:	0a000006 	beq	170 <strlen+0x34>
+ 154:	e1a02000 	mov	r2, r0
+ 158:	e3a03000 	mov	r3, #0
+ 15c:	e5f21001 	ldrb	r1, [r2, #1]!
+ 160:	e2833001 	add	r3, r3, #1
+ 164:	e1a00003 	mov	r0, r3
+ 168:	e3510000 	cmp	r1, #0
+ 16c:	1afffffa 	bne	15c <strlen+0x20>
+    ;
+  return n;
+}
+ 170:	e28bd000 	add	sp, fp, #0
+ 174:	e8bd0800 	pop	{fp}
+ 178:	e12fff1e 	bx	lr
+
+0000017c <memset>:
+memset(void *dst, int c, uint n)
+{
+  char *p=dst;
+  u32 rc=n;
+
+  while (rc-- > 0) *p++ = c;
+ 17c:	e3520000 	cmp	r2, #0
+  return n;
+}
+
+void*
+memset(void *dst, int c, uint n)
+{
+ 180:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 184:	e28db000 	add	fp, sp, #0
+  char *p=dst;
+  u32 rc=n;
+
+  while (rc-- > 0) *p++ = c;
+ 188:	0a000006 	beq	1a8 <memset+0x2c>
+ 18c:	e6ef1071 	uxtb	r1, r1
+ 190:	e1a03002 	mov	r3, r2
+}
+
+void*
+memset(void *dst, int c, uint n)
+{
+  char *p=dst;
+ 194:	e1a0c000 	mov	ip, r0
+  u32 rc=n;
+
+  while (rc-- > 0) *p++ = c;
+ 198:	e2533001 	subs	r3, r3, #1
+ 19c:	e4cc1001 	strb	r1, [ip], #1
+ 1a0:	1afffffc 	bne	198 <memset+0x1c>
+ 1a4:	e0800002 	add	r0, r0, r2
+  return (void *)p;
+}
+ 1a8:	e28bd000 	add	sp, fp, #0
+ 1ac:	e8bd0800 	pop	{fp}
+ 1b0:	e12fff1e 	bx	lr
+
+000001b4 <strchr>:
+
+char*
+strchr(const char *s, char c)
+{
+ 1b4:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 1b8:	e28db000 	add	fp, sp, #0
+  for(; *s; s++)
+ 1bc:	e5d03000 	ldrb	r3, [r0]
+ 1c0:	e3530000 	cmp	r3, #0
+ 1c4:	1a000004 	bne	1dc <strchr+0x28>
+ 1c8:	ea000008 	b	1f0 <strchr+0x3c>
+ 1cc:	e5d03001 	ldrb	r3, [r0, #1]
+ 1d0:	e2800001 	add	r0, r0, #1
+ 1d4:	e3530000 	cmp	r3, #0
+ 1d8:	0a000004 	beq	1f0 <strchr+0x3c>
+    if(*s == c)
+ 1dc:	e1530001 	cmp	r3, r1
+ 1e0:	1afffff9 	bne	1cc <strchr+0x18>
+      return (char*)s;
+  return 0;
+}
+ 1e4:	e28bd000 	add	sp, fp, #0
+ 1e8:	e8bd0800 	pop	{fp}
+ 1ec:	e12fff1e 	bx	lr
+strchr(const char *s, char c)
+{
+  for(; *s; s++)
+    if(*s == c)
+      return (char*)s;
+  return 0;
+ 1f0:	e1a00003 	mov	r0, r3
+ 1f4:	eafffffa 	b	1e4 <strchr+0x30>
+
+000001f8 <gets>:
+}
+
+char*
+gets(char *buf, int max)
+{
+ 1f8:	e92d49f0 	push	{r4, r5, r6, r7, r8, fp, lr}
+ 1fc:	e28db018 	add	fp, sp, #24
+ 200:	e24dd00c 	sub	sp, sp, #12
+ 204:	e1a08000 	mov	r8, r0
+ 208:	e1a07001 	mov	r7, r1
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+ 20c:	e1a06000 	mov	r6, r0
+ 210:	e3a05000 	mov	r5, #0
+ 214:	ea000008 	b	23c <gets+0x44>
+    cc = read(0, &c, 1);
+ 218:	eb000079 	bl	404 <read>
+    if(cc < 1)
+ 21c:	e3500000 	cmp	r0, #0
+ 220:	da00000b 	ble	254 <gets+0x5c>
+      break;
+    buf[i++] = c;
+ 224:	e55b301d 	ldrb	r3, [fp, #-29]
+    if(c == '\n' || c == '\r')
+ 228:	e1a05004 	mov	r5, r4
+ 22c:	e353000a 	cmp	r3, #10
+ 230:	1353000d 	cmpne	r3, #13
+
+  for(i=0; i+1 < max; ){
+    cc = read(0, &c, 1);
+    if(cc < 1)
+      break;
+    buf[i++] = c;
+ 234:	e4c63001 	strb	r3, [r6], #1
+    if(c == '\n' || c == '\r')
+ 238:	0a00000a 	beq	268 <gets+0x70>
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+    cc = read(0, &c, 1);
+ 23c:	e3a02001 	mov	r2, #1
+gets(char *buf, int max)
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+ 240:	e0854002 	add	r4, r5, r2
+ 244:	e1540007 	cmp	r4, r7
+    cc = read(0, &c, 1);
+ 248:	e3a00000 	mov	r0, #0
+ 24c:	e24b101d 	sub	r1, fp, #29
+gets(char *buf, int max)
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+ 250:	bafffff0 	blt	218 <gets+0x20>
+      break;
+    buf[i++] = c;
+    if(c == '\n' || c == '\r')
+      break;
+  }
+  buf[i] = '\0';
+ 254:	e3a03000 	mov	r3, #0
+ 258:	e7c83005 	strb	r3, [r8, r5]
+  return buf;
+}
+ 25c:	e1a00008 	mov	r0, r8
+ 260:	e24bd018 	sub	sp, fp, #24
+ 264:	e8bd89f0 	pop	{r4, r5, r6, r7, r8, fp, pc}
+gets(char *buf, int max)
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+ 268:	e1a05004 	mov	r5, r4
+ 26c:	eafffff8 	b	254 <gets+0x5c>
+
+00000270 <stat>:
+  return buf;
+}
+
+int
+stat(char *n, struct stat *st)
+{
+ 270:	e92d4830 	push	{r4, r5, fp, lr}
+ 274:	e1a05001 	mov	r5, r1
+ 278:	e28db00c 	add	fp, sp, #12
+  int fd;
+  int r;
+
+  fd = open(n, O_RDONLY);
+ 27c:	e3a01000 	mov	r1, #0
+ 280:	eb0000a0 	bl	508 <open>
+  if(fd < 0)
+ 284:	e2504000 	subs	r4, r0, #0
+    return -1;
+ 288:	b3e05000 	mvnlt	r5, #0
+{
+  int fd;
+  int r;
+
+  fd = open(n, O_RDONLY);
+  if(fd < 0)
+ 28c:	ba000004 	blt	2a4 <stat+0x34>
+    return -1;
+  r = fstat(fd, st);
+ 290:	e1a01005 	mov	r1, r5
+ 294:	eb0000c2 	bl	5a4 <fstat>
+ 298:	e1a05000 	mov	r5, r0
+  close(fd);
+ 29c:	e1a00004 	mov	r0, r4
+ 2a0:	eb000071 	bl	46c <close>
+  return r;
+}
+ 2a4:	e1a00005 	mov	r0, r5
+ 2a8:	e8bd8830 	pop	{r4, r5, fp, pc}
+
+000002ac <atoi>:
+
+int
+atoi(const char *s)
+{
+ 2ac:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 2b0:	e28db000 	add	fp, sp, #0
+  int n;
+
+  n = 0;
+  while('0' <= *s && *s <= '9')
+ 2b4:	e5d03000 	ldrb	r3, [r0]
+ 2b8:	e2432030 	sub	r2, r3, #48	; 0x30
+ 2bc:	e6ef2072 	uxtb	r2, r2
+ 2c0:	e3520009 	cmp	r2, #9
+int
+atoi(const char *s)
+{
+  int n;
+
+  n = 0;
+ 2c4:	83a00000 	movhi	r0, #0
+  while('0' <= *s && *s <= '9')
+ 2c8:	8a000009 	bhi	2f4 <atoi+0x48>
+ 2cc:	e1a02000 	mov	r2, r0
+int
+atoi(const char *s)
+{
+  int n;
+
+  n = 0;
+ 2d0:	e3a00000 	mov	r0, #0
+  while('0' <= *s && *s <= '9')
+    n = n*10 + *s++ - '0';
+ 2d4:	e0800100 	add	r0, r0, r0, lsl #2
+ 2d8:	e0830080 	add	r0, r3, r0, lsl #1
+atoi(const char *s)
+{
+  int n;
+
+  n = 0;
+  while('0' <= *s && *s <= '9')
+ 2dc:	e5f23001 	ldrb	r3, [r2, #1]!
+    n = n*10 + *s++ - '0';
+ 2e0:	e2400030 	sub	r0, r0, #48	; 0x30
+atoi(const char *s)
+{
+  int n;
+
+  n = 0;
+  while('0' <= *s && *s <= '9')
+ 2e4:	e2431030 	sub	r1, r3, #48	; 0x30
+ 2e8:	e6ef1071 	uxtb	r1, r1
+ 2ec:	e3510009 	cmp	r1, #9
+ 2f0:	9afffff7 	bls	2d4 <atoi+0x28>
+    n = n*10 + *s++ - '0';
+  return n;
+}
+ 2f4:	e28bd000 	add	sp, fp, #0
+ 2f8:	e8bd0800 	pop	{fp}
+ 2fc:	e12fff1e 	bx	lr
+
+00000300 <memmove>:
+{
+  char *dst, *src;
+  
+  dst = vdst;
+  src = vsrc;
+  while(n-- > 0)
+ 300:	e3520000 	cmp	r2, #0
+  return n;
+}
+
+void*
+memmove(void *vdst, void *vsrc, int n)
+{
+ 304:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 308:	e28db000 	add	fp, sp, #0
+  char *dst, *src;
+  
+  dst = vdst;
+  src = vsrc;
+  while(n-- > 0)
+ 30c:	da000005 	ble	328 <memmove+0x28>
+    n = n*10 + *s++ - '0';
+  return n;
+}
+
+void*
+memmove(void *vdst, void *vsrc, int n)
+ 310:	e0802002 	add	r2, r0, r2
+{
+  char *dst, *src;
+  
+  dst = vdst;
+ 314:	e1a03000 	mov	r3, r0
+  src = vsrc;
+  while(n-- > 0)
+    *dst++ = *src++;
+ 318:	e4d1c001 	ldrb	ip, [r1], #1
+ 31c:	e4c3c001 	strb	ip, [r3], #1
+{
+  char *dst, *src;
+  
+  dst = vdst;
+  src = vsrc;
+  while(n-- > 0)
+ 320:	e1530002 	cmp	r3, r2
+ 324:	1afffffb 	bne	318 <memmove+0x18>
+    *dst++ = *src++;
+  return vdst;
+}
+ 328:	e28bd000 	add	sp, fp, #0
+ 32c:	e8bd0800 	pop	{fp}
+ 330:	e12fff1e 	bx	lr
+
+00000334 <fork>:
+ 334:	e92d4000 	push	{lr}
+ 338:	e92d0008 	push	{r3}
+ 33c:	e92d0004 	push	{r2}
+ 340:	e92d0002 	push	{r1}
+ 344:	e92d0001 	push	{r0}
+ 348:	e3a00001 	mov	r0, #1
+ 34c:	ef000040 	svc	0x00000040
+ 350:	e8bd0002 	pop	{r1}
+ 354:	e8bd0002 	pop	{r1}
+ 358:	e8bd0004 	pop	{r2}
+ 35c:	e8bd0008 	pop	{r3}
+ 360:	e8bd4000 	pop	{lr}
+ 364:	e12fff1e 	bx	lr
+
+00000368 <exit>:
+ 368:	e92d4000 	push	{lr}
+ 36c:	e92d0008 	push	{r3}
+ 370:	e92d0004 	push	{r2}
+ 374:	e92d0002 	push	{r1}
+ 378:	e92d0001 	push	{r0}
+ 37c:	e3a00002 	mov	r0, #2
+ 380:	ef000040 	svc	0x00000040
+ 384:	e8bd0002 	pop	{r1}
+ 388:	e8bd0002 	pop	{r1}
+ 38c:	e8bd0004 	pop	{r2}
+ 390:	e8bd0008 	pop	{r3}
+ 394:	e8bd4000 	pop	{lr}
+ 398:	e12fff1e 	bx	lr
+
+0000039c <wait>:
+ 39c:	e92d4000 	push	{lr}
+ 3a0:	e92d0008 	push	{r3}
+ 3a4:	e92d0004 	push	{r2}
+ 3a8:	e92d0002 	push	{r1}
+ 3ac:	e92d0001 	push	{r0}
+ 3b0:	e3a00003 	mov	r0, #3
+ 3b4:	ef000040 	svc	0x00000040
+ 3b8:	e8bd0002 	pop	{r1}
+ 3bc:	e8bd0002 	pop	{r1}
+ 3c0:	e8bd0004 	pop	{r2}
+ 3c4:	e8bd0008 	pop	{r3}
+ 3c8:	e8bd4000 	pop	{lr}
+ 3cc:	e12fff1e 	bx	lr
+
+000003d0 <pipe>:
+ 3d0:	e92d4000 	push	{lr}
+ 3d4:	e92d0008 	push	{r3}
+ 3d8:	e92d0004 	push	{r2}
+ 3dc:	e92d0002 	push	{r1}
+ 3e0:	e92d0001 	push	{r0}
+ 3e4:	e3a00004 	mov	r0, #4
+ 3e8:	ef000040 	svc	0x00000040
+ 3ec:	e8bd0002 	pop	{r1}
+ 3f0:	e8bd0002 	pop	{r1}
+ 3f4:	e8bd0004 	pop	{r2}
+ 3f8:	e8bd0008 	pop	{r3}
+ 3fc:	e8bd4000 	pop	{lr}
+ 400:	e12fff1e 	bx	lr
+
+00000404 <read>:
+ 404:	e92d4000 	push	{lr}
+ 408:	e92d0008 	push	{r3}
+ 40c:	e92d0004 	push	{r2}
+ 410:	e92d0002 	push	{r1}
+ 414:	e92d0001 	push	{r0}
+ 418:	e3a00005 	mov	r0, #5
+ 41c:	ef000040 	svc	0x00000040
+ 420:	e8bd0002 	pop	{r1}
+ 424:	e8bd0002 	pop	{r1}
+ 428:	e8bd0004 	pop	{r2}
+ 42c:	e8bd0008 	pop	{r3}
+ 430:	e8bd4000 	pop	{lr}
+ 434:	e12fff1e 	bx	lr
+
+00000438 <write>:
+ 438:	e92d4000 	push	{lr}
+ 43c:	e92d0008 	push	{r3}
+ 440:	e92d0004 	push	{r2}
+ 444:	e92d0002 	push	{r1}
+ 448:	e92d0001 	push	{r0}
+ 44c:	e3a00010 	mov	r0, #16
+ 450:	ef000040 	svc	0x00000040
+ 454:	e8bd0002 	pop	{r1}
+ 458:	e8bd0002 	pop	{r1}
+ 45c:	e8bd0004 	pop	{r2}
+ 460:	e8bd0008 	pop	{r3}
+ 464:	e8bd4000 	pop	{lr}
+ 468:	e12fff1e 	bx	lr
+
+0000046c <close>:
+ 46c:	e92d4000 	push	{lr}
+ 470:	e92d0008 	push	{r3}
+ 474:	e92d0004 	push	{r2}
+ 478:	e92d0002 	push	{r1}
+ 47c:	e92d0001 	push	{r0}
+ 480:	e3a00015 	mov	r0, #21
+ 484:	ef000040 	svc	0x00000040
+ 488:	e8bd0002 	pop	{r1}
+ 48c:	e8bd0002 	pop	{r1}
+ 490:	e8bd0004 	pop	{r2}
+ 494:	e8bd0008 	pop	{r3}
+ 498:	e8bd4000 	pop	{lr}
+ 49c:	e12fff1e 	bx	lr
+
+000004a0 <kill>:
+ 4a0:	e92d4000 	push	{lr}
+ 4a4:	e92d0008 	push	{r3}
+ 4a8:	e92d0004 	push	{r2}
+ 4ac:	e92d0002 	push	{r1}
+ 4b0:	e92d0001 	push	{r0}
+ 4b4:	e3a00006 	mov	r0, #6
+ 4b8:	ef000040 	svc	0x00000040
+ 4bc:	e8bd0002 	pop	{r1}
+ 4c0:	e8bd0002 	pop	{r1}
+ 4c4:	e8bd0004 	pop	{r2}
+ 4c8:	e8bd0008 	pop	{r3}
+ 4cc:	e8bd4000 	pop	{lr}
+ 4d0:	e12fff1e 	bx	lr
+
+000004d4 <exec>:
+ 4d4:	e92d4000 	push	{lr}
+ 4d8:	e92d0008 	push	{r3}
+ 4dc:	e92d0004 	push	{r2}
+ 4e0:	e92d0002 	push	{r1}
+ 4e4:	e92d0001 	push	{r0}
+ 4e8:	e3a00007 	mov	r0, #7
+ 4ec:	ef000040 	svc	0x00000040
+ 4f0:	e8bd0002 	pop	{r1}
+ 4f4:	e8bd0002 	pop	{r1}
+ 4f8:	e8bd0004 	pop	{r2}
+ 4fc:	e8bd0008 	pop	{r3}
+ 500:	e8bd4000 	pop	{lr}
+ 504:	e12fff1e 	bx	lr
+
+00000508 <open>:
+ 508:	e92d4000 	push	{lr}
+ 50c:	e92d0008 	push	{r3}
+ 510:	e92d0004 	push	{r2}
+ 514:	e92d0002 	push	{r1}
+ 518:	e92d0001 	push	{r0}
+ 51c:	e3a0000f 	mov	r0, #15
+ 520:	ef000040 	svc	0x00000040
+ 524:	e8bd0002 	pop	{r1}
+ 528:	e8bd0002 	pop	{r1}
+ 52c:	e8bd0004 	pop	{r2}
+ 530:	e8bd0008 	pop	{r3}
+ 534:	e8bd4000 	pop	{lr}
+ 538:	e12fff1e 	bx	lr
+
+0000053c <mknod>:
+ 53c:	e92d4000 	push	{lr}
+ 540:	e92d0008 	push	{r3}
+ 544:	e92d0004 	push	{r2}
+ 548:	e92d0002 	push	{r1}
+ 54c:	e92d0001 	push	{r0}
+ 550:	e3a00011 	mov	r0, #17
+ 554:	ef000040 	svc	0x00000040
+ 558:	e8bd0002 	pop	{r1}
+ 55c:	e8bd0002 	pop	{r1}
+ 560:	e8bd0004 	pop	{r2}
+ 564:	e8bd0008 	pop	{r3}
+ 568:	e8bd4000 	pop	{lr}
+ 56c:	e12fff1e 	bx	lr
+
+00000570 <unlink>:
+ 570:	e92d4000 	push	{lr}
+ 574:	e92d0008 	push	{r3}
+ 578:	e92d0004 	push	{r2}
+ 57c:	e92d0002 	push	{r1}
+ 580:	e92d0001 	push	{r0}
+ 584:	e3a00012 	mov	r0, #18
+ 588:	ef000040 	svc	0x00000040
+ 58c:	e8bd0002 	pop	{r1}
+ 590:	e8bd0002 	pop	{r1}
+ 594:	e8bd0004 	pop	{r2}
+ 598:	e8bd0008 	pop	{r3}
+ 59c:	e8bd4000 	pop	{lr}
+ 5a0:	e12fff1e 	bx	lr
+
+000005a4 <fstat>:
+ 5a4:	e92d4000 	push	{lr}
+ 5a8:	e92d0008 	push	{r3}
+ 5ac:	e92d0004 	push	{r2}
+ 5b0:	e92d0002 	push	{r1}
+ 5b4:	e92d0001 	push	{r0}
+ 5b8:	e3a00008 	mov	r0, #8
+ 5bc:	ef000040 	svc	0x00000040
+ 5c0:	e8bd0002 	pop	{r1}
+ 5c4:	e8bd0002 	pop	{r1}
+ 5c8:	e8bd0004 	pop	{r2}
+ 5cc:	e8bd0008 	pop	{r3}
+ 5d0:	e8bd4000 	pop	{lr}
+ 5d4:	e12fff1e 	bx	lr
+
+000005d8 <link>:
+ 5d8:	e92d4000 	push	{lr}
+ 5dc:	e92d0008 	push	{r3}
+ 5e0:	e92d0004 	push	{r2}
+ 5e4:	e92d0002 	push	{r1}
+ 5e8:	e92d0001 	push	{r0}
+ 5ec:	e3a00013 	mov	r0, #19
+ 5f0:	ef000040 	svc	0x00000040
+ 5f4:	e8bd0002 	pop	{r1}
+ 5f8:	e8bd0002 	pop	{r1}
+ 5fc:	e8bd0004 	pop	{r2}
+ 600:	e8bd0008 	pop	{r3}
+ 604:	e8bd4000 	pop	{lr}
+ 608:	e12fff1e 	bx	lr
+
+0000060c <mkdir>:
+ 60c:	e92d4000 	push	{lr}
+ 610:	e92d0008 	push	{r3}
+ 614:	e92d0004 	push	{r2}
+ 618:	e92d0002 	push	{r1}
+ 61c:	e92d0001 	push	{r0}
+ 620:	e3a00014 	mov	r0, #20
+ 624:	ef000040 	svc	0x00000040
+ 628:	e8bd0002 	pop	{r1}
+ 62c:	e8bd0002 	pop	{r1}
+ 630:	e8bd0004 	pop	{r2}
+ 634:	e8bd0008 	pop	{r3}
+ 638:	e8bd4000 	pop	{lr}
+ 63c:	e12fff1e 	bx	lr
+
+00000640 <chdir>:
+ 640:	e92d4000 	push	{lr}
+ 644:	e92d0008 	push	{r3}
+ 648:	e92d0004 	push	{r2}
+ 64c:	e92d0002 	push	{r1}
+ 650:	e92d0001 	push	{r0}
+ 654:	e3a00009 	mov	r0, #9
+ 658:	ef000040 	svc	0x00000040
+ 65c:	e8bd0002 	pop	{r1}
+ 660:	e8bd0002 	pop	{r1}
+ 664:	e8bd0004 	pop	{r2}
+ 668:	e8bd0008 	pop	{r3}
+ 66c:	e8bd4000 	pop	{lr}
+ 670:	e12fff1e 	bx	lr
+
+00000674 <dup>:
+ 674:	e92d4000 	push	{lr}
+ 678:	e92d0008 	push	{r3}
+ 67c:	e92d0004 	push	{r2}
+ 680:	e92d0002 	push	{r1}
+ 684:	e92d0001 	push	{r0}
+ 688:	e3a0000a 	mov	r0, #10
+ 68c:	ef000040 	svc	0x00000040
+ 690:	e8bd0002 	pop	{r1}
+ 694:	e8bd0002 	pop	{r1}
+ 698:	e8bd0004 	pop	{r2}
+ 69c:	e8bd0008 	pop	{r3}
+ 6a0:	e8bd4000 	pop	{lr}
+ 6a4:	e12fff1e 	bx	lr
+
+000006a8 <getpid>:
+ 6a8:	e92d4000 	push	{lr}
+ 6ac:	e92d0008 	push	{r3}
+ 6b0:	e92d0004 	push	{r2}
+ 6b4:	e92d0002 	push	{r1}
+ 6b8:	e92d0001 	push	{r0}
+ 6bc:	e3a0000b 	mov	r0, #11
+ 6c0:	ef000040 	svc	0x00000040
+ 6c4:	e8bd0002 	pop	{r1}
+ 6c8:	e8bd0002 	pop	{r1}
+ 6cc:	e8bd0004 	pop	{r2}
+ 6d0:	e8bd0008 	pop	{r3}
+ 6d4:	e8bd4000 	pop	{lr}
+ 6d8:	e12fff1e 	bx	lr
+
+000006dc <sbrk>:
+ 6dc:	e92d4000 	push	{lr}
+ 6e0:	e92d0008 	push	{r3}
+ 6e4:	e92d0004 	push	{r2}
+ 6e8:	e92d0002 	push	{r1}
+ 6ec:	e92d0001 	push	{r0}
+ 6f0:	e3a0000c 	mov	r0, #12
+ 6f4:	ef000040 	svc	0x00000040
+ 6f8:	e8bd0002 	pop	{r1}
+ 6fc:	e8bd0002 	pop	{r1}
+ 700:	e8bd0004 	pop	{r2}
+ 704:	e8bd0008 	pop	{r3}
+ 708:	e8bd4000 	pop	{lr}
+ 70c:	e12fff1e 	bx	lr
+
+00000710 <sleep>:
+ 710:	e92d4000 	push	{lr}
+ 714:	e92d0008 	push	{r3}
+ 718:	e92d0004 	push	{r2}
+ 71c:	e92d0002 	push	{r1}
+ 720:	e92d0001 	push	{r0}
+ 724:	e3a0000d 	mov	r0, #13
+ 728:	ef000040 	svc	0x00000040
+ 72c:	e8bd0002 	pop	{r1}
+ 730:	e8bd0002 	pop	{r1}
+ 734:	e8bd0004 	pop	{r2}
+ 738:	e8bd0008 	pop	{r3}
+ 73c:	e8bd4000 	pop	{lr}
+ 740:	e12fff1e 	bx	lr
+
+00000744 <uptime>:
+ 744:	e92d4000 	push	{lr}
+ 748:	e92d0008 	push	{r3}
+ 74c:	e92d0004 	push	{r2}
+ 750:	e92d0002 	push	{r1}
+ 754:	e92d0001 	push	{r0}
+ 758:	e3a0000e 	mov	r0, #14
+ 75c:	ef000040 	svc	0x00000040
+ 760:	e8bd0002 	pop	{r1}
+ 764:	e8bd0002 	pop	{r1}
+ 768:	e8bd0004 	pop	{r2}
+ 76c:	e8bd0008 	pop	{r3}
+ 770:	e8bd4000 	pop	{lr}
+ 774:	e12fff1e 	bx	lr
+
+00000778 <putc>:
+#include "stat.h"
+#include "user.h"
+
+static void
+putc(int fd, char c)
+{
+ 778:	e92d4800 	push	{fp, lr}
+ 77c:	e28db004 	add	fp, sp, #4
+ 780:	e24b3004 	sub	r3, fp, #4
+ 784:	e24dd008 	sub	sp, sp, #8
+  write(fd, &c, 1);
+ 788:	e3a02001 	mov	r2, #1
+#include "stat.h"
+#include "user.h"
+
+static void
+putc(int fd, char c)
+{
+ 78c:	e5631001 	strb	r1, [r3, #-1]!
+  write(fd, &c, 1);
+ 790:	e1a01003 	mov	r1, r3
+ 794:	ebffff27 	bl	438 <write>
+}
+ 798:	e24bd004 	sub	sp, fp, #4
+ 79c:	e8bd8800 	pop	{fp, pc}
+
+000007a0 <printint>:
+    return q;
+}
+
+static void
+printint(int fd, int xx, int base, int sgn)
+{
+ 7a0:	e92d4ff0 	push	{r4, r5, r6, r7, r8, r9, sl, fp, lr}
+ 7a4:	e1a04000 	mov	r4, r0
+  char buf[16];
+  int i, neg;
+  uint x, y, b;
+
+  neg = 0;
+  if(sgn && xx < 0){
+ 7a8:	e1a00fa1 	lsr	r0, r1, #31
+ 7ac:	e3530000 	cmp	r3, #0
+ 7b0:	03a03000 	moveq	r3, #0
+ 7b4:	12003001 	andne	r3, r0, #1
+    return q;
+}
+
+static void
+printint(int fd, int xx, int base, int sgn)
+{
+ 7b8:	e28db020 	add	fp, sp, #32
+  char buf[16];
+  int i, neg;
+  uint x, y, b;
+
+  neg = 0;
+  if(sgn && xx < 0){
+ 7bc:	e3530000 	cmp	r3, #0
+    return q;
+}
+
+static void
+printint(int fd, int xx, int base, int sgn)
+{
+ 7c0:	e24dd014 	sub	sp, sp, #20
+ 7c4:	e59f909c 	ldr	r9, [pc, #156]	; 868 <printint+0xc8>
+  uint x, y, b;
+
+  neg = 0;
+  if(sgn && xx < 0){
+    neg = 1;
+    x = -xx;
+ 7c8:	12611000 	rsbne	r1, r1, #0
+  int i, neg;
+  uint x, y, b;
+
+  neg = 0;
+  if(sgn && xx < 0){
+    neg = 1;
+ 7cc:	13a03001 	movne	r3, #1
+  } else {
+    x = xx;
+  }
+
+  b = base;
+  i = 0;
+ 7d0:	e3a0a000 	mov	sl, #0
+ 7d4:	e24b6034 	sub	r6, fp, #52	; 0x34
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+        if(r >= d) {
+            r = r - d;
+            q = q | (1 << i);
+ 7d8:	e3a08001 	mov	r8, #1
+  write(fd, &c, 1);
+}
+
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+ 7dc:	e3a07000 	mov	r7, #0
+    int i;
+
+    for(i=31;i>=0;i--){
+ 7e0:	e3a0001f 	mov	r0, #31
+  write(fd, &c, 1);
+}
+
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+ 7e4:	e1a0c007 	mov	ip, r7
+    int i;
+
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+ 7e8:	e1a0e031 	lsr	lr, r1, r0
+ 7ec:	e20ee001 	and	lr, lr, #1
+ 7f0:	e18ec08c 	orr	ip, lr, ip, lsl #1
+        if(r >= d) {
+ 7f4:	e152000c 	cmp	r2, ip
+            r = r - d;
+            q = q | (1 << i);
+ 7f8:	91877018 	orrls	r7, r7, r8, lsl r0
+
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+        if(r >= d) {
+            r = r - d;
+ 7fc:	9062c00c 	rsbls	ip, r2, ip
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+    int i;
+
+    for(i=31;i>=0;i--){
+ 800:	e2500001 	subs	r0, r0, #1
+ 804:	2afffff7 	bcs	7e8 <printint+0x48>
+
+  b = base;
+  i = 0;
+  do{
+    y = div(x, b);
+    buf[i++] = digits[x - y * b];
+ 808:	e0000792 	mul	r0, r2, r7
+  }while((x = y) != 0);
+ 80c:	e3570000 	cmp	r7, #0
+
+  b = base;
+  i = 0;
+  do{
+    y = div(x, b);
+    buf[i++] = digits[x - y * b];
+ 810:	e0601001 	rsb	r1, r0, r1
+ 814:	e28a5001 	add	r5, sl, #1
+ 818:	e7d91001 	ldrb	r1, [r9, r1]
+ 81c:	e7c6100a 	strb	r1, [r6, sl]
+  }while((x = y) != 0);
+ 820:	11a01007 	movne	r1, r7
+
+  b = base;
+  i = 0;
+  do{
+    y = div(x, b);
+    buf[i++] = digits[x - y * b];
+ 824:	11a0a005 	movne	sl, r5
+ 828:	1affffeb 	bne	7dc <printint+0x3c>
+  }while((x = y) != 0);
+  if(neg)
+ 82c:	e3530000 	cmp	r3, #0
+    buf[i++] = '-';
+ 830:	124b2024 	subne	r2, fp, #36	; 0x24
+ 834:	10823005 	addne	r3, r2, r5
+ 838:	128a5002 	addne	r5, sl, #2
+
+  while(--i >= 0)
+ 83c:	e2455001 	sub	r5, r5, #1
+  do{
+    y = div(x, b);
+    buf[i++] = digits[x - y * b];
+  }while((x = y) != 0);
+  if(neg)
+    buf[i++] = '-';
+ 840:	13a0202d 	movne	r2, #45	; 0x2d
+ 844:	15432010 	strbne	r2, [r3, #-16]
+
+  while(--i >= 0)
+    putc(fd, buf[i]);
+ 848:	e7d61005 	ldrb	r1, [r6, r5]
+ 84c:	e1a00004 	mov	r0, r4
+    buf[i++] = digits[x - y * b];
+  }while((x = y) != 0);
+  if(neg)
+    buf[i++] = '-';
+
+  while(--i >= 0)
+ 850:	e2455001 	sub	r5, r5, #1
+    putc(fd, buf[i]);
+ 854:	ebffffc7 	bl	778 <putc>
+    buf[i++] = digits[x - y * b];
+  }while((x = y) != 0);
+  if(neg)
+    buf[i++] = '-';
+
+  while(--i >= 0)
+ 858:	e3750001 	cmn	r5, #1
+ 85c:	1afffff9 	bne	848 <printint+0xa8>
+    putc(fd, buf[i]);
+}
+ 860:	e24bd020 	sub	sp, fp, #32
+ 864:	e8bd8ff0 	pop	{r4, r5, r6, r7, r8, r9, sl, fp, pc}
+ 868:	00000bc8 	.word	0x00000bc8
+
+0000086c <div>:
+  write(fd, &c, 1);
+}
+
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+ 86c:	e3a03000 	mov	r3, #0
+{
+  write(fd, &c, 1);
+}
+
+u32 div(u32 n, u32 d)  // long division
+{
+ 870:	e92d0830 	push	{r4, r5, fp}
+ 874:	e1a02000 	mov	r2, r0
+ 878:	e28db008 	add	fp, sp, #8
+    u32 q=0, r=0;
+    int i;
+
+    for(i=31;i>=0;i--){
+ 87c:	e3a0c01f 	mov	ip, #31
+  write(fd, &c, 1);
+}
+
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+ 880:	e1a00003 	mov	r0, r3
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+        if(r >= d) {
+            r = r - d;
+            q = q | (1 << i);
+ 884:	e3a05001 	mov	r5, #1
+    u32 q=0, r=0;
+    int i;
+
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+ 888:	e1a04c32 	lsr	r4, r2, ip
+ 88c:	e2044001 	and	r4, r4, #1
+ 890:	e1843083 	orr	r3, r4, r3, lsl #1
+        if(r >= d) {
+ 894:	e1530001 	cmp	r3, r1
+            r = r - d;
+            q = q | (1 << i);
+ 898:	21800c15 	orrcs	r0, r0, r5, lsl ip
+
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+        if(r >= d) {
+            r = r - d;
+ 89c:	20613003 	rsbcs	r3, r1, r3
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+    int i;
+
+    for(i=31;i>=0;i--){
+ 8a0:	e25cc001 	subs	ip, ip, #1
+ 8a4:	2afffff7 	bcs	888 <div+0x1c>
+            r = r - d;
+            q = q | (1 << i);
+        }
+    }
+    return q;
+}
+ 8a8:	e24bd008 	sub	sp, fp, #8
+ 8ac:	e8bd0830 	pop	{r4, r5, fp}
+ 8b0:	e12fff1e 	bx	lr
+
+000008b4 <printf>:
+}
+
+// Print to the given fd. Only understands %d, %x, %p, %s.
+void
+printf(int fd, char *fmt, ...)
+{
+ 8b4:	e92d000e 	push	{r1, r2, r3}
+ 8b8:	e92d4ff0 	push	{r4, r5, r6, r7, r8, r9, sl, fp, lr}
+ 8bc:	e28db020 	add	fp, sp, #32
+ 8c0:	e1a05000 	mov	r5, r0
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+ 8c4:	e59b4004 	ldr	r4, [fp, #4]
+ 8c8:	e5d48000 	ldrb	r8, [r4]
+ 8cc:	e3580000 	cmp	r8, #0
+ 8d0:	0a000027 	beq	974 <printf+0xc0>
+        ap++;
+      } else if(c == 's'){
+        s = (char*)*ap;
+        ap++;
+        if(s == 0)
+          s = "(null)";
+ 8d4:	e59f712c 	ldr	r7, [pc, #300]	; a08 <printf+0x154>
+  char *s;
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+ 8d8:	e28b6008 	add	r6, fp, #8
+{
+  char *s;
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+ 8dc:	e3a0a000 	mov	sl, #0
+ 8e0:	ea000008 	b	908 <printf+0x54>
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+    c = fmt[i] & 0xff;
+    if(state == 0){
+      if(c == '%'){
+ 8e4:	e3580025 	cmp	r8, #37	; 0x25
+        state = '%';
+ 8e8:	01a0a008 	moveq	sl, r8
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+    c = fmt[i] & 0xff;
+    if(state == 0){
+      if(c == '%'){
+ 8ec:	0a000002 	beq	8fc <printf+0x48>
+        state = '%';
+      } else {
+        putc(fd, c);
+ 8f0:	e1a00005 	mov	r0, r5
+ 8f4:	e1a01008 	mov	r1, r8
+ 8f8:	ebffff9e 	bl	778 <putc>
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+ 8fc:	e5f48001 	ldrb	r8, [r4, #1]!
+ 900:	e3580000 	cmp	r8, #0
+ 904:	0a00001a 	beq	974 <printf+0xc0>
+    c = fmt[i] & 0xff;
+    if(state == 0){
+ 908:	e35a0000 	cmp	sl, #0
+ 90c:	0afffff4 	beq	8e4 <printf+0x30>
+      if(c == '%'){
+        state = '%';
+      } else {
+        putc(fd, c);
+      }
+    } else if(state == '%'){
+ 910:	e35a0025 	cmp	sl, #37	; 0x25
+ 914:	1afffff8 	bne	8fc <printf+0x48>
+      if(c == 'd'){
+ 918:	e3580064 	cmp	r8, #100	; 0x64
+ 91c:	0a00002c 	beq	9d4 <printf+0x120>
+        printint(fd, *ap, 10, 1);
+        ap++;
+      } else if(c == 'x' || c == 'p'){
+ 920:	e3580078 	cmp	r8, #120	; 0x78
+ 924:	13580070 	cmpne	r8, #112	; 0x70
+ 928:	13a09000 	movne	r9, #0
+ 92c:	03a09001 	moveq	r9, #1
+ 930:	0a000013 	beq	984 <printf+0xd0>
+        printint(fd, *ap, 16, 0);
+        ap++;
+      } else if(c == 's'){
+ 934:	e3580073 	cmp	r8, #115	; 0x73
+ 938:	0a000018 	beq	9a0 <printf+0xec>
+          s = "(null)";
+        while(*s != 0){
+          putc(fd, *s);
+          s++;
+        }
+      } else if(c == 'c'){
+ 93c:	e3580063 	cmp	r8, #99	; 0x63
+ 940:	0a00002a 	beq	9f0 <printf+0x13c>
+        putc(fd, *ap);
+        ap++;
+      } else if(c == '%'){
+ 944:	e3580025 	cmp	r8, #37	; 0x25
+        putc(fd, c);
+ 948:	e1a0100a 	mov	r1, sl
+ 94c:	e1a00005 	mov	r0, r5
+          s++;
+        }
+      } else if(c == 'c'){
+        putc(fd, *ap);
+        ap++;
+      } else if(c == '%'){
+ 950:	0a000002 	beq	960 <printf+0xac>
+        putc(fd, c);
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+ 954:	ebffff87 	bl	778 <putc>
+        putc(fd, c);
+ 958:	e1a00005 	mov	r0, r5
+ 95c:	e1a01008 	mov	r1, r8
+ 960:	ebffff84 	bl	778 <putc>
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+ 964:	e5f48001 	ldrb	r8, [r4, #1]!
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+        putc(fd, c);
+      }
+      state = 0;
+ 968:	e1a0a009 	mov	sl, r9
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+ 96c:	e3580000 	cmp	r8, #0
+ 970:	1affffe4 	bne	908 <printf+0x54>
+        putc(fd, c);
+      }
+      state = 0;
+    }
+  }
+}
+ 974:	e24bd020 	sub	sp, fp, #32
+ 978:	e8bd4ff0 	pop	{r4, r5, r6, r7, r8, r9, sl, fp, lr}
+ 97c:	e28dd00c 	add	sp, sp, #12
+ 980:	e12fff1e 	bx	lr
+    } else if(state == '%'){
+      if(c == 'd'){
+        printint(fd, *ap, 10, 1);
+        ap++;
+      } else if(c == 'x' || c == 'p'){
+        printint(fd, *ap, 16, 0);
+ 984:	e1a00005 	mov	r0, r5
+ 988:	e4961004 	ldr	r1, [r6], #4
+ 98c:	e3a02010 	mov	r2, #16
+ 990:	e3a03000 	mov	r3, #0
+ 994:	ebffff81 	bl	7a0 <printint>
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+        putc(fd, c);
+      }
+      state = 0;
+ 998:	e3a0a000 	mov	sl, #0
+ 99c:	eaffffd6 	b	8fc <printf+0x48>
+        ap++;
+      } else if(c == 'x' || c == 'p'){
+        printint(fd, *ap, 16, 0);
+        ap++;
+      } else if(c == 's'){
+        s = (char*)*ap;
+ 9a0:	e4968004 	ldr	r8, [r6], #4
+        ap++;
+        if(s == 0)
+          s = "(null)";
+ 9a4:	e3580000 	cmp	r8, #0
+ 9a8:	01a08007 	moveq	r8, r7
+        while(*s != 0){
+ 9ac:	e5d81000 	ldrb	r1, [r8]
+ 9b0:	e3510000 	cmp	r1, #0
+ 9b4:	0a000004 	beq	9cc <printf+0x118>
+          putc(fd, *s);
+ 9b8:	e1a00005 	mov	r0, r5
+ 9bc:	ebffff6d 	bl	778 <putc>
+      } else if(c == 's'){
+        s = (char*)*ap;
+        ap++;
+        if(s == 0)
+          s = "(null)";
+        while(*s != 0){
+ 9c0:	e5f81001 	ldrb	r1, [r8, #1]!
+ 9c4:	e3510000 	cmp	r1, #0
+ 9c8:	1afffffa 	bne	9b8 <printf+0x104>
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+        putc(fd, c);
+      }
+      state = 0;
+ 9cc:	e1a0a001 	mov	sl, r1
+ 9d0:	eaffffc9 	b	8fc <printf+0x48>
+      } else {
+        putc(fd, c);
+      }
+    } else if(state == '%'){
+      if(c == 'd'){
+        printint(fd, *ap, 10, 1);
+ 9d4:	e1a00005 	mov	r0, r5
+ 9d8:	e4961004 	ldr	r1, [r6], #4
+ 9dc:	e3a0200a 	mov	r2, #10
+ 9e0:	e3a03001 	mov	r3, #1
+ 9e4:	ebffff6d 	bl	7a0 <printint>
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+        putc(fd, c);
+      }
+      state = 0;
+ 9e8:	e3a0a000 	mov	sl, #0
+ 9ec:	eaffffc2 	b	8fc <printf+0x48>
+        while(*s != 0){
+          putc(fd, *s);
+          s++;
+        }
+      } else if(c == 'c'){
+        putc(fd, *ap);
+ 9f0:	e4961004 	ldr	r1, [r6], #4
+ 9f4:	e1a00005 	mov	r0, r5
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+        putc(fd, c);
+      }
+      state = 0;
+ 9f8:	e1a0a009 	mov	sl, r9
+        while(*s != 0){
+          putc(fd, *s);
+          s++;
+        }
+      } else if(c == 'c'){
+        putc(fd, *ap);
+ 9fc:	e6ef1071 	uxtb	r1, r1
+ a00:	ebffff5c 	bl	778 <putc>
+ a04:	eaffffbc 	b	8fc <printf+0x48>
+ a08:	00000bdc 	.word	0x00000bdc
+
+00000a0c <free>:
+free(void *ap)
+{
+  Header *bp, *p;
+
+  bp = (Header*)ap - 1;
+  for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
+ a0c:	e59f3098 	ldr	r3, [pc, #152]	; aac <free+0xa0>
+static Header base;
+static Header *freep;
+
+void
+free(void *ap)
+{
+ a10:	e92d0830 	push	{r4, r5, fp}
+  Header *bp, *p;
+
+  bp = (Header*)ap - 1;
+ a14:	e240c008 	sub	ip, r0, #8
+  for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
+ a18:	e5932000 	ldr	r2, [r3]
+static Header base;
+static Header *freep;
+
+void
+free(void *ap)
+{
+ a1c:	e28db008 	add	fp, sp, #8
+  Header *bp, *p;
+
+  bp = (Header*)ap - 1;
+  for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
+ a20:	e152000c 	cmp	r2, ip
+ a24:	e5921000 	ldr	r1, [r2]
+ a28:	2a000001 	bcs	a34 <free+0x28>
+ a2c:	e15c0001 	cmp	ip, r1
+ a30:	3a000007 	bcc	a54 <free+0x48>
+    if(p >= p->s.ptr && (bp > p || bp < p->s.ptr))
+ a34:	e1520001 	cmp	r2, r1
+ a38:	3a000003 	bcc	a4c <free+0x40>
+ a3c:	e152000c 	cmp	r2, ip
+ a40:	3a000003 	bcc	a54 <free+0x48>
+ a44:	e15c0001 	cmp	ip, r1
+ a48:	3a000001 	bcc	a54 <free+0x48>
+static Header base;
+static Header *freep;
+
+void
+free(void *ap)
+{
+ a4c:	e1a02001 	mov	r2, r1
+ a50:	eafffff2 	b	a20 <free+0x14>
+
+  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){
+ a54:	e5104004 	ldr	r4, [r0, #-4]
+  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;
+ a58:	e5832000 	str	r2, [r3]
+
+  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){
+ a5c:	e08c5184 	add	r5, ip, r4, lsl #3
+ a60:	e1550001 	cmp	r5, r1
+    bp->s.size += p->s.ptr->s.size;
+ a64:	05911004 	ldreq	r1, [r1, #4]
+ a68:	00814004 	addeq	r4, r1, r4
+ a6c:	05004004 	streq	r4, [r0, #-4]
+    bp->s.ptr = p->s.ptr->s.ptr;
+ a70:	05921000 	ldreq	r1, [r2]
+ a74:	05911000 	ldreq	r1, [r1]
+  } else
+    bp->s.ptr = p->s.ptr;
+ a78:	e5001008 	str	r1, [r0, #-8]
+  if(p + p->s.size == bp){
+ a7c:	e5921004 	ldr	r1, [r2, #4]
+ a80:	e0824181 	add	r4, r2, r1, lsl #3
+ a84:	e15c0004 	cmp	ip, r4
+    p->s.size += bp->s.size;
+    p->s.ptr = bp->s.ptr;
+  } else
+    p->s.ptr = bp;
+ a88:	1582c000 	strne	ip, [r2]
+    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;
+ a8c:	0510c004 	ldreq	ip, [r0, #-4]
+ a90:	008c1001 	addeq	r1, ip, r1
+ a94:	05821004 	streq	r1, [r2, #4]
+    p->s.ptr = bp->s.ptr;
+ a98:	05101008 	ldreq	r1, [r0, #-8]
+ a9c:	05821000 	streq	r1, [r2]
+  } else
+    p->s.ptr = bp;
+  freep = p;
+}
+ aa0:	e24bd008 	sub	sp, fp, #8
+ aa4:	e8bd0830 	pop	{r4, r5, fp}
+ aa8:	e12fff1e 	bx	lr
+ aac:	00000be4 	.word	0x00000be4
+
+00000ab0 <malloc>:
+  return freep;
+}
+
+void*
+malloc(uint nbytes)
+{
+ ab0:	e92d49f8 	push	{r3, r4, r5, r6, r7, r8, fp, lr}
+  Header *p, *prevp;
+  uint nunits;
+
+  nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
+ ab4:	e2804007 	add	r4, r0, #7
+  if((prevp = freep) == 0){
+ ab8:	e59f50d4 	ldr	r5, [pc, #212]	; b94 <malloc+0xe4>
+malloc(uint nbytes)
+{
+  Header *p, *prevp;
+  uint nunits;
+
+  nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
+ abc:	e1a041a4 	lsr	r4, r4, #3
+  return freep;
+}
+
+void*
+malloc(uint nbytes)
+{
+ ac0:	e28db01c 	add	fp, sp, #28
+  Header *p, *prevp;
+  uint nunits;
+
+  nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
+  if((prevp = freep) == 0){
+ ac4:	e5953000 	ldr	r3, [r5]
+malloc(uint nbytes)
+{
+  Header *p, *prevp;
+  uint nunits;
+
+  nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
+ ac8:	e2844001 	add	r4, r4, #1
+  if((prevp = freep) == 0){
+ acc:	e3530000 	cmp	r3, #0
+ ad0:	0a00002b 	beq	b84 <malloc+0xd4>
+ ad4:	e5930000 	ldr	r0, [r3]
+ ad8:	e5902004 	ldr	r2, [r0, #4]
+    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){
+ adc:	e1520004 	cmp	r2, r4
+ ae0:	2a00001b 	bcs	b54 <malloc+0xa4>
+morecore(uint nu)
+{
+  char *p;
+  Header *hp;
+
+  if(nu < 4096)
+ ae4:	e59f80ac 	ldr	r8, [pc, #172]	; b98 <malloc+0xe8>
+        p->s.size -= nunits;
+        p += p->s.size;
+        p->s.size = nunits;
+      }
+      freep = prevp;
+      return (void*)(p + 1);
+ ae8:	e1a07184 	lsl	r7, r4, #3
+ aec:	ea000003 	b	b00 <malloc+0x50>
+  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){
+ af0:	e5930000 	ldr	r0, [r3]
+    if(p->s.size >= nunits){
+ af4:	e5902004 	ldr	r2, [r0, #4]
+ af8:	e1540002 	cmp	r4, r2
+ afc:	9a000014 	bls	b54 <malloc+0xa4>
+        p->s.size = nunits;
+      }
+      freep = prevp;
+      return (void*)(p + 1);
+    }
+    if(p == freep)
+ b00:	e5952000 	ldr	r2, [r5]
+ b04:	e1a03000 	mov	r3, r0
+ b08:	e1500002 	cmp	r0, r2
+ b0c:	1afffff7 	bne	af0 <malloc+0x40>
+morecore(uint nu)
+{
+  char *p;
+  Header *hp;
+
+  if(nu < 4096)
+ b10:	e1540008 	cmp	r4, r8
+    nu = 4096;
+  p = sbrk(nu * sizeof(Header));
+ b14:	81a00007 	movhi	r0, r7
+ b18:	93a00902 	movls	r0, #32768	; 0x8000
+morecore(uint nu)
+{
+  char *p;
+  Header *hp;
+
+  if(nu < 4096)
+ b1c:	81a06004 	movhi	r6, r4
+ b20:	93a06a01 	movls	r6, #4096	; 0x1000
+    nu = 4096;
+  p = sbrk(nu * sizeof(Header));
+ b24:	ebfffeec 	bl	6dc <sbrk>
+ b28:	e1a03000 	mov	r3, r0
+  if(p == (char*)-1)
+ b2c:	e3730001 	cmn	r3, #1
+    return 0;
+  hp = (Header*)p;
+  hp->s.size = nu;
+  free((void*)(hp + 1));
+ b30:	e2800008 	add	r0, r0, #8
+  Header *hp;
+
+  if(nu < 4096)
+    nu = 4096;
+  p = sbrk(nu * sizeof(Header));
+  if(p == (char*)-1)
+ b34:	0a000010 	beq	b7c <malloc+0xcc>
+    return 0;
+  hp = (Header*)p;
+  hp->s.size = nu;
+ b38:	e5836004 	str	r6, [r3, #4]
+  free((void*)(hp + 1));
+ b3c:	ebffffb2 	bl	a0c <free>
+  return freep;
+ b40:	e5953000 	ldr	r3, [r5]
+      }
+      freep = prevp;
+      return (void*)(p + 1);
+    }
+    if(p == freep)
+      if((p = morecore(nunits)) == 0)
+ b44:	e3530000 	cmp	r3, #0
+ b48:	1affffe8 	bne	af0 <malloc+0x40>
+        return 0;
+ b4c:	e1a00003 	mov	r0, r3
+  }
+}
+ b50:	e8bd89f8 	pop	{r3, r4, r5, r6, r7, r8, fp, pc}
+    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)
+ b54:	e1540002 	cmp	r4, r2
+        prevp->s.ptr = p->s.ptr;
+      else {
+        p->s.size -= nunits;
+ b58:	10642002 	rsbne	r2, r4, r2
+ b5c:	15802004 	strne	r2, [r0, #4]
+    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;
+ b60:	05902000 	ldreq	r2, [r0]
+      else {
+        p->s.size -= nunits;
+        p += p->s.size;
+ b64:	10800182 	addne	r0, r0, r2, lsl #3
+    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;
+ b68:	05832000 	streq	r2, [r3]
+      else {
+        p->s.size -= nunits;
+        p += p->s.size;
+        p->s.size = nunits;
+ b6c:	15804004 	strne	r4, [r0, #4]
+      }
+      freep = prevp;
+ b70:	e5853000 	str	r3, [r5]
+      return (void*)(p + 1);
+ b74:	e2800008 	add	r0, r0, #8
+ b78:	e8bd89f8 	pop	{r3, r4, r5, r6, r7, r8, fp, pc}
+    }
+    if(p == freep)
+      if((p = morecore(nunits)) == 0)
+        return 0;
+ b7c:	e3a00000 	mov	r0, #0
+ b80:	e8bd89f8 	pop	{r3, r4, r5, r6, r7, r8, fp, pc}
+  Header *p, *prevp;
+  uint nunits;
+
+  nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
+  if((prevp = freep) == 0){
+    base.s.ptr = freep = prevp = &base;
+ b84:	e2850004 	add	r0, r5, #4
+ b88:	e5850000 	str	r0, [r5]
+    base.s.size = 0;
+ b8c:	e9850009 	stmib	r5, {r0, r3}
+ b90:	eaffffd3 	b	ae4 <malloc+0x34>
+ b94:	00000be4 	.word	0x00000be4
+ b98:	00000fff 	.word	0x00000fff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/cat.c	Sun Oct 22 18:25:39 2017 +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/cat.sym	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,66 @@
+00000000 .text
+00000b9c .rodata
+00000be4 .bss
+00000000 .comment
+00000000 .ARM.attributes
+00000000 .debug_aranges
+00000000 .debug_info
+00000000 .debug_abbrev
+00000000 .debug_line
+00000000 .debug_frame
+00000000 .debug_str
+00000000 .debug_loc
+00000000 .debug_ranges
+00000000 cat.c
+00000000 ulib.c
+00000000 printf.c
+00000778 putc
+000007a0 printint
+00000bc8 digits.993
+00000000 umalloc.c
+00000be4 freep
+00000be8 base
+000000c8 strcpy
+000008b4 printf
+00000300 memmove
+0000053c mknod
+00000df0 _bss_end__
+000001f8 gets
+000006a8 getpid
+00000078 cat
+00000ab0 malloc
+00000710 sleep
+00000be4 __bss_start__
+000003d0 pipe
+00000438 write
+000005a4 fstat
+000004a0 kill
+00000640 chdir
+000004d4 exec
+00000df0 __bss_end__
+0000039c wait
+00000404 read
+00000570 unlink
+00000334 fork
+000006dc sbrk
+00000744 uptime
+00000be4 __bss_start
+0000017c memset
+00000000 main
+00000df0 __end__
+000000f0 strcmp
+00000674 dup
+00000bf0 buf
+00000270 stat
+00000be4 _edata
+00000df0 _end
+000005d8 link
+00000368 exit
+000002ac atoi
+0000013c strlen
+00000508 open
+0000086c div
+000001b4 strchr
+0000060c mkdir
+0000046c close
+00000a0c free
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/defs.h	Sun Oct 22 18:25:39 2017 +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.asm	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,1665 @@
+
+_echo:     file format elf32-littlearm
+
+
+Disassembly of section .text:
+
+00000000 <main>:
+int
+main(int argc, char *argv[])
+{
+  int i;
+
+  for(i = 1; i < argc; i++)
+   0:	e3500001 	cmp	r0, #1
+#include "stat.h"
+#include "user.h"
+
+int
+main(int argc, char *argv[])
+{
+   4:	e92d4878 	push	{r3, r4, r5, r6, fp, lr}
+   8:	e1a06000 	mov	r6, r0
+   c:	e28db014 	add	fp, sp, #20
+  int i;
+
+  for(i = 1; i < argc; i++)
+  10:	da000011 	ble	5c <main+0x5c>
+  14:	e3a04001 	mov	r4, #1
+  18:	e1a05001 	mov	r5, r1
+    printf(1, "%s%s", argv[i], i+1 < argc ? " " : "\n");
+  1c:	e2844001 	add	r4, r4, #1
+  20:	e1540006 	cmp	r4, r6
+  24:	e5b52004 	ldr	r2, [r5, #4]!
+  28:	e3a00001 	mov	r0, #1
+  2c:	e59f102c 	ldr	r1, [pc, #44]	; 60 <main+0x60>
+  30:	0a000007 	beq	54 <main+0x54>
+  34:	e59f3028 	ldr	r3, [pc, #40]	; 64 <main+0x64>
+  38:	e2844001 	add	r4, r4, #1
+  3c:	eb000205 	bl	858 <printf>
+  40:	e1540006 	cmp	r4, r6
+  44:	e5b52004 	ldr	r2, [r5, #4]!
+  48:	e3a00001 	mov	r0, #1
+  4c:	e59f100c 	ldr	r1, [pc, #12]	; 60 <main+0x60>
+  50:	1afffff7 	bne	34 <main+0x34>
+  54:	e59f300c 	ldr	r3, [pc, #12]	; 68 <main+0x68>
+  58:	eb0001fe 	bl	858 <printf>
+  exit();
+  5c:	eb0000aa 	bl	30c <exit>
+  60:	00000b40 	.word	0x00000b40
+  64:	00000b48 	.word	0x00000b48
+  68:	00000b4c 	.word	0x00000b4c
+
+0000006c <strcpy>:
+#include "user.h"
+#include "arm.h"
+
+char*
+strcpy(char *s, char *t)
+{
+  6c:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+  char *os;
+
+  os = s;
+  while((*s++ = *t++) != 0)
+  70:	e1a02000 	mov	r2, r0
+#include "user.h"
+#include "arm.h"
+
+char*
+strcpy(char *s, char *t)
+{
+  74:	e28db000 	add	fp, sp, #0
+  char *os;
+
+  os = s;
+  while((*s++ = *t++) != 0)
+  78:	e4d13001 	ldrb	r3, [r1], #1
+  7c:	e3530000 	cmp	r3, #0
+  80:	e4c23001 	strb	r3, [r2], #1
+  84:	1afffffb 	bne	78 <strcpy+0xc>
+    ;
+  return os;
+}
+  88:	e28bd000 	add	sp, fp, #0
+  8c:	e8bd0800 	pop	{fp}
+  90:	e12fff1e 	bx	lr
+
+00000094 <strcmp>:
+
+int
+strcmp(const char *p, const char *q)
+{
+  94:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+  98:	e28db000 	add	fp, sp, #0
+  while(*p && *p == *q)
+  9c:	e5d03000 	ldrb	r3, [r0]
+  a0:	e5d12000 	ldrb	r2, [r1]
+  a4:	e3530000 	cmp	r3, #0
+  a8:	1a000004 	bne	c0 <strcmp+0x2c>
+  ac:	ea000005 	b	c8 <strcmp+0x34>
+  b0:	e5f03001 	ldrb	r3, [r0, #1]!
+  b4:	e3530000 	cmp	r3, #0
+  b8:	0a000006 	beq	d8 <strcmp+0x44>
+  bc:	e5f12001 	ldrb	r2, [r1, #1]!
+  c0:	e1530002 	cmp	r3, r2
+  c4:	0afffff9 	beq	b0 <strcmp+0x1c>
+    p++, q++;
+  return (uchar)*p - (uchar)*q;
+}
+  c8:	e0620003 	rsb	r0, r2, r3
+  cc:	e28bd000 	add	sp, fp, #0
+  d0:	e8bd0800 	pop	{fp}
+  d4:	e12fff1e 	bx	lr
+}
+
+int
+strcmp(const char *p, const char *q)
+{
+  while(*p && *p == *q)
+  d8:	e5d12001 	ldrb	r2, [r1, #1]
+  dc:	eafffff9 	b	c8 <strcmp+0x34>
+
+000000e0 <strlen>:
+  return (uchar)*p - (uchar)*q;
+}
+
+uint
+strlen(char *s)
+{
+  e0:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+  e4:	e28db000 	add	fp, sp, #0
+  int n;
+
+  for(n = 0; s[n]; n++)
+  e8:	e5d03000 	ldrb	r3, [r0]
+  ec:	e3530000 	cmp	r3, #0
+  f0:	01a00003 	moveq	r0, r3
+  f4:	0a000006 	beq	114 <strlen+0x34>
+  f8:	e1a02000 	mov	r2, r0
+  fc:	e3a03000 	mov	r3, #0
+ 100:	e5f21001 	ldrb	r1, [r2, #1]!
+ 104:	e2833001 	add	r3, r3, #1
+ 108:	e1a00003 	mov	r0, r3
+ 10c:	e3510000 	cmp	r1, #0
+ 110:	1afffffa 	bne	100 <strlen+0x20>
+    ;
+  return n;
+}
+ 114:	e28bd000 	add	sp, fp, #0
+ 118:	e8bd0800 	pop	{fp}
+ 11c:	e12fff1e 	bx	lr
+
+00000120 <memset>:
+memset(void *dst, int c, uint n)
+{
+  char *p=dst;
+  u32 rc=n;
+
+  while (rc-- > 0) *p++ = c;
+ 120:	e3520000 	cmp	r2, #0
+  return n;
+}
+
+void*
+memset(void *dst, int c, uint n)
+{
+ 124:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 128:	e28db000 	add	fp, sp, #0
+  char *p=dst;
+  u32 rc=n;
+
+  while (rc-- > 0) *p++ = c;
+ 12c:	0a000006 	beq	14c <memset+0x2c>
+ 130:	e6ef1071 	uxtb	r1, r1
+ 134:	e1a03002 	mov	r3, r2
+}
+
+void*
+memset(void *dst, int c, uint n)
+{
+  char *p=dst;
+ 138:	e1a0c000 	mov	ip, r0
+  u32 rc=n;
+
+  while (rc-- > 0) *p++ = c;
+ 13c:	e2533001 	subs	r3, r3, #1
+ 140:	e4cc1001 	strb	r1, [ip], #1
+ 144:	1afffffc 	bne	13c <memset+0x1c>
+ 148:	e0800002 	add	r0, r0, r2
+  return (void *)p;
+}
+ 14c:	e28bd000 	add	sp, fp, #0
+ 150:	e8bd0800 	pop	{fp}
+ 154:	e12fff1e 	bx	lr
+
+00000158 <strchr>:
+
+char*
+strchr(const char *s, char c)
+{
+ 158:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 15c:	e28db000 	add	fp, sp, #0
+  for(; *s; s++)
+ 160:	e5d03000 	ldrb	r3, [r0]
+ 164:	e3530000 	cmp	r3, #0
+ 168:	1a000004 	bne	180 <strchr+0x28>
+ 16c:	ea000008 	b	194 <strchr+0x3c>
+ 170:	e5d03001 	ldrb	r3, [r0, #1]
+ 174:	e2800001 	add	r0, r0, #1
+ 178:	e3530000 	cmp	r3, #0
+ 17c:	0a000004 	beq	194 <strchr+0x3c>
+    if(*s == c)
+ 180:	e1530001 	cmp	r3, r1
+ 184:	1afffff9 	bne	170 <strchr+0x18>
+      return (char*)s;
+  return 0;
+}
+ 188:	e28bd000 	add	sp, fp, #0
+ 18c:	e8bd0800 	pop	{fp}
+ 190:	e12fff1e 	bx	lr
+strchr(const char *s, char c)
+{
+  for(; *s; s++)
+    if(*s == c)
+      return (char*)s;
+  return 0;
+ 194:	e1a00003 	mov	r0, r3
+ 198:	eafffffa 	b	188 <strchr+0x30>
+
+0000019c <gets>:
+}
+
+char*
+gets(char *buf, int max)
+{
+ 19c:	e92d49f0 	push	{r4, r5, r6, r7, r8, fp, lr}
+ 1a0:	e28db018 	add	fp, sp, #24
+ 1a4:	e24dd00c 	sub	sp, sp, #12
+ 1a8:	e1a08000 	mov	r8, r0
+ 1ac:	e1a07001 	mov	r7, r1
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+ 1b0:	e1a06000 	mov	r6, r0
+ 1b4:	e3a05000 	mov	r5, #0
+ 1b8:	ea000008 	b	1e0 <gets+0x44>
+    cc = read(0, &c, 1);
+ 1bc:	eb000079 	bl	3a8 <read>
+    if(cc < 1)
+ 1c0:	e3500000 	cmp	r0, #0
+ 1c4:	da00000b 	ble	1f8 <gets+0x5c>
+      break;
+    buf[i++] = c;
+ 1c8:	e55b301d 	ldrb	r3, [fp, #-29]
+    if(c == '\n' || c == '\r')
+ 1cc:	e1a05004 	mov	r5, r4
+ 1d0:	e353000a 	cmp	r3, #10
+ 1d4:	1353000d 	cmpne	r3, #13
+
+  for(i=0; i+1 < max; ){
+    cc = read(0, &c, 1);
+    if(cc < 1)
+      break;
+    buf[i++] = c;
+ 1d8:	e4c63001 	strb	r3, [r6], #1
+    if(c == '\n' || c == '\r')
+ 1dc:	0a00000a 	beq	20c <gets+0x70>
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+    cc = read(0, &c, 1);
+ 1e0:	e3a02001 	mov	r2, #1
+gets(char *buf, int max)
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+ 1e4:	e0854002 	add	r4, r5, r2
+ 1e8:	e1540007 	cmp	r4, r7
+    cc = read(0, &c, 1);
+ 1ec:	e3a00000 	mov	r0, #0
+ 1f0:	e24b101d 	sub	r1, fp, #29
+gets(char *buf, int max)
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+ 1f4:	bafffff0 	blt	1bc <gets+0x20>
+      break;
+    buf[i++] = c;
+    if(c == '\n' || c == '\r')
+      break;
+  }
+  buf[i] = '\0';
+ 1f8:	e3a03000 	mov	r3, #0
+ 1fc:	e7c83005 	strb	r3, [r8, r5]
+  return buf;
+}
+ 200:	e1a00008 	mov	r0, r8
+ 204:	e24bd018 	sub	sp, fp, #24
+ 208:	e8bd89f0 	pop	{r4, r5, r6, r7, r8, fp, pc}
+gets(char *buf, int max)
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+ 20c:	e1a05004 	mov	r5, r4
+ 210:	eafffff8 	b	1f8 <gets+0x5c>
+
+00000214 <stat>:
+  return buf;
+}
+
+int
+stat(char *n, struct stat *st)
+{
+ 214:	e92d4830 	push	{r4, r5, fp, lr}
+ 218:	e1a05001 	mov	r5, r1
+ 21c:	e28db00c 	add	fp, sp, #12
+  int fd;
+  int r;
+
+  fd = open(n, O_RDONLY);
+ 220:	e3a01000 	mov	r1, #0
+ 224:	eb0000a0 	bl	4ac <open>
+  if(fd < 0)
+ 228:	e2504000 	subs	r4, r0, #0
+    return -1;
+ 22c:	b3e05000 	mvnlt	r5, #0
+{
+  int fd;
+  int r;
+
+  fd = open(n, O_RDONLY);
+  if(fd < 0)
+ 230:	ba000004 	blt	248 <stat+0x34>
+    return -1;
+  r = fstat(fd, st);
+ 234:	e1a01005 	mov	r1, r5
+ 238:	eb0000c2 	bl	548 <fstat>
+ 23c:	e1a05000 	mov	r5, r0
+  close(fd);
+ 240:	e1a00004 	mov	r0, r4
+ 244:	eb000071 	bl	410 <close>
+  return r;
+}
+ 248:	e1a00005 	mov	r0, r5
+ 24c:	e8bd8830 	pop	{r4, r5, fp, pc}
+
+00000250 <atoi>:
+
+int
+atoi(const char *s)
+{
+ 250:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 254:	e28db000 	add	fp, sp, #0
+  int n;
+
+  n = 0;
+  while('0' <= *s && *s <= '9')
+ 258:	e5d03000 	ldrb	r3, [r0]
+ 25c:	e2432030 	sub	r2, r3, #48	; 0x30
+ 260:	e6ef2072 	uxtb	r2, r2
+ 264:	e3520009 	cmp	r2, #9
+int
+atoi(const char *s)
+{
+  int n;
+
+  n = 0;
+ 268:	83a00000 	movhi	r0, #0
+  while('0' <= *s && *s <= '9')
+ 26c:	8a000009 	bhi	298 <atoi+0x48>
+ 270:	e1a02000 	mov	r2, r0
+int
+atoi(const char *s)
+{
+  int n;
+
+  n = 0;
+ 274:	e3a00000 	mov	r0, #0
+  while('0' <= *s && *s <= '9')
+    n = n*10 + *s++ - '0';
+ 278:	e0800100 	add	r0, r0, r0, lsl #2
+ 27c:	e0830080 	add	r0, r3, r0, lsl #1
+atoi(const char *s)
+{
+  int n;
+
+  n = 0;
+  while('0' <= *s && *s <= '9')
+ 280:	e5f23001 	ldrb	r3, [r2, #1]!
+    n = n*10 + *s++ - '0';
+ 284:	e2400030 	sub	r0, r0, #48	; 0x30
+atoi(const char *s)
+{
+  int n;
+
+  n = 0;
+  while('0' <= *s && *s <= '9')
+ 288:	e2431030 	sub	r1, r3, #48	; 0x30
+ 28c:	e6ef1071 	uxtb	r1, r1
+ 290:	e3510009 	cmp	r1, #9
+ 294:	9afffff7 	bls	278 <atoi+0x28>
+    n = n*10 + *s++ - '0';
+  return n;
+}
+ 298:	e28bd000 	add	sp, fp, #0
+ 29c:	e8bd0800 	pop	{fp}
+ 2a0:	e12fff1e 	bx	lr
+
+000002a4 <memmove>:
+{
+  char *dst, *src;
+  
+  dst = vdst;
+  src = vsrc;
+  while(n-- > 0)
+ 2a4:	e3520000 	cmp	r2, #0
+  return n;
+}
+
+void*
+memmove(void *vdst, void *vsrc, int n)
+{
+ 2a8:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 2ac:	e28db000 	add	fp, sp, #0
+  char *dst, *src;
+  
+  dst = vdst;
+  src = vsrc;
+  while(n-- > 0)
+ 2b0:	da000005 	ble	2cc <memmove+0x28>
+    n = n*10 + *s++ - '0';
+  return n;
+}
+
+void*
+memmove(void *vdst, void *vsrc, int n)
+ 2b4:	e0802002 	add	r2, r0, r2
+{
+  char *dst, *src;
+  
+  dst = vdst;
+ 2b8:	e1a03000 	mov	r3, r0
+  src = vsrc;
+  while(n-- > 0)
+    *dst++ = *src++;
+ 2bc:	e4d1c001 	ldrb	ip, [r1], #1
+ 2c0:	e4c3c001 	strb	ip, [r3], #1
+{
+  char *dst, *src;
+  
+  dst = vdst;
+  src = vsrc;
+  while(n-- > 0)
+ 2c4:	e1530002 	cmp	r3, r2
+ 2c8:	1afffffb 	bne	2bc <memmove+0x18>
+    *dst++ = *src++;
+  return vdst;
+}
+ 2cc:	e28bd000 	add	sp, fp, #0
+ 2d0:	e8bd0800 	pop	{fp}
+ 2d4:	e12fff1e 	bx	lr
+
+000002d8 <fork>:
+ 2d8:	e92d4000 	push	{lr}
+ 2dc:	e92d0008 	push	{r3}
+ 2e0:	e92d0004 	push	{r2}
+ 2e4:	e92d0002 	push	{r1}
+ 2e8:	e92d0001 	push	{r0}
+ 2ec:	e3a00001 	mov	r0, #1
+ 2f0:	ef000040 	svc	0x00000040
+ 2f4:	e8bd0002 	pop	{r1}
+ 2f8:	e8bd0002 	pop	{r1}
+ 2fc:	e8bd0004 	pop	{r2}
+ 300:	e8bd0008 	pop	{r3}
+ 304:	e8bd4000 	pop	{lr}
+ 308:	e12fff1e 	bx	lr
+
+0000030c <exit>:
+ 30c:	e92d4000 	push	{lr}
+ 310:	e92d0008 	push	{r3}
+ 314:	e92d0004 	push	{r2}
+ 318:	e92d0002 	push	{r1}
+ 31c:	e92d0001 	push	{r0}
+ 320:	e3a00002 	mov	r0, #2
+ 324:	ef000040 	svc	0x00000040
+ 328:	e8bd0002 	pop	{r1}
+ 32c:	e8bd0002 	pop	{r1}
+ 330:	e8bd0004 	pop	{r2}
+ 334:	e8bd0008 	pop	{r3}
+ 338:	e8bd4000 	pop	{lr}
+ 33c:	e12fff1e 	bx	lr
+
+00000340 <wait>:
+ 340:	e92d4000 	push	{lr}
+ 344:	e92d0008 	push	{r3}
+ 348:	e92d0004 	push	{r2}
+ 34c:	e92d0002 	push	{r1}
+ 350:	e92d0001 	push	{r0}
+ 354:	e3a00003 	mov	r0, #3
+ 358:	ef000040 	svc	0x00000040
+ 35c:	e8bd0002 	pop	{r1}
+ 360:	e8bd0002 	pop	{r1}
+ 364:	e8bd0004 	pop	{r2}
+ 368:	e8bd0008 	pop	{r3}
+ 36c:	e8bd4000 	pop	{lr}
+ 370:	e12fff1e 	bx	lr
+
+00000374 <pipe>:
+ 374:	e92d4000 	push	{lr}
+ 378:	e92d0008 	push	{r3}
+ 37c:	e92d0004 	push	{r2}
+ 380:	e92d0002 	push	{r1}
+ 384:	e92d0001 	push	{r0}
+ 388:	e3a00004 	mov	r0, #4
+ 38c:	ef000040 	svc	0x00000040
+ 390:	e8bd0002 	pop	{r1}
+ 394:	e8bd0002 	pop	{r1}
+ 398:	e8bd0004 	pop	{r2}
+ 39c:	e8bd0008 	pop	{r3}
+ 3a0:	e8bd4000 	pop	{lr}
+ 3a4:	e12fff1e 	bx	lr
+
+000003a8 <read>:
+ 3a8:	e92d4000 	push	{lr}
+ 3ac:	e92d0008 	push	{r3}
+ 3b0:	e92d0004 	push	{r2}
+ 3b4:	e92d0002 	push	{r1}
+ 3b8:	e92d0001 	push	{r0}
+ 3bc:	e3a00005 	mov	r0, #5
+ 3c0:	ef000040 	svc	0x00000040
+ 3c4:	e8bd0002 	pop	{r1}
+ 3c8:	e8bd0002 	pop	{r1}
+ 3cc:	e8bd0004 	pop	{r2}
+ 3d0:	e8bd0008 	pop	{r3}
+ 3d4:	e8bd4000 	pop	{lr}
+ 3d8:	e12fff1e 	bx	lr
+
+000003dc <write>:
+ 3dc:	e92d4000 	push	{lr}
+ 3e0:	e92d0008 	push	{r3}
+ 3e4:	e92d0004 	push	{r2}
+ 3e8:	e92d0002 	push	{r1}
+ 3ec:	e92d0001 	push	{r0}
+ 3f0:	e3a00010 	mov	r0, #16
+ 3f4:	ef000040 	svc	0x00000040
+ 3f8:	e8bd0002 	pop	{r1}
+ 3fc:	e8bd0002 	pop	{r1}
+ 400:	e8bd0004 	pop	{r2}
+ 404:	e8bd0008 	pop	{r3}
+ 408:	e8bd4000 	pop	{lr}
+ 40c:	e12fff1e 	bx	lr
+
+00000410 <close>:
+ 410:	e92d4000 	push	{lr}
+ 414:	e92d0008 	push	{r3}
+ 418:	e92d0004 	push	{r2}
+ 41c:	e92d0002 	push	{r1}
+ 420:	e92d0001 	push	{r0}
+ 424:	e3a00015 	mov	r0, #21
+ 428:	ef000040 	svc	0x00000040
+ 42c:	e8bd0002 	pop	{r1}
+ 430:	e8bd0002 	pop	{r1}
+ 434:	e8bd0004 	pop	{r2}
+ 438:	e8bd0008 	pop	{r3}
+ 43c:	e8bd4000 	pop	{lr}
+ 440:	e12fff1e 	bx	lr
+
+00000444 <kill>:
+ 444:	e92d4000 	push	{lr}
+ 448:	e92d0008 	push	{r3}
+ 44c:	e92d0004 	push	{r2}
+ 450:	e92d0002 	push	{r1}
+ 454:	e92d0001 	push	{r0}
+ 458:	e3a00006 	mov	r0, #6
+ 45c:	ef000040 	svc	0x00000040
+ 460:	e8bd0002 	pop	{r1}
+ 464:	e8bd0002 	pop	{r1}
+ 468:	e8bd0004 	pop	{r2}
+ 46c:	e8bd0008 	pop	{r3}
+ 470:	e8bd4000 	pop	{lr}
+ 474:	e12fff1e 	bx	lr
+
+00000478 <exec>:
+ 478:	e92d4000 	push	{lr}
+ 47c:	e92d0008 	push	{r3}
+ 480:	e92d0004 	push	{r2}
+ 484:	e92d0002 	push	{r1}
+ 488:	e92d0001 	push	{r0}
+ 48c:	e3a00007 	mov	r0, #7
+ 490:	ef000040 	svc	0x00000040
+ 494:	e8bd0002 	pop	{r1}
+ 498:	e8bd0002 	pop	{r1}
+ 49c:	e8bd0004 	pop	{r2}
+ 4a0:	e8bd0008 	pop	{r3}
+ 4a4:	e8bd4000 	pop	{lr}
+ 4a8:	e12fff1e 	bx	lr
+
+000004ac <open>:
+ 4ac:	e92d4000 	push	{lr}
+ 4b0:	e92d0008 	push	{r3}
+ 4b4:	e92d0004 	push	{r2}
+ 4b8:	e92d0002 	push	{r1}
+ 4bc:	e92d0001 	push	{r0}
+ 4c0:	e3a0000f 	mov	r0, #15
+ 4c4:	ef000040 	svc	0x00000040
+ 4c8:	e8bd0002 	pop	{r1}
+ 4cc:	e8bd0002 	pop	{r1}
+ 4d0:	e8bd0004 	pop	{r2}
+ 4d4:	e8bd0008 	pop	{r3}
+ 4d8:	e8bd4000 	pop	{lr}
+ 4dc:	e12fff1e 	bx	lr
+
+000004e0 <mknod>:
+ 4e0:	e92d4000 	push	{lr}
+ 4e4:	e92d0008 	push	{r3}
+ 4e8:	e92d0004 	push	{r2}
+ 4ec:	e92d0002 	push	{r1}
+ 4f0:	e92d0001 	push	{r0}
+ 4f4:	e3a00011 	mov	r0, #17
+ 4f8:	ef000040 	svc	0x00000040
+ 4fc:	e8bd0002 	pop	{r1}
+ 500:	e8bd0002 	pop	{r1}
+ 504:	e8bd0004 	pop	{r2}
+ 508:	e8bd0008 	pop	{r3}
+ 50c:	e8bd4000 	pop	{lr}
+ 510:	e12fff1e 	bx	lr
+
+00000514 <unlink>:
+ 514:	e92d4000 	push	{lr}
+ 518:	e92d0008 	push	{r3}
+ 51c:	e92d0004 	push	{r2}
+ 520:	e92d0002 	push	{r1}
+ 524:	e92d0001 	push	{r0}
+ 528:	e3a00012 	mov	r0, #18
+ 52c:	ef000040 	svc	0x00000040
+ 530:	e8bd0002 	pop	{r1}
+ 534:	e8bd0002 	pop	{r1}
+ 538:	e8bd0004 	pop	{r2}
+ 53c:	e8bd0008 	pop	{r3}
+ 540:	e8bd4000 	pop	{lr}
+ 544:	e12fff1e 	bx	lr
+
+00000548 <fstat>:
+ 548:	e92d4000 	push	{lr}
+ 54c:	e92d0008 	push	{r3}
+ 550:	e92d0004 	push	{r2}
+ 554:	e92d0002 	push	{r1}
+ 558:	e92d0001 	push	{r0}
+ 55c:	e3a00008 	mov	r0, #8
+ 560:	ef000040 	svc	0x00000040
+ 564:	e8bd0002 	pop	{r1}
+ 568:	e8bd0002 	pop	{r1}
+ 56c:	e8bd0004 	pop	{r2}
+ 570:	e8bd0008 	pop	{r3}
+ 574:	e8bd4000 	pop	{lr}
+ 578:	e12fff1e 	bx	lr
+
+0000057c <link>:
+ 57c:	e92d4000 	push	{lr}
+ 580:	e92d0008 	push	{r3}
+ 584:	e92d0004 	push	{r2}
+ 588:	e92d0002 	push	{r1}
+ 58c:	e92d0001 	push	{r0}
+ 590:	e3a00013 	mov	r0, #19
+ 594:	ef000040 	svc	0x00000040
+ 598:	e8bd0002 	pop	{r1}
+ 59c:	e8bd0002 	pop	{r1}
+ 5a0:	e8bd0004 	pop	{r2}
+ 5a4:	e8bd0008 	pop	{r3}
+ 5a8:	e8bd4000 	pop	{lr}
+ 5ac:	e12fff1e 	bx	lr
+
+000005b0 <mkdir>:
+ 5b0:	e92d4000 	push	{lr}
+ 5b4:	e92d0008 	push	{r3}
+ 5b8:	e92d0004 	push	{r2}
+ 5bc:	e92d0002 	push	{r1}
+ 5c0:	e92d0001 	push	{r0}
+ 5c4:	e3a00014 	mov	r0, #20
+ 5c8:	ef000040 	svc	0x00000040
+ 5cc:	e8bd0002 	pop	{r1}
+ 5d0:	e8bd0002 	pop	{r1}
+ 5d4:	e8bd0004 	pop	{r2}
+ 5d8:	e8bd0008 	pop	{r3}
+ 5dc:	e8bd4000 	pop	{lr}
+ 5e0:	e12fff1e 	bx	lr
+
+000005e4 <chdir>:
+ 5e4:	e92d4000 	push	{lr}
+ 5e8:	e92d0008 	push	{r3}
+ 5ec:	e92d0004 	push	{r2}
+ 5f0:	e92d0002 	push	{r1}
+ 5f4:	e92d0001 	push	{r0}
+ 5f8:	e3a00009 	mov	r0, #9
+ 5fc:	ef000040 	svc	0x00000040
+ 600:	e8bd0002 	pop	{r1}
+ 604:	e8bd0002 	pop	{r1}
+ 608:	e8bd0004 	pop	{r2}
+ 60c:	e8bd0008 	pop	{r3}
+ 610:	e8bd4000 	pop	{lr}
+ 614:	e12fff1e 	bx	lr
+
+00000618 <dup>:
+ 618:	e92d4000 	push	{lr}
+ 61c:	e92d0008 	push	{r3}
+ 620:	e92d0004 	push	{r2}
+ 624:	e92d0002 	push	{r1}
+ 628:	e92d0001 	push	{r0}
+ 62c:	e3a0000a 	mov	r0, #10
+ 630:	ef000040 	svc	0x00000040
+ 634:	e8bd0002 	pop	{r1}
+ 638:	e8bd0002 	pop	{r1}
+ 63c:	e8bd0004 	pop	{r2}
+ 640:	e8bd0008 	pop	{r3}
+ 644:	e8bd4000 	pop	{lr}
+ 648:	e12fff1e 	bx	lr
+
+0000064c <getpid>:
+ 64c:	e92d4000 	push	{lr}
+ 650:	e92d0008 	push	{r3}
+ 654:	e92d0004 	push	{r2}
+ 658:	e92d0002 	push	{r1}
+ 65c:	e92d0001 	push	{r0}
+ 660:	e3a0000b 	mov	r0, #11
+ 664:	ef000040 	svc	0x00000040
+ 668:	e8bd0002 	pop	{r1}
+ 66c:	e8bd0002 	pop	{r1}
+ 670:	e8bd0004 	pop	{r2}
+ 674:	e8bd0008 	pop	{r3}
+ 678:	e8bd4000 	pop	{lr}
+ 67c:	e12fff1e 	bx	lr
+
+00000680 <sbrk>:
+ 680:	e92d4000 	push	{lr}
+ 684:	e92d0008 	push	{r3}
+ 688:	e92d0004 	push	{r2}
+ 68c:	e92d0002 	push	{r1}
+ 690:	e92d0001 	push	{r0}
+ 694:	e3a0000c 	mov	r0, #12
+ 698:	ef000040 	svc	0x00000040
+ 69c:	e8bd0002 	pop	{r1}
+ 6a0:	e8bd0002 	pop	{r1}
+ 6a4:	e8bd0004 	pop	{r2}
+ 6a8:	e8bd0008 	pop	{r3}
+ 6ac:	e8bd4000 	pop	{lr}
+ 6b0:	e12fff1e 	bx	lr
+
+000006b4 <sleep>:
+ 6b4:	e92d4000 	push	{lr}
+ 6b8:	e92d0008 	push	{r3}
+ 6bc:	e92d0004 	push	{r2}
+ 6c0:	e92d0002 	push	{r1}
+ 6c4:	e92d0001 	push	{r0}
+ 6c8:	e3a0000d 	mov	r0, #13
+ 6cc:	ef000040 	svc	0x00000040
+ 6d0:	e8bd0002 	pop	{r1}
+ 6d4:	e8bd0002 	pop	{r1}
+ 6d8:	e8bd0004 	pop	{r2}
+ 6dc:	e8bd0008 	pop	{r3}
+ 6e0:	e8bd4000 	pop	{lr}
+ 6e4:	e12fff1e 	bx	lr
+
+000006e8 <uptime>:
+ 6e8:	e92d4000 	push	{lr}
+ 6ec:	e92d0008 	push	{r3}
+ 6f0:	e92d0004 	push	{r2}
+ 6f4:	e92d0002 	push	{r1}
+ 6f8:	e92d0001 	push	{r0}
+ 6fc:	e3a0000e 	mov	r0, #14
+ 700:	ef000040 	svc	0x00000040
+ 704:	e8bd0002 	pop	{r1}
+ 708:	e8bd0002 	pop	{r1}
+ 70c:	e8bd0004 	pop	{r2}
+ 710:	e8bd0008 	pop	{r3}
+ 714:	e8bd4000 	pop	{lr}
+ 718:	e12fff1e 	bx	lr
+
+0000071c <putc>:
+#include "stat.h"
+#include "user.h"
+
+static void
+putc(int fd, char c)
+{
+ 71c:	e92d4800 	push	{fp, lr}
+ 720:	e28db004 	add	fp, sp, #4
+ 724:	e24b3004 	sub	r3, fp, #4
+ 728:	e24dd008 	sub	sp, sp, #8
+  write(fd, &c, 1);
+ 72c:	e3a02001 	mov	r2, #1
+#include "stat.h"
+#include "user.h"
+
+static void
+putc(int fd, char c)
+{
+ 730:	e5631001 	strb	r1, [r3, #-1]!
+  write(fd, &c, 1);
+ 734:	e1a01003 	mov	r1, r3
+ 738:	ebffff27 	bl	3dc <write>
+}
+ 73c:	e24bd004 	sub	sp, fp, #4
+ 740:	e8bd8800 	pop	{fp, pc}
+
+00000744 <printint>:
+    return q;
+}
+
+static void
+printint(int fd, int xx, int base, int sgn)
+{
+ 744:	e92d4ff0 	push	{r4, r5, r6, r7, r8, r9, sl, fp, lr}
+ 748:	e1a04000 	mov	r4, r0
+  char buf[16];
+  int i, neg;
+  uint x, y, b;
+
+  neg = 0;
+  if(sgn && xx < 0){
+ 74c:	e1a00fa1 	lsr	r0, r1, #31
+ 750:	e3530000 	cmp	r3, #0
+ 754:	03a03000 	moveq	r3, #0
+ 758:	12003001 	andne	r3, r0, #1
+    return q;
+}
+
+static void
+printint(int fd, int xx, int base, int sgn)
+{
+ 75c:	e28db020 	add	fp, sp, #32
+  char buf[16];
+  int i, neg;
+  uint x, y, b;
+
+  neg = 0;
+  if(sgn && xx < 0){
+ 760:	e3530000 	cmp	r3, #0
+    return q;
+}
+
+static void
+printint(int fd, int xx, int base, int sgn)
+{
+ 764:	e24dd014 	sub	sp, sp, #20
+ 768:	e59f909c 	ldr	r9, [pc, #156]	; 80c <printint+0xc8>
+  uint x, y, b;
+
+  neg = 0;
+  if(sgn && xx < 0){
+    neg = 1;
+    x = -xx;
+ 76c:	12611000 	rsbne	r1, r1, #0
+  int i, neg;
+  uint x, y, b;
+
+  neg = 0;
+  if(sgn && xx < 0){
+    neg = 1;
+ 770:	13a03001 	movne	r3, #1
+  } else {
+    x = xx;
+  }
+
+  b = base;
+  i = 0;
+ 774:	e3a0a000 	mov	sl, #0
+ 778:	e24b6034 	sub	r6, fp, #52	; 0x34
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+        if(r >= d) {
+            r = r - d;
+            q = q | (1 << i);
+ 77c:	e3a08001 	mov	r8, #1
+  write(fd, &c, 1);
+}
+
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+ 780:	e3a07000 	mov	r7, #0
+    int i;
+
+    for(i=31;i>=0;i--){
+ 784:	e3a0001f 	mov	r0, #31
+  write(fd, &c, 1);
+}
+
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+ 788:	e1a0c007 	mov	ip, r7
+    int i;
+
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+ 78c:	e1a0e031 	lsr	lr, r1, r0
+ 790:	e20ee001 	and	lr, lr, #1
+ 794:	e18ec08c 	orr	ip, lr, ip, lsl #1
+        if(r >= d) {
+ 798:	e152000c 	cmp	r2, ip
+            r = r - d;
+            q = q | (1 << i);
+ 79c:	91877018 	orrls	r7, r7, r8, lsl r0
+
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+        if(r >= d) {
+            r = r - d;
+ 7a0:	9062c00c 	rsbls	ip, r2, ip
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+    int i;
+
+    for(i=31;i>=0;i--){
+ 7a4:	e2500001 	subs	r0, r0, #1
+ 7a8:	2afffff7 	bcs	78c <printint+0x48>
+
+  b = base;
+  i = 0;
+  do{
+    y = div(x, b);
+    buf[i++] = digits[x - y * b];
+ 7ac:	e0000792 	mul	r0, r2, r7
+  }while((x = y) != 0);
+ 7b0:	e3570000 	cmp	r7, #0
+
+  b = base;
+  i = 0;
+  do{
+    y = div(x, b);
+    buf[i++] = digits[x - y * b];
+ 7b4:	e0601001 	rsb	r1, r0, r1
+ 7b8:	e28a5001 	add	r5, sl, #1
+ 7bc:	e7d91001 	ldrb	r1, [r9, r1]
+ 7c0:	e7c6100a 	strb	r1, [r6, sl]
+  }while((x = y) != 0);
+ 7c4:	11a01007 	movne	r1, r7
+
+  b = base;
+  i = 0;
+  do{
+    y = div(x, b);
+    buf[i++] = digits[x - y * b];
+ 7c8:	11a0a005 	movne	sl, r5
+ 7cc:	1affffeb 	bne	780 <printint+0x3c>
+  }while((x = y) != 0);
+  if(neg)
+ 7d0:	e3530000 	cmp	r3, #0
+    buf[i++] = '-';
+ 7d4:	124b2024 	subne	r2, fp, #36	; 0x24
+ 7d8:	10823005 	addne	r3, r2, r5
+ 7dc:	128a5002 	addne	r5, sl, #2
+
+  while(--i >= 0)
+ 7e0:	e2455001 	sub	r5, r5, #1
+  do{
+    y = div(x, b);
+    buf[i++] = digits[x - y * b];
+  }while((x = y) != 0);
+  if(neg)
+    buf[i++] = '-';
+ 7e4:	13a0202d 	movne	r2, #45	; 0x2d
+ 7e8:	15432010 	strbne	r2, [r3, #-16]
+
+  while(--i >= 0)
+    putc(fd, buf[i]);
+ 7ec:	e7d61005 	ldrb	r1, [r6, r5]
+ 7f0:	e1a00004 	mov	r0, r4
+    buf[i++] = digits[x - y * b];
+  }while((x = y) != 0);
+  if(neg)
+    buf[i++] = '-';
+
+  while(--i >= 0)
+ 7f4:	e2455001 	sub	r5, r5, #1
+    putc(fd, buf[i]);
+ 7f8:	ebffffc7 	bl	71c <putc>
+    buf[i++] = digits[x - y * b];
+  }while((x = y) != 0);
+  if(neg)
+    buf[i++] = '-';
+
+  while(--i >= 0)
+ 7fc:	e3750001 	cmn	r5, #1
+ 800:	1afffff9 	bne	7ec <printint+0xa8>
+    putc(fd, buf[i]);
+}
+ 804:	e24bd020 	sub	sp, fp, #32
+ 808:	e8bd8ff0 	pop	{r4, r5, r6, r7, r8, r9, sl, fp, pc}
+ 80c:	00000b50 	.word	0x00000b50
+
+00000810 <div>:
+  write(fd, &c, 1);
+}
+
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+ 810:	e3a03000 	mov	r3, #0
+{
+  write(fd, &c, 1);
+}
+
+u32 div(u32 n, u32 d)  // long division
+{
+ 814:	e92d0830 	push	{r4, r5, fp}
+ 818:	e1a02000 	mov	r2, r0
+ 81c:	e28db008 	add	fp, sp, #8
+    u32 q=0, r=0;
+    int i;
+
+    for(i=31;i>=0;i--){
+ 820:	e3a0c01f 	mov	ip, #31
+  write(fd, &c, 1);
+}
+
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+ 824:	e1a00003 	mov	r0, r3
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+        if(r >= d) {
+            r = r - d;
+            q = q | (1 << i);
+ 828:	e3a05001 	mov	r5, #1
+    u32 q=0, r=0;
+    int i;
+
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+ 82c:	e1a04c32 	lsr	r4, r2, ip
+ 830:	e2044001 	and	r4, r4, #1
+ 834:	e1843083 	orr	r3, r4, r3, lsl #1
+        if(r >= d) {
+ 838:	e1530001 	cmp	r3, r1
+            r = r - d;
+            q = q | (1 << i);
+ 83c:	21800c15 	orrcs	r0, r0, r5, lsl ip
+
+    for(i=31;i>=0;i--){
+        r = r << 1;
+        r = r | ((n >> i) & 1);
+        if(r >= d) {
+            r = r - d;
+ 840:	20613003 	rsbcs	r3, r1, r3
+u32 div(u32 n, u32 d)  // long division
+{
+    u32 q=0, r=0;
+    int i;
+
+    for(i=31;i>=0;i--){
+ 844:	e25cc001 	subs	ip, ip, #1
+ 848:	2afffff7 	bcs	82c <div+0x1c>
+            r = r - d;
+            q = q | (1 << i);
+        }
+    }
+    return q;
+}
+ 84c:	e24bd008 	sub	sp, fp, #8
+ 850:	e8bd0830 	pop	{r4, r5, fp}
+ 854:	e12fff1e 	bx	lr
+
+00000858 <printf>:
+}
+
+// Print to the given fd. Only understands %d, %x, %p, %s.
+void
+printf(int fd, char *fmt, ...)
+{
+ 858:	e92d000e 	push	{r1, r2, r3}
+ 85c:	e92d4ff0 	push	{r4, r5, r6, r7, r8, r9, sl, fp, lr}
+ 860:	e28db020 	add	fp, sp, #32
+ 864:	e1a05000 	mov	r5, r0
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+ 868:	e59b4004 	ldr	r4, [fp, #4]
+ 86c:	e5d48000 	ldrb	r8, [r4]
+ 870:	e3580000 	cmp	r8, #0
+ 874:	0a000027 	beq	918 <printf+0xc0>
+        ap++;
+      } else if(c == 's'){
+        s = (char*)*ap;
+        ap++;
+        if(s == 0)
+          s = "(null)";
+ 878:	e59f712c 	ldr	r7, [pc, #300]	; 9ac <printf+0x154>
+  char *s;
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+ 87c:	e28b6008 	add	r6, fp, #8
+{
+  char *s;
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+ 880:	e3a0a000 	mov	sl, #0
+ 884:	ea000008 	b	8ac <printf+0x54>
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+    c = fmt[i] & 0xff;
+    if(state == 0){
+      if(c == '%'){
+ 888:	e3580025 	cmp	r8, #37	; 0x25
+        state = '%';
+ 88c:	01a0a008 	moveq	sl, r8
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+    c = fmt[i] & 0xff;
+    if(state == 0){
+      if(c == '%'){
+ 890:	0a000002 	beq	8a0 <printf+0x48>
+        state = '%';
+      } else {
+        putc(fd, c);
+ 894:	e1a00005 	mov	r0, r5
+ 898:	e1a01008 	mov	r1, r8
+ 89c:	ebffff9e 	bl	71c <putc>
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+ 8a0:	e5f48001 	ldrb	r8, [r4, #1]!
+ 8a4:	e3580000 	cmp	r8, #0
+ 8a8:	0a00001a 	beq	918 <printf+0xc0>
+    c = fmt[i] & 0xff;
+    if(state == 0){
+ 8ac:	e35a0000 	cmp	sl, #0
+ 8b0:	0afffff4 	beq	888 <printf+0x30>
+      if(c == '%'){
+        state = '%';
+      } else {
+        putc(fd, c);
+      }
+    } else if(state == '%'){
+ 8b4:	e35a0025 	cmp	sl, #37	; 0x25
+ 8b8:	1afffff8 	bne	8a0 <printf+0x48>
+      if(c == 'd'){
+ 8bc:	e3580064 	cmp	r8, #100	; 0x64
+ 8c0:	0a00002c 	beq	978 <printf+0x120>
+        printint(fd, *ap, 10, 1);
+        ap++;
+      } else if(c == 'x' || c == 'p'){
+ 8c4:	e3580078 	cmp	r8, #120	; 0x78
+ 8c8:	13580070 	cmpne	r8, #112	; 0x70
+ 8cc:	13a09000 	movne	r9, #0
+ 8d0:	03a09001 	moveq	r9, #1
+ 8d4:	0a000013 	beq	928 <printf+0xd0>
+        printint(fd, *ap, 16, 0);
+        ap++;
+      } else if(c == 's'){
+ 8d8:	e3580073 	cmp	r8, #115	; 0x73
+ 8dc:	0a000018 	beq	944 <printf+0xec>
+          s = "(null)";
+        while(*s != 0){
+          putc(fd, *s);
+          s++;
+        }
+      } else if(c == 'c'){
+ 8e0:	e3580063 	cmp	r8, #99	; 0x63
+ 8e4:	0a00002a 	beq	994 <printf+0x13c>
+        putc(fd, *ap);
+        ap++;
+      } else if(c == '%'){
+ 8e8:	e3580025 	cmp	r8, #37	; 0x25
+        putc(fd, c);
+ 8ec:	e1a0100a 	mov	r1, sl
+ 8f0:	e1a00005 	mov	r0, r5
+          s++;
+        }
+      } else if(c == 'c'){
+        putc(fd, *ap);
+        ap++;
+      } else if(c == '%'){
+ 8f4:	0a000002 	beq	904 <printf+0xac>
+        putc(fd, c);
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+ 8f8:	ebffff87 	bl	71c <putc>
+        putc(fd, c);
+ 8fc:	e1a00005 	mov	r0, r5
+ 900:	e1a01008 	mov	r1, r8
+ 904:	ebffff84 	bl	71c <putc>
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+ 908:	e5f48001 	ldrb	r8, [r4, #1]!
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+        putc(fd, c);
+      }
+      state = 0;
+ 90c:	e1a0a009 	mov	sl, r9
+  int c, i, state;
+  uint *ap;
+
+  state = 0;
+  ap = (uint*)(void*)&fmt + 1;
+  for(i = 0; fmt[i]; i++){
+ 910:	e3580000 	cmp	r8, #0
+ 914:	1affffe4 	bne	8ac <printf+0x54>
+        putc(fd, c);
+      }
+      state = 0;
+    }
+  }
+}
+ 918:	e24bd020 	sub	sp, fp, #32
+ 91c:	e8bd4ff0 	pop	{r4, r5, r6, r7, r8, r9, sl, fp, lr}
+ 920:	e28dd00c 	add	sp, sp, #12
+ 924:	e12fff1e 	bx	lr
+    } else if(state == '%'){
+      if(c == 'd'){
+        printint(fd, *ap, 10, 1);
+        ap++;
+      } else if(c == 'x' || c == 'p'){
+        printint(fd, *ap, 16, 0);
+ 928:	e1a00005 	mov	r0, r5
+ 92c:	e4961004 	ldr	r1, [r6], #4
+ 930:	e3a02010 	mov	r2, #16
+ 934:	e3a03000 	mov	r3, #0
+ 938:	ebffff81 	bl	744 <printint>
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+        putc(fd, c);
+      }
+      state = 0;
+ 93c:	e3a0a000 	mov	sl, #0
+ 940:	eaffffd6 	b	8a0 <printf+0x48>
+        ap++;
+      } else if(c == 'x' || c == 'p'){
+        printint(fd, *ap, 16, 0);
+        ap++;
+      } else if(c == 's'){
+        s = (char*)*ap;
+ 944:	e4968004 	ldr	r8, [r6], #4
+        ap++;
+        if(s == 0)
+          s = "(null)";
+ 948:	e3580000 	cmp	r8, #0
+ 94c:	01a08007 	moveq	r8, r7
+        while(*s != 0){
+ 950:	e5d81000 	ldrb	r1, [r8]
+ 954:	e3510000 	cmp	r1, #0
+ 958:	0a000004 	beq	970 <printf+0x118>
+          putc(fd, *s);
+ 95c:	e1a00005 	mov	r0, r5
+ 960:	ebffff6d 	bl	71c <putc>
+      } else if(c == 's'){
+        s = (char*)*ap;
+        ap++;
+        if(s == 0)
+          s = "(null)";
+        while(*s != 0){
+ 964:	e5f81001 	ldrb	r1, [r8, #1]!
+ 968:	e3510000 	cmp	r1, #0
+ 96c:	1afffffa 	bne	95c <printf+0x104>
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+        putc(fd, c);
+      }
+      state = 0;
+ 970:	e1a0a001 	mov	sl, r1
+ 974:	eaffffc9 	b	8a0 <printf+0x48>
+      } else {
+        putc(fd, c);
+      }
+    } else if(state == '%'){
+      if(c == 'd'){
+        printint(fd, *ap, 10, 1);
+ 978:	e1a00005 	mov	r0, r5
+ 97c:	e4961004 	ldr	r1, [r6], #4
+ 980:	e3a0200a 	mov	r2, #10
+ 984:	e3a03001 	mov	r3, #1
+ 988:	ebffff6d 	bl	744 <printint>
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+        putc(fd, c);
+      }
+      state = 0;
+ 98c:	e3a0a000 	mov	sl, #0
+ 990:	eaffffc2 	b	8a0 <printf+0x48>
+        while(*s != 0){
+          putc(fd, *s);
+          s++;
+        }
+      } else if(c == 'c'){
+        putc(fd, *ap);
+ 994:	e4961004 	ldr	r1, [r6], #4
+ 998:	e1a00005 	mov	r0, r5
+      } else {
+        // Unknown % sequence.  Print it to draw attention.
+        putc(fd, '%');
+        putc(fd, c);
+      }
+      state = 0;
+ 99c:	e1a0a009 	mov	sl, r9
+        while(*s != 0){
+          putc(fd, *s);
+          s++;
+        }
+      } else if(c == 'c'){
+        putc(fd, *ap);
+ 9a0:	e6ef1071 	uxtb	r1, r1
+ 9a4:	ebffff5c 	bl	71c <putc>
+ 9a8:	eaffffbc 	b	8a0 <printf+0x48>
+ 9ac:	00000b64 	.word	0x00000b64
+
+000009b0 <free>:
+free(void *ap)
+{
+  Header *bp, *p;
+
+  bp = (Header*)ap - 1;
+  for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
+ 9b0:	e59f3098 	ldr	r3, [pc, #152]	; a50 <free+0xa0>
+static Header base;
+static Header *freep;
+
+void
+free(void *ap)
+{
+ 9b4:	e92d0830 	push	{r4, r5, fp}
+  Header *bp, *p;
+
+  bp = (Header*)ap - 1;
+ 9b8:	e240c008 	sub	ip, r0, #8
+  for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
+ 9bc:	e5932000 	ldr	r2, [r3]
+static Header base;
+static Header *freep;
+
+void
+free(void *ap)
+{
+ 9c0:	e28db008 	add	fp, sp, #8
+  Header *bp, *p;
+
+  bp = (Header*)ap - 1;
+  for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
+ 9c4:	e152000c 	cmp	r2, ip
+ 9c8:	e5921000 	ldr	r1, [r2]
+ 9cc:	2a000001 	bcs	9d8 <free+0x28>
+ 9d0:	e15c0001 	cmp	ip, r1
+ 9d4:	3a000007 	bcc	9f8 <free+0x48>
+    if(p >= p->s.ptr && (bp > p || bp < p->s.ptr))
+ 9d8:	e1520001 	cmp	r2, r1
+ 9dc:	3a000003 	bcc	9f0 <free+0x40>
+ 9e0:	e152000c 	cmp	r2, ip
+ 9e4:	3a000003 	bcc	9f8 <free+0x48>
+ 9e8:	e15c0001 	cmp	ip, r1
+ 9ec:	3a000001 	bcc	9f8 <free+0x48>
+static Header base;
+static Header *freep;
+
+void
+free(void *ap)
+{
+ 9f0:	e1a02001 	mov	r2, r1
+ 9f4:	eafffff2 	b	9c4 <free+0x14>
+
+  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){
+ 9f8:	e5104004 	ldr	r4, [r0, #-4]
+  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;
+ 9fc:	e5832000 	str	r2, [r3]
+
+  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){
+ a00:	e08c5184 	add	r5, ip, r4, lsl #3
+ a04:	e1550001 	cmp	r5, r1
+    bp->s.size += p->s.ptr->s.size;
+ a08:	05911004 	ldreq	r1, [r1, #4]
+ a0c:	00814004 	addeq	r4, r1, r4
+ a10:	05004004 	streq	r4, [r0, #-4]
+    bp->s.ptr = p->s.ptr->s.ptr;
+ a14:	05921000 	ldreq	r1, [r2]
+ a18:	05911000 	ldreq	r1, [r1]
+  } else
+    bp->s.ptr = p->s.ptr;
+ a1c:	e5001008 	str	r1, [r0, #-8]
+  if(p + p->s.size == bp){
+ a20:	e5921004 	ldr	r1, [r2, #4]
+ a24:	e0824181 	add	r4, r2, r1, lsl #3
+ a28:	e15c0004 	cmp	ip, r4
+    p->s.size += bp->s.size;
+    p->s.ptr = bp->s.ptr;
+  } else
+    p->s.ptr = bp;
+ a2c:	1582c000 	strne	ip, [r2]
+    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;
+ a30:	0510c004 	ldreq	ip, [r0, #-4]
+ a34:	008c1001 	addeq	r1, ip, r1
+ a38:	05821004 	streq	r1, [r2, #4]
+    p->s.ptr = bp->s.ptr;
+ a3c:	05101008 	ldreq	r1, [r0, #-8]
+ a40:	05821000 	streq	r1, [r2]
+  } else
+    p->s.ptr = bp;
+  freep = p;
+}
+ a44:	e24bd008 	sub	sp, fp, #8
+ a48:	e8bd0830 	pop	{r4, r5, fp}
+ a4c:	e12fff1e 	bx	lr
+ a50:	00000b6c 	.word	0x00000b6c
+
+00000a54 <malloc>:
+  return freep;
+}
+
+void*
+malloc(uint nbytes)
+{
+ a54:	e92d49f8 	push	{r3, r4, r5, r6, r7, r8, fp, lr}
+  Header *p, *prevp;
+  uint nunits;
+
+  nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
+ a58:	e2804007 	add	r4, r0, #7
+  if((prevp = freep) == 0){
+ a5c:	e59f50d4 	ldr	r5, [pc, #212]	; b38 <malloc+0xe4>
+malloc(uint nbytes)
+{
+  Header *p, *prevp;
+  uint nunits;
+
+  nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
+ a60:	e1a041a4 	lsr	r4, r4, #3
+  return freep;
+}
+
+void*
+malloc(uint nbytes)
+{
+ a64:	e28db01c 	add	fp, sp, #28
+  Header *p, *prevp;
+  uint nunits;
+
+  nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
+  if((prevp = freep) == 0){
+ a68:	e5953000 	ldr	r3, [r5]
+malloc(uint nbytes)
+{
+  Header *p, *prevp;
+  uint nunits;
+
+  nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
+ a6c:	e2844001 	add	r4, r4, #1
+  if((prevp = freep) == 0){
+ a70:	e3530000 	cmp	r3, #0
+ a74:	0a00002b 	beq	b28 <malloc+0xd4>
+ a78:	e5930000 	ldr	r0, [r3]
+ a7c:	e5902004 	ldr	r2, [r0, #4]
+    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){
+ a80:	e1520004 	cmp	r2, r4
+ a84:	2a00001b 	bcs	af8 <malloc+0xa4>
+morecore(uint nu)
+{
+  char *p;
+  Header *hp;
+
+  if(nu < 4096)
+ a88:	e59f80ac 	ldr	r8, [pc, #172]	; b3c <malloc+0xe8>
+        p->s.size -= nunits;
+        p += p->s.size;
+        p->s.size = nunits;
+      }
+      freep = prevp;
+      return (void*)(p + 1);
+ a8c:	e1a07184 	lsl	r7, r4, #3
+ a90:	ea000003 	b	aa4 <malloc+0x50>
+  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){
+ a94:	e5930000 	ldr	r0, [r3]
+    if(p->s.size >= nunits){
+ a98:	e5902004 	ldr	r2, [r0, #4]
+ a9c:	e1540002 	cmp	r4, r2
+ aa0:	9a000014 	bls	af8 <malloc+0xa4>
+        p->s.size = nunits;
+      }
+      freep = prevp;
+      return (void*)(p + 1);
+    }
+    if(p == freep)
+ aa4:	e5952000 	ldr	r2, [r5]
+ aa8:	e1a03000 	mov	r3, r0
+ aac:	e1500002 	cmp	r0, r2
+ ab0:	1afffff7 	bne	a94 <malloc+0x40>
+morecore(uint nu)
+{
+  char *p;
+  Header *hp;
+
+  if(nu < 4096)
+ ab4:	e1540008 	cmp	r4, r8
+    nu = 4096;
+  p = sbrk(nu * sizeof(Header));
+ ab8:	81a00007 	movhi	r0, r7
+ abc:	93a00902 	movls	r0, #32768	; 0x8000
+morecore(uint nu)
+{
+  char *p;
+  Header *hp;
+
+  if(nu < 4096)
+ ac0:	81a06004 	movhi	r6, r4
+ ac4:	93a06a01 	movls	r6, #4096	; 0x1000
+    nu = 4096;
+  p = sbrk(nu * sizeof(Header));
+ ac8:	ebfffeec 	bl	680 <sbrk>
+ acc:	e1a03000 	mov	r3, r0
+  if(p == (char*)-1)
+ ad0:	e3730001 	cmn	r3, #1
+    return 0;
+  hp = (Header*)p;
+  hp->s.size = nu;
+  free((void*)(hp + 1));
+ ad4:	e2800008 	add	r0, r0, #8
+  Header *hp;
+
+  if(nu < 4096)
+    nu = 4096;
+  p = sbrk(nu * sizeof(Header));
+  if(p == (char*)-1)
+ ad8:	0a000010 	beq	b20 <malloc+0xcc>
+    return 0;
+  hp = (Header*)p;
+  hp->s.size = nu;
+ adc:	e5836004 	str	r6, [r3, #4]
+  free((void*)(hp + 1));
+ ae0:	ebffffb2 	bl	9b0 <free>
+  return freep;
+ ae4:	e5953000 	ldr	r3, [r5]
+      }
+      freep = prevp;
+      return (void*)(p + 1);
+    }
+    if(p == freep)
+      if((p = morecore(nunits)) == 0)
+ ae8:	e3530000 	cmp	r3, #0
+ aec:	1affffe8 	bne	a94 <malloc+0x40>
+        return 0;
+ af0:	e1a00003 	mov	r0, r3
+  }
+}
+ af4:	e8bd89f8 	pop	{r3, r4, r5, r6, r7, r8, fp, pc}
+    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)
+ af8:	e1540002 	cmp	r4, r2
+        prevp->s.ptr = p->s.ptr;
+      else {
+        p->s.size -= nunits;
+ afc:	10642002 	rsbne	r2, r4, r2
+ b00:	15802004 	strne	r2, [r0, #4]
+    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;
+ b04:	05902000 	ldreq	r2, [r0]
+      else {
+        p->s.size -= nunits;
+        p += p->s.size;
+ b08:	10800182 	addne	r0, r0, r2, lsl #3
+    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;
+ b0c:	05832000 	streq	r2, [r3]
+      else {
+        p->s.size -= nunits;
+        p += p->s.size;
+        p->s.size = nunits;
+ b10:	15804004 	strne	r4, [r0, #4]
+      }
+      freep = prevp;
+ b14:	e5853000 	str	r3, [r5]
+      return (void*)(p + 1);
+ b18:	e2800008 	add	r0, r0, #8
+ b1c:	e8bd89f8 	pop	{r3, r4, r5, r6, r7, r8, fp, pc}
+    }
+    if(p == freep)
+      if((p = morecore(nunits)) == 0)
+        return 0;
+ b20:	e3a00000 	mov	r0, #0
+ b24:	e8bd89f8 	pop	{r3, r4, r5, r6, r7, r8, fp, pc}
+  Header *p, *prevp;
+  uint nunits;
+
+  nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
+  if((prevp = freep) == 0){
+    base.s.ptr = freep = prevp = &base;
+ b28:	e2850004 	add	r0, r5, #4
+ b2c:	e5850000 	str	r0, [r5]
+    base.s.size = 0;
+ b30:	e9850009 	stmib	r5, {r0, r3}
+ b34:	eaffffd3 	b	a88 <malloc+0x34>
+ b38:	00000b6c 	.word	0x00000b6c
+ b3c:	00000fff 	.word	0x00000fff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/echo.c	Sun Oct 22 18:25:39 2017 +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/echo.sym	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,64 @@
+00000000 .text
+00000b40 .rodata
+00000b6c .bss
+00000000 .comment
+00000000 .ARM.attributes
+00000000 .debug_aranges
+00000000 .debug_info
+00000000 .debug_abbrev
+00000000 .debug_line
+00000000 .debug_frame
+00000000 .debug_str
+00000000 .debug_loc
+00000000 .debug_ranges
+00000000 echo.c
+00000000 ulib.c
+00000000 printf.c
+0000071c putc
+00000744 printint
+00000b50 digits.993
+00000000 umalloc.c
+00000b6c freep
+00000b70 base
+0000006c strcpy
+00000858 printf
+000002a4 memmove
+000004e0 mknod
+00000b78 _bss_end__
+0000019c gets
+0000064c getpid
+00000a54 malloc
+000006b4 sleep
+00000b6c __bss_start__
+00000374 pipe
+000003dc write
+00000548 fstat
+00000444 kill
+000005e4 chdir
+00000478 exec
+00000b78 __bss_end__
+00000340 wait
+000003a8 read
+00000514 unlink
+000002d8 fork
+00000680 sbrk
+000006e8 uptime
+00000b6c __bss_start
+00000120 memset
+00000000 main
+00000b78 __end__
+00000094 strcmp
+00000618 dup
+00000214 stat
+00000b6c _edata
+00000b78 _end
+0000057c link
+0000030c exit
+00000250 atoi
+000000e0 strlen
+000004ac open
+00000810 div
+00000158 strchr
+000005b0 mkdir
+00000410 close
+000009b0 free
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uprogs/elf.h	Sun Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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 Oct 22 18:25:39 2017 +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.asm	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,912 @@
+
+_forktest:     file format elf32-littlearm
+
+
+Disassembly of section .text:
+
+00000000 <main>:
+  printf(1, "fork test OK\n");
+}
+
+int
+main(void)
+{
+   0:	e92d4800 	push	{fp, lr}
+   4:	e28db004 	add	fp, sp, #4
+  forktest();
+   8:	eb00000f 	bl	4c <forktest>
+  exit();
+   c:	eb0000e3 	bl	3a0 <exit>
+
+00000010 <printf>:
+
+#define N  1000
+
+void
+printf(int fd, char *s, ...)
+{
+  10:	e92d000e 	push	{r1, r2, r3}
+  14:	e92d4838 	push	{r3, r4, r5, fp, lr}
+  18:	e28db010 	add	fp, sp, #16
+  1c:	e1a05000 	mov	r5, r0
+  20:	e59b4004 	ldr	r4, [fp, #4]
+  write(fd, s, strlen(s));
+  24:	e1a00004 	mov	r0, r4
+  28:	eb000051 	bl	174 <strlen>
+  2c:	e1a01004 	mov	r1, r4
+  30:	e1a02000 	mov	r2, r0
+  34:	e1a00005 	mov	r0, r5
+  38:	eb00010c 	bl	470 <write>
+}
+  3c:	e24bd010 	sub	sp, fp, #16
+  40:	e8bd4838 	pop	{r3, r4, r5, fp, lr}
+  44:	e28dd00c 	add	sp, sp, #12
+  48:	e12fff1e 	bx	lr
+
+0000004c <forktest>:
+
+void
+forktest(void)
+{
+  4c:	e92d4818 	push	{r3, r4, fp, lr}
+  int n, pid;
+
+  printf(1, "fork test\n");
+  50:	e3a00001 	mov	r0, #1
+  write(fd, s, strlen(s));
+}
+
+void
+forktest(void)
+{
+  54:	e28db00c 	add	fp, sp, #12
+  int n, pid;
+
+  printf(1, "fork test\n");
+  58:	e59f108c 	ldr	r1, [pc, #140]	; ec <forktest+0xa0>
+  5c:	ebffffeb 	bl	10 <printf>
+
+  for(n=0; n<N; n++){
+  60:	e3a04000 	mov	r4, #0
+  64:	ea000003 	b	78 <forktest+0x2c>
+    pid = fork();
+    if(pid < 0)
+      break;
+    if(pid == 0)
+  68:	0a00001b 	beq	dc <forktest+0x90>
+{
+  int n, pid;
+
+  printf(1, "fork test\n");
+
+  for(n=0; n<N; n++){
+  6c:	e2844001 	add	r4, r4, #1
+  70:	e3540ffa 	cmp	r4, #1000	; 0x3e8
+  74:	0a000010 	beq	bc <forktest+0x70>
+    pid = fork();
+  78:	eb0000bb 	bl	36c <fork>
+    if(pid < 0)
+  7c:	e3500000 	cmp	r0, #0
+  80:	aafffff8 	bge	68 <forktest+0x1c>
+  if(n == N){
+    printf(1, "fork claimed to work N times!\n", N);
+    exit();
+  }
+  
+  for(; n > 0; n--){
+  84:	e3540000 	cmp	r4, #0
+  88:	0a000004 	beq	a0 <forktest+0x54>
+    if(wait() < 0){
+  8c:	eb0000d0 	bl	3d4 <wait>
+  90:	e3500000 	cmp	r0, #0
+  94:	ba00000d 	blt	d0 <forktest+0x84>
+  if(n == N){
+    printf(1, "fork claimed to work N times!\n", N);
+    exit();
+  }
+  
+  for(; n > 0; n--){
+  98:	e2544001 	subs	r4, r4, #1
+  9c:	1afffffa 	bne	8c <forktest+0x40>
+      printf(1, "wait stopped early\n");
+      exit();
+    }
+  }
+  
+  if(wait() != -1){
+  a0:	eb0000cb 	bl	3d4 <wait>
+  a4:	e3700001 	cmn	r0, #1
+    printf(1, "wait got too many\n");
+  a8:	e3a00001 	mov	r0, #1
+      printf(1, "wait stopped early\n");
+      exit();
+    }
+  }
+  
+  if(wait() != -1){
+  ac:	1a00000b 	bne	e0 <forktest+0x94>
+    printf(1, "wait got too many\n");
+    exit();
+  }
+  
+  printf(1, "fork test OK\n");
+  b0:	e59f1038 	ldr	r1, [pc, #56]	; f0 <forktest+0xa4>
+}
+  b4:	e8bd4818 	pop	{r3, r4, fp, lr}
+  if(wait() != -1){
+    printf(1, "wait got too many\n");
+    exit();
+  }
+  
+  printf(1, "fork test OK\n");
+  b8:	eaffffd4 	b	10 <printf>
+    if(pid == 0)
+      exit();
+  }
+  
+  if(n == N){
+    printf(1, "fork claimed to work N times!\n", N);
+  bc:	e3a00001 	mov	r0, #1
+  c0:	e59f102c 	ldr	r1, [pc, #44]	; f4 <forktest+0xa8>
+  c4:	e1a02004 	mov	r2, r4
+  c8:	ebffffd0 	bl	10 <printf>
+    exit();
+  cc:	eb0000b3 	bl	3a0 <exit>
+  }
+  
+  for(; n > 0; n--){
+    if(wait() < 0){
+      printf(1, "wait stopped early\n");
+  d0:	e3a00001 	mov	r0, #1
+  d4:	e59f101c 	ldr	r1, [pc, #28]	; f8 <forktest+0xac>
+  d8:	ebffffcc 	bl	10 <printf>
+      exit();
+  dc:	eb0000af 	bl	3a0 <exit>
+    }
+  }
+  
+  if(wait() != -1){
+    printf(1, "wait got too many\n");
+  e0:	e59f1014 	ldr	r1, [pc, #20]	; fc <forktest+0xb0>
+  e4:	ebffffc9 	bl	10 <printf>
+    exit();
+  e8:	eb0000ac 	bl	3a0 <exit>
+  ec:	000007b0 	.word	0x000007b0
+  f0:	000007e4 	.word	0x000007e4
+  f4:	000007f4 	.word	0x000007f4
+  f8:	000007bc 	.word	0x000007bc
+  fc:	000007d0 	.word	0x000007d0
+
+00000100 <strcpy>:
+#include "user.h"
+#include "arm.h"
+
+char*
+strcpy(char *s, char *t)
+{
+ 100:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+  char *os;
+
+  os = s;
+  while((*s++ = *t++) != 0)
+ 104:	e1a02000 	mov	r2, r0
+#include "user.h"
+#include "arm.h"
+
+char*
+strcpy(char *s, char *t)
+{
+ 108:	e28db000 	add	fp, sp, #0
+  char *os;
+
+  os = s;
+  while((*s++ = *t++) != 0)
+ 10c:	e4d13001 	ldrb	r3, [r1], #1
+ 110:	e3530000 	cmp	r3, #0
+ 114:	e4c23001 	strb	r3, [r2], #1
+ 118:	1afffffb 	bne	10c <strcpy+0xc>
+    ;
+  return os;
+}
+ 11c:	e28bd000 	add	sp, fp, #0
+ 120:	e8bd0800 	pop	{fp}
+ 124:	e12fff1e 	bx	lr
+
+00000128 <strcmp>:
+
+int
+strcmp(const char *p, const char *q)
+{
+ 128:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 12c:	e28db000 	add	fp, sp, #0
+  while(*p && *p == *q)
+ 130:	e5d03000 	ldrb	r3, [r0]
+ 134:	e5d12000 	ldrb	r2, [r1]
+ 138:	e3530000 	cmp	r3, #0
+ 13c:	1a000004 	bne	154 <strcmp+0x2c>
+ 140:	ea000005 	b	15c <strcmp+0x34>
+ 144:	e5f03001 	ldrb	r3, [r0, #1]!
+ 148:	e3530000 	cmp	r3, #0
+ 14c:	0a000006 	beq	16c <strcmp+0x44>
+ 150:	e5f12001 	ldrb	r2, [r1, #1]!
+ 154:	e1530002 	cmp	r3, r2
+ 158:	0afffff9 	beq	144 <strcmp+0x1c>
+    p++, q++;
+  return (uchar)*p - (uchar)*q;
+}
+ 15c:	e0620003 	rsb	r0, r2, r3
+ 160:	e28bd000 	add	sp, fp, #0
+ 164:	e8bd0800 	pop	{fp}
+ 168:	e12fff1e 	bx	lr
+}
+
+int
+strcmp(const char *p, const char *q)
+{
+  while(*p && *p == *q)
+ 16c:	e5d12001 	ldrb	r2, [r1, #1]
+ 170:	eafffff9 	b	15c <strcmp+0x34>
+
+00000174 <strlen>:
+  return (uchar)*p - (uchar)*q;
+}
+
+uint
+strlen(char *s)
+{
+ 174:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 178:	e28db000 	add	fp, sp, #0
+  int n;
+
+  for(n = 0; s[n]; n++)
+ 17c:	e5d03000 	ldrb	r3, [r0]
+ 180:	e3530000 	cmp	r3, #0
+ 184:	01a00003 	moveq	r0, r3
+ 188:	0a000006 	beq	1a8 <strlen+0x34>
+ 18c:	e1a02000 	mov	r2, r0
+ 190:	e3a03000 	mov	r3, #0
+ 194:	e5f21001 	ldrb	r1, [r2, #1]!
+ 198:	e2833001 	add	r3, r3, #1
+ 19c:	e1a00003 	mov	r0, r3
+ 1a0:	e3510000 	cmp	r1, #0
+ 1a4:	1afffffa 	bne	194 <strlen+0x20>
+    ;
+  return n;
+}
+ 1a8:	e28bd000 	add	sp, fp, #0
+ 1ac:	e8bd0800 	pop	{fp}
+ 1b0:	e12fff1e 	bx	lr
+
+000001b4 <memset>:
+memset(void *dst, int c, uint n)
+{
+  char *p=dst;
+  u32 rc=n;
+
+  while (rc-- > 0) *p++ = c;
+ 1b4:	e3520000 	cmp	r2, #0
+  return n;
+}
+
+void*
+memset(void *dst, int c, uint n)
+{
+ 1b8:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 1bc:	e28db000 	add	fp, sp, #0
+  char *p=dst;
+  u32 rc=n;
+
+  while (rc-- > 0) *p++ = c;
+ 1c0:	0a000006 	beq	1e0 <memset+0x2c>
+ 1c4:	e6ef1071 	uxtb	r1, r1
+ 1c8:	e1a03002 	mov	r3, r2
+}
+
+void*
+memset(void *dst, int c, uint n)
+{
+  char *p=dst;
+ 1cc:	e1a0c000 	mov	ip, r0
+  u32 rc=n;
+
+  while (rc-- > 0) *p++ = c;
+ 1d0:	e2533001 	subs	r3, r3, #1
+ 1d4:	e4cc1001 	strb	r1, [ip], #1
+ 1d8:	1afffffc 	bne	1d0 <memset+0x1c>
+ 1dc:	e0800002 	add	r0, r0, r2
+  return (void *)p;
+}
+ 1e0:	e28bd000 	add	sp, fp, #0
+ 1e4:	e8bd0800 	pop	{fp}
+ 1e8:	e12fff1e 	bx	lr
+
+000001ec <strchr>:
+
+char*
+strchr(const char *s, char c)
+{
+ 1ec:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 1f0:	e28db000 	add	fp, sp, #0
+  for(; *s; s++)
+ 1f4:	e5d03000 	ldrb	r3, [r0]
+ 1f8:	e3530000 	cmp	r3, #0
+ 1fc:	1a000004 	bne	214 <strchr+0x28>
+ 200:	ea000008 	b	228 <strchr+0x3c>
+ 204:	e5d03001 	ldrb	r3, [r0, #1]
+ 208:	e2800001 	add	r0, r0, #1
+ 20c:	e3530000 	cmp	r3, #0
+ 210:	0a000004 	beq	228 <strchr+0x3c>
+    if(*s == c)
+ 214:	e1530001 	cmp	r3, r1
+ 218:	1afffff9 	bne	204 <strchr+0x18>
+      return (char*)s;
+  return 0;
+}
+ 21c:	e28bd000 	add	sp, fp, #0
+ 220:	e8bd0800 	pop	{fp}
+ 224:	e12fff1e 	bx	lr
+strchr(const char *s, char c)
+{
+  for(; *s; s++)
+    if(*s == c)
+      return (char*)s;
+  return 0;
+ 228:	e1a00003 	mov	r0, r3
+ 22c:	eafffffa 	b	21c <strchr+0x30>
+
+00000230 <gets>:
+}
+
+char*
+gets(char *buf, int max)
+{
+ 230:	e92d49f0 	push	{r4, r5, r6, r7, r8, fp, lr}
+ 234:	e28db018 	add	fp, sp, #24
+ 238:	e24dd00c 	sub	sp, sp, #12
+ 23c:	e1a08000 	mov	r8, r0
+ 240:	e1a07001 	mov	r7, r1
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+ 244:	e1a06000 	mov	r6, r0
+ 248:	e3a05000 	mov	r5, #0
+ 24c:	ea000008 	b	274 <gets+0x44>
+    cc = read(0, &c, 1);
+ 250:	eb000079 	bl	43c <read>
+    if(cc < 1)
+ 254:	e3500000 	cmp	r0, #0
+ 258:	da00000b 	ble	28c <gets+0x5c>
+      break;
+    buf[i++] = c;
+ 25c:	e55b301d 	ldrb	r3, [fp, #-29]
+    if(c == '\n' || c == '\r')
+ 260:	e1a05004 	mov	r5, r4
+ 264:	e353000a 	cmp	r3, #10
+ 268:	1353000d 	cmpne	r3, #13
+
+  for(i=0; i+1 < max; ){
+    cc = read(0, &c, 1);
+    if(cc < 1)
+      break;
+    buf[i++] = c;
+ 26c:	e4c63001 	strb	r3, [r6], #1
+    if(c == '\n' || c == '\r')
+ 270:	0a00000a 	beq	2a0 <gets+0x70>
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+    cc = read(0, &c, 1);
+ 274:	e3a02001 	mov	r2, #1
+gets(char *buf, int max)
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+ 278:	e0854002 	add	r4, r5, r2
+ 27c:	e1540007 	cmp	r4, r7
+    cc = read(0, &c, 1);
+ 280:	e3a00000 	mov	r0, #0
+ 284:	e24b101d 	sub	r1, fp, #29
+gets(char *buf, int max)
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+ 288:	bafffff0 	blt	250 <gets+0x20>
+      break;
+    buf[i++] = c;
+    if(c == '\n' || c == '\r')
+      break;
+  }
+  buf[i] = '\0';
+ 28c:	e3a03000 	mov	r3, #0
+ 290:	e7c83005 	strb	r3, [r8, r5]
+  return buf;
+}
+ 294:	e1a00008 	mov	r0, r8
+ 298:	e24bd018 	sub	sp, fp, #24
+ 29c:	e8bd89f0 	pop	{r4, r5, r6, r7, r8, fp, pc}
+gets(char *buf, int max)
+{
+  int i, cc;
+  char c;
+
+  for(i=0; i+1 < max; ){
+ 2a0:	e1a05004 	mov	r5, r4
+ 2a4:	eafffff8 	b	28c <gets+0x5c>
+
+000002a8 <stat>:
+  return buf;
+}
+
+int
+stat(char *n, struct stat *st)
+{
+ 2a8:	e92d4830 	push	{r4, r5, fp, lr}
+ 2ac:	e1a05001 	mov	r5, r1
+ 2b0:	e28db00c 	add	fp, sp, #12
+  int fd;
+  int r;
+
+  fd = open(n, O_RDONLY);
+ 2b4:	e3a01000 	mov	r1, #0
+ 2b8:	eb0000a0 	bl	540 <open>
+  if(fd < 0)
+ 2bc:	e2504000 	subs	r4, r0, #0
+    return -1;
+ 2c0:	b3e05000 	mvnlt	r5, #0
+{
+  int fd;
+  int r;
+
+  fd = open(n, O_RDONLY);
+  if(fd < 0)
+ 2c4:	ba000004 	blt	2dc <stat+0x34>
+    return -1;
+  r = fstat(fd, st);
+ 2c8:	e1a01005 	mov	r1, r5
+ 2cc:	eb0000c2 	bl	5dc <fstat>
+ 2d0:	e1a05000 	mov	r5, r0
+  close(fd);
+ 2d4:	e1a00004 	mov	r0, r4
+ 2d8:	eb000071 	bl	4a4 <close>
+  return r;
+}
+ 2dc:	e1a00005 	mov	r0, r5
+ 2e0:	e8bd8830 	pop	{r4, r5, fp, pc}
+
+000002e4 <atoi>:
+
+int
+atoi(const char *s)
+{
+ 2e4:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
+ 2e8:	e28db000 	add	fp, sp, #0
+  int n;
+
+  n = 0;
+  while('0' <= *s && *s <= '9')
+ 2ec:	e5d03000 	ldrb	r3, [r0]
+ 2f0:	e2432030 	sub	r2, r3, #48	; 0x30
+ 2f4:	e6ef2072 	uxtb	r2, r2
+ 2f8:	e3520009 	cmp	r2, #9
+int
+atoi(const char *s)
+{
+  int n;
+