Index: trunk/hal/x86_64/hal_gpt.c
===================================================================
--- trunk/hal/x86_64/hal_gpt.c	(revision 25)
+++ trunk/hal/x86_64/hal_gpt.c	(revision 35)
@@ -1,16 +1,14 @@
 /*
- * hal_gpt.c - implementation of the Generic Page Table API for TSAR-MIPS32
- *
- * Author   Alain Greiner (2016)
- *
- * Copyright (c) UPMC Sorbonne Universites
+ * hal_gpt.c - implementation of the Generic Page Table API for x86_64
+ *
+ * Copyright (c) 2017 Maxime Villard
  *
  * This file is part of ALMOS-MKH.
  *
- * ALMOS-MKH.is free software; you can redistribute it and/or modify it
+ * ALMOS-MKH is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by
  * the Free Software Foundation; version 2.0 of the License.
  *
- * ALMOS-MKH.is distributed in the hope that it will be useful, but
+ * ALMOS-MKH is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
@@ -23,8 +21,12 @@
 
 #include <hal_types.h>
+#include <hal_boot.h> /* XXX */
 #include <hal_gpt.h>
 #include <hal_special.h>
+#include <hal_internal.h>
+
 #include <printk.h>
 #include <bits.h>
+#include <string.h>
 #include <process.h>
 #include <kmem.h>
@@ -33,4 +35,140 @@
 #include <ppm.h>
 #include <page.h>
+
+#define VA_SIGN_MASK		0xffff000000000000
+#define VA_SIGN_POS(va)		((va) & ~VA_SIGN_MASK)
+
+#define pl1_i(VA)	(((VA_SIGN_POS(VA)) & L1_FRAME) >> L1_SHIFT)
+#define pl2_i(VA)	(((VA_SIGN_POS(VA)) & L2_FRAME) >> L2_SHIFT)
+#define pl3_i(VA)	(((VA_SIGN_POS(VA)) & L3_FRAME) >> L3_SHIFT)
+#define pl4_i(VA)	(((VA_SIGN_POS(VA)) & L4_FRAME) >> L4_SHIFT)
+
+paddr_t pa_avail __in_kdata = 0;
+vaddr_t va_avail __in_kdata = 0;
+vaddr_t tmpva __in_kdata = (KERNBASE + NKL2_KIMG_ENTRIES * NBPD_L2);
+
+paddr_t hal_gpt_bootstrap_palloc(size_t npages)
+{
+	paddr_t pa = pa_avail;
+	pa_avail += npages * PAGE_SIZE;
+	return pa;
+}
+
+vaddr_t hal_gpt_bootstrap_valloc(size_t npages)
+{
+	vaddr_t va = va_avail;
+	va_avail += npages * PAGE_SIZE;
+	return va;
+}
+
+void hal_gpt_enter(vaddr_t va, paddr_t pa)
+{
+	PTE_BASE[pl1_i(va)] = (pa & PG_FRAME) | PG_V | PG_KW | PG_NX;
+}
+
+/*
+ * Create a page tree that can map va_start->va_end. The caller can then
+ * enter these addresses to physical locations.
+ *
+ * This functions is a bit complicated, and may need to be revisited.
+ */
+void hal_gpt_maptree_area(vaddr_t va_start, vaddr_t va_end)
+{
+	size_t L4start, L4end, nL4e;
+	size_t L3start, L3end, nL3e;
+	size_t L2start, L2end, nL2e;
+	paddr_t L3page, L2page, L1page;
+	paddr_t pa;
+	size_t i, npa;
+	pt_entry_t *pde;
+
+	/* Allocate L3 */
+	L4start = pl4_i(va_start);
+	L4end = pl4_i(va_end);
+	nL4e = (L4end - L4start + 1);
+	L3page = hal_gpt_bootstrap_palloc(nL4e);
+
+	/* Allocate L2 */
+	L3start = pl3_i(va_start);
+	L3end = pl3_i(va_end);
+	nL3e = (L3end - L3start + 1);
+	L2page = hal_gpt_bootstrap_palloc(nL3e);
+
+	/* Allocate L1 */
+	L2start = pl2_i(va_start);
+	L2end = pl2_i(va_end);
+	nL2e = (L2end - L2start + 1);
+	L1page = hal_gpt_bootstrap_palloc(nL2e);
+
+	/* Zero out L1 */
+	for (i = 0; i < nL2e; i++) {
+		pa = L1page + i * PAGE_SIZE;
+		hal_gpt_enter(tmpva, pa);
+		invlpg(tmpva);
+
+		memset((void *)tmpva, 0, PAGE_SIZE);
+	}
+
+	/* Zero out L2 */
+	for (i = 0; i < nL3e; i++) {
+		pa = L2page + i * PAGE_SIZE;
+		hal_gpt_enter(tmpva, pa);
+		invlpg(tmpva);
+
+		memset((void *)tmpva, 0, PAGE_SIZE);
+	}
+
+	/* Zero out L3 */
+	for (i = 0; i < nL4e; i++) {
+		pa = L3page + i * PAGE_SIZE;
+		hal_gpt_enter(tmpva, pa);
+		invlpg(tmpva);
+
+		memset((void *)tmpva, 0, PAGE_SIZE);
+	}
+
+	/* Create L2, linked to L1 */
+	npa = (L2start / NPDPG) * PAGE_SIZE;
+	for (i = L2start; i <= L2end; i++) {
+		pa = (paddr_t)&(((pt_entry_t *)L2page)[i]);
+		pa -= npa;	/* shift on the left */
+		pa &= PG_FRAME; /* rounddown to a page boundary */
+		hal_gpt_enter(tmpva, pa);
+		invlpg(tmpva);
+
+		pde = (pt_entry_t *)tmpva;
+		pa = L1page + (i - L2start) * PAGE_SIZE;
+		pde[i % NPDPG] = (pa & PG_FRAME) | PG_V | PG_KW;
+	}
+
+	/* Create L3, linked to L2 */
+	npa = (L3start / NPDPG) * PAGE_SIZE;
+	for (i = L3start; i <= L3end; i++) {
+		pa = (paddr_t)&(((pt_entry_t *)L3page)[i]);
+		pa -= npa;	/* shift on the left */
+		pa &= PG_FRAME; /* rounddown to a page boundary */
+		hal_gpt_enter(tmpva, pa);
+		invlpg(tmpva);
+
+		pde = (pt_entry_t *)tmpva;
+		pa = L2page + (i - L3start) * PAGE_SIZE;
+		pde[i % NPDPG] = (pa & PG_FRAME) | PG_V | PG_KW;
+	}
+
+	/* Link L3 into L4 */
+	for (i = 0; i < nL4e; i++) {
+		pa = L3page + i * PAGE_SIZE;
+		L4_BASE[L4start + i] = (pa & PG_FRAME) | PG_V | PG_KW;
+	}
+}
+
+void hal_gpt_init(paddr_t firstpa)
+{
+	pa_avail = firstpa;
+	va_avail = CLUSTER0_MIN_VA;
+	hal_gpt_maptree_area(CLUSTER0_MIN_VA, CLUSTER0_MAX_VA);
+}
+
+/* -------------------------------------------------------------------------- */
 
 /****************************************************************************************
