Index: kernel/arch/abs32le/src/mm/frame.c
===================================================================
--- kernel/arch/abs32le/src/mm/frame.c	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/abs32le/src/mm/frame.c	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -49,5 +49,4 @@
 }
 
-
 void frame_low_arch_init(void)
 {
Index: kernel/arch/ia32/src/mm/frame.c
===================================================================
--- kernel/arch/ia32/src/mm/frame.c	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/ia32/src/mm/frame.c	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -147,5 +147,4 @@
 }
 
-
 void frame_low_arch_init(void)
 {
Index: kernel/arch/riscv64/Makefile.inc
===================================================================
--- kernel/arch/riscv64/Makefile.inc	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/Makefile.inc	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -31,10 +31,15 @@
 BFD = binary
 
+GCC_CFLAGS += -mcmodel=medany
+
 BITS = 64
 ENDIANESS = LE
 
 ARCH_SOURCES = \
+	arch/$(KARCH)/src/boot/boot.S \
 	arch/$(KARCH)/src/asm.S \
+	arch/$(KARCH)/src/context.S \
 	arch/$(KARCH)/src/debug/stacktrace.c \
+	arch/$(KARCH)/src/drivers/ucb.c \
 	arch/$(KARCH)/src/proc/scheduler.c \
 	arch/$(KARCH)/src/proc/task.c \
Index: kernel/arch/riscv64/_link.ld.in
===================================================================
--- kernel/arch/riscv64/_link.ld.in	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/_link.ld.in	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -14,17 +14,7 @@
 
 SECTIONS {
-	.unmapped BOOT_OFFSET: AT (0) {
-		unmapped_ktext_start = .;
+	.image (PA2KA(BOOT_OFFSET)) : AT (0) {
+		ktext_start = .;
 		*(K_TEXT_START);
-		unmapped_ktext_end = .;
-		
-		unmapped_kdata_start = .;
-		*(K_DATA_START);
-		*(K_INI_PTLS);
-		unmapped_kdata_end = .;
-	}
-	
-	.mapped (BOOT_OFFSET + SIZEOF(.unmapped)) : AT (SIZEOF(.unmapped)) {
-		ktext_start = .;
 		*(.text);
 		ktext_end = .;
@@ -36,11 +26,7 @@
 		QUAD(PA2KA(BOOT_OFFSET));
 		hardcoded_ktext_size = .;
-		QUAD(ktext_end - ktext_start + (unmapped_ktext_end - unmapped_ktext_start));
+		QUAD(ktext_end - ktext_start);
 		hardcoded_kdata_size = .;
-		QUAD(kdata_end - kdata_start + (unmapped_kdata_end - unmapped_kdata_start));
-		hardcoded_unmapped_ktext_size = .;
-		QUAD(unmapped_ktext_end - unmapped_ktext_start);
-		hardcoded_unmapped_kdata_size = .;
-		QUAD(unmapped_kdata_end - unmapped_kdata_start);
+		QUAD(kdata_end - kdata_start);
 		*(.sdata);
 		*(.reginfo);
Index: kernel/arch/riscv64/include/arch/arch.h
===================================================================
--- kernel/arch/riscv64/include/arch/arch.h	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/include/arch/arch.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -38,4 +38,6 @@
 #include <arch/boot/boot.h>
 
+extern void riscv64_pre_main(bootinfo_t *);
+
 #endif
 
Index: kernel/arch/riscv64/include/arch/asm.h
===================================================================
--- kernel/arch/riscv64/include/arch/asm.h	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/include/arch/asm.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -36,4 +36,5 @@
 #define KERN_riscv64_ASM_H_
 
+#include <arch/cpu.h>
 #include <typedefs.h>
 #include <config.h>
@@ -43,35 +44,62 @@
 NO_TRACE static inline ipl_t interrupts_enable(void)
 {
-	// FIXME
-	return 0;
+	ipl_t ipl;
+	
+	asm volatile (
+		"csrrsi %[ipl], sstatus, " STRING(SSTATUS_SIE_MASK) "\n"
+		: [ipl] "=r" (ipl)
+	);
+	
+	return ipl;
 }
 
 NO_TRACE static inline ipl_t interrupts_disable(void)
 {
-	// FIXME
-	return 0;
+	ipl_t ipl;
+	
+	asm volatile (
+		"csrrci %[ipl], sstatus, " STRING(SSTATUS_SIE_MASK) "\n"
+		: [ipl] "=r" (ipl)
+	);
+	
+	return ipl;
 }
 
 NO_TRACE static inline void interrupts_restore(ipl_t ipl)
 {
-	// FIXME
+	if ((ipl & SSTATUS_SIE_MASK) == SSTATUS_SIE_MASK)
+		interrupts_enable();
+	else
+		interrupts_disable();
 }
 
 NO_TRACE static inline ipl_t interrupts_read(void)
 {
-	// FIXME
-	return 0;
+	ipl_t ipl;
+	
+	asm volatile (
+		"csrr %[ipl], sstatus\n"
+		: [ipl] "=r" (ipl)
+	);
+	
+	return ipl;
 }
 
 NO_TRACE static inline bool interrupts_disabled(void)
 {
-	// FIXME
-	return 0;
+	return ((interrupts_read() & SSTATUS_SIE_MASK) == 0);
 }
 
 NO_TRACE static inline uintptr_t get_stack_base(void)
 {
-	// FIXME
-	return 0;
+	uintptr_t base;
+	
+	asm volatile (
+		"and %[base], sp, %[mask]\n"
+		: [base] "=r" (base)
+		: [mask] "r" (~(STACK_SIZE - 1))
+	);
+	
+	return base;
 }
 
Index: kernel/arch/riscv64/include/arch/atomic.h
===================================================================
--- kernel/arch/riscv64/include/arch/atomic.h	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/include/arch/atomic.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -40,34 +40,70 @@
 NO_TRACE static inline void atomic_inc(atomic_t *val)
 {
-	// FIXME
+	asm volatile (
+		"amoadd.d zero, %[inc], %[addr]\n"
+		: [addr] "+A" (val->count)
+		: [inc] "r" (1)
+	);
 }
 
 NO_TRACE static inline void atomic_dec(atomic_t *val)
 {
-	// FIXME
+	asm volatile (
+		"amoadd.d zero, %[inc], %[addr]\n"
+		: [addr] "+A" (val->count)
+		: [inc] "r" (-1)
+	);
 }
 
 NO_TRACE static inline atomic_count_t atomic_postinc(atomic_t *val)
 {
-	atomic_inc(val);
-	return val->count - 1;
+	atomic_count_t orig;
+	
+	asm volatile (
+		"amoadd.d %[orig], %[inc], %[addr]\n"
+		: [orig] "=r" (orig), [addr] "+A" (val->count)
+		: [inc] "r" (1)
+	);
+	
+	return orig;
 }
 
 NO_TRACE static inline atomic_count_t atomic_postdec(atomic_t *val)
 {
-	atomic_dec(val);
-	return val->count + 1;
+	atomic_count_t orig;
+	
+	asm volatile (
+		"amoadd.d %[orig], %[inc], %[addr]\n"
+		: [orig] "=r" (orig), [addr] "+A" (val->count)
+		: [inc] "r" (-1)
+	);
+	
+	return orig;
 }
 
 NO_TRACE static inline atomic_count_t atomic_preinc(atomic_t *val)
 {
-	atomic_inc(val);
-	return val->count;
+	atomic_count_t orig;
+	
+	asm volatile (
+		"amoadd.d %[orig], %[inc], %[addr]\n"
+		: [orig] "=r" (orig), [addr] "+A" (val->count)
+		: [inc] "r" (1)
+	);
+	
+	return orig - 1;
 }
 
 NO_TRACE static inline atomic_count_t atomic_predec(atomic_t *val)
 {
-	atomic_dec(val);
-	return val->count;
+	atomic_count_t orig;
+	
+	asm volatile (
+		"amoadd.d %[orig], %[inc], %[addr]\n"
+		: [orig] "=r" (orig), [addr] "+A" (val->count)
+		: [inc] "r" (-1)
+	);
+	
+	return orig + 1;
 }
 
Index: kernel/arch/riscv64/include/arch/boot/boot.h
===================================================================
--- kernel/arch/riscv64/include/arch/boot/boot.h	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/include/arch/boot/boot.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -36,9 +36,12 @@
 #define KERN_riscv64_BOOT_H_
 
-#define BOOT_OFFSET  0x200000
+#define BOOT_OFFSET  0x48000000
 
 #define TASKMAP_MAX_RECORDS        32
 #define MEMMAP_MAX_RECORDS         32
 #define BOOTINFO_TASK_NAME_BUFLEN  32
+
+/* Temporary stack size for boot process */
+#define TEMP_STACK_SIZE  0x1000
 
 #ifndef __ASM__
@@ -47,4 +50,20 @@
 #include <stdint.h>
 #include <config.h>
+
+typedef struct {
+	volatile uint64_t *tohost;
+	volatile uint64_t *fromhost;
+} ucbinfo_t;
+
+typedef struct {
+	void *start;
+	size_t size;
+} memzone_t;
+
+typedef struct {
+	uint64_t total;
+	size_t cnt;
+	memzone_t zones[MEMMAP_MAX_RECORDS];
+} memmap_t;
 
 typedef struct {
@@ -60,21 +79,11 @@
 
 typedef struct {
-	void *start;
-	size_t size;
-} memzone_t;
-
-typedef struct {
-	uint64_t total;
-	size_t cnt;
-	memzone_t zones[MEMMAP_MAX_RECORDS];
-} memmap_t;
-
-typedef struct {
+	ucbinfo_t ucbinfo;
+	uintptr_t physmem_start;
+	uintptr_t htif_frame;
+	uintptr_t pt_frame;
 	memmap_t memmap;
 	taskmap_t taskmap;
-	ballocs_t ballocs;
 } bootinfo_t;
-
-extern memmap_t memmap;
 
 #endif
Index: kernel/arch/riscv64/include/arch/context.h
===================================================================
--- kernel/arch/riscv64/include/arch/context.h	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/include/arch/context.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -40,6 +40,4 @@
 #define SP_DELTA  16
 
-// FIXME
-
 #define context_set(context, pc, stack, size) \
 	context_set_generic(context, pc, stack, size)
Index: kernel/arch/riscv64/include/arch/context_struct.ag
===================================================================
--- kernel/arch/riscv64/include/arch/context_struct.ag	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/include/arch/context_struct.ag	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -38,6 +38,6 @@
         members : [
                 #
-                # There is a room for optimization (we can store just those
-                # registers that must be preserved during ABI function call).
+                # Only save registers that must be preserved across function
+                # calls.
                 #
 
@@ -52,126 +52,57 @@
 
                 {
-                        name : zero,
+                        name : gp,
                         type : uint64_t
                 },
                 {
-                        name : ra,
-                        type : uint64_t
-                },
-
-                {
-                        name : x3,
+                        name : tp,
                         type : uint64_t
                 },
                 {
-                        name : x4,
+                        name : s0,
                         type : uint64_t
                 },
                 {
-                        name : x5,
+                        name : s1,
                         type : uint64_t
                 },
                 {
-                        name : x6,
+                        name : s2,
                         type : uint64_t
                 },
                 {
-                        name : x7,
+                        name : s3,
                         type : uint64_t
                 },
                 {
-                        name : x8,
+                        name : s4,
                         type : uint64_t
                 },
                 {
-                        name : x9,
+                        name : s5,
                         type : uint64_t
                 },
                 {
-                        name : x10,
+                        name : s6,
                         type : uint64_t
                 },
                 {
-                        name : x11,
+                        name : s7,
                         type : uint64_t
                 },
                 {
-                        name : x12,
+                        name : s8,
                         type : uint64_t
                 },
                 {
-                        name : x13,
+                        name : s9,
                         type : uint64_t
                 },
                 {
-                        name : x14,
+                        name : s10,
                         type : uint64_t
                 },
                 {
-                        name : x15,
-                        type : uint64_t
-                },
-                {
-                        name : x16,
-                        type : uint64_t
-                },
-                {
-                        name : x17,
-                        type : uint64_t
-                },
-                {
-                        name : x18,
-                        type : uint64_t
-                },
-                {
-                        name : x19,
-                        type : uint64_t
-                },
-                {
-                        name : x20,
-                        type : uint64_t
-                },
-                {
-                        name : x21,
-                        type : uint64_t
-                },
-                {
-                        name : x22,
-                        type : uint64_t
-                },
-                {
-                        name : x23,
-                        type : uint64_t
-                },
-                {
-                        name : x24,
-                        type : uint64_t
-                },
-                {
-                        name : x25,
-                        type : uint64_t
-                },
-                {
-                        name : x26,
-                        type : uint64_t
-                },
-                {
-                        name : x27,
-                        type : uint64_t
-                },
-                {
-                        name : x28,
-                        type : uint64_t
-                },
-                {
-                        name : x29,
-                        type : uint64_t
-                },
-                {
-                        name : x30,
-                        type : uint64_t
-                },
-                {
-                        name : x31,
+                        name : s11,
                         type : uint64_t
                 },
Index: kernel/arch/riscv64/include/arch/cpu.h
===================================================================
--- kernel/arch/riscv64/include/arch/cpu.h	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/include/arch/cpu.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -36,4 +36,13 @@
 #define KERN_riscv64_CPU_H_
 
+#define SSTATUS_SIE_MASK  0x00000002
+
+#define SATP_PFN_MASK  UINT64_C(0x00000fffffffffff)
+
+#define SATP_MODE_MASK  UINT64_C(0xf000000000000000)
+#define SATP_MODE_BARE  UINT64_C(0x0000000000000000)
+#define SATP_MODE_SV39  UINT64_C(0x8000000000000000)
+#define SATP_MODE_SV48  UINT64_C(0x9000000000000000)
+
 #ifndef __ASM__
 
Index: kernel/arch/riscv64/include/arch/cycle.h
===================================================================
--- kernel/arch/riscv64/include/arch/cycle.h	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/include/arch/cycle.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -40,5 +40,12 @@
 NO_TRACE static inline uint64_t get_cycle(void)
 {
-	return 0;
+	uint64_t cycle;
+	
+	asm volatile (
+		"rdcycle %[cycle]\n"
+		: [cycle] "=r" (cycle)
+	);
+	
+	return cycle;
 }
 
Index: kernel/arch/riscv64/include/arch/drivers/ucb.h
===================================================================
--- kernel/arch/riscv64/include/arch/drivers/ucb.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
+++ kernel/arch/riscv64/include/arch/drivers/ucb.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/** @addtogroup riscv64
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_riscv64_DRIVERS_UCB_H_
+#define KERN_riscv64_DRIVERS_UCB_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <console/chardev.h>
+
+extern void htif_init(volatile uint64_t *, volatile uint64_t *);
+extern outdev_t *htifout_init(void);
+extern void htif_putchar(outdev_t *, const wchar_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/riscv64/include/arch/mm/asid.h
===================================================================
--- kernel/arch/riscv64/include/arch/mm/asid.h	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/include/arch/mm/asid.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -42,4 +42,7 @@
 typedef uint32_t asid_t;
 
+#define asid_get()  (ASID_START + 1)
+#define asid_put(asid)
+
 #endif
 
Index: kernel/arch/riscv64/include/arch/mm/frame.h
===================================================================
--- kernel/arch/riscv64/include/arch/mm/frame.h	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/include/arch/mm/frame.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -43,4 +43,11 @@
 #ifndef __ASM__
 
+#include <arch/boot/boot.h>
+
+extern uintptr_t physmem_start;
+extern uintptr_t htif_frame;
+extern uintptr_t pt_frame;
+extern memmap_t memmap;
+
 extern void frame_low_arch_init(void);
 extern void frame_high_arch_init(void);
Index: kernel/arch/riscv64/include/arch/mm/km.h
===================================================================
--- kernel/arch/riscv64/include/arch/mm/km.h	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/include/arch/mm/km.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -39,4 +39,10 @@
 #include <stddef.h>
 
+#define KM_RISCV64_IDENTITY_START      UINT64_C(0xffff800000000000)
+#define KM_RISCV64_IDENTITY_SIZE       UINT64_C(0x0000400000000000)
+
+#define KM_RISCV64_NON_IDENTITY_START  UINT64_C(0xffffc00000000000)
+#define KM_RISCV64_NON_IDENTITY_SIZE   UINT64_C(0x0000400000000000)
+
 extern void km_identity_arch_init(void);
 extern void km_non_identity_arch_init(void);
Index: kernel/arch/riscv64/include/arch/mm/page.h
===================================================================
--- kernel/arch/riscv64/include/arch/mm/page.h	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/include/arch/mm/page.h	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -50,48 +50,4 @@
 
 /*
- * Page table entry types.
- *
- * - PTE_TYPE_PTR:         pointer to next level PTE
- * - PTE_TYPE_PTR_GLOBAL:  pointer to next level PTE (global mapping)
- *
- * - PTE_TYPE_SRURX:       kernel read, user read execute
- * - PTE_TYPE_SRWURWX:     kernel read write, user read write execute
- * - PTE_TYPE_SRUR:        kernel read, user read
- * - PTE_TYPE_SRWURW:      kernel read write, user read write
- * - PTE_TYPE_SRXURX:      kernel read execute, user read execute
- * - PTE_TYPE_SRWXURWX:    kernel read write execute, user read write execute
- *
- * - PTE_TYPE_SR:          kernel read
- * - PTE_TYPE_SRW:         kernel read write
- * - PTE_TYPE_SRX:         kernel read execute
- * - PTE_TYPE_SRWX:        kernel read write execute
- *
- * - PTE_TYPE_SR_GLOBAL:   kernel read (global mapping)
- * - PTE_TYPE_SRW_GLOBAL:  kernel read write (global mapping)
- * - PTE_TYPE_SRX_GLOBAL:  kernel read execute (global mapping)
- * - PTE_TYPE_SRWX_GLOBAL: kernel read write execute (global mapping)
- */
-
-#define PTE_TYPE_PTR          0
-#define PTE_TYPE_PTR_GLOBAL   1
-
-#define PTE_TYPE_SRURX        2
-#define PTE_TYPE_SRWURWX      3
-#define PTE_TYPE_SRUR         4
-#define PTE_TYPE_SRWURW       5
-#define PTE_TYPE_SRXURX       6
-#define PTE_TYPE_SRWXURWX     7
-
-#define PTE_TYPE_SR           8
-#define PTE_TYPE_SRW          9
-#define PTE_TYPE_SRX          10
-#define PTE_TYPE_SRWX         11
-
-#define PTE_TYPE_SR_GLOBAL    12
-#define PTE_TYPE_SRW_GLOBAL   13
-#define PTE_TYPE_SRX_GLOBAL   14
-#define PTE_TYPE_SRWX_GLOBAL  15
-
-/*
  * Implementation of 4-level page table interface.
  *
@@ -125,4 +81,7 @@
 #define PTL3_INDEX_ARCH(vaddr)  (((vaddr) >> 12) & 0x1ff)
 
+/* Flags mask for non-leaf page table entries */
+#define NON_LEAF_MASK  (~(PAGE_READ | PAGE_WRITE | PAGE_EXEC))
+
 /* Get PTE address accessors for each level. */
 #define GET_PTL1_ADDRESS_ARCH(ptl0, i) \
@@ -139,5 +98,6 @@
 
 /* Set PTE address accessors for each level. */
-#define SET_PTL0_ADDRESS_ARCH(ptl0)
+#define SET_PTL0_ADDRESS_ARCH(ptl0) \
+	(write_satp((uintptr_t) (ptl0)))
 
 #define SET_PTL1_ADDRESS_ARCH(ptl0, i, a) \
@@ -167,15 +127,15 @@
 
 /* Set PTE flags accessors for each level. */
-#define SET_PTL1_FLAGS_ARCH(ptl0, i, x) \
-	set_pt_flags((pte_t *) (ptl0), (size_t) (i), (x))
-
-#define SET_PTL2_FLAGS_ARCH(ptl1, i, x) \
-	set_pt_flags((pte_t *) (ptl1), (size_t) (i), (x))
-
-#define SET_PTL3_FLAGS_ARCH(ptl2, i, x) \
-	set_pt_flags((pte_t *) (ptl2), (size_t) (i), (x))
-
-#define SET_FRAME_FLAGS_ARCH(ptl3, i, x) \
-	set_pt_flags((pte_t *) (ptl3), (size_t) (i), (x))
+#define SET_PTL1_FLAGS_ARCH(ptl0, i, flags) \
+	set_pt_flags((pte_t *) (ptl0), (size_t) (i), ((flags) & NON_LEAF_MASK))
+
+#define SET_PTL2_FLAGS_ARCH(ptl1, i, flags) \
+	set_pt_flags((pte_t *) (ptl1), (size_t) (i), ((flags) & NON_LEAF_MASK))
+
+#define SET_PTL3_FLAGS_ARCH(ptl2, i, flags) \
+	set_pt_flags((pte_t *) (ptl2), (size_t) (i), ((flags) & NON_LEAF_MASK))
+
+#define SET_FRAME_FLAGS_ARCH(ptl3, i, flags) \
+	set_pt_flags((pte_t *) (ptl3), (size_t) (i), (flags))
 
 /* Set PTE present accessors for each level. */
@@ -196,15 +156,6 @@
 #define PTE_PRESENT_ARCH(pte)     ((pte)->valid != 0)
 #define PTE_GET_FRAME_ARCH(pte)   ((uintptr_t) (pte)->pfn << 12)
-
-#define PTE_WRITABLE_ARCH(pte) \
-	(((pte)->type == PTE_TYPE_SRWURWX) || \
-	((pte)->type == PTE_TYPE_SRWURW) || \
-	((pte)->type == PTE_TYPE_SRWXURWX))
-
-#define PTE_EXECUTABLE_ARCH(pte) \
-	(((pte)->type == PTE_TYPE_SRURX) || \
-	((pte)->type == PTE_TYPE_SRWURWX) || \
-	((pte)->type == PTE_TYPE_SRXURX) || \
-	((pte)->type == PTE_TYPE_SRWXURWX))
+#define PTE_WRITABLE_ARCH(pte)    ((pte)->writable != 0)
+#define PTE_EXECUTABLE_ARCH(pte)  ((pte)->executable != 0)
 
 #ifndef __ASM__
@@ -217,8 +168,12 @@
 typedef struct {
 	unsigned long valid : 1;       /**< Valid bit. */
-	unsigned long type : 4;        /**< Entry type. */
-	unsigned long referenced : 1;  /**< Refenced bit. */
+	unsigned long readable : 1;    /**< Readable bit. */
+	unsigned long writable : 1;    /**< Writable bit. */
+	unsigned long executable : 1;  /**< Executable bit. */
+	unsigned long user : 1;        /**< User mode accessible bit. */
+	unsigned long global : 1;      /**< Global mapping bit. */
+	unsigned long accessed : 1;    /**< Accessed bit. */
 	unsigned long dirty : 1;       /**< Dirty bit. */
-	unsigned long reserved : 3;    /**< Reserved bits. */
+	unsigned long reserved : 2;    /**< Reserved bits. */
 	unsigned long pfn : 54;        /**< Physical frame number. */
 } pte_t;
@@ -229,9 +184,9 @@
 	
 	return (((!entry->valid) << PAGE_PRESENT_SHIFT) |
-	    ((entry->type < PTE_TYPE_SR) << PAGE_USER_SHIFT) |
-	    PAGE_READ |
-	    (PTE_WRITABLE_ARCH(entry) << PAGE_WRITE_SHIFT) |
-	    (PTE_EXECUTABLE_ARCH(entry) << PAGE_EXEC_SHIFT) |
-	    ((entry->type >= PTE_TYPE_SR_GLOBAL) << PAGE_GLOBAL_SHIFT));
+	    (entry->user << PAGE_USER_SHIFT) |
+	    (entry->readable << PAGE_READ_SHIFT) |
+	    (entry->writable << PAGE_WRITE_SHIFT) |
+	    (entry->executable << PAGE_EXEC_SHIFT) |
+	    (entry->global << PAGE_GLOBAL_SHIFT));
 }
 
@@ -241,16 +196,11 @@
 	
 	entry->valid = !(flags & PAGE_NOT_PRESENT);
-	
-	if ((flags & PAGE_WRITE) != 0) {
-		if ((flags & PAGE_EXEC) != 0)
-			entry->type = PTE_TYPE_SRWXURWX;
-		else
-			entry->type = PTE_TYPE_SRWURW;
-	} else {
-		if ((flags & PAGE_EXEC) != 0)
-			entry->type = PTE_TYPE_SRXURX;
-		else
-			entry->type = PTE_TYPE_SRUR;
-	}
+	entry->readable = (flags & PAGE_READ) != 0;
+	entry->writable = (flags & PAGE_WRITE) != 0;
+	entry->executable = (flags & PAGE_EXEC) != 0;
+	entry->user = (flags & PAGE_USER) != 0;
+	entry->global = (flags & PAGE_GLOBAL) != 0;
+	entry->accessed = 1;
+	entry->dirty = 1;
 }
 
@@ -264,4 +214,5 @@
 extern void page_arch_init(void);
 extern void page_fault(unsigned int, istate_t *);
+extern void write_satp(uintptr_t);
 
 #endif /* __ASM__ */
Index: kernel/arch/riscv64/src/asm.S
===================================================================
--- kernel/arch/riscv64/src/asm.S	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/src/asm.S	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -31,5 +31,13 @@
 .text
 
-SYMBOL(kernel_image_start)
-	// FIXME
-	nop
+FUNCTION_BEGIN(asm_delay_loop)
+	ret
+FUNCTION_END(asm_delay_loop)
+
+FUNCTION_BEGIN(early_putchar)
+	ret
+FUNCTION_END(early_putchar)
+
+FUNCTION_BEGIN(cpu_halt)
+	j cpu_halt
+FUNCTION_END(cpu_halt)
Index: kernel/arch/riscv64/src/boot/boot.S
===================================================================
--- kernel/arch/riscv64/src/boot/boot.S	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
+++ kernel/arch/riscv64/src/boot/boot.S	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include <abi/asmtool.h>
+#include <arch/boot/boot.h>
+#include <arch/cpu.h>
+
+.section K_TEXT_START, "ax"
+
+SYMBOL(kernel_image_start)
+	/* Setup temporary stack */
+	la sp, temp_stack
+	
+	/* Create the first stack frame */
+	addi sp, sp, -16
+	
+	/* Call riscv64_pre_main() */
+	jal riscv64_pre_main
+	
+	/* Call main_bsp() */
+	jal main_bsp
+	
+	/* Not reached */
+	csrci sstatus, SSTATUS_SIE_MASK
+	hlt0:
+		wfi
+		j hlt0
+
+.data
+
+.align 16
+.space TEMP_STACK_SIZE
+temp_stack:
Index: kernel/arch/riscv64/src/context.S
===================================================================
--- kernel/arch/riscv64/src/context.S	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
+++ kernel/arch/riscv64/src/context.S	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -0,0 +1,80 @@
+#
+# Copyright (c) 2003-2004 Jakub Jermar
+# 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.
+#
+
+#include <abi/asmtool.h>
+#include <arch/context_struct.h>
+
+.text
+
+FUNCTION_BEGIN(context_save_arch)
+	sd gp, CONTEXT_OFFSET_GP(a0)
+	sd tp, CONTEXT_OFFSET_TP(a0)
+	sd s0, CONTEXT_OFFSET_S0(a0)
+	sd s1, CONTEXT_OFFSET_S1(a0)
+	sd s2, CONTEXT_OFFSET_S2(a0)
+	sd s3, CONTEXT_OFFSET_S3(a0)
+	sd s4, CONTEXT_OFFSET_S4(a0)
+	sd s5, CONTEXT_OFFSET_S5(a0)
+	sd s6, CONTEXT_OFFSET_S6(a0)
+	sd s7, CONTEXT_OFFSET_S7(a0)
+	sd s8, CONTEXT_OFFSET_S8(a0)
+	sd s9, CONTEXT_OFFSET_S9(a0)
+	sd s10, CONTEXT_OFFSET_S10(a0)
+	sd s11, CONTEXT_OFFSET_S11(a0)
+	
+	sd ra, CONTEXT_OFFSET_PC(a0)
+	sd sp, CONTEXT_OFFSET_SP(a0)
+	
+	# context_save returns 1
+	li a0, 1
+	ret
+FUNCTION_END(context_save_arch)
+
+FUNCTION_BEGIN(context_restore_arch)
+	ld gp, CONTEXT_OFFSET_GP(a0)
+	ld tp, CONTEXT_OFFSET_TP(a0)
+	ld s0, CONTEXT_OFFSET_S0(a0)
+	ld s1, CONTEXT_OFFSET_S1(a0)
+	ld s2, CONTEXT_OFFSET_S2(a0)
+	ld s3, CONTEXT_OFFSET_S3(a0)
+	ld s4, CONTEXT_OFFSET_S4(a0)
+	ld s5, CONTEXT_OFFSET_S5(a0)
+	ld s6, CONTEXT_OFFSET_S6(a0)
+	ld s7, CONTEXT_OFFSET_S7(a0)
+	ld s8, CONTEXT_OFFSET_S8(a0)
+	ld s9, CONTEXT_OFFSET_S9(a0)
+	ld s10, CONTEXT_OFFSET_S10(a0)
+	ld s11, CONTEXT_OFFSET_S11(a0)
+	
+	ld ra, CONTEXT_OFFSET_PC(a0)
+	ld sp, CONTEXT_OFFSET_SP(a0)
+	
+	# context_restore returns 0
+	li a0, 0
+	ret
+FUNCTION_END(context_restore_arch)
Index: kernel/arch/riscv64/src/drivers/ucb.c
===================================================================
--- kernel/arch/riscv64/src/drivers/ucb.c	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
+++ kernel/arch/riscv64/src/drivers/ucb.c	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#include <arch/drivers/ucb.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <console/chardev.h>
+#include <str.h>
+#include <mm/slab.h>
+
+#define HTIF_DEVICE_CONSOLE  1
+
+#define HTIF_CONSOLE_PUTC  1
+
+static volatile uint64_t *tohost;
+static volatile uint64_t *fromhost;
+
+static outdev_operations_t htifdev_ops = {
+	.write = htif_putchar,
+	.redraw = NULL,
+	.scroll_up = NULL,
+	.scroll_down = NULL
+};
+
+static void poll_fromhost()
+{
+	uint64_t val = *fromhost;
+	if (!val)
+		return;
+	
+	*fromhost = 0;
+}
+
+void htif_init(volatile uint64_t *tohost_addr, volatile uint64_t *fromhost_addr)
+{
+	tohost = tohost_addr;
+	fromhost = fromhost_addr;
+}
+
+outdev_t *htifout_init(void)
+{
+	outdev_t *htifdev = malloc(sizeof(outdev_t), FRAME_ATOMIC);
+	if (!htifdev)
+		return NULL;
+	
+	outdev_initialize("htifdev", htifdev, &htifdev_ops);
+	return htifdev;
+}
+
+static void htif_cmd(uint8_t device, uint8_t cmd, uint64_t payload)
+{
+	uint64_t val = (((uint64_t) device) << 56) |
+	    (((uint64_t) cmd) << 48) |
+	    (payload & UINT64_C(0xffffffffffff));
+	
+	while (*tohost)
+		poll_fromhost();
+	
+	*tohost = val;
+}
+
+void htif_putchar(outdev_t *dev, const wchar_t ch)
+{
+	if (ascii_check(ch))
+		htif_cmd(HTIF_DEVICE_CONSOLE, HTIF_CONSOLE_PUTC, ch);
+	else
+		htif_cmd(HTIF_DEVICE_CONSOLE, HTIF_CONSOLE_PUTC, U_SPECIAL);
+}
Index: kernel/arch/riscv64/src/mm/as.c
===================================================================
--- kernel/arch/riscv64/src/mm/as.c	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/src/mm/as.c	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -40,4 +40,15 @@
 }
 
+/** Install address space.
+ *
+ * Install ASID.
+ *
+ * @param as Address space structure.
+ */
+void as_install_arch(as_t *as)
+{
+	// FIXME
+}
+
 /** @}
  */
Index: kernel/arch/riscv64/src/mm/frame.c
===================================================================
--- kernel/arch/riscv64/src/mm/frame.c	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/src/mm/frame.c	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -32,5 +32,7 @@
 
 #include <mm/frame.h>
+#include <arch/boot/boot.h>
 #include <arch/mm/frame.h>
+#include <arch/drivers/ucb.h>
 #include <mm/as.h>
 #include <config.h>
@@ -39,9 +41,10 @@
 #include <align.h>
 #include <macros.h>
-
 #include <print.h>
 
-size_t hardcoded_unmapped_ktext_size = 0;
-size_t hardcoded_unmapped_kdata_size = 0;
+uintptr_t physmem_start;
+uintptr_t htif_frame;
+uintptr_t pt_frame;
+memmap_t memmap;
 
 void physmem_print(void)
@@ -49,11 +52,51 @@
 }
 
+static void frame_common_arch_init(bool low)
+{
+	pfn_t minconf =
+	    max3(ADDR2PFN(physmem_start), htif_frame + 1, pt_frame + 1);
+	
+	for (size_t i = 0; i < memmap.cnt; i++) {
+		/* To be safe, make the available zone possibly smaller */
+		uintptr_t base = ALIGN_UP((uintptr_t) memmap.zones[i].start,
+		    FRAME_SIZE);
+		size_t size = ALIGN_DOWN(memmap.zones[i].size -
+		    (base - ((uintptr_t) memmap.zones[i].start)), FRAME_SIZE);
+		
+		if (!frame_adjust_zone_bounds(low, &base, &size))
+			return;
+		
+		pfn_t pfn = ADDR2PFN(base);
+		size_t count = SIZE2FRAMES(size);
+		pfn_t conf;
+		
+		if (low) {
+			if ((minconf < pfn) || (minconf >= pfn + count))
+				conf = pfn;
+			else
+				conf = minconf;
+			
+			zone_create(pfn, count, conf,
+			    ZONE_AVAILABLE | ZONE_LOWMEM);
+		} else {
+			conf = zone_external_conf_alloc(count);
+			if (conf != 0)
+				zone_create(pfn, count, conf,
+				    ZONE_AVAILABLE | ZONE_HIGHMEM);
+		}
+	}
+}
 
 void frame_low_arch_init(void)
 {
+	frame_common_arch_init(true);
+	
+	frame_mark_unavailable(htif_frame, 1);
+	frame_mark_unavailable(pt_frame, 1);
 }
 
 void frame_high_arch_init(void)
 {
+	frame_common_arch_init(false);
 }
 
Index: kernel/arch/riscv64/src/mm/km.c
===================================================================
--- kernel/arch/riscv64/src/mm/km.c	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/src/mm/km.c	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -32,18 +32,25 @@
 
 #include <arch/mm/km.h>
+#include <mm/km.h>
 #include <stdbool.h>
 #include <typedefs.h>
+#include <macros.h>
 
 void km_identity_arch_init(void)
 {
+	config.identity_base = KM_RISCV64_IDENTITY_START;
+	config.identity_size = KM_RISCV64_IDENTITY_SIZE;
 }
 
 void km_non_identity_arch_init(void)
 {
+	km_non_identity_span_add(KM_RISCV64_NON_IDENTITY_START,
+	    KM_RISCV64_NON_IDENTITY_SIZE);
 }
 
 bool km_is_non_identity_arch(uintptr_t addr)
 {
-	return false;
+	return iswithin(KM_RISCV64_NON_IDENTITY_START,
+	    KM_RISCV64_NON_IDENTITY_SIZE, addr, 1);
 }
 
Index: kernel/arch/riscv64/src/mm/page.c
===================================================================
--- kernel/arch/riscv64/src/mm/page.c	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/src/mm/page.c	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -36,4 +36,5 @@
 #include <genarch/mm/page_pt.h>
 #include <arch/mm/frame.h>
+#include <arch/cpu.h>
 #include <mm/frame.h>
 #include <mm/page.h>
@@ -50,6 +51,27 @@
 void page_arch_init(void)
 {
-	if (config.cpu_active == 1)
+	if (config.cpu_active == 1) {
 		page_mapping_operations = &pt_mapping_operations;
+		
+		page_table_lock(AS_KERNEL, true);
+		
+		/*
+		 * PA2KA(identity) mapping for all low-memory frames.
+		 */
+		for (uintptr_t cur = 0;
+		    cur < min(config.identity_size, config.physmem_end);
+		    cur += FRAME_SIZE)
+			page_mapping_insert(AS_KERNEL, PA2KA(cur), cur,
+			    PAGE_GLOBAL | PAGE_CACHEABLE | PAGE_EXEC | PAGE_WRITE | PAGE_READ);
+		
+		page_table_unlock(AS_KERNEL, true);
+		
+		// FIXME: register page fault extension handler
+		
+		write_satp((uintptr_t) AS_KERNEL->genarch.page_table);
+		
+		/* The boot page table is no longer needed. */
+		// FIXME: frame_mark_available(pt_frame, 1);
+	}
 }
 
@@ -58,4 +80,15 @@
 }
 
+void write_satp(uintptr_t ptl0)
+{
+	uint64_t satp = ((ptl0 >> FRAME_WIDTH) & SATP_PFN_MASK) |
+	    SATP_MODE_SV48;
+	
+	asm volatile (
+		"csrw sptbr, %[satp]\n"
+		:: [satp] "r" (satp)
+	);
+}
+
 /** @}
  */
Index: kernel/arch/riscv64/src/riscv64.c
===================================================================
--- kernel/arch/riscv64/src/riscv64.c	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/arch/riscv64/src/riscv64.c	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -35,6 +35,8 @@
 #include <arch.h>
 #include <stddef.h>
+#include <arch/arch.h>
 #include <arch/interrupt.h>
 #include <arch/asm.h>
+#include <arch/drivers/ucb.h>
 
 #include <func.h>
@@ -49,12 +51,51 @@
 #include <console/console.h>
 #include <mem.h>
+#include <str.h>
 
 char memcpy_from_uspace_failover_address;
 char memcpy_to_uspace_failover_address;
 
+static void riscv64_post_mm_init(void);
+
 arch_ops_t riscv64_ops = {
+	.post_mm_init = riscv64_post_mm_init
 };
 
 arch_ops_t *arch_ops = &riscv64_ops;
+
+void riscv64_pre_main(bootinfo_t *bootinfo)
+{
+	physmem_start = bootinfo->physmem_start;
+	htif_frame = bootinfo->htif_frame;
+	pt_frame = bootinfo->pt_frame;
+	
+	htif_init(bootinfo->ucbinfo.tohost, bootinfo->ucbinfo.fromhost);
+	
+	/* Copy tasks map. */
+	init.cnt = min3(bootinfo->taskmap.cnt, TASKMAP_MAX_RECORDS,
+	    CONFIG_INIT_TASKS);
+	
+	for (size_t i = 0; i < init.cnt; i++) {
+		init.tasks[i].paddr = KA2PA(bootinfo->taskmap.tasks[i].addr);
+		init.tasks[i].size = bootinfo->taskmap.tasks[i].size;
+		str_cpy(init.tasks[i].name, CONFIG_TASK_NAME_BUFLEN,
+		    bootinfo->taskmap.tasks[i].name);
+	}
+	
+	/* Copy physical memory map. */
+	memmap.total = bootinfo->memmap.total;
+	memmap.cnt = min(bootinfo->memmap.cnt, MEMMAP_MAX_RECORDS);
+	for (size_t i = 0; i < memmap.cnt; i++) {
+		memmap.zones[i].start = bootinfo->memmap.zones[i].start;
+		memmap.zones[i].size = bootinfo->memmap.zones[i].size;
+	}
+}
+
+void riscv64_post_mm_init(void)
+{
+	outdev_t *htifout = htifout_init();
+	if (htifout)
+		stdout_wire(htifout);
+}
 
 void calibrate_delay_loop(void)
@@ -90,14 +131,4 @@
 }
 
-int context_save_arch(context_t *ctx)
-{
-	return 1;
-}
-
-void context_restore_arch(context_t *ctx)
-{
-	while (true);
-}
-
 void fpu_init(void)
 {
@@ -122,8 +153,4 @@
 }
 
-void early_putchar(wchar_t ch)
-{
-}
-
 /** @}
  */
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/generic/src/ipc/sysipc.c	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -766,5 +766,5 @@
 		}
 		
-		STRUCT_TO_USPACE(&calldata->args, &call->data.args);
+		STRUCT_TO_USPACE(calldata, &call->data);
 		ipc_call_free(call);
 		
Index: kernel/test/synch/rcu1.c
===================================================================
--- kernel/test/synch/rcu1.c	(revision 6636fb199c2da579a541a22014f1a1e5321c2a68)
+++ kernel/test/synch/rcu1.c	(revision 91b604993517a2bdc14cfe1ede6902150ab29533)
@@ -389,4 +389,9 @@
 static void seq_func(void *arg)
 {
+	/*
+	 * Temporarily workaround GCC 7.1.0 internal
+	 * compiler error when compiling for riscv64.
+	 */
+#ifndef KARCH_riscv64
 	seq_work_t *work = (seq_work_t*)arg;
 	
@@ -435,5 +440,8 @@
 		}
 		
-	} 
+	}
+#else
+	(void) seq_cb;
+#endif
 }
 
