Index: boot/arch/riscv64/Makefile.inc
===================================================================
--- boot/arch/riscv64/Makefile.inc	(revision 94c05b89b35e97bd16e44d00f32fdf77dcd0470c)
+++ boot/arch/riscv64/Makefile.inc	(revision 6c742f5e8be7b02f0ab11fb675e9209a206e67f2)
@@ -34,4 +34,5 @@
 BITS = 64
 ENDIANESS = LE
+EXTRA_CFLAGS = -mcmodel=medany
 
 SOURCES = \
Index: boot/arch/riscv64/_link.ld.in
===================================================================
--- boot/arch/riscv64/_link.ld.in	(revision 94c05b89b35e97bd16e44d00f32fdf77dcd0470c)
+++ boot/arch/riscv64/_link.ld.in	(revision 6c742f5e8be7b02f0ab11fb675e9209a206e67f2)
@@ -1,9 +1,27 @@
+#include <arch/arch.h>
+
 ENTRY(start)
 
 SECTIONS {
+	. = PHYSMEM_START;
+	
 	.text : {
 		*(BOOTSTRAP);
 		*(.text);
 	}
+	
+	. = ALIGN(0x1000);
+	.htif : {
+		htif_page = .;
+		*(.htif)
+	}
+	. = ALIGN(0x1000);
+	
+	. = ALIGN(0x1000);
+	.pt : {
+		pt_page = .;
+		*(.pt)
+	}
+	. = ALIGN(0x1000);
 	
 	.data : {
Index: boot/arch/riscv64/include/arch.h
===================================================================
--- boot/arch/riscv64/include/arch.h	(revision 94c05b89b35e97bd16e44d00f32fdf77dcd0470c)
+++ boot/arch/riscv64/include/arch.h	(revision 6c742f5e8be7b02f0ab11fb675e9209a206e67f2)
@@ -35,4 +35,8 @@
 #define BOOT_STACK_SIZE  PAGE_SIZE
 
+#define PHYSMEM_START  0x40000000
+#define PHYSMEM_SIZE   1073741824
+#define BOOT_OFFSET    0x48000000
+
 #define DEFAULT_MTVEC      0x00000100
 #define TRAP_VECTOR_RESET  0x0100
Index: boot/arch/riscv64/include/asm.h
===================================================================
--- boot/arch/riscv64/include/asm.h	(revision 94c05b89b35e97bd16e44d00f32fdf77dcd0470c)
+++ boot/arch/riscv64/include/asm.h	(revision 6c742f5e8be7b02f0ab11fb675e9209a206e67f2)
@@ -32,5 +32,8 @@
 #include <stddef.h>
 
-extern void jump_to_kernel(void *, uintptr_t)
+extern char htif_page[];
+extern char pt_page[];
+
+extern void jump_to_kernel(uintptr_t)
     __attribute__((noreturn));
 
Index: boot/arch/riscv64/include/mm.h
===================================================================
--- boot/arch/riscv64/include/mm.h	(revision 6c742f5e8be7b02f0ab11fb675e9209a206e67f2)
+++ boot/arch/riscv64/include/mm.h	(revision 6c742f5e8be7b02f0ab11fb675e9209a206e67f2)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ */
+
+#ifndef BOOT_riscv64_MM_H_
+#define BOOT_riscv64_MM_H_
+
+#ifndef __ASM__
+	#define KA2PA(x)  (((uintptr_t) (x)) - UINT64_C(0xffff800000000000))
+	#define PA2KA(x)  (((uintptr_t) (x)) + UINT64_C(0xffff800000000000))
+#else
+	#define KA2PA(x)  ((x) - 0xffff800000000000)
+	#define PA2KA(x)  ((x) + 0xffff800000000000)
+#endif
+
+#define PTL_DIRTY       (1 << 7)
+#define PTL_ACCESSED    (1 << 6)
+#define PTL_GLOBAL      (1 << 5)
+#define PTL_USER        (1 << 4)
+#define PTL_EXECUTABLE  (1 << 3)
+#define PTL_WRITABLE    (1 << 2)
+#define PTL_READABLE    (1 << 1)
+#define PTL_VALID       1
+
+#endif
+
+/** @}
+ */
Index: boot/arch/riscv64/include/types.h
===================================================================
--- boot/arch/riscv64/include/types.h	(revision 94c05b89b35e97bd16e44d00f32fdf77dcd0470c)
+++ boot/arch/riscv64/include/types.h	(revision 6c742f5e8be7b02f0ab11fb675e9209a206e67f2)
@@ -42,4 +42,9 @@
 
 typedef struct {
+	volatile uint64_t *tohost;
+	volatile uint64_t *fromhost;
+} ucbinfo_t;
+
+typedef struct {
 	void *start;
 	size_t size;
@@ -67,4 +72,8 @@
 
 typedef struct {
+	ucbinfo_t ucbinfo;
+	uintptr_t physmem_start;
+	uintptr_t htif_frame;
+	uintptr_t pt_frame;
 	memmap_t memmap;
 	taskmap_t taskmap;
Index: boot/arch/riscv64/include/ucb.h
===================================================================
--- boot/arch/riscv64/include/ucb.h	(revision 94c05b89b35e97bd16e44d00f32fdf77dcd0470c)
+++ boot/arch/riscv64/include/ucb.h	(revision 6c742f5e8be7b02f0ab11fb675e9209a206e67f2)
@@ -38,6 +38,6 @@
 #include <stddef.h>
 
-#define CSR_MTOHOST    0x780
-#define CSR_MFROMHOST  0x781
+extern volatile uint64_t tohost;
+extern volatile uint64_t fromhost;
 
 #define HTIF_DEVICE_CONSOLE  1
Index: boot/arch/riscv64/src/asm.S
===================================================================
--- boot/arch/riscv64/src/asm.S	(revision 94c05b89b35e97bd16e44d00f32fdf77dcd0470c)
+++ boot/arch/riscv64/src/asm.S	(revision 6c742f5e8be7b02f0ab11fb675e9209a206e67f2)
@@ -29,4 +29,19 @@
 #include <abi/asmtool.h>
 #include <arch/arch.h>
+#include <arch/mm.h>
+
+#define MSTATUS_MPP_MASK        0x00001800
+#define MSTATUS_MPP_USER        0x00000000
+#define MSTATUS_MPP_SUPERVISOR  0x00000800
+#define MSTATUS_MPP_MACHINE     0x00001800
+
+#define MSTATUS_SUM_MASK        0x00040000
+
+#define SATP_PFN_MASK  0x00000fffffffffff
+
+#define SATP_MODE_MASK  0xf000000000000000
+#define SATP_MODE_BARE  0x0000000000000000
+#define SATP_MODE_SV39  0x8000000000000000
+#define SATP_MODE_SV48  0x9000000000000000
 
 .section BOOTSTRAP
@@ -76,5 +91,36 @@
 
 FUNCTION_BEGIN(jump_to_kernel)
-	j halt
+	/* Setup SV48 paging for supervisor mode */
+	la t0, ptl_0
+	srli t0, t0, 12
+	
+	li t1, SATP_PFN_MASK
+	and t0, t0, t1
+	
+	li t1, SATP_MODE_SV48
+	or t0, t0, t1
+	
+	csrw sptbr, t0
+	
+	/* Jump to supervisor mode */
+	csrr t0, mstatus
+	
+	li t1, ~MSTATUS_MPP_MASK
+	and t0, t0, t1
+	
+	
+	/*
+	 * TODO: Enable running with Supervisor User Mode
+	 * access disabled.
+	 */
+	li t1, MSTATUS_MPP_SUPERVISOR | MSTATUS_SUM_MASK
+	or t0, t0, t1
+	
+	csrw mstatus, t0
+	
+	li ra, PA2KA(BOOT_OFFSET)
+	csrw mepc, ra
+	
+	mret
 FUNCTION_END(jump_to_kernel)
 
@@ -88,2 +134,11 @@
 SYMBOL(boot_stack)
 	.space BOOT_STACK_SIZE
+
+.section .pt, "aw", @progbits
+
+.align PAGE_WIDTH
+SYMBOL(ptl_0)
+	.fill 256, 8, 0
+	/* Identity mapping for [0; 512G) */
+	.quad 0 + (PTL_DIRTY | PTL_ACCESSED | PTL_EXECUTABLE | PTL_WRITABLE | PTL_READABLE | PTL_VALID)
+	.fill 255, 8, 0
Index: boot/arch/riscv64/src/main.c
===================================================================
--- boot/arch/riscv64/src/main.c	(revision 94c05b89b35e97bd16e44d00f32fdf77dcd0470c)
+++ boot/arch/riscv64/src/main.c	(revision 6c742f5e8be7b02f0ab11fb675e9209a206e67f2)
@@ -30,4 +30,6 @@
 #include <arch/arch.h>
 #include <arch/asm.h>
+#include <arch/ucb.h>
+#include <arch/mm.h>
 #include <version.h>
 #include <stddef.h>
@@ -41,7 +43,4 @@
 #include "../../components.h"
 
-#define KA2PA(x)  (((uintptr_t) (x)) - UINT64_C(0xffff800000000000))
-#define PA2KA(x)  (((uintptr_t) (x)) + UINT64_C(0xffff800000000000))
-
 static bootinfo_t bootinfo;
 
@@ -50,12 +49,24 @@
 	version_print();
 	
+	bootinfo.htif_frame = ((uintptr_t) &htif_page) >> PAGE_WIDTH;
+	bootinfo.pt_frame = ((uintptr_t) &pt_page) >> PAGE_WIDTH;
+	
+	bootinfo.ucbinfo.tohost =
+	    (volatile uint64_t *) PA2KA((uintptr_t) &tohost);
+	bootinfo.ucbinfo.fromhost =
+	    (volatile uint64_t *) PA2KA((uintptr_t) &fromhost);
+	
 	// FIXME TODO: read from device tree
-	bootinfo.memmap.total = 1024 * 1024 * 1024;
-	bootinfo.memmap.cnt = 0;
+	bootinfo.physmem_start = PHYSMEM_START;
+	bootinfo.memmap.total = PHYSMEM_SIZE;
+	bootinfo.memmap.cnt = 1;
+	bootinfo.memmap.zones[0].start = (void *) PHYSMEM_START;
+	bootinfo.memmap.zones[0].size = PHYSMEM_SIZE;
 	
-	printf("\nMemory statistics (total %lu MB)\n\n", bootinfo.memmap.total >> 20);
+	printf("\nMemory statistics (total %lu MB, starting at %p)\n\n",
+	    bootinfo.memmap.total >> 20, (void *) bootinfo.physmem_start);
 	printf(" %p: boot info structure\n", &bootinfo);
 	
-	uintptr_t top = 0;
+	uintptr_t top = BOOT_OFFSET;
 	
 	for (size_t i = 0; i < COMPONENTS; i++) {
@@ -66,9 +77,11 @@
 		uintptr_t tail = (uintptr_t) components[i].addr +
 		    components[i].size;
-		if (tail > top)
-			top = tail;
+		if (tail > top) {
+			printf("\n%s: Image too large to fit (%p >= %p), halting.\n",
+			    components[i].name, (void *) tail, (void *) top);
+			halt();
+		}
 	}
 	
-	top = ALIGN_UP(top, PAGE_SIZE);
 	printf(" %p: inflate area\n", (void *) top);
 	
@@ -92,5 +105,5 @@
 			bootinfo.taskmap.cnt++;
 		} else
-			kernel_entry = (void *) top;
+			kernel_entry = (void *) PA2KA(top);
 		
 		dest[i] = (void *) top;
@@ -101,5 +114,5 @@
 	printf(" %p: kernel entry point\n", kernel_entry);
 	
-	if (top >= bootinfo.memmap.total) {
+	if (top >= bootinfo.physmem_start + bootinfo.memmap.total) {
 		printf("Not enough physical memory available.\n");
 		printf("The boot image is too large. Halting.\n");
@@ -125,4 +138,4 @@
 	
 	printf("Booting the kernel...\n");
-	jump_to_kernel(kernel_entry, PA2KA(&bootinfo));
+	jump_to_kernel(PA2KA(&bootinfo));
 }
Index: boot/arch/riscv64/src/ucb.c
===================================================================
--- boot/arch/riscv64/src/ucb.c	(revision 94c05b89b35e97bd16e44d00f32fdf77dcd0470c)
+++ boot/arch/riscv64/src/ucb.c	(revision 6c742f5e8be7b02f0ab11fb675e9209a206e67f2)
@@ -31,4 +31,16 @@
 #include <macros.h>
 
+volatile uint64_t tohost __attribute__((section(".htif")));
+volatile uint64_t fromhost __attribute__((section(".htif")));
+
+static void poll_fromhost()
+{
+	uint64_t val = fromhost;
+	if (!val)
+		return;
+	
+	fromhost = 0;
+}
+
 void htif_cmd(uint8_t device, uint8_t cmd, uint64_t payload)
 {
@@ -36,12 +48,8 @@
 	    (((uint64_t) cmd) << 48) |
 	    (payload & UINT64_C(0xffffffffffff));
-	uint64_t retval;
 	
-	do {
-		asm volatile (
-			"csrrw %[retval], " STRING(CSR_MTOHOST) ", %[val]\n"
-			: [retval] "=r" (retval)
-			: [val] "r" (val)
-		);
-	} while (retval != 0);
+	while (tohost)
+		poll_fromhost();
+	
+	tohost = val;
 }
