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

Last change on this file since 484 was 482, checked in by viala@…, 6 years ago

[hal/x86_64] Add void type to function prototypes with no parameter

File size: 10.7 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_kernel_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( void )
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        hal_gpt_leave_range(CLUSTER_MIN_VA(0), (KERNTEXTOFF - KERNBASE) / PAGE_SIZE);
71
72        va_avail = CLUSTER_MIN_VA(0) + KERNEL_VA_SIZE;
73}
74
75/*
76 * Uniformize the PA and VA offsets, and return the value. After this function,
77 * we are guaranteed to have [VA = PA + constant_offset]. And therefore we can
78 * only call hal_gpt_bootstrap_valloc, without entering it in a PA.
79 */
80size_t hal_gpt_bootstrap_uniformize( void )
81{
82        size_t pa_offset = pa_avail - 0;
83        size_t va_offset = va_avail - CLUSTER_MIN_VA(0);
84
85        if (pa_offset < va_offset)
86                pa_avail += (va_offset - pa_offset);
87        else if (pa_offset > va_offset)
88                va_avail += (pa_offset - va_offset);
89
90        return MAX(pa_offset, va_offset);
91}
92
93void hal_gpt_enter(vaddr_t va, paddr_t pa, pt_entry_t flags)
94{
95        XASSERT(va % PAGE_SIZE == 0);
96        XASSERT(pa % PAGE_SIZE == 0);
97        //XASSERT(va == tmpva || PTE_BASE[pl1_i(va)] == 0);
98        PTE_BASE[pl1_i(va)] = (pa & PG_FRAME) | flags;
99        invlpg(va);
100}
101
102void hal_gpt_enter_range(vaddr_t va, paddr_t pa, size_t n)
103{
104        pt_entry_t flags = PG_V | PG_KW | PG_NX;
105        size_t i;
106        for (i = 0; i < n; i++) {
107                hal_gpt_enter(va + i * PAGE_SIZE, pa + i * PAGE_SIZE, flags);
108        }
109}
110
111void hal_gpt_leave(vaddr_t va)
112{
113        XASSERT(va % PAGE_SIZE == 0);
114        XASSERT(PTE_BASE[pl1_i(va)] != 0);
115        PTE_BASE[pl1_i(va)] = 0;
116        invlpg(va);
117}
118
119void hal_gpt_leave_range(vaddr_t va, size_t n)
120{
121        size_t i;
122        for (i = 0; i < n; i++) {
123                hal_gpt_leave(va + i * PAGE_SIZE);
124        }
125}
126
127/*
128 * Create a page tree that can map va_start->va_end. The caller can then
129 * enter these addresses to physical locations.
130 *
131 * This function is a bit complicated, and may need to be revisited.
132 */
133void hal_gpt_maptree_area(vaddr_t va_start, vaddr_t va_end)
134{
135        pt_entry_t flags = PG_V | PG_KW | PG_NX;
136        size_t L4start, L4end, nL4e;
137        size_t L3start, L3end, nL3e;
138        size_t L2start, L2end, nL2e;
139        paddr_t L3page, L2page, L1page;
140        paddr_t pa;
141        size_t i, npa;
142        pt_entry_t *pde;
143
144        /* Allocate L3 */
145        L4start = pl4_i(va_start);
146        L4end = pl4_i(va_end);
147        nL4e = (L4end - L4start + 1);
148        L3page = hal_gpt_bootstrap_palloc(nL4e);
149
150        /* Allocate L2 */
151        L3start = pl3_i(va_start);
152        L3end = pl3_i(va_end);
153        nL3e = (L3end - L3start + 1);
154        L2page = hal_gpt_bootstrap_palloc(nL3e);
155
156        /* Allocate L1 */
157        L2start = pl2_i(va_start);
158        L2end = pl2_i(va_end);
159        nL2e = (L2end - L2start + 1);
160        L1page = hal_gpt_bootstrap_palloc(nL2e);
161
162        /* Zero out L1 */
163        for (i = 0; i < nL2e; i++) {
164                pa = L1page + i * PAGE_SIZE;
165                hal_gpt_enter(tmpva, pa, flags);
166
167                memset((void *)tmpva, 0, PAGE_SIZE);
168        }
169
170        /* Zero out L2 */
171        for (i = 0; i < nL3e; i++) {
172                pa = L2page + i * PAGE_SIZE;
173                hal_gpt_enter(tmpva, pa, flags);
174
175                memset((void *)tmpva, 0, PAGE_SIZE);
176        }
177
178        /* Zero out L3 */
179        for (i = 0; i < nL4e; i++) {
180                pa = L3page + i * PAGE_SIZE;
181                hal_gpt_enter(tmpva, pa, flags);
182
183                memset((void *)tmpva, 0, PAGE_SIZE);
184        }
185
186        /* Create L2, linked to L1 */
187        npa = (L2start / NPDPG) * PAGE_SIZE;
188        for (i = L2start; i <= L2end; i++) {
189                pa = (paddr_t)&(((pt_entry_t *)L2page)[i]);
190                pa -= npa;      /* shift on the left */
191                pa &= PG_FRAME; /* rounddown to a page boundary */
192                hal_gpt_enter(tmpva, pa, flags);
193
194                pde = (pt_entry_t *)tmpva;
195                pa = L1page + (i - L2start) * PAGE_SIZE;
196                pde[i % NPDPG] = (pa & PG_FRAME) | PG_V | PG_KW;
197        }
198
199        /* Create L3, linked to L2 */
200        npa = (L3start / NPDPG) * PAGE_SIZE;
201        for (i = L3start; i <= L3end; i++) {
202                pa = (paddr_t)&(((pt_entry_t *)L3page)[i]);
203                pa -= npa;      /* shift on the left */
204                pa &= PG_FRAME; /* rounddown to a page boundary */
205                hal_gpt_enter(tmpva, pa, flags);
206
207                pde = (pt_entry_t *)tmpva;
208                pa = L2page + (i - L3start) * PAGE_SIZE;
209                pde[i % NPDPG] = (pa & PG_FRAME) | PG_V | PG_KW;
210        }
211
212        /* Link L3 into L4 */
213        for (i = 0; i < nL4e; i++) {
214                pa = L3page + i * PAGE_SIZE;
215                L4_BASE[L4start + i] = (pa & PG_FRAME) | PG_V | PG_KW;
216        }
217}
218
219void hal_gpt_init(paddr_t firstpa)
220{
221        /* Initialize global values */
222        pa_avail = firstpa;
223        va_avail = CLUSTER_MIN_VA(0) + KERNEL_VA_SIZE;
224        kimg_size = ((uint64_t)&__kernel_end - KERNBASE);
225        XASSERT(kimg_size % PAGE_SIZE == 0);
226
227        /*
228         * Create cluster0's page tree, enter the space, and unmap the area
229         * below the kernel.
230         */
231        hal_gpt_maptree_area(CLUSTER_MIN_VA(0), CLUSTER_MIN_VA(0) + CLUSTER_PA_SIZE);
232        hal_gpt_enter_range(CLUSTER_MIN_VA(0), 0, CLUSTER_PA_SIZE / PAGE_SIZE);
233        hal_gpt_leave_range(CLUSTER_MIN_VA(0), (KERNTEXTOFF - KERNBASE) / PAGE_SIZE);
234}
235
236/* -------------------------------------------------------------------------- */
237
238static uint32_t hal_gpt_pte_to_attr(pt_entry_t *pte)
239{
240        uint32_t attr = 0;
241
242        if (*pte & PG_V)
243                attr |= (GPT_MAPPED | GPT_READABLE);
244        if (*pte & PG_RW)
245                attr |= GPT_WRITABLE;
246        if (!(*pte & PG_NX))
247                attr |= GPT_EXECUTABLE;
248        if (*pte & PG_u)
249                attr |= GPT_USER;
250        if (!(*pte & PG_PS))
251                attr |= GPT_SMALL;
252
253        return attr;
254}
255
256static pt_entry_t hal_gpt_attr_to_pte(uint32_t attr)
257{
258        pt_entry_t pte = 0;
259
260        if (attr & GPT_MAPPED)
261                pte |= PG_V;
262        if (attr & GPT_WRITABLE)
263                pte |= PG_RW;
264        if (!(attr & GPT_EXECUTABLE))
265                pte |= PG_NX;
266        if (attr & GPT_USER)
267                pte |= PG_u;
268
269        return pte;
270}
271
272error_t hal_gpt_create(gpt_t *gpt)
273{
274        page_t *page;
275        xptr_t page_xp;
276
277        /* check page size */
278        if (CONFIG_PPM_PAGE_SIZE != 4096) {
279                panic("for x86, the page must be 4 Kbytes");
280        }
281
282        /* allocate a physical page for L4 */
283        kmem_req_t req;
284        req.type  = KMEM_PAGE;
285        req.size  = 1;
286        req.flags = AF_KERNEL | AF_ZERO;
287        page = (page_t *)kmem_alloc(&req);
288
289        if (page == NULL) {
290                printk("\n[ERROR] in %s : cannot allocate physical memory for PT1\n", __FUNCTION__);
291                return ENOMEM;
292        }
293
294        page_xp = XPTR(local_cxy, page);
295
296        /* populate the kernel entries */
297        pt_entry_t *L4src, *L4dst;
298        extern paddr_t L4paddr; // XXX XXX smp
299        vaddr_t L4vaddr = L4paddr + KERNBASE; // XXX
300        L4src = (pt_entry_t *)L4vaddr;
301        L4dst = (pt_entry_t *)ppm_page2base(page_xp);
302        memcpy(&L4dst[256], &L4src[256], 256 * sizeof(pt_entry_t));
303        L4dst[L4_SLOT_PTE] = (ppm_page2ppn(page_xp) << CONFIG_PPM_PAGE_SHIFT) |
304            PG_V | PG_KW | PG_NX;
305
306        /* initialize generic page table descriptor */
307        gpt->ptr  = GET_PTR(ppm_page2base(page_xp));
308        gpt->ppn  = ppm_page2ppn(page_xp);
309        gpt->page = GET_PTR(page_xp);
310
311        return 0;
312}
313
314void hal_gpt_destroy( gpt_t * gpt )
315{
316        x86_panic((char *)__func__);
317}
318
319void hal_gpt_print( gpt_t * gpt , pid_t pid )
320{
321        x86_panic((char *)__func__);
322}
323
324error_t hal_gpt_set_pte(gpt_t *gpt, vpn_t vpn, uint32_t attr, ppn_t ppn)
325{
326        vaddr_t va = vpn << CONFIG_PPM_PAGE_SHIFT;
327        paddr_t pa;
328        kmem_req_t req;
329        page_t *page;
330        xptr_t page_xp;
331
332        req.type  = KMEM_PAGE;
333        req.size  = 0;
334        req.flags = AF_KERNEL | AF_ZERO;
335
336        if (!(attr & GPT_MAPPED))
337                x86_panic("hal_gpt_set_pte: unmapped!");
338        if (!(attr & GPT_USER))
339                x86_panic("hal_gpt_set_pte: kernel!");
340        if (!(attr & GPT_SMALL))
341                x86_panic("hal_gpt_set_pte: large!");
342
343        if (!(L4_BASE[pl4_i(va)] & PG_V)) {
344                /* if L4 is not present, create it */
345                page = (page_t *)kmem_alloc(&req);
346                if (page == NULL) {
347                        x86_panic("out of memory in hal_gpt_set_pte (L4)!");
348                        return ENOMEM;
349                }
350
351                page_xp = XPTR(local_cxy, page);       
352                pa = (paddr_t)PADDR(local_cxy, ppm_page2base(page_xp));
353
354                L4_BASE[pl4_i(va)] = pa | PG_V | PG_u | PG_RW;
355
356        }
357
358        if (!(L3_BASE[pl3_i(va)] & PG_V)) {
359                /* if L3 is not present, create it */
360                page = (page_t *)kmem_alloc(&req);
361                if (page == NULL) {
362                        x86_panic("out of memory in hal_gpt_set_pte (L3)!");
363                        return ENOMEM;
364                }
365
366                page_xp = XPTR(local_cxy, page);       
367                pa = (paddr_t)PADDR(local_cxy, ppm_page2base(page_xp));
368
369                L3_BASE[pl3_i(va)] = pa | PG_V | PG_u | PG_RW;
370        }
371
372        if (!(L2_BASE[pl2_i(va)] & PG_V)) {
373                /* if L2 is not present, create it */
374                page = (page_t *)kmem_alloc(&req);
375                if (page == NULL) {
376                        x86_panic("out of memory in hal_gpt_set_pte (L2)!");
377                        return ENOMEM;
378                }
379
380                page_xp = XPTR(local_cxy, page);       
381                pa = (paddr_t)PADDR(local_cxy, ppm_page2base(page_xp));
382
383                L2_BASE[pl2_i(va)] = pa | PG_V | PG_u | PG_RW;
384        }
385
386        pa = ppn << CONFIG_PPM_PAGE_SHIFT;
387        L1_BASE[pl1_i(va)] = pa | hal_gpt_attr_to_pte(attr);
388
389        return 0;
390}
391
392void hal_gpt_get_pte(gpt_t *gpt, vpn_t vpn, uint32_t *attr, ppn_t *ppn)
393{
394        vaddr_t va = vpn << CONFIG_PPM_PAGE_SHIFT;
395
396        *attr = 0;
397        if (!(L4_BASE[pl4_i(va)] & PG_V)) {
398                return;
399        }
400        if (!(L3_BASE[pl3_i(va)] & PG_V)) {
401                return;
402        }
403        if (!(L2_BASE[pl2_i(va)] & PG_V)) {
404                return;
405        }
406
407        if (L2_BASE[pl2_i(va)] & PG_PS) {
408                /* large page */
409                *attr = hal_gpt_pte_to_attr(&L2_BASE[pl2_i(va)]);
410                *ppn = (L2_BASE[pl2_i(va)] & PG_2MFRAME) >> CONFIG_PPM_PAGE_SHIFT;
411        } else {
412                /* small page */
413                *attr = hal_gpt_pte_to_attr(&L1_BASE[pl1_i(va)]);
414                *ppn = (L1_BASE[pl1_i(va)] & PG_FRAME) >> CONFIG_PPM_PAGE_SHIFT;
415        }
416
417        x86_panic((char *)__func__);
418}
419
420void hal_gpt_reset_pte( gpt_t * gpt,
421                        vpn_t   vpn )
422{
423        x86_panic((char *)__func__);
424}
425
426error_t hal_gpt_lock_pte( gpt_t * gpt,
427                          vpn_t   vpn )
428{
429        x86_panic((char *)__func__);
430        return 0;
431}
432
433error_t hal_gpt_unlock_pte( gpt_t * gpt,
434                            vpn_t   vpn )
435{
436        x86_panic((char *)__func__);
437        return 0;
438}
439
440error_t hal_gpt_copy( gpt_t  * dst_gpt,
441                      gpt_t  * src_gpt,
442                      bool_t   cow )
443{
444        x86_panic((char *)__func__);
445    return 0;
446}
447
Note: See TracBrowser for help on using the repository browser.