Index: kernel/arch/xen32/include/boot/boot.h
===================================================================
--- kernel/arch/xen32/include/boot/boot.h	(revision e386cbf7b94023b86cf28ea0747181297aa532e7)
+++ kernel/arch/xen32/include/boot/boot.h	(revision e12ccc58f0ffb42cd6c2b5def689f4d61e526d1d)
@@ -37,20 +37,70 @@
 
 #define GUEST_CMDLINE	1024
+#define VIRT_CPUS		32
 #define START_INFO_SIZE	1104
+
 #define BOOT_OFFSET		0x0000
+#define XEN_VIRT_START	0xFC000000
+
+#define TEMP_STACK_SIZE 0x1000
 
 #ifndef __ASM__
 
+#define mp_map ((pfn_t *) XEN_VIRT_START)
+
 #include <arch/types.h>
+
+typedef uint32_t evtchn_t;
+
+typedef struct {
+	uint32_t version;
+	uint32_t pad0;
+	uint64_t tsc_timestamp;   /**< TSC at last update of time vals */
+	uint64_t system_time;     /**< Time, in nanosecs, since boot */
+	uint32_t tsc_to_system_mul;
+	int8_t tsc_shift;
+	int8_t pad1[3];
+} vcpu_time_info_t;
+
+typedef struct {
+	uint32_t cr2;
+	uint32_t pad[5];
+} arch_vcpu_info_t;
+
+typedef struct arch_shared_info {
+	pfn_t max_pfn;                  /**< max pfn that appears in table */
+	uint32_t pfn_to_mfn_frame_list_list;
+    uint32_t nmi_reason;
+} arch_shared_info_t;
+
+typedef struct {
+	uint8_t evtchn_upcall_pending;
+	uint8_t evtchn_upcall_mask;
+	evtchn_t evtchn_pending_sel;
+	arch_vcpu_info_t arch;
+	vcpu_time_info_t time;
+} vcpu_info_t;
+
+typedef struct {
+	vcpu_info_t vcpu_info[VIRT_CPUS];
+	evtchn_t evtchn_pending[32];
+	evtchn_t evtchn_mask[32];
+	
+	uint32_t wc_version;                  /**< Version counter */
+	uint32_t wc_sec;                      /**< Secs  00:00:00 UTC, Jan 1, 1970 */
+	uint32_t wc_nsec;                     /**< Nsecs 00:00:00 UTC, Jan 1, 1970 */
+	
+	arch_shared_info_t arch;
+} shared_info_t;
 
 typedef struct {
 	int8_t magic[32];           /**< "xen-<version>-<platform>" */
 	uint32_t frames;            /**< Available frames */
-	void *shared_info;          /**< Shared info structure (machine address) */
+	shared_info_t *shared_info; /**< Shared info structure (machine address) */
 	uint32_t flags;             /**< SIF_xxx flags */
 	pfn_t store_mfn;            /**< Shared page (machine page) */
-	uint32_t store_evtchn;      /**< Event channel for store communication */
+	evtchn_t store_evtchn;      /**< Event channel for store communication */
 	void *console_mfn;          /**< Console page (machine address) */
-	uint32_t console_evtchn;    /**< Event channel for console messages */
+	evtchn_t console_evtchn;    /**< Event channel for console messages */
 	pte_t *ptl0;                /**< Boot PTL0 (kernel address) */
 	uint32_t pt_frames;         /**< Number of bootstrap page table frames */
@@ -61,5 +111,13 @@
 } start_info_t;
 
+typedef struct {
+	pfn_t start;
+	pfn_t size;
+	pfn_t reserved;
+} memzone_t;
+
 extern start_info_t start_info;
+extern shared_info_t shared_info;
+extern memzone_t meminfo;
 
 #endif
Index: kernel/arch/xen32/include/hypercall.h
===================================================================
--- kernel/arch/xen32/include/hypercall.h	(revision e386cbf7b94023b86cf28ea0747181297aa532e7)
+++ kernel/arch/xen32/include/hypercall.h	(revision e12ccc58f0ffb42cd6c2b5def689f4d61e526d1d)
@@ -36,25 +36,10 @@
 typedef uint16_t domid_t;
 
-typedef struct {
-    uint64_t ptr;  /**< Machine address of PTE */
-    uint64_t val;  /**< New contents of PTE */
-} mmu_update_t;
-
-typedef struct {
-    unsigned int cmd;
-    union {
-        unsigned long mfn;
-        unsigned long linear_addr;
-    } arg1;
-    union {
-        unsigned int nr_ents;
-        void *vcpumask;
-    } arg2;
-} mmuext_op_t;
-
-
-#define XEN_MMU_UPDATE	1
-#define XEN_CONSOLE_IO	18
-#define XEN_MMUEXT_OP	26
+
+#define XEN_MMU_UPDATE			1
+#define XEN_UPDATE_VA_MAPPING	14
+#define XEN_CONSOLE_IO			18
+#define XEN_VM_ASSIST			21
+#define XEN_MMUEXT_OP			26
 
 
@@ -83,4 +68,23 @@
 
 
+#define UVMF_NONE				0        /**< No flushing at all */
+#define UVMF_TLB_FLUSH			1        /**< Flush entire TLB(s) */
+#define UVMF_INVLPG				2        /**< Flush only one entry */
+#define UVMF_FLUSHTYPE_MASK		3
+#define UVMF_MULTI				0        /**< Flush subset of TLBs */
+#define UVMF_LOCAL				0        /**< Flush local TLB */
+#define UVMF_ALL				(1 << 2) /**< Flush all TLBs */
+
+
+/*
+ * Commands to XEN_VM_ASSIST
+ */
+#define VMASST_CMD_ENABLE				0
+#define VMASST_CMD_DISABLE				1
+#define VMASST_TYPE_4GB_SEGMENTS		0
+#define VMASST_TYPE_4GB_SEGMENTS_NOTIFY	1
+#define VMASST_TYPE_WRITABLE_PAGETABLES	2
+
+
 #define DOMID_SELF (0x7FF0U)
 #define DOMID_IO   (0x7FF1U)
@@ -190,13 +194,8 @@
 }
 
-static inline int xen_mmu_update(const mmu_update_t *req, const unsigned int count, unsigned int *success_count, domid_t domid)
+static inline int xen_vm_assist(const unsigned int cmd, const unsigned int type)
 {
-	return hypercall4(XEN_MMU_UPDATE, req, count, success_count, domid);
+    return hypercall2(XEN_VM_ASSIST, cmd, type);
 }
 
-static inline int xen_mmuext_op(const mmuext_op_t *op, const unsigned int count, unsigned int *success_count, domid_t domid)
-{
-	return hypercall4(XEN_MMUEXT_OP, op, count, success_count, domid);
-}
-
 #endif
Index: kernel/arch/xen32/include/mm/frame.h
===================================================================
--- kernel/arch/xen32/include/mm/frame.h	(revision e386cbf7b94023b86cf28ea0747181297aa532e7)
+++ kernel/arch/xen32/include/mm/frame.h	(revision e12ccc58f0ffb42cd6c2b5def689f4d61e526d1d)
@@ -47,6 +47,5 @@
 
 #define PA2MA(x)	((start_info.pm_map[((uintptr_t) (x)) >> 12] << 12) + (((uintptr_t) (x)) & 0xfff))
-
-extern uintptr_t last_frame;
+#define MA2PA(x)	((mp_map[((uintptr_t) (x)) >> 12] << 12) + (((uintptr_t) (x)) & 0xfff))
 
 extern void frame_arch_init(void);
Index: kernel/arch/xen32/include/mm/page.h
===================================================================
--- kernel/arch/xen32/include/mm/page.h	(revision e386cbf7b94023b86cf28ea0747181297aa532e7)
+++ kernel/arch/xen32/include/mm/page.h	(revision e12ccc58f0ffb42cd6c2b5def689f4d61e526d1d)
@@ -44,5 +44,4 @@
 
 #ifndef __ASM__
-#	include <arch/hypercall.h>
 #	define KA2PA(x)	(((uintptr_t) (x)) - 0x80000000)
 #	define PA2KA(x)	(((uintptr_t) (x)) + 0x80000000)
@@ -66,39 +65,37 @@
 #define PTL3_INDEX_ARCH(vaddr)	(((vaddr) >> 12) & 0x3ff)
 
-#define GET_PTL1_ADDRESS_ARCH(ptl0, i)		((pte_t *)((((pte_t *)(ptl0))[(i)].frame_address) << 12))
+#define GET_PTL1_ADDRESS_ARCH(ptl0, i)		((pte_t *) MA2PA((((pte_t *) (ptl0))[(i)].frame_address) << 12))
 #define GET_PTL2_ADDRESS_ARCH(ptl1, i)		(ptl1)
 #define GET_PTL3_ADDRESS_ARCH(ptl2, i)		(ptl2)
-#define GET_FRAME_ADDRESS_ARCH(ptl3, i)		((uintptr_t)((((pte_t *)(ptl3))[(i)].frame_address) << 12))
+#define GET_FRAME_ADDRESS_ARCH(ptl3, i)		((uintptr_t) MA2PA((((pte_t *) (ptl3))[(i)].frame_address) << 12))
 
 #define SET_PTL0_ADDRESS_ARCH(ptl0) { \
 	mmuext_op_t mmu_ext; \
+	\
 	mmu_ext.cmd = MMUEXT_NEW_BASEPTR; \
-	mmu_ext.arg1.mfn = ADDR2PFN(PA2MA(ptl0)); \
+	mmu_ext.mfn = ADDR2PFN(PA2MA(ptl0)); \
 	xen_mmuext_op(&mmu_ext, 1, NULL, DOMID_SELF); \
 }
+
 #define SET_PTL1_ADDRESS_ARCH(ptl0, i, a) { \
 	mmu_update_t update; \
+	\
 	update.ptr = PA2MA(KA2PA(&((pte_t *) (ptl0))[(i)])); \
-	update.val = PA2MA(a); \
+	update.val = PA2MA(a) | 0x0003; \
 	xen_mmu_update(&update, 1, NULL, DOMID_SELF); \
 }
 #define SET_PTL2_ADDRESS_ARCH(ptl1, i, a)
 #define SET_PTL3_ADDRESS_ARCH(ptl2, i, a)
-#define SET_FRAME_ADDRESS_ARCH(ptl3, i, a) { \
-	mmu_update_t update; \
-	update.ptr = PA2MA(KA2PA(&((pte_t *) (ptl3))[(i)])); \
-	update.val = PA2MA(a); \
-	xen_mmu_update(&update, 1, NULL, DOMID_SELF); \
-}
-
-#define GET_PTL1_FLAGS_ARCH(ptl0, i)		get_pt_flags((pte_t *)(ptl0), (index_t)(i))
+#define SET_FRAME_ADDRESS_ARCH(ptl3, i, a)	(((pte_t *) (ptl3))[(i)].frame_address = PA2MA(a) >> 12)
+
+#define GET_PTL1_FLAGS_ARCH(ptl0, i)		get_pt_flags((pte_t *) (ptl0), (index_t)(i))
 #define GET_PTL2_FLAGS_ARCH(ptl1, i)		PAGE_PRESENT
 #define GET_PTL3_FLAGS_ARCH(ptl2, i)		PAGE_PRESENT
-#define GET_FRAME_FLAGS_ARCH(ptl3, i)		get_pt_flags((pte_t *)(ptl3), (index_t)(i))
-
-#define SET_PTL1_FLAGS_ARCH(ptl0, i, x)		set_pt_flags((pte_t *)(ptl0), (index_t)(i), (x))
+#define GET_FRAME_FLAGS_ARCH(ptl3, i)		get_pt_flags((pte_t *) (ptl3), (index_t)(i))
+
+#define SET_PTL1_FLAGS_ARCH(ptl0, i, x)		set_pt_flags((pte_t *) (ptl0), (index_t)(i), (x))
 #define SET_PTL2_FLAGS_ARCH(ptl1, i, x)
 #define SET_PTL3_FLAGS_ARCH(ptl2, i, x)
-#define SET_FRAME_FLAGS_ARCH(ptl3, i, x)	set_pt_flags((pte_t *)(ptl3), (index_t)(i), (x))
+#define SET_FRAME_FLAGS_ARCH(ptl3, i, x)		set_pt_flags((pte_t *) (ptl3), (index_t)(i), (x))
 
 #define PTE_VALID_ARCH(p)			(*((uint32_t *) (p)) != 0)
@@ -114,4 +111,5 @@
 #include <arch/mm/frame.h>
 #include <typedefs.h>
+#include <arch/hypercall.h>
 
 /* Page fault error codes. */
@@ -145,4 +143,39 @@
 } __attribute__ ((packed));
 
+typedef struct {
+	uint64_t ptr;      /**< Machine address of PTE */
+	union {            /**< New contents of PTE */
+		uint64_t val;
+		pte_t pte;
+	};
+} mmu_update_t;
+
+typedef struct {
+	unsigned int cmd;
+	union {
+		unsigned long mfn;
+		unsigned long linear_addr;
+	};
+	union {
+		unsigned int nr_ents;
+		void *vcpumask;
+	};
+} mmuext_op_t;
+
+static inline int xen_update_va_mapping(const void *va, const pte_t pte, const unsigned int flags)
+{
+	return hypercall4(XEN_UPDATE_VA_MAPPING, va, pte, 0, flags);
+}
+
+static inline int xen_mmu_update(const mmu_update_t *req, const unsigned int count, unsigned int *success_count, domid_t domid)
+{
+	return hypercall4(XEN_MMU_UPDATE, req, count, success_count, domid);
+}
+
+static inline int xen_mmuext_op(const mmuext_op_t *op, const unsigned int count, unsigned int *success_count, domid_t domid)
+{
+	return hypercall4(XEN_MMUEXT_OP, op, count, success_count, domid);
+}
+
 static inline int get_pt_flags(pte_t *pt, index_t i)
 {
Index: kernel/arch/xen32/src/boot/boot.S
===================================================================
--- kernel/arch/xen32/src/boot/boot.S	(revision e386cbf7b94023b86cf28ea0747181297aa532e7)
+++ kernel/arch/xen32/src/boot/boot.S	(revision e12ccc58f0ffb42cd6c2b5def689f4d61e526d1d)
@@ -33,8 +33,9 @@
 
 .section __xen_guest
-	.ascii  "GUEST_OS=HelenOS,"
-	.ascii  "XEN_VER=xen-3.0,"
-	.ascii  "HYPERCALL_PAGE=0x0000,"
-	.ascii  "LOADER=generic"
+	.ascii "GUEST_OS=HelenOS,"
+	.ascii "XEN_VER=xen-3.0,"
+	.ascii "HYPERCALL_PAGE=0x0000,"
+	.ascii "LOADER=generic,"
+	.ascii "FEATURES=writable_page_tables"
 	.byte   0
 
@@ -52,9 +53,18 @@
 	cld
 	rep movsb
-
+	
+	# switch to temporal kernel stack
+	
+	movl $kernel_stack, %esp
+	
+	call arch_pre_main
 	call main_bsp								# never returns
 
 	cli
 	hlt
+
+kernel_stack_bottom:
+	.space TEMP_STACK_SIZE
+kernel_stack:
 
 .section K_TEXT_START, "aw", @progbits
@@ -63,2 +73,7 @@
 hypercall_page:
 	.space PAGE_SIZE
+
+.global shared_info
+.org 0x1000
+shared_info:
+	.space PAGE_SIZE
Index: kernel/arch/xen32/src/mm/frame.c
===================================================================
--- kernel/arch/xen32/src/mm/frame.c	(revision e386cbf7b94023b86cf28ea0747181297aa532e7)
+++ kernel/arch/xen32/src/mm/frame.c	(revision e12ccc58f0ffb42cd6c2b5def689f4d61e526d1d)
@@ -35,118 +35,12 @@
 
 #include <mm/frame.h>
-#include <arch/mm/frame.h>
-#include <mm/as.h>
 #include <config.h>
-#include <arch/boot/boot.h>
-#include <arch/hypercall.h>
-#include <panic.h>
-#include <debug.h>
-#include <align.h>
-#include <macros.h>
-
-#include <console/cmd.h>
-#include <console/kconsole.h>
-
-uintptr_t last_frame = 0;
-
-#define L0_PT_SHIFT	10
-#define L3_PT_SHIFT	0
-
-#define L0_PT_ENTRIES	1024
-#define L3_PT_ENTRIES	1024
-
-#define L0_INDEX_MASK			(L0_PT_ENTRIES - 1)
-#define L3_INDEX_MASK			(L3_PT_ENTRIES - 1)
-
-#define PFN2PTL0_INDEX(pfn)	((pfn >> L0_PT_SHIFT) & L0_INDEX_MASK)
-#define PFN2PTL3_INDEX(pfn)	((pfn >> L3_PT_SHIFT) & L3_INDEX_MASK)
-
-#define PAGE_MASK	(~(PAGE_SIZE - 1))
-
-#define _PAGE_PRESENT	0x001UL
-#define _PAGE_RW		0x002UL
-#define _PAGE_USER		0x004UL
-#define _PAGE_PWT		0x008UL
-#define _PAGE_PCD		0x010UL
-#define _PAGE_ACCESSED	0x020UL
-#define _PAGE_DIRTY		0x040UL
-#define _PAGE_PAT		0x080UL
-#define _PAGE_PSE		0x080UL
-#define _PAGE_GLOBAL	0x100UL
-
-#define L0_PROT	(_PAGE_PRESENT | _PAGE_ACCESSED)
-#define L3_PROT	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED)
 
 void frame_arch_init(void)
 {
 	if (config.cpu_active == 1) {
-		/* The only memory zone starts just after page table */
-		pfn_t start = ADDR2PFN(ALIGN_UP(KA2PA(start_info.ptl0), PAGE_SIZE)) + start_info.pt_frames;
-		size_t size = start_info.frames - start;
-		
-		/* Create identity mapping */
-		pfn_t phys;
-		count_t count = 0;
-		for (phys = start; phys < start + size; phys++) {
-			mmu_update_t updates[L3_PT_ENTRIES];
-			pfn_t virt = ADDR2PFN(PA2KA(PFN2ADDR(phys)));
-			
-			size_t ptl0_index = PFN2PTL0_INDEX(virt);
-			size_t ptl3_index = PFN2PTL3_INDEX(virt);
-			
-			pte_t *ptl3 = (pte_t *) PFN2ADDR(start_info.ptl0[ptl0_index].frame_address);
-			
-			if (ptl3 == 0) {
-				mmuext_op_t mmu_ext;
-				
-				pfn_t virt2 = ADDR2PFN(PA2KA(PFN2ADDR(start)));
-				
-				/* New L1 page table entry needed */
-				memsetb(PFN2ADDR(virt2), PAGE_SIZE, 0);
-				
-				size_t ptl0_index2 = PFN2PTL0_INDEX(virt2);
-				size_t ptl3_index2 = PFN2PTL3_INDEX(virt2);
-				pte_t *ptl3_2 = (pte_t *) PFN2ADDR(start_info.ptl0[ptl0_index2].frame_address);
-				
-				if (ptl3_2 == 0)
-					panic("Unable to find page table reference");
-				
-				updates[count].ptr = (uintptr_t) &ptl3_2[ptl3_index2];
-				updates[count].val = PA2MA(PFN2ADDR(start)) | L0_PROT;
-				if (xen_mmu_update(updates, count + 1, NULL, DOMID_SELF) < 0)
-					panic("Unable to map new page table");
-				count = 0;
-				
-				mmu_ext.cmd = MMUEXT_PIN_L1_TABLE;
-				mmu_ext.arg1.mfn = ADDR2PFN(PA2MA(PFN2ADDR(start)));
-				if (xen_mmuext_op(&mmu_ext, 1, NULL, DOMID_SELF) < 0)
-					panic("Error pinning new page table");
-				
-				pte_t *ptl0 = (pte_t *) PA2MA(KA2PA(start_info.ptl0));
-				
-				updates[count].ptr = (uintptr_t) &ptl0[ptl0_index];
-				updates[count].val = PA2MA(PFN2ADDR(start)) | L3_PROT;
-				if (xen_mmu_update(updates, count + 1, NULL, DOMID_SELF) < 0)
-					panic("Unable to update PTE for page table");
-				count = 0;
-				
-				ptl3 = (pte_t *) PFN2ADDR(start_info.ptl0[ptl0_index].frame_address);
-				start++;
-				size--;
-			}
-			
-			updates[count].ptr = (uintptr_t) &ptl3[ptl3_index];
-			updates[count].val = PA2MA(PFN2ADDR(phys)) | L3_PROT;
-			count++;
-			
-			if ((count == L3_PT_ENTRIES) || (phys + 1 == start + size)) {
-				if (xen_mmu_update(updates, count, NULL, DOMID_SELF) < 0)
-					panic("Unable to update PTE");
-				count = 0;
-			}
-		}
-		
-		zone_create(start, size, start, 0);
-		last_frame = start + size;
+		/* The only memory zone */
+		zone_create(meminfo.start, meminfo.size, meminfo.start + meminfo.reserved, 0);
+		frame_mark_unavailable(meminfo.start, meminfo.reserved);
 	}
 }
Index: kernel/arch/xen32/src/xen32.c
===================================================================
--- kernel/arch/xen32/src/xen32.c	(revision e386cbf7b94023b86cf28ea0747181297aa532e7)
+++ kernel/arch/xen32/src/xen32.c	(revision e12ccc58f0ffb42cd6c2b5def689f4d61e526d1d)
@@ -37,8 +37,10 @@
 #include <arch/types.h>
 #include <typedefs.h>
+#include <align.h>
 
 #include <arch/pm.h>
 
 #include <arch/drivers/xconsole.h>
+#include <arch/mm/page.h>
 
 #include <arch/context.h>
@@ -61,4 +63,50 @@
 
 start_info_t start_info;
+memzone_t meminfo;
+
+void arch_pre_main(void)
+{
+	xen_vm_assist(VMASST_CMD_ENABLE, VMASST_TYPE_WRITABLE_PAGETABLES);
+	
+	pte_t pte;
+	memsetb((uintptr_t) &pte, sizeof(pte), 0);
+	
+	pte.present = 1;
+	pte.writeable = 1;
+	pte.frame_address = ADDR2PFN((uintptr_t) start_info.shared_info);
+	xen_update_va_mapping(&shared_info, pte, UVMF_INVLPG);
+	
+	/* Create identity mapping */
+	
+	meminfo.start = ADDR2PFN(ALIGN_UP(KA2PA(start_info.ptl0), PAGE_SIZE)) + start_info.pt_frames;
+	meminfo.size = start_info.frames - meminfo.start;
+	meminfo.reserved = 0;
+	
+	uintptr_t pa;
+	index_t last_ptl0 = 0;
+	for (pa = PFN2ADDR(meminfo.start); pa < PFN2ADDR(meminfo.start + meminfo.size); pa += FRAME_SIZE) {
+		uintptr_t va = PA2KA(pa);
+		
+		if ((PTL0_INDEX(va) != last_ptl0) && (GET_PTL1_FLAGS(start_info.ptl0, PTL0_INDEX(va)) & PAGE_NOT_PRESENT)) {
+			/* New page directory entry needed */
+			uintptr_t tpa = PFN2ADDR(meminfo.start + meminfo.reserved);
+			uintptr_t tva = PA2KA(tpa);
+			
+			memsetb(tva, PAGE_SIZE, 0);
+			
+			pte_t *tptl3 = (pte_t *) PA2KA(GET_PTL1_ADDRESS(start_info.ptl0, PTL0_INDEX(tva)));
+			SET_FRAME_FLAGS(tptl3, PTL3_INDEX(tva), PAGE_PRESENT);
+			SET_PTL1_ADDRESS(start_info.ptl0, PTL0_INDEX(va), tpa);
+			
+			last_ptl0 = PTL0_INDEX(va);
+			meminfo.reserved++;
+		}
+		
+		pte_t *ptl3 = (pte_t *) PA2KA(GET_PTL1_ADDRESS(start_info.ptl0, PTL0_INDEX(va)));
+		
+		SET_FRAME_ADDRESS(ptl3, PTL3_INDEX(va), pa);
+		SET_FRAME_FLAGS(ptl3, PTL3_INDEX(va), PAGE_PRESENT | PAGE_WRITE);
+	}
+}
 
 void arch_pre_mm_init(void)
