source: trunk/hal/x86_64/core/hal_gpt.c @ 226

Last change on this file since 226 was 225, checked in by max@…, 7 years ago

implement hal_gpt_create

File size: 9.3 KB
Line 
1/*
2 * hal_gpt.c - implementation of the Generic Page Table API for x86_64
3 *
4 * Copyright (c) 2017 Maxime Villard
5 *
6 * This file is part of ALMOS-MKH.
7 *
8 * ALMOS-MKH is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2.0 of the License.
11 *
12 * ALMOS-MKH is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <hal_types.h>
23#include <hal_boot.h> /* XXX */
24#include <hal_gpt.h>
25#include <hal_special.h>
26#include <hal_internal.h>
27
28#include <printk.h>
29#include <bits.h>
30#include <string.h>
31#include <process.h>
32#include <kmem.h>
33#include <thread.h>
34#include <cluster.h>
35#include <ppm.h>
36#include <page.h>
37
38extern vaddr_t __kernel_end;
39size_t kimg_size __in_kdata = 0;
40
41paddr_t pa_avail __in_kdata = 0;
42vaddr_t va_avail __in_kdata = 0;
43vaddr_t tmpva __in_kdata = (KERNBASE + NKL2_KIMG_ENTRIES * NBPD_L2);
44
45paddr_t hal_gpt_bootstrap_palloc(size_t npages)
46{
47        paddr_t pa = pa_avail;
48        pa_avail += npages * PAGE_SIZE;
49        return pa;
50}
51
52vaddr_t hal_gpt_bootstrap_valloc(size_t npages)
53{
54        vaddr_t va = va_avail;
55        va_avail += npages * PAGE_SIZE;
56        return va;
57}
58
59/*
60 * Reset the bootstrap VA we've used in cluster0 so far. After this
61 * function, cluster0's heap is empty.
62 */
63void hal_gpt_bootstrap_reset()
64{
65        /*
66         * Re-enter cluster0's space, because we altered it when mapping the ACPI
67         * tables.
68         */
69        hal_gpt_enter_range(CLUSTER_MIN_VA(0), 0, CLUSTER_PA_SIZE / PAGE_SIZE);
70
71        va_avail = CLUSTER_MIN_VA(0) + KERNEL_VA_SIZE;
72}
73
74/*
75 * Uniformize the PA and VA offsets, and return the value. After this function,
76 * we are guaranteed to have [VA = PA + constant_offset]. And therefore we can
77 * only call hal_gpt_bootstrap_valloc, without entering it in a PA.
78 */
79size_t hal_gpt_bootstrap_uniformize()
80{
81        size_t pa_offset = pa_avail - 0;
82        size_t va_offset = va_avail - CLUSTER_MIN_VA(0);
83
84        if (pa_offset < va_offset)
85                pa_avail += (va_offset - pa_offset);
86        else if (pa_offset > va_offset)
87                va_avail += (pa_offset - va_offset);
88
89        return MAX(pa_offset, va_offset);
90}
91
92void hal_gpt_enter(vaddr_t va, paddr_t pa, pt_entry_t flags)
93{
94        XASSERT(va % PAGE_SIZE == 0);
95        XASSERT(pa % PAGE_SIZE == 0);
96        //XASSERT(va == tmpva || PTE_BASE[pl1_i(va)] == 0);
97        PTE_BASE[pl1_i(va)] = (pa & PG_FRAME) | flags;
98        invlpg(va);
99}
100
101void hal_gpt_enter_range(vaddr_t va, paddr_t pa, size_t n)
102{
103        pt_entry_t flags = PG_V | PG_KW | PG_NX;
104        size_t i;
105        for (i = 0; i < n; i++) {
106                hal_gpt_enter(va + i * PAGE_SIZE, pa + i * PAGE_SIZE, flags);
107        }
108}
109
110void hal_gpt_leave(vaddr_t va)
111{
112        XASSERT(va % PAGE_SIZE == 0);
113        XASSERT(PTE_BASE[pl1_i(va)] != 0);
114        PTE_BASE[pl1_i(va)] = 0;
115        invlpg(va);
116}
117
118void hal_gpt_leave_range(vaddr_t va, size_t n)
119{
120        size_t i;
121        for (i = 0; i < n; i++) {
122                hal_gpt_leave(va + i * PAGE_SIZE);
123        }
124}
125
126/*
127 * Create a page tree that can map va_start->va_end. The caller can then
128 * enter these addresses to physical locations.
129 *
130 * This function is a bit complicated, and may need to be revisited.
131 */
132void hal_gpt_maptree_area(vaddr_t va_start, vaddr_t va_end)
133{
134        pt_entry_t flags = PG_V | PG_KW | PG_NX;
135        size_t L4start, L4end, nL4e;
136        size_t L3start, L3end, nL3e;
137        size_t L2start, L2end, nL2e;
138        paddr_t L3page, L2page, L1page;
139        paddr_t pa;
140        size_t i, npa;
141        pt_entry_t *pde;
142
143        /* Allocate L3 */
144        L4start = pl4_i(va_start);
145        L4end = pl4_i(va_end);
146        nL4e = (L4end - L4start + 1);
147        L3page = hal_gpt_bootstrap_palloc(nL4e);
148
149        /* Allocate L2 */
150        L3start = pl3_i(va_start);
151        L3end = pl3_i(va_end);
152        nL3e = (L3end - L3start + 1);
153        L2page = hal_gpt_bootstrap_palloc(nL3e);
154
155        /* Allocate L1 */
156        L2start = pl2_i(va_start);
157        L2end = pl2_i(va_end);
158        nL2e = (L2end - L2start + 1);
159        L1page = hal_gpt_bootstrap_palloc(nL2e);
160
161        /* Zero out L1 */
162        for (i = 0; i < nL2e; i++) {
163                pa = L1page + i * PAGE_SIZE;
164                hal_gpt_enter(tmpva, pa, flags);
165
166                memset((void *)tmpva, 0, PAGE_SIZE);
167        }
168
169        /* Zero out L2 */
170        for (i = 0; i < nL3e; i++) {
171                pa = L2page + i * PAGE_SIZE;
172                hal_gpt_enter(tmpva, pa, flags);
173
174                memset((void *)tmpva, 0, PAGE_SIZE);
175        }
176
177        /* Zero out L3 */
178        for (i = 0; i < nL4e; i++) {
179                pa = L3page + i * PAGE_SIZE;
180                hal_gpt_enter(tmpva, pa, flags);
181
182                memset((void *)tmpva, 0, PAGE_SIZE);
183        }
184
185        /* Create L2, linked to L1 */
186        npa = (L2start / NPDPG) * PAGE_SIZE;
187        for (i = L2start; i <= L2end; i++) {
188                pa = (paddr_t)&(((pt_entry_t *)L2page)[i]);
189                pa -= npa;      /* shift on the left */
190                pa &= PG_FRAME; /* rounddown to a page boundary */
191                hal_gpt_enter(tmpva, pa, flags);
192
193                pde = (pt_entry_t *)tmpva;
194                pa = L1page + (i - L2start) * PAGE_SIZE;
195                pde[i % NPDPG] = (pa & PG_FRAME) | PG_V | PG_KW;
196        }
197
198        /* Create L3, linked to L2 */
199        npa = (L3start / NPDPG) * PAGE_SIZE;
200        for (i = L3start; i <= L3end; i++) {
201                pa = (paddr_t)&(((pt_entry_t *)L3page)[i]);
202                pa -= npa;      /* shift on the left */
203                pa &= PG_FRAME; /* rounddown to a page boundary */
204                hal_gpt_enter(tmpva, pa, flags);
205
206                pde = (pt_entry_t *)tmpva;
207                pa = L2page + (i - L3start) * PAGE_SIZE;
208                pde[i % NPDPG] = (pa & PG_FRAME) | PG_V | PG_KW;
209        }
210
211        /* Link L3 into L4 */
212        for (i = 0; i < nL4e; i++) {
213                pa = L3page + i * PAGE_SIZE;
214                L4_BASE[L4start + i] = (pa & PG_FRAME) | PG_V | PG_KW;
215        }
216}
217
218void hal_gpt_init(paddr_t firstpa)
219{
220        /* Initialize global values */
221        pa_avail = firstpa;
222        va_avail = CLUSTER_MIN_VA(0) + KERNEL_VA_SIZE;
223        kimg_size = ((uint64_t)&__kernel_end - KERNBASE);
224        XASSERT(kimg_size % PAGE_SIZE == 0);
225
226        /*
227         * Create cluster0's page tree, enter the space, and unmap the area
228         * below the kernel.
229         */
230        hal_gpt_maptree_area(CLUSTER_MIN_VA(0), CLUSTER_MIN_VA(0) + CLUSTER_PA_SIZE);
231        hal_gpt_enter_range(CLUSTER_MIN_VA(0), 0, CLUSTER_PA_SIZE / PAGE_SIZE);
232        hal_gpt_leave_range(CLUSTER_MIN_VA(0), (KERNTEXTOFF - KERNBASE) / PAGE_SIZE);
233
234        /*
235         * Do the same, but now in the local cluster map.
236         */
237        hal_gpt_maptree_area(LOCAL_CLUSTER_MIN_VA, LOCAL_CLUSTER_MIN_VA + CLUSTER_PA_SIZE);
238        hal_gpt_enter_range(LOCAL_CLUSTER_MIN_VA, 0, CLUSTER_PA_SIZE / PAGE_SIZE);
239        hal_gpt_leave_range(LOCAL_CLUSTER_MIN_VA, (KERNTEXTOFF - KERNBASE) / PAGE_SIZE);
240}
241
242/* -------------------------------------------------------------------------- */
243
244/****************************************************************************************
245 * These global variables defines the masks for the Generic Page Table Entry attributes,
246 * and must be defined in all GPT implementation.
247 ***************************************************************************************/
248
249uint32_t GPT_MAPPED;
250uint32_t GPT_SMALL;
251uint32_t GPT_READABLE;
252uint32_t GPT_WRITABLE;
253uint32_t GPT_EXECUTABLE;
254uint32_t GPT_CACHABLE;
255uint32_t GPT_USER;
256uint32_t GPT_DIRTY;
257uint32_t GPT_ACCESSED;
258uint32_t GPT_GLOBAL;
259uint32_t GPT_COW;
260uint32_t GPT_SWAP;
261uint32_t GPT_LOCKED;
262
263error_t hal_gpt_create(gpt_t *gpt)
264{
265        page_t *page;
266
267        /* check page size */
268        if (CONFIG_PPM_PAGE_SIZE != 4096) {
269                printk("\n[PANIC] in %s : For x86, the page must be 4 Kbytes\n", __FUNCTION__);
270                hal_core_sleep();
271        }
272
273        /* allocate a physical page for L4 */
274        kmem_req_t req;
275        req.type  = KMEM_PAGE;
276        req.size  = 1;
277        req.flags = AF_KERNEL | AF_ZERO;
278        page = (page_t *)kmem_alloc(&req);
279
280        if (page == NULL) {
281                printk("\n[ERROR] in %s : cannot allocate physical memory for PT1\n", __FUNCTION__);
282                return ENOMEM;
283        }
284
285        /* populate the kernel entries */
286        pt_entry_t *L4src, *L4dst;
287        extern paddr_t L4paddr; // XXX XXX smp
288        vaddr_t L4vaddr = L4paddr + KERNBASE; // XXX
289        L4src = (pt_entry_t *)L4vaddr;
290        L4dst = (pt_entry_t *)ppm_page2vaddr(page);
291        memcpy(&L4dst[256], &L4src[256], 256 * sizeof(pt_entry_t));
292        L4dst[L4_SLOT_PTE] = (ppm_page2ppn(page) >> CONFIG_PPM_PAGE_SHIFT) |
293            PG_V | PG_KW | PG_NX;
294
295        /* initialize generic page table descriptor */
296        gpt->ptr  = ppm_page2vaddr(page);
297        gpt->ppn  = ppm_page2ppn(page);
298        gpt->page = page;
299
300        /* initialize PTE entries attributes masks */
301        GPT_MAPPED     = PG_V;
302        GPT_SMALL      = 0;
303        GPT_READABLE   = PG_V;
304        GPT_WRITABLE   = PG_RW;
305        GPT_EXECUTABLE = 0;
306        GPT_CACHABLE   = 0;
307        GPT_USER       = PG_u;
308        GPT_DIRTY      = 0;
309        GPT_ACCESSED   = 0;
310        GPT_GLOBAL     = PG_G;
311        GPT_COW        = 0;
312        GPT_SWAP       = 0;
313        GPT_LOCKED     = 0;
314
315        return 0;
316}
317
318void hal_gpt_destroy( gpt_t * gpt )
319{
320        x86_panic((char *)__func__);
321}
322
323void hal_gpt_print( gpt_t * gpt )
324{
325        x86_panic((char *)__func__);
326}
327
328error_t hal_gpt_set_pte( gpt_t   * gpt,
329                         vpn_t     vpn,
330                         ppn_t     ppn,
331                         uint32_t  attr )
332{
333        x86_panic((char *)__func__);
334        return 0;
335}
336
337void hal_gpt_get_pte( gpt_t    * gpt,
338                      vpn_t      vpn,
339                      uint32_t * attr,
340                      ppn_t    * ppn )
341{
342        x86_panic((char *)__func__);
343}
344
345void hal_gpt_reset_pte( gpt_t * gpt,
346                        vpn_t   vpn )
347{
348        x86_panic((char *)__func__);
349}
350
351error_t hal_gpt_lock_pte( gpt_t * gpt,
352                          vpn_t   vpn )
353{
354        x86_panic((char *)__func__);
355        return 0;
356}
357
358error_t hal_gpt_unlock_pte( gpt_t * gpt,
359                            vpn_t   vpn )
360{
361        x86_panic((char *)__func__);
362        return 0;
363}
364
365error_t hal_gpt_copy( gpt_t  * dst_gpt,
366                      gpt_t  * src_gpt,
367                      bool_t   cow )
368{
369        x86_panic((char *)__func__);
370    return 0;
371}
372
Note: See TracBrowser for help on using the repository browser.