diff --git a/.gdbinit.tmpl b/.gdbinit.tmpl new file mode 100644 index 00000000..234bb85b --- /dev/null +++ b/.gdbinit.tmpl @@ -0,0 +1,30 @@ +set $lastcs = -1 + +define hook-stop + # There doesn't seem to be a good way to detect if we're in 16- or + # 32-bit mode, but we always run with CS == 8 in 32-bit mode. + if $cs == 8 || $cs == 27 + if $lastcs != 8 && $lastcs != 27 + set architecture i386 + end + x/i $pc + else + if $lastcs == -1 || $lastcs == 8 || $lastcs == 27 + set architecture i8086 + end + # Translate the segment:offset into a physical address + printf "[%4x:%4x] ", $cs, $eip + x/i $cs*16+$eip + end + set $lastcs = $cs +end + +echo + target remote localhost:1234\n +target remote localhost:1234 + +# If this fails, it's probably because your GDB doesn't support ELF. +# Look at the tools page at +# http://pdos.csail.mit.edu/6.828/2009/tools.html +# for instructions on building GDB with ELF support. +echo + symbol-file obj/kern/kernel\n +symbol-file obj/kern/kernel diff --git a/CODING b/CODING new file mode 100644 index 00000000..898097ee --- /dev/null +++ b/CODING @@ -0,0 +1,37 @@ +JOS CODING STANDARDS + +It's easier on everyone if all authors working on a shared +code base are consistent in the way they write their programs. +We have the following conventions in our code: + +* No space after the name of a function in a call + For example, printf("hello") not printf ("hello"). + +* One space after keywords "if", "for", "while", "switch". + For example, if (x) not if(x). + +* Space before braces. + For example, if (x) { not if (x){. + +* Function names are all lower-case separated by underscores. + +* Beginning-of-line indentation via tabs, not spaces. + +* Preprocessor macros are always UPPERCASE. + There are a few grandfathered exceptions: assert, panic, + static_assert, offsetof. + +* Pointer types have spaces: (uint16_t *) not (uint16_t*). + +* Multi-word names are lower_case_with_underscores. + +* Comments in imported code are usually C /* ... */ comments. + Comments in new code are C++ style //. + +* In a function definition, the function name starts a new line. + Then you can grep -n '^foo' */*.c to find the definition of foo. + +* Functions that take no arguments are declared f(void) not f(). + +The included .dir-locals.el file will automatically set up the basic +indentation style in Emacs. diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 00000000..41f1ffaf --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,199 @@ +# +# This makefile system follows the structuring conventions +# recommended by Peter Miller in his excellent paper: +# +# Recursive Make Considered Harmful +# http://aegis.sourceforge.net/auug97.pdf +# +OBJDIR := obj + +-include conf/lab.mk + +-include conf/env.mk + +ifndef LABSETUP +LABSETUP := ./ +endif + +TOP = . + +# Cross-compiler jos toolchain +# +# This Makefile will automatically use the cross-compiler toolchain +# installed as 'i386-jos-elf-*', if one exists. If the host tools ('gcc', +# 'objdump', and so forth) compile for a 32-bit x86 ELF target, that will +# be detected as well. If you have the right compiler toolchain installed +# using a different name, set GCCPREFIX explicitly in conf/env.mk + +# try to infer the correct GCCPREFIX +ifndef GCCPREFIX +GCCPREFIX := $(shell if i386-jos-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \ + then echo 'i386-jos-elf-'; \ + elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; \ + then echo ''; \ + else echo "***" 1>&2; \ + echo "*** Error: Couldn't find an i386-*-elf version of GCC/binutils." 1>&2; \ + echo "*** Is the directory with i386-jos-elf-gcc in your PATH?" 1>&2; \ + echo "*** If your i386-*-elf toolchain is installed with a command" 1>&2; \ + echo "*** prefix other than 'i386-jos-elf-', set your GCCPREFIX" 1>&2; \ + echo "*** environment variable to that prefix and run 'make' again." 1>&2; \ + echo "*** To turn off this error, run 'gmake GCCPREFIX= ...'." 1>&2; \ + echo "***" 1>&2; exit 1; fi) +endif + +# try to infer the correct QEMU +ifndef QEMU +QEMU := $(shell if which qemu > /dev/null; \ + then echo qemu; exit; \ + else \ + qemu=/Applications/Q.app/Contents/MacOS/i386-softmmu.app/Contents/MacOS/i386-softmmu; \ + if test -x $$qemu; then echo $$qemu; exit; fi; fi; \ + echo "***" 1>&2; \ + echo "*** Error: Couldn't find a working QEMU executable." 1>&2; \ + echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; \ + echo "*** or have you tried setting the QEMU variable in conf/env.mk?" 1>&2; \ + echo "***" 1>&2; exit 1) +endif + +# try to generate a unique GDB port +GDBPORT := $(shell expr `id -u` % 5000 + 25000) +# QEMU's gdb stub command line changed in 0.11 +QEMUGDB = $(shell if $(QEMU) -nographic -help | grep -q '^-gdb'; \ + then echo "-gdb tcp::$(GDBPORT)"; \ + else echo "-s -p $(GDBPORT)"; fi) + +CC := $(GCCPREFIX)gcc -pipe +AS := $(GCCPREFIX)as +AR := $(GCCPREFIX)ar +LD := $(GCCPREFIX)ld +OBJCOPY := $(GCCPREFIX)objcopy +OBJDUMP := $(GCCPREFIX)objdump +NM := $(GCCPREFIX)nm + +# Native commands +NCC := gcc $(CC_VER) -pipe +TAR := gtar +PERL := perl + +# Compiler flags +# -fno-builtin is required to avoid refs to undefined functions in the kernel. +# Only optimize to -O1 to discourage inlining, which complicates backtraces. +CFLAGS := $(CFLAGS) $(DEFS) $(LABDEFS) -O1 -fno-builtin -I$(TOP) -MD +CFLAGS += -fno-omit-frame-pointer +CFLAGS += -Wall -Wno-format -Wno-unused -Werror -gstabs -m32 + +# Add -fno-stack-protector if the option exists. +CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) + +# Common linker flags +LDFLAGS := -m elf_i386 + +# Linker flags for JOS user programs +ULDFLAGS := -T user/user.ld + +GCC_LIB := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +# Lists that the */Makefrag makefile fragments will add to +OBJDIRS := + +# Make sure that 'all' is the first target +all: + +# Eliminate default suffix rules +.SUFFIXES: + +# Delete target files if there is an error (or make is interrupted) +.DELETE_ON_ERROR: + +# make it so that no intermediate .o files are ever deleted +.PRECIOUS: %.o $(OBJDIR)/boot/%.o $(OBJDIR)/kern/%.o \ + $(OBJDIR)/lib/%.o $(OBJDIR)/fs/%.o $(OBJDIR)/net/%.o \ + $(OBJDIR)/user/%.o + +KERN_CFLAGS := $(CFLAGS) -DJOS_KERNEL -gstabs +USER_CFLAGS := $(CFLAGS) -DJOS_USER -gstabs + + + + +# Include Makefrags for subdirectories +include boot/Makefrag +include kern/Makefrag + + +IMAGES = $(OBJDIR)/kern/kernel.img +QEMUOPTS = -hda $(OBJDIR)/kern/kernel.img -serial mon:stdio $(QEMUEXTRA) + +.gdbinit: .gdbinit.tmpl + sed "s/localhost:1234/localhost:$(GDBPORT)/" < $^ > $@ + +qemu: $(IMAGES) + $(QEMU) $(QEMUOPTS) + +qemu-nox: $(IMAGES) + @echo "***" + @echo "*** Use Ctrl-a x to exit qemu" + @echo "***" + $(QEMU) -nographic $(QEMUOPTS) + +qemu-gdb: $(IMAGES) .gdbinit + @echo "***" + @echo "*** Now run 'gdb'." 1>&2 + @echo "***" + $(QEMU) $(QEMUOPTS) -S $(QEMUGDB) + +qemu-nox-gdb: $(IMAGES) .gdbinit + @echo "***" + @echo "*** Now run 'gdb'." 1>&2 + @echo "***" + $(QEMU) -nographic $(QEMUOPTS) -S $(QEMUGDB) + +print-qemu: + @echo $(QEMU) + +print-gdbport: + @echo $(GDBPORT) + +print-qemugdb: + @echo $(QEMUGDB) + +# For deleting the build +clean: + rm -rf $(OBJDIR) .gdbinit jos.in + +realclean: clean + rm -rf lab$(LAB).tar.gz jos.out + +distclean: realclean + rm -rf conf/gcc.mk + +grade: $(LABSETUP)grade-lab$(LAB).sh + @echo $(MAKE) clean + @$(MAKE) clean || \ + (echo "'make clean' failed. HINT: Do you have another running instance of JOS?" && exit 1) + $(MAKE) all + sh $(LABSETUP)grade-lab$(LAB).sh + +handin: tarball + @echo Please visit http://pdos.csail.mit.edu/6.828/submit/ + @echo and upload lab$(LAB)-handin.tar.gz. Thanks! + +tarball: realclean + tar cf - `find . -type f | grep -v '^\.*$$' | grep -v '/CVS/' | grep -v '/\.svn/' | grep -v '/\.git/' | grep -v 'lab[0-9].*\.tar\.gz'` | gzip > lab$(LAB)-handin.tar.gz + + +# This magic automatically generates makefile dependencies +# for header files included from C source files we compile, +# and keeps those dependencies up-to-date every time we recompile. +# See 'mergedep.pl' for more information. +$(OBJDIR)/.deps: $(foreach dir, $(OBJDIRS), $(wildcard $(OBJDIR)/$(dir)/*.d)) + @mkdir -p $(@D) + @$(PERL) mergedep.pl $@ $^ + +-include $(OBJDIR)/.deps + +always: + @: + +.PHONY: all always \ + handin tarball clean realclean distclean grade diff --git a/boot/Makefrag b/boot/Makefrag new file mode 100644 index 00000000..a2f49f8b --- /dev/null +++ b/boot/Makefrag @@ -0,0 +1,32 @@ +# +# Makefile fragment for the JOS kernel. +# This is NOT a complete makefile; +# you must run GNU make in the top-level directory +# where the GNUmakefile is located. +# + +OBJDIRS += boot + +BOOT_OBJS := $(OBJDIR)/boot/boot.o $(OBJDIR)/boot/main.o + +$(OBJDIR)/boot/%.o: boot/%.c + @echo + cc -Os $< + @mkdir -p $(@D) + $(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $@ $< + +$(OBJDIR)/boot/%.o: boot/%.S + @echo + as $< + @mkdir -p $(@D) + $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< + +$(OBJDIR)/boot/main.o: boot/main.c + @echo + cc -Os $< + $(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $(OBJDIR)/boot/main.o boot/main.c + +$(OBJDIR)/boot/boot: $(BOOT_OBJS) + @echo + ld boot/boot + $(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o $@.out $^ + $(V)$(OBJDUMP) -S $@.out >$@.asm + $(V)$(OBJCOPY) -S -O binary -j .text $@.out $@ + $(V)perl boot/sign.pl $(OBJDIR)/boot/boot + diff --git a/boot/boot.S b/boot/boot.S new file mode 100644 index 00000000..7a91ab1a --- /dev/null +++ b/boot/boot.S @@ -0,0 +1,85 @@ +#include + +# Start the CPU: switch to 32-bit protected mode, jump into C. +# The BIOS loads this code from the first sector of the hard disk into +# memory at physical address 0x7c00 and starts executing in real mode +# with %cs=0 %ip=7c00. + +.set PROT_MODE_CSEG, 0x8 # kernel code segment selector +.set PROT_MODE_DSEG, 0x10 # kernel data segment selector +.set CR0_PE_ON, 0x1 # protected mode enable flag + +.globl start +start: + .code16 # Assemble for 16-bit mode + cli # Disable interrupts + cld # String operations increment + + # Set up the important data segment registers (DS, ES, SS). + xorw %ax,%ax # Segment number zero + movw %ax,%ds # -> Data Segment + movw %ax,%es # -> Extra Segment + movw %ax,%ss # -> Stack Segment + + # Enable A20: + # For backwards compatibility with the earliest PCs, physical + # address line 20 is tied low, so that addresses higher than + # 1MB wrap around to zero by default. This code undoes this. +seta20.1: + inb $0x64,%al # Wait for not busy + testb $0x2,%al + jnz seta20.1 + + movb $0xd1,%al # 0xd1 -> port 0x64 + outb %al,$0x64 + +seta20.2: + inb $0x64,%al # Wait for not busy + testb $0x2,%al + jnz seta20.2 + + movb $0xdf,%al # 0xdf -> port 0x60 + outb %al,$0x60 + + # Switch from real to protected mode, using a bootstrap GDT + # and segment translation that makes virtual addresses + # identical to their physical addresses, so that the + # effective memory map does not change during the switch. + lgdt gdtdesc + movl %cr0, %eax + orl $CR0_PE_ON, %eax + movl %eax, %cr0 + + # Jump to next instruction, but in 32-bit code segment. + # Switches processor into 32-bit mode. + ljmp $PROT_MODE_CSEG, $protcseg + + .code32 # Assemble for 32-bit mode +protcseg: + # Set up the protected-mode data segment registers + movw $PROT_MODE_DSEG, %ax # Our data segment selector + movw %ax, %ds # -> DS: Data Segment + movw %ax, %es # -> ES: Extra Segment + movw %ax, %fs # -> FS + movw %ax, %gs # -> GS + movw %ax, %ss # -> SS: Stack Segment + + # Set up the stack pointer and call into C. + movl $start, %esp + call bootmain + + # If bootmain returns (it shouldn't), loop. +spin: + jmp spin + +# Bootstrap GDT +.p2align 2 # force 4 byte alignment +gdt: + SEG_NULL # null seg + SEG(STA_X|STA_R, 0x0, 0xffffffff) # code seg + SEG(STA_W, 0x0, 0xffffffff) # data seg + +gdtdesc: + .word 0x17 # sizeof(gdt) - 1 + .long gdt # address gdt + diff --git a/boot/main.c b/boot/main.c new file mode 100644 index 00000000..42ca4bb3 --- /dev/null +++ b/boot/main.c @@ -0,0 +1,125 @@ +#include +#include + +/********************************************************************** + * This a dirt simple boot loader, whose sole job is to boot + * an ELF kernel image from the first IDE hard disk. + * + * DISK LAYOUT + * * This program(boot.S and main.c) is the bootloader. It should + * be stored in the first sector of the disk. + * + * * The 2nd sector onward holds the kernel image. + * + * * The kernel image must be in ELF format. + * + * BOOT UP STEPS + * * when the CPU boots it loads the BIOS into memory and executes it + * + * * the BIOS intializes devices, sets of the interrupt routines, and + * reads the first sector of the boot device(e.g., hard-drive) + * into memory and jumps to it. + * + * * Assuming this boot loader is stored in the first sector of the + * hard-drive, this code takes over... + * + * * control starts in boot.S -- which sets up protected mode, + * and a stack so C code then run, then calls bootmain() + * + * * bootmain() in this file takes over, reads in the kernel and jumps to it. + **********************************************************************/ + +#define SECTSIZE 512 +#define ELFHDR ((struct Elf *) 0x10000) // scratch space + +void readsect(void*, uint32_t); +void readseg(uint32_t, uint32_t, uint32_t); + +void +bootmain(void) +{ + struct Proghdr *ph, *eph; + + // read 1st page off disk + readseg((uint32_t) ELFHDR, SECTSIZE*8, 0); + + // is this a valid ELF? + if (ELFHDR->e_magic != ELF_MAGIC) + goto bad; + + // load each program segment (ignores ph flags) + ph = (struct Proghdr *) ((uint8_t *) ELFHDR + ELFHDR->e_phoff); + eph = ph + ELFHDR->e_phnum; + for (; ph < eph; ph++) + // p_pa is the load address of this segment (as well + // as the physical address) + readseg(ph->p_pa, ph->p_memsz, ph->p_offset); + + // call the entry point from the ELF header + // note: does not return! + ((void (*)(void)) (ELFHDR->e_entry))(); + +bad: + outw(0x8A00, 0x8A00); + outw(0x8A00, 0x8E00); + while (1) + /* do nothing */; +} + +// Read 'count' bytes at 'offset' from kernel into physical address 'pa'. +// Might copy more than asked +void +readseg(uint32_t pa, uint32_t count, uint32_t offset) +{ + uint32_t end_pa; + + end_pa = pa + count; + + // round down to sector boundary + pa &= ~(SECTSIZE - 1); + + // translate from bytes to sectors, and kernel starts at sector 1 + offset = (offset / SECTSIZE) + 1; + + // If this is too slow, we could read lots of sectors at a time. + // We'd write more to memory than asked, but it doesn't matter -- + // we load in increasing order. + while (pa < end_pa) { + // Since we haven't enabled paging yet and we're using + // an identity segment mapping (see boot.S), we can + // use physical addresses directly. This won't be the + // case once JOS enables the MMU. + readsect((uint8_t*) pa, offset); + pa += SECTSIZE; + offset++; + } +} + +void +waitdisk(void) +{ + // wait for disk reaady + while ((inb(0x1F7) & 0xC0) != 0x40) + /* do nothing */; +} + +void +readsect(void *dst, uint32_t offset) +{ + // wait for disk to be ready + waitdisk(); + + outb(0x1F2, 1); // count = 1 + outb(0x1F3, offset); + outb(0x1F4, offset >> 8); + outb(0x1F5, offset >> 16); + outb(0x1F6, (offset >> 24) | 0xE0); + outb(0x1F7, 0x20); // cmd 0x20 - read sectors + + // wait for disk to be ready + waitdisk(); + + // read a sector + insl(0x1F0, dst, SECTSIZE/4); +} + diff --git a/boot/sign.pl b/boot/sign.pl new file mode 100644 index 00000000..0bf46cb0 --- /dev/null +++ b/boot/sign.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl + +open(BB, $ARGV[0]) || die "open $ARGV[0]: $!"; + +binmode BB; +my $buf; +read(BB, $buf, 1000); +$n = length($buf); + +if($n > 510){ + print STDERR "boot block too large: $n bytes (max 510)\n"; + exit 1; +} + +print STDERR "boot block is $n bytes (max 510)\n"; + +$buf .= "\0" x (510-$n); +$buf .= "\x55\xAA"; + +open(BB, ">$ARGV[0]") || die "open >$ARGV[0]: $!"; +binmode BB; +print BB $buf; +close BB; diff --git a/conf/env.mk b/conf/env.mk new file mode 100644 index 00000000..a603f9e0 --- /dev/null +++ b/conf/env.mk @@ -0,0 +1,20 @@ +# env.mk - configuration variables for the JOS lab + +# '$(V)' controls whether the lab makefiles print verbose commands (the +# actual shell commands run by Make), as well as the "overview" commands +# (such as '+ cc lib/readline.c'). +# +# For overview commands only, the line should read 'V = @'. +# For overview and verbose commands, the line should read 'V ='. +V = @ + +# If your system-standard GNU toolchain is ELF-compatible, then comment +# out the following line to use those tools (as opposed to the i386-jos-elf +# tools that the 6.828 make system looks for by default). +# +# GCCPREFIX='' + +# If the makefile cannot find your QEMU binary, uncomment the +# following line and set it to the full path to QEMU. +# +# QEMU= diff --git a/conf/lab.mk b/conf/lab.mk new file mode 100644 index 00000000..a09b5685 --- /dev/null +++ b/conf/lab.mk @@ -0,0 +1,2 @@ +LAB=1 +PACKAGEDATE=Tue Sep 6 13:28:58 EDT 2011 diff --git a/grade-functions.sh b/grade-functions.sh new file mode 100644 index 00000000..d7397292 --- /dev/null +++ b/grade-functions.sh @@ -0,0 +1,124 @@ +verbose=false + +if [ "x$1" = "x-v" ] +then + verbose=true + out=/dev/stdout + err=/dev/stderr +else + out=/dev/null + err=/dev/null +fi + +if gmake --version >/dev/null 2>&1; then make=gmake; else make=make; fi + +# +# QEMU +# + +timeout=30 +preservefs=n +qemu=`$make -s --no-print-directory print-qemu` +gdbport=`$make -s --no-print-directory print-gdbport` +qemugdb=`$make -s --no-print-directory print-qemugdb` +brkfn=readline + +echo_n () { + # suns can't echo -n, and Mac OS X can't echo "x\c" + # assume argument has no doublequotes + awk 'BEGIN { printf("'"$*"'"); }' /dev/null` + ( + ulimit -t $timeout + exec $qemu -nographic $qemuopts -serial file:jos.out -monitor null -no-reboot $qemuextra + ) >$out 2>$err & + PID=$! + + # Wait for QEMU to start + sleep 1 + + if [ "$brkfn" ]; then + # Find the address of the kernel $brkfn function, + # which is typically what the kernel monitor uses to + # read commands interactively. + brkaddr=`grep " $brkfn\$" obj/kern/kernel.sym | sed -e's/ .*$//g'` + + ( + echo "target remote localhost:$gdbport" + echo "br *0x$brkaddr" + echo c + ) > jos.in + gdb -batch -nx -x jos.in > /dev/null 2>&1 + + # Make sure QEMU is dead. On OS X, exiting gdb + # doesn't always exit QEMU. + kill $PID > /dev/null 2>&1 + fi +} + +# +# Scoring +# + +pts=5 +part=0 +partpos=0 +total=0 +totalpos=0 + +showpart () { + echo "Part $1 score: $part/$partpos" + echo + total=`expr $total + $part` + totalpos=`expr $totalpos + $partpos` + part=0 + partpos=0 +} + +showfinal () { + total=`expr $total + $part` + totalpos=`expr $totalpos + $partpos` + echo "Score: $total/$totalpos" + if [ $total -lt $totalpos ]; then + exit 1 + fi +} + +passfailmsg () { + msg="$1" + shift + if [ $# -gt 0 ]; then + msg="$msg," + fi + + t1=`date +%s.%N 2>/dev/null` + time=`echo "scale=1; ($t1-$t0)/1" | sed 's/.N/.0/g' | bc 2>/dev/null` + + echo $msg "$@" "(${time}s)" +} + +pass () { + passfailmsg OK "$@" + part=`expr $part + $pts` + partpos=`expr $partpos + $pts` +} + +fail () { + passfailmsg WRONG "$@" + partpos=`expr $partpos + $pts` + if $verbose; then + exit 1 + fi +} + diff --git a/grade-lab1.sh b/grade-lab1.sh new file mode 100644 index 00000000..5d598a01 --- /dev/null +++ b/grade-lab1.sh @@ -0,0 +1,54 @@ +#!/bin/sh + +qemuopts="-hda obj/kern/kernel.img" +. ./grade-functions.sh + + +$make + +check () { + pts=20 + echo_n "Printf: " + if grep "6828 decimal is 15254 octal!" jos.out >/dev/null + then + pass + else + fail + fi + + pts=10 + echo "Backtrace:" + args=`grep "ebp f01.* eip f0100.* args" jos.out | awk '{ print $6 }'` + cnt=`echo $args | grep '^00000000 00000000 00000001 00000002 00000003 00000004 00000005' | wc -w` + echo_n " Count " + if [ $cnt -eq 8 ] + then + pass + else + fail + fi + + cnt=`grep "ebp f01.* eip f0100.* args" jos.out | awk 'BEGIN { FS = ORS = " " } +{ print $6 } +END { printf("\n") }' | grep '^00000000 00000000 00000001 00000002 00000003 00000004 00000005' | wc -w` + echo_n " Args " + if [ $cnt -eq 8 ]; then + pass + else + fail "($args)" + fi + + syms=`grep "kern/init.c:[0-9]*: *test_backtrace[+]" jos.out` + symcnt=`grep "kern/init.c:[0-9]*: *test_backtrace[+]" jos.out | wc -l` + echo_n " Symbols " + if [ $symcnt -eq 6 ]; then + pass + else + fail "($syms)" + fi +} + +run +check + +showfinal diff --git a/inc/COPYRIGHT b/inc/COPYRIGHT new file mode 100644 index 00000000..54e7f320 --- /dev/null +++ b/inc/COPYRIGHT @@ -0,0 +1,229 @@ +The files in this directory are: + +/* + * Copyright (C) 1997 Massachusetts Institute of Technology + * + * This software is being provided by the copyright holders under the + * following license. By obtaining, using and/or copying this software, + * you agree that you have read, understood, and will comply with the + * following terms and conditions: + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose and without fee or royalty is + * hereby granted, provided that the full text of this NOTICE appears on + * ALL copies of the software and documentation or portions thereof, + * including modifications, that you make. + * + * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, + * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR + * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR + * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY + * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT + * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR + * DOCUMENTATION. + * + * The name and trademarks of copyright holders may NOT be used in + * advertising or publicity pertaining to the software without specific, + * written prior permission. Title to copyright in this software and any + * associated documentation will at all times remain with copyright + * holders. See the file AUTHORS which should have accompanied this software + * for a list of all copyright holders. + * + * This file may be derived from previously copyrighted software. This + * copyright applies only to those changes made by the copyright + * holders listed in the AUTHORS file. The rest of this file is covered by + * the copyright notices, if any, listed below. + */ + +isareg.h is copyright: + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)isa.h 5.7 (Berkeley) 5/9/91 + */ + +queue.h is: + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +stdarg.h is: + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)stdarg.h 8.1 (Berkeley) 6/10/93 + */ + +timerreg.h is: + +/*- + * Copyright (c) 1993 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +types.h is: + +/*- + * Copyright (c) 1982, 1986, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)types.h 8.4 (Berkeley) 1/21/94 + */ + diff --git a/inc/assert.h b/inc/assert.h new file mode 100644 index 00000000..aba04dea --- /dev/null +++ b/inc/assert.h @@ -0,0 +1,20 @@ +/* See COPYRIGHT for copyright information. */ + +#ifndef JOS_INC_ASSERT_H +#define JOS_INC_ASSERT_H + +#include + +void _warn(const char*, int, const char*, ...); +void _panic(const char*, int, const char*, ...) __attribute__((noreturn)); + +#define warn(...) _warn(__FILE__, __LINE__, __VA_ARGS__) +#define panic(...) _panic(__FILE__, __LINE__, __VA_ARGS__) + +#define assert(x) \ + do { if (!(x)) panic("assertion failed: %s", #x); } while (0) + +// static_assert(x) will generate a compile-time error if 'x' is false. +#define static_assert(x) switch (x) case 0: case (x): + +#endif /* !JOS_INC_ASSERT_H */ diff --git a/inc/elf.h b/inc/elf.h new file mode 100644 index 00000000..f0ce1e14 --- /dev/null +++ b/inc/elf.h @@ -0,0 +1,65 @@ +#ifndef JOS_INC_ELF_H +#define JOS_INC_ELF_H + +#define ELF_MAGIC 0x464C457FU /* "\x7FELF" in little endian */ + +struct Elf { + uint32_t e_magic; // must equal ELF_MAGIC + uint8_t e_elf[12]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +}; + +struct Proghdr { + uint32_t p_type; + uint32_t p_offset; + uint32_t p_va; + uint32_t p_pa; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; +}; + +struct Secthdr { + uint32_t sh_name; + uint32_t sh_type; + uint32_t sh_flags; + uint32_t sh_addr; + uint32_t sh_offset; + uint32_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint32_t sh_addralign; + uint32_t sh_entsize; +}; + +// Values for Proghdr::p_type +#define ELF_PROG_LOAD 1 + +// Flag bits for Proghdr::p_flags +#define ELF_PROG_FLAG_EXEC 1 +#define ELF_PROG_FLAG_WRITE 2 +#define ELF_PROG_FLAG_READ 4 + +// Values for Secthdr::sh_type +#define ELF_SHT_NULL 0 +#define ELF_SHT_PROGBITS 1 +#define ELF_SHT_SYMTAB 2 +#define ELF_SHT_STRTAB 3 + +// Values for Secthdr::sh_name +#define ELF_SHN_UNDEF 0 + +#endif /* !JOS_INC_ELF_H */ diff --git a/inc/error.h b/inc/error.h new file mode 100644 index 00000000..d4f1443b --- /dev/null +++ b/inc/error.h @@ -0,0 +1,20 @@ +/* See COPYRIGHT for copyright information. */ + +#ifndef JOS_INC_ERROR_H +#define JOS_INC_ERROR_H + +enum { + // Kernel error codes -- keep in sync with list in lib/printfmt.c. + E_UNSPECIFIED = 1, // Unspecified or unknown problem + E_BAD_ENV = 2, // Environment doesn't exist or otherwise + // cannot be used in requested action + E_INVAL = 3, // Invalid parameter + E_NO_MEM = 4, // Request failed due to memory shortage + E_NO_FREE_ENV = 5, // Attempt to create a new environment beyond + // the maximum allowed + E_FAULT = 6, // Memory fault + + MAXERROR +}; + +#endif // !JOS_INC_ERROR_H */ diff --git a/inc/kbdreg.h b/inc/kbdreg.h new file mode 100644 index 00000000..7c6d740a --- /dev/null +++ b/inc/kbdreg.h @@ -0,0 +1,83 @@ +#ifndef JOS_KBDREG_H +#define JOS_KBDREG_H + +// Special keycodes +#define KEY_HOME 0xE0 +#define KEY_END 0xE1 +#define KEY_UP 0xE2 +#define KEY_DN 0xE3 +#define KEY_LF 0xE4 +#define KEY_RT 0xE5 +#define KEY_PGUP 0xE6 +#define KEY_PGDN 0xE7 +#define KEY_INS 0xE8 +#define KEY_DEL 0xE9 + + +/* This is i8042reg.h + kbdreg.h from NetBSD. */ + +#define KBSTATP 0x64 /* kbd controller status port(I) */ +#define KBS_DIB 0x01 /* kbd data in buffer */ +#define KBS_IBF 0x02 /* kbd input buffer low */ +#define KBS_WARM 0x04 /* kbd input buffer low */ +#define KBS_OCMD 0x08 /* kbd output buffer has command */ +#define KBS_NOSEC 0x10 /* kbd security lock not engaged */ +#define KBS_TERR 0x20 /* kbd transmission error */ +#define KBS_RERR 0x40 /* kbd receive error */ +#define KBS_PERR 0x80 /* kbd parity error */ + +#define KBCMDP 0x64 /* kbd controller port(O) */ +#define KBC_RAMREAD 0x20 /* read from RAM */ +#define KBC_RAMWRITE 0x60 /* write to RAM */ +#define KBC_AUXDISABLE 0xa7 /* disable auxiliary port */ +#define KBC_AUXENABLE 0xa8 /* enable auxiliary port */ +#define KBC_AUXTEST 0xa9 /* test auxiliary port */ +#define KBC_KBDECHO 0xd2 /* echo to keyboard port */ +#define KBC_AUXECHO 0xd3 /* echo to auxiliary port */ +#define KBC_AUXWRITE 0xd4 /* write to auxiliary port */ +#define KBC_SELFTEST 0xaa /* start self-test */ +#define KBC_KBDTEST 0xab /* test keyboard port */ +#define KBC_KBDDISABLE 0xad /* disable keyboard port */ +#define KBC_KBDENABLE 0xae /* enable keyboard port */ +#define KBC_PULSE0 0xfe /* pulse output bit 0 */ +#define KBC_PULSE1 0xfd /* pulse output bit 1 */ +#define KBC_PULSE2 0xfb /* pulse output bit 2 */ +#define KBC_PULSE3 0xf7 /* pulse output bit 3 */ + +#define KBDATAP 0x60 /* kbd data port(I) */ +#define KBOUTP 0x60 /* kbd data port(O) */ + +#define K_RDCMDBYTE 0x20 +#define K_LDCMDBYTE 0x60 + +#define KC8_TRANS 0x40 /* convert to old scan codes */ +#define KC8_MDISABLE 0x20 /* disable mouse */ +#define KC8_KDISABLE 0x10 /* disable keyboard */ +#define KC8_IGNSEC 0x08 /* ignore security lock */ +#define KC8_CPU 0x04 /* exit from protected mode reset */ +#define KC8_MENABLE 0x02 /* enable mouse interrupt */ +#define KC8_KENABLE 0x01 /* enable keyboard interrupt */ +#define CMDBYTE (KC8_TRANS|KC8_CPU|KC8_MENABLE|KC8_KENABLE) + +/* keyboard commands */ +#define KBC_RESET 0xFF /* reset the keyboard */ +#define KBC_RESEND 0xFE /* request the keyboard resend the last byte */ +#define KBC_SETDEFAULT 0xF6 /* resets keyboard to its power-on defaults */ +#define KBC_DISABLE 0xF5 /* as per KBC_SETDEFAULT, but also disable key scanning */ +#define KBC_ENABLE 0xF4 /* enable key scanning */ +#define KBC_TYPEMATIC 0xF3 /* set typematic rate and delay */ +#define KBC_SETTABLE 0xF0 /* set scancode translation table */ +#define KBC_MODEIND 0xED /* set mode indicators(i.e. LEDs) */ +#define KBC_ECHO 0xEE /* request an echo from the keyboard */ + +/* keyboard responses */ +#define KBR_EXTENDED 0xE0 /* extended key sequence */ +#define KBR_RESEND 0xFE /* needs resend of command */ +#define KBR_ACK 0xFA /* received a valid command */ +#define KBR_OVERRUN 0x00 /* flooded */ +#define KBR_FAILURE 0xFD /* diagnosic failure */ +#define KBR_BREAK 0xF0 /* break code prefix - sent on key release */ +#define KBR_RSTDONE 0xAA /* reset complete */ +#define KBR_ECHO 0xEE /* echo response */ + +#endif /* !JOS_KBDREG_H */ diff --git a/inc/malloc.h b/inc/malloc.h new file mode 100644 index 00000000..bef7267e --- /dev/null +++ b/inc/malloc.h @@ -0,0 +1,7 @@ +#ifndef JOS_INC_MALLOC_H +#define JOS_INC_MALLOC_H 1 + +void *malloc(size_t size); +void free(void *addr); + +#endif diff --git a/inc/memlayout.h b/inc/memlayout.h new file mode 100644 index 00000000..b6395c85 --- /dev/null +++ b/inc/memlayout.h @@ -0,0 +1,183 @@ +#ifndef JOS_INC_MEMLAYOUT_H +#define JOS_INC_MEMLAYOUT_H + +#ifndef __ASSEMBLER__ +#include +#include +#include +#endif /* not __ASSEMBLER__ */ + +/* + * This file contains definitions for memory management in our OS, + * which are relevant to both the kernel and user-mode software. + */ + +// Global descriptor numbers +#define GD_KT 0x08 // kernel text +#define GD_KD 0x10 // kernel data +#define GD_UT 0x18 // user text +#define GD_UD 0x20 // user data +#define GD_TSS 0x28 // Task segment selector + +/* + * Virtual memory map: Permissions + * kernel/user + * + * 4 Gig --------> +------------------------------+ + * | | RW/-- + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * : . : + * : . : + * : . : + * |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| RW/-- + * | | RW/-- + * | Remapped Physical Memory | RW/-- + * | | RW/-- + * KERNBASE -----> +------------------------------+ 0xf0000000 + * | Cur. Page Table (Kern. RW) | RW/-- PTSIZE + * VPT,KSTACKTOP--> +------------------------------+ 0xefc00000 --+ + * | Kernel Stack | RW/-- KSTKSIZE | + * | - - - - - - - - - - - - - - -| PTSIZE + * | Invalid Memory (*) | --/-- | + * ULIM ------> +------------------------------+ 0xef800000 --+ + * | Cur. Page Table (User R-) | R-/R- PTSIZE + * UVPT ----> +------------------------------+ 0xef400000 + * | RO PAGES | R-/R- PTSIZE + * UPAGES ----> +------------------------------+ 0xef000000 + * | RO ENVS | R-/R- PTSIZE + * UTOP,UENVS ------> +------------------------------+ 0xeec00000 + * UXSTACKTOP -/ | User Exception Stack | RW/RW PGSIZE + * +------------------------------+ 0xeebff000 + * | Empty Memory (*) | --/-- PGSIZE + * USTACKTOP ---> +------------------------------+ 0xeebfe000 + * | Normal User Stack | RW/RW PGSIZE + * +------------------------------+ 0xeebfd000 + * | | + * | | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * . . + * . . + * . . + * |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| + * | Program Data & Heap | + * UTEXT --------> +------------------------------+ 0x00800000 + * PFTEMP -------> | Empty Memory (*) | PTSIZE + * | | + * UTEMP --------> +------------------------------+ 0x00400000 --+ + * | Empty Memory (*) | | + * | - - - - - - - - - - - - - - -| | + * | User STAB Data (optional) | PTSIZE + * USTABDATA ----> +------------------------------+ 0x00200000 | + * | Empty Memory (*) | | + * 0 ------------> +------------------------------+ --+ + * + * (*) Note: The kernel ensures that "Invalid Memory" (ULIM) is *never* + * mapped. "Empty Memory" is normally unmapped, but user programs may + * map pages there if desired. JOS user programs map pages temporarily + * at UTEMP. + */ + + +// All physical memory mapped at this address +#define KERNBASE 0xF0000000 + +// At IOPHYSMEM (640K) there is a 384K hole for I/O. From the kernel, +// IOPHYSMEM can be addressed at KERNBASE + IOPHYSMEM. The hole ends +// at physical address EXTPHYSMEM. +#define IOPHYSMEM 0x0A0000 +#define EXTPHYSMEM 0x100000 + +// Virtual page table. Entry PDX[VPT] in the PD contains a pointer to +// the page directory itself, thereby turning the PD into a page table, +// which maps all the PTEs containing the page mappings for the entire +// virtual address space into that 4 Meg region starting at VPT. +#define VPT (KERNBASE - PTSIZE) +#define KSTACKTOP VPT +#define KSTKSIZE (8*PGSIZE) // size of a kernel stack +#define ULIM (KSTACKTOP - PTSIZE) + +/* + * User read-only mappings! Anything below here til UTOP are readonly to user. + * They are global pages mapped in at env allocation time. + */ + +// Same as VPT but read-only for users +#define UVPT (ULIM - PTSIZE) +// Read-only copies of the Page structures +#define UPAGES (UVPT - PTSIZE) +// Read-only copies of the global env structures +#define UENVS (UPAGES - PTSIZE) + +/* + * Top of user VM. User can manipulate VA from UTOP-1 and down! + */ + +// Top of user-accessible VM +#define UTOP UENVS +// Top of one-page user exception stack +#define UXSTACKTOP UTOP +// Next page left invalid to guard against exception stack overflow; then: +// Top of normal user stack +#define USTACKTOP (UTOP - 2*PGSIZE) + +// Where user programs generally begin +#define UTEXT (2*PTSIZE) + +// Used for temporary page mappings. Typed 'void*' for convenience +#define UTEMP ((void*) PTSIZE) +// Used for temporary page mappings for the user page-fault handler +// (should not conflict with other temporary page mappings) +#define PFTEMP (UTEMP + PTSIZE - PGSIZE) +// The location of the user-level STABS data structure +#define USTABDATA (PTSIZE / 2) + + +#ifndef __ASSEMBLER__ + +/* + * The page directory entry corresponding to the virtual address range + * [VPT, VPT + PTSIZE) points to the page directory itself. Thus, the page + * directory is treated as a page table as well as a page directory. + * + * One result of treating the page directory as a page table is that all PTEs + * can be accessed through a "virtual page table" at virtual address VPT (to + * which vpt is set in entry.S). The PTE for page number N is stored in + * vpt[N]. (It's worth drawing a diagram of this!) + * + * A second consequence is that the contents of the current page directory + * will always be available at virtual address (VPT + (VPT >> PGSHIFT)), to + * which vpd is set in entry.S. + */ +typedef uint32_t pte_t; +typedef uint32_t pde_t; + +extern volatile pte_t vpt[]; // VA of "virtual page table" +extern volatile pde_t vpd[]; // VA of current page directory + + +/* + * Page descriptor structures, mapped at UPAGES. + * Read/write to the kernel, read-only to user programs. + * + * Each struct Page stores metadata for one physical page. + * Is it NOT the physical page itself, but there is a one-to-one + * correspondence between physical pages and struct Page's. + * You can map a Page * to the corresponding physical address + * with page2pa() in kern/pmap.h. + */ +LIST_HEAD(Page_list, Page); +typedef LIST_ENTRY(Page) Page_LIST_entry_t; + +struct Page { + Page_LIST_entry_t pp_link; /* free list link */ + + // pp_ref is the count of pointers (usually in page table entries) + // to this page, for pages allocated using page_alloc. + // Pages allocated at boot time using pmap.c's + // boot_alloc do not have valid reference count fields. + + uint16_t pp_ref; +}; + +#endif /* !__ASSEMBLER__ */ +#endif /* !JOS_INC_MEMLAYOUT_H */ diff --git a/inc/mmu.h b/inc/mmu.h new file mode 100644 index 00000000..31d10b66 --- /dev/null +++ b/inc/mmu.h @@ -0,0 +1,319 @@ +#ifndef JOS_INC_MMU_H +#define JOS_INC_MMU_H + +/* + * This file contains definitions for the x86 memory management unit (MMU), + * including paging- and segmentation-related data structures and constants, + * the %cr0, %cr4, and %eflags registers, and traps. + */ + +/* + * + * Part 1. Paging data structures and constants. + * + */ + +// A linear address 'la' has a three-part structure as follows: +// +// +--------10------+-------10-------+---------12----------+ +// | Page Directory | Page Table | Offset within Page | +// | Index | Index | | +// +----------------+----------------+---------------------+ +// \--- PDX(la) --/ \--- PTX(la) --/ \---- PGOFF(la) ----/ +// \----------- VPN(la) -----------/ +// +// The PDX, PTX, PGOFF, and VPN macros decompose linear addresses as shown. +// To construct a linear address la from PDX(la), PTX(la), and PGOFF(la), +// use PGADDR(PDX(la), PTX(la), PGOFF(la)). + +// page number field of address +#define PPN(pa) (((uintptr_t) (pa)) >> PTXSHIFT) +#define VPN(la) PPN(la) // used to index into vpt[] + +// page directory index +#define PDX(la) ((((uintptr_t) (la)) >> PDXSHIFT) & 0x3FF) +#define VPD(la) PDX(la) // used to index into vpd[] + +// page table index +#define PTX(la) ((((uintptr_t) (la)) >> PTXSHIFT) & 0x3FF) + +// offset in page +#define PGOFF(la) (((uintptr_t) (la)) & 0xFFF) + +// construct linear address from indexes and offset +#define PGADDR(d, t, o) ((void*) ((d) << PDXSHIFT | (t) << PTXSHIFT | (o))) + +// Page directory and page table constants. +#define NPDENTRIES 1024 // page directory entries per page directory +#define NPTENTRIES 1024 // page table entries per page table + +#define PGSIZE 4096 // bytes mapped by a page +#define PGSHIFT 12 // log2(PGSIZE) + +#define PTSIZE (PGSIZE*NPTENTRIES) // bytes mapped by a page directory entry +#define PTSHIFT 22 // log2(PTSIZE) + +#define PTXSHIFT 12 // offset of PTX in a linear address +#define PDXSHIFT 22 // offset of PDX in a linear address + +// Page table/directory entry flags. +#define PTE_P 0x001 // Present +#define PTE_W 0x002 // Writeable +#define PTE_U 0x004 // User +#define PTE_PWT 0x008 // Write-Through +#define PTE_PCD 0x010 // Cache-Disable +#define PTE_A 0x020 // Accessed +#define PTE_D 0x040 // Dirty +#define PTE_PS 0x080 // Page Size +#define PTE_G 0x100 // Global + +// The PTE_AVAIL bits aren't used by the kernel or interpreted by the +// hardware, so user processes are allowed to set them arbitrarily. +#define PTE_AVAIL 0xE00 // Available for software use + +// Only flags in PTE_ALLOWED may be used in system calls. +#define PTE_ALLOWED (PTE_AVAIL | PTE_P | PTE_W | PTE_U) + +// Address in page table or page directory entry +#define PTE_ADDR(pte) ((physaddr_t) (pte) & ~0xFFF) + +// Control Register flags +#define CR0_PE 0x00000001 // Protection Enable +#define CR0_MP 0x00000002 // Monitor coProcessor +#define CR0_EM 0x00000004 // Emulation +#define CR0_TS 0x00000008 // Task Switched +#define CR0_ET 0x00000010 // Extension Type +#define CR0_NE 0x00000020 // Numeric Errror +#define CR0_WP 0x00010000 // Write Protect +#define CR0_AM 0x00040000 // Alignment Mask +#define CR0_NW 0x20000000 // Not Writethrough +#define CR0_CD 0x40000000 // Cache Disable +#define CR0_PG 0x80000000 // Paging + +#define CR4_PCE 0x00000100 // Performance counter enable +#define CR4_MCE 0x00000040 // Machine Check Enable +#define CR4_PSE 0x00000010 // Page Size Extensions +#define CR4_DE 0x00000008 // Debugging Extensions +#define CR4_TSD 0x00000004 // Time Stamp Disable +#define CR4_PVI 0x00000002 // Protected-Mode Virtual Interrupts +#define CR4_VME 0x00000001 // V86 Mode Extensions + +// Eflags register +#define FL_CF 0x00000001 // Carry Flag +#define FL_PF 0x00000004 // Parity Flag +#define FL_AF 0x00000010 // Auxiliary carry Flag +#define FL_ZF 0x00000040 // Zero Flag +#define FL_SF 0x00000080 // Sign Flag +#define FL_TF 0x00000100 // Trap Flag +#define FL_IF 0x00000200 // Interrupt Flag +#define FL_DF 0x00000400 // Direction Flag +#define FL_OF 0x00000800 // Overflow Flag +#define FL_IOPL_MASK 0x00003000 // I/O Privilege Level bitmask +#define FL_IOPL_0 0x00000000 // IOPL == 0 +#define FL_IOPL_1 0x00001000 // IOPL == 1 +#define FL_IOPL_2 0x00002000 // IOPL == 2 +#define FL_IOPL_3 0x00003000 // IOPL == 3 +#define FL_NT 0x00004000 // Nested Task +#define FL_RF 0x00010000 // Resume Flag +#define FL_VM 0x00020000 // Virtual 8086 mode +#define FL_AC 0x00040000 // Alignment Check +#define FL_VIF 0x00080000 // Virtual Interrupt Flag +#define FL_VIP 0x00100000 // Virtual Interrupt Pending +#define FL_ID 0x00200000 // ID flag + +// Page fault error codes +#define FEC_PR 0x1 // Page fault caused by protection violation +#define FEC_WR 0x2 // Page fault caused by a write +#define FEC_U 0x4 // Page fault occured while in user mode + + +/* + * + * Part 2. Segmentation data structures and constants. + * + */ + +#ifdef __ASSEMBLER__ + +/* + * Macros to build GDT entries in assembly. + */ +#define SEG_NULL \ + .word 0, 0; \ + .byte 0, 0, 0, 0 +#define SEG(type,base,lim) \ + .word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \ + .byte (((base) >> 16) & 0xff), (0x90 | (type)), \ + (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) + +#else // not __ASSEMBLER__ + +#include + +// Segment Descriptors +struct Segdesc { + unsigned sd_lim_15_0 : 16; // Low bits of segment limit + unsigned sd_base_15_0 : 16; // Low bits of segment base address + unsigned sd_base_23_16 : 8; // Middle bits of segment base address + unsigned sd_type : 4; // Segment type (see STS_ constants) + unsigned sd_s : 1; // 0 = system, 1 = application + unsigned sd_dpl : 2; // Descriptor Privilege Level + unsigned sd_p : 1; // Present + unsigned sd_lim_19_16 : 4; // High bits of segment limit + unsigned sd_avl : 1; // Unused (available for software use) + unsigned sd_rsv1 : 1; // Reserved + unsigned sd_db : 1; // 0 = 16-bit segment, 1 = 32-bit segment + unsigned sd_g : 1; // Granularity: limit scaled by 4K when set + unsigned sd_base_31_24 : 8; // High bits of segment base address +}; +// Null segment +#define SEG_NULL (struct Segdesc){ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +// Segment that is loadable but faults when used +#define SEG_FAULT (struct Segdesc){ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 } +// Normal segment +#define SEG(type, base, lim, dpl) (struct Segdesc) \ +{ ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff, \ + type, 1, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1, \ + (unsigned) (base) >> 24 } +#define SEG16(type, base, lim, dpl) (struct Segdesc) \ +{ (lim) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff, \ + type, 1, dpl, 1, (unsigned) (lim) >> 16, 0, 0, 1, 0, \ + (unsigned) (base) >> 24 } + +#endif /* !__ASSEMBLER__ */ + +// Application segment type bits +#define STA_X 0x8 // Executable segment +#define STA_E 0x4 // Expand down (non-executable segments) +#define STA_C 0x4 // Conforming code segment (executable only) +#define STA_W 0x2 // Writeable (non-executable segments) +#define STA_R 0x2 // Readable (executable segments) +#define STA_A 0x1 // Accessed + +// System segment type bits +#define STS_T16A 0x1 // Available 16-bit TSS +#define STS_LDT 0x2 // Local Descriptor Table +#define STS_T16B 0x3 // Busy 16-bit TSS +#define STS_CG16 0x4 // 16-bit Call Gate +#define STS_TG 0x5 // Task Gate / Coum Transmitions +#define STS_IG16 0x6 // 16-bit Interrupt Gate +#define STS_TG16 0x7 // 16-bit Trap Gate +#define STS_T32A 0x9 // Available 32-bit TSS +#define STS_T32B 0xB // Busy 32-bit TSS +#define STS_CG32 0xC // 32-bit Call Gate +#define STS_IG32 0xE // 32-bit Interrupt Gate +#define STS_TG32 0xF // 32-bit Trap Gate + + +/* + * + * Part 3. Traps. + * + */ + +#ifndef __ASSEMBLER__ + +// Task state segment format (as described by the Pentium architecture book) +struct Taskstate { + uint32_t ts_link; // Old ts selector + uintptr_t ts_esp0; // Stack pointers and segment selectors + uint16_t ts_ss0; // after an increase in privilege level + uint16_t ts_padding1; + uintptr_t ts_esp1; + uint16_t ts_ss1; + uint16_t ts_padding2; + uintptr_t ts_esp2; + uint16_t ts_ss2; + uint16_t ts_padding3; + physaddr_t ts_cr3; // Page directory base + uintptr_t ts_eip; // Saved state from last task switch + uint32_t ts_eflags; + uint32_t ts_eax; // More saved state (registers) + uint32_t ts_ecx; + uint32_t ts_edx; + uint32_t ts_ebx; + uintptr_t ts_esp; + uintptr_t ts_ebp; + uint32_t ts_esi; + uint32_t ts_edi; + uint16_t ts_es; // Even more saved state (segment selectors) + uint16_t ts_padding4; + uint16_t ts_cs; + uint16_t ts_padding5; + uint16_t ts_ss; + uint16_t ts_padding6; + uint16_t ts_ds; + uint16_t ts_padding7; + uint16_t ts_fs; + uint16_t ts_padding8; + uint16_t ts_gs; + uint16_t ts_padding9; + uint16_t ts_ldt; + uint16_t ts_padding10; + uint16_t ts_t; // Trap on task switch + uint16_t ts_iomb; // I/O map base address +}; + +// Gate descriptors for interrupts and traps +struct Gatedesc { + unsigned gd_off_15_0 : 16; // low 16 bits of offset in segment + unsigned gd_ss : 16; // segment selector + unsigned gd_args : 5; // # args, 0 for interrupt/trap gates + unsigned gd_rsv1 : 3; // reserved(should be zero I guess) + unsigned gd_type : 4; // type(STS_{TG,IG32,TG32}) + unsigned gd_s : 1; // must be 0 (system) + unsigned gd_dpl : 2; // descriptor(meaning new) privilege level + unsigned gd_p : 1; // Present + unsigned gd_off_31_16 : 16; // high bits of offset in segment +}; + +// Set up a normal interrupt/trap gate descriptor. +// - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate. + // see section 9.6.1.3 of the i386 reference: "The difference between + // an interrupt gate and a trap gate is in the effect on IF (the + // interrupt-enable flag). An interrupt that vectors through an + // interrupt gate resets IF, thereby preventing other interrupts from + // interfering with the current interrupt handler. A subsequent IRET + // instruction restores IF to the value in the EFLAGS image on the + // stack. An interrupt through a trap gate does not change IF." +// - sel: Code segment selector for interrupt/trap handler +// - off: Offset in code segment for interrupt/trap handler +// - dpl: Descriptor Privilege Level - +// the privilege level required for software to invoke +// this interrupt/trap gate explicitly using an int instruction. +#define SETGATE(gate, istrap, sel, off, dpl) \ +{ \ + (gate).gd_off_15_0 = (uint32_t) (off) & 0xffff; \ + (gate).gd_ss = (sel); \ + (gate).gd_args = 0; \ + (gate).gd_rsv1 = 0; \ + (gate).gd_type = (istrap) ? STS_TG32 : STS_IG32; \ + (gate).gd_s = 0; \ + (gate).gd_dpl = (dpl); \ + (gate).gd_p = 1; \ + (gate).gd_off_31_16 = (uint32_t) (off) >> 16; \ +} + +// Set up a call gate descriptor. +#define SETCALLGATE(gate, ss, off, dpl) \ +{ \ + (gate).gd_off_15_0 = (uint32_t) (off) & 0xffff; \ + (gate).gd_ss = (ss); \ + (gate).gd_args = 0; \ + (gate).gd_rsv1 = 0; \ + (gate).gd_type = STS_CG32; \ + (gate).gd_s = 0; \ + (gate).gd_dpl = (dpl); \ + (gate).gd_p = 1; \ + (gate).gd_off_31_16 = (uint32_t) (off) >> 16; \ +} + +// Pseudo-descriptors used for LGDT, LLDT and LIDT instructions. +struct Pseudodesc { + uint16_t pd_lim; // Limit + uint32_t pd_base; // Base address +} __attribute__ ((packed)); + +#endif /* !__ASSEMBLER__ */ + +#endif /* !JOS_INC_MMU_H */ diff --git a/inc/queue.h b/inc/queue.h new file mode 100644 index 00000000..76804156 --- /dev/null +++ b/inc/queue.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.3 (Berkeley) 12/13/93 + * + * For Jos, extra comments have been added to this file, and the original + * TAILQ and CIRCLEQ definitions have been removed. - August 9, 2005 + */ + +#ifndef JOS_INC_QUEUE_H +#define JOS_INC_QUEUE_H + +/* + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + */ + +/* + * An example using the below functions. + */ +#if 0 + +struct Frob +{ + int frobozz; + LIST_ENTRY(Frob) frob_link; /* this contains the list element pointers */ +}; + +LIST_HEAD(Frob_list, Frob) /* defines struct Frob_list as a list of Frob */ + +struct Frob_list flist; /* declare a Frob list */ + +LIST_INIT(&flist); /* clear flist (globals are cleared anyway) */ +flist = LIST_HEAD_INITIALIZER(&flist); /* alternate way to clear flist */ + +if(LIST_EMPTY(&flist)) /* check whether list is empty */ + printf("list is empty\n"); + +struct Frob *f = LIST_FIRST(&flist); /* f is first element in list */ +f = LIST_NEXT(f, frob_link); /* now f is next (second) element in list */ +f = LIST_NEXT(f, frob_link); /* now f is next (third) element in list */ + +for(f=LIST_FIRST(&flist); f != 0; /* iterate over elements in flist */ + f = LIST_NEXT(f, frob_link)) + printf("f %d\n", f->frobozz); + +LIST_FOREACH(f, &flist, frob_link) /* alternate way to say that */ + printf("f %d\n", f->frobozz); + +f = LIST_NEXT(LIST_FIRST(&flist)); /* f is second element in list */ +LIST_INSERT_AFTER(f, g, frob_link); /* add g right after f in list */ +LIST_REMOVE(g, frob_link); /* remove g from list (can't insert twice!) */ +LIST_INSERT_BEFORE(f, g, frob_link); /* add g right before f */ +LIST_REMOVE(g, frob_link); /* remove g again */ +LIST_INSERT_HEAD(&flist, g, frob_link); /* add g as first element in list */ + +#endif + +/* + * List declarations. + */ + +/* + * A list is headed by a structure defined by the LIST_HEAD macro. This structure con‐ + * tains a single pointer to the first element on the list. The elements are doubly + * linked so that an arbitrary element can be removed without traversing the list. New + * elements can be added to the list after an existing element or at the head of the list. + * A LIST_HEAD structure is declared as follows: + * + * LIST_HEAD(HEADNAME, TYPE) head; + * + * where HEADNAME is the name of the structure to be defined, and TYPE is the type of the + * elements to be linked into the list. A pointer to the head of the list can later be + * declared as: + * + * struct HEADNAME *headp; + * + * (The names head and headp are user selectable.) + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +/* + * Set a list head variable to LIST_HEAD_INITIALIZER(head) + * to reset it to the empty list. + */ +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +/* + * Use this inside a structure "LIST_ENTRY(type) field" to use + * x as the list piece. + * + * The le_prev points at the pointer to the structure containing + * this very LIST_ENTRY, so that if we want to remove this list entry, + * we can do *le_prev = le_next to update the structure pointing at us. + */ +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* ptr to ptr to this element */ \ +} + +/* + * List functions. + */ + +/* + * Is the list named "head" empty? + */ +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +/* + * Return the first element in the list named "head". + */ +#define LIST_FIRST(head) ((head)->lh_first) + +/* + * Return the element after "elm" in the list. + * The "field" name is the link element as above. + */ +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +/* + * Iterate over the elements in the list named "head". + * During the loop, assign the list elements to the variable "var" + * and use the LIST_ENTRY structure member "field" as the link field. + */ +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +/* + * Reset the list named "head" to the empty list. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +/* + * Insert the element "elm" *after* the element "listelm" which is + * already in the list. The "field" name is the link element + * as above. + */ +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +/* + * Insert the element "elm" *before* the element "listelm" which is + * already in the list. The "field" name is the link element + * as above. + */ +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +/* + * Insert the element "elm" at the head of the list named "head". + * The "field" name is the link element as above. + */ +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +/* + * Remove the element "elm" from the list. + * The "field" name is the link element as above. + */ +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/inc/stab.h b/inc/stab.h new file mode 100644 index 00000000..8153cec4 --- /dev/null +++ b/inc/stab.h @@ -0,0 +1,51 @@ +#ifndef JOS_STAB_H +#define JOS_STAB_H +#include + +// +// STABS debugging info + +// The JOS kernel debugger can understand some debugging information +// in the STABS format. For more information on this format, see +// http://sourceware.org/gdb/onlinedocs/stabs.html + +// The constants below define some symbol types used by various debuggers +// and compilers. JOS uses the N_SO, N_SOL, N_FUN, and N_SLINE types. + +#define N_GSYM 0x20 // global symbol +#define N_FNAME 0x22 // F77 function name +#define N_FUN 0x24 // procedure name +#define N_STSYM 0x26 // data segment variable +#define N_LCSYM 0x28 // bss segment variable +#define N_MAIN 0x2a // main function name +#define N_PC 0x30 // global Pascal symbol +#define N_RSYM 0x40 // register variable +#define N_SLINE 0x44 // text segment line number +#define N_DSLINE 0x46 // data segment line number +#define N_BSLINE 0x48 // bss segment line number +#define N_SSYM 0x60 // structure/union element +#define N_SO 0x64 // main source file name +#define N_LSYM 0x80 // stack variable +#define N_BINCL 0x82 // include file beginning +#define N_SOL 0x84 // included source file name +#define N_PSYM 0xa0 // parameter variable +#define N_EINCL 0xa2 // include file end +#define N_ENTRY 0xa4 // alternate entry point +#define N_LBRAC 0xc0 // left bracket +#define N_EXCL 0xc2 // deleted include file +#define N_RBRAC 0xe0 // right bracket +#define N_BCOMM 0xe2 // begin common +#define N_ECOMM 0xe4 // end common +#define N_ECOML 0xe8 // end common (local name) +#define N_LENG 0xfe // length of preceding entry + +// Entries in the STABS table are formatted as follows. +struct Stab { + uint32_t n_strx; // index into string table of name + uint8_t n_type; // type of symbol + uint8_t n_other; // misc info (usually empty) + uint16_t n_desc; // description field + uintptr_t n_value; // value of symbol +}; + +#endif /* !JOS_STAB_H */ diff --git a/inc/stdarg.h b/inc/stdarg.h new file mode 100644 index 00000000..cf8d814e --- /dev/null +++ b/inc/stdarg.h @@ -0,0 +1,14 @@ +/* $NetBSD: stdarg.h,v 1.12 1995/12/25 23:15:31 mycroft Exp $ */ + +#ifndef JOS_INC_STDARG_H +#define JOS_INC_STDARG_H + +typedef __builtin_va_list va_list; + +#define va_start(ap, last) __builtin_va_start(ap, last) + +#define va_arg(ap, type) __builtin_va_arg(ap, type) + +#define va_end(ap) __builtin_va_end(ap) + +#endif /* !JOS_INC_STDARG_H */ diff --git a/inc/stdio.h b/inc/stdio.h new file mode 100644 index 00000000..a7769966 --- /dev/null +++ b/inc/stdio.h @@ -0,0 +1,33 @@ +#ifndef JOS_INC_STDIO_H +#define JOS_INC_STDIO_H + +#include + +#ifndef NULL +#define NULL ((void *) 0) +#endif /* !NULL */ + +// lib/stdio.c +void cputchar(int c); +int getchar(void); +int iscons(int fd); + +// lib/printfmt.c +void printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...); +void vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list); +int snprintf(char *str, int size, const char *fmt, ...); +int vsnprintf(char *str, int size, const char *fmt, va_list); + +// lib/printf.c +int cprintf(const char *fmt, ...); +int vcprintf(const char *fmt, va_list); + +// lib/fprintf.c +int printf(const char *fmt, ...); +int fprintf(int fd, const char *fmt, ...); +int vfprintf(int fd, const char *fmt, va_list); + +// lib/readline.c +char* readline(const char *prompt); + +#endif /* !JOS_INC_STDIO_H */ diff --git a/inc/string.h b/inc/string.h new file mode 100644 index 00000000..617cd286 --- /dev/null +++ b/inc/string.h @@ -0,0 +1,24 @@ +#ifndef JOS_INC_STRING_H +#define JOS_INC_STRING_H + +#include + +int strlen(const char *s); +int strnlen(const char *s, size_t size); +char * strcpy(char *dst, const char *src); +char * strncpy(char *dst, const char *src, size_t size); +size_t strlcpy(char *dst, const char *src, size_t size); +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t size); +char * strchr(const char *s, char c); +char * strfind(const char *s, char c); + +void * memset(void *dst, int c, size_t len); +/* no memcpy - use memmove instead */ +void * memmove(void *dst, const void *src, size_t len); +int memcmp(const void *s1, const void *s2, size_t len); +void * memfind(const void *s, int c, size_t len); + +long strtol(const char *s, char **endptr, int base); + +#endif /* not JOS_INC_STRING_H */ diff --git a/inc/types.h b/inc/types.h new file mode 100644 index 00000000..46271786 --- /dev/null +++ b/inc/types.h @@ -0,0 +1,72 @@ +#ifndef JOS_INC_TYPES_H +#define JOS_INC_TYPES_H + +#ifndef NULL +#define NULL ((void*) 0) +#endif + +// Represents true-or-false values +typedef int bool; + +// Explicitly-sized versions of integer types +typedef __signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; + +// Pointers and addresses are 32 bits long. +// We use pointer types to represent virtual addresses, +// uintptr_t to represent the numerical values of virtual addresses, +// and physaddr_t to represent physical addresses. +typedef int32_t intptr_t; +typedef uint32_t uintptr_t; +typedef uint32_t physaddr_t; + +// Page numbers are 32 bits long. +typedef uint32_t ppn_t; + +// size_t is used for memory object sizes. +typedef uint32_t size_t; +// ssize_t is a signed version of ssize_t, used in case there might be an +// error return. +typedef int32_t ssize_t; + +// off_t is used for file offsets and lengths. +typedef int32_t off_t; + +// Efficient min and max operations +#define MIN(_a, _b) \ +({ \ + typeof(_a) __a = (_a); \ + typeof(_b) __b = (_b); \ + __a <= __b ? __a : __b; \ +}) +#define MAX(_a, _b) \ +({ \ + typeof(_a) __a = (_a); \ + typeof(_b) __b = (_b); \ + __a >= __b ? __a : __b; \ +}) + +// Rounding operations (efficient when n is a power of 2) +// Round down to the nearest multiple of n +#define ROUNDDOWN(a, n) \ +({ \ + uint32_t __a = (uint32_t) (a); \ + (typeof(a)) (__a - __a % (n)); \ +}) +// Round up to the nearest multiple of n +#define ROUNDUP(a, n) \ +({ \ + uint32_t __n = (uint32_t) (n); \ + (typeof(a)) (ROUNDDOWN((uint32_t) (a) + __n - 1, __n)); \ +}) + +// Return the offset of 'member' relative to the beginning of a struct type +#define offsetof(type, member) ((size_t) (&((type*)0)->member)) + +#endif /* !JOS_INC_TYPES_H */ diff --git a/inc/x86.h b/inc/x86.h new file mode 100644 index 00000000..67ad5c98 --- /dev/null +++ b/inc/x86.h @@ -0,0 +1,277 @@ +#ifndef JOS_INC_X86_H +#define JOS_INC_X86_H + +#include + +static __inline void breakpoint(void) __attribute__((always_inline)); +static __inline uint8_t inb(int port) __attribute__((always_inline)); +static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline)); +static __inline uint16_t inw(int port) __attribute__((always_inline)); +static __inline void insw(int port, void *addr, int cnt) __attribute__((always_inline)); +static __inline uint32_t inl(int port) __attribute__((always_inline)); +static __inline void insl(int port, void *addr, int cnt) __attribute__((always_inline)); +static __inline void outb(int port, uint8_t data) __attribute__((always_inline)); +static __inline void outsb(int port, const void *addr, int cnt) __attribute__((always_inline)); +static __inline void outw(int port, uint16_t data) __attribute__((always_inline)); +static __inline void outsw(int port, const void *addr, int cnt) __attribute__((always_inline)); +static __inline void outsl(int port, const void *addr, int cnt) __attribute__((always_inline)); +static __inline void outl(int port, uint32_t data) __attribute__((always_inline)); +static __inline void invlpg(void *addr) __attribute__((always_inline)); +static __inline void lidt(void *p) __attribute__((always_inline)); +static __inline void lldt(uint16_t sel) __attribute__((always_inline)); +static __inline void ltr(uint16_t sel) __attribute__((always_inline)); +static __inline void lcr0(uint32_t val) __attribute__((always_inline)); +static __inline uint32_t rcr0(void) __attribute__((always_inline)); +static __inline uint32_t rcr2(void) __attribute__((always_inline)); +static __inline void lcr3(uint32_t val) __attribute__((always_inline)); +static __inline uint32_t rcr3(void) __attribute__((always_inline)); +static __inline void lcr4(uint32_t val) __attribute__((always_inline)); +static __inline uint32_t rcr4(void) __attribute__((always_inline)); +static __inline void tlbflush(void) __attribute__((always_inline)); +static __inline uint32_t read_eflags(void) __attribute__((always_inline)); +static __inline void write_eflags(uint32_t eflags) __attribute__((always_inline)); +static __inline uint32_t read_ebp(void) __attribute__((always_inline)); +static __inline uint32_t read_esp(void) __attribute__((always_inline)); +static __inline void cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp); +static __inline uint64_t read_tsc(void) __attribute__((always_inline)); + +static __inline void +breakpoint(void) +{ + __asm __volatile("int3"); +} + +static __inline uint8_t +inb(int port) +{ + uint8_t data; + __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static __inline void +insb(int port, void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\tinsb" : + "=D" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "memory", "cc"); +} + +static __inline uint16_t +inw(int port) +{ + uint16_t data; + __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static __inline void +insw(int port, void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\tinsw" : + "=D" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "memory", "cc"); +} + +static __inline uint32_t +inl(int port) +{ + uint32_t data; + __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static __inline void +insl(int port, void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\tinsl" : + "=D" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "memory", "cc"); +} + +static __inline void +outb(int port, uint8_t data) +{ + __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port)); +} + +static __inline void +outsb(int port, const void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\toutsb" : + "=S" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "cc"); +} + +static __inline void +outw(int port, uint16_t data) +{ + __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port)); +} + +static __inline void +outsw(int port, const void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\toutsw" : + "=S" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "cc"); +} + +static __inline void +outsl(int port, const void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\toutsl" : + "=S" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "cc"); +} + +static __inline void +outl(int port, uint32_t data) +{ + __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port)); +} + +static __inline void +invlpg(void *addr) +{ + __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory"); +} + +static __inline void +lidt(void *p) +{ + __asm __volatile("lidt (%0)" : : "r" (p)); +} + +static __inline void +lldt(uint16_t sel) +{ + __asm __volatile("lldt %0" : : "r" (sel)); +} + +static __inline void +ltr(uint16_t sel) +{ + __asm __volatile("ltr %0" : : "r" (sel)); +} + +static __inline void +lcr0(uint32_t val) +{ + __asm __volatile("movl %0,%%cr0" : : "r" (val)); +} + +static __inline uint32_t +rcr0(void) +{ + uint32_t val; + __asm __volatile("movl %%cr0,%0" : "=r" (val)); + return val; +} + +static __inline uint32_t +rcr2(void) +{ + uint32_t val; + __asm __volatile("movl %%cr2,%0" : "=r" (val)); + return val; +} + +static __inline void +lcr3(uint32_t val) +{ + __asm __volatile("movl %0,%%cr3" : : "r" (val)); +} + +static __inline uint32_t +rcr3(void) +{ + uint32_t val; + __asm __volatile("movl %%cr3,%0" : "=r" (val)); + return val; +} + +static __inline void +lcr4(uint32_t val) +{ + __asm __volatile("movl %0,%%cr4" : : "r" (val)); +} + +static __inline uint32_t +rcr4(void) +{ + uint32_t cr4; + __asm __volatile("movl %%cr4,%0" : "=r" (cr4)); + return cr4; +} + +static __inline void +tlbflush(void) +{ + uint32_t cr3; + __asm __volatile("movl %%cr3,%0" : "=r" (cr3)); + __asm __volatile("movl %0,%%cr3" : : "r" (cr3)); +} + +static __inline uint32_t +read_eflags(void) +{ + uint32_t eflags; + __asm __volatile("pushfl; popl %0" : "=r" (eflags)); + return eflags; +} + +static __inline void +write_eflags(uint32_t eflags) +{ + __asm __volatile("pushl %0; popfl" : : "r" (eflags)); +} + +static __inline uint32_t +read_ebp(void) +{ + uint32_t ebp; + __asm __volatile("movl %%ebp,%0" : "=r" (ebp)); + return ebp; +} + +static __inline uint32_t +read_esp(void) +{ + uint32_t esp; + __asm __volatile("movl %%esp,%0" : "=r" (esp)); + return esp; +} + +static __inline void +cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp) +{ + uint32_t eax, ebx, ecx, edx; + asm volatile("cpuid" + : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) + : "a" (info)); + if (eaxp) + *eaxp = eax; + if (ebxp) + *ebxp = ebx; + if (ecxp) + *ecxp = ecx; + if (edxp) + *edxp = edx; +} + +static __inline uint64_t +read_tsc(void) +{ + uint64_t tsc; + __asm __volatile("rdtsc" : "=A" (tsc)); + return tsc; +} + +#endif /* !JOS_INC_X86_H */ diff --git a/kern/COPYRIGHT b/kern/COPYRIGHT new file mode 100644 index 00000000..6a0270cb --- /dev/null +++ b/kern/COPYRIGHT @@ -0,0 +1,155 @@ +Most of the source files in this directory are derived from the Exokernel, +which is: + +/* + * Copyright (C) 1997 Massachusetts Institute of Technology + * + * This software is being provided by the copyright holders under the + * following license. By obtaining, using and/or copying this software, + * you agree that you have read, understood, and will comply with the + * following terms and conditions: + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose and without fee or royalty is + * hereby granted, provided that the full text of this NOTICE appears on + * ALL copies of the software and documentation or portions thereof, + * including modifications, that you make. + * + * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, + * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR + * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR + * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY + * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT + * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR + * DOCUMENTATION. + * + * The name and trademarks of copyright holders may NOT be used in + * advertising or publicity pertaining to the software without specific, + * written prior permission. Title to copyright in this software and any + * associated documentation will at all times remain with copyright + * holders. See the file AUTHORS which should have accompanied this software + * for a list of all copyright holders. + * + * This file may be derived from previously copyrighted software. This + * copyright applies only to those changes made by the copyright + * holders listed in the AUTHORS file. The rest of this file is covered by + * the copyright notices, if any, listed below. + */ + +Console.c was created consulting the NetBSD pccons driver which is: + +/*- + * Copyright (c) 1993, 1994, 1995 Charles Hannum. All rights reserved. + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz and Don Ahn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +Kclock.h, sched.h, and printf.h are copyright: + +/* + * Copyright (C) 1998 Exotec, Inc. + * + * This software is being provided by the copyright holders under the + * following license. By obtaining, using and/or copying this software, + * you agree that you have read, understood, and will comply with the + * following terms and conditions: + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose and without fee or royalty is + * hereby granted, provided that the full text of this NOTICE appears on + * ALL copies of the software and documentation or portions thereof, + * including modifications, that you make. + * + * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, + * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR + * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR + * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY + * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT + * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR + * DOCUMENTATION. + * + * The name and trademarks of copyright holders may NOT be used in + * advertising or publicity pertaining to the software without specific, + * written prior permission. Title to copyright in this software and any + * associated documentation will at all times remain with Exotec, Inc.. + * + * This file may be derived from previously copyrighted software. This + * copyright applies only to those changes made by Exotec, Inc. The rest + * of this file is covered by the copyright notices, if any, listed below. + */ + +Printf.c is copyright: + +/*- + * Copyright (c) 1986, 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 + */ + diff --git a/kern/Makefrag b/kern/Makefrag new file mode 100644 index 00000000..549ff6bb --- /dev/null +++ b/kern/Makefrag @@ -0,0 +1,83 @@ +# +# Makefile fragment for JOS kernel. +# This is NOT a complete makefile; +# you must run GNU make in the top-level directory +# where the GNUmakefile is located. +# + +OBJDIRS += kern + +KERN_LDFLAGS := $(LDFLAGS) -T kern/kernel.ld -nostdlib + +# entry.S must be first, so that it's the first code in the text segment!!! +# +# We also snatch the use of a couple handy source files +# from the lib directory, to avoid gratuitous code duplication. +KERN_SRCFILES := kern/entry.S \ + kern/entrypgdir.c \ + kern/init.c \ + kern/console.c \ + kern/monitor.c \ + kern/pmap.c \ + kern/env.c \ + kern/kclock.c \ + kern/picirq.c \ + kern/printf.c \ + kern/trap.c \ + kern/trapentry.S \ + kern/sched.c \ + kern/syscall.c \ + kern/kdebug.c \ + lib/printfmt.c \ + lib/readline.c \ + lib/string.c + +# Only build files if they exist. +KERN_SRCFILES := $(wildcard $(KERN_SRCFILES)) + +KERN_BINFILES := + +KERN_OBJFILES := $(patsubst %.c, $(OBJDIR)/%.o, $(KERN_SRCFILES)) +KERN_OBJFILES := $(patsubst %.S, $(OBJDIR)/%.o, $(KERN_OBJFILES)) +KERN_OBJFILES := $(patsubst $(OBJDIR)/lib/%, $(OBJDIR)/kern/%, $(KERN_OBJFILES)) + +KERN_BINFILES := $(patsubst %, $(OBJDIR)/%, $(KERN_BINFILES)) + +# How to build kernel object files +$(OBJDIR)/kern/%.o: kern/%.c + @echo + cc $< + @mkdir -p $(@D) + $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< + +$(OBJDIR)/kern/%.o: kern/%.S + @echo + as $< + @mkdir -p $(@D) + $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< + +$(OBJDIR)/kern/%.o: lib/%.c + @echo + cc $< + @mkdir -p $(@D) + $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< + +# How to build the kernel itself +$(OBJDIR)/kern/kernel: $(KERN_OBJFILES) $(KERN_BINFILES) kern/kernel.ld + @echo + ld $@ + $(V)$(LD) -o $@ $(KERN_LDFLAGS) $(KERN_OBJFILES) $(GCC_LIB) -b binary $(KERN_BINFILES) + $(V)$(OBJDUMP) -S $@ > $@.asm + $(V)$(NM) -n $@ > $@.sym + +# How to build the kernel disk image +$(OBJDIR)/kern/kernel.img: $(OBJDIR)/kern/kernel $(OBJDIR)/boot/boot + @echo + mk $@ + $(V)dd if=/dev/zero of=$(OBJDIR)/kern/kernel.img~ count=10000 2>/dev/null + $(V)dd if=$(OBJDIR)/boot/boot of=$(OBJDIR)/kern/kernel.img~ conv=notrunc 2>/dev/null + $(V)dd if=$(OBJDIR)/kern/kernel of=$(OBJDIR)/kern/kernel.img~ seek=1 conv=notrunc 2>/dev/null + $(V)mv $(OBJDIR)/kern/kernel.img~ $(OBJDIR)/kern/kernel.img + +all: $(OBJDIR)/kern/kernel.img + +grub: $(OBJDIR)/jos-grub + +$(OBJDIR)/jos-grub: $(OBJDIR)/kern/kernel + @echo + oc $@ + $(V)$(OBJCOPY) --adjust-vma=0x10000000 $^ $@ diff --git a/kern/console.c b/kern/console.c new file mode 100644 index 00000000..29e73df1 --- /dev/null +++ b/kern/console.c @@ -0,0 +1,472 @@ +/* See COPYRIGHT for copyright information. */ + +#include +#include +#include +#include +#include + +#include + +static void cons_intr(int (*proc)(void)); +static void cons_putc(int c); + +// Stupid I/O delay routine necessitated by historical PC design flaws +static void +delay(void) +{ + inb(0x84); + inb(0x84); + inb(0x84); + inb(0x84); +} + +/***** Serial I/O code *****/ + +#define COM1 0x3F8 + +#define COM_RX 0 // In: Receive buffer (DLAB=0) +#define COM_TX 0 // Out: Transmit buffer (DLAB=0) +#define COM_DLL 0 // Out: Divisor Latch Low (DLAB=1) +#define COM_DLM 1 // Out: Divisor Latch High (DLAB=1) +#define COM_IER 1 // Out: Interrupt Enable Register +#define COM_IER_RDI 0x01 // Enable receiver data interrupt +#define COM_IIR 2 // In: Interrupt ID Register +#define COM_FCR 2 // Out: FIFO Control Register +#define COM_LCR 3 // Out: Line Control Register +#define COM_LCR_DLAB 0x80 // Divisor latch access bit +#define COM_LCR_WLEN8 0x03 // Wordlength: 8 bits +#define COM_MCR 4 // Out: Modem Control Register +#define COM_MCR_RTS 0x02 // RTS complement +#define COM_MCR_DTR 0x01 // DTR complement +#define COM_MCR_OUT2 0x08 // Out2 complement +#define COM_LSR 5 // In: Line Status Register +#define COM_LSR_DATA 0x01 // Data available +#define COM_LSR_TXRDY 0x20 // Transmit buffer avail +#define COM_LSR_TSRE 0x40 // Transmitter off + +static bool serial_exists; + +static int +serial_proc_data(void) +{ + if (!(inb(COM1+COM_LSR) & COM_LSR_DATA)) + return -1; + return inb(COM1+COM_RX); +} + +void +serial_intr(void) +{ + if (serial_exists) + cons_intr(serial_proc_data); +} + +static void +serial_putc(int c) +{ + int i; + + for (i = 0; + !(inb(COM1 + COM_LSR) & COM_LSR_TXRDY) && i < 12800; + i++) + delay(); + + outb(COM1 + COM_TX, c); +} + +static void +serial_init(void) +{ + // Turn off the FIFO + outb(COM1+COM_FCR, 0); + + // Set speed; requires DLAB latch + outb(COM1+COM_LCR, COM_LCR_DLAB); + outb(COM1+COM_DLL, (uint8_t) (115200 / 9600)); + outb(COM1+COM_DLM, 0); + + // 8 data bits, 1 stop bit, parity off; turn off DLAB latch + outb(COM1+COM_LCR, COM_LCR_WLEN8 & ~COM_LCR_DLAB); + + // No modem controls + outb(COM1+COM_MCR, 0); + // Enable rcv interrupts + outb(COM1+COM_IER, COM_IER_RDI); + + // Clear any preexisting overrun indications and interrupts + // Serial port doesn't exist if COM_LSR returns 0xFF + serial_exists = (inb(COM1+COM_LSR) != 0xFF); + (void) inb(COM1+COM_IIR); + (void) inb(COM1+COM_RX); + +} + + + +/***** Parallel port output code *****/ +// For information on PC parallel port programming, see the class References +// page. + +static void +lpt_putc(int c) +{ + int i; + + for (i = 0; !(inb(0x378+1) & 0x80) && i < 12800; i++) + delay(); + outb(0x378+0, c); + outb(0x378+2, 0x08|0x04|0x01); + outb(0x378+2, 0x08); +} + + + + +/***** Text-mode CGA/VGA display output *****/ + +static unsigned addr_6845; +static uint16_t *crt_buf; +static uint16_t crt_pos; + +static void +cga_init(void) +{ + volatile uint16_t *cp; + uint16_t was; + unsigned pos; + + cp = (uint16_t*) (KERNBASE + CGA_BUF); + was = *cp; + *cp = (uint16_t) 0xA55A; + if (*cp != 0xA55A) { + cp = (uint16_t*) (KERNBASE + MONO_BUF); + addr_6845 = MONO_BASE; + } else { + *cp = was; + addr_6845 = CGA_BASE; + } + + /* Extract cursor location */ + outb(addr_6845, 14); + pos = inb(addr_6845 + 1) << 8; + outb(addr_6845, 15); + pos |= inb(addr_6845 + 1); + + crt_buf = (uint16_t*) cp; + crt_pos = pos; +} + + + +static void +cga_putc(int c) +{ + // if no attribute given, then use black on white + if (!(c & ~0xFF)) + c |= 0x0700; + + switch (c & 0xff) { + case '\b': + if (crt_pos > 0) { + crt_pos--; + crt_buf[crt_pos] = (c & ~0xff) | ' '; + } + break; + case '\n': + crt_pos += CRT_COLS; + /* fallthru */ + case '\r': + crt_pos -= (crt_pos % CRT_COLS); + break; + case '\t': + cons_putc(' '); + cons_putc(' '); + cons_putc(' '); + cons_putc(' '); + cons_putc(' '); + break; + default: + crt_buf[crt_pos++] = c; /* write the character */ + break; + } + + // What is the purpose of this? + if (crt_pos >= CRT_SIZE) { + int i; + + memmove(crt_buf, crt_buf + CRT_COLS, (CRT_SIZE - CRT_COLS) * sizeof(uint16_t)); + for (i = CRT_SIZE - CRT_COLS; i < CRT_SIZE; i++) + crt_buf[i] = 0x0700 | ' '; + crt_pos -= CRT_COLS; + } + + /* move that little blinky thing */ + outb(addr_6845, 14); + outb(addr_6845 + 1, crt_pos >> 8); + outb(addr_6845, 15); + outb(addr_6845 + 1, crt_pos); +} + + +/***** Keyboard input code *****/ + +#define NO 0 + +#define SHIFT (1<<0) +#define CTL (1<<1) +#define ALT (1<<2) + +#define CAPSLOCK (1<<3) +#define NUMLOCK (1<<4) +#define SCROLLLOCK (1<<5) + +#define E0ESC (1<<6) + +static uint8_t shiftcode[256] = +{ + [0x1D] = CTL, + [0x2A] = SHIFT, + [0x36] = SHIFT, + [0x38] = ALT, + [0x9D] = CTL, + [0xB8] = ALT +}; + +static uint8_t togglecode[256] = +{ + [0x3A] = CAPSLOCK, + [0x45] = NUMLOCK, + [0x46] = SCROLLLOCK +}; + +static uint8_t normalmap[256] = +{ + NO, 0x1B, '1', '2', '3', '4', '5', '6', // 0x00 + '7', '8', '9', '0', '-', '=', '\b', '\t', + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', // 0x10 + 'o', 'p', '[', ']', '\n', NO, 'a', 's', + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', // 0x20 + '\'', '`', NO, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', NO, '*', // 0x30 + NO, ' ', NO, NO, NO, NO, NO, NO, + NO, NO, NO, NO, NO, NO, NO, '7', // 0x40 + '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', NO, NO, NO, NO, // 0x50 + [0xC7] = KEY_HOME, [0x9C] = '\n' /*KP_Enter*/, + [0xB5] = '/' /*KP_Div*/, [0xC8] = KEY_UP, + [0xC9] = KEY_PGUP, [0xCB] = KEY_LF, + [0xCD] = KEY_RT, [0xCF] = KEY_END, + [0xD0] = KEY_DN, [0xD1] = KEY_PGDN, + [0xD2] = KEY_INS, [0xD3] = KEY_DEL +}; + +static uint8_t shiftmap[256] = +{ + NO, 033, '!', '@', '#', '$', '%', '^', // 0x00 + '&', '*', '(', ')', '_', '+', '\b', '\t', + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', // 0x10 + 'O', 'P', '{', '}', '\n', NO, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', // 0x20 + '"', '~', NO, '|', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', NO, '*', // 0x30 + NO, ' ', NO, NO, NO, NO, NO, NO, + NO, NO, NO, NO, NO, NO, NO, '7', // 0x40 + '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', NO, NO, NO, NO, // 0x50 + [0xC7] = KEY_HOME, [0x9C] = '\n' /*KP_Enter*/, + [0xB5] = '/' /*KP_Div*/, [0xC8] = KEY_UP, + [0xC9] = KEY_PGUP, [0xCB] = KEY_LF, + [0xCD] = KEY_RT, [0xCF] = KEY_END, + [0xD0] = KEY_DN, [0xD1] = KEY_PGDN, + [0xD2] = KEY_INS, [0xD3] = KEY_DEL +}; + +#define C(x) (x - '@') + +static uint8_t ctlmap[256] = +{ + NO, NO, NO, NO, NO, NO, NO, NO, + NO, NO, NO, NO, NO, NO, NO, NO, + C('Q'), C('W'), C('E'), C('R'), C('T'), C('Y'), C('U'), C('I'), + C('O'), C('P'), NO, NO, '\r', NO, C('A'), C('S'), + C('D'), C('F'), C('G'), C('H'), C('J'), C('K'), C('L'), NO, + NO, NO, NO, C('\\'), C('Z'), C('X'), C('C'), C('V'), + C('B'), C('N'), C('M'), NO, NO, C('/'), NO, NO, + [0x97] = KEY_HOME, + [0xB5] = C('/'), [0xC8] = KEY_UP, + [0xC9] = KEY_PGUP, [0xCB] = KEY_LF, + [0xCD] = KEY_RT, [0xCF] = KEY_END, + [0xD0] = KEY_DN, [0xD1] = KEY_PGDN, + [0xD2] = KEY_INS, [0xD3] = KEY_DEL +}; + +static uint8_t *charcode[4] = { + normalmap, + shiftmap, + ctlmap, + ctlmap +}; + +/* + * Get data from the keyboard. If we finish a character, return it. Else 0. + * Return -1 if no data. + */ +static int +kbd_proc_data(void) +{ + int c; + uint8_t data; + static uint32_t shift; + + if ((inb(KBSTATP) & KBS_DIB) == 0) + return -1; + + data = inb(KBDATAP); + + if (data == 0xE0) { + // E0 escape character + shift |= E0ESC; + return 0; + } else if (data & 0x80) { + // Key released + data = (shift & E0ESC ? data : data & 0x7F); + shift &= ~(shiftcode[data] | E0ESC); + return 0; + } else if (shift & E0ESC) { + // Last character was an E0 escape; or with 0x80 + data |= 0x80; + shift &= ~E0ESC; + } + + shift |= shiftcode[data]; + shift ^= togglecode[data]; + + c = charcode[shift & (CTL | SHIFT)][data]; + if (shift & CAPSLOCK) { + if ('a' <= c && c <= 'z') + c += 'A' - 'a'; + else if ('A' <= c && c <= 'Z') + c += 'a' - 'A'; + } + + // Process special keys + // Ctrl-Alt-Del: reboot + if (!(~shift & (CTL | ALT)) && c == KEY_DEL) { + cprintf("Rebooting!\n"); + outb(0x92, 0x3); // courtesy of Chris Frost + } + + return c; +} + +void +kbd_intr(void) +{ + cons_intr(kbd_proc_data); +} + +static void +kbd_init(void) +{ +} + + + +/***** General device-independent console code *****/ +// Here we manage the console input buffer, +// where we stash characters received from the keyboard or serial port +// whenever the corresponding interrupt occurs. + +#define CONSBUFSIZE 512 + +static struct { + uint8_t buf[CONSBUFSIZE]; + uint32_t rpos; + uint32_t wpos; +} cons; + +// called by device interrupt routines to feed input characters +// into the circular console input buffer. +static void +cons_intr(int (*proc)(void)) +{ + int c; + + while ((c = (*proc)()) != -1) { + if (c == 0) + continue; + cons.buf[cons.wpos++] = c; + if (cons.wpos == CONSBUFSIZE) + cons.wpos = 0; + } +} + +// return the next input character from the console, or 0 if none waiting +int +cons_getc(void) +{ + int c; + + // poll for any pending input characters, + // so that this function works even when interrupts are disabled + // (e.g., when called from the kernel monitor). + serial_intr(); + kbd_intr(); + + // grab the next character from the input buffer. + if (cons.rpos != cons.wpos) { + c = cons.buf[cons.rpos++]; + if (cons.rpos == CONSBUFSIZE) + cons.rpos = 0; + return c; + } + return 0; +} + +// output a character to the console +static void +cons_putc(int c) +{ + serial_putc(c); + lpt_putc(c); + cga_putc(c); +} + +// initialize the console devices +void +cons_init(void) +{ + cga_init(); + kbd_init(); + serial_init(); + + if (!serial_exists) + cprintf("Serial port does not exist!\n"); +} + + +// `High'-level console I/O. Used by readline and cprintf. + +void +cputchar(int c) +{ + cons_putc(c); +} + +int +getchar(void) +{ + int c; + + while ((c = cons_getc()) == 0) + /* do nothing */; + return c; +} + +int +iscons(int fdnum) +{ + // used by readline + return 1; +} diff --git a/kern/console.h b/kern/console.h new file mode 100644 index 00000000..36686264 --- /dev/null +++ b/kern/console.h @@ -0,0 +1,26 @@ +/* See COPYRIGHT for copyright information. */ + +#ifndef _CONSOLE_H_ +#define _CONSOLE_H_ +#ifndef JOS_KERNEL +# error "This is a JOS kernel header; user programs should not #include it" +#endif + +#include + +#define MONO_BASE 0x3B4 +#define MONO_BUF 0xB0000 +#define CGA_BASE 0x3D4 +#define CGA_BUF 0xB8000 + +#define CRT_ROWS 25 +#define CRT_COLS 80 +#define CRT_SIZE (CRT_ROWS * CRT_COLS) + +void cons_init(void); +int cons_getc(void); + +void kbd_intr(void); // irq 1 +void serial_intr(void); // irq 4 + +#endif /* _CONSOLE_H_ */ diff --git a/kern/entry.S b/kern/entry.S new file mode 100644 index 00000000..8e44f972 --- /dev/null +++ b/kern/entry.S @@ -0,0 +1,104 @@ +/* See COPYRIGHT for copyright information. */ + +#include +#include + +# Shift Right Logical +#define SRL(val, shamt) (((val) >> (shamt)) & ~(-1 << (32 - (shamt)))) + + +################################################################### +# The kernel (this code) is linked at address ~(KERNBASE + 1 Meg), +# but the bootloader loads it at address ~1 Meg. +# +# RELOC(x) maps a symbol x from its link address to its actual +# location in physical memory (its load address). +################################################################### + +#define RELOC(x) ((x) - KERNBASE) + +#define MULTIBOOT_HEADER_MAGIC (0x1BADB002) +#define MULTIBOOT_HEADER_FLAGS (0) +#define CHECKSUM (-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)) + +################################################################### +# entry point +################################################################### + +.text + +# The Multiboot header +.align 4 +.long MULTIBOOT_HEADER_MAGIC +.long MULTIBOOT_HEADER_FLAGS +.long CHECKSUM + +# '_start' specifies the ELF entry point. Since we haven't set up +# virtual memory when the bootloader enters this code, we need the +# bootloader to jump to the *physical* address of the entry point. +.globl _start +_start = RELOC(entry) + +.globl entry +entry: + movw $0x1234,0x472 # warm boot + + # We haven't set up virtual memory yet, so we're running from + # the physical address the boot loader loaded the kernel at: 1MB + # (plus a few bytes). However, the C code is linked to run at + # KERNBASE+1MB. Hence, we set up a trivial page directory that + # translates virtual addresses [KERNBASE, KERNBASE+4MB) to + # physical addresses [0, 4MB). This 4MB region will be suffice + # until we set up our real page table in i386_vm_init in lab 2. + + # Load the physical address of entry_pgdir into cr3. entry_pgdir + # is defined in entrypgdir.c. + movl $(RELOC(entry_pgdir)), %eax + movl %eax, %cr3 + # Turn on paging. + movl %cr0, %eax + orl $(CR0_PE|CR0_PG|CR0_WP), %eax + movl %eax, %cr0 + + # Now paging is enabled, but we're still running at a low EIP + # (why is this okay?). Jump up above KERNBASE before entering + # C code. + mov $relocated, %eax + jmp *%eax +relocated: + + # Clear the frame pointer register (EBP) + # so that once we get into debugging C code, + # stack backtraces will be terminated properly. + movl $0x0,%ebp # nuke frame pointer + + # Set the stack pointer + movl $(bootstacktop),%esp + + # now to C code + call i386_init + + # Should never get here, but in case we do, just spin. +spin: jmp spin + + +################################################################### +# See for a complete description of these two symbols. +################################################################### +.data + .globl vpt + .set vpt, VPT + .globl vpd + .set vpd, (VPT + SRL(VPT, 10)) + + +################################################################### +# boot stack +################################################################### + .p2align PGSHIFT # force page alignment + .globl bootstack +bootstack: + .space KSTKSIZE + .globl bootstacktop +bootstacktop: + diff --git a/kern/entrypgdir.c b/kern/entrypgdir.c new file mode 100644 index 00000000..4f324d16 --- /dev/null +++ b/kern/entrypgdir.c @@ -0,0 +1,1059 @@ +#include +#include + +pte_t entry_pgtable[NPTENTRIES]; + +// The entry.S page directory maps the first 4MB of physical memory +// starting at virtual address KERNBASE (that is, it maps virtual +// addresses [KERNBASE, KERNBASE+4MB) to physical addresses [0, 4MB)). +// We choose 4MB because that's how much we can map with one page +// table and it's enough to get us through early boot. We also map +// virtual addresses [0, 4MB) to physical addresses [0, 4MB); this +// region is critical for a few instructions in entry.S and then we +// never use it again. +// +// Page directories (and page tables), must start on a page boundary, +// hence the "__aligned__" attribute. Also, because of restrictions +// related to linking and static initializers, we use "x + PTE_P" +// here, rather than the more standard "x | PTE_P". Everywhere else +// you should use "|" to combine flags. +__attribute__((__aligned__(PGSIZE))) +pde_t entry_pgdir[NPDENTRIES] = { + // Map VA's [0, 4MB) to PA's [0, 4MB) + [0] + = ((uintptr_t)entry_pgtable - KERNBASE) + PTE_P, + // Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB) + [KERNBASE>>PDXSHIFT] + = ((uintptr_t)entry_pgtable - KERNBASE) + PTE_P + PTE_W +}; + +// Entry 0 of the page table maps to physical page 0, entry 1 to +// physical page 1, etc. +__attribute__((__aligned__(PGSIZE))) +pte_t entry_pgtable[NPTENTRIES] = { + 0x000000 | PTE_P | PTE_W, + 0x001000 | PTE_P | PTE_W, + 0x002000 | PTE_P | PTE_W, + 0x003000 | PTE_P | PTE_W, + 0x004000 | PTE_P | PTE_W, + 0x005000 | PTE_P | PTE_W, + 0x006000 | PTE_P | PTE_W, + 0x007000 | PTE_P | PTE_W, + 0x008000 | PTE_P | PTE_W, + 0x009000 | PTE_P | PTE_W, + 0x00a000 | PTE_P | PTE_W, + 0x00b000 | PTE_P | PTE_W, + 0x00c000 | PTE_P | PTE_W, + 0x00d000 | PTE_P | PTE_W, + 0x00e000 | PTE_P | PTE_W, + 0x00f000 | PTE_P | PTE_W, + 0x010000 | PTE_P | PTE_W, + 0x011000 | PTE_P | PTE_W, + 0x012000 | PTE_P | PTE_W, + 0x013000 | PTE_P | PTE_W, + 0x014000 | PTE_P | PTE_W, + 0x015000 | PTE_P | PTE_W, + 0x016000 | PTE_P | PTE_W, + 0x017000 | PTE_P | PTE_W, + 0x018000 | PTE_P | PTE_W, + 0x019000 | PTE_P | PTE_W, + 0x01a000 | PTE_P | PTE_W, + 0x01b000 | PTE_P | PTE_W, + 0x01c000 | PTE_P | PTE_W, + 0x01d000 | PTE_P | PTE_W, + 0x01e000 | PTE_P | PTE_W, + 0x01f000 | PTE_P | PTE_W, + 0x020000 | PTE_P | PTE_W, + 0x021000 | PTE_P | PTE_W, + 0x022000 | PTE_P | PTE_W, + 0x023000 | PTE_P | PTE_W, + 0x024000 | PTE_P | PTE_W, + 0x025000 | PTE_P | PTE_W, + 0x026000 | PTE_P | PTE_W, + 0x027000 | PTE_P | PTE_W, + 0x028000 | PTE_P | PTE_W, + 0x029000 | PTE_P | PTE_W, + 0x02a000 | PTE_P | PTE_W, + 0x02b000 | PTE_P | PTE_W, + 0x02c000 | PTE_P | PTE_W, + 0x02d000 | PTE_P | PTE_W, + 0x02e000 | PTE_P | PTE_W, + 0x02f000 | PTE_P | PTE_W, + 0x030000 | PTE_P | PTE_W, + 0x031000 | PTE_P | PTE_W, + 0x032000 | PTE_P | PTE_W, + 0x033000 | PTE_P | PTE_W, + 0x034000 | PTE_P | PTE_W, + 0x035000 | PTE_P | PTE_W, + 0x036000 | PTE_P | PTE_W, + 0x037000 | PTE_P | PTE_W, + 0x038000 | PTE_P | PTE_W, + 0x039000 | PTE_P | PTE_W, + 0x03a000 | PTE_P | PTE_W, + 0x03b000 | PTE_P | PTE_W, + 0x03c000 | PTE_P | PTE_W, + 0x03d000 | PTE_P | PTE_W, + 0x03e000 | PTE_P | PTE_W, + 0x03f000 | PTE_P | PTE_W, + 0x040000 | PTE_P | PTE_W, + 0x041000 | PTE_P | PTE_W, + 0x042000 | PTE_P | PTE_W, + 0x043000 | PTE_P | PTE_W, + 0x044000 | PTE_P | PTE_W, + 0x045000 | PTE_P | PTE_W, + 0x046000 | PTE_P | PTE_W, + 0x047000 | PTE_P | PTE_W, + 0x048000 | PTE_P | PTE_W, + 0x049000 | PTE_P | PTE_W, + 0x04a000 | PTE_P | PTE_W, + 0x04b000 | PTE_P | PTE_W, + 0x04c000 | PTE_P | PTE_W, + 0x04d000 | PTE_P | PTE_W, + 0x04e000 | PTE_P | PTE_W, + 0x04f000 | PTE_P | PTE_W, + 0x050000 | PTE_P | PTE_W, + 0x051000 | PTE_P | PTE_W, + 0x052000 | PTE_P | PTE_W, + 0x053000 | PTE_P | PTE_W, + 0x054000 | PTE_P | PTE_W, + 0x055000 | PTE_P | PTE_W, + 0x056000 | PTE_P | PTE_W, + 0x057000 | PTE_P | PTE_W, + 0x058000 | PTE_P | PTE_W, + 0x059000 | PTE_P | PTE_W, + 0x05a000 | PTE_P | PTE_W, + 0x05b000 | PTE_P | PTE_W, + 0x05c000 | PTE_P | PTE_W, + 0x05d000 | PTE_P | PTE_W, + 0x05e000 | PTE_P | PTE_W, + 0x05f000 | PTE_P | PTE_W, + 0x060000 | PTE_P | PTE_W, + 0x061000 | PTE_P | PTE_W, + 0x062000 | PTE_P | PTE_W, + 0x063000 | PTE_P | PTE_W, + 0x064000 | PTE_P | PTE_W, + 0x065000 | PTE_P | PTE_W, + 0x066000 | PTE_P | PTE_W, + 0x067000 | PTE_P | PTE_W, + 0x068000 | PTE_P | PTE_W, + 0x069000 | PTE_P | PTE_W, + 0x06a000 | PTE_P | PTE_W, + 0x06b000 | PTE_P | PTE_W, + 0x06c000 | PTE_P | PTE_W, + 0x06d000 | PTE_P | PTE_W, + 0x06e000 | PTE_P | PTE_W, + 0x06f000 | PTE_P | PTE_W, + 0x070000 | PTE_P | PTE_W, + 0x071000 | PTE_P | PTE_W, + 0x072000 | PTE_P | PTE_W, + 0x073000 | PTE_P | PTE_W, + 0x074000 | PTE_P | PTE_W, + 0x075000 | PTE_P | PTE_W, + 0x076000 | PTE_P | PTE_W, + 0x077000 | PTE_P | PTE_W, + 0x078000 | PTE_P | PTE_W, + 0x079000 | PTE_P | PTE_W, + 0x07a000 | PTE_P | PTE_W, + 0x07b000 | PTE_P | PTE_W, + 0x07c000 | PTE_P | PTE_W, + 0x07d000 | PTE_P | PTE_W, + 0x07e000 | PTE_P | PTE_W, + 0x07f000 | PTE_P | PTE_W, + 0x080000 | PTE_P | PTE_W, + 0x081000 | PTE_P | PTE_W, + 0x082000 | PTE_P | PTE_W, + 0x083000 | PTE_P | PTE_W, + 0x084000 | PTE_P | PTE_W, + 0x085000 | PTE_P | PTE_W, + 0x086000 | PTE_P | PTE_W, + 0x087000 | PTE_P | PTE_W, + 0x088000 | PTE_P | PTE_W, + 0x089000 | PTE_P | PTE_W, + 0x08a000 | PTE_P | PTE_W, + 0x08b000 | PTE_P | PTE_W, + 0x08c000 | PTE_P | PTE_W, + 0x08d000 | PTE_P | PTE_W, + 0x08e000 | PTE_P | PTE_W, + 0x08f000 | PTE_P | PTE_W, + 0x090000 | PTE_P | PTE_W, + 0x091000 | PTE_P | PTE_W, + 0x092000 | PTE_P | PTE_W, + 0x093000 | PTE_P | PTE_W, + 0x094000 | PTE_P | PTE_W, + 0x095000 | PTE_P | PTE_W, + 0x096000 | PTE_P | PTE_W, + 0x097000 | PTE_P | PTE_W, + 0x098000 | PTE_P | PTE_W, + 0x099000 | PTE_P | PTE_W, + 0x09a000 | PTE_P | PTE_W, + 0x09b000 | PTE_P | PTE_W, + 0x09c000 | PTE_P | PTE_W, + 0x09d000 | PTE_P | PTE_W, + 0x09e000 | PTE_P | PTE_W, + 0x09f000 | PTE_P | PTE_W, + 0x0a0000 | PTE_P | PTE_W, + 0x0a1000 | PTE_P | PTE_W, + 0x0a2000 | PTE_P | PTE_W, + 0x0a3000 | PTE_P | PTE_W, + 0x0a4000 | PTE_P | PTE_W, + 0x0a5000 | PTE_P | PTE_W, + 0x0a6000 | PTE_P | PTE_W, + 0x0a7000 | PTE_P | PTE_W, + 0x0a8000 | PTE_P | PTE_W, + 0x0a9000 | PTE_P | PTE_W, + 0x0aa000 | PTE_P | PTE_W, + 0x0ab000 | PTE_P | PTE_W, + 0x0ac000 | PTE_P | PTE_W, + 0x0ad000 | PTE_P | PTE_W, + 0x0ae000 | PTE_P | PTE_W, + 0x0af000 | PTE_P | PTE_W, + 0x0b0000 | PTE_P | PTE_W, + 0x0b1000 | PTE_P | PTE_W, + 0x0b2000 | PTE_P | PTE_W, + 0x0b3000 | PTE_P | PTE_W, + 0x0b4000 | PTE_P | PTE_W, + 0x0b5000 | PTE_P | PTE_W, + 0x0b6000 | PTE_P | PTE_W, + 0x0b7000 | PTE_P | PTE_W, + 0x0b8000 | PTE_P | PTE_W, + 0x0b9000 | PTE_P | PTE_W, + 0x0ba000 | PTE_P | PTE_W, + 0x0bb000 | PTE_P | PTE_W, + 0x0bc000 | PTE_P | PTE_W, + 0x0bd000 | PTE_P | PTE_W, + 0x0be000 | PTE_P | PTE_W, + 0x0bf000 | PTE_P | PTE_W, + 0x0c0000 | PTE_P | PTE_W, + 0x0c1000 | PTE_P | PTE_W, + 0x0c2000 | PTE_P | PTE_W, + 0x0c3000 | PTE_P | PTE_W, + 0x0c4000 | PTE_P | PTE_W, + 0x0c5000 | PTE_P | PTE_W, + 0x0c6000 | PTE_P | PTE_W, + 0x0c7000 | PTE_P | PTE_W, + 0x0c8000 | PTE_P | PTE_W, + 0x0c9000 | PTE_P | PTE_W, + 0x0ca000 | PTE_P | PTE_W, + 0x0cb000 | PTE_P | PTE_W, + 0x0cc000 | PTE_P | PTE_W, + 0x0cd000 | PTE_P | PTE_W, + 0x0ce000 | PTE_P | PTE_W, + 0x0cf000 | PTE_P | PTE_W, + 0x0d0000 | PTE_P | PTE_W, + 0x0d1000 | PTE_P | PTE_W, + 0x0d2000 | PTE_P | PTE_W, + 0x0d3000 | PTE_P | PTE_W, + 0x0d4000 | PTE_P | PTE_W, + 0x0d5000 | PTE_P | PTE_W, + 0x0d6000 | PTE_P | PTE_W, + 0x0d7000 | PTE_P | PTE_W, + 0x0d8000 | PTE_P | PTE_W, + 0x0d9000 | PTE_P | PTE_W, + 0x0da000 | PTE_P | PTE_W, + 0x0db000 | PTE_P | PTE_W, + 0x0dc000 | PTE_P | PTE_W, + 0x0dd000 | PTE_P | PTE_W, + 0x0de000 | PTE_P | PTE_W, + 0x0df000 | PTE_P | PTE_W, + 0x0e0000 | PTE_P | PTE_W, + 0x0e1000 | PTE_P | PTE_W, + 0x0e2000 | PTE_P | PTE_W, + 0x0e3000 | PTE_P | PTE_W, + 0x0e4000 | PTE_P | PTE_W, + 0x0e5000 | PTE_P | PTE_W, + 0x0e6000 | PTE_P | PTE_W, + 0x0e7000 | PTE_P | PTE_W, + 0x0e8000 | PTE_P | PTE_W, + 0x0e9000 | PTE_P | PTE_W, + 0x0ea000 | PTE_P | PTE_W, + 0x0eb000 | PTE_P | PTE_W, + 0x0ec000 | PTE_P | PTE_W, + 0x0ed000 | PTE_P | PTE_W, + 0x0ee000 | PTE_P | PTE_W, + 0x0ef000 | PTE_P | PTE_W, + 0x0f0000 | PTE_P | PTE_W, + 0x0f1000 | PTE_P | PTE_W, + 0x0f2000 | PTE_P | PTE_W, + 0x0f3000 | PTE_P | PTE_W, + 0x0f4000 | PTE_P | PTE_W, + 0x0f5000 | PTE_P | PTE_W, + 0x0f6000 | PTE_P | PTE_W, + 0x0f7000 | PTE_P | PTE_W, + 0x0f8000 | PTE_P | PTE_W, + 0x0f9000 | PTE_P | PTE_W, + 0x0fa000 | PTE_P | PTE_W, + 0x0fb000 | PTE_P | PTE_W, + 0x0fc000 | PTE_P | PTE_W, + 0x0fd000 | PTE_P | PTE_W, + 0x0fe000 | PTE_P | PTE_W, + 0x0ff000 | PTE_P | PTE_W, + 0x100000 | PTE_P | PTE_W, + 0x101000 | PTE_P | PTE_W, + 0x102000 | PTE_P | PTE_W, + 0x103000 | PTE_P | PTE_W, + 0x104000 | PTE_P | PTE_W, + 0x105000 | PTE_P | PTE_W, + 0x106000 | PTE_P | PTE_W, + 0x107000 | PTE_P | PTE_W, + 0x108000 | PTE_P | PTE_W, + 0x109000 | PTE_P | PTE_W, + 0x10a000 | PTE_P | PTE_W, + 0x10b000 | PTE_P | PTE_W, + 0x10c000 | PTE_P | PTE_W, + 0x10d000 | PTE_P | PTE_W, + 0x10e000 | PTE_P | PTE_W, + 0x10f000 | PTE_P | PTE_W, + 0x110000 | PTE_P | PTE_W, + 0x111000 | PTE_P | PTE_W, + 0x112000 | PTE_P | PTE_W, + 0x113000 | PTE_P | PTE_W, + 0x114000 | PTE_P | PTE_W, + 0x115000 | PTE_P | PTE_W, + 0x116000 | PTE_P | PTE_W, + 0x117000 | PTE_P | PTE_W, + 0x118000 | PTE_P | PTE_W, + 0x119000 | PTE_P | PTE_W, + 0x11a000 | PTE_P | PTE_W, + 0x11b000 | PTE_P | PTE_W, + 0x11c000 | PTE_P | PTE_W, + 0x11d000 | PTE_P | PTE_W, + 0x11e000 | PTE_P | PTE_W, + 0x11f000 | PTE_P | PTE_W, + 0x120000 | PTE_P | PTE_W, + 0x121000 | PTE_P | PTE_W, + 0x122000 | PTE_P | PTE_W, + 0x123000 | PTE_P | PTE_W, + 0x124000 | PTE_P | PTE_W, + 0x125000 | PTE_P | PTE_W, + 0x126000 | PTE_P | PTE_W, + 0x127000 | PTE_P | PTE_W, + 0x128000 | PTE_P | PTE_W, + 0x129000 | PTE_P | PTE_W, + 0x12a000 | PTE_P | PTE_W, + 0x12b000 | PTE_P | PTE_W, + 0x12c000 | PTE_P | PTE_W, + 0x12d000 | PTE_P | PTE_W, + 0x12e000 | PTE_P | PTE_W, + 0x12f000 | PTE_P | PTE_W, + 0x130000 | PTE_P | PTE_W, + 0x131000 | PTE_P | PTE_W, + 0x132000 | PTE_P | PTE_W, + 0x133000 | PTE_P | PTE_W, + 0x134000 | PTE_P | PTE_W, + 0x135000 | PTE_P | PTE_W, + 0x136000 | PTE_P | PTE_W, + 0x137000 | PTE_P | PTE_W, + 0x138000 | PTE_P | PTE_W, + 0x139000 | PTE_P | PTE_W, + 0x13a000 | PTE_P | PTE_W, + 0x13b000 | PTE_P | PTE_W, + 0x13c000 | PTE_P | PTE_W, + 0x13d000 | PTE_P | PTE_W, + 0x13e000 | PTE_P | PTE_W, + 0x13f000 | PTE_P | PTE_W, + 0x140000 | PTE_P | PTE_W, + 0x141000 | PTE_P | PTE_W, + 0x142000 | PTE_P | PTE_W, + 0x143000 | PTE_P | PTE_W, + 0x144000 | PTE_P | PTE_W, + 0x145000 | PTE_P | PTE_W, + 0x146000 | PTE_P | PTE_W, + 0x147000 | PTE_P | PTE_W, + 0x148000 | PTE_P | PTE_W, + 0x149000 | PTE_P | PTE_W, + 0x14a000 | PTE_P | PTE_W, + 0x14b000 | PTE_P | PTE_W, + 0x14c000 | PTE_P | PTE_W, + 0x14d000 | PTE_P | PTE_W, + 0x14e000 | PTE_P | PTE_W, + 0x14f000 | PTE_P | PTE_W, + 0x150000 | PTE_P | PTE_W, + 0x151000 | PTE_P | PTE_W, + 0x152000 | PTE_P | PTE_W, + 0x153000 | PTE_P | PTE_W, + 0x154000 | PTE_P | PTE_W, + 0x155000 | PTE_P | PTE_W, + 0x156000 | PTE_P | PTE_W, + 0x157000 | PTE_P | PTE_W, + 0x158000 | PTE_P | PTE_W, + 0x159000 | PTE_P | PTE_W, + 0x15a000 | PTE_P | PTE_W, + 0x15b000 | PTE_P | PTE_W, + 0x15c000 | PTE_P | PTE_W, + 0x15d000 | PTE_P | PTE_W, + 0x15e000 | PTE_P | PTE_W, + 0x15f000 | PTE_P | PTE_W, + 0x160000 | PTE_P | PTE_W, + 0x161000 | PTE_P | PTE_W, + 0x162000 | PTE_P | PTE_W, + 0x163000 | PTE_P | PTE_W, + 0x164000 | PTE_P | PTE_W, + 0x165000 | PTE_P | PTE_W, + 0x166000 | PTE_P | PTE_W, + 0x167000 | PTE_P | PTE_W, + 0x168000 | PTE_P | PTE_W, + 0x169000 | PTE_P | PTE_W, + 0x16a000 | PTE_P | PTE_W, + 0x16b000 | PTE_P | PTE_W, + 0x16c000 | PTE_P | PTE_W, + 0x16d000 | PTE_P | PTE_W, + 0x16e000 | PTE_P | PTE_W, + 0x16f000 | PTE_P | PTE_W, + 0x170000 | PTE_P | PTE_W, + 0x171000 | PTE_P | PTE_W, + 0x172000 | PTE_P | PTE_W, + 0x173000 | PTE_P | PTE_W, + 0x174000 | PTE_P | PTE_W, + 0x175000 | PTE_P | PTE_W, + 0x176000 | PTE_P | PTE_W, + 0x177000 | PTE_P | PTE_W, + 0x178000 | PTE_P | PTE_W, + 0x179000 | PTE_P | PTE_W, + 0x17a000 | PTE_P | PTE_W, + 0x17b000 | PTE_P | PTE_W, + 0x17c000 | PTE_P | PTE_W, + 0x17d000 | PTE_P | PTE_W, + 0x17e000 | PTE_P | PTE_W, + 0x17f000 | PTE_P | PTE_W, + 0x180000 | PTE_P | PTE_W, + 0x181000 | PTE_P | PTE_W, + 0x182000 | PTE_P | PTE_W, + 0x183000 | PTE_P | PTE_W, + 0x184000 | PTE_P | PTE_W, + 0x185000 | PTE_P | PTE_W, + 0x186000 | PTE_P | PTE_W, + 0x187000 | PTE_P | PTE_W, + 0x188000 | PTE_P | PTE_W, + 0x189000 | PTE_P | PTE_W, + 0x18a000 | PTE_P | PTE_W, + 0x18b000 | PTE_P | PTE_W, + 0x18c000 | PTE_P | PTE_W, + 0x18d000 | PTE_P | PTE_W, + 0x18e000 | PTE_P | PTE_W, + 0x18f000 | PTE_P | PTE_W, + 0x190000 | PTE_P | PTE_W, + 0x191000 | PTE_P | PTE_W, + 0x192000 | PTE_P | PTE_W, + 0x193000 | PTE_P | PTE_W, + 0x194000 | PTE_P | PTE_W, + 0x195000 | PTE_P | PTE_W, + 0x196000 | PTE_P | PTE_W, + 0x197000 | PTE_P | PTE_W, + 0x198000 | PTE_P | PTE_W, + 0x199000 | PTE_P | PTE_W, + 0x19a000 | PTE_P | PTE_W, + 0x19b000 | PTE_P | PTE_W, + 0x19c000 | PTE_P | PTE_W, + 0x19d000 | PTE_P | PTE_W, + 0x19e000 | PTE_P | PTE_W, + 0x19f000 | PTE_P | PTE_W, + 0x1a0000 | PTE_P | PTE_W, + 0x1a1000 | PTE_P | PTE_W, + 0x1a2000 | PTE_P | PTE_W, + 0x1a3000 | PTE_P | PTE_W, + 0x1a4000 | PTE_P | PTE_W, + 0x1a5000 | PTE_P | PTE_W, + 0x1a6000 | PTE_P | PTE_W, + 0x1a7000 | PTE_P | PTE_W, + 0x1a8000 | PTE_P | PTE_W, + 0x1a9000 | PTE_P | PTE_W, + 0x1aa000 | PTE_P | PTE_W, + 0x1ab000 | PTE_P | PTE_W, + 0x1ac000 | PTE_P | PTE_W, + 0x1ad000 | PTE_P | PTE_W, + 0x1ae000 | PTE_P | PTE_W, + 0x1af000 | PTE_P | PTE_W, + 0x1b0000 | PTE_P | PTE_W, + 0x1b1000 | PTE_P | PTE_W, + 0x1b2000 | PTE_P | PTE_W, + 0x1b3000 | PTE_P | PTE_W, + 0x1b4000 | PTE_P | PTE_W, + 0x1b5000 | PTE_P | PTE_W, + 0x1b6000 | PTE_P | PTE_W, + 0x1b7000 | PTE_P | PTE_W, + 0x1b8000 | PTE_P | PTE_W, + 0x1b9000 | PTE_P | PTE_W, + 0x1ba000 | PTE_P | PTE_W, + 0x1bb000 | PTE_P | PTE_W, + 0x1bc000 | PTE_P | PTE_W, + 0x1bd000 | PTE_P | PTE_W, + 0x1be000 | PTE_P | PTE_W, + 0x1bf000 | PTE_P | PTE_W, + 0x1c0000 | PTE_P | PTE_W, + 0x1c1000 | PTE_P | PTE_W, + 0x1c2000 | PTE_P | PTE_W, + 0x1c3000 | PTE_P | PTE_W, + 0x1c4000 | PTE_P | PTE_W, + 0x1c5000 | PTE_P | PTE_W, + 0x1c6000 | PTE_P | PTE_W, + 0x1c7000 | PTE_P | PTE_W, + 0x1c8000 | PTE_P | PTE_W, + 0x1c9000 | PTE_P | PTE_W, + 0x1ca000 | PTE_P | PTE_W, + 0x1cb000 | PTE_P | PTE_W, + 0x1cc000 | PTE_P | PTE_W, + 0x1cd000 | PTE_P | PTE_W, + 0x1ce000 | PTE_P | PTE_W, + 0x1cf000 | PTE_P | PTE_W, + 0x1d0000 | PTE_P | PTE_W, + 0x1d1000 | PTE_P | PTE_W, + 0x1d2000 | PTE_P | PTE_W, + 0x1d3000 | PTE_P | PTE_W, + 0x1d4000 | PTE_P | PTE_W, + 0x1d5000 | PTE_P | PTE_W, + 0x1d6000 | PTE_P | PTE_W, + 0x1d7000 | PTE_P | PTE_W, + 0x1d8000 | PTE_P | PTE_W, + 0x1d9000 | PTE_P | PTE_W, + 0x1da000 | PTE_P | PTE_W, + 0x1db000 | PTE_P | PTE_W, + 0x1dc000 | PTE_P | PTE_W, + 0x1dd000 | PTE_P | PTE_W, + 0x1de000 | PTE_P | PTE_W, + 0x1df000 | PTE_P | PTE_W, + 0x1e0000 | PTE_P | PTE_W, + 0x1e1000 | PTE_P | PTE_W, + 0x1e2000 | PTE_P | PTE_W, + 0x1e3000 | PTE_P | PTE_W, + 0x1e4000 | PTE_P | PTE_W, + 0x1e5000 | PTE_P | PTE_W, + 0x1e6000 | PTE_P | PTE_W, + 0x1e7000 | PTE_P | PTE_W, + 0x1e8000 | PTE_P | PTE_W, + 0x1e9000 | PTE_P | PTE_W, + 0x1ea000 | PTE_P | PTE_W, + 0x1eb000 | PTE_P | PTE_W, + 0x1ec000 | PTE_P | PTE_W, + 0x1ed000 | PTE_P | PTE_W, + 0x1ee000 | PTE_P | PTE_W, + 0x1ef000 | PTE_P | PTE_W, + 0x1f0000 | PTE_P | PTE_W, + 0x1f1000 | PTE_P | PTE_W, + 0x1f2000 | PTE_P | PTE_W, + 0x1f3000 | PTE_P | PTE_W, + 0x1f4000 | PTE_P | PTE_W, + 0x1f5000 | PTE_P | PTE_W, + 0x1f6000 | PTE_P | PTE_W, + 0x1f7000 | PTE_P | PTE_W, + 0x1f8000 | PTE_P | PTE_W, + 0x1f9000 | PTE_P | PTE_W, + 0x1fa000 | PTE_P | PTE_W, + 0x1fb000 | PTE_P | PTE_W, + 0x1fc000 | PTE_P | PTE_W, + 0x1fd000 | PTE_P | PTE_W, + 0x1fe000 | PTE_P | PTE_W, + 0x1ff000 | PTE_P | PTE_W, + 0x200000 | PTE_P | PTE_W, + 0x201000 | PTE_P | PTE_W, + 0x202000 | PTE_P | PTE_W, + 0x203000 | PTE_P | PTE_W, + 0x204000 | PTE_P | PTE_W, + 0x205000 | PTE_P | PTE_W, + 0x206000 | PTE_P | PTE_W, + 0x207000 | PTE_P | PTE_W, + 0x208000 | PTE_P | PTE_W, + 0x209000 | PTE_P | PTE_W, + 0x20a000 | PTE_P | PTE_W, + 0x20b000 | PTE_P | PTE_W, + 0x20c000 | PTE_P | PTE_W, + 0x20d000 | PTE_P | PTE_W, + 0x20e000 | PTE_P | PTE_W, + 0x20f000 | PTE_P | PTE_W, + 0x210000 | PTE_P | PTE_W, + 0x211000 | PTE_P | PTE_W, + 0x212000 | PTE_P | PTE_W, + 0x213000 | PTE_P | PTE_W, + 0x214000 | PTE_P | PTE_W, + 0x215000 | PTE_P | PTE_W, + 0x216000 | PTE_P | PTE_W, + 0x217000 | PTE_P | PTE_W, + 0x218000 | PTE_P | PTE_W, + 0x219000 | PTE_P | PTE_W, + 0x21a000 | PTE_P | PTE_W, + 0x21b000 | PTE_P | PTE_W, + 0x21c000 | PTE_P | PTE_W, + 0x21d000 | PTE_P | PTE_W, + 0x21e000 | PTE_P | PTE_W, + 0x21f000 | PTE_P | PTE_W, + 0x220000 | PTE_P | PTE_W, + 0x221000 | PTE_P | PTE_W, + 0x222000 | PTE_P | PTE_W, + 0x223000 | PTE_P | PTE_W, + 0x224000 | PTE_P | PTE_W, + 0x225000 | PTE_P | PTE_W, + 0x226000 | PTE_P | PTE_W, + 0x227000 | PTE_P | PTE_W, + 0x228000 | PTE_P | PTE_W, + 0x229000 | PTE_P | PTE_W, + 0x22a000 | PTE_P | PTE_W, + 0x22b000 | PTE_P | PTE_W, + 0x22c000 | PTE_P | PTE_W, + 0x22d000 | PTE_P | PTE_W, + 0x22e000 | PTE_P | PTE_W, + 0x22f000 | PTE_P | PTE_W, + 0x230000 | PTE_P | PTE_W, + 0x231000 | PTE_P | PTE_W, + 0x232000 | PTE_P | PTE_W, + 0x233000 | PTE_P | PTE_W, + 0x234000 | PTE_P | PTE_W, + 0x235000 | PTE_P | PTE_W, + 0x236000 | PTE_P | PTE_W, + 0x237000 | PTE_P | PTE_W, + 0x238000 | PTE_P | PTE_W, + 0x239000 | PTE_P | PTE_W, + 0x23a000 | PTE_P | PTE_W, + 0x23b000 | PTE_P | PTE_W, + 0x23c000 | PTE_P | PTE_W, + 0x23d000 | PTE_P | PTE_W, + 0x23e000 | PTE_P | PTE_W, + 0x23f000 | PTE_P | PTE_W, + 0x240000 | PTE_P | PTE_W, + 0x241000 | PTE_P | PTE_W, + 0x242000 | PTE_P | PTE_W, + 0x243000 | PTE_P | PTE_W, + 0x244000 | PTE_P | PTE_W, + 0x245000 | PTE_P | PTE_W, + 0x246000 | PTE_P | PTE_W, + 0x247000 | PTE_P | PTE_W, + 0x248000 | PTE_P | PTE_W, + 0x249000 | PTE_P | PTE_W, + 0x24a000 | PTE_P | PTE_W, + 0x24b000 | PTE_P | PTE_W, + 0x24c000 | PTE_P | PTE_W, + 0x24d000 | PTE_P | PTE_W, + 0x24e000 | PTE_P | PTE_W, + 0x24f000 | PTE_P | PTE_W, + 0x250000 | PTE_P | PTE_W, + 0x251000 | PTE_P | PTE_W, + 0x252000 | PTE_P | PTE_W, + 0x253000 | PTE_P | PTE_W, + 0x254000 | PTE_P | PTE_W, + 0x255000 | PTE_P | PTE_W, + 0x256000 | PTE_P | PTE_W, + 0x257000 | PTE_P | PTE_W, + 0x258000 | PTE_P | PTE_W, + 0x259000 | PTE_P | PTE_W, + 0x25a000 | PTE_P | PTE_W, + 0x25b000 | PTE_P | PTE_W, + 0x25c000 | PTE_P | PTE_W, + 0x25d000 | PTE_P | PTE_W, + 0x25e000 | PTE_P | PTE_W, + 0x25f000 | PTE_P | PTE_W, + 0x260000 | PTE_P | PTE_W, + 0x261000 | PTE_P | PTE_W, + 0x262000 | PTE_P | PTE_W, + 0x263000 | PTE_P | PTE_W, + 0x264000 | PTE_P | PTE_W, + 0x265000 | PTE_P | PTE_W, + 0x266000 | PTE_P | PTE_W, + 0x267000 | PTE_P | PTE_W, + 0x268000 | PTE_P | PTE_W, + 0x269000 | PTE_P | PTE_W, + 0x26a000 | PTE_P | PTE_W, + 0x26b000 | PTE_P | PTE_W, + 0x26c000 | PTE_P | PTE_W, + 0x26d000 | PTE_P | PTE_W, + 0x26e000 | PTE_P | PTE_W, + 0x26f000 | PTE_P | PTE_W, + 0x270000 | PTE_P | PTE_W, + 0x271000 | PTE_P | PTE_W, + 0x272000 | PTE_P | PTE_W, + 0x273000 | PTE_P | PTE_W, + 0x274000 | PTE_P | PTE_W, + 0x275000 | PTE_P | PTE_W, + 0x276000 | PTE_P | PTE_W, + 0x277000 | PTE_P | PTE_W, + 0x278000 | PTE_P | PTE_W, + 0x279000 | PTE_P | PTE_W, + 0x27a000 | PTE_P | PTE_W, + 0x27b000 | PTE_P | PTE_W, + 0x27c000 | PTE_P | PTE_W, + 0x27d000 | PTE_P | PTE_W, + 0x27e000 | PTE_P | PTE_W, + 0x27f000 | PTE_P | PTE_W, + 0x280000 | PTE_P | PTE_W, + 0x281000 | PTE_P | PTE_W, + 0x282000 | PTE_P | PTE_W, + 0x283000 | PTE_P | PTE_W, + 0x284000 | PTE_P | PTE_W, + 0x285000 | PTE_P | PTE_W, + 0x286000 | PTE_P | PTE_W, + 0x287000 | PTE_P | PTE_W, + 0x288000 | PTE_P | PTE_W, + 0x289000 | PTE_P | PTE_W, + 0x28a000 | PTE_P | PTE_W, + 0x28b000 | PTE_P | PTE_W, + 0x28c000 | PTE_P | PTE_W, + 0x28d000 | PTE_P | PTE_W, + 0x28e000 | PTE_P | PTE_W, + 0x28f000 | PTE_P | PTE_W, + 0x290000 | PTE_P | PTE_W, + 0x291000 | PTE_P | PTE_W, + 0x292000 | PTE_P | PTE_W, + 0x293000 | PTE_P | PTE_W, + 0x294000 | PTE_P | PTE_W, + 0x295000 | PTE_P | PTE_W, + 0x296000 | PTE_P | PTE_W, + 0x297000 | PTE_P | PTE_W, + 0x298000 | PTE_P | PTE_W, + 0x299000 | PTE_P | PTE_W, + 0x29a000 | PTE_P | PTE_W, + 0x29b000 | PTE_P | PTE_W, + 0x29c000 | PTE_P | PTE_W, + 0x29d000 | PTE_P | PTE_W, + 0x29e000 | PTE_P | PTE_W, + 0x29f000 | PTE_P | PTE_W, + 0x2a0000 | PTE_P | PTE_W, + 0x2a1000 | PTE_P | PTE_W, + 0x2a2000 | PTE_P | PTE_W, + 0x2a3000 | PTE_P | PTE_W, + 0x2a4000 | PTE_P | PTE_W, + 0x2a5000 | PTE_P | PTE_W, + 0x2a6000 | PTE_P | PTE_W, + 0x2a7000 | PTE_P | PTE_W, + 0x2a8000 | PTE_P | PTE_W, + 0x2a9000 | PTE_P | PTE_W, + 0x2aa000 | PTE_P | PTE_W, + 0x2ab000 | PTE_P | PTE_W, + 0x2ac000 | PTE_P | PTE_W, + 0x2ad000 | PTE_P | PTE_W, + 0x2ae000 | PTE_P | PTE_W, + 0x2af000 | PTE_P | PTE_W, + 0x2b0000 | PTE_P | PTE_W, + 0x2b1000 | PTE_P | PTE_W, + 0x2b2000 | PTE_P | PTE_W, + 0x2b3000 | PTE_P | PTE_W, + 0x2b4000 | PTE_P | PTE_W, + 0x2b5000 | PTE_P | PTE_W, + 0x2b6000 | PTE_P | PTE_W, + 0x2b7000 | PTE_P | PTE_W, + 0x2b8000 | PTE_P | PTE_W, + 0x2b9000 | PTE_P | PTE_W, + 0x2ba000 | PTE_P | PTE_W, + 0x2bb000 | PTE_P | PTE_W, + 0x2bc000 | PTE_P | PTE_W, + 0x2bd000 | PTE_P | PTE_W, + 0x2be000 | PTE_P | PTE_W, + 0x2bf000 | PTE_P | PTE_W, + 0x2c0000 | PTE_P | PTE_W, + 0x2c1000 | PTE_P | PTE_W, + 0x2c2000 | PTE_P | PTE_W, + 0x2c3000 | PTE_P | PTE_W, + 0x2c4000 | PTE_P | PTE_W, + 0x2c5000 | PTE_P | PTE_W, + 0x2c6000 | PTE_P | PTE_W, + 0x2c7000 | PTE_P | PTE_W, + 0x2c8000 | PTE_P | PTE_W, + 0x2c9000 | PTE_P | PTE_W, + 0x2ca000 | PTE_P | PTE_W, + 0x2cb000 | PTE_P | PTE_W, + 0x2cc000 | PTE_P | PTE_W, + 0x2cd000 | PTE_P | PTE_W, + 0x2ce000 | PTE_P | PTE_W, + 0x2cf000 | PTE_P | PTE_W, + 0x2d0000 | PTE_P | PTE_W, + 0x2d1000 | PTE_P | PTE_W, + 0x2d2000 | PTE_P | PTE_W, + 0x2d3000 | PTE_P | PTE_W, + 0x2d4000 | PTE_P | PTE_W, + 0x2d5000 | PTE_P | PTE_W, + 0x2d6000 | PTE_P | PTE_W, + 0x2d7000 | PTE_P | PTE_W, + 0x2d8000 | PTE_P | PTE_W, + 0x2d9000 | PTE_P | PTE_W, + 0x2da000 | PTE_P | PTE_W, + 0x2db000 | PTE_P | PTE_W, + 0x2dc000 | PTE_P | PTE_W, + 0x2dd000 | PTE_P | PTE_W, + 0x2de000 | PTE_P | PTE_W, + 0x2df000 | PTE_P | PTE_W, + 0x2e0000 | PTE_P | PTE_W, + 0x2e1000 | PTE_P | PTE_W, + 0x2e2000 | PTE_P | PTE_W, + 0x2e3000 | PTE_P | PTE_W, + 0x2e4000 | PTE_P | PTE_W, + 0x2e5000 | PTE_P | PTE_W, + 0x2e6000 | PTE_P | PTE_W, + 0x2e7000 | PTE_P | PTE_W, + 0x2e8000 | PTE_P | PTE_W, + 0x2e9000 | PTE_P | PTE_W, + 0x2ea000 | PTE_P | PTE_W, + 0x2eb000 | PTE_P | PTE_W, + 0x2ec000 | PTE_P | PTE_W, + 0x2ed000 | PTE_P | PTE_W, + 0x2ee000 | PTE_P | PTE_W, + 0x2ef000 | PTE_P | PTE_W, + 0x2f0000 | PTE_P | PTE_W, + 0x2f1000 | PTE_P | PTE_W, + 0x2f2000 | PTE_P | PTE_W, + 0x2f3000 | PTE_P | PTE_W, + 0x2f4000 | PTE_P | PTE_W, + 0x2f5000 | PTE_P | PTE_W, + 0x2f6000 | PTE_P | PTE_W, + 0x2f7000 | PTE_P | PTE_W, + 0x2f8000 | PTE_P | PTE_W, + 0x2f9000 | PTE_P | PTE_W, + 0x2fa000 | PTE_P | PTE_W, + 0x2fb000 | PTE_P | PTE_W, + 0x2fc000 | PTE_P | PTE_W, + 0x2fd000 | PTE_P | PTE_W, + 0x2fe000 | PTE_P | PTE_W, + 0x2ff000 | PTE_P | PTE_W, + 0x300000 | PTE_P | PTE_W, + 0x301000 | PTE_P | PTE_W, + 0x302000 | PTE_P | PTE_W, + 0x303000 | PTE_P | PTE_W, + 0x304000 | PTE_P | PTE_W, + 0x305000 | PTE_P | PTE_W, + 0x306000 | PTE_P | PTE_W, + 0x307000 | PTE_P | PTE_W, + 0x308000 | PTE_P | PTE_W, + 0x309000 | PTE_P | PTE_W, + 0x30a000 | PTE_P | PTE_W, + 0x30b000 | PTE_P | PTE_W, + 0x30c000 | PTE_P | PTE_W, + 0x30d000 | PTE_P | PTE_W, + 0x30e000 | PTE_P | PTE_W, + 0x30f000 | PTE_P | PTE_W, + 0x310000 | PTE_P | PTE_W, + 0x311000 | PTE_P | PTE_W, + 0x312000 | PTE_P | PTE_W, + 0x313000 | PTE_P | PTE_W, + 0x314000 | PTE_P | PTE_W, + 0x315000 | PTE_P | PTE_W, + 0x316000 | PTE_P | PTE_W, + 0x317000 | PTE_P | PTE_W, + 0x318000 | PTE_P | PTE_W, + 0x319000 | PTE_P | PTE_W, + 0x31a000 | PTE_P | PTE_W, + 0x31b000 | PTE_P | PTE_W, + 0x31c000 | PTE_P | PTE_W, + 0x31d000 | PTE_P | PTE_W, + 0x31e000 | PTE_P | PTE_W, + 0x31f000 | PTE_P | PTE_W, + 0x320000 | PTE_P | PTE_W, + 0x321000 | PTE_P | PTE_W, + 0x322000 | PTE_P | PTE_W, + 0x323000 | PTE_P | PTE_W, + 0x324000 | PTE_P | PTE_W, + 0x325000 | PTE_P | PTE_W, + 0x326000 | PTE_P | PTE_W, + 0x327000 | PTE_P | PTE_W, + 0x328000 | PTE_P | PTE_W, + 0x329000 | PTE_P | PTE_W, + 0x32a000 | PTE_P | PTE_W, + 0x32b000 | PTE_P | PTE_W, + 0x32c000 | PTE_P | PTE_W, + 0x32d000 | PTE_P | PTE_W, + 0x32e000 | PTE_P | PTE_W, + 0x32f000 | PTE_P | PTE_W, + 0x330000 | PTE_P | PTE_W, + 0x331000 | PTE_P | PTE_W, + 0x332000 | PTE_P | PTE_W, + 0x333000 | PTE_P | PTE_W, + 0x334000 | PTE_P | PTE_W, + 0x335000 | PTE_P | PTE_W, + 0x336000 | PTE_P | PTE_W, + 0x337000 | PTE_P | PTE_W, + 0x338000 | PTE_P | PTE_W, + 0x339000 | PTE_P | PTE_W, + 0x33a000 | PTE_P | PTE_W, + 0x33b000 | PTE_P | PTE_W, + 0x33c000 | PTE_P | PTE_W, + 0x33d000 | PTE_P | PTE_W, + 0x33e000 | PTE_P | PTE_W, + 0x33f000 | PTE_P | PTE_W, + 0x340000 | PTE_P | PTE_W, + 0x341000 | PTE_P | PTE_W, + 0x342000 | PTE_P | PTE_W, + 0x343000 | PTE_P | PTE_W, + 0x344000 | PTE_P | PTE_W, + 0x345000 | PTE_P | PTE_W, + 0x346000 | PTE_P | PTE_W, + 0x347000 | PTE_P | PTE_W, + 0x348000 | PTE_P | PTE_W, + 0x349000 | PTE_P | PTE_W, + 0x34a000 | PTE_P | PTE_W, + 0x34b000 | PTE_P | PTE_W, + 0x34c000 | PTE_P | PTE_W, + 0x34d000 | PTE_P | PTE_W, + 0x34e000 | PTE_P | PTE_W, + 0x34f000 | PTE_P | PTE_W, + 0x350000 | PTE_P | PTE_W, + 0x351000 | PTE_P | PTE_W, + 0x352000 | PTE_P | PTE_W, + 0x353000 | PTE_P | PTE_W, + 0x354000 | PTE_P | PTE_W, + 0x355000 | PTE_P | PTE_W, + 0x356000 | PTE_P | PTE_W, + 0x357000 | PTE_P | PTE_W, + 0x358000 | PTE_P | PTE_W, + 0x359000 | PTE_P | PTE_W, + 0x35a000 | PTE_P | PTE_W, + 0x35b000 | PTE_P | PTE_W, + 0x35c000 | PTE_P | PTE_W, + 0x35d000 | PTE_P | PTE_W, + 0x35e000 | PTE_P | PTE_W, + 0x35f000 | PTE_P | PTE_W, + 0x360000 | PTE_P | PTE_W, + 0x361000 | PTE_P | PTE_W, + 0x362000 | PTE_P | PTE_W, + 0x363000 | PTE_P | PTE_W, + 0x364000 | PTE_P | PTE_W, + 0x365000 | PTE_P | PTE_W, + 0x366000 | PTE_P | PTE_W, + 0x367000 | PTE_P | PTE_W, + 0x368000 | PTE_P | PTE_W, + 0x369000 | PTE_P | PTE_W, + 0x36a000 | PTE_P | PTE_W, + 0x36b000 | PTE_P | PTE_W, + 0x36c000 | PTE_P | PTE_W, + 0x36d000 | PTE_P | PTE_W, + 0x36e000 | PTE_P | PTE_W, + 0x36f000 | PTE_P | PTE_W, + 0x370000 | PTE_P | PTE_W, + 0x371000 | PTE_P | PTE_W, + 0x372000 | PTE_P | PTE_W, + 0x373000 | PTE_P | PTE_W, + 0x374000 | PTE_P | PTE_W, + 0x375000 | PTE_P | PTE_W, + 0x376000 | PTE_P | PTE_W, + 0x377000 | PTE_P | PTE_W, + 0x378000 | PTE_P | PTE_W, + 0x379000 | PTE_P | PTE_W, + 0x37a000 | PTE_P | PTE_W, + 0x37b000 | PTE_P | PTE_W, + 0x37c000 | PTE_P | PTE_W, + 0x37d000 | PTE_P | PTE_W, + 0x37e000 | PTE_P | PTE_W, + 0x37f000 | PTE_P | PTE_W, + 0x380000 | PTE_P | PTE_W, + 0x381000 | PTE_P | PTE_W, + 0x382000 | PTE_P | PTE_W, + 0x383000 | PTE_P | PTE_W, + 0x384000 | PTE_P | PTE_W, + 0x385000 | PTE_P | PTE_W, + 0x386000 | PTE_P | PTE_W, + 0x387000 | PTE_P | PTE_W, + 0x388000 | PTE_P | PTE_W, + 0x389000 | PTE_P | PTE_W, + 0x38a000 | PTE_P | PTE_W, + 0x38b000 | PTE_P | PTE_W, + 0x38c000 | PTE_P | PTE_W, + 0x38d000 | PTE_P | PTE_W, + 0x38e000 | PTE_P | PTE_W, + 0x38f000 | PTE_P | PTE_W, + 0x390000 | PTE_P | PTE_W, + 0x391000 | PTE_P | PTE_W, + 0x392000 | PTE_P | PTE_W, + 0x393000 | PTE_P | PTE_W, + 0x394000 | PTE_P | PTE_W, + 0x395000 | PTE_P | PTE_W, + 0x396000 | PTE_P | PTE_W, + 0x397000 | PTE_P | PTE_W, + 0x398000 | PTE_P | PTE_W, + 0x399000 | PTE_P | PTE_W, + 0x39a000 | PTE_P | PTE_W, + 0x39b000 | PTE_P | PTE_W, + 0x39c000 | PTE_P | PTE_W, + 0x39d000 | PTE_P | PTE_W, + 0x39e000 | PTE_P | PTE_W, + 0x39f000 | PTE_P | PTE_W, + 0x3a0000 | PTE_P | PTE_W, + 0x3a1000 | PTE_P | PTE_W, + 0x3a2000 | PTE_P | PTE_W, + 0x3a3000 | PTE_P | PTE_W, + 0x3a4000 | PTE_P | PTE_W, + 0x3a5000 | PTE_P | PTE_W, + 0x3a6000 | PTE_P | PTE_W, + 0x3a7000 | PTE_P | PTE_W, + 0x3a8000 | PTE_P | PTE_W, + 0x3a9000 | PTE_P | PTE_W, + 0x3aa000 | PTE_P | PTE_W, + 0x3ab000 | PTE_P | PTE_W, + 0x3ac000 | PTE_P | PTE_W, + 0x3ad000 | PTE_P | PTE_W, + 0x3ae000 | PTE_P | PTE_W, + 0x3af000 | PTE_P | PTE_W, + 0x3b0000 | PTE_P | PTE_W, + 0x3b1000 | PTE_P | PTE_W, + 0x3b2000 | PTE_P | PTE_W, + 0x3b3000 | PTE_P | PTE_W, + 0x3b4000 | PTE_P | PTE_W, + 0x3b5000 | PTE_P | PTE_W, + 0x3b6000 | PTE_P | PTE_W, + 0x3b7000 | PTE_P | PTE_W, + 0x3b8000 | PTE_P | PTE_W, + 0x3b9000 | PTE_P | PTE_W, + 0x3ba000 | PTE_P | PTE_W, + 0x3bb000 | PTE_P | PTE_W, + 0x3bc000 | PTE_P | PTE_W, + 0x3bd000 | PTE_P | PTE_W, + 0x3be000 | PTE_P | PTE_W, + 0x3bf000 | PTE_P | PTE_W, + 0x3c0000 | PTE_P | PTE_W, + 0x3c1000 | PTE_P | PTE_W, + 0x3c2000 | PTE_P | PTE_W, + 0x3c3000 | PTE_P | PTE_W, + 0x3c4000 | PTE_P | PTE_W, + 0x3c5000 | PTE_P | PTE_W, + 0x3c6000 | PTE_P | PTE_W, + 0x3c7000 | PTE_P | PTE_W, + 0x3c8000 | PTE_P | PTE_W, + 0x3c9000 | PTE_P | PTE_W, + 0x3ca000 | PTE_P | PTE_W, + 0x3cb000 | PTE_P | PTE_W, + 0x3cc000 | PTE_P | PTE_W, + 0x3cd000 | PTE_P | PTE_W, + 0x3ce000 | PTE_P | PTE_W, + 0x3cf000 | PTE_P | PTE_W, + 0x3d0000 | PTE_P | PTE_W, + 0x3d1000 | PTE_P | PTE_W, + 0x3d2000 | PTE_P | PTE_W, + 0x3d3000 | PTE_P | PTE_W, + 0x3d4000 | PTE_P | PTE_W, + 0x3d5000 | PTE_P | PTE_W, + 0x3d6000 | PTE_P | PTE_W, + 0x3d7000 | PTE_P | PTE_W, + 0x3d8000 | PTE_P | PTE_W, + 0x3d9000 | PTE_P | PTE_W, + 0x3da000 | PTE_P | PTE_W, + 0x3db000 | PTE_P | PTE_W, + 0x3dc000 | PTE_P | PTE_W, + 0x3dd000 | PTE_P | PTE_W, + 0x3de000 | PTE_P | PTE_W, + 0x3df000 | PTE_P | PTE_W, + 0x3e0000 | PTE_P | PTE_W, + 0x3e1000 | PTE_P | PTE_W, + 0x3e2000 | PTE_P | PTE_W, + 0x3e3000 | PTE_P | PTE_W, + 0x3e4000 | PTE_P | PTE_W, + 0x3e5000 | PTE_P | PTE_W, + 0x3e6000 | PTE_P | PTE_W, + 0x3e7000 | PTE_P | PTE_W, + 0x3e8000 | PTE_P | PTE_W, + 0x3e9000 | PTE_P | PTE_W, + 0x3ea000 | PTE_P | PTE_W, + 0x3eb000 | PTE_P | PTE_W, + 0x3ec000 | PTE_P | PTE_W, + 0x3ed000 | PTE_P | PTE_W, + 0x3ee000 | PTE_P | PTE_W, + 0x3ef000 | PTE_P | PTE_W, + 0x3f0000 | PTE_P | PTE_W, + 0x3f1000 | PTE_P | PTE_W, + 0x3f2000 | PTE_P | PTE_W, + 0x3f3000 | PTE_P | PTE_W, + 0x3f4000 | PTE_P | PTE_W, + 0x3f5000 | PTE_P | PTE_W, + 0x3f6000 | PTE_P | PTE_W, + 0x3f7000 | PTE_P | PTE_W, + 0x3f8000 | PTE_P | PTE_W, + 0x3f9000 | PTE_P | PTE_W, + 0x3fa000 | PTE_P | PTE_W, + 0x3fb000 | PTE_P | PTE_W, + 0x3fc000 | PTE_P | PTE_W, + 0x3fd000 | PTE_P | PTE_W, + 0x3fe000 | PTE_P | PTE_W, + 0x3ff000 | PTE_P | PTE_W, +}; + diff --git a/kern/init.c b/kern/init.c new file mode 100644 index 00000000..96af7a1b --- /dev/null +++ b/kern/init.c @@ -0,0 +1,92 @@ +/* See COPYRIGHT for copyright information. */ + +#include +#include +#include + +#include +#include + +// Test the stack backtrace function (lab 1 only) +void +test_backtrace(int x) +{ + cprintf("entering test_backtrace %d\n", x); + if (x > 0) + test_backtrace(x-1); + else + mon_backtrace(0, 0, 0); + cprintf("leaving test_backtrace %d\n", x); +} + +void +i386_init(void) +{ + extern char edata[], end[]; + + // Before doing anything else, complete the ELF loading process. + // Clear the uninitialized global data (BSS) section of our program. + // This ensures that all static/global variables start out zero. + memset(edata, 0, end - edata); + + // Initialize the console. + // Can't call cprintf until after we do this! + cons_init(); + + cprintf("6828 decimal is %o octal!\n", 6828); + + // Test the stack backtrace function (lab 1 only) + test_backtrace(5); + + // Drop into the kernel monitor. + while (1) + monitor(NULL); +} + + +/* + * Variable panicstr contains argument to first call to panic; used as flag + * to indicate that the kernel has already called panic. + */ +static const char *panicstr; + +/* + * Panic is called on unresolvable fatal errors. + * It prints "panic: mesg", and then enters the kernel monitor. + */ +void +_panic(const char *file, int line, const char *fmt,...) +{ + va_list ap; + + if (panicstr) + goto dead; + panicstr = fmt; + + // Be extra sure that the machine is in as reasonable state + __asm __volatile("cli; cld"); + + va_start(ap, fmt); + cprintf("kernel panic at %s:%d: ", file, line); + vcprintf(fmt, ap); + cprintf("\n"); + va_end(ap); + +dead: + /* break into the kernel monitor */ + while (1) + monitor(NULL); +} + +/* like panic, but don't */ +void +_warn(const char *file, int line, const char *fmt,...) +{ + va_list ap; + + va_start(ap, fmt); + cprintf("kernel warning at %s:%d: ", file, line); + vcprintf(fmt, ap); + cprintf("\n"); + va_end(ap); +} diff --git a/kern/kdebug.c b/kern/kdebug.c new file mode 100644 index 00000000..4f76f93e --- /dev/null +++ b/kern/kdebug.c @@ -0,0 +1,206 @@ +#include +#include +#include +#include + +#include + +extern const struct Stab __STAB_BEGIN__[]; // Beginning of stabs table +extern const struct Stab __STAB_END__[]; // End of stabs table +extern const char __STABSTR_BEGIN__[]; // Beginning of string table +extern const char __STABSTR_END__[]; // End of string table + + +// stab_binsearch(stabs, region_left, region_right, type, addr) +// +// Some stab types are arranged in increasing order by instruction +// address. For example, N_FUN stabs (stab entries with n_type == +// N_FUN), which mark functions, and N_SO stabs, which mark source files. +// +// Given an instruction address, this function finds the single stab +// entry of type 'type' that contains that address. +// +// The search takes place within the range [*region_left, *region_right]. +// Thus, to search an entire set of N stabs, you might do: +// +// left = 0; +// right = N - 1; /* rightmost stab */ +// stab_binsearch(stabs, &left, &right, type, addr); +// +// The search modifies *region_left and *region_right to bracket the +// 'addr'. *region_left points to the matching stab that contains +// 'addr', and *region_right points just before the next stab. If +// *region_left > *region_right, then 'addr' is not contained in any +// matching stab. +// +// For example, given these N_SO stabs: +// Index Type Address +// 0 SO f0100000 +// 13 SO f0100040 +// 117 SO f0100176 +// 118 SO f0100178 +// 555 SO f0100652 +// 556 SO f0100654 +// 657 SO f0100849 +// this code: +// left = 0, right = 657; +// stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184); +// will exit setting left = 118, right = 554. +// +static void +stab_binsearch(const struct Stab *stabs, int *region_left, int *region_right, + int type, uintptr_t addr) +{ + int l = *region_left, r = *region_right, any_matches = 0; + + while (l <= r) { + int true_m = (l + r) / 2, m = true_m; + + // search for earliest stab with right type + while (m >= l && stabs[m].n_type != type) + m--; + if (m < l) { // no match in [l, m] + l = true_m + 1; + continue; + } + + // actual binary search + any_matches = 1; + if (stabs[m].n_value < addr) { + *region_left = m; + l = true_m + 1; + } else if (stabs[m].n_value > addr) { + *region_right = m - 1; + r = m - 1; + } else { + // exact match for 'addr', but continue loop to find + // *region_right + *region_left = m; + l = m; + addr++; + } + } + + if (!any_matches) + *region_right = *region_left - 1; + else { + // find rightmost region containing 'addr' + for (l = *region_right; + l > *region_left && stabs[l].n_type != type; + l--) + /* do nothing */; + *region_left = l; + } +} + + +// debuginfo_eip(addr, info) +// +// Fill in the 'info' structure with information about the specified +// instruction address, 'addr'. Returns 0 if information was found, and +// negative if not. But even if it returns negative it has stored some +// information into '*info'. +// +int +debuginfo_eip(uintptr_t addr, struct Eipdebuginfo *info) +{ + const struct Stab *stabs, *stab_end; + const char *stabstr, *stabstr_end; + int lfile, rfile, lfun, rfun, lline, rline; + + // Initialize *info + info->eip_file = ""; + info->eip_line = 0; + info->eip_fn_name = ""; + info->eip_fn_namelen = 9; + info->eip_fn_addr = addr; + info->eip_fn_narg = 0; + + // Find the relevant set of stabs + if (addr >= ULIM) { + stabs = __STAB_BEGIN__; + stab_end = __STAB_END__; + stabstr = __STABSTR_BEGIN__; + stabstr_end = __STABSTR_END__; + } else { + // Can't search for user-level addresses yet! + panic("User address"); + } + + // String table validity checks + if (stabstr_end <= stabstr || stabstr_end[-1] != 0) + return -1; + + // Now we find the right stabs that define the function containing + // 'eip'. First, we find the basic source file containing 'eip'. + // Then, we look in that source file for the function. Then we look + // for the line number. + + // Search the entire set of stabs for the source file (type N_SO). + lfile = 0; + rfile = (stab_end - stabs) - 1; + stab_binsearch(stabs, &lfile, &rfile, N_SO, addr); + if (lfile == 0) + return -1; + + // Search within that file's stabs for the function definition + // (N_FUN). + lfun = lfile; + rfun = rfile; + stab_binsearch(stabs, &lfun, &rfun, N_FUN, addr); + + if (lfun <= rfun) { + // stabs[lfun] points to the function name + // in the string table, but check bounds just in case. + if (stabs[lfun].n_strx < stabstr_end - stabstr) + info->eip_fn_name = stabstr + stabs[lfun].n_strx; + info->eip_fn_addr = stabs[lfun].n_value; + addr -= info->eip_fn_addr; + // Search within the function definition for the line number. + lline = lfun; + rline = rfun; + } else { + // Couldn't find function stab! Maybe we're in an assembly + // file. Search the whole file for the line number. + info->eip_fn_addr = addr; + lline = lfile; + rline = rfile; + } + // Ignore stuff after the colon. + info->eip_fn_namelen = strfind(info->eip_fn_name, ':') - info->eip_fn_name; + + + // Search within [lline, rline] for the line number stab. + // If found, set info->eip_line to the right line number. + // If not found, return -1. + // + // Hint: + // There's a particular stabs type used for line numbers. + // Look at the STABS documentation and to find + // which one. + // Your code here. + + + // Search backwards from the line number for the relevant filename + // stab. + // We can't just use the "lfile" stab because inlined functions + // can interpolate code from a different file! + // Such included source files use the N_SOL stab type. + while (lline >= lfile + && stabs[lline].n_type != N_SOL + && (stabs[lline].n_type != N_SO || !stabs[lline].n_value)) + lline--; + if (lline >= lfile && stabs[lline].n_strx < stabstr_end - stabstr) + info->eip_file = stabstr + stabs[lline].n_strx; + + + // Set eip_fn_narg to the number of arguments taken by the function, + // or 0 if there was no containing function. + if (lfun < rfun) + for (lline = lfun + 1; + lline < rfun && stabs[lline].n_type == N_PSYM; + lline++) + info->eip_fn_narg++; + + return 0; +} diff --git a/kern/kdebug.h b/kern/kdebug.h new file mode 100644 index 00000000..236af392 --- /dev/null +++ b/kern/kdebug.h @@ -0,0 +1,20 @@ +#ifndef JOS_KERN_KDEBUG_H +#define JOS_KERN_KDEBUG_H + +#include + +// Debug information about a particular instruction pointer +struct Eipdebuginfo { + const char *eip_file; // Source code filename for EIP + int eip_line; // Source code linenumber for EIP + + const char *eip_fn_name; // Name of function containing EIP + // - Note: not null terminated! + int eip_fn_namelen; // Length of function name + uintptr_t eip_fn_addr; // Address of start of function + int eip_fn_narg; // Number of function arguments +}; + +int debuginfo_eip(uintptr_t eip, struct Eipdebuginfo *info); + +#endif diff --git a/kern/kernel.ld b/kern/kernel.ld new file mode 100644 index 00000000..45a0b6af --- /dev/null +++ b/kern/kernel.ld @@ -0,0 +1,61 @@ +/* Simple linker script for the JOS kernel. + See the GNU ld 'info' manual ("info ld") to learn the syntax. */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + /* Link the kernel at this address: "." means the current address */ + . = 0xF0100000; + + /* AT(...) gives the load address of this section, which tells + the boot loader where to load the kernel in physical memory */ + .text : AT(0x100000) { + *(.text .stub .text.* .gnu.linkonce.t.*) + } + + PROVIDE(etext = .); /* Define the 'etext' symbol to this value */ + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + /* Include debugging information in kernel memory */ + .stab : { + PROVIDE(__STAB_BEGIN__ = .); + *(.stab); + PROVIDE(__STAB_END__ = .); + BYTE(0) /* Force the linker to allocate space + for this section */ + } + + .stabstr : { + PROVIDE(__STABSTR_BEGIN__ = .); + *(.stabstr); + PROVIDE(__STABSTR_END__ = .); + BYTE(0) /* Force the linker to allocate space + for this section */ + } + + /* Adjust the address for the data segment to the next page */ + . = ALIGN(0x1000); + + /* The data segment */ + .data : { + *(.data) + } + + PROVIDE(edata = .); + + .bss : { + *(.bss) + } + + PROVIDE(end = .); + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack) + } +} diff --git a/kern/monitor.c b/kern/monitor.c new file mode 100644 index 00000000..14d8d141 --- /dev/null +++ b/kern/monitor.c @@ -0,0 +1,138 @@ +// Simple command-line kernel monitor useful for +// controlling the kernel and exploring the system interactively. + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define CMDBUF_SIZE 80 // enough for one VGA text line + + +struct Command { + const char *name; + const char *desc; + // return -1 to force monitor to exit + int (*func)(int argc, char** argv, struct Trapframe* tf); +}; + +static struct Command commands[] = { + { "help", "Display this list of commands", mon_help }, + { "kerninfo", "Display information about the kernel", mon_kerninfo }, +}; +#define NCOMMANDS (sizeof(commands)/sizeof(commands[0])) + +unsigned read_eip(); + +/***** Implementations of basic kernel monitor commands *****/ + +int +mon_help(int argc, char **argv, struct Trapframe *tf) +{ + int i; + + for (i = 0; i < NCOMMANDS; i++) + cprintf("%s - %s\n", commands[i].name, commands[i].desc); + return 0; +} + +int +mon_kerninfo(int argc, char **argv, struct Trapframe *tf) +{ + extern char _start[], etext[], edata[], end[]; + + cprintf("Special kernel symbols:\n"); + cprintf(" _start %08x (virt) %08x (phys)\n", _start, _start - KERNBASE); + cprintf(" etext %08x (virt) %08x (phys)\n", etext, etext - KERNBASE); + cprintf(" edata %08x (virt) %08x (phys)\n", edata, edata - KERNBASE); + cprintf(" end %08x (virt) %08x (phys)\n", end, end - KERNBASE); + cprintf("Kernel executable memory footprint: %dKB\n", + (end-_start+1023)/1024); + return 0; +} + +int +mon_backtrace(int argc, char **argv, struct Trapframe *tf) +{ + // Your code here. + return 0; +} + + + +/***** Kernel monitor command interpreter *****/ + +#define WHITESPACE "\t\r\n " +#define MAXARGS 16 + +static int +runcmd(char *buf, struct Trapframe *tf) +{ + int argc; + char *argv[MAXARGS]; + int i; + + // Parse the command buffer into whitespace-separated arguments + argc = 0; + argv[argc] = 0; + while (1) { + // gobble whitespace + while (*buf && strchr(WHITESPACE, *buf)) + *buf++ = 0; + if (*buf == 0) + break; + + // save and scan past next arg + if (argc == MAXARGS-1) { + cprintf("Too many arguments (max %d)\n", MAXARGS); + return 0; + } + argv[argc++] = buf; + while (*buf && !strchr(WHITESPACE, *buf)) + buf++; + } + argv[argc] = 0; + + // Lookup and invoke the command + if (argc == 0) + return 0; + for (i = 0; i < NCOMMANDS; i++) { + if (strcmp(argv[0], commands[i].name) == 0) + return commands[i].func(argc, argv, tf); + } + cprintf("Unknown command '%s'\n", argv[0]); + return 0; +} + +void +monitor(struct Trapframe *tf) +{ + char *buf; + + cprintf("Welcome to the JOS kernel monitor!\n"); + cprintf("Type 'help' for a list of commands.\n"); + + + while (1) { + buf = readline("K> "); + if (buf != NULL) + if (runcmd(buf, tf) < 0) + break; + } +} + +// return EIP of caller. +// does not work if inlined. +// putting at the end of the file seems to prevent inlining. +unsigned +read_eip() +{ + uint32_t callerpc; + __asm __volatile("movl 4(%%ebp), %0" : "=r" (callerpc)); + return callerpc; +} diff --git a/kern/monitor.h b/kern/monitor.h new file mode 100644 index 00000000..0aa0f26f --- /dev/null +++ b/kern/monitor.h @@ -0,0 +1,19 @@ +#ifndef JOS_KERN_MONITOR_H +#define JOS_KERN_MONITOR_H +#ifndef JOS_KERNEL +# error "This is a JOS kernel header; user programs should not #include it" +#endif + +struct Trapframe; + +// Activate the kernel monitor, +// optionally providing a trap frame indicating the current state +// (NULL if none). +void monitor(struct Trapframe *tf); + +// Functions implementing monitor commands. +int mon_help(int argc, char **argv, struct Trapframe *tf); +int mon_kerninfo(int argc, char **argv, struct Trapframe *tf); +int mon_backtrace(int argc, char **argv, struct Trapframe *tf); + +#endif // !JOS_KERN_MONITOR_H diff --git a/kern/printf.c b/kern/printf.c new file mode 100644 index 00000000..6932ca57 --- /dev/null +++ b/kern/printf.c @@ -0,0 +1,37 @@ +// Simple implementation of cprintf console output for the kernel, +// based on printfmt() and the kernel console's cputchar(). + +#include +#include +#include + + +static void +putch(int ch, int *cnt) +{ + cputchar(ch); + *cnt++; +} + +int +vcprintf(const char *fmt, va_list ap) +{ + int cnt = 0; + + vprintfmt((void*)putch, &cnt, fmt, ap); + return cnt; +} + +int +cprintf(const char *fmt, ...) +{ + va_list ap; + int cnt; + + va_start(ap, fmt); + cnt = vcprintf(fmt, ap); + va_end(ap); + + return cnt; +} + diff --git a/lib/printfmt.c b/lib/printfmt.c new file mode 100644 index 00000000..5bea78e7 --- /dev/null +++ b/lib/printfmt.c @@ -0,0 +1,300 @@ +// Stripped-down primitive printf-style formatting routines, +// used in common by printf, sprintf, fprintf, etc. +// This code is also used by both the kernel and user programs. + +#include +#include +#include +#include +#include + +/* + * Space or zero padding and a field width are supported for the numeric + * formats only. + * + * The special format %e takes an integer error code + * and prints a string describing the error. + * The integer may be positive or negative, + * so that -E_NO_MEM and E_NO_MEM are equivalent. + */ + +static const char * const error_string[MAXERROR] = +{ + [E_UNSPECIFIED] = "unspecified error", + [E_BAD_ENV] = "bad environment", + [E_INVAL] = "invalid parameter", + [E_NO_MEM] = "out of memory", + [E_NO_FREE_ENV] = "out of environments", + [E_FAULT] = "segmentation fault", +}; + +/* + * Print a number (base <= 16) in reverse order, + * using specified putch function and associated pointer putdat. + */ +static void +printnum(void (*putch)(int, void*), void *putdat, + unsigned long long num, unsigned base, int width, int padc) +{ + // first recursively print all preceding (more significant) digits + if (num >= base) { + printnum(putch, putdat, num / base, base, width - 1, padc); + } else { + // print any needed pad characters before first digit + while (--width > 0) + putch(padc, putdat); + } + + // then print this (the least significant) digit + putch("0123456789abcdef"[num % base], putdat); +} + +// Get an unsigned int of various possible sizes from a varargs list, +// depending on the lflag parameter. +static unsigned long long +getuint(va_list *ap, int lflag) +{ + if (lflag >= 2) + return va_arg(*ap, unsigned long long); + else if (lflag) + return va_arg(*ap, unsigned long); + else + return va_arg(*ap, unsigned int); +} + +// Same as getuint but signed - can't use getuint +// because of sign extension +static long long +getint(va_list *ap, int lflag) +{ + if (lflag >= 2) + return va_arg(*ap, long long); + else if (lflag) + return va_arg(*ap, long); + else + return va_arg(*ap, int); +} + + +// Main function to format and print a string. +void printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...); + +void +vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap) +{ + register const char *p; + register int ch, err; + unsigned long long num; + int base, lflag, width, precision, altflag; + char padc; + + while (1) { + while ((ch = *(unsigned char *) fmt++) != '%') { + if (ch == '\0') + return; + putch(ch, putdat); + } + + // Process a %-escape sequence + padc = ' '; + width = -1; + precision = -1; + lflag = 0; + altflag = 0; + reswitch: + switch (ch = *(unsigned char *) fmt++) { + + // flag to pad on the right + case '-': + padc = '-'; + goto reswitch; + + // flag to pad with 0's instead of spaces + case '0': + padc = '0'; + goto reswitch; + + // width field + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + for (precision = 0; ; ++fmt) { + precision = precision * 10 + ch - '0'; + ch = *fmt; + if (ch < '0' || ch > '9') + break; + } + goto process_precision; + + case '*': + precision = va_arg(ap, int); + goto process_precision; + + case '.': + if (width < 0) + width = 0; + goto reswitch; + + case '#': + altflag = 1; + goto reswitch; + + process_precision: + if (width < 0) + width = precision, precision = -1; + goto reswitch; + + // long flag (doubled for long long) + case 'l': + lflag++; + goto reswitch; + + // character + case 'c': + putch(va_arg(ap, int), putdat); + break; + + // error message + case 'e': + err = va_arg(ap, int); + if (err < 0) + err = -err; + if (err >= MAXERROR || (p = error_string[err]) == NULL) + printfmt(putch, putdat, "error %d", err); + else + printfmt(putch, putdat, "%s", p); + break; + + // string + case 's': + if ((p = va_arg(ap, char *)) == NULL) + p = "(null)"; + if (width > 0 && padc != '-') + for (width -= strnlen(p, precision); width > 0; width--) + putch(padc, putdat); + for (; (ch = *p++) != '\0' && (precision < 0 || --precision >= 0); width--) + if (altflag && (ch < ' ' || ch > '~')) + putch('?', putdat); + else + putch(ch, putdat); + for (; width > 0; width--) + putch(' ', putdat); + break; + + // (signed) decimal + case 'd': + num = getint(&ap, lflag); + if ((long long) num < 0) { + putch('-', putdat); + num = -(long long) num; + } + base = 10; + goto number; + + // unsigned decimal + case 'u': + num = getuint(&ap, lflag); + base = 10; + goto number; + + // (unsigned) octal + case 'o': + // Replace this with your code. + putch('X', putdat); + putch('X', putdat); + putch('X', putdat); + break; + + // pointer + case 'p': + putch('0', putdat); + putch('x', putdat); + num = (unsigned long long) + (uintptr_t) va_arg(ap, void *); + base = 16; + goto number; + + // (unsigned) hexadecimal + case 'x': + num = getuint(&ap, lflag); + base = 16; + number: + printnum(putch, putdat, num, base, width, padc); + break; + + // escaped '%' character + case '%': + putch(ch, putdat); + break; + + // unrecognized escape sequence - just print it literally + default: + putch('%', putdat); + for (fmt--; fmt[-1] != '%'; fmt--) + /* do nothing */; + break; + } + } +} + +void +printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintfmt(putch, putdat, fmt, ap); + va_end(ap); +} + +struct sprintbuf { + char *buf; + char *ebuf; + int cnt; +}; + +static void +sprintputch(int ch, struct sprintbuf *b) +{ + b->cnt++; + if (b->buf < b->ebuf) + *b->buf++ = ch; +} + +int +vsnprintf(char *buf, int n, const char *fmt, va_list ap) +{ + struct sprintbuf b = {buf, buf+n-1, 0}; + + if (buf == NULL || n < 1) + return -E_INVAL; + + // print the string to the buffer + vprintfmt((void*)sprintputch, &b, fmt, ap); + + // null terminate the buffer + *b.buf = '\0'; + + return b.cnt; +} + +int +snprintf(char *buf, int n, const char *fmt, ...) +{ + va_list ap; + int rc; + + va_start(ap, fmt); + rc = vsnprintf(buf, n, fmt, ap); + va_end(ap); + + return rc; +} + + diff --git a/lib/readline.c b/lib/readline.c new file mode 100644 index 00000000..bc77b1f3 --- /dev/null +++ b/lib/readline.c @@ -0,0 +1,38 @@ +#include +#include + +#define BUFLEN 1024 +static char buf[BUFLEN]; + +char * +readline(const char *prompt) +{ + int i, c, echoing; + + if (prompt != NULL) + cprintf("%s", prompt); + + i = 0; + echoing = iscons(0); + while (1) { + c = getchar(); + if (c < 0) { + cprintf("read error: %e\n", c); + return NULL; + } else if ((c == '\b' || c == '\x7f') && i > 0) { + if (echoing) + cputchar('\b'); + i--; + } else if (c >= ' ' && i < BUFLEN-1) { + if (echoing) + cputchar(c); + buf[i++] = c; + } else if (c == '\n' || c == '\r') { + if (echoing) + cputchar('\n'); + buf[i] = 0; + return buf; + } + } +} + diff --git a/lib/string.c b/lib/string.c new file mode 100644 index 00000000..6cd10175 --- /dev/null +++ b/lib/string.c @@ -0,0 +1,281 @@ +// Basic string routines. Not hardware optimized, but not shabby. + +#include + +// Using assembly for memset/memmove +// makes some difference on real hardware, +// but it makes an even bigger difference on bochs. +// Primespipe runs 3x faster this way. +#define ASM 1 + +int +strlen(const char *s) +{ + int n; + + for (n = 0; *s != '\0'; s++) + n++; + return n; +} + +int +strnlen(const char *s, size_t size) +{ + int n; + + for (n = 0; size > 0 && *s != '\0'; s++, size--) + n++; + return n; +} + +char * +strcpy(char *dst, const char *src) +{ + char *ret; + + ret = dst; + while ((*dst++ = *src++) != '\0') + /* do nothing */; + return ret; +} + +char * +strncpy(char *dst, const char *src, size_t size) { + size_t i; + char *ret; + + ret = dst; + for (i = 0; i < size; i++) { + *dst++ = *src; + // If strlen(src) < size, null-pad 'dst' out to 'size' chars + if (*src != '\0') + src++; + } + return ret; +} + +size_t +strlcpy(char *dst, const char *src, size_t size) +{ + char *dst_in; + + dst_in = dst; + if (size > 0) { + while (--size > 0 && *src != '\0') + *dst++ = *src++; + *dst = '\0'; + } + return dst - dst_in; +} + +int +strcmp(const char *p, const char *q) +{ + while (*p && *p == *q) + p++, q++; + return (int) ((unsigned char) *p - (unsigned char) *q); +} + +int +strncmp(const char *p, const char *q, size_t n) +{ + while (n > 0 && *p && *p == *q) + n--, p++, q++; + if (n == 0) + return 0; + else + return (int) ((unsigned char) *p - (unsigned char) *q); +} + +// Return a pointer to the first occurrence of 'c' in 's', +// or a null pointer if the string has no 'c'. +char * +strchr(const char *s, char c) +{ + for (; *s; s++) + if (*s == c) + return (char *) s; + return 0; +} + +// Return a pointer to the first occurrence of 'c' in 's', +// or a pointer to the string-ending null character if the string has no 'c'. +char * +strfind(const char *s, char c) +{ + for (; *s; s++) + if (*s == c) + break; + return (char *) s; +} + +#if ASM +void * +memset(void *v, int c, size_t n) +{ + char *p; + + if (n == 0) + return v; + if ((int)v%4 == 0 && n%4 == 0) { + c &= 0xFF; + c = (c<<24)|(c<<16)|(c<<8)|c; + asm volatile("cld; rep stosl\n" + :: "D" (v), "a" (c), "c" (n/4) + : "cc", "memory"); + } else + asm volatile("cld; rep stosb\n" + :: "D" (v), "a" (c), "c" (n) + : "cc", "memory"); + return v; +} + +void * +memmove(void *dst, const void *src, size_t n) +{ + const char *s; + char *d; + + s = src; + d = dst; + if (s < d && s + n > d) { + s += n; + d += n; + if ((int)s%4 == 0 && (int)d%4 == 0 && n%4 == 0) + asm volatile("std; rep movsl\n" + :: "D" (d-4), "S" (s-4), "c" (n/4) : "cc", "memory"); + else + asm volatile("std; rep movsb\n" + :: "D" (d-1), "S" (s-1), "c" (n) : "cc", "memory"); + // Some versions of GCC rely on DF being clear + asm volatile("cld" ::: "cc"); + } else { + if ((int)s%4 == 0 && (int)d%4 == 0 && n%4 == 0) + asm volatile("cld; rep movsl\n" + :: "D" (d), "S" (s), "c" (n/4) : "cc", "memory"); + else + asm volatile("cld; rep movsb\n" + :: "D" (d), "S" (s), "c" (n) : "cc", "memory"); + } + return dst; +} + +#else + +void * +memset(void *v, int c, size_t n) +{ + char *p; + int m; + + p = v; + m = n; + while (--m >= 0) + *p++ = c; + + return v; +} + +/* no memcpy - use memmove instead */ + +void * +memmove(void *dst, const void *src, size_t 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; +} +#endif + +/* sigh - gcc emits references to this for structure assignments! */ +/* it is *not* prototyped in inc/string.h - do not use directly. */ +void * +memcpy(void *dst, void *src, size_t n) +{ + return memmove(dst, src, n); +} + +int +memcmp(const void *v1, const void *v2, size_t n) +{ + const uint8_t *s1 = (const uint8_t *) v1; + const uint8_t *s2 = (const uint8_t *) v2; + + while (n-- > 0) { + if (*s1 != *s2) + return (int) *s1 - (int) *s2; + s1++, s2++; + } + + return 0; +} + +void * +memfind(const void *s, int c, size_t n) +{ + const void *ends = (const char *) s + n; + for (; s < ends; s++) + if (*(const unsigned char *) s == (unsigned char) c) + break; + return (void *) s; +} + +long +strtol(const char *s, char **endptr, int base) +{ + int neg = 0; + long val = 0; + + // gobble initial whitespace + while (*s == ' ' || *s == '\t') + s++; + + // plus/minus sign + if (*s == '+') + s++; + else if (*s == '-') + s++, neg = 1; + + // hex or octal base prefix + if ((base == 0 || base == 16) && (s[0] == '0' && s[1] == 'x')) + s += 2, base = 16; + else if (base == 0 && s[0] == '0') + s++, base = 8; + else if (base == 0) + base = 10; + + // digits + while (1) { + int dig; + + if (*s >= '0' && *s <= '9') + dig = *s - '0'; + else if (*s >= 'a' && *s <= 'z') + dig = *s - 'a' + 10; + else if (*s >= 'A' && *s <= 'Z') + dig = *s - 'A' + 10; + else + break; + if (dig >= base) + break; + s++, val = (val * base) + dig; + // we don't properly detect overflow! + } + + if (endptr) + *endptr = (char *) s; + return (neg ? -val : val); +} + diff --git a/mergedep.pl b/mergedep.pl new file mode 100644 index 00000000..1730d539 --- /dev/null +++ b/mergedep.pl @@ -0,0 +1,86 @@ +#!/usr/bin/perl +# Copyright 2003 Bryan Ford +# Distributed under the GNU General Public License. +# +# Usage: mergedep [ ...] +# +# This script merges the contents of all specified +# on the command line into the single file , +# which may or may not previously exist. +# Dependencies in the will override +# any existing dependencies for the same targets in . +# The are deleted after is updated. +# +# The are typically generated by GCC with the -MD option, +# and the is typically included from a Makefile, +# as shown here for GNU 'make': +# +# .deps: $(wildcard *.d) +# perl mergedep $@ $^ +# -include .deps +# +# This script properly handles multiple dependencies per , +# including dependencies having no target, +# so it is compatible with GCC3's -MP option. +# + +sub readdeps { + my $filename = shift; + + open(DEPFILE, $filename) or return 0; + while () { + if (/([^:]*):([^\\:]*)([\\]?)$/) { + my $target = $1; + my $deplines = $2; + my $slash = $3; + while ($slash ne '') { + $_ = ; + defined($_) or die + "Unterminated dependency in $filename"; + /(^[ \t][^\\]*)([\\]?)$/ or die + "Bad continuation line in $filename"; + $deplines = "$deplines\\\n$1"; + $slash = $2; + } + #print "DEPENDENCY [[$target]]: [[$deplines]]\n"; + $dephash{$target} = $deplines; + } elsif (/^[#]?[ \t]*$/) { + # ignore blank lines and comments + } else { + die "Bad dependency line in $filename: $_"; + } + } + close DEPFILE; + return 1; +} + + +if ($#ARGV < 0) { + print "Usage: mergedep [ ..]\n"; + exit(1); +} + +%dephash = (); + +# Read the main dependency file +$maindeps = $ARGV[0]; +readdeps($maindeps); + +# Read and merge in the new dependency files +foreach $i (1 .. $#ARGV) { + readdeps($ARGV[$i]) or die "Can't open $ARGV[$i]"; +} + +# Update the main dependency file +open(DEPFILE, ">$maindeps.tmp") or die "Can't open output file $maindeps.tmp"; +foreach $target (keys %dephash) { + print DEPFILE "$target:$dephash{$target}"; +} +close DEPFILE; +rename("$maindeps.tmp", "$maindeps") or die "Can't overwrite $maindeps"; + +# Finally, delete the new dependency files +foreach $i (1 .. $#ARGV) { + unlink($ARGV[$i]) or print "Error removing $ARGV[$i]\n"; +} +