Splits x86 into 32 and 64 bit (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 12 Jun 2013 00:38:00 +0000 (17:38 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 12 Jun 2013 21:15:42 +0000 (14:15 -0700)
No real change in functionality, just separating out the bit-specific items
within the arch directory and build process.

This builds and links in 64 bit mode, but doesn't actually do anything (like
jump into longmode, etc).

69 files changed:
Makefile
kern/arch/x86/Kbuild
kern/arch/x86/Makefile
kern/arch/x86/apic.c
kern/arch/x86/apic.h
kern/arch/x86/arch.h
kern/arch/x86/atomic.h
kern/arch/x86/cpuinfo.c
kern/arch/x86/entry.S [deleted file]
kern/arch/x86/entry32.S [new file with mode: 0644]
kern/arch/x86/entry64.S [new file with mode: 0644]
kern/arch/x86/env.c [deleted file]
kern/arch/x86/ioapic.c
kern/arch/x86/ioapic.h
kern/arch/x86/kdebug.c
kern/arch/x86/kdebug.h
kern/arch/x86/kernel.ld [deleted file]
kern/arch/x86/kernel32.ld [new file with mode: 0644]
kern/arch/x86/kernel64.ld [new file with mode: 0644]
kern/arch/x86/mptables.c
kern/arch/x86/mptables.h
kern/arch/x86/page_alloc.c
kern/arch/x86/perfmon.h
kern/arch/x86/pmap.c
kern/arch/x86/pmap32.c [new file with mode: 0644]
kern/arch/x86/pmap64.c [new file with mode: 0644]
kern/arch/x86/process.c [deleted file]
kern/arch/x86/process32.c [new file with mode: 0644]
kern/arch/x86/process64.c [new file with mode: 0644]
kern/arch/x86/ros/bits/syscall.h [deleted file]
kern/arch/x86/ros/mmu.h
kern/arch/x86/ros/mmu32.h [new file with mode: 0644]
kern/arch/x86/ros/mmu64.h [new file with mode: 0644]
kern/arch/x86/ros/syscall.h
kern/arch/x86/ros/syscall32.h [new file with mode: 0644]
kern/arch/x86/ros/syscall64.h [new file with mode: 0644]
kern/arch/x86/ros/trapframe.h
kern/arch/x86/ros/trapframe32.h [new file with mode: 0644]
kern/arch/x86/ros/trapframe64.h [new file with mode: 0644]
kern/arch/x86/smp_boot.c
kern/arch/x86/smp_entry.S [deleted file]
kern/arch/x86/smp_entry32.S [new file with mode: 0644]
kern/arch/x86/smp_entry64.S [new file with mode: 0644]
kern/arch/x86/trap.c
kern/arch/x86/trap.h
kern/arch/x86/trap32.c [new file with mode: 0644]
kern/arch/x86/trap32.h [new file with mode: 0644]
kern/arch/x86/trap64.c [new file with mode: 0644]
kern/arch/x86/trap64.h [new file with mode: 0644]
kern/arch/x86/trapentry.S [deleted file]
kern/arch/x86/trapentry32.S [new file with mode: 0644]
kern/arch/x86/trapentry64.S [new file with mode: 0644]
kern/arch/x86/types.h
kern/arch/x86/x86.h
kern/include/ros/memlayout.h
kern/include/ros/procdata.h
kern/include/smp.h
kern/src/frontend.c
kern/src/mm.c
kern/src/monitor.c
kern/src/multiboot.c
kern/src/syscall.c
kern/src/testing.c
scripts/kvm-up.sh
user/parlib/include/x86/arch.h
user/parlib/include/x86/atomic.h
user/parlib/include/x86/vcore.h
user/parlib/include/x86/vcore32.h [new file with mode: 0644]
user/parlib/include/x86/vcore64.h [new file with mode: 0644]

index ab6855c..72d4975 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -296,6 +296,7 @@ OBJCOPY     := $(CROSS_COMPILE)objcopy
 OBJDUMP        := $(CROSS_COMPILE)objdump
 NM         := $(CROSS_COMPILE)nm
 STRIP   := $(CROSS_COMPILE)strip
+KERNEL_LD ?= kernel.ld
 
 # These may have bogus values if there is no compiler.  The kernel and user
 # build targets will check cc-exists.  Hopefully no cleaning targets rely on
@@ -308,7 +309,7 @@ NOSTDINC_FLAGS += -nostdinc -isystem \
 XCC_TARGET_ROOT := $(dir $(shell which $(CC)))../$(patsubst %-,%,\
                                                    $(CROSS_COMPILE))
 
-CFLAGS_KERNEL += -O2 -pipe -MD -gstabs
+CFLAGS_KERNEL += -O2 -pipe -MD
 CFLAGS_KERNEL += -std=gnu99 -fgnu89-inline
 CFLAGS_KERNEL += -fno-strict-aliasing -fno-omit-frame-pointer
 CFLAGS_KERNEL += -fno-stack-protector
@@ -318,7 +319,7 @@ CFLAGS_KERNEL += -include include/generated/autoconf.h -include include/common.h
 ifeq ($(CONFIG_64BIT),y)
 CFLAGS_KERNEL += -m64
 else
-CFLAGS_KERNEL += -m32
+CFLAGS_KERNEL += -m32 -gstabs
 endif
 
 # TODO: do we need this, or can we rely on the compiler's defines?
@@ -400,7 +401,7 @@ core-y          := $(patsubst %/, %/built-in.o, $(core-y))
 arch-y          := $(patsubst %/, %/built-in.o, $(arch-y))
 
 kbuild_akaros_main := $(core-y) $(arch-y)
-akaros-deps := $(kbuild_akaros_main)  kern/arch/$(ARCH)/kernel.ld
+akaros-deps := $(kbuild_akaros_main)  kern/arch/$(ARCH)/$(KERNEL_LD)
 
 kern_cpio := $(OBJDIR)/kern/initramfs.cpio
 kern_cpio_obj := $(kern_cpio).o
@@ -441,7 +442,8 @@ $(ext2_bdev_obj): $(ext2-bdev)
        $(Q)$(OBJCOPY) -I binary -B $(ld_arch) -O $(ld_emulation) $^ $@
 
 quiet_cmd_link-akaros = LINK    $@
-      cmd_link-akaros = $(LD) -T kern/arch/$(ARCH)/kernel.ld -o $@ \
+      cmd_link-akaros = $(LD) -T kern/arch/$(ARCH)/$(KERNEL_LD) -o $@ \
+                              $(LDFLAGS_KERNEL) \
                               $(akaros-deps) \
                               $(gcc-lib) \
                               $(kern_cpio_obj) \
index e0713b7..409a7f6 100644 (file)
@@ -2,8 +2,7 @@ obj-y                                           += apic.o
 obj-y                                          += colored_caches.o
 obj-y                                          += console.o
 obj-y                                          += cpuinfo.o
-obj-y                                          += entry.o
-obj-y                                          += env.o
+obj-y                                          += entry$(BITS).o
 obj-y                                          += frontend.o
 obj-y                                          += init.o
 obj-y                                          += ioapic.o
@@ -13,11 +12,11 @@ obj-y                                               += mptables.o
 obj-y                                          += page_alloc.o
 obj-y                                          += pci.o
 obj-y                                          += perfmon.o
-obj-y                                          += pmap.o
-obj-y                                          += process.o
+obj-y                                          += pmap.o pmap$(BITS).o
+obj-y                                          += process$(BITS).o
 obj-y                                          += rdtsc_test.o
 obj-y                                          += smp.o
 obj-y                                          += smp_boot.o
-obj-y                                          += smp_entry.o
-obj-y                                          += trap.o
-obj-y                                          += trapentry.o
+obj-y                                          += smp_entry$(BITS).o
+obj-y                                          += trap.o trap$(BITS).o
+obj-y                                          += trapentry$(BITS).o
index 73f976e..86068b9 100644 (file)
@@ -1,5 +1,16 @@
 ifeq ($(CONFIG_X86_64),y)
-CROSS_COMPILE := x86_64-ros-
+#CROSS_COMPILE := x86_64-ros-
+CROSS_COMPILE := 
+BITS := 64
+KERNEL_LD := kernel64.ld
+CFLAGS_KERNEL += -mcmodel=kernel
+CFLAGS_KERNEL += -mno-red-zone -ffreestanding
+LDFLAGS_KERNEL += -z max-page-size=0x1000
 else
 CROSS_COMPILE := i686-ros-
+BITS := 32
+KERNEL_LD := kernel32.ld
 endif
+
+# BITS is used in Kbuilds, so we can select bit-specific source files.
+export BITS
index 06ec86b..5a9d83e 100644 (file)
@@ -105,7 +105,7 @@ void lapic_print_isr(void)
 /* Returns TRUE if the bit 'vector' is set in the LAPIC ISR or IRR (whatever you
  * pass in.  These registers consist of 8, 32 byte registers spaced every 16
  * bytes from the base in the LAPIC. */
-static bool __lapic_get_isrr_bit(uint32_t base, uint8_t vector)
+static bool __lapic_get_isrr_bit(unsigned long base, uint8_t vector)
 {
        int which_reg = vector >> 5;    /* 32 bits per reg */
        uint32_t *lapic_reg = (uint32_t*)(base + which_reg * 0x10);     /* offset 16 */
index 47dec11..9bd89fb 100644 (file)
 #define PIC_READ_ISR                           0x0b    /* OCW3 irq service next CMD read */
 
 // Local APIC
-/* PBASE is the physical address.  It is mapped in at the VADDR LAPIC_BASE */
+/* PBASE is the physical address.  It is mapped in at the VADDR LAPIC_BASE.
+ * 64 bit note: it looks like this is mapped to the same place in 64 bit address
+ * spaces.  We just happen to have a slight 'hole' in addressable physical
+ * memory.  We can move the PBASE, but we're limited to 32 bit (physical)
+ * addresses. */
 #define LAPIC_PBASE                                    0xfee00000 /* default *physical* address */
 #define LAPIC_EOI                                      (LAPIC_BASE + 0x0b0)
 #define LAPIC_SPURIOUS                         (LAPIC_BASE + 0x0f0)
index 0efd46d..5042f97 100644 (file)
@@ -8,30 +8,31 @@
 
 /* Arch Constants */
 #define ARCH_CL_SIZE                            64
-/* Top of the kernel virtual mapping area (KERNBASE) */
-/* For sanity reasons, I don't plan to map the top page */
-#define KERN_VMAP_TOP                          0xfffff000
-
-static __inline void breakpoint(void) __attribute__((always_inline));
-static __inline void invlpg(void *SNT addr) __attribute__((always_inline));
-static __inline void tlbflush(void) __attribute__((always_inline));
-static __inline void icache_flush_page(void* va, void* kva) __attribute__((always_inline));
-static __inline uint64_t read_tsc(void) __attribute__((always_inline));
-static __inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
-static __inline void enable_irq(void) __attribute__((always_inline));
-static __inline void disable_irq(void) __attribute__((always_inline));
-static __inline void enable_irqsave(int8_t* state) __attribute__((always_inline));
-static __inline void disable_irqsave(int8_t* state) __attribute__((always_inline));
-static __inline void cpu_relax(void) __attribute__((always_inline));
-static __inline void cpu_halt(void) __attribute__((always_inline));
-static __inline void clflush(uintptr_t* addr) __attribute__((always_inline));
-static __inline int irq_is_enabled(void) __attribute__((always_inline));
-static __inline int get_hw_coreid(uint32_t coreid);
-static __inline int hw_core_id(void) __attribute__((always_inline));
-static __inline int get_os_coreid(int hw_coreid);
-static __inline int core_id(void) __attribute__((always_inline));
-static __inline void cache_flush(void) __attribute__((always_inline));
-static __inline void reboot(void) __attribute__((always_inline)) __attribute__((noreturn));
+
+static inline void breakpoint(void) __attribute__((always_inline));
+static inline void invlpg(void *addr) __attribute__((always_inline));  
+static inline void tlbflush(void) __attribute__((always_inline));
+static inline void icache_flush_page(void *va, void *kva)
+              __attribute__((always_inline));
+static inline uint64_t read_tsc(void) __attribute__((always_inline));
+static inline uint64_t read_tscp(void) __attribute__((always_inline));
+static inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
+static inline void enable_irq(void) __attribute__((always_inline));
+static inline void disable_irq(void) __attribute__((always_inline));
+static inline void enable_irqsave(int8_t *state) __attribute__((always_inline));
+static inline void disable_irqsave(int8_t *state)
+              __attribute__((always_inline));
+static inline void cpu_relax(void) __attribute__((always_inline));
+static inline void cpu_halt(void) __attribute__((always_inline));
+static inline void clflush(uintptr_t* addr) __attribute__((always_inline));
+static inline int irq_is_enabled(void) __attribute__((always_inline));
+static inline int get_hw_coreid(uint32_t coreid) __attribute__((always_inline));
+static inline int hw_core_id(void) __attribute__((always_inline));
+static inline int get_os_coreid(int hw_coreid) __attribute__((always_inline));
+static inline int core_id(void) __attribute__((always_inline));
+static inline void cache_flush(void) __attribute__((always_inline));
+static inline void reboot(void)
+              __attribute__((always_inline)) __attribute__((noreturn));
 
 /* in trap.c */
 void send_ipi(uint32_t os_coreid, uint8_t vector);
@@ -40,74 +41,64 @@ void print_cpuinfo(void);
 void show_mapping(uintptr_t start, size_t size);
 
 /* declared in smp.c */
-int hw_coreid_lookup[MAX_NUM_CPUS];
-int os_coreid_lookup[MAX_NUM_CPUS];
+extern int hw_coreid_lookup[MAX_NUM_CPUS];
+extern int os_coreid_lookup[MAX_NUM_CPUS];
 
-static __inline void
-breakpoint(void)
+static inline void breakpoint(void)
 {
-       __asm __volatile("int3");
+       asm volatile("int3");
 }
 
-static __inline void 
-invlpg(void *addr)
+static inline void invlpg(void *addr)
 { 
-       __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
+       asm volatile("invlpg (%0)" : : "r" (addr) : "memory");
 }  
 
-static __inline void
-tlbflush(void)
+static inline void tlbflush(void)
 {
-       uint32_t cr3;
-       __asm __volatile("movl %%cr3,%0" : "=r" (cr3));
-       __asm __volatile("movl %0,%%cr3" : : "r" (cr3));
+       unsigned long cr3;
+       asm volatile("mov %%cr3,%0" : "=r" (cr3));
+       asm volatile("mov %0,%%cr3" : : "r" (cr3));
 }
 
-static __inline void
-icache_flush_page(void* va, void* kva)
+static inline void icache_flush_page(void *va, void *kva)
 {
        // x86 handles self-modifying code (mostly) without SW support
 }
 
-static __inline uint64_t
-read_tsc(void)
+static inline uint64_t read_tsc(void)
 {
-       uint64_t tsc;
-       __asm __volatile("rdtsc" : "=A" (tsc));
-       return tsc;
+       uint32_t edx, eax;
+       asm volatile("rdtsc" : "=d"(edx), "=a"(eax));
+       return (uint64_t)edx << 32 | eax;
 }
 
 /* non-core-id reporting style (it is in ecx) */
-static __inline uint64_t
-read_tscp(void)
+static inline uint64_t read_tscp(void)
 {
-       uint64_t tsc;
-       __asm __volatile("rdtscp" : "=A" (tsc) : : "ecx");
-       return tsc;
+       uint32_t edx, eax;
+       asm volatile("rdtscp" : "=d"(edx), "=a"(eax) : : X86_REG_CX);
+       return (uint64_t)edx << 32 | eax;
 }
 
 /* Check out k/a/x86/rdtsc_test.c for more info */
-static __inline uint64_t 
-read_tsc_serialized(void)
+static inline uint64_t read_tsc_serialized(void)
 {
        asm volatile("lfence"); /* mfence on amd */
        return read_tsc();
 }
 
-static __inline void
-enable_irq(void)
+static inline void enable_irq(void)
 {
        asm volatile("sti");
 }
 
-static __inline void
-disable_irq(void)
+static inline void disable_irq(void)
 {
        asm volatile("cli");
 }
 
-static __inline void
-enable_irqsave(int8_t* state)
+static inline void enable_irqsave(int8_t *state)
 {
        // *state tracks the number of nested enables and disables
        // initial value of state: 0 = first run / no favorite
@@ -126,8 +117,7 @@ enable_irqsave(int8_t* state)
                (*state)++;
 }
 
-static __inline void
-disable_irqsave(int8_t* state)
+static inline void disable_irqsave(int8_t *state)
 {
        if ((*state == 0) && irq_is_enabled())
                disable_irq();
@@ -135,48 +125,41 @@ disable_irqsave(int8_t* state)
                (*state)--;
 }
 
-static __inline void
-cpu_relax(void)
+static inline void cpu_relax(void)
 {
        __cpu_relax();
 }
 
 /* This doesn't atomically enable interrupts and then halt, like we want, so
  * x86 needs to use a custom helper in the irq handler in trap.c. */
-static __inline void
-cpu_halt(void)
+static inline void cpu_halt(void)
 {
        asm volatile("sti; hlt" : : : "memory");
 }
 
-static __inline void
-clflush(uintptr_t* addr)
+static inline void clflush(uintptr_t* addr)
 {
        asm volatile("clflush %0" : : "m"(*addr));
 }
 
-static __inline int
-irq_is_enabled(void)
+static inline int irq_is_enabled(void)
 {
-       return read_eflags() & FL_IF;
+       return read_flags() & FL_IF;
 }
 
 /* os_coreid -> hw_coreid */
-static __inline int
-get_hw_coreid(uint32_t coreid)
+static inline int get_hw_coreid(uint32_t coreid)
 {
        return hw_coreid_lookup[coreid];
 }
 
-static __inline int
-hw_core_id(void)
+static inline int hw_core_id(void)
 {
        return lapic_get_id();
 }
 
 /* hw_coreid -> os_coreid */
-static __inline int
-get_os_coreid(int hw_coreid)
+static inline int get_os_coreid(int hw_coreid)
 {
        return os_coreid_lookup[hw_coreid];
 }
@@ -184,24 +167,21 @@ get_os_coreid(int hw_coreid)
 /* core_id() returns the OS core number, not to be confused with the
  * hardware-specific core identifier (such as the lapic id) returned by
  * hw_core_id() */
-static __inline int
-core_id(void)
+static inline int core_id(void)
 {
        return get_os_coreid(hw_core_id());
 }
 
-static __inline void
-cache_flush(void)
+static inline void cache_flush(void)
 {
        wbinvd();
 }
 
-static __inline void
-reboot(void)
+static inline void reboot(void)
 {
        outb(0x92, 0x3);
-       asm volatile ("movl $0, %esp; int $0");
-       while(1);
+       asm volatile ("mov $0, %"X86_REG_SP"; int $0");
+       while (1);
 }
 
 #endif /* !ROS_INC_ARCH_H */
index 839cb3e..687421a 100644 (file)
 #include <arch/x86.h>
 #include <arch/arch.h>
 
-static inline void atomic_andb(volatile uint8_t RACY* number, uint8_t mask);
-static inline void atomic_orb(volatile uint8_t RACY* number, uint8_t mask);
+static inline void atomic_andb(volatile uint8_t *number, uint8_t mask);
+static inline void atomic_orb(volatile uint8_t *number, uint8_t mask);
 
 /* Inlined functions declared above */
 static inline void atomic_init(atomic_t *number, long val)
 {
-       asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
+       asm volatile("mov %1,%0" : "=m"(*number) : "r"(val));
 }
 
 static inline long atomic_read(atomic_t *number)
 {
        long val;
-       asm volatile("movl %1,%0" : "=r"(val) : "m"(*number));
+       asm volatile("mov %1,%0" : "=r"(val) : "m"(*number));
        return val;
 }
 
 static inline void atomic_set(atomic_t *number, long val)
 {
-       asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
+       asm volatile("mov %1,%0" : "=m"(*number) : "r"(val));
 }
 
 static inline void atomic_add(atomic_t *number, long val)
 {
-       asm volatile("lock addl %1,%0" : "=m"(*number) : "r"(val) : "cc");
+       __sync_fetch_and_add(number, val);
 }
 
-// need to do this with pointers and deref.  %0 needs to be the memory address
 static inline void atomic_inc(atomic_t *number)
 {
-       asm volatile("lock incl %0" : "=m"(*number) : : "cc");
+       __sync_fetch_and_add(number, 1);
 }
 
 static inline void atomic_dec(atomic_t *number)
 {
-       // for instance, this doesn't work:
-       //asm volatile("lock decl (%0)" : "=r"(number) : : "cc");
-       asm volatile("lock decl %0" : "=m"(*number) : : "cc");
+       __sync_fetch_and_sub(number, 1);
 }
 
-/* Adds val to number, returning number's original value */
 static inline long atomic_fetch_and_add(atomic_t *number, long val)
 {
-       asm volatile("lock xadd %0,%1" : "=r"(val), "=m"(*number)
-                                      : "0"(val), "m"(*number)
-                                      : "cc" );
-       return val;
+       return (long)__sync_fetch_and_add(number, val);
 }
 
 static inline void atomic_and(atomic_t *number, long mask)
 {
-       asm volatile("lock andl %1,%0" : "=m"(*number) : "q"(mask) : "cc");
+       __sync_fetch_and_and(number, mask);
 }
 
 static inline void atomic_or(atomic_t *number, long mask)
 {
-       asm volatile("lock orl %1,%0" : "=m"(*number) : "q"(mask) : "cc");
+       __sync_fetch_and_or(number, mask);
 }
 
 static inline long atomic_swap(atomic_t *addr, long val)
 {
-       // this would work, but its code is bigger, and it's not like the others
-       //asm volatile("xchgl %0,(%2)" : "=r"(val) : "0"(val), "r"(addr) : "memory");
-       asm volatile("xchgl %0,%1" : "=r"(val), "=m"(*addr) : "0"(val), "m"(*addr));
-       return val;
+       /* This poorly named function does an xchg */
+       return (long)__sync_lock_test_and_set(addr, val);
 }
 
-/* reusing exp_val for the bool return.  1 (TRUE) for success (like test).  Need
- * to zero eax, since it will get set if the cmpxchgl failed. */
 static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
 {
-       asm volatile("lock cmpxchgl %4,%1; movl $0,%%eax; sete %%al"
-                    : "=a"(exp_val), "=m"(*addr)
-                    : "m"(*addr), "a"(exp_val), "r"(new_val)
-                    : "cc", "memory");
-       return exp_val;
+       return __sync_bool_compare_and_swap(addr, exp_val, new_val);
 }
 
 static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
 {
-       return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
+       return __sync_bool_compare_and_swap(addr, exp_val, new_val);
 }
 
 static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
                                   uint32_t new_val)
 {
-       return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
+       return __sync_bool_compare_and_swap(addr, exp_val, new_val);
 }
 
 /* Adds val to number, so long as number was not zero.  Returns TRUE if the
@@ -114,7 +99,7 @@ static inline bool atomic_add_not_zero(atomic_t *number, long val)
        return TRUE;
 }
 
-/* Subtraces val from number, returning True if the new value is 0. */
+/* Subtracts val from number, returning True if the new value is 0. */
 static inline bool atomic_sub_and_test(atomic_t *number, long val)
 {
        bool b;
@@ -124,18 +109,14 @@ static inline bool atomic_sub_and_test(atomic_t *number, long val)
        return b;
 }
 
-/* Be sure to use "q" for byte operations (compared to longs), since this
- * constrains the asm to use e{a,b,c,d}x instead of esi and edi.  32 bit x86
- * cannot access the lower parts of esi or edi (will get warnings like "no such
- * register %sil or %dil." */
-static inline void atomic_andb(volatile uint8_t RACY*number, uint8_t mask)
+static inline void atomic_andb(volatile uint8_t *number, uint8_t mask)
 {
-       asm volatile("lock andb %1,%0" : "=m"(*number) : "q"(mask) : "cc");
+       __sync_fetch_and_and(number, mask);
 }
 
-static inline void atomic_orb(volatile uint8_t RACY*number, uint8_t mask)
+static inline void atomic_orb(volatile uint8_t *number, uint8_t mask)
 {
-       asm volatile("lock orb %1,%0" : "=m"(*number) : "q"(mask) : "cc");
+       __sync_fetch_and_or(number, mask);
 }
 
 static inline bool spin_locked(spinlock_t *lock)
index 9233299..1e81e20 100644 (file)
@@ -147,10 +147,9 @@ void print_cpuinfo(void)
 
 void show_mapping(uintptr_t start, size_t size)
 {
-       pde_t LCKD(&vpd_lock) *CT(PTSIZE) pgdir =
-           (pde_t LCKD(&vpd_lock) *CT(PTSIZE))vpd;
+       pde_t *pgdir = (pde_t*)vpd;
        pte_t *pte;
-       pte_t LCKD(&vpd_lock) *pde;
+       pte_t *pde;
        page_t *page;
        uintptr_t i;
 
diff --git a/kern/arch/x86/entry.S b/kern/arch/x86/entry.S
deleted file mode 100644 (file)
index 7852761..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Copyright (c) 2009-13 The Regents of the University of California
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details. */
-
-#include <arch/mmu.h>
-#include <arch/trap.h>
-#include <ros/memlayout.h>
-
-# Shift Right Logical 
-#define SRL(val, shamt)                (((val) >> (shamt)) & ~(-1 << (32 - (shamt))))
-
-.set CODE_SEL,0x8              # index of code seg within mygdt
-.set DATA_SEL,0x10             # index of data seg within mygdt
-
-#define MULTIBOOT_PAGE_ALIGN  (1<<0)
-#define MULTIBOOT_MEMORY_INFO (1<<1)
-#define MULTIBOOT_HEADER_MAGIC (0x1BADB002)
-#define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN)
-#define CHECKSUM (-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS))
-
-# The kernel bootstrap (this code) is linked and loaded at physical address
-# 0x00100000 (1MB), which is the start of extended memory.  (See kernel.ld)
-
-# Flagging boottext to be text.  Check out:
-# http://sourceware.org/binutils/docs/as/Section.html
-.section .boottext, "awx"
-
-.code32
-.align 4
-multiboot_header:
-.long MULTIBOOT_HEADER_MAGIC
-.long MULTIBOOT_HEADER_FLAGS
-.long CHECKSUM
-
-.globl         _start
-_start:
-       movw    $0x1234,0x472                   # warm boot
-       # Reload all segment registers (including CS!) with flag segment selectors
-       # from our boot GDT.
-       lgdt    mygdtdesc
-       movl    $DATA_SEL, %eax
-       movw    %ax,%ds
-       movw    %ax,%es
-       movw    %ax,%ss
-       ljmp    $CODE_SEL,$newcs                # reload CS by jumping
-newcs:
-       # build page table.  need a mapping for current code at 0x00100000 and a
-       # basic kernbase mapping.  we're using the 32 bit second PT (aka, pg_dir),
-       # which covers 4MB per entry
-       movl    $boot_pdt, %edx
-       # identity map the first jumbo PTE from 0x0 -> 0x0
-       movl    $(PTE_P | PTE_W | PTE_PS), (%edx)
-       # map KERNBASE -> 0 for 200 MB
-       movl    $50, %ecx
-       # init loop, eax at paddr 0, and edx is advanced by KERNBASE mapping slots
-       # (with 4 bytes per PTE).
-       addl    $((KERNBASE >> PTSHIFT) << 2), %edx
-       movl    $(PTE_P | PTE_W | PTE_PS), %eax
-loop:
-       movl    %eax, (%edx)
-       addl    $PTSIZE, %eax
-       addl    $4, %edx
-       decl    %ecx
-       jnz             loop
-       # load cr3 and turn on paging.  note we assume PSE support.  if we didn't
-       # have it, then our jumbo page mappings are going to fail.
-       movl    $boot_pdt, %eax
-       movl    %eax, %cr3
-       movl    %cr4, %eax
-       orl             $(CR4_PSE | CR4_PGE), %eax
-       movl    %eax, %cr4
-       movl    %cr0, %eax
-       orl             $(CR0_PE | CR0_PG | CR0_AM | CR0_WP | CR0_NE | CR0_MP), %eax  
-       andl    $(~(CR0_TS | CR0_EM | CR0_CD | CR0_NW)), %eax  
-       movl    %eax, %cr0
-       # paging is on, and our code is still running at 0x00100000 do some
-       # miscellaneous OS setup.  the coreid stuff is so we can call core_id()
-       # before smp_boot.  this is the only arch-dependent code called before then.
-       movl    $0x0, os_coreid_lookup
-       movl    $0x0, hw_coreid_lookup
-       # Clear the frame pointer register (EBP)
-       # so that once we get into debugging C code,
-       # stack backtraces will be terminated properly.
-       movl    $0x0,%ebp
-       movl    $(bootstacktop),%esp
-       # Save multiboot info
-       push    %ebx
-       movl    $0x1,num_cpus           # init global var, for now
-       call    kernel_init
-       # Should never get here, but in case we do, just spin.
-spin:  jmp     spin
-
-.section .bootdata, "aw"
-       .p2align        2               # force 4 byte alignment
-mygdt:
-       SEG_NULL                        # null seg
-       SEG(STA_X|STA_R, 0, 0xffffffff) # code seg
-       SEG(STA_W, 0, 0xffffffff)       # data seg
-mygdtdesc:
-       .word   0x17            # sizeof(mygdt) - 1
-       .long   mygdt           # address mygdt
-# boot page directory.  going to use jumbo page entries
-       .align PGSIZE
-boot_pdt:
-       .space  PGSIZE
-
-
-# From here down is linked for KERNBASE
-
-###################################################################    
-# See <inc/memlayout.h> 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/arch/x86/entry32.S b/kern/arch/x86/entry32.S
new file mode 100644 (file)
index 0000000..7852761
--- /dev/null
@@ -0,0 +1,128 @@
+/* Copyright (c) 2009-13 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details. */
+
+#include <arch/mmu.h>
+#include <arch/trap.h>
+#include <ros/memlayout.h>
+
+# Shift Right Logical 
+#define SRL(val, shamt)                (((val) >> (shamt)) & ~(-1 << (32 - (shamt))))
+
+.set CODE_SEL,0x8              # index of code seg within mygdt
+.set DATA_SEL,0x10             # index of data seg within mygdt
+
+#define MULTIBOOT_PAGE_ALIGN  (1<<0)
+#define MULTIBOOT_MEMORY_INFO (1<<1)
+#define MULTIBOOT_HEADER_MAGIC (0x1BADB002)
+#define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN)
+#define CHECKSUM (-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS))
+
+# The kernel bootstrap (this code) is linked and loaded at physical address
+# 0x00100000 (1MB), which is the start of extended memory.  (See kernel.ld)
+
+# Flagging boottext to be text.  Check out:
+# http://sourceware.org/binutils/docs/as/Section.html
+.section .boottext, "awx"
+
+.code32
+.align 4
+multiboot_header:
+.long MULTIBOOT_HEADER_MAGIC
+.long MULTIBOOT_HEADER_FLAGS
+.long CHECKSUM
+
+.globl         _start
+_start:
+       movw    $0x1234,0x472                   # warm boot
+       # Reload all segment registers (including CS!) with flag segment selectors
+       # from our boot GDT.
+       lgdt    mygdtdesc
+       movl    $DATA_SEL, %eax
+       movw    %ax,%ds
+       movw    %ax,%es
+       movw    %ax,%ss
+       ljmp    $CODE_SEL,$newcs                # reload CS by jumping
+newcs:
+       # build page table.  need a mapping for current code at 0x00100000 and a
+       # basic kernbase mapping.  we're using the 32 bit second PT (aka, pg_dir),
+       # which covers 4MB per entry
+       movl    $boot_pdt, %edx
+       # identity map the first jumbo PTE from 0x0 -> 0x0
+       movl    $(PTE_P | PTE_W | PTE_PS), (%edx)
+       # map KERNBASE -> 0 for 200 MB
+       movl    $50, %ecx
+       # init loop, eax at paddr 0, and edx is advanced by KERNBASE mapping slots
+       # (with 4 bytes per PTE).
+       addl    $((KERNBASE >> PTSHIFT) << 2), %edx
+       movl    $(PTE_P | PTE_W | PTE_PS), %eax
+loop:
+       movl    %eax, (%edx)
+       addl    $PTSIZE, %eax
+       addl    $4, %edx
+       decl    %ecx
+       jnz             loop
+       # load cr3 and turn on paging.  note we assume PSE support.  if we didn't
+       # have it, then our jumbo page mappings are going to fail.
+       movl    $boot_pdt, %eax
+       movl    %eax, %cr3
+       movl    %cr4, %eax
+       orl             $(CR4_PSE | CR4_PGE), %eax
+       movl    %eax, %cr4
+       movl    %cr0, %eax
+       orl             $(CR0_PE | CR0_PG | CR0_AM | CR0_WP | CR0_NE | CR0_MP), %eax  
+       andl    $(~(CR0_TS | CR0_EM | CR0_CD | CR0_NW)), %eax  
+       movl    %eax, %cr0
+       # paging is on, and our code is still running at 0x00100000 do some
+       # miscellaneous OS setup.  the coreid stuff is so we can call core_id()
+       # before smp_boot.  this is the only arch-dependent code called before then.
+       movl    $0x0, os_coreid_lookup
+       movl    $0x0, hw_coreid_lookup
+       # Clear the frame pointer register (EBP)
+       # so that once we get into debugging C code,
+       # stack backtraces will be terminated properly.
+       movl    $0x0,%ebp
+       movl    $(bootstacktop),%esp
+       # Save multiboot info
+       push    %ebx
+       movl    $0x1,num_cpus           # init global var, for now
+       call    kernel_init
+       # Should never get here, but in case we do, just spin.
+spin:  jmp     spin
+
+.section .bootdata, "aw"
+       .p2align        2               # force 4 byte alignment
+mygdt:
+       SEG_NULL                        # null seg
+       SEG(STA_X|STA_R, 0, 0xffffffff) # code seg
+       SEG(STA_W, 0, 0xffffffff)       # data seg
+mygdtdesc:
+       .word   0x17            # sizeof(mygdt) - 1
+       .long   mygdt           # address mygdt
+# boot page directory.  going to use jumbo page entries
+       .align PGSIZE
+boot_pdt:
+       .space  PGSIZE
+
+
+# From here down is linked for KERNBASE
+
+###################################################################    
+# See <inc/memlayout.h> 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/arch/x86/entry64.S b/kern/arch/x86/entry64.S
new file mode 100644 (file)
index 0000000..41cf0cb
--- /dev/null
@@ -0,0 +1,141 @@
+/* Copyright (c) 2009-13 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details. */
+
+#include <arch/mmu.h>
+#include <arch/trap.h>
+#include <ros/memlayout.h>
+
+# Shift Right Logical 
+#define SRL(val, shamt)                (((val) >> (shamt)) & ~(-1 << (32 - (shamt))))
+
+.set CODE_SEL,0x8              # index of code seg within mygdt
+.set DATA_SEL,0x10             # index of data seg within mygdt
+
+#define MULTIBOOT_PAGE_ALIGN  (1<<0)
+#define MULTIBOOT_MEMORY_INFO (1<<1)
+#define MULTIBOOT_HEADER_MAGIC (0x1BADB002)
+#define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN)
+#define CHECKSUM (-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS))
+
+# The kernel bootstrap (this code) is linked and loaded at physical address
+# 0x00100000 (1MB), which is the start of extended memory.  (See kernel.ld)
+
+# Flagging boottext to be text.  Check out:
+# http://sourceware.org/binutils/docs/as/Section.html
+.section .boottext, "awx"
+
+.code32
+.align 4
+multiboot_header:
+.long MULTIBOOT_HEADER_MAGIC
+.long MULTIBOOT_HEADER_FLAGS
+.long CHECKSUM
+
+.globl         _start
+_start:
+       movw    $0x1234,0x472                   # warm boot
+       # Reload all segment registers (including CS!) with flag segment selectors
+       # from our boot GDT.
+       lgdt    mygdtdesc
+       movl    $DATA_SEL, %eax
+       movw    %ax,%ds
+       movw    %ax,%es
+       movw    %ax,%ss
+       ljmp    $CODE_SEL,$newcs                # reload CS by jumping
+newcs:
+       # build page table.  need a mapping for current code at 0x00100000 and a
+       # basic kernbase mapping.  we're using the 32 bit second PT (aka, pg_dir),
+       # which covers 4MB per entry
+       movl    $boot_pdt, %edx
+       # identity map the first jumbo PTE from 0x0 -> 0x0
+       movl    $(PTE_P | PTE_W | PTE_PS), (%edx)
+       # map KERNBASE -> 0 for 200 MB
+       movl    $50, %ecx
+       # init loop, eax at paddr 0, and edx is advanced by KERNBASE mapping slots
+       # (with 4 bytes per PTE).
+       # XXX addl      $((KERNBASE >> PTSHIFT) << 2), %edx
+       movl    $(PTE_P | PTE_W | PTE_PS), %eax
+loop:
+       movl    %eax, (%edx)
+       addl    $PTSIZE, %eax
+       addl    $4, %edx
+       decl    %ecx
+       jnz             loop
+
+# hack to compile / link
+spin2:
+       jmp spin2
+
+       # load cr3 and turn on paging.  note we assume PSE support.  if we didn't
+       # have it, then our jumbo page mappings are going to fail.
+       movl    $boot_pdt, %eax
+       movl    %eax, %cr3
+       movl    %cr4, %eax
+       orl             $(CR4_PSE | CR4_PGE), %eax
+       movl    %eax, %cr4
+       movl    %cr0, %eax
+       orl             $(CR0_PE | CR0_PG | CR0_AM | CR0_WP | CR0_NE | CR0_MP), %eax  
+       andl    $(~(CR0_TS | CR0_EM | CR0_CD | CR0_NW)), %eax  
+       movl    %eax, %cr0
+       # paging is on, and our code is still running at 0x00100000 do some
+       # miscellaneous OS setup.  the coreid stuff is so we can call core_id()
+       # before smp_boot.  this is the only arch-dependent code called before then.
+.code64 # temp hack for linkage.  also, this symbol is too far at link time
+       movabs  $(os_coreid_lookup), %rax
+       movl    $0x0, (%rax)
+       movabs  $(hw_coreid_lookup), %rax
+       movl    $0x0, (%rax)
+       # Clear the frame pointer register (EBP)
+       # so that once we get into debugging C code,
+       # stack backtraces will be terminated properly.
+       movl    $0x0,%ebp
+       movabs  $(bootstacktop),%rsp
+       # Save multiboot info
+       push    %rbx
+       movabs  $(num_cpus), %rax
+       movl    $0x1, (%rax)
+
+       movabs  $(kernel_init), %rax
+       call    *%rax
+       # Should never get here, but in case we do, just spin.
+spin:  jmp     spin
+
+.section .bootdata, "aw"
+       .p2align        2               # force 4 byte alignment
+mygdt:
+       SEG_NULL                        # null seg
+       SEG(STA_X|STA_R, 0, 0xffffffff) # code seg
+       SEG(STA_W, 0, 0xffffffff)       # data seg
+mygdtdesc:
+       .word   0x17            # sizeof(mygdt) - 1
+       .long   mygdt           # address mygdt
+# boot page directory.  going to use jumbo page entries
+       .align PGSIZE
+boot_pdt:
+       .space  PGSIZE
+
+
+# From here down is linked for KERNBASE
+
+###################################################################    
+# See <inc/memlayout.h> for a complete description of these two symbols.
+###################################################################
+.data
+       .globl  vpt
+       .quad   vpt
+       .set    vpt, VPT
+       .globl  vpd
+       .quad   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/arch/x86/env.c b/kern/arch/x86/env.c
deleted file mode 100644 (file)
index d1da684..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* See COPYRIGHT for copyright information. */
-#ifdef __SHARC__
-#pragma nosharc
-#endif
-
-#include <trap.h>
-#include <env.h>
-#include <assert.h>
-#include <pmap.h>
-#include <smp.h>
-
-/* Walks len bytes from start, executing 'callback' on every PTE, passing it a
- * specific VA and whatever arg is passed in.  Note, this cannot handle jumbo
- * pages. */
-int env_user_mem_walk(env_t* e, void* start, size_t len,
-                      mem_walk_callback_t callback, void* arg)
-{
-       pte_t *pt;
-       uint32_t pdeno, pteno;
-       physaddr_t pa;
-
-       assert((uintptr_t)start % PGSIZE == 0 && len % PGSIZE == 0);
-       void* end = (char*)start+len;
-       uint32_t pdeno_start = PDX(start);
-       uint32_t pdeno_end = PDX(ROUNDUP(end,PTSIZE));
-       /* concerned about overflow.  this should catch it for now, given the above
-        * assert. */
-       assert((len == 0) || (pdeno_start < pdeno_end));
-
-       for (pdeno = pdeno_start; pdeno < pdeno_end; pdeno++) {
-               if (!(e->env_pgdir[pdeno] & PTE_P))
-                       continue;
-               /* find the pa and a pointer to the page table */
-               pa = PTE_ADDR(e->env_pgdir[pdeno]);
-               pt = (pte_t*COUNT(NPTENTRIES)) KADDR(pa);
-               /* figure out where we start and end within the page table */
-               uint32_t pteno_start = (pdeno == pdeno_start ? PTX(start) : 0);
-               uint32_t pteno_end = (pdeno == pdeno_end - 1 && PTX(end) != 0 ?
-                                     PTX(end) : NPTENTRIES );
-               int ret;
-               for (pteno = pteno_start; pteno < pteno_end; pteno++) {
-                       if (!PAGE_UNMAPPED(pt[pteno]))
-                               if((ret = callback(e, &pt[pteno], PGADDR(pdeno, pteno, 0), arg)))
-                                       return ret;
-               }
-       }
-       return 0;
-}
-
-/* Frees (decrefs) all pages of the process's page table, including the page
- * directory.  Does not free the memory that is actually mapped. */
-void env_pagetable_free(env_t* e)
-{
-       static_assert(UVPT % PTSIZE == 0);
-       assert(e->env_cr3 != rcr3());
-       for(uint32_t pdeno = 0; pdeno < PDX(UVPT); pdeno++)
-       {
-               // only look at mapped page tables
-               if (!(e->env_pgdir[pdeno] & PTE_P))
-                       continue;
-
-               // find the pa and va of the page table
-               physaddr_t pa = PTE_ADDR(e->env_pgdir[pdeno]);
-
-               // free the page table itself
-               e->env_pgdir[pdeno] = 0;
-               page_decref(pa2page(pa));
-       }
-
-       // free the page directory
-       physaddr_t pa = e->env_cr3;
-       e->env_cr3 = 0;
-       page_decref(pa2page(pa));
-       tlbflush();
-}
-
index d07142e..adb1e08 100644 (file)
@@ -22,7 +22,9 @@
  * @todo Come up with an impliment a concurrency model for use of the route/unroute functions
  * @todo Once we begin using logical core ID's for groups, adjust route/unroute to utilize this (adjust high word)
  * @todo Some notion of a 'initalized' flag we can check to ensure bootup call order.
- */
+ *
+ * TODO: fix the formatting and make helper functions.  it's hard to see what
+ * the heck is going on, esp with the rite_mmregs. */
 
 #include <arch/mmu.h>
 #include <arch/x86.h>
@@ -101,7 +103,7 @@ void ioapic_init() {
                if (dst_apic_id == INVALID_DEST_APIC)
                        continue;
                        
-               if (ioapic_redirects[i].ioapic_address != NULL) {
+               if (ioapic_redirects[i].ioapic_address != 0) {
                        // This is technically a lie. We could in theory handle this, so long as
                        //  everything agrees.... however this shouldnt ever really happen
                        //  as this means we have both PCI and ISA claiming an interrupt
@@ -160,7 +162,8 @@ void ioapic_init() {
 
 void ioapic_route_irq(uint8_t irq, uint8_t dest) {
        
-       if (((irq + KERNEL_IRQ_OFFSET) >= NUM_IRQS) || (ioapic_redirects[irq].ioapic_address == NULL)) {
+       if (((irq + KERNEL_IRQ_OFFSET) >= NUM_IRQS) ||
+           (ioapic_redirects[irq].ioapic_address == 0)) {
                panic("TRYING TO REROUTE AN INVALID IRQ!");
        }
 
@@ -179,10 +182,10 @@ void ioapic_route_irq(uint8_t irq, uint8_t dest) {
        
        // YOU MUST MUST MUST MUST MUST MUST MUST write the high bits first. If you don't, you get interrupts going to crazy places
        // Ask Paul about that afternoon of his life.
-       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int + 1);
-       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address  + IOAPIC_WRITE_WINDOW_OFFSET, redirect_high);
-       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int);
-       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address  + IOAPIC_WRITE_WINDOW_OFFSET, redirect_low);
+       write_mmreg32(ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int + 1);
+       write_mmreg32(ioapic_redirects[irq].ioapic_address  + IOAPIC_WRITE_WINDOW_OFFSET, redirect_high);
+       write_mmreg32(ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int);
+       write_mmreg32(ioapic_redirects[irq].ioapic_address  + IOAPIC_WRITE_WINDOW_OFFSET, redirect_low);
 }
 
 /** @brief Reconfigure the correct IOAPIC to no longer route a given irq to any core
@@ -200,15 +203,16 @@ void ioapic_route_irq(uint8_t irq, uint8_t dest) {
   */
 void ioapic_unroute_irq(uint8_t irq) {
 
-       if (((irq + KERNEL_IRQ_OFFSET) >= NUM_IRQS) || (ioapic_redirects[irq].ioapic_address == NULL)) {
+       if (((irq + KERNEL_IRQ_OFFSET) >= NUM_IRQS) ||
+           (ioapic_redirects[irq].ioapic_address == 0)) {
                panic("TRYING TO REROUTE AN INVALID IRQ!");
        }
        
        // Must write low first, else we will reroute to a wrong core for a split before turning off
-       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int);
-       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address  + IOAPIC_WRITE_WINDOW_OFFSET, IOAPIC_UNROUTE_LOW);
+       write_mmreg32(ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int);
+       write_mmreg32(ioapic_redirects[irq].ioapic_address  + IOAPIC_WRITE_WINDOW_OFFSET, IOAPIC_UNROUTE_LOW);
        
-       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int + 1);
-       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address  + IOAPIC_WRITE_WINDOW_OFFSET, IOAPIC_UNROUTE_HIGH);
+       write_mmreg32(ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int + 1);
+       write_mmreg32(ioapic_redirects[irq].ioapic_address  + IOAPIC_WRITE_WINDOW_OFFSET, IOAPIC_UNROUTE_HIGH);
 
 }
index 39d0226..b3de524 100644 (file)
@@ -45,7 +45,7 @@
  *             Ioapic ADDR (physical Addr)
  */
 typedef struct IOAPICREDIRECT {
-    void*                      ioapic_address; // NULL means invalid
+    uintptr_t          ioapic_address; /* 0 means invalid */
        uint8_t                 ioapic_flags;
        uint8_t                 ioapic_int;
 } ioapic_redirect_t;
index 94af666..7c4b1f7 100644 (file)
@@ -307,17 +307,17 @@ void *debug_get_fn_addr(char *fn_name)
 void backtrace(void)
 { 
        extern char (SNT RO _start)[];
-       uint32_t *ebp, eip;
+       unsigned long *ebp, eip;
        eipdebuginfo_t debuginfo;
        char buf[256];
        int j, i = 1;
-       ebp = (uint32_t*)read_ebp();
+       ebp = (unsigned long*)read_bp();
        // this is part of the way back into the call() instruction's bytes
        // eagle-eyed readers should be able to explain why this is good enough,
        // and retaddr (just *(ebp + 1) is not)
        eip = *(ebp + 1) - 1;
        // jump back a frame (out of backtrace)
-       ebp = (uint32_t*)(*ebp);
+       ebp = (unsigned long*)(*ebp);
        printk("Stack Backtrace on Core %d:\n", core_id());
        // on each iteration, ebp holds the stack frame and eip an addr in that func
        while (1) {
@@ -326,8 +326,8 @@ void backtrace(void)
                strncpy(buf, debuginfo.eip_fn_name, MIN(debuginfo.eip_fn_namelen, 256));
                buf[MIN(debuginfo.eip_fn_namelen, 255)] = 0;
                cprintf("#%02d [<%p>] in %s+%x(%p) from %s:%d\n", i++,  eip, buf, 
-                       debuginfo.eip_fn_addr - (uint32_t)_start, debuginfo.eip_fn_addr, 
-                       debuginfo.eip_file, debuginfo.eip_line);
+                       debuginfo.eip_fn_addr - (uintptr_t)_start,
+                       debuginfo.eip_fn_addr, debuginfo.eip_file, debuginfo.eip_line);
                cprintf("    ebp: %x   Args:", ebp);
                for (j = 0; j < MIN(debuginfo.eip_fn_narg, 5); j++)
                        cprintf(" %08x", *(ebp + 2 + j));
@@ -335,7 +335,7 @@ void backtrace(void)
                if (!ebp)
                        break;
                eip = *(ebp + 1) - 1;
-               ebp = (uint32_t*)(*ebp);
+               ebp = (unsigned long*)(*ebp);
                #ifdef CONFIG_RESET_STACKS
                if (!strncmp("__smp_idle", debuginfo.eip_fn_name, 10))
                        break;
index 291d8c4..025a3b6 100644 (file)
@@ -16,7 +16,7 @@
  * site.  Returns 0 when we can't jump back any farther. */
 static inline uintptr_t get_caller_pc(void)
 {
-       uint32_t *ebp = (uint32_t*)read_ebp();
+       unsigned long *ebp = (unsigned long*)read_bp();
        if (!ebp)
                return 0;
        /* this is part of the way back into the call() instruction's bytes
diff --git a/kern/arch/x86/kernel.ld b/kern/arch/x86/kernel.ld
deleted file mode 100644 (file)
index 87e4a11..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Simple linker script for the ROS 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)
-KERNBASE = 0xc0000000;
-
-SECTIONS
-{
-       /* Entry Linked and loaded at 0x00100000 (includes multiboot) */
-       . = 0x00100000;
-
-       .bootstrap : {
-               *(.boottext .bootdata)
-       }
-
-       /* Link the main kernel for the space after entry + KERNBASE.  We'll still
-        * load it adjacent in physical memory */
-       . += KERNBASE;
-
-       .text : AT(ADDR(.text) - KERNBASE) {
-               *(.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 = .);
-               PROVIDE(__STAB_BEGIN__ = .);
-               *(.stab);
-               PROVIDE(estab = .);
-               PROVIDE(__STAB_END__ = .);
-               BYTE(0)         /* Force the linker to allocate space
-                                  for this section */
-       }
-
-       .stabstr : {
-               PROVIDE(stabstr = .);
-               PROVIDE(__STABSTR_BEGIN__ = .);
-               *(.stabstr);
-               PROVIDE(estabstr = .);
-               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)
-               *(COMMON)
-       }
-
-       PROVIDE(end = .);
-
-       /DISCARD/ : {
-               *(.eh_frame .note.GNU-stack)
-       }
-}
diff --git a/kern/arch/x86/kernel32.ld b/kern/arch/x86/kernel32.ld
new file mode 100644 (file)
index 0000000..87e4a11
--- /dev/null
@@ -0,0 +1,73 @@
+/* Simple linker script for the ROS 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)
+KERNBASE = 0xc0000000;
+
+SECTIONS
+{
+       /* Entry Linked and loaded at 0x00100000 (includes multiboot) */
+       . = 0x00100000;
+
+       .bootstrap : {
+               *(.boottext .bootdata)
+       }
+
+       /* Link the main kernel for the space after entry + KERNBASE.  We'll still
+        * load it adjacent in physical memory */
+       . += KERNBASE;
+
+       .text : AT(ADDR(.text) - KERNBASE) {
+               *(.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 = .);
+               PROVIDE(__STAB_BEGIN__ = .);
+               *(.stab);
+               PROVIDE(estab = .);
+               PROVIDE(__STAB_END__ = .);
+               BYTE(0)         /* Force the linker to allocate space
+                                  for this section */
+       }
+
+       .stabstr : {
+               PROVIDE(stabstr = .);
+               PROVIDE(__STABSTR_BEGIN__ = .);
+               *(.stabstr);
+               PROVIDE(estabstr = .);
+               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)
+               *(COMMON)
+       }
+
+       PROVIDE(end = .);
+
+       /DISCARD/ : {
+               *(.eh_frame .note.GNU-stack)
+       }
+}
diff --git a/kern/arch/x86/kernel64.ld b/kern/arch/x86/kernel64.ld
new file mode 100644 (file)
index 0000000..d76bbc9
--- /dev/null
@@ -0,0 +1,70 @@
+/* Simple linker script for the ROS kernel.
+   See the GNU ld 'info' manual ("info ld") to learn the syntax. */
+
+/* This script needs to be invoked with -z max-page-size=0x1000.  Otherwise,
+ * ld will offset our first section to 1MB within the actual file.  Multiboot
+ * requires the header to be in the first two pages. */
+
+/* We're lying about our output format, so that grub thinks we are a 32 bit elf
+ * and just loads our sections.  Since we're getting loaded into low memory, it
+ * doesn't really matter (to grub) what our VMAs are.  Our LMAs are fine as
+ * either 32 or 64 bit. */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386:x86-64)
+/* This is for a pure 64 bit elf: 
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+*/
+ENTRY(_start)
+KERN_LOAD_ADDR = 0xffffffffc0000000;
+
+SECTIONS
+{
+       /* Entry Linked and loaded at 0x00100000 (includes multiboot) */
+       . = 0x00100000;
+
+       .bootstrap : {
+               *(.boottext .bootdata)
+       }
+
+       /* Link the main kernel for the space after entry + KERN_LOAD_ADDR.  We'll
+        * still load it adjacent in physical memory */
+       . += KERN_LOAD_ADDR;
+
+       .text : AT(ADDR(.text) - KERN_LOAD_ADDR) {
+               *(.text .stub .text.* .gnu.linkonce.t.*)
+       }
+
+       PROVIDE(etext = .);     /* Define the 'etext' symbol to this value */
+
+       .rodata : {
+               *(.rodata .rodata.* .gnu.linkonce.r.*)
+       }
+
+       /* TODO: add some debug info.  i hear stabs are 32 bit only, so we'll need
+        * to bring in some dwarves.  for now, hack in the symbols to compile. */
+       PROVIDE(__STAB_BEGIN__ = .);
+       PROVIDE(__STAB_END__ = .);
+       PROVIDE(__STABSTR_BEGIN__ = .);
+       PROVIDE(__STABSTR_END__ = .);
+
+       /* Adjust the address for the data segment to the next page */
+       . = ALIGN(0x1000);
+
+       /* The data segment */
+       .data : {
+               *(.data)
+       }
+
+       PROVIDE(edata = .);
+
+       .bss : {
+               *(.bss)
+               *(COMMON)
+       }
+
+       PROVIDE(end = .);
+
+       /DISCARD/ : {
+               *(.eh_frame .note.GNU-stack)
+       }
+}
index 9cd58ec..bdde2a3 100644 (file)
@@ -186,7 +186,7 @@ void mptables_parse() {
                mptables_info("Virtual Wire\n");
        }
        
-       configuration_parse((physaddr_t)KADDR((uint32_t)(mpfps->pap)));
+       configuration_parse((physaddr_t)KADDR((uintptr_t)(mpfps->pap)));
        
        proc_parse();
        bus_parse();
index afee595..e8126ec 100644 (file)
@@ -179,7 +179,7 @@ typedef struct IOAPICENTRY {
     uint8_t    apic_id;
     uint8_t    apic_version;
     uint8_t    apic_flags;
-    void*      apic_address;
+    uintptr_t  apic_address;
 } ioapic_entry_t;
 
 typedef struct INTENTRY {
index 6039636..694a0d9 100644 (file)
@@ -58,6 +58,7 @@ void page_alloc_init()
        //     Some of it is in use, some is free.
        int i;
        extern char (SNT RO end)[];
+       /* TODO 64b Might need to translate to the KERNBASE mapping */
        physaddr_t physaddr_after_kernel = PADDR(PTRROUNDUP(boot_freemem, PGSIZE));
 
        page_setref(&pages[0], 1);
index 051f336..14c6d22 100644 (file)
 #define ENABLE_PERFCTR 0x00400000
 #define DISABLE_PERFCTR 0xFFAFFFFF
 
-
-static __inline uint64_t
-read_pmc(uint32_t index)
-{                                                                                                    
-    uint64_t pmc;
-
-    __asm __volatile("rdpmc" : "=A" (pmc) : "c" (index)); 
-    return pmc;                                                                                      
+static inline uint64_t read_pmc(uint32_t index)
+{
+       uint32_t edx, eax;
+       asm volatile("rdpmc" : "=d"(edx), "=a"(eax) : "c"(index));
+       return (uint64_t)edx << 32 | eax;
 }
 
 void perfmon_init();
index 6c0c94d..2fe9f56 100644 (file)
@@ -1,9 +1,9 @@
-#ifdef __SHARC__
-#pragma nosharc
-#define SINIT(x) x
-#endif
+/* Copyright (c) 2009 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Physical memory managment, common to 32 and 64 bit */
 
-/* See COPYRIGHT for copyright information. */
 #include <arch/x86.h>
 #include <arch/arch.h>
 #include <arch/mmu.h>
 #include <kmalloc.h>
 #include <page_alloc.h>
 
-// These variables are set in i386_vm_init()
-pde_t* boot_pgdir;             // Virtual address of boot time page directory
-physaddr_t RO boot_cr3;                // Physical address of boot time page directory
-
-// Global variables
-page_t *RO pages = NULL;          // Virtual address of physical page array
-
-// Global descriptor table.
-//
-// The kernel and user segments are identical (except for the DPL).
-// To load the SS register, the CPL must equal the DPL.  Thus,
-// we must duplicate the segments for the user and the kernel.
-//
-segdesc_t gdt[] =
-{
-       // 0x0 - unused (always faults -- for trapping NULL far pointers)
-       SEG_NULL,
-
-       // 0x8 - kernel code segment
-       [GD_KT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 0),
-
-       // 0x10 - kernel data segment
-       [GD_KD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 0),
-
-       // 0x18 - user code segment
-       [GD_UT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 3),
-
-       // 0x20 - user data segment
-       [GD_UD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 3),
-
-       // 0x28 - tss, initialized in idt_init()
-       [GD_TSS >> 3] = SEG_NULL,
-
-       // 0x30 - LDT, set per-process
-       [GD_LDT >> 3] = SEG_NULL
-};
-
-pseudodesc_t gdt_pd = {
-       sizeof(gdt) - 1, (unsigned long) gdt
-};
-
-static int
-nvram_read(int r)
+static int nvram_read(int r)
 {
        return mc146818_read(r) | (mc146818_read(r + 1) << 8);
 }
@@ -82,107 +40,6 @@ bool enable_pse(void)
                return 0;
 }
 
-// --------------------------------------------------------------
-// Set up initial memory mappings and turn on MMU.
-// --------------------------------------------------------------
-
-static void check_boot_pgdir(bool pse);
-
-//
-// Given pgdir, a pointer to a page directory,
-// walk the 2-level page table structure to find
-// the page table entry (PTE) for linear address la.
-// Return a pointer to this PTE.
-//
-// If the relevant page table doesn't exist in the page directory:
-//     - If create == 0, return 0.
-//     - Otherwise allocate a new page table, install it into pgdir,
-//       and return a pointer into it.
-//        (Questions: What data should the new page table contain?
-//       And what permissions should the new pgdir entry have?
-//       Note that we use the 486-only "WP" feature of %cr0, which
-//       affects the way supervisor-mode writes are checked.)
-//
-// This function abstracts away the 2-level nature of
-// the page directory by allocating new page tables
-// as needed.
-// 
-// boot_pgdir_walk may ONLY be used during initialization,
-// before the page_free_list has been set up.
-// It should panic on failure.  (Note that boot_alloc already panics
-// on failure.)
-//
-// Supports returning jumbo (4MB PSE) PTEs.  To create with a jumbo, pass in 2.
-// 
-// Maps non-PSE PDEs as U/W.  W so the kernel can, U so the user can read via
-// UVPT.  UVPT security comes from the UVPT mapping (U/R).  All other kernel pages
-// protected at the second layer
-static pte_t*
-boot_pgdir_walk(pde_t *COUNT(NPDENTRIES) pgdir, uintptr_t la, int create)
-{
-       pde_t* the_pde = &pgdir[PDX(la)];
-       void* new_table;
-
-       if (*the_pde & PTE_P) {
-               if (*the_pde & PTE_PS)
-                       return (pte_t*)the_pde;
-               return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(la)];
-       }
-       if (!create)
-               return NULL;
-       if (create == 2) {
-               if (JPGOFF(la))
-                       panic("Attempting to find a Jumbo PTE at an unaligned VA!");
-               *the_pde = PTE_PS | PTE_P;
-               return (pte_t*)the_pde;
-       }
-       new_table = boot_alloc(PGSIZE, PGSIZE);
-       memset(new_table, 0, PGSIZE);
-       *the_pde = (pde_t)PADDR(new_table) | PTE_P | PTE_W | PTE_U | PTE_G;
-       return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(la)];
-}
-
-//
-// Map [la, la+size) of linear address space to physical [pa, pa+size)
-// in the page table rooted at pgdir.  Size is a multiple of PGSIZE.
-// Use permission bits perm|PTE_P for the entries.
-//
-// This function may ONLY be used during initialization,
-// before the page_free_list has been set up.
-//
-// To map with Jumbos, set PTE_PS in perm
-static void
-boot_map_segment(pde_t *COUNT(NPDENTRIES) pgdir, uintptr_t la, size_t size, physaddr_t pa, int perm)
-{
-       uintptr_t i;
-       pte_t *pte;
-       // la can be page unaligned, but weird things will happen
-       // unless pa has the same offset.  pa always truncates any
-       // possible offset.  will warn.  size can be weird too. 
-       if (PGOFF(la)) {
-               warn("la not page aligned in boot_map_segment!");
-               size += PGOFF(la);
-       }
-       if (perm & PTE_PS) {
-               if (JPGOFF(la) || JPGOFF(pa))
-                       panic("Tried to map a Jumbo page at an unaligned address!");
-               // need to index with i instead of la + size, in case of wrap-around
-               for (i = 0; i < size; i += JPGSIZE, la += JPGSIZE, pa += JPGSIZE) {
-                       pte = boot_pgdir_walk(pgdir, la, 2);
-                       *pte = PTE_ADDR(pa) | PTE_P | perm;
-               }
-       } else {
-               for (i = 0; i < size; i += PGSIZE, la += PGSIZE, pa += PGSIZE) {
-                       pte = boot_pgdir_walk(pgdir, la, 1);
-                       if (*pte & PTE_PS)
-                               // if we start using the extra flag for PAT, which we aren't,
-                               // this will warn, since PTE_PS and PTE_PAT are the same....
-                               warn("Possibly attempting to map a regular page into a Jumbo PDE");
-                       *pte = PTE_ADDR(pa) | PTE_P | perm;
-               }
-       }
-}
-
 // could consider having an API to allow these to dynamically change
 // MTRRs are for physical, static ranges.  PAT are linear, more granular, and 
 // more dynamic
@@ -242,376 +99,6 @@ void setup_default_mtrrs(barrier_t* smp_barrier)
        enable_irqsave(&state);
 }
 
-
-// Set up a two-level page table:
-//    boot_pgdir is its linear (virtual) address of the root
-//    boot_cr3 is the physical adresss of the root
-// Then turn on paging.  Then effectively turn off segmentation.
-// (i.e., the segment base addrs are set to zero).
-// 
-// This function only sets up the kernel part of the address space
-// (ie. addresses >= ULIM).  The user part of the address space
-// will be setup later.
-//
-// From UWLIM to ULIM, the user is allowed to read but not write.
-// Above ULIM the user cannot read (or write). 
-void
-vm_init(void)
-{
-       pde_t* pgdir;
-       uint32_t cr0, edx;
-       size_t n;
-       bool pse;
-
-       pse = enable_pse();
-       if (pse)
-               cprintf("PSE capability detected.\n");
-
-       // we paniced earlier if we don't support PGE.  turn it on now.
-       // it's used in boot_map_segment, which covers all of the mappings that are
-       // the same for all address spaces.  and also for the VPT mapping below.
-       lcr4(rcr4() | CR4_PGE);
-
-       // set up mtrr's for core0.  other cores will do the same later
-       setup_default_mtrrs(0);
-
-       /*
-        * PSE status: 
-        * - can walk and set up boot_map_segments with jumbos but can't
-        *   insert yet.  need to look at the page_dir and friends.
-        * - anything related to a single struct page still can't handle 
-        *   jumbos.  will need to think about and adjust Page functions
-        * - do we want to store info like this in the struct page?  or just check
-        *   by walking the PTE
-        * - when we alloc a page, and we want it to be 4MB, we'll need
-        *   to have contiguous memory, etc
-        * - there's a difference between having 4MB page table entries
-        *   and having 4MB Page tracking structs.  changing the latter will
-        *   break a lot of things
-        * - showmapping and friends work on a 4KB granularity, but map to the
-        *   correct entries
-        * - need to not insert / boot_map a single page into an area that is 
-        *   already holding a jumbo page.  will need to break the jumbo up so that
-        *   we can then insert the lone page.  currently warns.
-        * - some inherent issues with the pgdir_walks returning a PTE, and we
-        *   don't know whether it is a jumbo (PDE) or a regular PTE.
-        */
-
-       //////////////////////////////////////////////////////////////////////
-       // create initial page directory.
-       pgdir = boot_alloc(PGSIZE, PGSIZE);
-       memset(pgdir, 0, PGSIZE);
-       boot_pgdir = pgdir;
-       boot_cr3 = PADDR(pgdir);
-       // helpful if you want to manually walk with kvm / bochs
-       //printk("pgdir va = %p, pgdir pa = %p\n\n", pgdir, PADDR(pgdir));
-
-       //////////////////////////////////////////////////////////////////////
-       // Recursively insert PD in itself as a page table, to form
-       // a virtual page table at virtual address VPT.
-       // (For now, you don't have understand the greater purpose of the
-       // following two lines.  Unless you are eagle-eyed, in which case you
-       // should already know.)
-
-       // Permissions: kernel RW, user NONE, Global Page
-       pgdir[PDX(VPT)] = PADDR(pgdir) | PTE_W | PTE_P | PTE_G;
-
-       // same for UVPT
-       // Permissions: kernel R, user R, Global Page
-       pgdir[PDX(UVPT)] = PADDR(pgdir) | PTE_U | PTE_P | PTE_G;
-
-       //////////////////////////////////////////////////////////////////////
-       // Map all of physical memory at KERNBASE. 
-       // Ie.  the VA range [KERNBASE, 2^32) should map to
-       //      the PA range [0, 2^32 - KERNBASE)
-       // We might not have 2^32 - KERNBASE bytes of physical memory, but
-       // we just set up the mapping anyway.
-       // Permissions: kernel RW, user NONE
-       // Your code goes here: 
-       
-       // this maps all of the possible phys memory
-       // note the use of unsigned underflow to get size = 0x40000000
-       //boot_map_segment(pgdir, KERNBASE, -KERNBASE, 0, PTE_W);
-       // but this only maps what is available, and saves memory.  every 4MB of
-       // mapped memory requires a 2nd level page: 2^10 entries, each covering 2^12
-       // need to modify tests below to account for this
-       if (pse) {
-               // map the first 4MB as regular entries, to support different MTRRs
-               boot_map_segment(pgdir, KERNBASE, JPGSIZE, 0, PTE_W | PTE_G);
-               boot_map_segment(pgdir, KERNBASE + JPGSIZE, maxaddrpa - JPGSIZE, JPGSIZE,
-                                PTE_W | PTE_G | PTE_PS);
-       } else
-               boot_map_segment(pgdir, KERNBASE, maxaddrpa, 0, PTE_W | PTE_G);
-
-       // APIC mapping: using PAT (but not *the* PAT flag) to make these type UC
-       // IOAPIC
-       boot_map_segment(pgdir, IOAPIC_BASE, PGSIZE, IOAPIC_PBASE, 
-                        PTE_PCD | PTE_PWT | PTE_W | PTE_G);
-       // Local APIC
-       boot_map_segment(pgdir, LAPIC_BASE, PGSIZE, LAPIC_PBASE,
-                        PTE_PCD | PTE_PWT | PTE_W | PTE_G);
-
-       // Check that the initial page directory has been set up correctly.
-       check_boot_pgdir(pse);
-
-       //////////////////////////////////////////////////////////////////////
-       // On x86, segmentation maps a VA to a LA (linear addr) and
-       // paging maps the LA to a PA.  I.e. VA => LA => PA.  If paging is
-       // turned off the LA is used as the PA.  Note: there is no way to
-       // turn off segmentation.  The closest thing is to set the base
-       // address to 0, so the VA => LA mapping is the identity.
-
-       // Current mapping: VA KERNBASE+x => PA x.
-       //     (segmentation base=-KERNBASE and paging is off)
-
-       // From here on down we must maintain this VA KERNBASE + x => PA x
-       // mapping, even though we are turning on paging and reconfiguring
-       // segmentation.
-
-       // Map VA 0:4MB same as VA KERNBASE, i.e. to PA 0:4MB.
-       // (Limits our kernel to <4MB)
-       /* They mean linear address 0:4MB, and the kernel < 4MB is only until 
-        * segmentation is turned off.
-        * once we turn on paging, segmentation is still on, so references to
-        * KERNBASE+x will get mapped to linear address x, which we need to make 
-        * sure can map to phys addr x, until we can turn off segmentation and
-        * KERNBASE+x maps to LA KERNBASE+x, which maps to PA x, via paging
-        */
-       pgdir[0] = pgdir[PDX(KERNBASE)];
-
-       // Install page table.
-       lcr3(boot_cr3);
-
-       // Turn on paging.
-       cr0 = rcr0();
-       // CD and NW should already be on, but just in case these turn on caching
-       cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP;
-       cr0 &= ~(CR0_TS|CR0_EM|CR0_CD|CR0_NW);
-       lcr0(cr0);
-
-       // Current mapping: KERNBASE+x => x => x.
-       // (x < 4MB so uses paging pgdir[0])
-
-       // Reload all segment registers.
-       asm volatile("lgdt gdt_pd");
-       asm volatile("movw %%ax,%%gs" :: "a" (GD_UD|3));
-       asm volatile("movw %%ax,%%fs" :: "a" (GD_UD|3));
-       asm volatile("movw %%ax,%%es" :: "a" (GD_KD));
-       asm volatile("movw %%ax,%%ds" :: "a" (GD_KD));
-       asm volatile("movw %%ax,%%ss" :: "a" (GD_KD));
-       asm volatile("ljmp %0,$1f\n 1:\n" :: "i" (GD_KT));  // reload cs
-       asm volatile("lldt %%ax" :: "a" (0));
-
-       // Final mapping: KERNBASE+x => KERNBASE+x => x.
-
-       // This mapping was only used after paging was turned on but
-       // before the segment registers were reloaded.
-       pgdir[0] = 0;
-
-       // Flush the TLB for good measure, to kill the pgdir[0] mapping.
-       tlb_flush_global();
-}
-
-//
-// Checks that the kernel part of virtual address space
-// has been setup roughly correctly(by i386_vm_init()).
-//
-// This function doesn't test every corner case,
-// in fact it doesn't test the permission bits at all,
-// but it is a pretty good sanity check. 
-//
-static physaddr_t check_va2pa(pde_t *COUNT(NPDENTRIES) pgdir, uintptr_t va);
-
-static void
-check_boot_pgdir(bool pse)
-{
-       uint32_t i, n;
-       pde_t *pgdir, pte;
-
-       pgdir = boot_pgdir;
-
-       // check phys mem
-       //for (i = 0; KERNBASE + i != 0; i += PGSIZE)
-       // adjusted check to account for only mapping avail mem
-       if (pse)
-               for (i = 0; i < maxaddrpa; i += JPGSIZE)
-                       assert(check_va2pa(pgdir, KERNBASE + i) == i);
-       else
-               for (i = 0; i < maxaddrpa; i += PGSIZE)
-                       assert(check_va2pa(pgdir, KERNBASE + i) == i);
-
-       // check for zero/non-zero in PDEs
-       for (i = 0; i < NPDENTRIES; i++) {
-               switch (i) {
-               case PDX(VPT):
-               case PDX(UVPT):
-               case PDX(LAPIC_BASE): // LAPIC mapping.  TODO: remove when MTRRs are up
-                       assert(pgdir[i]);
-                       break;
-               default:
-                       //if (i >= PDX(KERNBASE))
-                       // adjusted check to account for only mapping avail mem
-                       // and you can't KADDR maxpa (just above legal range)
-                       // maxaddrpa can be up to maxpa, so assume the worst
-                       if (i >= PDX(KERNBASE) && i <= PDX(KADDR(maxaddrpa-1)))
-                               assert(pgdir[i]);
-                       else
-                               assert(pgdir[i] == 0);
-                       break;
-               }
-       }
-
-       /* check permissions
-        * user read-only.  check for user and write, should be only user
-        * eagle-eyed viewers should be able to explain the extra cases.
-        * for the mongoose-eyed, remember that weird shit happens when you loop
-        * through UVPT.  Specifically, you can't loop once, then look at a jumbo
-        * page that is kernel only.  That's the end of the page table for you, so
-        * having a U on the entry doesn't make sense.  Thus we check for a jumbo
-        * page, and special case it.  This will happen at 0xbf701000.  Why is this
-        * magical?  Get your eagle glasses and figure it out. */
-       for (i = UWLIM; i < ULIM; i+=PGSIZE) {
-               pte = get_va_perms(pgdir, (void*SAFE)TC(i));
-               if (pte & PTE_P) {
-                       if (i == UVPT+(VPT >> 10))
-                               continue;
-                       if (*pgdir_walk(pgdir, (void*SAFE)TC(i), 0) & PTE_PS) {
-                               assert((pte & PTE_U) != PTE_U);
-                               assert((pte & PTE_W) != PTE_W);
-                       } else {
-                               assert((pte & PTE_U) == PTE_U);
-                               assert((pte & PTE_W) != PTE_W);
-                       }
-               }
-       }
-       // kernel read-write.
-       for (i = ULIM; i <= KERNBASE + maxaddrpa - PGSIZE; i+=PGSIZE) {
-               pte = get_va_perms(pgdir, (void*SAFE)TC(i));
-               if ((pte & PTE_P) && (i != VPT+(UVPT>>10))) {
-                       assert((pte & PTE_U) != PTE_U);
-                       assert((pte & PTE_W) == PTE_W);
-               }
-       }
-       // special mappings
-       pte = get_va_perms(pgdir, (void*SAFE)TC(UVPT+(VPT>>10)));
-       assert((pte & PTE_U) != PTE_U);
-       assert((pte & PTE_W) != PTE_W);
-
-       // note this means the kernel cannot directly manipulate this virtual address
-       // convince yourself this isn't a big deal, eagle-eyes!
-       pte = get_va_perms(pgdir, (void*SAFE)TC(VPT+(UVPT>>10)));
-       assert((pte & PTE_U) != PTE_U);
-       assert((pte & PTE_W) != PTE_W);
-
-       cprintf("check_boot_pgdir() succeeded!\n");
-}
-
-// This function returns the physical address of the page containing 'va',
-// defined by the page directory 'pgdir'.  The hardware normally performs
-// this functionality for us!  We define our own version to help check
-// the check_boot_pgdir() function; it shouldn't be used elsewhere.
-
-static physaddr_t
-check_va2pa(pde_t *COUNT(NPDENTRIES) _pgdir, uintptr_t va)
-{
-       pte_t *COUNT(NPTENTRIES) p;
-       pde_t *COUNT(1) pgdir;
-
-       pgdir = &_pgdir[PDX(va)];
-       if (!(*pgdir & PTE_P))
-               return ~0;
-       if (*pgdir & PTE_PS)
-               return PTE_ADDR(*pgdir);
-       p = (pte_t*COUNT(NPTENTRIES)) KADDR(PTE_ADDR(*pgdir));
-       if (!(p[PTX(va)] & PTE_P))
-               return ~0;
-       return PTE_ADDR(p[PTX(va)]);
-}
-
-/* 
- * Remove the second level page table associated with virtual address va.
- * Will 0 out the PDE for that page table.
- * Panics if the page table has any present entries.
- * This should be called rarely and with good cause.
- * Currently errors if the PDE is jumbo or not present.
- */
-error_t        pagetable_remove(pde_t *pgdir, void *va)
-{
-       pde_t* the_pde = &pgdir[PDX(va)];
-
-       if (!(*the_pde & PTE_P) || (*the_pde & PTE_PS))
-               return -EFAULT;
-       pte_t* page_table = (pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde));
-       for (int i = 0; i < NPTENTRIES; i++) 
-               if (page_table[i] & PTE_P)
-                       panic("Page table not empty during attempted removal!");
-       *the_pde = 0;
-       page_decref(pa2page(PADDR(page_table)));
-       return 0;
-}
-
-// Given 'pgdir', a pointer to a page directory, pgdir_walk returns
-// a pointer to the page table entry (PTE) for linear address 'va'.
-// This requires walking the two-level page table structure.
-//
-// If the relevant page table doesn't exist in the page directory, then:
-//    - If create == 0, pgdir_walk returns NULL.
-//    - Otherwise, pgdir_walk tries to allocate a new page table
-//     with page_alloc.  If this fails, pgdir_walk returns NULL.
-//    - Otherwise, pgdir_walk returns a pointer into the new page table.
-//
-// This is boot_pgdir_walk, but using page_alloc() instead of boot_alloc().
-// Unlike boot_pgdir_walk, pgdir_walk can fail.
-//
-// Hint: you can turn a Page * into the physical address of the
-// page it refers to with page2pa() from kern/pmap.h.
-//
-// Supports returning jumbo (4MB PSE) PTEs.  To create with a jumbo, pass in 2.
-pte_t*
-pgdir_walk(pde_t *pgdir, const void *SNT va, int create)
-{
-       pde_t* the_pde = &pgdir[PDX(va)];
-       page_t *new_table;
-
-       if (*the_pde & PTE_P) {
-               if (*the_pde & PTE_PS)
-                       return (pte_t*)the_pde;
-               return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(va)];
-       }
-       if (!create)
-               return NULL;
-       if (create == 2) {
-               if (JPGOFF(va))
-                       panic("Attempting to find a Jumbo PTE at an unaligned VA!");
-               *the_pde = PTE_PS | PTE_P;
-               return (pte_t*)the_pde;
-       }
-       if (kpage_alloc(&new_table))
-               return NULL;
-       memset(page2kva(new_table), 0, PGSIZE);
-       /* storing our ref to new_table in the PTE */
-       *the_pde = (pde_t)page2pa(new_table) | PTE_P | PTE_W | PTE_U;
-       return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(va)];
-}
-
-/* Returns the effective permissions for PTE_U, PTE_W, and PTE_P on a given
- * virtual address.  Note we need to consider the composition of every PTE in
- * the page table walk. */
-int get_va_perms(pde_t *pgdir, const void *SNT va)
-{
-       pde_t the_pde = pgdir[PDX(va)];
-       pte_t the_pte;
-
-       if (!(the_pde & PTE_P))
-               return 0;
-       if (the_pde & PTE_PS)
-               return the_pde & (PTE_U | PTE_W | PTE_P);
-       the_pte = ((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(the_pde)))[PTX(va)];
-       if (!(the_pte & PTE_P))
-               return 0;
-       return the_pte & the_pde & (PTE_U | PTE_W | PTE_P);
-}
-
 /* Flushes a TLB, including global pages.  We should always have the CR4_PGE
  * flag set, but just in case, we'll check.  Toggling this bit flushes the TLB.
  */
@@ -624,226 +111,3 @@ void tlb_flush_global(void)
        } else 
                lcr3(rcr3());
 }
-
-void
-page_check(void)
-{
-       page_t *pp, *pp0, *pp1, *pp2;
-       page_list_t fl[1024];
-       pte_t *ptep;
-
-       // should be able to allocate three pages
-       pp0 = pp1 = pp2 = 0;
-       assert(kpage_alloc(&pp0) == 0);
-       assert(kpage_alloc(&pp1) == 0);
-       assert(kpage_alloc(&pp2) == 0);
-
-       assert(pp0);
-       assert(pp1 && pp1 != pp0);
-       assert(pp2 && pp2 != pp1 && pp2 != pp0);
-
-       // temporarily steal the rest of the free pages
-       for(int i=0; i<llc_cache->num_colors; i++) {
-               fl[i] = colored_page_free_list[i];
-               LIST_INIT(&colored_page_free_list[i]);
-       }
-
-       // should be no free memory
-       assert(kpage_alloc(&pp) == -ENOMEM);
-
-       // Fill pp1 with bogus data and check for invalid tlb entries
-       memset(page2kva(pp1), 0xFFFFFFFF, PGSIZE);
-
-       // there is no page allocated at address 0
-       assert(page_lookup(boot_pgdir, (void *) 0x0, &ptep) == NULL);
-
-       // there is no free memory, so we can't allocate a page table 
-       assert(page_insert(boot_pgdir, pp1, 0x0, 0) < 0);
-
-       // free pp0 and try again: pp0 should be used for page table
-       page_decref(pp0);
-       assert(page_insert(boot_pgdir, pp1, 0x0, 0) == 0);
-       tlb_invalidate(boot_pgdir, 0x0);
-       // DEP Should have shot down invalid TLB entry - let's check
-       { TRUSTEDBLOCK
-         int *x = 0x0;
-         assert(*x == 0xFFFFFFFF);
-       }
-       assert(PTE_ADDR(boot_pgdir[0]) == page2pa(pp0));
-       assert(check_va2pa(boot_pgdir, 0x0) == page2pa(pp1));
-       assert(kref_refcnt(&pp1->pg_kref) == 2);
-       assert(kref_refcnt(&pp0->pg_kref) == 1);
-
-       // should be able to map pp2 at PGSIZE because pp0 is already allocated for page table
-       assert(page_insert(boot_pgdir, pp2, (void*SNT) PGSIZE, 0) == 0);
-       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
-       assert(kref_refcnt(&pp2->pg_kref) == 2);
-
-       // Make sure that pgdir_walk returns a pointer to the pte and
-       // not the table or some other garbage
-       {
-         pte_t *p = (pte_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(boot_pgdir[PDX(PGSIZE)]));
-         assert(pgdir_walk(boot_pgdir, (void *SNT)PGSIZE, 0) == &p[PTX(PGSIZE)]);
-       }
-
-       // should be no free memory
-       assert(kpage_alloc(&pp) == -ENOMEM);
-
-       // should be able to map pp2 at PGSIZE because it's already there
-       assert(page_insert(boot_pgdir, pp2, (void*SNT) PGSIZE, PTE_U) == 0);
-       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
-       assert(kref_refcnt(&pp2->pg_kref) == 2);
-
-       // Make sure that we actually changed the permission on pp2 when we re-mapped it
-       {
-         pte_t *p = pgdir_walk(boot_pgdir, (void*SNT)PGSIZE, 0);
-         assert(((*p) & PTE_U) == PTE_U);
-       }
-
-       // pp2 should NOT be on the free list
-       // could happen if ref counts are handled sloppily in page_insert
-       assert(kpage_alloc(&pp) == -ENOMEM);
-
-       // should not be able to map at PTSIZE because need free page for page table
-       assert(page_insert(boot_pgdir, pp0, (void*SNT) PTSIZE, 0) < 0);
-
-       // insert pp1 at PGSIZE (replacing pp2)
-       assert(page_insert(boot_pgdir, pp1, (void*SNT) PGSIZE, 0) == 0);
-
-       // should have pp1 at both 0 and PGSIZE, pp2 nowhere, ...
-       assert(check_va2pa(boot_pgdir, 0) == page2pa(pp1));
-       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));
-       // ... and ref counts should reflect this
-       assert(kref_refcnt(&pp1->pg_kref) == 3);
-       assert(kref_refcnt(&pp2->pg_kref) == 1);
-
-       // pp2 should be returned by page_alloc
-       page_decref(pp2);       /* should free it */
-       assert(kpage_alloc(&pp) == 0 && pp == pp2);
-
-       // unmapping pp1 at 0 should keep pp1 at PGSIZE
-       page_remove(boot_pgdir, 0x0);
-       assert(check_va2pa(boot_pgdir, 0x0) == ~0);
-       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));
-       assert(kref_refcnt(&pp1->pg_kref) == 2);
-       assert(kref_refcnt(&pp2->pg_kref) == 1);
-
-       // unmapping pp1 at PGSIZE should free it
-       page_remove(boot_pgdir, (void*SNT) PGSIZE);
-       assert(check_va2pa(boot_pgdir, 0x0) == ~0);
-       assert(check_va2pa(boot_pgdir, PGSIZE) == ~0);
-       assert(kref_refcnt(&pp1->pg_kref) == 1);
-       assert(kref_refcnt(&pp2->pg_kref) == 1);
-       page_decref(pp1);
-
-       // so it should be returned by page_alloc
-       assert(kpage_alloc(&pp) == 0 && pp == pp1);
-
-       // should be no free memory
-       assert(kpage_alloc(&pp) == -ENOMEM);
-
-       // forcibly take pp0 back
-       assert(PTE_ADDR(boot_pgdir[0]) == page2pa(pp0));
-       boot_pgdir[0] = 0;
-       assert(kref_refcnt(&pp0->pg_kref) == 1);
-
-       // Catch invalid pointer addition in pgdir_walk - i.e. pgdir + PDX(va)
-       {
-         // Give back pp0 for a bit
-         page_decref(pp0);
-
-         void *SNT va = (void *SNT)((PGSIZE * NPDENTRIES) + PGSIZE);
-         pte_t *p2 = pgdir_walk(boot_pgdir, va, 1);
-         pte_t *p = (pte_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(boot_pgdir[PDX(va)]));
-         assert(p2 == &p[PTX(va)]);
-
-         // Clean up again
-         boot_pgdir[PDX(va)] = 0;
-       }
-
-       // give free list back
-       for(int i=0; i<llc_cache->num_colors; i++)
-               colored_page_free_list[i] = fl[i];
-
-       // free the pages we took
-       page_decref(pp0);
-       page_decref(pp1);
-       page_decref(pp2);
-       assert(!kref_refcnt(&pp0->pg_kref));
-       assert(!kref_refcnt(&pp1->pg_kref));
-       assert(!kref_refcnt(&pp2->pg_kref));
-
-       cprintf("page_check() succeeded!\n");
-}
-
-/* 
-
-    // testing code for boot_pgdir_walk 
-       pte_t* temp;
-       temp = boot_pgdir_walk(pgdir, VPT + (VPT >> 10), 1);
-       cprintf("pgdir = %p\n", pgdir);
-       cprintf("test recursive walking pte_t* = %p\n", temp);
-       cprintf("test recursive walking entry = %p\n", PTE_ADDR(temp));
-       temp = boot_pgdir_walk(pgdir, 0xc0400000, 1);
-       cprintf("LA = 0xc0400000 = %p\n", temp);
-       temp = boot_pgdir_walk(pgdir, 0xc0400070, 1);
-       cprintf("LA = 0xc0400070 = %p\n", temp);
-       temp = boot_pgdir_walk(pgdir, 0xc0800000, 0);
-       cprintf("LA = 0xc0800000, no create = %p\n", temp);
-       temp = boot_pgdir_walk(pgdir, 0xc0600070, 1);
-       cprintf("LA = 0xc0600070 = %p\n", temp);
-       temp = boot_pgdir_walk(pgdir, 0xc0600090, 0);
-       cprintf("LA = 0xc0600090, nc = %p\n", temp);
-       temp = boot_pgdir_walk(pgdir, 0xc0608070, 0);
-       cprintf("LA = 0xc0608070, nc = %p\n", temp);
-       temp = boot_pgdir_walk(pgdir, 0xc0800070, 1);
-       cprintf("LA = 0xc0800070 = %p\n", temp);
-       temp = boot_pgdir_walk(pgdir, 0xc0b00070, 0);
-       cprintf("LA = 0xc0b00070, nc = %p\n", temp);
-       temp = boot_pgdir_walk(pgdir, 0xc0c00000, 0);
-       cprintf("LA = 0xc0c00000, nc = %p\n", temp);
-
-       // testing for boot_map_seg
-       cprintf("\n");
-       cprintf("before mapping 1 page to 0x00350000\n");
-       cprintf("0xc4000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc4000000, 1));
-       cprintf("0xc4000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc4000000, 1)));
-       boot_map_segment(pgdir, 0xc4000000, 4096, 0x00350000, PTE_W);
-       cprintf("after mapping\n");
-       cprintf("0xc4000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc4000000, 1));
-       cprintf("0xc4000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc4000000, 1)));
-
-       cprintf("\n");
-       cprintf("before mapping 3 pages to 0x00700000\n");
-       cprintf("0xd0000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0000000, 1));
-       cprintf("0xd0000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0000000, 1)));
-       cprintf("0xd0001000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0001000, 1));
-       cprintf("0xd0001000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0001000, 1)));
-       cprintf("0xd0002000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0002000, 1));
-       cprintf("0xd0002000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0002000, 1)));
-       boot_map_segment(pgdir, 0xd0000000, 4096*3, 0x00700000, 0);
-       cprintf("after mapping\n");
-       cprintf("0xd0000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0000000, 1));
-       cprintf("0xd0000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0000000, 1)));
-       cprintf("0xd0001000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0001000, 1));
-       cprintf("0xd0001000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0001000, 1)));
-       cprintf("0xd0002000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0002000, 1));
-       cprintf("0xd0002000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0002000, 1)));
-
-       cprintf("\n");
-       cprintf("before mapping 1 unaligned to 0x00500010\n");
-       cprintf("0xc8000010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8000010, 1));
-       cprintf("0xc8000010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8000010, 1)));
-       cprintf("0xc8001010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8001010, 1));
-       cprintf("0xc8001010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8001010, 1)));
-       boot_map_segment(pgdir, 0xc8000010, 4096, 0x00500010, PTE_W);
-       cprintf("after mapping\n");
-       cprintf("0xc8000010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8000010, 1));
-       cprintf("0xc8000010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8000010, 1)));
-       cprintf("0xc8001010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8001010, 1));
-       cprintf("0xc8001010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8001010, 1)));
-
-       cprintf("\n");
-       boot_map_segment(pgdir, 0xe0000000, 4096, 0x10000000, PTE_W);
-
-*/
diff --git a/kern/arch/x86/pmap32.c b/kern/arch/x86/pmap32.c
new file mode 100644 (file)
index 0000000..b79f9e5
--- /dev/null
@@ -0,0 +1,822 @@
+#ifdef __SHARC__
+#pragma nosharc
+#define SINIT(x) x
+#endif
+
+/* See COPYRIGHT for copyright information. */
+#include <arch/x86.h>
+#include <arch/arch.h>
+#include <arch/mmu.h>
+#include <arch/apic.h>
+
+#include <error.h>
+#include <sys/queue.h>
+
+#include <atomic.h>
+#include <string.h>
+#include <assert.h>
+#include <pmap.h>
+#include <kclock.h>
+#include <env.h>
+#include <stdio.h>
+#include <kmalloc.h>
+#include <page_alloc.h>
+
+// These variables are set in i386_vm_init()
+pde_t* boot_pgdir;             // Virtual address of boot time page directory
+physaddr_t RO boot_cr3;                // Physical address of boot time page directory
+
+// Global variables
+page_t *RO pages = NULL;          // Virtual address of physical page array
+
+// Global descriptor table.
+//
+// The kernel and user segments are identical (except for the DPL).
+// To load the SS register, the CPL must equal the DPL.  Thus,
+// we must duplicate the segments for the user and the kernel.
+//
+segdesc_t gdt[] =
+{
+       // 0x0 - unused (always faults -- for trapping NULL far pointers)
+       SEG_NULL,
+
+       // 0x8 - kernel code segment
+       [GD_KT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 0),
+
+       // 0x10 - kernel data segment
+       [GD_KD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 0),
+
+       // 0x18 - user code segment
+       [GD_UT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 3),
+
+       // 0x20 - user data segment
+       [GD_UD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 3),
+
+       // 0x28 - tss, initialized in idt_init()
+       [GD_TSS >> 3] = SEG_NULL,
+
+       // 0x30 - LDT, set per-process
+       [GD_LDT >> 3] = SEG_NULL
+};
+
+pseudodesc_t gdt_pd = {
+       sizeof(gdt) - 1, (unsigned long) gdt
+};
+
+// --------------------------------------------------------------
+// Set up initial memory mappings and turn on MMU.
+// --------------------------------------------------------------
+
+static void check_boot_pgdir(bool pse);
+
+//
+// Given pgdir, a pointer to a page directory,
+// walk the 2-level page table structure to find
+// the page table entry (PTE) for linear address la.
+// Return a pointer to this PTE.
+//
+// If the relevant page table doesn't exist in the page directory:
+//     - If create == 0, return 0.
+//     - Otherwise allocate a new page table, install it into pgdir,
+//       and return a pointer into it.
+//        (Questions: What data should the new page table contain?
+//       And what permissions should the new pgdir entry have?
+//       Note that we use the 486-only "WP" feature of %cr0, which
+//       affects the way supervisor-mode writes are checked.)
+//
+// This function abstracts away the 2-level nature of
+// the page directory by allocating new page tables
+// as needed.
+// 
+// boot_pgdir_walk may ONLY be used during initialization,
+// before the page_free_list has been set up.
+// It should panic on failure.  (Note that boot_alloc already panics
+// on failure.)
+//
+// Supports returning jumbo (4MB PSE) PTEs.  To create with a jumbo, pass in 2.
+// 
+// Maps non-PSE PDEs as U/W.  W so the kernel can, U so the user can read via
+// UVPT.  UVPT security comes from the UVPT mapping (U/R).  All other kernel pages
+// protected at the second layer
+static pte_t*
+boot_pgdir_walk(pde_t *COUNT(NPDENTRIES) pgdir, uintptr_t la, int create)
+{
+       pde_t* the_pde = &pgdir[PDX(la)];
+       void* new_table;
+
+       if (*the_pde & PTE_P) {
+               if (*the_pde & PTE_PS)
+                       return (pte_t*)the_pde;
+               return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(la)];
+       }
+       if (!create)
+               return NULL;
+       if (create == 2) {
+               if (JPGOFF(la))
+                       panic("Attempting to find a Jumbo PTE at an unaligned VA!");
+               *the_pde = PTE_PS | PTE_P;
+               return (pte_t*)the_pde;
+       }
+       new_table = boot_alloc(PGSIZE, PGSIZE);
+       memset(new_table, 0, PGSIZE);
+       *the_pde = (pde_t)PADDR(new_table) | PTE_P | PTE_W | PTE_U | PTE_G;
+       return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(la)];
+}
+
+//
+// Map [la, la+size) of linear address space to physical [pa, pa+size)
+// in the page table rooted at pgdir.  Size is a multiple of PGSIZE.
+// Use permission bits perm|PTE_P for the entries.
+//
+// This function may ONLY be used during initialization,
+// before the page_free_list has been set up.
+//
+// To map with Jumbos, set PTE_PS in perm
+static void
+boot_map_segment(pde_t *COUNT(NPDENTRIES) pgdir, uintptr_t la, size_t size, physaddr_t pa, int perm)
+{
+       uintptr_t i;
+       pte_t *pte;
+       // la can be page unaligned, but weird things will happen
+       // unless pa has the same offset.  pa always truncates any
+       // possible offset.  will warn.  size can be weird too. 
+       if (PGOFF(la)) {
+               warn("la not page aligned in boot_map_segment!");
+               size += PGOFF(la);
+       }
+       if (perm & PTE_PS) {
+               if (JPGOFF(la) || JPGOFF(pa))
+                       panic("Tried to map a Jumbo page at an unaligned address!");
+               // need to index with i instead of la + size, in case of wrap-around
+               for (i = 0; i < size; i += JPGSIZE, la += JPGSIZE, pa += JPGSIZE) {
+                       pte = boot_pgdir_walk(pgdir, la, 2);
+                       *pte = PTE_ADDR(pa) | PTE_P | perm;
+               }
+       } else {
+               for (i = 0; i < size; i += PGSIZE, la += PGSIZE, pa += PGSIZE) {
+                       pte = boot_pgdir_walk(pgdir, la, 1);
+                       if (*pte & PTE_PS)
+                               // if we start using the extra flag for PAT, which we aren't,
+                               // this will warn, since PTE_PS and PTE_PAT are the same....
+                               warn("Possibly attempting to map a regular page into a Jumbo PDE");
+                       *pte = PTE_ADDR(pa) | PTE_P | perm;
+               }
+       }
+}
+
+// Set up a two-level page table:
+//    boot_pgdir is its linear (virtual) address of the root
+//    boot_cr3 is the physical adresss of the root
+// Then turn on paging.  Then effectively turn off segmentation.
+// (i.e., the segment base addrs are set to zero).
+// 
+// This function only sets up the kernel part of the address space
+// (ie. addresses >= ULIM).  The user part of the address space
+// will be setup later.
+//
+// From UWLIM to ULIM, the user is allowed to read but not write.
+// Above ULIM the user cannot read (or write). 
+void
+vm_init(void)
+{
+       pde_t* pgdir;
+       uint32_t cr0, edx;
+       size_t n;
+       bool pse;
+
+       pse = enable_pse();
+       if (pse)
+               cprintf("PSE capability detected.\n");
+
+       // we paniced earlier if we don't support PGE.  turn it on now.
+       // it's used in boot_map_segment, which covers all of the mappings that are
+       // the same for all address spaces.  and also for the VPT mapping below.
+       lcr4(rcr4() | CR4_PGE);
+
+       // set up mtrr's for core0.  other cores will do the same later
+       setup_default_mtrrs(0);
+
+       /*
+        * PSE status: 
+        * - can walk and set up boot_map_segments with jumbos but can't
+        *   insert yet.  need to look at the page_dir and friends.
+        * - anything related to a single struct page still can't handle 
+        *   jumbos.  will need to think about and adjust Page functions
+        * - do we want to store info like this in the struct page?  or just check
+        *   by walking the PTE
+        * - when we alloc a page, and we want it to be 4MB, we'll need
+        *   to have contiguous memory, etc
+        * - there's a difference between having 4MB page table entries
+        *   and having 4MB Page tracking structs.  changing the latter will
+        *   break a lot of things
+        * - showmapping and friends work on a 4KB granularity, but map to the
+        *   correct entries
+        * - need to not insert / boot_map a single page into an area that is 
+        *   already holding a jumbo page.  will need to break the jumbo up so that
+        *   we can then insert the lone page.  currently warns.
+        * - some inherent issues with the pgdir_walks returning a PTE, and we
+        *   don't know whether it is a jumbo (PDE) or a regular PTE.
+        */
+
+       //////////////////////////////////////////////////////////////////////
+       // create initial page directory.
+       pgdir = boot_alloc(PGSIZE, PGSIZE);
+       memset(pgdir, 0, PGSIZE);
+       boot_pgdir = pgdir;
+       boot_cr3 = PADDR(pgdir);
+       // helpful if you want to manually walk with kvm / bochs
+       //printk("pgdir va = %p, pgdir pa = %p\n\n", pgdir, PADDR(pgdir));
+
+       //////////////////////////////////////////////////////////////////////
+       // Recursively insert PD in itself as a page table, to form
+       // a virtual page table at virtual address VPT.
+       // (For now, you don't have understand the greater purpose of the
+       // following two lines.  Unless you are eagle-eyed, in which case you
+       // should already know.)
+
+       // Permissions: kernel RW, user NONE, Global Page
+       pgdir[PDX(VPT)] = PADDR(pgdir) | PTE_W | PTE_P | PTE_G;
+
+       // same for UVPT
+       // Permissions: kernel R, user R, Global Page
+       pgdir[PDX(UVPT)] = PADDR(pgdir) | PTE_U | PTE_P | PTE_G;
+
+       //////////////////////////////////////////////////////////////////////
+       // Map all of physical memory at KERNBASE. 
+       // Ie.  the VA range [KERNBASE, 2^32) should map to
+       //      the PA range [0, 2^32 - KERNBASE)
+       // We might not have 2^32 - KERNBASE bytes of physical memory, but
+       // we just set up the mapping anyway.
+       // Permissions: kernel RW, user NONE
+       // Your code goes here: 
+       
+       // this maps all of the possible phys memory
+       // note the use of unsigned underflow to get size = 0x40000000
+       //boot_map_segment(pgdir, KERNBASE, -KERNBASE, 0, PTE_W);
+       // but this only maps what is available, and saves memory.  every 4MB of
+       // mapped memory requires a 2nd level page: 2^10 entries, each covering 2^12
+       // need to modify tests below to account for this
+       if (pse) {
+               // map the first 4MB as regular entries, to support different MTRRs
+               boot_map_segment(pgdir, KERNBASE, JPGSIZE, 0, PTE_W | PTE_G);
+               boot_map_segment(pgdir, KERNBASE + JPGSIZE, maxaddrpa - JPGSIZE, JPGSIZE,
+                                PTE_W | PTE_G | PTE_PS);
+       } else
+               boot_map_segment(pgdir, KERNBASE, maxaddrpa, 0, PTE_W | PTE_G);
+
+       // APIC mapping: using PAT (but not *the* PAT flag) to make these type UC
+       // IOAPIC
+       boot_map_segment(pgdir, IOAPIC_BASE, PGSIZE, IOAPIC_PBASE, 
+                        PTE_PCD | PTE_PWT | PTE_W | PTE_G);
+       // Local APIC
+       boot_map_segment(pgdir, LAPIC_BASE, PGSIZE, LAPIC_PBASE,
+                        PTE_PCD | PTE_PWT | PTE_W | PTE_G);
+
+       // Check that the initial page directory has been set up correctly.
+       check_boot_pgdir(pse);
+
+       //////////////////////////////////////////////////////////////////////
+       // On x86, segmentation maps a VA to a LA (linear addr) and
+       // paging maps the LA to a PA.  I.e. VA => LA => PA.  If paging is
+       // turned off the LA is used as the PA.  Note: there is no way to
+       // turn off segmentation.  The closest thing is to set the base
+       // address to 0, so the VA => LA mapping is the identity.
+
+       // Current mapping: VA KERNBASE+x => PA x.
+       //     (segmentation base=-KERNBASE and paging is off)
+
+       // From here on down we must maintain this VA KERNBASE + x => PA x
+       // mapping, even though we are turning on paging and reconfiguring
+       // segmentation.
+
+       // Map VA 0:4MB same as VA KERNBASE, i.e. to PA 0:4MB.
+       // (Limits our kernel to <4MB)
+       /* They mean linear address 0:4MB, and the kernel < 4MB is only until 
+        * segmentation is turned off.
+        * once we turn on paging, segmentation is still on, so references to
+        * KERNBASE+x will get mapped to linear address x, which we need to make 
+        * sure can map to phys addr x, until we can turn off segmentation and
+        * KERNBASE+x maps to LA KERNBASE+x, which maps to PA x, via paging
+        */
+       pgdir[0] = pgdir[PDX(KERNBASE)];
+
+       // Install page table.
+       lcr3(boot_cr3);
+
+       // Turn on paging.
+       cr0 = rcr0();
+       // CD and NW should already be on, but just in case these turn on caching
+       cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP;
+       cr0 &= ~(CR0_TS|CR0_EM|CR0_CD|CR0_NW);
+       lcr0(cr0);
+
+       // Current mapping: KERNBASE+x => x => x.
+       // (x < 4MB so uses paging pgdir[0])
+
+       // Reload all segment registers.
+       asm volatile("lgdt gdt_pd");
+       asm volatile("movw %%ax,%%gs" :: "a" (GD_UD|3));
+       asm volatile("movw %%ax,%%fs" :: "a" (GD_UD|3));
+       asm volatile("movw %%ax,%%es" :: "a" (GD_KD));
+       asm volatile("movw %%ax,%%ds" :: "a" (GD_KD));
+       asm volatile("movw %%ax,%%ss" :: "a" (GD_KD));
+       asm volatile("ljmp %0,$1f\n 1:\n" :: "i" (GD_KT));  // reload cs
+       asm volatile("lldt %%ax" :: "a" (0));
+
+       // Final mapping: KERNBASE+x => KERNBASE+x => x.
+
+       // This mapping was only used after paging was turned on but
+       // before the segment registers were reloaded.
+       pgdir[0] = 0;
+
+       // Flush the TLB for good measure, to kill the pgdir[0] mapping.
+       tlb_flush_global();
+}
+
+//
+// Checks that the kernel part of virtual address space
+// has been setup roughly correctly(by i386_vm_init()).
+//
+// This function doesn't test every corner case,
+// in fact it doesn't test the permission bits at all,
+// but it is a pretty good sanity check. 
+//
+static physaddr_t check_va2pa(pde_t *COUNT(NPDENTRIES) pgdir, uintptr_t va);
+
+static void
+check_boot_pgdir(bool pse)
+{
+       uint32_t i, n;
+       pde_t *pgdir, pte;
+
+       pgdir = boot_pgdir;
+
+       // check phys mem
+       //for (i = 0; KERNBASE + i != 0; i += PGSIZE)
+       // adjusted check to account for only mapping avail mem
+       if (pse)
+               for (i = 0; i < maxaddrpa; i += JPGSIZE)
+                       assert(check_va2pa(pgdir, KERNBASE + i) == i);
+       else
+               for (i = 0; i < maxaddrpa; i += PGSIZE)
+                       assert(check_va2pa(pgdir, KERNBASE + i) == i);
+
+       // check for zero/non-zero in PDEs
+       for (i = 0; i < NPDENTRIES; i++) {
+               switch (i) {
+               case PDX(VPT):
+               case PDX(UVPT):
+               case PDX(LAPIC_BASE): // LAPIC mapping.  TODO: remove when MTRRs are up
+                       assert(pgdir[i]);
+                       break;
+               default:
+                       //if (i >= PDX(KERNBASE))
+                       // adjusted check to account for only mapping avail mem
+                       // and you can't KADDR maxpa (just above legal range)
+                       // maxaddrpa can be up to maxpa, so assume the worst
+                       if (i >= PDX(KERNBASE) && i <= PDX(KADDR(maxaddrpa-1)))
+                               assert(pgdir[i]);
+                       else
+                               assert(pgdir[i] == 0);
+                       break;
+               }
+       }
+
+       /* check permissions
+        * user read-only.  check for user and write, should be only user
+        * eagle-eyed viewers should be able to explain the extra cases.
+        * for the mongoose-eyed, remember that weird shit happens when you loop
+        * through UVPT.  Specifically, you can't loop once, then look at a jumbo
+        * page that is kernel only.  That's the end of the page table for you, so
+        * having a U on the entry doesn't make sense.  Thus we check for a jumbo
+        * page, and special case it.  This will happen at 0xbf701000.  Why is this
+        * magical?  Get your eagle glasses and figure it out. */
+       for (i = UWLIM; i < ULIM; i+=PGSIZE) {
+               pte = get_va_perms(pgdir, (void*SAFE)TC(i));
+               if (pte & PTE_P) {
+                       if (i == UVPT+(VPT >> 10))
+                               continue;
+                       if (*pgdir_walk(pgdir, (void*SAFE)TC(i), 0) & PTE_PS) {
+                               assert((pte & PTE_U) != PTE_U);
+                               assert((pte & PTE_W) != PTE_W);
+                       } else {
+                               assert((pte & PTE_U) == PTE_U);
+                               assert((pte & PTE_W) != PTE_W);
+                       }
+               }
+       }
+       // kernel read-write.
+       for (i = ULIM; i <= KERNBASE + maxaddrpa - PGSIZE; i+=PGSIZE) {
+               pte = get_va_perms(pgdir, (void*SAFE)TC(i));
+               if ((pte & PTE_P) && (i != VPT+(UVPT>>10))) {
+                       assert((pte & PTE_U) != PTE_U);
+                       assert((pte & PTE_W) == PTE_W);
+               }
+       }
+       // special mappings
+       pte = get_va_perms(pgdir, (void*SAFE)TC(UVPT+(VPT>>10)));
+       assert((pte & PTE_U) != PTE_U);
+       assert((pte & PTE_W) != PTE_W);
+
+       // note this means the kernel cannot directly manipulate this virtual address
+       // convince yourself this isn't a big deal, eagle-eyes!
+       pte = get_va_perms(pgdir, (void*SAFE)TC(VPT+(UVPT>>10)));
+       assert((pte & PTE_U) != PTE_U);
+       assert((pte & PTE_W) != PTE_W);
+
+       cprintf("check_boot_pgdir() succeeded!\n");
+}
+
+// This function returns the physical address of the page containing 'va',
+// defined by the page directory 'pgdir'.  The hardware normally performs
+// this functionality for us!  We define our own version to help check
+// the check_boot_pgdir() function; it shouldn't be used elsewhere.
+
+static physaddr_t
+check_va2pa(pde_t *COUNT(NPDENTRIES) _pgdir, uintptr_t va)
+{
+       pte_t *COUNT(NPTENTRIES) p;
+       pde_t *COUNT(1) pgdir;
+
+       pgdir = &_pgdir[PDX(va)];
+       if (!(*pgdir & PTE_P))
+               return ~0;
+       if (*pgdir & PTE_PS)
+               return PTE_ADDR(*pgdir);
+       p = (pte_t*COUNT(NPTENTRIES)) KADDR(PTE_ADDR(*pgdir));
+       if (!(p[PTX(va)] & PTE_P))
+               return ~0;
+       return PTE_ADDR(p[PTX(va)]);
+}
+
+/* 
+ * Remove the second level page table associated with virtual address va.
+ * Will 0 out the PDE for that page table.
+ * Panics if the page table has any present entries.
+ * This should be called rarely and with good cause.
+ * Currently errors if the PDE is jumbo or not present.
+ */
+error_t        pagetable_remove(pde_t *pgdir, void *va)
+{
+       pde_t* the_pde = &pgdir[PDX(va)];
+
+       if (!(*the_pde & PTE_P) || (*the_pde & PTE_PS))
+               return -EFAULT;
+       pte_t* page_table = (pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde));
+       for (int i = 0; i < NPTENTRIES; i++) 
+               if (page_table[i] & PTE_P)
+                       panic("Page table not empty during attempted removal!");
+       *the_pde = 0;
+       page_decref(pa2page(PADDR(page_table)));
+       return 0;
+}
+
+// Given 'pgdir', a pointer to a page directory, pgdir_walk returns
+// a pointer to the page table entry (PTE) for linear address 'va'.
+// This requires walking the two-level page table structure.
+//
+// If the relevant page table doesn't exist in the page directory, then:
+//    - If create == 0, pgdir_walk returns NULL.
+//    - Otherwise, pgdir_walk tries to allocate a new page table
+//     with page_alloc.  If this fails, pgdir_walk returns NULL.
+//    - Otherwise, pgdir_walk returns a pointer into the new page table.
+//
+// This is boot_pgdir_walk, but using page_alloc() instead of boot_alloc().
+// Unlike boot_pgdir_walk, pgdir_walk can fail.
+//
+// Hint: you can turn a Page * into the physical address of the
+// page it refers to with page2pa() from kern/pmap.h.
+//
+// Supports returning jumbo (4MB PSE) PTEs.  To create with a jumbo, pass in 2.
+pte_t*
+pgdir_walk(pde_t *pgdir, const void *SNT va, int create)
+{
+       pde_t* the_pde = &pgdir[PDX(va)];
+       page_t *new_table;
+
+       if (*the_pde & PTE_P) {
+               if (*the_pde & PTE_PS)
+                       return (pte_t*)the_pde;
+               return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(va)];
+       }
+       if (!create)
+               return NULL;
+       if (create == 2) {
+               if (JPGOFF(va))
+                       panic("Attempting to find a Jumbo PTE at an unaligned VA!");
+               *the_pde = PTE_PS | PTE_P;
+               return (pte_t*)the_pde;
+       }
+       if (kpage_alloc(&new_table))
+               return NULL;
+       memset(page2kva(new_table), 0, PGSIZE);
+       /* storing our ref to new_table in the PTE */
+       *the_pde = (pde_t)page2pa(new_table) | PTE_P | PTE_W | PTE_U;
+       return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(va)];
+}
+
+/* Returns the effective permissions for PTE_U, PTE_W, and PTE_P on a given
+ * virtual address.  Note we need to consider the composition of every PTE in
+ * the page table walk. */
+int get_va_perms(pde_t *pgdir, const void *SNT va)
+{
+       pde_t the_pde = pgdir[PDX(va)];
+       pte_t the_pte;
+
+       if (!(the_pde & PTE_P))
+               return 0;
+       if (the_pde & PTE_PS)
+               return the_pde & (PTE_U | PTE_W | PTE_P);
+       the_pte = ((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(the_pde)))[PTX(va)];
+       if (!(the_pte & PTE_P))
+               return 0;
+       return the_pte & the_pde & (PTE_U | PTE_W | PTE_P);
+}
+
+void
+page_check(void)
+{
+       page_t *pp, *pp0, *pp1, *pp2;
+       page_list_t fl[1024];
+       pte_t *ptep;
+
+       // should be able to allocate three pages
+       pp0 = pp1 = pp2 = 0;
+       assert(kpage_alloc(&pp0) == 0);
+       assert(kpage_alloc(&pp1) == 0);
+       assert(kpage_alloc(&pp2) == 0);
+
+       assert(pp0);
+       assert(pp1 && pp1 != pp0);
+       assert(pp2 && pp2 != pp1 && pp2 != pp0);
+
+       // temporarily steal the rest of the free pages
+       for(int i=0; i<llc_cache->num_colors; i++) {
+               fl[i] = colored_page_free_list[i];
+               LIST_INIT(&colored_page_free_list[i]);
+       }
+
+       // should be no free memory
+       assert(kpage_alloc(&pp) == -ENOMEM);
+
+       // Fill pp1 with bogus data and check for invalid tlb entries
+       memset(page2kva(pp1), 0xFFFFFFFF, PGSIZE);
+
+       // there is no page allocated at address 0
+       assert(page_lookup(boot_pgdir, (void *) 0x0, &ptep) == NULL);
+
+       // there is no free memory, so we can't allocate a page table 
+       assert(page_insert(boot_pgdir, pp1, 0x0, 0) < 0);
+
+       // free pp0 and try again: pp0 should be used for page table
+       page_decref(pp0);
+       assert(page_insert(boot_pgdir, pp1, 0x0, 0) == 0);
+       tlb_invalidate(boot_pgdir, 0x0);
+       // DEP Should have shot down invalid TLB entry - let's check
+       { TRUSTEDBLOCK
+         int *x = 0x0;
+         assert(*x == 0xFFFFFFFF);
+       }
+       assert(PTE_ADDR(boot_pgdir[0]) == page2pa(pp0));
+       assert(check_va2pa(boot_pgdir, 0x0) == page2pa(pp1));
+       assert(kref_refcnt(&pp1->pg_kref) == 2);
+       assert(kref_refcnt(&pp0->pg_kref) == 1);
+
+       // should be able to map pp2 at PGSIZE because pp0 is already allocated for page table
+       assert(page_insert(boot_pgdir, pp2, (void*SNT) PGSIZE, 0) == 0);
+       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
+       assert(kref_refcnt(&pp2->pg_kref) == 2);
+
+       // Make sure that pgdir_walk returns a pointer to the pte and
+       // not the table or some other garbage
+       {
+         pte_t *p = (pte_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(boot_pgdir[PDX(PGSIZE)]));
+         assert(pgdir_walk(boot_pgdir, (void *SNT)PGSIZE, 0) == &p[PTX(PGSIZE)]);
+       }
+
+       // should be no free memory
+       assert(kpage_alloc(&pp) == -ENOMEM);
+
+       // should be able to map pp2 at PGSIZE because it's already there
+       assert(page_insert(boot_pgdir, pp2, (void*SNT) PGSIZE, PTE_U) == 0);
+       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
+       assert(kref_refcnt(&pp2->pg_kref) == 2);
+
+       // Make sure that we actually changed the permission on pp2 when we re-mapped it
+       {
+         pte_t *p = pgdir_walk(boot_pgdir, (void*SNT)PGSIZE, 0);
+         assert(((*p) & PTE_U) == PTE_U);
+       }
+
+       // pp2 should NOT be on the free list
+       // could happen if ref counts are handled sloppily in page_insert
+       assert(kpage_alloc(&pp) == -ENOMEM);
+
+       // should not be able to map at PTSIZE because need free page for page table
+       assert(page_insert(boot_pgdir, pp0, (void*SNT) PTSIZE, 0) < 0);
+
+       // insert pp1 at PGSIZE (replacing pp2)
+       assert(page_insert(boot_pgdir, pp1, (void*SNT) PGSIZE, 0) == 0);
+
+       // should have pp1 at both 0 and PGSIZE, pp2 nowhere, ...
+       assert(check_va2pa(boot_pgdir, 0) == page2pa(pp1));
+       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));
+       // ... and ref counts should reflect this
+       assert(kref_refcnt(&pp1->pg_kref) == 3);
+       assert(kref_refcnt(&pp2->pg_kref) == 1);
+
+       // pp2 should be returned by page_alloc
+       page_decref(pp2);       /* should free it */
+       assert(kpage_alloc(&pp) == 0 && pp == pp2);
+
+       // unmapping pp1 at 0 should keep pp1 at PGSIZE
+       page_remove(boot_pgdir, 0x0);
+       assert(check_va2pa(boot_pgdir, 0x0) == ~0);
+       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));
+       assert(kref_refcnt(&pp1->pg_kref) == 2);
+       assert(kref_refcnt(&pp2->pg_kref) == 1);
+
+       // unmapping pp1 at PGSIZE should free it
+       page_remove(boot_pgdir, (void*SNT) PGSIZE);
+       assert(check_va2pa(boot_pgdir, 0x0) == ~0);
+       assert(check_va2pa(boot_pgdir, PGSIZE) == ~0);
+       assert(kref_refcnt(&pp1->pg_kref) == 1);
+       assert(kref_refcnt(&pp2->pg_kref) == 1);
+       page_decref(pp1);
+
+       // so it should be returned by page_alloc
+       assert(kpage_alloc(&pp) == 0 && pp == pp1);
+
+       // should be no free memory
+       assert(kpage_alloc(&pp) == -ENOMEM);
+
+       // forcibly take pp0 back
+       assert(PTE_ADDR(boot_pgdir[0]) == page2pa(pp0));
+       boot_pgdir[0] = 0;
+       assert(kref_refcnt(&pp0->pg_kref) == 1);
+
+       // Catch invalid pointer addition in pgdir_walk - i.e. pgdir + PDX(va)
+       {
+         // Give back pp0 for a bit
+         page_decref(pp0);
+
+         void *SNT va = (void *SNT)((PGSIZE * NPDENTRIES) + PGSIZE);
+         pte_t *p2 = pgdir_walk(boot_pgdir, va, 1);
+         pte_t *p = (pte_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(boot_pgdir[PDX(va)]));
+         assert(p2 == &p[PTX(va)]);
+
+         // Clean up again
+         boot_pgdir[PDX(va)] = 0;
+       }
+
+       // give free list back
+       for(int i=0; i<llc_cache->num_colors; i++)
+               colored_page_free_list[i] = fl[i];
+
+       // free the pages we took
+       page_decref(pp0);
+       page_decref(pp1);
+       page_decref(pp2);
+       assert(!kref_refcnt(&pp0->pg_kref));
+       assert(!kref_refcnt(&pp1->pg_kref));
+       assert(!kref_refcnt(&pp2->pg_kref));
+
+       cprintf("page_check() succeeded!\n");
+}
+
+/* Walks len bytes from start, executing 'callback' on every PTE, passing it a
+ * specific VA and whatever arg is passed in.  Note, this cannot handle jumbo
+ * pages. */
+int env_user_mem_walk(env_t* e, void* start, size_t len,
+                      mem_walk_callback_t callback, void* arg)
+{
+       pte_t *pt;
+       uint32_t pdeno, pteno;
+       physaddr_t pa;
+
+       assert((uintptr_t)start % PGSIZE == 0 && len % PGSIZE == 0);
+       void* end = (char*)start+len;
+       uint32_t pdeno_start = PDX(start);
+       uint32_t pdeno_end = PDX(ROUNDUP(end,PTSIZE));
+       /* concerned about overflow.  this should catch it for now, given the above
+        * assert. */
+       assert((len == 0) || (pdeno_start < pdeno_end));
+
+       for (pdeno = pdeno_start; pdeno < pdeno_end; pdeno++) {
+               if (!(e->env_pgdir[pdeno] & PTE_P))
+                       continue;
+               /* find the pa and a pointer to the page table */
+               pa = PTE_ADDR(e->env_pgdir[pdeno]);
+               pt = (pte_t*COUNT(NPTENTRIES)) KADDR(pa);
+               /* figure out where we start and end within the page table */
+               uint32_t pteno_start = (pdeno == pdeno_start ? PTX(start) : 0);
+               uint32_t pteno_end = (pdeno == pdeno_end - 1 && PTX(end) != 0 ?
+                                     PTX(end) : NPTENTRIES );
+               int ret;
+               for (pteno = pteno_start; pteno < pteno_end; pteno++) {
+                       if (!PAGE_UNMAPPED(pt[pteno]))
+                               if((ret = callback(e, &pt[pteno], PGADDR(pdeno, pteno, 0), arg)))
+                                       return ret;
+               }
+       }
+       return 0;
+}
+
+/* Frees (decrefs) all pages of the process's page table, including the page
+ * directory.  Does not free the memory that is actually mapped. */
+void env_pagetable_free(env_t* e)
+{
+       static_assert(UVPT % PTSIZE == 0);
+       assert(e->env_cr3 != rcr3());
+       for(uint32_t pdeno = 0; pdeno < PDX(UVPT); pdeno++)
+       {
+               // only look at mapped page tables
+               if (!(e->env_pgdir[pdeno] & PTE_P))
+                       continue;
+
+               // find the pa and va of the page table
+               physaddr_t pa = PTE_ADDR(e->env_pgdir[pdeno]);
+
+               // free the page table itself
+               e->env_pgdir[pdeno] = 0;
+               page_decref(pa2page(pa));
+       }
+
+       // free the page directory
+       physaddr_t pa = e->env_cr3;
+       e->env_cr3 = 0;
+       page_decref(pa2page(pa));
+       tlbflush();
+}
+
+/* 
+
+    // testing code for boot_pgdir_walk 
+       pte_t* temp;
+       temp = boot_pgdir_walk(pgdir, VPT + (VPT >> 10), 1);
+       cprintf("pgdir = %p\n", pgdir);
+       cprintf("test recursive walking pte_t* = %p\n", temp);
+       cprintf("test recursive walking entry = %p\n", PTE_ADDR(temp));
+       temp = boot_pgdir_walk(pgdir, 0xc0400000, 1);
+       cprintf("LA = 0xc0400000 = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0400070, 1);
+       cprintf("LA = 0xc0400070 = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0800000, 0);
+       cprintf("LA = 0xc0800000, no create = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0600070, 1);
+       cprintf("LA = 0xc0600070 = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0600090, 0);
+       cprintf("LA = 0xc0600090, nc = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0608070, 0);
+       cprintf("LA = 0xc0608070, nc = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0800070, 1);
+       cprintf("LA = 0xc0800070 = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0b00070, 0);
+       cprintf("LA = 0xc0b00070, nc = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0c00000, 0);
+       cprintf("LA = 0xc0c00000, nc = %p\n", temp);
+
+       // testing for boot_map_seg
+       cprintf("\n");
+       cprintf("before mapping 1 page to 0x00350000\n");
+       cprintf("0xc4000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc4000000, 1));
+       cprintf("0xc4000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc4000000, 1)));
+       boot_map_segment(pgdir, 0xc4000000, 4096, 0x00350000, PTE_W);
+       cprintf("after mapping\n");
+       cprintf("0xc4000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc4000000, 1));
+       cprintf("0xc4000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc4000000, 1)));
+
+       cprintf("\n");
+       cprintf("before mapping 3 pages to 0x00700000\n");
+       cprintf("0xd0000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0000000, 1));
+       cprintf("0xd0000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0000000, 1)));
+       cprintf("0xd0001000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0001000, 1));
+       cprintf("0xd0001000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0001000, 1)));
+       cprintf("0xd0002000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0002000, 1));
+       cprintf("0xd0002000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0002000, 1)));
+       boot_map_segment(pgdir, 0xd0000000, 4096*3, 0x00700000, 0);
+       cprintf("after mapping\n");
+       cprintf("0xd0000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0000000, 1));
+       cprintf("0xd0000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0000000, 1)));
+       cprintf("0xd0001000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0001000, 1));
+       cprintf("0xd0001000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0001000, 1)));
+       cprintf("0xd0002000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0002000, 1));
+       cprintf("0xd0002000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0002000, 1)));
+
+       cprintf("\n");
+       cprintf("before mapping 1 unaligned to 0x00500010\n");
+       cprintf("0xc8000010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8000010, 1));
+       cprintf("0xc8000010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8000010, 1)));
+       cprintf("0xc8001010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8001010, 1));
+       cprintf("0xc8001010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8001010, 1)));
+       boot_map_segment(pgdir, 0xc8000010, 4096, 0x00500010, PTE_W);
+       cprintf("after mapping\n");
+       cprintf("0xc8000010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8000010, 1));
+       cprintf("0xc8000010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8000010, 1)));
+       cprintf("0xc8001010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8001010, 1));
+       cprintf("0xc8001010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8001010, 1)));
+
+       cprintf("\n");
+       boot_map_segment(pgdir, 0xe0000000, 4096, 0x10000000, PTE_W);
+
+*/
diff --git a/kern/arch/x86/pmap64.c b/kern/arch/x86/pmap64.c
new file mode 100644 (file)
index 0000000..31ab9ca
--- /dev/null
@@ -0,0 +1,827 @@
+#ifdef __SHARC__
+#pragma nosharc
+#define SINIT(x) x
+#endif
+
+/* See COPYRIGHT for copyright information. */
+#include <arch/x86.h>
+#include <arch/arch.h>
+#include <arch/mmu.h>
+#include <arch/apic.h>
+
+#include <error.h>
+#include <sys/queue.h>
+
+#include <atomic.h>
+#include <string.h>
+#include <assert.h>
+#include <pmap.h>
+#include <kclock.h>
+#include <env.h>
+#include <stdio.h>
+#include <kmalloc.h>
+#include <page_alloc.h>
+
+// These variables are set in i386_vm_init()
+pde_t* boot_pgdir;             // Virtual address of boot time page directory
+physaddr_t RO boot_cr3;                // Physical address of boot time page directory
+
+// Global variables
+page_t *RO pages = NULL;          // Virtual address of physical page array
+
+// Global descriptor table.
+//
+// The kernel and user segments are identical (except for the DPL).
+// To load the SS register, the CPL must equal the DPL.  Thus,
+// we must duplicate the segments for the user and the kernel.
+//
+segdesc_t gdt[] =
+{
+       // 0x0 - unused (always faults -- for trapping NULL far pointers)
+       SEG_NULL,
+
+       // 0x8 - kernel code segment
+       [GD_KT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 0),
+
+       // 0x10 - kernel data segment
+       [GD_KD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 0),
+
+       // 0x18 - user code segment
+       [GD_UT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 3),
+
+       // 0x20 - user data segment
+       [GD_UD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 3),
+
+       // 0x28 - tss, initialized in idt_init()
+       [GD_TSS >> 3] = SEG_NULL,
+
+       // 0x30 - LDT, set per-process
+       [GD_LDT >> 3] = SEG_NULL
+};
+
+pseudodesc_t gdt_pd = {
+       /* 64 bit compiler complains about this.  going to redo it anyways. */
+       //sizeof(gdt) - 1, (unsigned long) gdt
+       sizeof(gdt) - 1, 0xdeadbeef
+};
+
+// --------------------------------------------------------------
+// Set up initial memory mappings and turn on MMU.
+// --------------------------------------------------------------
+
+static void check_boot_pgdir(bool pse);
+
+//
+// Given pgdir, a pointer to a page directory,
+// walk the 2-level page table structure to find
+// the page table entry (PTE) for linear address la.
+// Return a pointer to this PTE.
+//
+// If the relevant page table doesn't exist in the page directory:
+//     - If create == 0, return 0.
+//     - Otherwise allocate a new page table, install it into pgdir,
+//       and return a pointer into it.
+//        (Questions: What data should the new page table contain?
+//       And what permissions should the new pgdir entry have?
+//       Note that we use the 486-only "WP" feature of %cr0, which
+//       affects the way supervisor-mode writes are checked.)
+//
+// This function abstracts away the 2-level nature of
+// the page directory by allocating new page tables
+// as needed.
+// 
+// boot_pgdir_walk may ONLY be used during initialization,
+// before the page_free_list has been set up.
+// It should panic on failure.  (Note that boot_alloc already panics
+// on failure.)
+//
+// Supports returning jumbo (4MB PSE) PTEs.  To create with a jumbo, pass in 2.
+// 
+// Maps non-PSE PDEs as U/W.  W so the kernel can, U so the user can read via
+// UVPT.  UVPT security comes from the UVPT mapping (U/R).  All other kernel pages
+// protected at the second layer
+static pte_t*
+boot_pgdir_walk(pde_t *COUNT(NPDENTRIES) pgdir, uintptr_t la, int create)
+{
+       pde_t* the_pde = &pgdir[PDX(la)];
+       void* new_table;
+
+       if (*the_pde & PTE_P) {
+               if (*the_pde & PTE_PS)
+                       return (pte_t*)the_pde;
+               return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(la)];
+       }
+       if (!create)
+               return NULL;
+       if (create == 2) {
+               if (JPGOFF(la))
+                       panic("Attempting to find a Jumbo PTE at an unaligned VA!");
+               *the_pde = PTE_PS | PTE_P;
+               return (pte_t*)the_pde;
+       }
+       new_table = boot_alloc(PGSIZE, PGSIZE);
+       memset(new_table, 0, PGSIZE);
+       *the_pde = (pde_t)PADDR(new_table) | PTE_P | PTE_W | PTE_U | PTE_G;
+       return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(la)];
+}
+
+//
+// Map [la, la+size) of linear address space to physical [pa, pa+size)
+// in the page table rooted at pgdir.  Size is a multiple of PGSIZE.
+// Use permission bits perm|PTE_P for the entries.
+//
+// This function may ONLY be used during initialization,
+// before the page_free_list has been set up.
+//
+// To map with Jumbos, set PTE_PS in perm
+static void
+boot_map_segment(pde_t *COUNT(NPDENTRIES) pgdir, uintptr_t la, size_t size, physaddr_t pa, int perm)
+{
+       uintptr_t i;
+       pte_t *pte;
+       // la can be page unaligned, but weird things will happen
+       // unless pa has the same offset.  pa always truncates any
+       // possible offset.  will warn.  size can be weird too. 
+       if (PGOFF(la)) {
+               warn("la not page aligned in boot_map_segment!");
+               size += PGOFF(la);
+       }
+       if (perm & PTE_PS) {
+               if (JPGOFF(la) || JPGOFF(pa))
+                       panic("Tried to map a Jumbo page at an unaligned address!");
+               // need to index with i instead of la + size, in case of wrap-around
+               for (i = 0; i < size; i += JPGSIZE, la += JPGSIZE, pa += JPGSIZE) {
+                       pte = boot_pgdir_walk(pgdir, la, 2);
+                       *pte = PTE_ADDR(pa) | PTE_P | perm;
+               }
+       } else {
+               for (i = 0; i < size; i += PGSIZE, la += PGSIZE, pa += PGSIZE) {
+                       pte = boot_pgdir_walk(pgdir, la, 1);
+                       if (*pte & PTE_PS)
+                               // if we start using the extra flag for PAT, which we aren't,
+                               // this will warn, since PTE_PS and PTE_PAT are the same....
+                               warn("Possibly attempting to map a regular page into a Jumbo PDE");
+                       *pte = PTE_ADDR(pa) | PTE_P | perm;
+               }
+       }
+}
+
+// Set up a two-level page table:
+//    boot_pgdir is its linear (virtual) address of the root
+//    boot_cr3 is the physical adresss of the root
+// Then turn on paging.  Then effectively turn off segmentation.
+// (i.e., the segment base addrs are set to zero).
+// 
+// This function only sets up the kernel part of the address space
+// (ie. addresses >= ULIM).  The user part of the address space
+// will be setup later.
+//
+// From UWLIM to ULIM, the user is allowed to read but not write.
+// Above ULIM the user cannot read (or write). 
+void
+vm_init(void)
+{
+       pde_t* pgdir;
+       uint32_t cr0, edx;
+       size_t n;
+       bool pse;
+
+       pse = enable_pse();
+       if (pse)
+               cprintf("PSE capability detected.\n");
+
+       // we paniced earlier if we don't support PGE.  turn it on now.
+       // it's used in boot_map_segment, which covers all of the mappings that are
+       // the same for all address spaces.  and also for the VPT mapping below.
+       lcr4(rcr4() | CR4_PGE);
+
+       // set up mtrr's for core0.  other cores will do the same later
+       setup_default_mtrrs(0);
+
+       /*
+        * PSE status: 
+        * - can walk and set up boot_map_segments with jumbos but can't
+        *   insert yet.  need to look at the page_dir and friends.
+        * - anything related to a single struct page still can't handle 
+        *   jumbos.  will need to think about and adjust Page functions
+        * - do we want to store info like this in the struct page?  or just check
+        *   by walking the PTE
+        * - when we alloc a page, and we want it to be 4MB, we'll need
+        *   to have contiguous memory, etc
+        * - there's a difference between having 4MB page table entries
+        *   and having 4MB Page tracking structs.  changing the latter will
+        *   break a lot of things
+        * - showmapping and friends work on a 4KB granularity, but map to the
+        *   correct entries
+        * - need to not insert / boot_map a single page into an area that is 
+        *   already holding a jumbo page.  will need to break the jumbo up so that
+        *   we can then insert the lone page.  currently warns.
+        * - some inherent issues with the pgdir_walks returning a PTE, and we
+        *   don't know whether it is a jumbo (PDE) or a regular PTE.
+        */
+
+       //////////////////////////////////////////////////////////////////////
+       // create initial page directory.
+       pgdir = boot_alloc(PGSIZE, PGSIZE);
+       memset(pgdir, 0, PGSIZE);
+       boot_pgdir = pgdir;
+       boot_cr3 = PADDR(pgdir);
+       // helpful if you want to manually walk with kvm / bochs
+       //printk("pgdir va = %p, pgdir pa = %p\n\n", pgdir, PADDR(pgdir));
+
+       //////////////////////////////////////////////////////////////////////
+       // Recursively insert PD in itself as a page table, to form
+       // a virtual page table at virtual address VPT.
+       // (For now, you don't have understand the greater purpose of the
+       // following two lines.  Unless you are eagle-eyed, in which case you
+       // should already know.)
+
+       // Permissions: kernel RW, user NONE, Global Page
+       pgdir[PDX(VPT)] = PADDR(pgdir) | PTE_W | PTE_P | PTE_G;
+
+       // same for UVPT
+       // Permissions: kernel R, user R, Global Page
+       pgdir[PDX(UVPT)] = PADDR(pgdir) | PTE_U | PTE_P | PTE_G;
+
+       //////////////////////////////////////////////////////////////////////
+       // Map all of physical memory at KERNBASE. 
+       // Ie.  the VA range [KERNBASE, 2^32) should map to
+       //      the PA range [0, 2^32 - KERNBASE)
+       // We might not have 2^32 - KERNBASE bytes of physical memory, but
+       // we just set up the mapping anyway.
+       // Permissions: kernel RW, user NONE
+       // Your code goes here: 
+       
+       // this maps all of the possible phys memory
+       // note the use of unsigned underflow to get size = 0x40000000
+       //boot_map_segment(pgdir, KERNBASE, -KERNBASE, 0, PTE_W);
+       // but this only maps what is available, and saves memory.  every 4MB of
+       // mapped memory requires a 2nd level page: 2^10 entries, each covering 2^12
+       // need to modify tests below to account for this
+       if (pse) {
+               // map the first 4MB as regular entries, to support different MTRRs
+               boot_map_segment(pgdir, KERNBASE, JPGSIZE, 0, PTE_W | PTE_G);
+               boot_map_segment(pgdir, KERNBASE + JPGSIZE, maxaddrpa - JPGSIZE, JPGSIZE,
+                                PTE_W | PTE_G | PTE_PS);
+       } else
+               boot_map_segment(pgdir, KERNBASE, maxaddrpa, 0, PTE_W | PTE_G);
+
+       // APIC mapping: using PAT (but not *the* PAT flag) to make these type UC
+       // IOAPIC
+       boot_map_segment(pgdir, IOAPIC_BASE, PGSIZE, IOAPIC_PBASE, 
+                        PTE_PCD | PTE_PWT | PTE_W | PTE_G);
+       // Local APIC
+       boot_map_segment(pgdir, LAPIC_BASE, PGSIZE, LAPIC_PBASE,
+                        PTE_PCD | PTE_PWT | PTE_W | PTE_G);
+
+       // Check that the initial page directory has been set up correctly.
+       check_boot_pgdir(pse);
+
+       //////////////////////////////////////////////////////////////////////
+       // On x86, segmentation maps a VA to a LA (linear addr) and
+       // paging maps the LA to a PA.  I.e. VA => LA => PA.  If paging is
+       // turned off the LA is used as the PA.  Note: there is no way to
+       // turn off segmentation.  The closest thing is to set the base
+       // address to 0, so the VA => LA mapping is the identity.
+
+       // Current mapping: VA KERNBASE+x => PA x.
+       //     (segmentation base=-KERNBASE and paging is off)
+
+       // From here on down we must maintain this VA KERNBASE + x => PA x
+       // mapping, even though we are turning on paging and reconfiguring
+       // segmentation.
+
+       // Map VA 0:4MB same as VA KERNBASE, i.e. to PA 0:4MB.
+       // (Limits our kernel to <4MB)
+       /* They mean linear address 0:4MB, and the kernel < 4MB is only until 
+        * segmentation is turned off.
+        * once we turn on paging, segmentation is still on, so references to
+        * KERNBASE+x will get mapped to linear address x, which we need to make 
+        * sure can map to phys addr x, until we can turn off segmentation and
+        * KERNBASE+x maps to LA KERNBASE+x, which maps to PA x, via paging
+        */
+       pgdir[0] = pgdir[PDX(KERNBASE)];
+
+       // Install page table.
+       lcr3(boot_cr3);
+
+       // Turn on paging.
+       cr0 = rcr0();
+       // CD and NW should already be on, but just in case these turn on caching
+       cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP;
+       cr0 &= ~(CR0_TS|CR0_EM|CR0_CD|CR0_NW);
+       lcr0(cr0);
+
+       // Current mapping: KERNBASE+x => x => x.
+       // (x < 4MB so uses paging pgdir[0])
+
+       // Reload all segment registers. 
+
+       /* Pending 64b rewrite */
+       //asm volatile("lgdt gdt_pd");
+       //asm volatile("movw %%ax,%%gs" :: "a" (GD_UD|3));
+       //asm volatile("movw %%ax,%%fs" :: "a" (GD_UD|3));
+       //asm volatile("movw %%ax,%%es" :: "a" (GD_KD));
+       //asm volatile("movw %%ax,%%ds" :: "a" (GD_KD));
+       //asm volatile("movw %%ax,%%ss" :: "a" (GD_KD));
+       //asm volatile("ljmp %0,$1f\n 1:\n" :: "i" (GD_KT));  // reload cs
+       //asm volatile("lldt %%ax" :: "a" (0));
+
+       // Final mapping: KERNBASE+x => KERNBASE+x => x.
+
+       // This mapping was only used after paging was turned on but
+       // before the segment registers were reloaded.
+       pgdir[0] = 0;
+
+       // Flush the TLB for good measure, to kill the pgdir[0] mapping.
+       tlb_flush_global();
+}
+
+//
+// Checks that the kernel part of virtual address space
+// has been setup roughly correctly(by i386_vm_init()).
+//
+// This function doesn't test every corner case,
+// in fact it doesn't test the permission bits at all,
+// but it is a pretty good sanity check. 
+//
+static physaddr_t check_va2pa(pde_t *COUNT(NPDENTRIES) pgdir, uintptr_t va);
+
+static void
+check_boot_pgdir(bool pse)
+{
+       unsigned long i, n;
+       pde_t *pgdir, pte;
+
+       pgdir = boot_pgdir;
+
+       // check phys mem
+       //for (i = 0; KERNBASE + i != 0; i += PGSIZE)
+       // adjusted check to account for only mapping avail mem
+       if (pse)
+               for (i = 0; i < maxaddrpa; i += JPGSIZE)
+                       assert(check_va2pa(pgdir, KERNBASE + i) == i);
+       else
+               for (i = 0; i < maxaddrpa; i += PGSIZE)
+                       assert(check_va2pa(pgdir, KERNBASE + i) == i);
+
+       // check for zero/non-zero in PDEs
+       for (i = 0; i < NPDENTRIES; i++) {
+               switch (i) {
+               /* XXX this old PDX shit is broken with 4 PMLs */
+               //case PDX(VPT):
+               //case PDX(UVPT):
+               case PDX(LAPIC_BASE): // LAPIC mapping.  TODO: remove when MTRRs are up
+                       assert(pgdir[i]);
+                       break;
+               default:
+                       //if (i >= PDX(KERNBASE))
+                       // adjusted check to account for only mapping avail mem
+                       // and you can't KADDR maxpa (just above legal range)
+                       // maxaddrpa can be up to maxpa, so assume the worst
+                       if (i >= PDX(KERNBASE) && i <= PDX(KADDR(maxaddrpa-1)))
+                               assert(pgdir[i]);
+                       else
+                               assert(pgdir[i] == 0);
+                       break;
+               }
+       }
+
+       /* check permissions
+        * user read-only.  check for user and write, should be only user
+        * eagle-eyed viewers should be able to explain the extra cases.
+        * for the mongoose-eyed, remember that weird shit happens when you loop
+        * through UVPT.  Specifically, you can't loop once, then look at a jumbo
+        * page that is kernel only.  That's the end of the page table for you, so
+        * having a U on the entry doesn't make sense.  Thus we check for a jumbo
+        * page, and special case it.  This will happen at 0xbf701000.  Why is this
+        * magical?  Get your eagle glasses and figure it out. */
+       for (i = UWLIM; i < ULIM; i+=PGSIZE) {
+               pte = get_va_perms(pgdir, (void*SAFE)TC(i));
+               if (pte & PTE_P) {
+                       if (i == UVPT+(VPT >> 10))
+                               continue;
+                       if (*pgdir_walk(pgdir, (void*SAFE)TC(i), 0) & PTE_PS) {
+                               assert((pte & PTE_U) != PTE_U);
+                               assert((pte & PTE_W) != PTE_W);
+                       } else {
+                               assert((pte & PTE_U) == PTE_U);
+                               assert((pte & PTE_W) != PTE_W);
+                       }
+               }
+       }
+       // kernel read-write.
+       for (i = ULIM; i <= KERNBASE + maxaddrpa - PGSIZE; i+=PGSIZE) {
+               pte = get_va_perms(pgdir, (void*SAFE)TC(i));
+               if ((pte & PTE_P) && (i != VPT+(UVPT>>10))) {
+                       assert((pte & PTE_U) != PTE_U);
+                       assert((pte & PTE_W) == PTE_W);
+               }
+       }
+       // special mappings
+       pte = get_va_perms(pgdir, (void*SAFE)TC(UVPT+(VPT>>10)));
+       assert((pte & PTE_U) != PTE_U);
+       assert((pte & PTE_W) != PTE_W);
+
+       // note this means the kernel cannot directly manipulate this virtual address
+       // convince yourself this isn't a big deal, eagle-eyes!
+       pte = get_va_perms(pgdir, (void*SAFE)TC(VPT+(UVPT>>10)));
+       assert((pte & PTE_U) != PTE_U);
+       assert((pte & PTE_W) != PTE_W);
+
+       cprintf("check_boot_pgdir() succeeded!\n");
+}
+
+// This function returns the physical address of the page containing 'va',
+// defined by the page directory 'pgdir'.  The hardware normally performs
+// this functionality for us!  We define our own version to help check
+// the check_boot_pgdir() function; it shouldn't be used elsewhere.
+
+static physaddr_t
+check_va2pa(pde_t *COUNT(NPDENTRIES) _pgdir, uintptr_t va)
+{
+       pte_t *COUNT(NPTENTRIES) p;
+       pde_t *COUNT(1) pgdir;
+
+       pgdir = &_pgdir[PDX(va)];
+       if (!(*pgdir & PTE_P))
+               return ~0;
+       if (*pgdir & PTE_PS)
+               return PTE_ADDR(*pgdir);
+       p = (pte_t*COUNT(NPTENTRIES)) KADDR(PTE_ADDR(*pgdir));
+       if (!(p[PTX(va)] & PTE_P))
+               return ~0;
+       return PTE_ADDR(p[PTX(va)]);
+}
+
+/* 
+ * Remove the second level page table associated with virtual address va.
+ * Will 0 out the PDE for that page table.
+ * Panics if the page table has any present entries.
+ * This should be called rarely and with good cause.
+ * Currently errors if the PDE is jumbo or not present.
+ */
+error_t        pagetable_remove(pde_t *pgdir, void *va)
+{
+       pde_t* the_pde = &pgdir[PDX(va)];
+
+       if (!(*the_pde & PTE_P) || (*the_pde & PTE_PS))
+               return -EFAULT;
+       pte_t* page_table = (pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde));
+       for (int i = 0; i < NPTENTRIES; i++) 
+               if (page_table[i] & PTE_P)
+                       panic("Page table not empty during attempted removal!");
+       *the_pde = 0;
+       page_decref(pa2page(PADDR(page_table)));
+       return 0;
+}
+
+// Given 'pgdir', a pointer to a page directory, pgdir_walk returns
+// a pointer to the page table entry (PTE) for linear address 'va'.
+// This requires walking the two-level page table structure.
+//
+// If the relevant page table doesn't exist in the page directory, then:
+//    - If create == 0, pgdir_walk returns NULL.
+//    - Otherwise, pgdir_walk tries to allocate a new page table
+//     with page_alloc.  If this fails, pgdir_walk returns NULL.
+//    - Otherwise, pgdir_walk returns a pointer into the new page table.
+//
+// This is boot_pgdir_walk, but using page_alloc() instead of boot_alloc().
+// Unlike boot_pgdir_walk, pgdir_walk can fail.
+//
+// Hint: you can turn a Page * into the physical address of the
+// page it refers to with page2pa() from kern/pmap.h.
+//
+// Supports returning jumbo (4MB PSE) PTEs.  To create with a jumbo, pass in 2.
+pte_t*
+pgdir_walk(pde_t *pgdir, const void *SNT va, int create)
+{
+       pde_t* the_pde = &pgdir[PDX(va)];
+       page_t *new_table;
+
+       if (*the_pde & PTE_P) {
+               if (*the_pde & PTE_PS)
+                       return (pte_t*)the_pde;
+               return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(va)];
+       }
+       if (!create)
+               return NULL;
+       if (create == 2) {
+               if (JPGOFF(va))
+                       panic("Attempting to find a Jumbo PTE at an unaligned VA!");
+               *the_pde = PTE_PS | PTE_P;
+               return (pte_t*)the_pde;
+       }
+       if (kpage_alloc(&new_table))
+               return NULL;
+       memset(page2kva(new_table), 0, PGSIZE);
+       /* storing our ref to new_table in the PTE */
+       *the_pde = (pde_t)page2pa(new_table) | PTE_P | PTE_W | PTE_U;
+       return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(va)];
+}
+
+/* Returns the effective permissions for PTE_U, PTE_W, and PTE_P on a given
+ * virtual address.  Note we need to consider the composition of every PTE in
+ * the page table walk. */
+int get_va_perms(pde_t *pgdir, const void *SNT va)
+{
+       pde_t the_pde = pgdir[PDX(va)];
+       pte_t the_pte;
+
+       if (!(the_pde & PTE_P))
+               return 0;
+       if (the_pde & PTE_PS)
+               return the_pde & (PTE_U | PTE_W | PTE_P);
+       the_pte = ((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(the_pde)))[PTX(va)];
+       if (!(the_pte & PTE_P))
+               return 0;
+       return the_pte & the_pde & (PTE_U | PTE_W | PTE_P);
+}
+
+void
+page_check(void)
+{
+       page_t *pp, *pp0, *pp1, *pp2;
+       page_list_t fl[1024];
+       pte_t *ptep;
+
+       // should be able to allocate three pages
+       pp0 = pp1 = pp2 = 0;
+       assert(kpage_alloc(&pp0) == 0);
+       assert(kpage_alloc(&pp1) == 0);
+       assert(kpage_alloc(&pp2) == 0);
+
+       assert(pp0);
+       assert(pp1 && pp1 != pp0);
+       assert(pp2 && pp2 != pp1 && pp2 != pp0);
+
+       // temporarily steal the rest of the free pages
+       for(int i=0; i<llc_cache->num_colors; i++) {
+               fl[i] = colored_page_free_list[i];
+               LIST_INIT(&colored_page_free_list[i]);
+       }
+
+       // should be no free memory
+       assert(kpage_alloc(&pp) == -ENOMEM);
+
+       // Fill pp1 with bogus data and check for invalid tlb entries
+       memset(page2kva(pp1), 0xFFFFFFFF, PGSIZE);
+
+       // there is no page allocated at address 0
+       assert(page_lookup(boot_pgdir, (void *) 0x0, &ptep) == NULL);
+
+       // there is no free memory, so we can't allocate a page table 
+       assert(page_insert(boot_pgdir, pp1, 0x0, 0) < 0);
+
+       // free pp0 and try again: pp0 should be used for page table
+       page_decref(pp0);
+       assert(page_insert(boot_pgdir, pp1, 0x0, 0) == 0);
+       tlb_invalidate(boot_pgdir, 0x0);
+       // DEP Should have shot down invalid TLB entry - let's check
+       { TRUSTEDBLOCK
+         int *x = 0x0;
+         assert(*x == 0xFFFFFFFF);
+       }
+       assert(PTE_ADDR(boot_pgdir[0]) == page2pa(pp0));
+       assert(check_va2pa(boot_pgdir, 0x0) == page2pa(pp1));
+       assert(kref_refcnt(&pp1->pg_kref) == 2);
+       assert(kref_refcnt(&pp0->pg_kref) == 1);
+
+       // should be able to map pp2 at PGSIZE because pp0 is already allocated for page table
+       assert(page_insert(boot_pgdir, pp2, (void*SNT) PGSIZE, 0) == 0);
+       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
+       assert(kref_refcnt(&pp2->pg_kref) == 2);
+
+       // Make sure that pgdir_walk returns a pointer to the pte and
+       // not the table or some other garbage
+       {
+         pte_t *p = (pte_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(boot_pgdir[PDX(PGSIZE)]));
+         assert(pgdir_walk(boot_pgdir, (void *SNT)PGSIZE, 0) == &p[PTX(PGSIZE)]);
+       }
+
+       // should be no free memory
+       assert(kpage_alloc(&pp) == -ENOMEM);
+
+       // should be able to map pp2 at PGSIZE because it's already there
+       assert(page_insert(boot_pgdir, pp2, (void*SNT) PGSIZE, PTE_U) == 0);
+       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
+       assert(kref_refcnt(&pp2->pg_kref) == 2);
+
+       // Make sure that we actually changed the permission on pp2 when we re-mapped it
+       {
+         pte_t *p = pgdir_walk(boot_pgdir, (void*SNT)PGSIZE, 0);
+         assert(((*p) & PTE_U) == PTE_U);
+       }
+
+       // pp2 should NOT be on the free list
+       // could happen if ref counts are handled sloppily in page_insert
+       assert(kpage_alloc(&pp) == -ENOMEM);
+
+       // should not be able to map at PTSIZE because need free page for page table
+       assert(page_insert(boot_pgdir, pp0, (void*SNT) PTSIZE, 0) < 0);
+
+       // insert pp1 at PGSIZE (replacing pp2)
+       assert(page_insert(boot_pgdir, pp1, (void*SNT) PGSIZE, 0) == 0);
+
+       // should have pp1 at both 0 and PGSIZE, pp2 nowhere, ...
+       assert(check_va2pa(boot_pgdir, 0) == page2pa(pp1));
+       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));
+       // ... and ref counts should reflect this
+       assert(kref_refcnt(&pp1->pg_kref) == 3);
+       assert(kref_refcnt(&pp2->pg_kref) == 1);
+
+       // pp2 should be returned by page_alloc
+       page_decref(pp2);       /* should free it */
+       assert(kpage_alloc(&pp) == 0 && pp == pp2);
+
+       // unmapping pp1 at 0 should keep pp1 at PGSIZE
+       page_remove(boot_pgdir, 0x0);
+       assert(check_va2pa(boot_pgdir, 0x0) == ~0);
+       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));
+       assert(kref_refcnt(&pp1->pg_kref) == 2);
+       assert(kref_refcnt(&pp2->pg_kref) == 1);
+
+       // unmapping pp1 at PGSIZE should free it
+       page_remove(boot_pgdir, (void*SNT) PGSIZE);
+       assert(check_va2pa(boot_pgdir, 0x0) == ~0);
+       assert(check_va2pa(boot_pgdir, PGSIZE) == ~0);
+       assert(kref_refcnt(&pp1->pg_kref) == 1);
+       assert(kref_refcnt(&pp2->pg_kref) == 1);
+       page_decref(pp1);
+
+       // so it should be returned by page_alloc
+       assert(kpage_alloc(&pp) == 0 && pp == pp1);
+
+       // should be no free memory
+       assert(kpage_alloc(&pp) == -ENOMEM);
+
+       // forcibly take pp0 back
+       assert(PTE_ADDR(boot_pgdir[0]) == page2pa(pp0));
+       boot_pgdir[0] = 0;
+       assert(kref_refcnt(&pp0->pg_kref) == 1);
+
+       // Catch invalid pointer addition in pgdir_walk - i.e. pgdir + PDX(va)
+       {
+         // Give back pp0 for a bit
+         page_decref(pp0);
+
+         void *SNT va = (void *SNT)((PGSIZE * NPDENTRIES) + PGSIZE);
+         pte_t *p2 = pgdir_walk(boot_pgdir, va, 1);
+         pte_t *p = (pte_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(boot_pgdir[PDX(va)]));
+         assert(p2 == &p[PTX(va)]);
+
+         // Clean up again
+         boot_pgdir[PDX(va)] = 0;
+       }
+
+       // give free list back
+       for(int i=0; i<llc_cache->num_colors; i++)
+               colored_page_free_list[i] = fl[i];
+
+       // free the pages we took
+       page_decref(pp0);
+       page_decref(pp1);
+       page_decref(pp2);
+       assert(!kref_refcnt(&pp0->pg_kref));
+       assert(!kref_refcnt(&pp1->pg_kref));
+       assert(!kref_refcnt(&pp2->pg_kref));
+
+       cprintf("page_check() succeeded!\n");
+}
+
+/* Walks len bytes from start, executing 'callback' on every PTE, passing it a
+ * specific VA and whatever arg is passed in.  Note, this cannot handle jumbo
+ * pages. */
+int env_user_mem_walk(env_t* e, void* start, size_t len,
+                      mem_walk_callback_t callback, void* arg)
+{
+       pte_t *pt;
+       uintptr_t pdeno, pteno;
+       physaddr_t pa;
+
+       assert((uintptr_t)start % PGSIZE == 0 && len % PGSIZE == 0);
+       void* end = (char*)start+len;
+       uintptr_t pdeno_start = PDX(start);
+       uintptr_t pdeno_end = PDX(ROUNDUP(end,PTSIZE));
+       /* concerned about overflow.  this should catch it for now, given the above
+        * assert. */
+       assert((len == 0) || (pdeno_start < pdeno_end));
+
+       for (pdeno = pdeno_start; pdeno < pdeno_end; pdeno++) {
+               if (!(e->env_pgdir[pdeno] & PTE_P))
+                       continue;
+               /* find the pa and a pointer to the page table */
+               pa = PTE_ADDR(e->env_pgdir[pdeno]);
+               pt = (pte_t*COUNT(NPTENTRIES)) KADDR(pa);
+               /* figure out where we start and end within the page table */
+               uintptr_t pteno_start = (pdeno == pdeno_start ? PTX(start) : 0);
+               uintptr_t pteno_end = (pdeno == pdeno_end - 1 && PTX(end) != 0 ?
+                                     PTX(end) : NPTENTRIES );
+               int ret;
+               for (pteno = pteno_start; pteno < pteno_end; pteno++) {
+                       if (!PAGE_UNMAPPED(pt[pteno]))
+                               if((ret = callback(e, &pt[pteno], PGADDR(pdeno, pteno, 0), arg)))
+                                       return ret;
+               }
+       }
+       return 0;
+}
+
+/* Frees (decrefs) all pages of the process's page table, including the page
+ * directory.  Does not free the memory that is actually mapped. */
+void env_pagetable_free(env_t* e)
+{
+       static_assert(UVPT % PTSIZE == 0);
+       assert(e->env_cr3 != rcr3());
+       for(uint32_t pdeno = 0; pdeno < PDX(UVPT); pdeno++)
+       {
+               // only look at mapped page tables
+               if (!(e->env_pgdir[pdeno] & PTE_P))
+                       continue;
+
+               // find the pa and va of the page table
+               physaddr_t pa = PTE_ADDR(e->env_pgdir[pdeno]);
+
+               // free the page table itself
+               e->env_pgdir[pdeno] = 0;
+               page_decref(pa2page(pa));
+       }
+
+       // free the page directory
+       physaddr_t pa = e->env_cr3;
+       e->env_cr3 = 0;
+       page_decref(pa2page(pa));
+       tlbflush();
+}
+
+/* 
+
+    // testing code for boot_pgdir_walk 
+       pte_t* temp;
+       temp = boot_pgdir_walk(pgdir, VPT + (VPT >> 10), 1);
+       cprintf("pgdir = %p\n", pgdir);
+       cprintf("test recursive walking pte_t* = %p\n", temp);
+       cprintf("test recursive walking entry = %p\n", PTE_ADDR(temp));
+       temp = boot_pgdir_walk(pgdir, 0xc0400000, 1);
+       cprintf("LA = 0xc0400000 = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0400070, 1);
+       cprintf("LA = 0xc0400070 = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0800000, 0);
+       cprintf("LA = 0xc0800000, no create = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0600070, 1);
+       cprintf("LA = 0xc0600070 = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0600090, 0);
+       cprintf("LA = 0xc0600090, nc = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0608070, 0);
+       cprintf("LA = 0xc0608070, nc = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0800070, 1);
+       cprintf("LA = 0xc0800070 = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0b00070, 0);
+       cprintf("LA = 0xc0b00070, nc = %p\n", temp);
+       temp = boot_pgdir_walk(pgdir, 0xc0c00000, 0);
+       cprintf("LA = 0xc0c00000, nc = %p\n", temp);
+
+       // testing for boot_map_seg
+       cprintf("\n");
+       cprintf("before mapping 1 page to 0x00350000\n");
+       cprintf("0xc4000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc4000000, 1));
+       cprintf("0xc4000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc4000000, 1)));
+       boot_map_segment(pgdir, 0xc4000000, 4096, 0x00350000, PTE_W);
+       cprintf("after mapping\n");
+       cprintf("0xc4000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc4000000, 1));
+       cprintf("0xc4000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc4000000, 1)));
+
+       cprintf("\n");
+       cprintf("before mapping 3 pages to 0x00700000\n");
+       cprintf("0xd0000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0000000, 1));
+       cprintf("0xd0000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0000000, 1)));
+       cprintf("0xd0001000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0001000, 1));
+       cprintf("0xd0001000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0001000, 1)));
+       cprintf("0xd0002000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0002000, 1));
+       cprintf("0xd0002000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0002000, 1)));
+       boot_map_segment(pgdir, 0xd0000000, 4096*3, 0x00700000, 0);
+       cprintf("after mapping\n");
+       cprintf("0xd0000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0000000, 1));
+       cprintf("0xd0000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0000000, 1)));
+       cprintf("0xd0001000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0001000, 1));
+       cprintf("0xd0001000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0001000, 1)));
+       cprintf("0xd0002000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0002000, 1));
+       cprintf("0xd0002000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0002000, 1)));
+
+       cprintf("\n");
+       cprintf("before mapping 1 unaligned to 0x00500010\n");
+       cprintf("0xc8000010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8000010, 1));
+       cprintf("0xc8000010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8000010, 1)));
+       cprintf("0xc8001010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8001010, 1));
+       cprintf("0xc8001010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8001010, 1)));
+       boot_map_segment(pgdir, 0xc8000010, 4096, 0x00500010, PTE_W);
+       cprintf("after mapping\n");
+       cprintf("0xc8000010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8000010, 1));
+       cprintf("0xc8000010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8000010, 1)));
+       cprintf("0xc8001010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8001010, 1));
+       cprintf("0xc8001010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8001010, 1)));
+
+       cprintf("\n");
+       boot_map_segment(pgdir, 0xe0000000, 4096, 0x10000000, PTE_W);
+
+*/
diff --git a/kern/arch/x86/process.c b/kern/arch/x86/process.c
deleted file mode 100644 (file)
index c4ff756..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-#include <arch/arch.h>
-#include <trap.h>
-#include <process.h>
-#include <pmap.h>
-#include <smp.h>
-
-#include <string.h>
-#include <assert.h>
-#include <stdio.h>
-
-/* TODO: handle user and kernel contexts */
-void proc_pop_ctx(struct user_context *ctx)
-{
-       struct hw_trapframe *tf = &ctx->tf.hw_tf;
-       assert(ctx->type == ROS_HW_CTX);
-
-       /* Bug with this whole idea (TODO: (TLSV))*/
-       /* Load the LDT for this process.  Slightly ghetto doing it here. */
-       /* copy-in and check the LDT location.  the segmentation hardware writes the
-        * accessed bit, so we want the memory to be in the user-writeable area. */
-       segdesc_t *ldt = current->procdata->ldt;
-       ldt = (segdesc_t*)MIN((uintptr_t)ldt, UWLIM - LDT_SIZE);
-       /* Only set up the ldt if a pointer to the ldt actually exists */
-       if(ldt != NULL) {
-               segdesc_t *my_gdt = per_cpu_info[core_id()].gdt;
-               segdesc_t ldt_temp = SEG_SYS(STS_LDT, (uint32_t)ldt, LDT_SIZE, 3);
-               my_gdt[GD_LDT >> 3] = ldt_temp;
-               asm volatile("lldt %%ax" :: "a"(GD_LDT));
-       }
-
-       /* In case they are enabled elsewhere.  We can't take an interrupt in these
-        * routines, due to how they play with the kernel stack pointer. */
-       disable_irq();
-       /*
-        * If the process entered the kernel via sysenter, we need to leave via
-        * sysexit.  sysenter trapframes have 0 for a CS, which is pushed in
-        * sysenter_handler.
-        */
-       if(tf->tf_cs) {
-               /*
-                * Restores the register values in the Trapframe with the 'iret'
-                * instruction.  This exits the kernel and starts executing some
-                * environment's code.  This function does not return.
-                */
-               asm volatile ("movl %0,%%esp;           "
-                             "popal;                   "
-                             "popl %%gs;               "
-                             "popl %%fs;               "
-                             "popl %%es;               "
-                             "popl %%ds;               "
-                             "addl $0x8,%%esp;         "
-                             "iret                     "
-                             : : "g" (tf) : "memory");
-               panic("iret failed");  /* mostly to placate the compiler */
-       } else {
-               /* Return path of sysexit.  See sysenter_handler's asm for details.
-                * One difference is that this tf could be somewhere other than a stack
-                * (like in a struct proc).  We need to make sure esp is valid once
-                * interrupts are turned on (which would happen on popfl normally), so
-                * we need to save and restore a decent esp (the current one).  We need
-                * a place to save it that is accessible after we change the stack
-                * pointer to the tf *and* that is specific to this core/instance of
-                * sysexit.  The simplest and nicest is to use the tf_esp, which we
-                * can just pop.  Incidentally, the value in oesp would work too.
-                * To prevent popfl from turning interrupts on, we hack the tf's eflags
-                * so that we have a chance to change esp to a good value before
-                * interrupts are enabled.  The other option would be to throw away the
-                * eflags, but that's less desirable. */
-               tf->tf_eflags &= !FL_IF;
-               tf->tf_esp = read_esp();
-               asm volatile ("movl %0,%%esp;           "
-                             "popal;                   "
-                             "popl %%gs;               "
-                             "popl %%fs;               "
-                             "popl %%es;               "
-                             "popl %%ds;               "
-                             "addl $0x10,%%esp;        "
-                             "popfl;                   "
-                             "movl %%ebp,%%ecx;        "
-                             "popl %%esp;              "
-                             "sti;                     "
-                             "sysexit                  "
-                             : : "g" (tf) : "memory");
-               panic("sysexit failed");  /* mostly to placate your mom */
-       }
-}
-
-/* TODO: consider using a SW context */
-void proc_init_ctx(struct user_context *ctx, uint32_t vcoreid, uintptr_t entryp,
-                   uintptr_t stack_top)
-{
-       struct hw_trapframe *tf = &ctx->tf.hw_tf;
-       ctx->type = ROS_HW_CTX;
-
-       memset(tf,0,sizeof(*tf));
-
-       /* Set up appropriate initial values for the segment registers.
-        * GD_UD is the user data segment selector in the GDT, and
-        * GD_UT is the user text segment selector (see inc/memlayout.h).
-        * The low 2 bits of each segment register contains the
-        * Requestor Privilege Level (RPL); 3 means user mode. */
-       tf->tf_ds = GD_UD | 3;
-       tf->tf_es = GD_UD | 3;
-       tf->tf_ss = GD_UD | 3;
-       tf->tf_esp = stack_top-64;
-       tf->tf_cs = GD_UT | 3;
-       /* set the env's EFLAGSs to have interrupts enabled */
-       tf->tf_eflags |= 0x00000200; // bit 9 is the interrupts-enabled
-
-       tf->tf_eip = entryp;
-
-       /* Coupled closely with user's entry.S.  id is the vcoreid, which entry.S
-        * uses to determine what to do.  vcoreid == 0 is the main core/context. */
-       tf->tf_regs.reg_eax = vcoreid;
-}
-
-/* TODO: handle both HW and SW contexts */
-void proc_secure_ctx(struct user_context *ctx)
-{
-       struct hw_trapframe *tf = &ctx->tf.hw_tf;
-       ctx->type = ROS_HW_CTX;
-       /* we normally don't need to set the non-CS regs, but they could be
-        * gibberish and cause a GPF.  gs can still be gibberish, but we don't
-        * necessarily know what it ought to be (we could check, but that's a pain).
-        * the code protecting the kernel from TLS related things ought to be able
-        * to handle GPFs on popping gs. TODO: (TLSV) */
-       tf->tf_ds = GD_UD | 3;
-       tf->tf_es = GD_UD | 3;
-       tf->tf_fs = 0;
-       //tf->tf_gs = whatevs.  ignoring this.
-       tf->tf_ss = GD_UD | 3;
-       tf->tf_cs ? GD_UT | 3 : 0; // can be 0 for sysenter TFs.
-       tf->tf_eflags |= 0x00000200; // bit 9 is the interrupts-enabled
-}
-
-/* Called when we are currently running an address space on our core and want to
- * abandon it.  We need a known good pgdir before releasing the old one.  We
- * decref, since current no longer tracks the proc (and current no longer
- * protects the cr3).  We also need to clear out the TLS registers (before
- * unmapping the address space!) */
-void __abandon_core(void)
-{
-       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
-       asm volatile ("movw %%ax,%%gs; lldt %%ax" :: "a"(0));
-       lcr3(boot_cr3);
-       proc_decref(pcpui->cur_proc);
-       pcpui->cur_proc = 0;
-}
diff --git a/kern/arch/x86/process32.c b/kern/arch/x86/process32.c
new file mode 100644 (file)
index 0000000..d2f7859
--- /dev/null
@@ -0,0 +1,148 @@
+#include <arch/arch.h>
+#include <trap.h>
+#include <process.h>
+#include <pmap.h>
+#include <smp.h>
+
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+
+/* TODO: handle user and kernel contexts */
+void proc_pop_ctx(struct user_context *ctx)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       assert(ctx->type == ROS_HW_CTX);
+
+       /* Bug with this whole idea (TODO: (TLSV))*/
+       /* Load the LDT for this process.  Slightly ghetto doing it here. */
+       /* copy-in and check the LDT location.  the segmentation hardware writes the
+        * accessed bit, so we want the memory to be in the user-writeable area. */
+       segdesc_t *ldt = current->procdata->ldt;
+       ldt = (segdesc_t*)MIN((uintptr_t)ldt, UWLIM - LDT_SIZE);
+       /* Only set up the ldt if a pointer to the ldt actually exists */
+       if(ldt != NULL) {
+               segdesc_t *my_gdt = per_cpu_info[core_id()].gdt;
+               segdesc_t ldt_temp = SEG_SYS(STS_LDT, (uint32_t)ldt, LDT_SIZE, 3);
+               my_gdt[GD_LDT >> 3] = ldt_temp;
+               asm volatile("lldt %%ax" :: "a"(GD_LDT));
+       }
+
+       /* In case they are enabled elsewhere.  We can't take an interrupt in these
+        * routines, due to how they play with the kernel stack pointer. */
+       disable_irq();
+       /*
+        * If the process entered the kernel via sysenter, we need to leave via
+        * sysexit.  sysenter trapframes have 0 for a CS, which is pushed in
+        * sysenter_handler.
+        */
+       if(tf->tf_cs) {
+               /*
+                * Restores the register values in the Trapframe with the 'iret'
+                * instruction.  This exits the kernel and starts executing some
+                * environment's code.  This function does not return.
+                */
+               asm volatile ("movl %0,%%esp;           "
+                             "popal;                   "
+                             "popl %%gs;               "
+                             "popl %%fs;               "
+                             "popl %%es;               "
+                             "popl %%ds;               "
+                             "addl $0x8,%%esp;         "
+                             "iret                     "
+                             : : "g" (tf) : "memory");
+               panic("iret failed");  /* mostly to placate the compiler */
+       } else {
+               /* Return path of sysexit.  See sysenter_handler's asm for details.
+                * One difference is that this tf could be somewhere other than a stack
+                * (like in a struct proc).  We need to make sure esp is valid once
+                * interrupts are turned on (which would happen on popfl normally), so
+                * we need to save and restore a decent esp (the current one).  We need
+                * a place to save it that is accessible after we change the stack
+                * pointer to the tf *and* that is specific to this core/instance of
+                * sysexit.  The simplest and nicest is to use the tf_esp, which we
+                * can just pop.  Incidentally, the value in oesp would work too.
+                * To prevent popfl from turning interrupts on, we hack the tf's eflags
+                * so that we have a chance to change esp to a good value before
+                * interrupts are enabled.  The other option would be to throw away the
+                * eflags, but that's less desirable. */
+               tf->tf_eflags &= !FL_IF;
+               tf->tf_esp = read_sp();
+               asm volatile ("movl %0,%%esp;           "
+                             "popal;                   "
+                             "popl %%gs;               "
+                             "popl %%fs;               "
+                             "popl %%es;               "
+                             "popl %%ds;               "
+                             "addl $0x10,%%esp;        "
+                             "popfl;                   "
+                             "movl %%ebp,%%ecx;        "
+                             "popl %%esp;              "
+                             "sti;                     "
+                             "sysexit                  "
+                             : : "g" (tf) : "memory");
+               panic("sysexit failed");  /* mostly to placate your mom */
+       }
+}
+
+/* TODO: consider using a SW context */
+void proc_init_ctx(struct user_context *ctx, uint32_t vcoreid, uintptr_t entryp,
+                   uintptr_t stack_top)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       ctx->type = ROS_HW_CTX;
+
+       memset(tf,0,sizeof(*tf));
+
+       /* Set up appropriate initial values for the segment registers.
+        * GD_UD is the user data segment selector in the GDT, and
+        * GD_UT is the user text segment selector (see inc/memlayout.h).
+        * The low 2 bits of each segment register contains the
+        * Requestor Privilege Level (RPL); 3 means user mode. */
+       tf->tf_ds = GD_UD | 3;
+       tf->tf_es = GD_UD | 3;
+       tf->tf_ss = GD_UD | 3;
+       tf->tf_esp = stack_top-64;
+       tf->tf_cs = GD_UT | 3;
+       /* set the env's EFLAGSs to have interrupts enabled */
+       tf->tf_eflags |= 0x00000200; // bit 9 is the interrupts-enabled
+
+       tf->tf_eip = entryp;
+
+       /* Coupled closely with user's entry.S.  id is the vcoreid, which entry.S
+        * uses to determine what to do.  vcoreid == 0 is the main core/context. */
+       tf->tf_regs.reg_eax = vcoreid;
+}
+
+/* TODO: handle both HW and SW contexts */
+void proc_secure_ctx(struct user_context *ctx)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       ctx->type = ROS_HW_CTX;
+       /* we normally don't need to set the non-CS regs, but they could be
+        * gibberish and cause a GPF.  gs can still be gibberish, but we don't
+        * necessarily know what it ought to be (we could check, but that's a pain).
+        * the code protecting the kernel from TLS related things ought to be able
+        * to handle GPFs on popping gs. TODO: (TLSV) */
+       tf->tf_ds = GD_UD | 3;
+       tf->tf_es = GD_UD | 3;
+       tf->tf_fs = 0;
+       //tf->tf_gs = whatevs.  ignoring this.
+       tf->tf_ss = GD_UD | 3;
+       tf->tf_cs ? GD_UT | 3 : 0; // can be 0 for sysenter TFs.
+       tf->tf_eflags |= 0x00000200; // bit 9 is the interrupts-enabled
+}
+
+/* Called when we are currently running an address space on our core and want to
+ * abandon it.  We need a known good pgdir before releasing the old one.  We
+ * decref, since current no longer tracks the proc (and current no longer
+ * protects the cr3).  We also need to clear out the TLS registers (before
+ * unmapping the address space!) */
+void __abandon_core(void)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       asm volatile ("movw %%ax,%%gs; lldt %%ax" :: "a"(0));
+       lcr3(boot_cr3);
+       proc_decref(pcpui->cur_proc);
+       pcpui->cur_proc = 0;
+}
diff --git a/kern/arch/x86/process64.c b/kern/arch/x86/process64.c
new file mode 100644 (file)
index 0000000..882c1e9
--- /dev/null
@@ -0,0 +1,153 @@
+#include <arch/arch.h>
+#include <trap.h>
+#include <process.h>
+#include <pmap.h>
+#include <smp.h>
+
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+
+/* TODO: handle user and kernel contexts */
+void proc_pop_ctx(struct user_context *ctx)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       assert(ctx->type == ROS_HW_CTX);
+
+       /* Bug with this whole idea (TODO: (TLSV))*/
+       /* Load the LDT for this process.  Slightly ghetto doing it here. */
+       /* copy-in and check the LDT location.  the segmentation hardware writes the
+        * accessed bit, so we want the memory to be in the user-writeable area. */
+       segdesc_t *ldt = current->procdata->ldt;
+       ldt = (segdesc_t*)MIN((uintptr_t)ldt, UWLIM - LDT_SIZE);
+       /* Only set up the ldt if a pointer to the ldt actually exists */
+#if 0 /* think about how to do TLS.  need better seg macros too */
+       if(ldt != NULL) {
+               segdesc_t *my_gdt = per_cpu_info[core_id()].gdt;
+               /* TODO: 64b issues here.  need to redo this anyways.  Considering how
+                * slow userspace TLS changes are (70ns), I might opt for just changing
+                * FS base, either via fast syscall or in userspace on newer versions */
+               segdesc_t ldt_temp = SEG_SYS(STS_LDT, (uint32_t)ldt, LDT_SIZE, 3);
+               my_gdt[GD_LDT >> 3] = ldt_temp;
+               asm volatile("lldt %%ax" :: "a"(GD_LDT));
+       }
+#endif
+
+       /* In case they are enabled elsewhere.  We can't take an interrupt in these
+        * routines, due to how they play with the kernel stack pointer. */
+       disable_irq();
+       /*
+        * If the process entered the kernel via sysenter, we need to leave via
+        * sysexit.  sysenter trapframes have 0 for a CS, which is pushed in
+        * sysenter_handler.
+        */
+       if(tf->tf_cs) {
+               /*
+                * Restores the register values in the Trapframe with the 'iret'
+                * instruction.  This exits the kernel and starts executing some
+                * environment's code.  This function does not return.
+                */
+//             asm volatile ("movl %0,%%esp;           "
+//                           "popal;                   "
+//                           "popl %%gs;               "
+//                           "popl %%fs;               "
+//                           "popl %%es;               "
+//                           "popl %%ds;               "
+//                           "addl $0x8,%%esp;         "
+//                           "iret                     "
+//                           : : "g" (tf) : "memory");
+               panic("iret failed");  /* mostly to placate the compiler */
+       } else {
+               /* Return path of sysexit.  See sysenter_handler's asm for details.
+                * One difference is that this tf could be somewhere other than a stack
+                * (like in a struct proc).  We need to make sure esp is valid once
+                * interrupts are turned on (which would happen on popfl normally), so
+                * we need to save and restore a decent esp (the current one).  We need
+                * a place to save it that is accessible after we change the stack
+                * pointer to the tf *and* that is specific to this core/instance of
+                * sysexit.  The simplest and nicest is to use the tf_esp, which we
+                * can just pop.  Incidentally, the value in oesp would work too.
+                * To prevent popfl from turning interrupts on, we hack the tf's eflags
+                * so that we have a chance to change esp to a good value before
+                * interrupts are enabled.  The other option would be to throw away the
+                * eflags, but that's less desirable. */
+               tf->tf_eflags &= !FL_IF;
+               tf->tf_esp = read_sp();
+//             asm volatile ("movl %0,%%esp;           "
+//                           "popal;                   "
+//                           "popl %%gs;               "
+//                           "popl %%fs;               "
+//                           "popl %%es;               "
+//                           "popl %%ds;               "
+//                           "addl $0x10,%%esp;        "
+//                           "popfl;                   "
+//                           "movl %%ebp,%%ecx;        "
+//                           "popl %%esp;              "
+//                           "sti;                     "
+//                           "sysexit                  "
+//                           : : "g" (tf) : "memory");
+               panic("sysexit failed");  /* mostly to placate your mom */
+       }
+}
+
+/* TODO: consider using a SW context */
+void proc_init_ctx(struct user_context *ctx, uint32_t vcoreid, uintptr_t entryp,
+                   uintptr_t stack_top)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       ctx->type = ROS_HW_CTX;
+
+       memset(tf,0,sizeof(*tf));
+
+       /* Set up appropriate initial values for the segment registers.
+        * GD_UD is the user data segment selector in the GDT, and
+        * GD_UT is the user text segment selector (see inc/memlayout.h).
+        * The low 2 bits of each segment register contains the
+        * Requestor Privilege Level (RPL); 3 means user mode. */
+       tf->tf_ds = GD_UD | 3;
+       tf->tf_es = GD_UD | 3;
+       tf->tf_ss = GD_UD | 3;
+       tf->tf_esp = stack_top-64;
+       tf->tf_cs = GD_UT | 3;
+       /* set the env's EFLAGSs to have interrupts enabled */
+       tf->tf_eflags |= 0x00000200; // bit 9 is the interrupts-enabled
+
+       tf->tf_eip = entryp;
+
+       /* Coupled closely with user's entry.S.  id is the vcoreid, which entry.S
+        * uses to determine what to do.  vcoreid == 0 is the main core/context. */
+       tf->tf_regs.reg_eax = vcoreid;
+}
+
+/* TODO: handle both HW and SW contexts */
+void proc_secure_ctx(struct user_context *ctx)
+{
+       struct hw_trapframe *tf = &ctx->tf.hw_tf;
+       ctx->type = ROS_HW_CTX;
+       /* we normally don't need to set the non-CS regs, but they could be
+        * gibberish and cause a GPF.  gs can still be gibberish, but we don't
+        * necessarily know what it ought to be (we could check, but that's a pain).
+        * the code protecting the kernel from TLS related things ought to be able
+        * to handle GPFs on popping gs. TODO: (TLSV) */
+       tf->tf_ds = GD_UD | 3;
+       tf->tf_es = GD_UD | 3;
+       tf->tf_fs = 0;
+       //tf->tf_gs = whatevs.  ignoring this.
+       tf->tf_ss = GD_UD | 3;
+       tf->tf_cs ? GD_UT | 3 : 0; // can be 0 for sysenter TFs.
+       tf->tf_eflags |= 0x00000200; // bit 9 is the interrupts-enabled
+}
+
+/* Called when we are currently running an address space on our core and want to
+ * abandon it.  We need a known good pgdir before releasing the old one.  We
+ * decref, since current no longer tracks the proc (and current no longer
+ * protects the cr3).  We also need to clear out the TLS registers (before
+ * unmapping the address space!) */
+void __abandon_core(void)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       asm volatile ("movw %%ax,%%gs; lldt %%ax" :: "a"(0));
+       lcr3(boot_cr3);
+       proc_decref(pcpui->cur_proc);
+       pcpui->cur_proc = 0;
+}
diff --git a/kern/arch/x86/ros/bits/syscall.h b/kern/arch/x86/ros/bits/syscall.h
deleted file mode 100644 (file)
index 1fc420a..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef _ROS_ARCH_BITS_SYSCALL_H
-#define _ROS_ARCH_BITS_SYSCALL_H
-
-#define T_SYSCALL      0x80
-
-#ifndef ROS_KERNEL
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <ros/common.h>
-#include <assert.h>
-
-static inline intreg_t __syscall_sysenter(uintreg_t a0, uintreg_t a1)
-{
-       /* The kernel clobbers ecx, so we save it manually. */
-       intreg_t ret = 0;
-       asm volatile ("  pushl %%ecx;        "
-                     "  pushl %%edx;        "
-                     "  pushl %%ebp;        "
-                     "  movl %%esp, %%ebp;  "
-                     "  leal 1f, %%edx;     "
-                     "  sysenter;           "
-                     "1:                    "
-                     "  popl %%ebp;         "
-                     "  popl %%edx;         "
-                     "  popl %%ecx;         "
-                     : "=a" (ret)
-                     : "a" (a0),
-                       "S" (a1)
-                     : "cc", "memory");
-       return ret;
-}
-
-static inline intreg_t __syscall_trap(uintreg_t a0, uintreg_t a1)
-{
-       intreg_t ret;
-
-       /* If you change this, change pop_user_ctx() */
-       asm volatile("int %1"
-                    : "=a" (ret)
-                    : "i" (T_SYSCALL),
-                      "a" (a0),
-                      "d" (a1)
-                    : "cc", "memory");
-       return ret;
-}
-
-#endif
-
-#endif
-
index 64a1d1d..960b40f 100644 (file)
 #ifndef ROS_INC_ARCH_MMU_H
 #define ROS_INC_ARCH_MMU_H
 
-#ifndef __ASSEMBLER__
-#include <ros/common.h>
-typedef unsigned long pte_t;
-typedef unsigned long pde_t;
+#ifdef __x86_64__
+#include <ros/arch/mmu64.h>
+#else
+#include <ros/arch/mmu32.h>
 #endif
 
 /* **************************************** */
-/* Kernel Virtual Memory Mapping  (not really an MMU thing) */
-
-#define KERNBASE        0xC0000000
-#define KERN_LOAD_ADDR  KERNBASE
-
-/* Static kernel mappings */
-/* 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 LAPIC_BASE             (VPT - PGSIZE)
-#define IOAPIC_BASE            (LAPIC_BASE - PGSIZE)
-
-/* All arches must define this, which is the lower limit of their static
- * mappings, and where the dynamic mappings will start. */
-#define KERN_DYN_TOP   IOAPIC_BASE
-
-#define ULIM            0x80000000
-
-// Use this if needed in annotations
-#define IVY_KERNBASE (0xC000U << 16)
-
-/* **************************************** */
-/* Page table constants, macros, etc */
-
-// 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) ----/
-//  \----------- PPN(la) -----------/
-//
-// The PDX, PTX, PGOFF, and PPN 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 LA2PPN(la)     (((uintptr_t) (la)) >> PTXSHIFT)
-#define PTE2PPN(pte)   LA2PPN(pte)
-#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)
-
-// offset in jumbo page
-#define JPGOFF(la)     (((uintptr_t) (la)) & 0x003FFFFF)
-
-// construct PTE from PPN and flags
-#define PTE(ppn, flags) ((ppn) << PTXSHIFT | PGOFF(flags))
-
-// construct linear address from indexes and offset
-#define PGADDR(d, t, o)        ((void*SNT) ((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 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 (only applies to PDEs)
-#define PTE_PAT                0x080   // PAT (only applies to second layer PTEs)
-#define PTE_G          0x100   // Global Page
-
-#define PTE_PERM       (PTE_W | PTE_U) // The permissions fields
-// commly used access modes
-#define PTE_KERN_RW    PTE_W           // Kernel Read/Write
-#define PTE_KERN_RO    0               // Kernel Read-Only
-#define PTE_USER_RW    (PTE_W | PTE_U) // Kernel/User Read/Write
-#define PTE_USER_RO    PTE_U           // Kernel/User Read-Only
-
-// 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_USER may be used in system calls.
-#define PTE_USER       (PTE_AVAIL | PTE_P | PTE_W | PTE_U)
-
-// address in page table entry
-#define PTE_ADDR(pte)  ((physaddr_t) (pte) & ~0xFFF)
-
-#define PTSHIFT 22
-#define PTSIZE (1 << PTSHIFT)
-#define PGSHIFT 12
-#define PGSIZE (1 << PGSHIFT)
-#define JPGSIZE PTSIZE
-
-// we must guarantee that for any PTE, exactly one of the following is true
-#define PAGE_PRESENT(pte) ((pte) & PTE_P)
-#define PAGE_UNMAPPED(pte) ((pte) == 0)
-#define PAGE_PAGED_OUT(pte) (!PAGE_PRESENT(pte) && !PAGE_UNMAPPED(pte))
-
-/* **************************************** */
 /* Control Registers */
 
 // Control Register flags
@@ -184,222 +73,4 @@ typedef unsigned long pde_t;
 #define FEC_WR         0x2     // Page fault caused by a write
 #define FEC_U          0x4     // Page fault occured while in user mode
 
-/* **************************************** */
-/* Segmentation */
-
-// Global descriptor numbers
-#define GD_NULL   0x00     // NULL descriptor
-#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
-#define GD_LDT    0x30     // local descriptor table
-
-#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__
-
-// Segment Descriptors
-typedef 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
-} segdesc_t;
-// Null segment
-#define SEG_NULL       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
-// Segment that is loadable but faults when used
-#define SEG_FAULT      { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 }
-// Normal segment
-#define SEG(type, base, lim, dpl)                                                                      \
-{ ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,      \
-    type, 1, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1,                       \
-    (unsigned) (base) >> 24 }
-// System segment (LDT)
-#define SEG_SYS(type, base, lim, dpl)                                                                  \
-{ ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,      \
-    type, 0, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1,                       \
-    (unsigned) (base) >> 24 }
-
-#define SEG16(type, base, lim, dpl)                                                            \
-{ (lim) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,                      \
-    type, 1, dpl, 1, (unsigned) (lim) >> 16, 0, 0, 1, 0,                       \
-    (unsigned) (base) >> 24 }
-
-#define SEG16ROINIT(seg,type,base,lim,dpl) \
-       {\
-               (seg).sd_lim_15_0 = SINIT((lim) & 0xffff);\
-               (seg).sd_base_15_0 = SINIT((base)&0xffff);\
-               (seg).sd_base_23_16 = SINIT(((base)>>16)&0xff);\
-               (seg).sd_type = SINIT(type);\
-               (seg).sd_s = SINIT(1);\
-               (seg).sd_dpl = SINIT(dpl);\
-               (seg).sd_p = SINIT(1);\
-               (seg).sd_lim_19_16 = SINIT((unsigned)(lim)>>16);\
-               (seg).sd_avl = SINIT(0);\
-               (seg).sd_rsv1 = SINIT(0);\
-               (seg).sd_db = SINIT(1);\
-               (seg).sd_g = SINIT(0);\
-               (seg).sd_base_31_24 = SINIT((unsigned)(base)>> 24);\
-       }
-
-// Task state segment format (as described by the Pentium architecture book)
-typedef 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
-} taskstate_t;
-
-// Gate descriptors for interrupts and traps
-typedef 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;         // DPL - highest ring allowed to use this
-       unsigned gd_p : 1;           // Present
-       unsigned gd_off_31_16 : 16;  // high bits of offset in segment
-} gatedesc_t;
-
-// Set up a normal interrupt/trap gate descriptor.
-// - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate.
-//   - interrupt gates automatically disable interrupts (cli)
-// - 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;           \
-}
-
-#define ROSETGATE(gate, istrap, sel, off, dpl)                 \
-{                                                              \
-       (gate).gd_off_15_0 = SINIT((uint32_t) (off) & 0xffff);          \
-       (gate).gd_ss = SINIT(sel);                                      \
-       (gate).gd_args = SINIT(0);                                      \
-       (gate).gd_rsv1 = SINIT(0);                                      \
-       (gate).gd_type = SINIT((istrap) ? STS_TG32 : STS_IG32); \
-       (gate).gd_s = SINIT(0);                                 \
-       (gate).gd_dpl = SINIT(dpl);                                     \
-       (gate).gd_p = SINIT(1);                                 \
-       (gate).gd_off_31_16 = SINIT((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.
-typedef struct Pseudodesc {
-       uint16_t pd_lim;                // Limit
-       uint32_t pd_base;               // Base address
-} __attribute__ ((packed)) pseudodesc_t;
-
-extern segdesc_t (COUNT(SEG_COUNT) RO gdt)[];
-extern pseudodesc_t gdt_pd;
-
-#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
-
-#define SEG_COUNT      7               // Number of segments in the steady state
-#define LDT_SIZE       (8192 * sizeof(segdesc_t))
-
 #endif /* ROS_INC_ARCH_MMU_H */
diff --git a/kern/arch/x86/ros/mmu32.h b/kern/arch/x86/ros/mmu32.h
new file mode 100644 (file)
index 0000000..3a74b75
--- /dev/null
@@ -0,0 +1,430 @@
+#ifndef ROS_INC_ARCH_MMU32_H
+#define ROS_INC_ARCH_MMU32_H
+
+#ifndef ROS_INC_ARCH_MMU_H
+#error "Do not include include ros/arch/mmu32.h directly"
+#endif
+
+#ifndef __ASSEMBLER__
+#include <ros/common.h>
+typedef unsigned long pte_t;
+typedef unsigned long pde_t;
+#endif
+
+/* x86's 32 bit Virtual Memory Map.  Symbols are similar on other archs
+ *
+ * Virtual memory map:                                Permissions
+ *                                                    kernel/user
+ *
+ *    4 Gig -------->  +------------------------------+
+ *                     :              .               :
+ *  KERN_VMAP_TOP      +------------------------------+ 0xfffff000
+ *                     |                              |
+ *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RW/--
+ *                     :              .               :
+ *                     :              .               :
+ *                     :              .               :
+ *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| RW/--
+ *                     |                              | RW/--
+ *                     |   Remapped Physical Memory   | RW/--
+ *                     |                              | RW/--
+ *    KERNBASE ----->  +------------------------------+ 0xc0000000
+ *                     |  Cur. Page Table (Kern. RW)  | RW/--  PTSIZE
+ *    VPT          --> +------------------------------+ 0xbfc00000
+ *                     |          Local APIC          | RW/--  PGSIZE
+ *    LAPIC        --> +------------------------------+ 0xbfbff000
+ *                     |            IOAPIC            | RW/--  PGSIZE
+ *    IOAPIC,      --> +------------------------------+ 0xbfbfe000
+ *  KERN_DYN_TOP       |   Kernel Dynamic Mappings    |
+ *                     |              .               |
+ *                     :              .               :
+ *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RW/--
+ *                     :                              :
+ *                     |      Invalid Memory (*)      | --/--
+ *    ULIM      ---->  +------------------------------+ 0x80000000      --+
+ *                     |  Cur. Page Table (User R-)   | R-/R-  PTSIZE     |
+ *    UVPT      ---->  +------------------------------+ 0x7fc00000      --+
+ *                     | Unmapped (expandable region) |                   |
+ *                     |                              | R-/R-            PTSIZE
+ *                     |     Per-Process R/O Info     |                   |
+ * UWLIM, UINFO ---->  +------------------------------+ 0x7f800000      --+
+ *                     | Unmapped (expandable region) |                   |
+ *                     |                              | RW/RW            PTSIZE
+ *                     |     Per-Process R/W Data     |                   |
+ *    UDATA     ---->  +------------------------------+ 0x7f400000      --+
+ *    UMAPTOP,         |    Global Shared R/W Data    | RW/RW  PGSIZE
+ * UXSTACKTOP,UGDATA ->+------------------------------+ 0x7f3ff000
+ *                     |     User Exception Stack     | RW/RW  PGSIZE
+ *                     +------------------------------+ 0x7f3fe000
+ *                     |       Empty Memory (*)       | --/--  PGSIZE
+ *    USTACKTOP  --->  +------------------------------+ 0x7f3fd000
+ *                     |      Normal User Stack       | RW/RW  256*PGSIZE (1MB)
+ *                     +------------------------------+ 0x7f2fd000
+ *                     |       Empty Memory (*)       | --/--  PGSIZE
+ *    USTACKBOT  --->  +------------------------------+ 0x7f2fc000
+ *                     |                              |
+ *                     |                              |
+ *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *                     .                              .
+ *                     .                              .
+ *                     .                              .
+ *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
+ *                     |     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.  ROS user programs map pages temporarily
+ *     at UTEMP.
+ */
+
+
+// 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 VGAPHYSMEM     0x0A0000
+#define DEVPHYSMEM     0x0C0000
+#define BIOSPHYSMEM    0x0F0000
+
+/* **************************************** */
+/* Kernel Virtual Memory Mapping  (not really an MMU thing) */
+
+#define KERNBASE        0xC0000000
+#define KERN_LOAD_ADDR  KERNBASE
+/* Top of the kernel virtual mapping area (KERNBASE) */
+/* For sanity reasons, I don't plan to map the top page */
+#define KERN_VMAP_TOP                          0xfffff000
+
+/* Static kernel mappings */
+/* 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 LAPIC_BASE             (VPT - PGSIZE)
+#define IOAPIC_BASE            (LAPIC_BASE - PGSIZE)
+
+/* All arches must define this, which is the lower limit of their static
+ * mappings, and where the dynamic mappings will start. */
+#define KERN_DYN_TOP   IOAPIC_BASE
+
+#define ULIM            0x80000000
+
+// Use this if needed in annotations
+#define IVY_KERNBASE (0xC000U << 16)
+
+/* **************************************** */
+/* Page table constants, macros, etc */
+
+// 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) ----/
+//  \----------- PPN(la) -----------/
+//
+// The PDX, PTX, PGOFF, and PPN 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 LA2PPN(la)     (((uintptr_t) (la)) >> PTXSHIFT)
+#define PTE2PPN(pte)   LA2PPN(pte)
+#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)
+
+// offset in jumbo page
+#define JPGOFF(la)     (((uintptr_t) (la)) & 0x003FFFFF)
+
+// construct PTE from PPN and flags
+#define PTE(ppn, flags) ((ppn) << PTXSHIFT | PGOFF(flags))
+
+// construct linear address from indexes and offset
+#define PGADDR(d, t, o)        ((void*SNT) ((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 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 (only applies to PDEs)
+#define PTE_PAT                0x080   // PAT (only applies to second layer PTEs)
+#define PTE_G          0x100   // Global Page
+
+#define PTE_PERM       (PTE_W | PTE_U) // The permissions fields
+// commly used access modes
+#define PTE_KERN_RW    PTE_W           // Kernel Read/Write
+#define PTE_KERN_RO    0               // Kernel Read-Only
+#define PTE_USER_RW    (PTE_W | PTE_U) // Kernel/User Read/Write
+#define PTE_USER_RO    PTE_U           // Kernel/User Read-Only
+
+// 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_USER may be used in system calls.
+#define PTE_USER       (PTE_AVAIL | PTE_P | PTE_W | PTE_U)
+
+// address in page table entry
+#define PTE_ADDR(pte)  ((physaddr_t) (pte) & ~0xFFF)
+
+#define PTSHIFT 22
+#define PTSIZE (1 << PTSHIFT)
+#define PGSHIFT 12
+#define PGSIZE (1 << PGSHIFT)
+#define JPGSIZE PTSIZE
+
+// we must guarantee that for any PTE, exactly one of the following is true
+#define PAGE_PRESENT(pte) ((pte) & PTE_P)
+#define PAGE_UNMAPPED(pte) ((pte) == 0)
+#define PAGE_PAGED_OUT(pte) (!PAGE_PRESENT(pte) && !PAGE_UNMAPPED(pte))
+
+/* **************************************** */
+/* Segmentation */
+
+// Global descriptor numbers
+#define GD_NULL   0x00     // NULL descriptor
+#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
+#define GD_LDT    0x30     // local descriptor table
+
+#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__
+
+// Segment Descriptors
+typedef 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
+} segdesc_t;
+// Null segment
+#define SEG_NULL       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+// Segment that is loadable but faults when used
+#define SEG_FAULT      { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 }
+// Normal segment
+#define SEG(type, base, lim, dpl)                                                                      \
+{ ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,      \
+    type, 1, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1,                       \
+    (unsigned) (base) >> 24 }
+// System segment (LDT)
+#define SEG_SYS(type, base, lim, dpl)                                                                  \
+{ ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,      \
+    type, 0, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1,                       \
+    (unsigned) (base) >> 24 }
+
+#define SEG16(type, base, lim, dpl)                                                            \
+{ (lim) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,                      \
+    type, 1, dpl, 1, (unsigned) (lim) >> 16, 0, 0, 1, 0,                       \
+    (unsigned) (base) >> 24 }
+
+#define SEG16ROINIT(seg,type,base,lim,dpl) \
+       {\
+               (seg).sd_lim_15_0 = SINIT((lim) & 0xffff);\
+               (seg).sd_base_15_0 = SINIT((uint32_t)(base)&0xffff);\
+               (seg).sd_base_23_16 = SINIT(((uint32_t)(base)>>16)&0xff);\
+               (seg).sd_type = SINIT(type);\
+               (seg).sd_s = SINIT(1);\
+               (seg).sd_dpl = SINIT(dpl);\
+               (seg).sd_p = SINIT(1);\
+               (seg).sd_lim_19_16 = SINIT((unsigned)(lim)>>16);\
+               (seg).sd_avl = SINIT(0);\
+               (seg).sd_rsv1 = SINIT(0);\
+               (seg).sd_db = SINIT(1);\
+               (seg).sd_g = SINIT(0);\
+               (seg).sd_base_31_24 = SINIT((uint32_t)(base)>> 24);\
+       }
+
+// Task state segment format (as described by the Pentium architecture book)
+typedef 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
+} taskstate_t;
+
+// Gate descriptors for interrupts and traps
+typedef 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;         // DPL - highest ring allowed to use this
+       unsigned gd_p : 1;           // Present
+       unsigned gd_off_31_16 : 16;  // high bits of offset in segment
+} gatedesc_t;
+
+// Set up a normal interrupt/trap gate descriptor.
+// - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate.
+//   - interrupt gates automatically disable interrupts (cli)
+// - 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;           \
+}
+
+#define ROSETGATE(gate, istrap, sel, off, dpl)                 \
+{                                                              \
+       (gate).gd_off_15_0 = SINIT((uint32_t) (off) & 0xffff);          \
+       (gate).gd_ss = SINIT(sel);                                      \
+       (gate).gd_args = SINIT(0);                                      \
+       (gate).gd_rsv1 = SINIT(0);                                      \
+       (gate).gd_type = SINIT((istrap) ? STS_TG32 : STS_IG32); \
+       (gate).gd_s = SINIT(0);                                 \
+       (gate).gd_dpl = SINIT(dpl);                                     \
+       (gate).gd_p = SINIT(1);                                 \
+       (gate).gd_off_31_16 = SINIT((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.
+typedef struct Pseudodesc {
+       uint16_t pd_lim;                // Limit
+       uint32_t pd_base;               // Base address
+} __attribute__ ((packed)) pseudodesc_t;
+
+extern segdesc_t (COUNT(SEG_COUNT) RO gdt)[];
+extern pseudodesc_t gdt_pd;
+
+#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
+
+#define SEG_COUNT      7               // Number of segments in the steady state
+#define LDT_SIZE       (8192 * sizeof(segdesc_t))
+#endif /* ROS_INC_ARCH_MMU32_H */
diff --git a/kern/arch/x86/ros/mmu64.h b/kern/arch/x86/ros/mmu64.h
new file mode 100644 (file)
index 0000000..fd2dbe8
--- /dev/null
@@ -0,0 +1,436 @@
+#ifndef ROS_INC_ARCH_MMU64_H
+#define ROS_INC_ARCH_MMU64_H
+
+#ifndef ROS_INC_ARCH_MMU_H
+#error "Do not include include ros/arch/mmu64.h directly"
+#endif
+
+#ifndef __ASSEMBLER__
+#include <ros/common.h>
+typedef unsigned long pte_t;
+typedef unsigned long pde_t;
+#endif
+
+// TODO: 64 bit
+/* x86's 32 bit Virtual Memory Map.  Symbols are similar on other archs
+ *
+ * Virtual memory map:                                Permissions
+ *                                                    kernel/user
+ *
+ *    4 Gig -------->  +------------------------------+
+ *                     :              .               :
+ *  KERN_LOAD_ADDR,    +------------------------------+ 0xffffffffc0000000
+ *  KERN_VMAP_TOP      |                              |
+ *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RW/--
+ *                     :              .               :
+ *                     :              .               :
+ *                     :              .               :
+ *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| RW/--
+ *                     |                              | RW/--
+ *                     |   Remapped Physical Memory   | RW/--
+ *                     |                              | RW/--
+ *    KERNBASE ----->  +------------------------------+ 0xffff80000000
+ *
+ *
+ *
+ *                     |  Cur. Page Table (Kern. RW)  | RW/--  PTSIZE
+ *    VPT          --> +------------------------------+ 0xbfc00000
+ *                     |          Local APIC          | RW/--  PGSIZE
+ *    LAPIC        --> +------------------------------+ 0xbfbff000
+ *                     |            IOAPIC            | RW/--  PGSIZE
+ *    IOAPIC,      --> +------------------------------+ 0xbfbfe000
+ *  KERN_DYN_TOP       |   Kernel Dynamic Mappings    |
+ *                     |              .               |
+ *                     :              .               :
+ *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RW/--
+ *                     :                              :
+ *                     |      Invalid Memory (*)      | --/--
+ *    ULIM      ---->  +------------------------------+ 0x80000000      --+
+ *                     |  Cur. Page Table (User R-)   | R-/R-  PTSIZE     |
+ *    UVPT      ---->  +------------------------------+ 0x7fc00000      --+
+ *                     | Unmapped (expandable region) |                   |
+ *                     |                              | R-/R-            PTSIZE
+ *                     |     Per-Process R/O Info     |                   |
+ * UWLIM, UINFO ---->  +------------------------------+ 0x7f800000      --+
+ *                     | Unmapped (expandable region) |                   |
+ *                     |                              | RW/RW            PTSIZE
+ *                     |     Per-Process R/W Data     |                   |
+ *    UDATA     ---->  +------------------------------+ 0x7f400000      --+
+ *    UMAPTOP,         |    Global Shared R/W Data    | RW/RW  PGSIZE
+ * UXSTACKTOP,UGDATA ->+------------------------------+ 0x7f3ff000
+ *                     |     User Exception Stack     | RW/RW  PGSIZE
+ *                     +------------------------------+ 0x7f3fe000
+ *                     |       Empty Memory (*)       | --/--  PGSIZE
+ *    USTACKTOP  --->  +------------------------------+ 0x7f3fd000
+ *                     |      Normal User Stack       | RW/RW  256*PGSIZE (1MB)
+ *                     +------------------------------+ 0x7f2fd000
+ *                     |       Empty Memory (*)       | --/--  PGSIZE
+ *    USTACKBOT  --->  +------------------------------+ 0x7f2fc000
+ *                     |                              |
+ *                     |                              |
+ *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *                     .                              .
+ *                     .                              .
+ *                     .                              .
+ *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
+ *                     |     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.  ROS user programs map pages temporarily
+ *     at UTEMP.
+ */
+
+
+// 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 VGAPHYSMEM     0x0A0000
+#define DEVPHYSMEM     0x0C0000
+#define BIOSPHYSMEM    0x0F0000
+#define EXTPHYSMEM     0x100000
+
+/* **************************************** */
+/* Kernel Virtual Memory Mapping  (not really an MMU thing) */
+
+#define KERNBASE        0xffff800000000000
+#define KERN_LOAD_ADDR  0xffffffffc0000000
+/* Top of the kernel virtual mapping area (KERNBASE) */
+#define KERN_VMAP_TOP  KERN_LOAD_ADDR /* upper 2GB reserved */
+
+/* Static kernel mappings */
+/* 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                            (KERN_LOAD_ADDR - PTSIZE)
+#define LAPIC_BASE             (VPT - PGSIZE)
+#define IOAPIC_BASE            (LAPIC_BASE - PGSIZE)
+
+/* All arches must define this, which is the lower limit of their static
+ * mappings, and where the dynamic mappings will start. */
+#define KERN_DYN_TOP   IOAPIC_BASE
+
+/* Highest user address: 0x00007fffffffffff: 1 zero, 47 ones, sign extended */
+#define ULIM            0x0000800000000000
+
+// Use this if needed in annotations
+//#define IVY_KERNBASE (0xC000U << 16)
+
+/* **************************************** */
+/* Page table constants, macros, etc */
+
+// 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) ----/
+//  \----------- PPN(la) -----------/
+//
+// The PDX, PTX, PGOFF, and PPN 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 LA2PPN(la)     (((uintptr_t) (la)) >> PTXSHIFT)
+#define PTE2PPN(pte)   LA2PPN(pte)
+#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)
+
+// offset in jumbo page
+#define JPGOFF(la)     (((uintptr_t) (la)) & 0x003FFFFF)
+
+// construct PTE from PPN and flags
+#define PTE(ppn, flags) ((ppn) << PTXSHIFT | PGOFF(flags))
+
+// construct linear address from indexes and offset
+#define PGADDR(d, t, o)        ((void*SNT) ((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 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 (only applies to PDEs)
+#define PTE_PAT                0x080   // PAT (only applies to second layer PTEs)
+#define PTE_G          0x100   // Global Page
+
+#define PTE_PERM       (PTE_W | PTE_U) // The permissions fields
+// commly used access modes
+#define PTE_KERN_RW    PTE_W           // Kernel Read/Write
+#define PTE_KERN_RO    0               // Kernel Read-Only
+#define PTE_USER_RW    (PTE_W | PTE_U) // Kernel/User Read/Write
+#define PTE_USER_RO    PTE_U           // Kernel/User Read-Only
+
+// 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_USER may be used in system calls.
+#define PTE_USER       (PTE_AVAIL | PTE_P | PTE_W | PTE_U)
+
+// address in page table entry
+#define PTE_ADDR(pte)  ((physaddr_t) (pte) & ~0xFFF)
+
+#define PTSHIFT 22
+#define PTSIZE (1 << PTSHIFT)
+#define PGSHIFT 12
+#define PGSIZE (1 << PGSHIFT)
+#define JPGSIZE PTSIZE
+
+// we must guarantee that for any PTE, exactly one of the following is true
+#define PAGE_PRESENT(pte) ((pte) & PTE_P)
+#define PAGE_UNMAPPED(pte) ((pte) == 0)
+#define PAGE_PAGED_OUT(pte) (!PAGE_PRESENT(pte) && !PAGE_UNMAPPED(pte))
+
+/* **************************************** */
+/* Segmentation */
+// XXX 64b: these all need redone
+
+// Global descriptor numbers
+#define GD_NULL   0x00     // NULL descriptor
+#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
+#define GD_LDT    0x30     // local descriptor table
+
+#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__
+
+// Segment Descriptors
+typedef 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
+} segdesc_t;
+// Null segment
+#define SEG_NULL       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+// Segment that is loadable but faults when used
+#define SEG_FAULT      { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 }
+// Normal segment
+#define SEG(type, base, lim, dpl)                                                                      \
+{ ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,      \
+    type, 1, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1,                       \
+    (unsigned) (base) >> 24 }
+// System segment (LDT)
+#define SEG_SYS(type, base, lim, dpl)                                                                  \
+{ ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,      \
+    type, 0, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1,                       \
+    (unsigned) (base) >> 24 }
+
+#define SEG16(type, base, lim, dpl)                                                            \
+{ (lim) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,                      \
+    type, 1, dpl, 1, (unsigned) (lim) >> 16, 0, 0, 1, 0,                       \
+    (unsigned) (base) >> 24 }
+
+#define SEG16ROINIT(seg,type,base,lim,dpl) \
+       {\
+               (seg).sd_lim_15_0 = SINIT((lim) & 0xffff);\
+               (seg).sd_base_15_0 = SINIT((uintptr_t)(base)&0xffff);\
+               (seg).sd_base_23_16 = SINIT(((uintptr_t)(base)>>16)&0xff);\
+               (seg).sd_type = SINIT(type);\
+               (seg).sd_s = SINIT(1);\
+               (seg).sd_dpl = SINIT(dpl);\
+               (seg).sd_p = SINIT(1);\
+               (seg).sd_lim_19_16 = SINIT((unsigned)(lim)>>16);\
+               (seg).sd_avl = SINIT(0);\
+               (seg).sd_rsv1 = SINIT(0);\
+               (seg).sd_db = SINIT(1);\
+               (seg).sd_g = SINIT(0);\
+               (seg).sd_base_31_24 = SINIT((uintptr_t)(base)>> 24);\
+       }
+
+// Task state segment format (as described by the Pentium architecture book)
+typedef struct Taskstate {
+       uintptr_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
+       uintptr_t ts_eflags;
+       uintptr_t ts_eax;       // More saved state (registers)
+       uintptr_t ts_ecx;
+       uintptr_t ts_edx;
+       uintptr_t ts_ebx;
+       uintptr_t ts_esp;
+       uintptr_t ts_ebp;
+       uintptr_t ts_esi;
+       uintptr_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
+} taskstate_t;
+
+// Gate descriptors for interrupts and traps
+typedef 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;         // DPL - highest ring allowed to use this
+       unsigned gd_p : 1;           // Present
+       unsigned gd_off_31_16 : 16;  // high bits of offset in segment
+} gatedesc_t;
+
+// Set up a normal interrupt/trap gate descriptor.
+// - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate.
+//   - interrupt gates automatically disable interrupts (cli)
+// - 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 = (uintptr_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 = (uintptr_t) (off) >> 16;          \
+}
+
+#define ROSETGATE(gate, istrap, sel, off, dpl)                 \
+{                                                              \
+       (gate).gd_off_15_0 = SINIT((uintptr_t) (off) & 0xffff);         \
+       (gate).gd_ss = SINIT(sel);                                      \
+       (gate).gd_args = SINIT(0);                                      \
+       (gate).gd_rsv1 = SINIT(0);                                      \
+       (gate).gd_type = SINIT((istrap) ? STS_TG32 : STS_IG32); \
+       (gate).gd_s = SINIT(0);                                 \
+       (gate).gd_dpl = SINIT(dpl);                                     \
+       (gate).gd_p = SINIT(1);                                 \
+       (gate).gd_off_31_16 = SINIT((uintptr_t) (off) >> 16);           \
+}
+
+// Set up a call gate descriptor.
+#define SETCALLGATE(gate, ss, off, dpl)                        \
+{                                                              \
+       (gate).gd_off_15_0 = (uintptr_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 = (uintptr_t) (off) >> 16;          \
+}
+
+// Pseudo-descriptors used for LGDT, LLDT and LIDT instructions.
+typedef struct Pseudodesc {
+       uint16_t pd_lim;                // Limit
+       uintptr_t pd_base;              // Base address
+} __attribute__ ((packed)) pseudodesc_t;
+
+extern segdesc_t (COUNT(SEG_COUNT) RO gdt)[];
+extern pseudodesc_t gdt_pd;
+
+#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
+
+#define SEG_COUNT      7               // Number of segments in the steady state
+#define LDT_SIZE       (8192 * sizeof(segdesc_t))
+#endif /* ROS_INC_ARCH_MMU64_H */
index 5771a2d..cf18be0 100644 (file)
@@ -1,11 +1,15 @@
-#ifndef _ROS_ARCH_SYSCALL_H
-#define _ROS_ARCH_SYSCALL_H
+#ifndef ROS_INC_ARCH_SYSCALL_H
+#define ROS_INC_ARCH_SYSCALL_H
 
 #define T_SYSCALL      0x80
 
 #ifndef ROS_KERNEL
 
-#include <ros/arch/bits/syscall.h>
+#ifdef __x86_64__
+#include <ros/arch/syscall64.h>
+#else
+#include <ros/arch/syscall32.h>
+#endif
 
 static inline long __ros_arch_syscall(long _a0, long _a1)
 {
@@ -18,5 +22,4 @@ static inline long __ros_arch_syscall(long _a0, long _a1)
 
 #endif /* ifndef ROS_KERNEL */
 
-#endif
-
+#endif /* ROS_INC_ARCH_SYSCALL_H */
diff --git a/kern/arch/x86/ros/syscall32.h b/kern/arch/x86/ros/syscall32.h
new file mode 100644 (file)
index 0000000..de3db97
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef ROS_INC_ARCH_SYSCALL32_H
+#define ROS_INC_ARCH_SYSCALL32_H
+
+#ifndef ROS_INC_ARCH_SYSCALL_H
+#error "Do not include include ros/arch/syscall32.h directly"
+#endif
+
+#define T_SYSCALL      0x80
+
+#ifndef ROS_KERNEL
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <ros/common.h>
+#include <assert.h>
+
+static inline intreg_t __syscall_sysenter(uintreg_t a0, uintreg_t a1)
+{
+       /* The kernel clobbers ecx, so we save it manually. */
+       intreg_t ret = 0;
+       asm volatile ("  pushl %%ecx;        "
+                     "  pushl %%edx;        "
+                     "  pushl %%ebp;        "
+                     "  movl %%esp, %%ebp;  "
+                     "  leal 1f, %%edx;     "
+                     "  sysenter;           "
+                     "1:                    "
+                     "  popl %%ebp;         "
+                     "  popl %%edx;         "
+                     "  popl %%ecx;         "
+                     : "=a" (ret)
+                     : "a" (a0),
+                       "S" (a1)
+                     : "cc", "memory");
+       return ret;
+}
+
+static inline intreg_t __syscall_trap(uintreg_t a0, uintreg_t a1)
+{
+       intreg_t ret;
+
+       /* If you change this, change pop_user_ctx() */
+       asm volatile("int %1"
+                    : "=a" (ret)
+                    : "i" (T_SYSCALL),
+                      "a" (a0),
+                      "d" (a1)
+                    : "cc", "memory");
+       return ret;
+}
+
+#endif
+
+#endif /* ROS_INC_ARCH_SYSCALL32_H */
diff --git a/kern/arch/x86/ros/syscall64.h b/kern/arch/x86/ros/syscall64.h
new file mode 100644 (file)
index 0000000..60c5dfe
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef ROS_INC_ARCH_SYSCALL64_H
+#define ROS_INC_ARCH_SYSCALL64_H
+
+#ifndef ROS_INC_ARCH_SYSCALL_H
+#error "Do not include include ros/arch/syscall64.h directly"
+#endif
+
+#define T_SYSCALL      0x80
+
+#ifndef ROS_KERNEL
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <ros/common.h>
+#include <assert.h>
+
+static inline intreg_t __syscall_sysenter(uintreg_t a0, uintreg_t a1)
+{
+       /* The kernel clobbers ecx, so we save it manually. */
+       intreg_t ret = 0;
+       #if 0
+       asm volatile ("  pushl %%ecx;        "
+                     "  pushl %%edx;        "
+                     "  pushl %%ebp;        "
+                     "  movl %%esp, %%ebp;  "
+                     "  leal 1f, %%edx;     "
+                     "  sysenter;           "
+                     "1:                    "
+                     "  popl %%ebp;         "
+                     "  popl %%edx;         "
+                     "  popl %%ecx;         "
+                     : "=a" (ret)
+                     : "a" (a0),
+                       "S" (a1)
+                     : "cc", "memory");
+       #endif
+       return ret;
+}
+
+static inline intreg_t __syscall_trap(uintreg_t a0, uintreg_t a1)
+{
+       intreg_t ret;
+
+       #if 0
+       /* If you change this, change pop_user_ctx() */
+       asm volatile("int %1"
+                    : "=a" (ret)
+                    : "i" (T_SYSCALL),
+                      "a" (a0),
+                      "d" (a1)
+                    : "cc", "memory");
+       #endif
+       return ret;
+}
+
+#endif
+
+#endif /* ROS_INC_ARCH_SYSCALL64_H */
index 15f9ae5..3c15c99 100644 (file)
@@ -1,5 +1,3 @@
-/*  Mostly from JOS.   See COPYRIGHT for copyright information. */
-
 #ifndef ROS_INC_ARCH_TRAPFRAME_H
 #define ROS_INC_ARCH_TRAPFRAME_H
 
@@ -9,51 +7,11 @@
 
 #include <ros/common.h>
 
-typedef struct pushregs {
-       /* registers as pushed by pusha */
-       uint32_t reg_edi;
-       uint32_t reg_esi;
-       uint32_t reg_ebp; uint32_t reg_oesp;            /* Useless */
-       uint32_t reg_ebx;
-       uint32_t reg_edx;
-       uint32_t reg_ecx;
-       uint32_t reg_eax;
-} push_regs_t;
-
-struct hw_trapframe {
-       push_regs_t tf_regs;
-       uint16_t tf_gs;
-       uint16_t tf_padding1;
-       uint16_t tf_fs;
-       uint16_t tf_padding2;
-       uint16_t tf_es;
-       uint16_t tf_padding3;
-       uint16_t tf_ds;
-       uint16_t tf_padding4;
-       uint32_t tf_trapno;
-       /* below here defined by x86 hardware */
-       uint32_t tf_err;
-       uintptr_t tf_eip;
-       uint16_t tf_cs;
-       uint16_t tf_padding5;
-       uint32_t tf_eflags;
-       /* below here only when crossing rings, such as from user to kernel */
-       uintptr_t tf_esp;
-       uint16_t tf_ss;
-       uint16_t tf_padding6;
-};
-
-struct sw_trapframe {
-       uint32_t tf_ebp;
-       uint32_t tf_ebx;
-       uint32_t tf_esi;
-       uint32_t tf_edi;
-       uint32_t tf_esp;
-       uint32_t tf_eip;
-       uint32_t tf_mxcsr;
-       uint16_t tf_fpucw;
-       uint16_t tf_gs;         /* something to track TLS is callee-saved (sort of) */
-};
+#ifdef __x86_64__
+#include <ros/arch/trapframe64.h>
+#else
+#include <ros/arch/trapframe32.h>
+#endif
 
 /* FP state and whatever else the kernel won't muck with automatically.  For
  * now, it's the Non-64-bit-mode layout of FP and XMM registers, as used by
@@ -109,7 +67,7 @@ struct fp_header_64bit_default {
 /* Just for storage space, not for real use    */
 typedef struct {
        unsigned int stor[4];
-} __uint128_t;
+} __128bits;
 
 typedef struct ancillary_state {
        union { /* whichever header used depends on the mode */
@@ -117,36 +75,36 @@ typedef struct ancillary_state {
                struct fp_header_64bit_promoted         fp_head_64p;
                struct fp_header_64bit_default          fp_head_64d;
        };
-       __uint128_t             st0_mm0;        /* 128 bits: 80 for the st0, 48 rsv */
-       __uint128_t             st1_mm1;
-       __uint128_t             st2_mm2;
-       __uint128_t             st3_mm3;
-       __uint128_t             st4_mm4;
-       __uint128_t             st5_mm5;
-       __uint128_t             st6_mm6;
-       __uint128_t             st7_mm7;
-       __uint128_t             xmm0;
-       __uint128_t             xmm1;
-       __uint128_t             xmm2;
-       __uint128_t             xmm3;
-       __uint128_t             xmm4;
-       __uint128_t             xmm5;
-       __uint128_t             xmm6;
-       __uint128_t             xmm7;
-       __uint128_t             xmm8;           /* xmm8 and below only for 64-bit-mode */
-       __uint128_t             xmm9;
-       __uint128_t             xmm10;
-       __uint128_t             xmm11;
-       __uint128_t             xmm12;
-       __uint128_t             xmm13;
-       __uint128_t             xmm14;
-       __uint128_t             xmm15;
-       __uint128_t             reserv0;
-       __uint128_t             reserv1;
-       __uint128_t             reserv2;
-       __uint128_t             reserv3;
-       __uint128_t             reserv4;
-       __uint128_t             reserv5;
+       __128bits               st0_mm0;        /* 128 bits: 80 for the st0, 48 rsv */
+       __128bits               st1_mm1;
+       __128bits               st2_mm2;
+       __128bits               st3_mm3;
+       __128bits               st4_mm4;
+       __128bits               st5_mm5;
+       __128bits               st6_mm6;
+       __128bits               st7_mm7;
+       __128bits               xmm0;
+       __128bits               xmm1;
+       __128bits               xmm2;
+       __128bits               xmm3;
+       __128bits               xmm4;
+       __128bits               xmm5;
+       __128bits               xmm6;
+       __128bits               xmm7;
+       __128bits               xmm8;           /* xmm8 and below only for 64-bit-mode */
+       __128bits               xmm9;
+       __128bits               xmm10;
+       __128bits               xmm11;
+       __128bits               xmm12;
+       __128bits               xmm13;
+       __128bits               xmm14;
+       __128bits               xmm15;
+       __128bits               reserv0;
+       __128bits               reserv1;
+       __128bits               reserv2;
+       __128bits               reserv3;
+       __128bits               reserv4;
+       __128bits               reserv5;
 } __attribute__((aligned(16))) ancillary_state_t;
 
 #endif /* ROS_INC_ARCH_TRAPFRAME_H */
diff --git a/kern/arch/x86/ros/trapframe32.h b/kern/arch/x86/ros/trapframe32.h
new file mode 100644 (file)
index 0000000..0cc3e19
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef ROS_INC_ARCH_TRAPFRAME32_H
+#define ROS_INC_ARCH_TRAPFRAME32_H
+
+#ifndef ROS_INC_ARCH_TRAPFRAME_H
+#error "Do not include include ros/arch/trapframe32.h directly"
+#endif
+
+typedef struct pushregs {
+       /* registers as pushed by pusha */
+       uint32_t reg_edi;
+       uint32_t reg_esi;
+       uint32_t reg_ebp; uint32_t reg_oesp;            /* Useless */
+       uint32_t reg_ebx;
+       uint32_t reg_edx;
+       uint32_t reg_ecx;
+       uint32_t reg_eax;
+} push_regs_t;
+
+struct hw_trapframe {
+       push_regs_t tf_regs;
+       uint16_t tf_gs;
+       uint16_t tf_padding1;
+       uint16_t tf_fs;
+       uint16_t tf_padding2;
+       uint16_t tf_es;
+       uint16_t tf_padding3;
+       uint16_t tf_ds;
+       uint16_t tf_padding4;
+       uint32_t tf_trapno;
+       /* below here defined by x86 hardware */
+       uint32_t tf_err;
+       uintptr_t tf_eip;
+       uint16_t tf_cs;
+       uint16_t tf_padding5;
+       uint32_t tf_eflags;
+       /* below here only when crossing rings, such as from user to kernel */
+       uintptr_t tf_esp;
+       uint16_t tf_ss;
+       uint16_t tf_padding6;
+};
+
+struct sw_trapframe {
+       uint32_t tf_ebp;
+       uint32_t tf_ebx;
+       uint32_t tf_esi;
+       uint32_t tf_edi;
+       uint32_t tf_esp;
+       uint32_t tf_eip;
+       uint32_t tf_mxcsr;
+       uint16_t tf_fpucw;
+       uint16_t tf_gs;         /* something to track TLS is callee-saved (sort of) */
+};
+
+#endif /* ROS_INC_ARCH_TRAPFRAME32_H */
diff --git a/kern/arch/x86/ros/trapframe64.h b/kern/arch/x86/ros/trapframe64.h
new file mode 100644 (file)
index 0000000..d86e79a
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef ROS_INC_ARCH_TRAPFRAME64_H
+#define ROS_INC_ARCH_TRAPFRAME64_H
+
+#ifndef ROS_INC_ARCH_TRAPFRAME_H
+#error "Do not include include ros/arch/trapframe64.h directly"
+#endif
+
+typedef struct pushregs {
+       /* registers as pushed by pusha */
+       uint32_t reg_edi;
+       uint32_t reg_esi;
+       uint32_t reg_ebp; uint32_t reg_oesp;            /* Useless */
+       uint32_t reg_ebx;
+       uint32_t reg_edx;
+       uint32_t reg_ecx;
+       uint32_t reg_eax;
+} push_regs_t;
+
+struct hw_trapframe {
+       push_regs_t tf_regs;
+       uint16_t tf_gs;
+       uint16_t tf_padding1;
+       uint16_t tf_fs;
+       uint16_t tf_padding2;
+       uint16_t tf_es;
+       uint16_t tf_padding3;
+       uint16_t tf_ds;
+       uint16_t tf_padding4;
+       uint32_t tf_trapno;
+       /* below here defined by x86 hardware */
+       uint32_t tf_err;
+       uintptr_t tf_eip;
+       uint16_t tf_cs;
+       uint16_t tf_padding5;
+       uint32_t tf_eflags;
+       /* below here only when crossing rings, such as from user to kernel */
+       uintptr_t tf_esp;
+       uint16_t tf_ss;
+       uint16_t tf_padding6;
+};
+
+struct sw_trapframe {
+       uint32_t tf_ebp;
+       uint32_t tf_ebx;
+       uint32_t tf_esi;
+       uint32_t tf_edi;
+       uint32_t tf_esp;
+       uint32_t tf_eip;
+       uint32_t tf_mxcsr;
+       uint16_t tf_fpucw;
+       uint16_t tf_gs;         /* something to track TLS is callee-saved (sort of) */
+};
+
+#endif /* ROS_INC_ARCH_TRAPFRAME64_H */
index c8d93c7..49579c1 100644 (file)
@@ -67,7 +67,7 @@ static void smp_final_core_init(struct hw_trapframe *hw_tf, void *data)
 }
 
 // this needs to be set in smp_entry too...
-#define trampoline_pg 0x00001000
+#define trampoline_pg 0x00001000UL
 extern char (SNT SREADONLY smp_entry)[];
 extern char (SNT SREADONLY smp_entry_end)[];
 extern char (SNT SREADONLY smp_boot_lock)[];
@@ -232,10 +232,11 @@ uint32_t smp_main(void)
         * we use the bottom of the stack page... */
        *(uintptr_t*)page2kva(my_stack) = (uintptr_t)gdt_etc;
 
+       /* TODO: 64b is diff, use a helper */
        // Set up MSR for SYSENTER 
        write_msr(MSR_IA32_SYSENTER_CS, GD_KT);
        write_msr(MSR_IA32_SYSENTER_ESP, my_stack_top);
-       write_msr(MSR_IA32_SYSENTER_EIP, (uint32_t) &sysenter_handler);
+       write_msr(MSR_IA32_SYSENTER_EIP, (uintptr_t) &sysenter_handler);
 
        // Build and load the gdt / gdt_pd
        memcpy(my_gdt, gdt, sizeof(segdesc_t)*SEG_COUNT);
@@ -247,14 +248,14 @@ uint32_t smp_main(void)
        my_ts->ts_esp0 = my_stack_top;
        my_ts->ts_ss0 = GD_KD;
        // Initialize the TSS field of my_gdt.
-       my_gdt[GD_TSS >> 3] = (segdesc_t)SEG16(STS_T32A, (uint32_t) (my_ts),
+       my_gdt[GD_TSS >> 3] = (segdesc_t)SEG16(STS_T32A, (uintptr_t)my_ts,
                              sizeof(taskstate_t), 0);
        my_gdt[GD_TSS >> 3].sd_s = 0;
        // Load the TSS
        ltr(GD_TSS);
 
        // Loads the same IDT used by the other cores
-       asm volatile("lidt idt_pd");
+       asm volatile("lidt %0" : : "m"(idt_pd));
 
        // APIC setup
        // set LINT0 to receive ExtINTs (KVM's default).  At reset they are 0x1000.
@@ -296,7 +297,7 @@ void __arch_pcpu_init(uint32_t coreid)
                per_cpu_info[0].tss = &ts;
                per_cpu_info[0].gdt = gdt;
        } else {
-               my_stack_bot = ROUNDDOWN(read_esp(), PGSIZE);
+               my_stack_bot = ROUNDDOWN(read_sp(), PGSIZE);
                per_cpu_info[coreid].tss = (taskstate_t*)(*(uintptr_t*)my_stack_bot);
                per_cpu_info[coreid].gdt = (segdesc_t*)(*(uintptr_t*)my_stack_bot +
                                           sizeof(taskstate_t) + sizeof(pseudodesc_t));
diff --git a/kern/arch/x86/smp_entry.S b/kern/arch/x86/smp_entry.S
deleted file mode 100644 (file)
index 6382467..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-#include <arch/mmu.h>
-#include <ros/memlayout.h>
-#include <arch/trap.h>
-
-#define        RELOC(x) ((x) - KERNBASE)
-#define        CPUID_PSE_SUPPORT       0x00000008
-
-.globl                 smp_entry
-smp_entry:             .code16
-       cli
-       cld
-       lock incw       smp_semaphore - smp_entry + 0x1000  # announce our presence
-spin_start:                                            # grab lock in real mode
-       movw    $1, %ax
-       xchgw   %ax, smp_boot_lock - smp_entry + 0x1000
-       test    %ax, %ax
-       jne             spin_start
-
-       # Set up rudimentary segmentation
-       xorw    %ax, %ax                        # Segment number zero
-       movw    %ax, %ds                        # -> Data Segment
-       movw    %ax, %es                        # -> Extra Segment
-       movw    %ax, %ss                        # -> Stack Segment
-       # Would like to patch all of these 0x1000's at trampoline relocation time
-       # There's three of them, so we could patch the trampoline code when we load,
-       # once we're sure the entry code will not change anymore
-       # Note that this GDT is straight through, with no KERNBASE translation
-       lgdt    gdtdesc - smp_entry + 0x1000
-
-       # Turn on protected mode
-       movl    %cr0, %eax
-       orl             $CR0_PE, %eax
-       movl    %eax, %cr0
-       ljmp    $GD_KT, $(protcseg - smp_entry + 0x1000)
-       
-protcseg:      .code32
-       # Set up the protected-mode data segment registers
-       movw    $GD_KD, %ax             # Kernel segment selector
-       movw    %ax, %ds                # -> DS: Data Segment
-       movw    %ax, %es                # -> ES: Extra Segment
-       movw    %ax, %ss                # -> SS: Stack Segment
-       movw    %ax, %fs                # -> FS
-       movw    %ax, %gs                # -> GS
-
-       # Turn on Paging
-       movl    RELOC(boot_cr3), %eax
-       movl    %eax, %cr3
-       # Enable PSE, if available
-       movl    $1, %eax
-       cpuid
-       test    $CPUID_PSE_SUPPORT, %edx
-       jz              past_pse
-       movl    %cr4, %eax
-       orl             $CR4_PSE, %eax
-       movl    %eax, %cr4
-past_pse:
-       # Turn on PGE, no matter what.  Ghetto, but we panic if it's not supported.
-       movl    %cr4, %eax
-       orl             $CR4_PGE, %eax
-       movl    %eax, %cr4
-       movl    %cr0, %eax      
-       # These cr0 flags are the same as in pmap.c.  Keep them in sync
-       orl             $(CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP), %eax  
-       andl    $(~(CR0_TS|CR0_EM|CR0_CD|CR0_NW)), %eax  
-       movl    %eax, %cr0
-
-       # Reload Segments, using the same gdt_pd as Core 0
-       lgdt    gdt_pd
-       movw    $GD_KD, %ax             # Kernel segment selector
-       movw    %ax, %ds                # -> DS: Data Segment
-       movw    %ax, %es                # -> ES: Extra Segment
-       movw    %ax, %ss                # -> SS: Stack Segment
-       movw    $GD_UD|3, %ax   # User segment selector, with RPL=3
-       movw    %ax, %fs                # -> FS
-       movw    %ax, %gs                # -> GS
-       ljmp    $GD_KT, $here   # jumping to original location of trampoline!
-here:
-       xorl    %eax, %eax
-       lldt    %ax
-       incl    num_cpus
-       movl    (smp_stack_top), %esp
-       movl    $0, %ebp                # so backtrace works
-       call    smp_main
-       movl    %eax, %esp              # use our new stack, value returned from smp_main
-       # note the next two lines are using the direct mapping from smp_boot()
-       movw    $0, smp_boot_lock - smp_entry + 0x1000  # release lock
-       lock decw       smp_semaphore - smp_entry + 0x1000  # show we are done
-       sti                     # so we can get the IPI
-       hlt                     # wait for the IPI to run smp_pcu_init()
-       call    smp_idle                # idle loop, will have interrupts turned on
-
-       # Below here is just data, stored with the code text
-       .p2align        2                                               # force 4 byte alignment
-gdt:
-       SEG_NULL                                                        # null seg
-       SEG(STA_X|STA_R, 0, 0xffffffff)         # code seg
-       SEG(STA_W, 0, 0xffffffff)                       # data seg
-gdtdesc:
-       .word   gdtdesc - gdt - 1                       # sizeof(gdt) - 1
-       .long   gdt - smp_entry + 0x1000        # address gdt
-       .p2align        2                                               # force 4 byte alignment
-.globl                 smp_boot_lock
-smp_boot_lock:                                                 # this lock word will be only used from
-       .word   0                                                       # its spot in the trampoline (0x1000)
-.globl                 smp_semaphore
-smp_semaphore:                                                 # poor man's polling semaphore
-       .word   0                                                       
-.globl                 smp_entry_end
-smp_entry_end:
diff --git a/kern/arch/x86/smp_entry32.S b/kern/arch/x86/smp_entry32.S
new file mode 100644 (file)
index 0000000..6382467
--- /dev/null
@@ -0,0 +1,109 @@
+#include <arch/mmu.h>
+#include <ros/memlayout.h>
+#include <arch/trap.h>
+
+#define        RELOC(x) ((x) - KERNBASE)
+#define        CPUID_PSE_SUPPORT       0x00000008
+
+.globl                 smp_entry
+smp_entry:             .code16
+       cli
+       cld
+       lock incw       smp_semaphore - smp_entry + 0x1000  # announce our presence
+spin_start:                                            # grab lock in real mode
+       movw    $1, %ax
+       xchgw   %ax, smp_boot_lock - smp_entry + 0x1000
+       test    %ax, %ax
+       jne             spin_start
+
+       # Set up rudimentary segmentation
+       xorw    %ax, %ax                        # Segment number zero
+       movw    %ax, %ds                        # -> Data Segment
+       movw    %ax, %es                        # -> Extra Segment
+       movw    %ax, %ss                        # -> Stack Segment
+       # Would like to patch all of these 0x1000's at trampoline relocation time
+       # There's three of them, so we could patch the trampoline code when we load,
+       # once we're sure the entry code will not change anymore
+       # Note that this GDT is straight through, with no KERNBASE translation
+       lgdt    gdtdesc - smp_entry + 0x1000
+
+       # Turn on protected mode
+       movl    %cr0, %eax
+       orl             $CR0_PE, %eax
+       movl    %eax, %cr0
+       ljmp    $GD_KT, $(protcseg - smp_entry + 0x1000)
+       
+protcseg:      .code32
+       # Set up the protected-mode data segment registers
+       movw    $GD_KD, %ax             # Kernel segment selector
+       movw    %ax, %ds                # -> DS: Data Segment
+       movw    %ax, %es                # -> ES: Extra Segment
+       movw    %ax, %ss                # -> SS: Stack Segment
+       movw    %ax, %fs                # -> FS
+       movw    %ax, %gs                # -> GS
+
+       # Turn on Paging
+       movl    RELOC(boot_cr3), %eax
+       movl    %eax, %cr3
+       # Enable PSE, if available
+       movl    $1, %eax
+       cpuid
+       test    $CPUID_PSE_SUPPORT, %edx
+       jz              past_pse
+       movl    %cr4, %eax
+       orl             $CR4_PSE, %eax
+       movl    %eax, %cr4
+past_pse:
+       # Turn on PGE, no matter what.  Ghetto, but we panic if it's not supported.
+       movl    %cr4, %eax
+       orl             $CR4_PGE, %eax
+       movl    %eax, %cr4
+       movl    %cr0, %eax      
+       # These cr0 flags are the same as in pmap.c.  Keep them in sync
+       orl             $(CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP), %eax  
+       andl    $(~(CR0_TS|CR0_EM|CR0_CD|CR0_NW)), %eax  
+       movl    %eax, %cr0
+
+       # Reload Segments, using the same gdt_pd as Core 0
+       lgdt    gdt_pd
+       movw    $GD_KD, %ax             # Kernel segment selector
+       movw    %ax, %ds                # -> DS: Data Segment
+       movw    %ax, %es                # -> ES: Extra Segment
+       movw    %ax, %ss                # -> SS: Stack Segment
+       movw    $GD_UD|3, %ax   # User segment selector, with RPL=3
+       movw    %ax, %fs                # -> FS
+       movw    %ax, %gs                # -> GS
+       ljmp    $GD_KT, $here   # jumping to original location of trampoline!
+here:
+       xorl    %eax, %eax
+       lldt    %ax
+       incl    num_cpus
+       movl    (smp_stack_top), %esp
+       movl    $0, %ebp                # so backtrace works
+       call    smp_main
+       movl    %eax, %esp              # use our new stack, value returned from smp_main
+       # note the next two lines are using the direct mapping from smp_boot()
+       movw    $0, smp_boot_lock - smp_entry + 0x1000  # release lock
+       lock decw       smp_semaphore - smp_entry + 0x1000  # show we are done
+       sti                     # so we can get the IPI
+       hlt                     # wait for the IPI to run smp_pcu_init()
+       call    smp_idle                # idle loop, will have interrupts turned on
+
+       # Below here is just data, stored with the code text
+       .p2align        2                                               # force 4 byte alignment
+gdt:
+       SEG_NULL                                                        # null seg
+       SEG(STA_X|STA_R, 0, 0xffffffff)         # code seg
+       SEG(STA_W, 0, 0xffffffff)                       # data seg
+gdtdesc:
+       .word   gdtdesc - gdt - 1                       # sizeof(gdt) - 1
+       .long   gdt - smp_entry + 0x1000        # address gdt
+       .p2align        2                                               # force 4 byte alignment
+.globl                 smp_boot_lock
+smp_boot_lock:                                                 # this lock word will be only used from
+       .word   0                                                       # its spot in the trampoline (0x1000)
+.globl                 smp_semaphore
+smp_semaphore:                                                 # poor man's polling semaphore
+       .word   0                                                       
+.globl                 smp_entry_end
+smp_entry_end:
diff --git a/kern/arch/x86/smp_entry64.S b/kern/arch/x86/smp_entry64.S
new file mode 100644 (file)
index 0000000..f2a8210
--- /dev/null
@@ -0,0 +1,127 @@
+#include <arch/mmu.h>
+#include <ros/memlayout.h>
+#include <arch/trap.h>
+
+#define        RELOC(x) ((x) - KERNBASE)
+#define        CPUID_PSE_SUPPORT       0x00000008
+
+.globl                 smp_entry
+smp_entry:             .code16
+       cli
+       cld
+       lock incw       smp_semaphore - smp_entry + 0x1000  # announce our presence
+spin_start:                                            # grab lock in real mode
+       movw    $1, %ax
+       xchgw   %ax, smp_boot_lock - smp_entry + 0x1000
+       test    %ax, %ax
+       jne             spin_start
+
+       # Set up rudimentary segmentation
+       xorw    %ax, %ax                        # Segment number zero
+       movw    %ax, %ds                        # -> Data Segment
+       movw    %ax, %es                        # -> Extra Segment
+       movw    %ax, %ss                        # -> Stack Segment
+       # Would like to patch all of these 0x1000's at trampoline relocation time
+       # There's three of them, so we could patch the trampoline code when we load,
+       # once we're sure the entry code will not change anymore
+       # Note that this GDT is straight through, with no KERNBASE translation
+       lgdt    gdtdesc - smp_entry + 0x1000
+
+       # Turn on protected mode
+       movl    %cr0, %eax
+       orl             $CR0_PE, %eax
+       movl    %eax, %cr0
+       ljmp    $GD_KT, $(protcseg - smp_entry + 0x1000)
+       
+.code32
+protcseg:
+       # Set up the protected-mode data segment registers
+       movw    $GD_KD, %ax             # Kernel segment selector
+       movw    %ax, %ds                # -> DS: Data Segment
+       movw    %ax, %es                # -> ES: Extra Segment
+       movw    %ax, %ss                # -> SS: Stack Segment
+       movw    %ax, %fs                # -> FS
+       movw    %ax, %gs                # -> GS
+
+       # Turn on Paging
+       # crap, how do we sort out the relocs such that this is reachable from 32
+       # bit code?  need to put these in a magic location?
+       # XXX movl      RELOC(boot_cr3), %eax
+       movl    %eax, %cr3
+       # Enable PSE, if available
+       movl    $1, %eax
+       cpuid
+       test    $CPUID_PSE_SUPPORT, %edx
+       jz              past_pse
+       movl    %cr4, %eax
+       orl             $CR4_PSE, %eax
+       movl    %eax, %cr4
+past_pse:
+       # Turn on PGE, no matter what.  Ghetto, but we panic if it's not supported.
+       movl    %cr4, %eax
+       orl             $CR4_PGE, %eax
+       movl    %eax, %cr4
+       movl    %cr0, %eax      
+       # These cr0 flags are the same as in pmap.c.  Keep them in sync
+       orl             $(CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP), %eax  
+       andl    $(~(CR0_TS|CR0_EM|CR0_CD|CR0_NW)), %eax  
+       movl    %eax, %cr0
+
+       # Reload Segments, using the same gdt_pd as Core 0
+       # XXX lgdt      gdt_pd
+       movw    $GD_KD, %ax             # Kernel segment selector
+       movw    %ax, %ds                # -> DS: Data Segment
+       movw    %ax, %es                # -> ES: Extra Segment
+       movw    %ax, %ss                # -> SS: Stack Segment
+       movw    $GD_UD|3, %ax   # User segment selector, with RPL=3
+       movw    %ax, %fs                # -> FS
+       movw    %ax, %gs                # -> GS
+       # TODO: this reloc is mucking up.  it assembles for 32 bit okay, but if you asm
+       # for 64 bit, or if you objcopy ther 32 to 64, it can't find 'here'.  tried
+       # other names too.  is it because the linker doesn't know where smp entry
+       # is going to be, or that it later becomes a 64 bit reloc (unlike in
+       # _start, where we know it is linked for low mem).  Subtracting them gives
+       # the linker the ability to do the math now. (don't forget you can't trust
+       # the disassembly when the format doesn't match the code type)
+       # 
+       # we're going to have issues with all of the relocs like that - trying to
+       # find 64 bit addresses in 32 bit code.  for all of the external ones,
+       # we're going to need to either put the memory in here, so we don't need to
+       # reloc, or do it after we turn on 64b mode
+
+
+       # ljmp  $GD_KT, $(here) # jumping to original location of trampoline!
+       ljmp    $GD_KT, $(here - smp_entry + 0x1000)
+here:
+       xorl    %eax, %eax
+       lldt    %ax
+       # XXX incl      num_cpus
+       # XXX movl      (smp_stack_top), %esp
+       movl    $0, %ebp                # so backtrace works
+       call    smp_main
+       movl    %eax, %esp              # use our new stack, value returned from smp_main
+       # note the next two lines are using the direct mapping from smp_boot()
+       movw    $0, smp_boot_lock - smp_entry + 0x1000  # release lock
+       lock decw       smp_semaphore - smp_entry + 0x1000  # show we are done
+       sti                     # so we can get the IPI
+       hlt                     # wait for the IPI to run smp_pcu_init()
+       call    smp_idle                # idle loop, will have interrupts turned on
+
+       # Below here is just data, stored with the code text
+       .p2align        2                                               # force 4 byte alignment
+gdt:
+       SEG_NULL                                                        # null seg
+       SEG(STA_X|STA_R, 0, 0xffffffff)         # code seg
+       SEG(STA_W, 0, 0xffffffff)                       # data seg
+gdtdesc:
+       .word   gdtdesc - gdt - 1                       # sizeof(gdt) - 1
+       .long   gdt - smp_entry + 0x1000        # address gdt
+       .p2align        2                                               # force 4 byte alignment
+.globl                 smp_boot_lock
+smp_boot_lock:                                                 # this lock word will be only used from
+       .word   0                                                       # its spot in the trampoline (0x1000)
+.globl                 smp_semaphore
+smp_semaphore:                                                 # poor man's polling semaphore
+       .word   0                                                       
+.globl                 smp_entry_end
+smp_entry_end:
index 0f0cede..a1ddaed 100644 (file)
@@ -29,9 +29,7 @@ taskstate_t RO ts;
  */
 // Aligned on an 8 byte boundary (SDM V3A 5-13)
 gatedesc_t __attribute__ ((aligned (8))) (RO idt)[256] = { { 0 } };
-pseudodesc_t RO idt_pd = {
-       sizeof(idt) - 1, (uint32_t) idt
-};
+pseudodesc_t idt_pd;
 
 /* global handler table, used by core0 (for now).  allows the registration
  * of functions to be called when servicing an interrupt.  other cores
@@ -43,7 +41,7 @@ pseudodesc_t RO idt_pd = {
 spinlock_t iht_lock;
 handler_t TP(TV(t)) LCKD(&iht_lock) (RO interrupt_handlers)[NUM_INTERRUPT_HANDLERS];
 
-static const char *NTS trapname(int trapno)
+const char *x86_trapname(int trapno)
 {
     // zra: excnames is SREADONLY because Ivy doesn't trust const
        static const char *NT const (RO excnames)[] = {
@@ -86,7 +84,7 @@ void set_stack_top(uintptr_t stacktop)
        /* No need to reload the task register, this takes effect immediately */
        pcpu->tss->ts_esp0 = stacktop;
        /* Also need to make sure sysenters come in correctly */
-       write_msr(MSR_IA32_SYSENTER_ESP, stacktop);
+       x86_set_sysenter_stacktop(stacktop);
 }
 
 /* Note the check implies we only are on a one page stack (or the first page) */
@@ -96,34 +94,14 @@ uintptr_t get_stack_top(void)
        uintptr_t stacktop;
        /* so we can check this in interrupt handlers (before smp_boot()) */
        if (!pcpui->tss)
-               return ROUNDUP(read_esp(), PGSIZE);
+               return ROUNDUP(read_sp(), PGSIZE);
        stacktop = pcpui->tss->ts_esp0;
-       if (stacktop != ROUNDUP(read_esp(), PGSIZE))
+       if (stacktop != ROUNDUP(read_sp(), PGSIZE))
                panic("Bad stacktop: %p esp one is %p\n", stacktop,
-                     ROUNDUP(read_esp(), PGSIZE));
+                     ROUNDUP(read_sp(), PGSIZE));
        return stacktop;
 }
 
-/* Starts running the current TF, just using ret. */
-void pop_kernel_ctx(struct kernel_ctx *ctx)
-{
-       asm volatile ("movl %1,%%esp;           " /* move to future stack */
-                     "pushl %2;                " /* push cs */
-                     "movl %0,%%esp;           " /* move to TF */
-                     "addl $0x20,%%esp;        " /* move to tf_gs slot */
-                     "movl %1,(%%esp);         " /* write future esp */
-                     "subl $0x20,%%esp;        " /* move back to tf start */
-                     "popal;                   " /* restore regs */
-                     "popl %%esp;              " /* set stack ptr */
-                     "subl $0x4,%%esp;         " /* jump down past CS */
-                     "ret                      " /* return to the EIP */
-                     :
-                     : "g"(&ctx->hw_tf), "r"(ctx->hw_tf.tf_esp),
-                       "r"(ctx->hw_tf.tf_eip)
-                     : "memory");
-       panic("ret failed");                            /* mostly to placate your mom */
-}
-
 /* Sends a non-maskable interrupt; the handler will print a trapframe. */
 void send_nmi(uint32_t os_coreid)
 {
@@ -139,7 +117,7 @@ void idt_init(void)
        // This table is made in trapentry.S by each macro in that file.
        // It is layed out such that the ith entry is the ith's traphandler's
        // (uint32_t) trap addr, then (uint32_t) trap number
-       struct trapinfo { uint32_t trapaddr; uint32_t trapnumber; };
+       struct trapinfo { uintptr_t trapaddr; uint32_t trapnumber; };
        extern struct trapinfo (BND(__this,trap_tbl_end) RO trap_tbl)[];
        extern struct trapinfo (SNT RO trap_tbl_end)[];
        int i, trap_tbl_size = trap_tbl_end - trap_tbl;
@@ -175,16 +153,20 @@ void idt_init(void)
 #endif /* CONFIG_KTHREAD_POISON */
 
        // Initialize the TSS field of the gdt.
-       SEG16ROINIT(gdt[GD_TSS >> 3],STS_T32A, (uint32_t)(&ts),sizeof(taskstate_t),0);
+       SEG16ROINIT(gdt[GD_TSS >> 3], STS_T32A, &ts,
+                   sizeof(taskstate_t), 0);
        //gdt[GD_TSS >> 3] = (segdesc_t)SEG16(STS_T32A, (uint32_t) (&ts),
        //                                 sizeof(taskstate_t), 0);
        gdt[GD_TSS >> 3].sd_s = SINIT(0);
 
-       // Load the TSS
+       /* Init the IDT PD.  Need to do this before ltr for some reason.  (Doing
+        * this between ltr and lidt causes the machine to reboot... */
+       idt_pd.pd_lim = sizeof(idt) - 1;
+       idt_pd.pd_base = (uintptr_t)idt;
+
        ltr(GD_TSS);
 
-       // Load the IDT
-       asm volatile("lidt idt_pd");
+       asm volatile("lidt %0" : : "m"(idt_pd));
 
        // This will go away when we start using the IOAPIC properly
        pic_remap();
@@ -202,57 +184,6 @@ void idt_init(void)
                                   handle_kmsg_ipi, NULL);
 }
 
-static void print_regs(push_regs_t *regs)
-{
-       cprintf("  edi  0x%08x\n", regs->reg_edi);
-       cprintf("  esi  0x%08x\n", regs->reg_esi);
-       cprintf("  ebp  0x%08x\n", regs->reg_ebp);
-       cprintf("  oesp 0x%08x\n", regs->reg_oesp);
-       cprintf("  ebx  0x%08x\n", regs->reg_ebx);
-       cprintf("  edx  0x%08x\n", regs->reg_edx);
-       cprintf("  ecx  0x%08x\n", regs->reg_ecx);
-       cprintf("  eax  0x%08x\n", regs->reg_eax);
-}
-
-void print_trapframe(struct hw_trapframe *hw_tf)
-{
-       static spinlock_t ptf_lock = SPINLOCK_INITIALIZER_IRQSAVE;
-
-       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
-       /* This is only called in debug scenarios, and often when the kernel trapped
-        * and needs to tell us about it.  Disable the lock checker so it doesn't go
-        * nuts when we print/panic */
-       pcpui->__lock_depth_disabled++;
-       spin_lock_irqsave(&ptf_lock);
-       printk("TRAP frame at %p on core %d\n", hw_tf, core_id());
-       print_regs(&hw_tf->tf_regs);
-       printk("  gs   0x----%04x\n", hw_tf->tf_gs);
-       printk("  fs   0x----%04x\n", hw_tf->tf_fs);
-       printk("  es   0x----%04x\n", hw_tf->tf_es);
-       printk("  ds   0x----%04x\n", hw_tf->tf_ds);
-       printk("  trap 0x%08x %s\n",  hw_tf->tf_trapno, trapname(hw_tf->tf_trapno));
-       printk("  err  0x%08x\n",     hw_tf->tf_err);
-       printk("  eip  0x%08x\n",     hw_tf->tf_eip);
-       printk("  cs   0x----%04x\n", hw_tf->tf_cs);
-       printk("  flag 0x%08x\n",     hw_tf->tf_eflags);
-       /* Prevents us from thinking these mean something for nested interrupts. */
-       if (hw_tf->tf_cs != GD_KT) {
-               printk("  esp  0x%08x\n",     hw_tf->tf_esp);
-               printk("  ss   0x----%04x\n", hw_tf->tf_ss);
-       }
-       spin_unlock_irqsave(&ptf_lock);
-       pcpui->__lock_depth_disabled--;
-}
-
-static void fake_rdtscp(struct hw_trapframe *hw_tf)
-{
-       uint64_t tsc_time = read_tsc();
-       hw_tf->tf_eip += 3;
-       hw_tf->tf_regs.reg_eax = tsc_time & 0xffffffff;
-       hw_tf->tf_regs.reg_edx = tsc_time >> 32;
-       hw_tf->tf_regs.reg_ecx = core_id();
-}
-
 static void handle_fperr(struct hw_trapframe *hw_tf)
 {
        uint16_t fpcw, fpsw;
@@ -303,8 +234,8 @@ static void trap_dispatch(struct hw_trapframe *hw_tf)
                        pcpui = &per_cpu_info[core_id()];
                        pcpui->__lock_depth_disabled++;
                        print_trapframe(hw_tf);
-                       char *fn_name = get_fn_name(hw_tf->tf_eip);
-                       printk("Core %d is at %p (%s)\n", core_id(), hw_tf->tf_eip,
+                       char *fn_name = get_fn_name(x86_get_ip_hw(hw_tf));
+                       printk("Core %d is at %p (%s)\n", core_id(), x86_get_ip_hw(hw_tf),
                               fn_name);
                        kfree(fn_name);
                        print_kmsgs(core_id());
@@ -315,6 +246,8 @@ static void trap_dispatch(struct hw_trapframe *hw_tf)
                        monitor(hw_tf);
                        break;
                case T_ILLOP:
+               {
+                       uintptr_t ip = x86_get_ip_hw(hw_tf);
                        pcpui = &per_cpu_info[core_id()];
                        pcpui->__lock_depth_disabled++;         /* for print debugging */
                        /* We will muck with the actual TF.  If we're dealing with
@@ -323,16 +256,15 @@ static void trap_dispatch(struct hw_trapframe *hw_tf)
                         * the same).  See set_current_ctx() for more info. */
                        if (!in_kernel(hw_tf))
                                hw_tf = &pcpui->cur_ctx->tf.hw_tf;
-                       printd("bad opcode, eip: %p, next 3 bytes: %x %x %x\n",
-                              hw_tf->tf_eip, 
-                              *(uint8_t*)(hw_tf->tf_eip + 0), 
-                              *(uint8_t*)(hw_tf->tf_eip + 1), 
-                              *(uint8_t*)(hw_tf->tf_eip + 2)); 
+                       printd("bad opcode, eip: %p, next 3 bytes: %x %x %x\n", ip, 
+                              *(uint8_t*)(ip + 0), 
+                              *(uint8_t*)(ip + 1), 
+                              *(uint8_t*)(ip + 2)); 
                        /* rdtscp: 0f 01 f9 */
-                       if (*(uint8_t*)(hw_tf->tf_eip + 0) == 0x0f, 
-                           *(uint8_t*)(hw_tf->tf_eip + 1) == 0x01, 
-                           *(uint8_t*)(hw_tf->tf_eip + 2) == 0xf9) {
-                               fake_rdtscp(hw_tf);
+                       if (*(uint8_t*)(ip + 0) == 0x0f, 
+                           *(uint8_t*)(ip + 1) == 0x01, 
+                           *(uint8_t*)(ip + 2) == 0xf9) {
+                               x86_fake_rdtscp(hw_tf);
                                pcpui->__lock_depth_disabled--; /* for print debugging */
                                return;
                        }
@@ -340,6 +272,7 @@ static void trap_dispatch(struct hw_trapframe *hw_tf)
                        monitor(hw_tf);
                        pcpui->__lock_depth_disabled--;         /* for print debugging */
                        break;
+               }
                case T_PGFLT:
                        page_fault_handler(hw_tf);
                        break;
@@ -351,8 +284,9 @@ static void trap_dispatch(struct hw_trapframe *hw_tf)
                        // check for userspace, for now
                        assert(hw_tf->tf_cs != GD_KT);
                        /* Set up and run the async calls */
-                       prep_syscalls(current, (struct syscall*)hw_tf->tf_regs.reg_eax,
-                                     hw_tf->tf_regs.reg_edx);
+                       prep_syscalls(current,
+                                     (struct syscall*)x86_get_sysenter_arg0(hw_tf),
+                                                 (unsigned int)x86_get_sysenter_arg1(hw_tf));
                        break;
                default:
                        // Unexpected trap: The user process or the kernel has a bug.
@@ -413,9 +347,9 @@ static void abort_halt(struct hw_trapframe *hw_tf)
         * like immediately after a fork (which doesn't populate the pages). */
        if (!in_kernel(hw_tf))
                return;
-       /* the halt instruction in 32 bit is 0xf4, and it's size is 1 byte */
-       if (*(uint8_t*)hw_tf->tf_eip == 0xf4)
-               hw_tf->tf_eip += 1;
+       /* the halt instruction in is 0xf4, and it's size is 1 byte */
+       if (*(uint8_t*)x86_get_ip_hw(hw_tf) == 0xf4)
+               x86_advance_ip(hw_tf, 1);
 }
 
 void trap(struct hw_trapframe *hw_tf)
@@ -573,46 +507,6 @@ register_interrupt_handler(handler_t TP(TV(t)) table[],
        table[int_num].data = data;
 }
 
-void page_fault_handler(struct hw_trapframe *hw_tf)
-{
-       uint32_t fault_va = rcr2();
-       int prot = hw_tf->tf_err & PF_ERROR_WRITE ? PROT_WRITE : PROT_READ;
-       int err;
-
-       /* TODO - handle kernel page faults */
-       if ((hw_tf->tf_cs & 3) == 0) {
-               print_trapframe(hw_tf);
-               panic("Page Fault in the Kernel at 0x%08x!", fault_va);
-               /* if we want to do something like kill a process or other code, be
-                * aware we are in a sort of irq-like context, meaning the main kernel
-                * code we 'interrupted' could be holding locks - even irqsave locks. */
-       }
-       /* safe to reenable after rcr2 */
-       enable_irq();
-       if ((err = handle_page_fault(current, fault_va, prot))) {
-               /* Destroy the faulting process */
-               printk("[%08x] user %s fault va %08x ip %08x on core %d with err %d\n",
-                      current->pid, prot & PROT_READ ? "READ" : "WRITE", fault_va,
-                      hw_tf->tf_eip, core_id(), err);
-               print_trapframe(hw_tf);
-               /* Turn this on to help debug bad function pointers */
-               printd("esp %p\n\t 0(esp): %p\n\t 4(esp): %p\n\t 8(esp): %p\n"
-                      "\t12(esp): %p\n", hw_tf->tf_esp,
-                      *(uintptr_t*)(hw_tf->tf_esp +  0),
-                      *(uintptr_t*)(hw_tf->tf_esp +  4),
-                      *(uintptr_t*)(hw_tf->tf_esp +  8),
-                      *(uintptr_t*)(hw_tf->tf_esp + 12));
-               proc_destroy(current);
-       }
-}
-
-void sysenter_init(void)
-{
-       write_msr(MSR_IA32_SYSENTER_CS, GD_KT);
-       write_msr(MSR_IA32_SYSENTER_ESP, ts.ts_esp0);
-       write_msr(MSR_IA32_SYSENTER_EIP, (uint32_t) &sysenter_handler);
-}
-
 /* This is called from sysenter's asm, with the tf on the kernel stack. */
 /* TODO: use a sw_tf for sysenter */
 void sysenter_callwrapper(struct hw_trapframe *hw_tf)
@@ -626,8 +520,9 @@ void sysenter_callwrapper(struct hw_trapframe *hw_tf)
        enable_irq();
 
        /* Set up and run the async calls */
-       prep_syscalls(current, (struct syscall*)hw_tf->tf_regs.reg_eax,
-                     hw_tf->tf_regs.reg_esi);
+       prep_syscalls(current,
+                                 (struct syscall*)x86_get_sysenter_arg0(hw_tf),
+                                 (unsigned int)x86_get_sysenter_arg1(hw_tf));
        /* If you use pcpui again, reread it, since you might have migrated */
        proc_restartcore();
 }
index 784fd1c..7003160 100644 (file)
@@ -34,7 +34,7 @@
 // T_SYSCALL is defined by the following include:
 #include <ros/arch/syscall.h>
 
-#define T_DEFAULT   0xdeadbeef         // catchall
+#define T_DEFAULT   0x0000beef         // catchall
 
 /* Page faults return the nature of the fault in the bits of the error code: */
 #define PF_ERROR_PRESENT               0x01
 
 /* The kernel's interrupt descriptor table */
 extern gatedesc_t idt[];
+extern pseudodesc_t idt_pd;
 extern taskstate_t ts;
+extern const char *x86_trapname(int trapno);
 
 /* Defined and set up in in arch/init.c, used for XMM initialization */
 extern struct ancillary_state x86_default_fpu;
 
-/* Determines if the given TF was in the kernel or not. */
-static inline bool in_kernel(struct hw_trapframe *hw_tf)
-{
-       return (hw_tf->tf_cs & ~3) == GD_KT;
-}
-
 static inline void save_fp_state(struct ancillary_state *silly)
 {
        asm volatile("fxsave %0" : : "m"(*silly));
@@ -128,30 +124,14 @@ static inline void init_fp_state(void)
 static inline void __attribute__((always_inline))
 set_stack_pointer(uintptr_t sp)
 {
-       asm volatile("mov %0,%%esp" : : "r"(sp) : "memory","esp");
+       asm volatile("mov %0,%%"X86_REG_SP"" : : "r"(sp) : "memory", X86_REG_SP);
 }
 
-/* Save's the current kernel context into tf, setting the PC to the end of this
- * function.  Note the kernel doesn't need to save a lot. */
-static inline void save_kernel_ctx(struct kernel_ctx *ctx)
-{
-       /* Save the regs and the future esp. */
-       asm volatile("movl %%esp,(%0);       " /* save esp in it's slot*/
-                    "pushl %%eax;           " /* temp save eax */
-                    "leal 1f,%%eax;         " /* get future eip */
-                    "movl %%eax,(%1);       " /* store future eip */
-                    "popl %%eax;            " /* restore eax */
-                    "movl %2,%%esp;         " /* move to the beginning of the tf */
-                    "addl $0x20,%%esp;      " /* move to after the push_regs */
-                    "pushal;                " /* save regs */
-                    "addl $0x44,%%esp;      " /* move to esp slot */
-                    "popl %%esp;            " /* restore esp */
-                    "1:                     " /* where this tf will restart */
-                    : 
-                    : "r"(&ctx->hw_tf.tf_esp), "r"(&ctx->hw_tf.tf_eip),
-                      "g"(&ctx->hw_tf)
-                    : "eax", "memory", "cc");
-}
+#ifdef CONFIG_X86_64
+#include <arch/trap64.h>
+#else
+#include <arch/trap32.h>
+#endif
 
 #endif /* !__ASSEMBLER__ */
 
diff --git a/kern/arch/x86/trap32.c b/kern/arch/x86/trap32.c
new file mode 100644 (file)
index 0000000..dbc9140
--- /dev/null
@@ -0,0 +1,127 @@
+/* Copyright (c) 2009-13 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * x86 trap.c bit-specific functions. */
+
+#include <arch/mmu.h>
+#include <arch/x86.h>
+#include <arch/arch.h>
+#include <arch/console.h>
+#include <arch/apic.h>
+#include <ros/common.h>
+#include <smp.h>
+#include <assert.h>
+#include <pmap.h>
+#include <trap.h>
+#include <monitor.h>
+#include <process.h>
+#include <mm.h>
+#include <stdio.h>
+#include <slab.h>
+#include <syscall.h>
+#include <kdebug.h>
+#include <kmalloc.h>
+
+/* Starts running the current TF, just using ret. */
+void pop_kernel_ctx(struct kernel_ctx *ctx)
+{
+       asm volatile ("movl %1,%%esp;           " /* move to future stack */
+                     "pushl %2;                " /* push cs */
+                     "movl %0,%%esp;           " /* move to TF */
+                     "addl $0x20,%%esp;        " /* move to tf_gs slot */
+                     "movl %1,(%%esp);         " /* write future esp */
+                     "subl $0x20,%%esp;        " /* move back to tf start */
+                     "popal;                   " /* restore regs */
+                     "popl %%esp;              " /* set stack ptr */
+                     "subl $0x4,%%esp;         " /* jump down past CS */
+                     "ret                      " /* return to the EIP */
+                     :
+                     : "g"(&ctx->hw_tf), "r"(ctx->hw_tf.tf_esp),
+                       "r"(ctx->hw_tf.tf_eip)
+                     : "memory");
+       panic("ret failed");                            /* mostly to placate your mom */
+}
+
+static void print_regs(push_regs_t *regs)
+{
+       printk("  edi  0x%08x\n", regs->reg_edi);
+       printk("  esi  0x%08x\n", regs->reg_esi);
+       printk("  ebp  0x%08x\n", regs->reg_ebp);
+       printk("  oesp 0x%08x\n", regs->reg_oesp);
+       printk("  ebx  0x%08x\n", regs->reg_ebx);
+       printk("  edx  0x%08x\n", regs->reg_edx);
+       printk("  ecx  0x%08x\n", regs->reg_ecx);
+       printk("  eax  0x%08x\n", regs->reg_eax);
+}
+
+void print_trapframe(struct hw_trapframe *hw_tf)
+{
+       static spinlock_t ptf_lock = SPINLOCK_INITIALIZER_IRQSAVE;
+
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       /* This is only called in debug scenarios, and often when the kernel trapped
+        * and needs to tell us about it.  Disable the lock checker so it doesn't go
+        * nuts when we print/panic */
+       pcpui->__lock_depth_disabled++;
+       spin_lock_irqsave(&ptf_lock);
+       printk("TRAP frame at %p on core %d\n", hw_tf, core_id());
+       print_regs(&hw_tf->tf_regs);
+       printk("  gs   0x----%04x\n", hw_tf->tf_gs);
+       printk("  fs   0x----%04x\n", hw_tf->tf_fs);
+       printk("  es   0x----%04x\n", hw_tf->tf_es);
+       printk("  ds   0x----%04x\n", hw_tf->tf_ds);
+       printk("  trap 0x%08x %s\n",  hw_tf->tf_trapno,
+                                     x86_trapname(hw_tf->tf_trapno));
+       printk("  err  0x%08x\n",     hw_tf->tf_err);
+       printk("  eip  0x%08x\n",     hw_tf->tf_eip);
+       printk("  cs   0x----%04x\n", hw_tf->tf_cs);
+       printk("  flag 0x%08x\n",     hw_tf->tf_eflags);
+       /* Prevents us from thinking these mean something for nested interrupts. */
+       if (hw_tf->tf_cs != GD_KT) {
+               printk("  esp  0x%08x\n",     hw_tf->tf_esp);
+               printk("  ss   0x----%04x\n", hw_tf->tf_ss);
+       }
+       spin_unlock_irqsave(&ptf_lock);
+       pcpui->__lock_depth_disabled--;
+}
+
+void page_fault_handler(struct hw_trapframe *hw_tf)
+{
+       uint32_t fault_va = rcr2();
+       int prot = hw_tf->tf_err & PF_ERROR_WRITE ? PROT_WRITE : PROT_READ;
+       int err;
+
+       /* TODO - handle kernel page faults */
+       if ((hw_tf->tf_cs & 3) == 0) {
+               print_trapframe(hw_tf);
+               panic("Page Fault in the Kernel at 0x%08x!", fault_va);
+               /* if we want to do something like kill a process or other code, be
+                * aware we are in a sort of irq-like context, meaning the main kernel
+                * code we 'interrupted' could be holding locks - even irqsave locks. */
+       }
+       /* safe to reenable after rcr2 */
+       enable_irq();
+       if ((err = handle_page_fault(current, fault_va, prot))) {
+               /* Destroy the faulting process */
+               printk("[%08x] user %s fault va %08x ip %08x on core %d with err %d\n",
+                      current->pid, prot & PROT_READ ? "READ" : "WRITE", fault_va,
+                      hw_tf->tf_eip, core_id(), err);
+               print_trapframe(hw_tf);
+               /* Turn this on to h