02a848cb544d8698ab71b1a551c5cc27449dfbda
[barrelfish] / kernel / arch / armv5 / paging.c
1 /*
2  * Copyright (c) 2009 ETH Zurich.
3  * All rights reserved.
4  *
5  * This file is distributed under the terms in the attached LICENSE file.
6  * If you do not find this file, copies can be found by writing to:
7  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8  */
9
10 #include <kernel.h>
11 #include <dispatch.h>
12 #include <cp15.h>
13 #include <paging_kernel_arch.h>
14 #include <string.h>
15 #include <cap_predicates.h>
16
17 // ------------------------------------------------------------------------
18 // Internal declarations
19
20 union l1_entry {
21     uint32_t raw;
22
23     /// Invalid L1 entry
24     struct {
25         uint32_t        type            :2;     // == 0
26     } invalid;
27
28     /// L1 entry for 256 4K L2 entries
29     struct {
30         uint32_t        type            :2;     // == 1
31         uint32_t        sbz0            :2;     // Should-be-zero
32         uint32_t        mb1             :1;     // Must-be-one
33         uint32_t        domain          :4;
34         uint32_t        sbz1            :1;     // Should-be-zero
35         uint32_t        base_address    :22;
36     } coarse;
37
38     /// L1 entry for 1MB mapped section
39     struct {
40         uint32_t        type            :2;     // == 2
41         uint32_t        bufferable      :1;
42         uint32_t        cacheable       :1;
43         uint32_t        mb1             :1;     // Must-be-One
44         uint32_t        domain          :4;
45         uint32_t        sbz0            :1;
46         uint32_t        ap              :2;
47         uint32_t        sbz1            :8;
48         uint32_t        base_address    :12;
49     } section;
50
51     /// L1 entry for 1024 1K L2 descriptors
52     struct {
53         uint32_t        type            :2;     // == 3
54         uint32_t        sbz0            :2;
55         uint32_t        mb1             :1;
56         uint32_t        domain          :4;
57         uint32_t        sbz1            :3;
58         uint32_t        base_address    :20;
59     } fine;
60 };
61
62 STATIC_ASSERT_SIZEOF(union l1_entry, 4);
63
64 #define L1_TYPE_INVALID_ENTRY   0
65 #define L1_TYPE_COARSE_ENTRY    1
66 #define L1_TYPE_SECTION_ENTRY   2
67 #define L1_TYPE_FINE_ENTRY      3
68 #define L1_TYPE(x)              ((x) & 3)
69
70 union l2_entry {
71     uint32_t raw;
72
73     /// Invalid L2 entry
74     struct {
75         uint32_t        type            :2;     // == 0
76     } invalid;
77
78     /// Descriptior for a 64K page
79     struct {
80         uint32_t        type            :2;     // == 1
81         uint32_t        bufferable      :1;
82         uint32_t        cacheable       :1;
83         uint32_t        ap0             :2;
84         uint32_t        ap1             :2;
85         uint32_t        ap2             :2;
86         uint32_t        ap3             :2;
87         uint32_t        sbz             :4;
88         uint32_t        base_address    :16;
89     } large_page;
90
91     /// Descriptor for a 4K page
92     struct {
93         uint32_t        type            :2;     // == 2
94         uint32_t        bufferable      :1;
95         uint32_t        cacheable       :1;
96         uint32_t        ap0             :2;
97         uint32_t        ap1             :2;
98         uint32_t        ap2             :2;
99         uint32_t        ap3             :2;
100         uint32_t        base_address    :20;
101     } small_page;
102
103     /// Descriptor for a 1K page
104     struct {
105         uint32_t        type            :2;     // == 3
106         uint32_t        bufferable      :1;
107         uint32_t        cacheable       :1;
108         uint32_t        ap              :2;
109         uint32_t        sbz             :4;
110         uint32_t        base_address    :22;
111     } tiny_page;
112 };
113
114 STATIC_ASSERT_SIZEOF(union l2_entry, 4);
115
116 #define L2_TYPE_INVALID_PAGE    0
117 #define L2_TYPE_LARGE_PAGE      1
118 #define L2_TYPE_SMALL_PAGE      2
119 #define L2_TYPE_TINY_PAGE       3
120 #define L2_TYPE(x)              ((x) & 3)
121
122 #define BYTES_PER_SECTION       0x100000
123 #define BYTES_PER_PAGE          0x1000
124 #define BYTES_PER_SMALL_PAGE    0x400
125
126 // ------------------------------------------------------------------------
127 // Utility declarations
128
129 inline static uintptr_t paging_round_down(uintptr_t address, uintptr_t size)
130 {
131     return address & ~(size - 1);
132 }
133
134 inline static uintptr_t paging_round_up(uintptr_t address, uintptr_t size)
135 {
136     return (address + size - 1) & ~(size - 1);
137 }
138
139 inline static int aligned(uintptr_t address, uintptr_t bytes)
140 {
141     return (address & (bytes - 1)) == 0;
142 }
143
144 // ------------------------------------------------------------------------
145 // Exported functions
146
147 static void
148 paging_write_section_entry(uintptr_t ttbase, lvaddr_t va, union l1_entry l1)
149 {
150     union l1_entry *l1_table;
151     if (ttbase == 0) {
152         ttbase = cp15_read_ttbr() + KERNEL_OFFSET;
153     }
154     l1_table = (union l1_entry *) ttbase;
155     l1_table[va >> 20u] = l1;
156 }
157
158 void paging_map_kernel_section(uintptr_t ttbase, lvaddr_t va, lpaddr_t pa)
159 {
160
161     union l1_entry l1;
162
163     l1.raw = 0;
164     l1.section.type = L1_TYPE_SECTION_ENTRY;
165     l1.section.bufferable   = 1;
166     l1.section.cacheable    = 1;
167     l1.section.ap           = 1;
168     l1.section.base_address = pa >> 20u;
169
170     paging_write_section_entry(ttbase, va, l1);
171 }
172
173 void paging_map_memory(uintptr_t ttbase, lpaddr_t paddr, size_t bytes)
174 {
175     lpaddr_t pend  = paging_round_up(paddr + bytes, BYTES_PER_SECTION);
176     while (paddr < pend) {
177         paging_map_kernel_section(0, paddr + MEMORY_OFFSET, paddr);
178         paddr += BYTES_PER_SECTION;
179     }
180 }
181
182 static void
183 paging_map_device_section(uintptr_t ttbase, lvaddr_t va, lpaddr_t pa)
184 {
185     union l1_entry l1;
186
187     l1.raw = 0;
188     l1.section.type = L1_TYPE_SECTION_ENTRY;
189     l1.section.bufferable   = 0;
190     l1.section.cacheable    = 0;
191     l1.section.ap           = 1;
192     l1.section.base_address = pa >> 20u;
193
194     paging_write_section_entry(ttbase, va, l1);
195 }
196
197 lvaddr_t paging_map_device(lpaddr_t device_base, size_t device_bytes)
198 {
199     // HACK to put device in high memory.
200     // Should likely track these allocations.
201     static lvaddr_t dev_alloc = KERNEL_OFFSET;
202     assert(device_bytes <= BYTES_PER_SECTION);
203     dev_alloc -= BYTES_PER_SECTION;
204
205     paging_map_device_section(0, dev_alloc, device_base);
206
207     return dev_alloc;
208 }
209
210 void paging_make_good(lvaddr_t new_table_base, size_t new_table_bytes)
211 {
212     assert(new_table_base >= MEMORY_OFFSET);
213     assert(new_table_bytes == ARM_L1_ALIGN);
214     assert(aligned(new_table_base, ARM_L1_ALIGN));
215
216     lvaddr_t ttbr = local_phys_to_mem(cp15_read_ttbr());
217     size_t st = (MEMORY_OFFSET / ARM_L1_SECTION_BYTES) * ARM_L1_BYTES_PER_ENTRY;
218
219     // Copy kernel pages (everything from MEMORY_OFFSET upwards)
220     memcpy((void*)new_table_base + st, (void*)ttbr + st,
221            ARM_L1_MAX_ENTRIES * ARM_L1_BYTES_PER_ENTRY - st);
222 }
223
224 void paging_map_user_pages_l1(lvaddr_t table_base, lvaddr_t va, lpaddr_t pa)
225 {
226     assert(aligned(table_base, ARM_L1_ALIGN));
227     assert(aligned(va, BYTES_PER_SECTION));
228     assert(aligned(pa, BYTES_PER_SMALL_PAGE));
229
230     union l1_entry e;
231
232     e.raw                 = 0;
233     e.coarse.type         = L1_TYPE_COARSE_ENTRY;
234     e.coarse.mb1          = 1;
235     e.coarse.domain       = 0;
236     e.coarse.base_address = (pa >> 10);
237
238     union l1_entry *l1table = (union l1_entry*)table_base;
239     l1table[va / BYTES_PER_SECTION] = e;
240 }
241
242 void paging_set_l2_entry(uintptr_t* l2e, lpaddr_t addr, uintptr_t flags)
243 {
244     assert(0 == (flags & 0xfffff000));
245     assert(0 == (flags & 0x3));
246     assert(0 == (addr & 0xfff));
247
248     union l2_entry e;
249     e.raw = flags;
250     assert(e.small_page.ap0 == e.small_page.ap1 &&
251            e.small_page.ap0 == e.small_page.ap2 &&
252            e.small_page.ap0 == e.small_page.ap3);
253
254     e.small_page.type = L2_TYPE_SMALL_PAGE;
255     e.small_page.base_address = (addr >> 12);
256
257     *l2e = e.raw;
258 }
259
260 void paging_context_switch(lpaddr_t ttbr)
261 {
262     assert(ttbr < MEMORY_OFFSET);
263     assert((ttbr & 0x3fff) == 0);
264
265     lpaddr_t old_ttbr = cp15_read_ttbr();
266     if (ttbr != old_ttbr)
267     {
268         cp15_write_ttbr(ttbr);
269         cp15_invalidate_tlb();
270         cp15_invalidate_i_and_d_caches();
271     }
272 }
273
274 static void
275 paging_set_flags(union l2_entry *entry, uintptr_t kpi_paging_flags)
276 {
277     entry->small_page.bufferable = 1;
278     entry->small_page.cacheable =
279         (kpi_paging_flags & KPI_PAGING_FLAGS_NOCACHE) ? 0 : 1;
280
281     entry->small_page.ap0  =
282         (kpi_paging_flags & KPI_PAGING_FLAGS_READ)  ? 2 : 0;
283     entry->small_page.ap0 |=
284         (kpi_paging_flags & KPI_PAGING_FLAGS_WRITE) ? 3 : 0;
285     entry->small_page.ap1 = entry->small_page.ap0;
286     entry->small_page.ap2 = entry->small_page.ap0;
287     entry->small_page.ap3 = entry->small_page.ap0;
288 }
289
290 static errval_t
291 caps_map_l1(struct capability* dest,
292             cslot_t            slot,
293             struct capability* src,
294             uintptr_t          kpi_paging_flags,
295             uintptr_t          offset,
296             uintptr_t          pte_count)
297 {
298     //
299     // Note:
300     //
301     // We have chicken-and-egg problem in initializing resources so
302     // instead of treating an L2 table it's actual 1K size, we treat
303     // it as being 4K. As a result when we map an "L2" table we actually
304     // map a page of memory as if it is 4 consecutive L2 tables.
305     //
306     // See lib/barrelfish/arch/arm/pmap_arch.c for more discussion.
307     //
308     const int ARM_L1_SCALE = 4;
309
310     if (slot >= 1024) {
311         printf("slot = %"PRIuCSLOT"\n",slot);
312         panic("oops: slot id >= 1024");
313         return SYS_ERR_VNODE_SLOT_INVALID;
314     }
315
316     if (pte_count != 1) {
317         printf("pte_count = %zu\n",(size_t)pte_count);
318         panic("oops: pte_count");
319         return SYS_ERR_VM_MAP_SIZE;
320     }
321
322     if (src->type != ObjType_VNode_ARM_l2) {
323         panic("oops: wrong src type");
324         return SYS_ERR_WRONG_MAPPING;
325     }
326
327     if (slot >= ARM_L1_OFFSET(MEMORY_OFFSET) / ARM_L1_SCALE) {
328         printf("slot = %"PRIuCSLOT"\n",slot);
329         panic("oops: slot id");
330         return SYS_ERR_VNODE_SLOT_RESERVED;
331     }
332
333     // Destination
334     lpaddr_t dest_lpaddr = gen_phys_to_local_phys(get_address(dest));
335     lvaddr_t dest_lvaddr = local_phys_to_mem(dest_lpaddr);
336
337     union l1_entry* entry = (union l1_entry*)dest_lvaddr + (slot * ARM_L1_SCALE);
338
339     // Source
340     genpaddr_t src_gpaddr = get_address(src);
341     lpaddr_t   src_lpaddr = gen_phys_to_local_phys(src_gpaddr);
342
343     assert(offset == 0);
344     assert(aligned(src_lpaddr, 1u << 10));
345     assert((src_lpaddr < dest_lpaddr) || (src_lpaddr >= dest_lpaddr + 16384));
346
347     struct cte *src_cte = cte_for_cap(src);
348     src_cte->mapping_info.pte_count = pte_count;
349     src_cte->mapping_info.pte = dest_lpaddr + (slot * ARM_L1_SCALE);
350     src_cte->mapping_info.offset = 0;
351
352     for (int i = 0; i < 4; i++, entry++)
353     {
354         entry->raw = 0;
355         entry->coarse.type   = L1_TYPE_COARSE_ENTRY;
356         entry->coarse.mb1    = 1;
357         entry->coarse.domain = 0;
358         entry->coarse.base_address =
359             (src_lpaddr + i * BASE_PAGE_SIZE / ARM_L1_SCALE) >> 10;
360         debug(SUBSYS_PAGING, "L1 mapping %"PRIuCSLOT". @%p = %08"PRIx32"\n",
361               slot * ARM_L1_SCALE + i, entry, entry->raw);
362     }
363
364     cp15_invalidate_tlb();
365
366     return SYS_ERR_OK;
367 }
368
369 static errval_t
370 caps_map_l2(struct capability* dest,
371             cslot_t            slot,
372             struct capability* src,
373             uintptr_t          kpi_paging_flags,
374             uintptr_t          offset,
375             uintptr_t          pte_count)
376 {
377     assert(0 == (kpi_paging_flags & ~KPI_PAGING_FLAGS_MASK));
378
379     // ARM L2 has 256 entries, but we treat a 4K page as a consecutive
380     // region of L2 with a single index. 4K == 4 * 1K
381     if (slot >= (256 * 4)) {
382         panic("oops");
383         return SYS_ERR_VNODE_SLOT_INVALID;
384     }
385
386     if (src->type != ObjType_Frame && src->type != ObjType_DevFrame) {
387         panic("oops");
388         return SYS_ERR_WRONG_MAPPING;
389     }
390
391     // check offset within frame
392     if ((offset + BYTES_PER_PAGE > get_size(src)) ||
393         ((offset % BYTES_PER_PAGE) != 0)) {
394         panic("oops");
395         return SYS_ERR_FRAME_OFFSET_INVALID;
396     }
397
398     // check mapping does not overlap leaf page table
399     if (slot + pte_count > (256 * 4)) {
400         return SYS_ERR_VM_MAP_SIZE;
401     }
402
403     // Destination
404     lpaddr_t dest_lpaddr = gen_phys_to_local_phys(get_address(dest));
405     lvaddr_t dest_lvaddr = local_phys_to_mem(dest_lpaddr);
406
407     union l2_entry* entry = (union l2_entry*)dest_lvaddr + slot;
408     if (entry->small_page.type != L2_TYPE_INVALID_PAGE) {
409         panic("Remapping valid page.");
410     }
411
412     lpaddr_t src_lpaddr = gen_phys_to_local_phys(get_address(src) + offset);
413     if ((src_lpaddr & (BASE_PAGE_SIZE - 1))) {
414         panic("Invalid target");
415     }
416
417     struct cte *src_cte = cte_for_cap(src);
418     src_cte->mapping_info.pte_count = pte_count;
419     src_cte->mapping_info.pte = dest_lpaddr;
420     src_cte->mapping_info.offset = offset;
421
422     for (int i = 0; i < pte_count; i++) {
423         entry->raw = 0;
424
425         entry->small_page.type = L2_TYPE_SMALL_PAGE;
426         paging_set_flags(entry, kpi_paging_flags);
427         entry->small_page.base_address = (src_lpaddr + i * BYTES_PER_PAGE) >> 12;
428
429         entry++;
430
431         debug(SUBSYS_PAGING, "L2 mapping %08"PRIxLVADDR"[%"PRIuCSLOT"] @%p = %08"PRIx32"\n",
432                dest_lvaddr, slot, entry, entry->raw);
433     }
434
435     // Flush TLB if remapping.
436     cp15_invalidate_tlb();
437
438     return SYS_ERR_OK;
439 }
440
441 /// Create page mappings
442 errval_t caps_copy_to_vnode(struct cte *dest_vnode_cte, cslot_t dest_slot,
443                             struct cte *src_cte, uintptr_t flags,
444                             uintptr_t offset, uintptr_t pte_count)
445 {
446     struct capability *src_cap  = &src_cte->cap;
447     struct capability *dest_cap = &dest_vnode_cte->cap;
448
449     if (src_cte->mapping_info.pte) {
450         return SYS_ERR_VM_ALREADY_MAPPED;
451     }
452
453
454     if (ObjType_VNode_ARM_l1 == dest_cap->type) {
455         //printf("caps_map_l1: %zu\n", (size_t)pte_count);
456         return caps_map_l1(dest_cap, dest_slot, src_cap,
457                            flags,
458                            offset,
459                            pte_count
460                           );
461     }
462     else if (ObjType_VNode_ARM_l2 == dest_cap->type) {
463         //printf("caps_map_l2: %zu\n", (size_t)pte_count);
464         return caps_map_l2(dest_cap, dest_slot, src_cap,
465                            flags,
466                            offset,
467                            pte_count
468                           );
469     }
470     else {
471         panic("ObjType not VNode");
472     }
473 }
474
475 size_t do_unmap(lvaddr_t pt, cslot_t slot, size_t num_pages)
476 {
477     size_t unmapped_pages = 0;
478     union l2_entry *ptentry = (union l2_entry *)pt + slot;
479     for (int i = 0; i < num_pages; i++) {
480         ptentry++->raw = 0;
481         unmapped_pages++;
482     }
483     return unmapped_pages;
484 }
485
486 static inline void read_pt_entry(struct capability *pgtable, size_t slot, genpaddr_t *paddr)
487 {
488     assert(type_is_vnode(pgtable->type));
489     assert(paddr);
490
491     genpaddr_t gp = get_address(pgtable);
492     lpaddr_t lp = gen_phys_to_local_phys(gp);
493     lvaddr_t lv = local_phys_to_mem(lp);
494
495     switch (pgtable->type) {
496         case ObjType_VNode_ARM_l1:
497         {
498             union l1_entry *e = (union l1_entry*)lv;
499             *paddr = (genpaddr_t)(e->coarse.base_address) << 10;
500             return;
501         }
502         case ObjType_VNode_ARM_l2:
503         {
504             union l2_entry *e = (union l2_entry*)lv;
505             *paddr = (genpaddr_t)(e->small_page.base_address) << 12;
506             return;
507         }
508         default:
509             assert(!"Should not get here");
510     }
511 }
512
513 errval_t page_mappings_unmap(struct capability *pgtable, struct cte *mapping, size_t slot, size_t num_pages)
514 {
515     assert(type_is_vnode(pgtable->type));
516     //printf("page_mappings_unmap(%zd pages, slot = %zd)\n", num_pages, slot);
517
518     // get page table entry data
519     genpaddr_t paddr;
520     //lpaddr_t pte;
521     read_pt_entry(pgtable, slot, &paddr);
522     lvaddr_t pt = local_phys_to_mem(gen_phys_to_local_phys(get_address(pgtable)));
523
524     // get virtual address of first page
525     // TODO: error checking
526     genvaddr_t vaddr;
527     struct cte *leaf_pt = cte_for_cap(pgtable);
528     compile_vaddr(leaf_pt, slot, &vaddr);
529     //genvaddr_t vend = vaddr + num_pages * BASE_PAGE_SIZE;
530     // printf("vaddr = 0x%"PRIxGENVADDR"\n", vaddr);
531     // printf("num_pages = %zu\n", num_pages);
532
533     // get cap for mapping
534     /*
535     struct cte *mem;
536     errval_t err = lookup_cap_for_mapping(paddr, pte, &mem);
537     if (err_is_fail(err)) {
538         printf("page_mappings_unmap: %ld\n", err);
539         return err;
540     }
541     */
542     //printf("state before unmap: mapped_pages = %zd\n", mem->mapping_info.mapped_pages);
543     //printf("state before unmap: num_pages    = %zd\n", num_pages);
544
545     if (num_pages != mapping->mapping_info.pte_count) {
546         printf("num_pages = %zu, mapping = %zu\n", num_pages, mapping->mapping_info.pte_count);
547         // want to unmap a different amount of pages than was mapped
548         return SYS_ERR_VM_MAP_SIZE;
549     }
550
551     do_unmap(pt, slot, num_pages);
552
553     // flush TLB for unmapped pages
554     // TODO: selective TLB flush
555     cp15_invalidate_tlb();
556
557     // update mapping info
558     memset(&mapping->mapping_info, 0, sizeof(struct mapping_info));
559
560     return SYS_ERR_OK;
561 }
562
563 errval_t paging_modify_flags(struct capability *frame, uintptr_t offset,
564                              uintptr_t pages, uintptr_t kpi_paging_flags)
565 {
566     // check flags
567     assert(0 == (kpi_paging_flags & ~KPI_PAGING_FLAGS_MASK));
568
569     struct cte *mapping = cte_for_cap(frame);
570     struct mapping_info *info = &mapping->mapping_info;
571
572     /* Calculate location of page table entries we need to modify */
573     lvaddr_t base = local_phys_to_mem(info->pte) + offset;
574
575     for (int i = 0; i < pages; i++) {
576         union l2_entry *entry =
577             (union l2_entry *)base + i;
578         paging_set_flags(entry, kpi_paging_flags);
579     }
580
581     return paging_tlb_flush_range(mapping, offset, pages);
582 }
583
584 void paging_dump_tables(struct dcb *dispatcher)
585 {
586     lvaddr_t l1 = local_phys_to_mem(dispatcher->vspace);
587
588     for (int l1_index = 0; l1_index < ARM_L1_MAX_ENTRIES; l1_index++) {
589         // get level2 table
590         union l1_entry *l2 = ((union l1_entry *)l1) + l1_index;
591         if (L1_TYPE(l2->raw) == L1_TYPE_INVALID_ENTRY) { continue; }
592
593         if (L1_TYPE(l2->raw) == L1_TYPE_SECTION_ENTRY) {
594             genpaddr_t paddr = ((genpaddr_t)l2->section.base_address) << 20u;
595             printf("%d: 0x%"PRIxGENPADDR"\n", l1_index, paddr);
596             continue;
597         }
598
599         else if (L1_TYPE(l2->raw) != L1_TYPE_COARSE_ENTRY) {
600             printf("%d: 0x%"PRIx32" -> type = %d not handled\n", l1_index, l2->raw, L1_TYPE(l2->raw));
601             continue;
602         }
603
604         genpaddr_t ptable_gp = (genpaddr_t)(l2->coarse.base_address) << 10;
605         lvaddr_t ptable_lv = local_phys_to_mem(gen_phys_to_local_phys(ptable_gp));
606
607         for (int entry = 0; entry < ARM_L2_MAX_ENTRIES; entry++) {
608             union l2_entry *e =
609                 (union l2_entry *)ptable_lv + entry;
610             genpaddr_t paddr = (genpaddr_t)(e->small_page.base_address) << BASE_PAGE_BITS;
611             if (!paddr) {
612                 continue;
613             }
614             printf("%d.%d: 0x%"PRIxGENPADDR"\n", l1_index, entry, paddr);
615         }
616     }
617 }