arm: fix caps_map_l1 for armv5 and remove panic()s in armv7
[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     // XXX: magic constant
309     const int ARM_L1_SCALE = 4;
310
311     if (slot >= 4096) {
312         printf("Error: slot = %"PRIuCSLOT"\n",slot);
313         return SYS_ERR_VNODE_SLOT_INVALID;
314     }
315
316     // check offset within frame
317     if ((offset + pte_count * 1024 > get_size(src)) ||
318             ((offset % 1024) != 0)) {
319         printf("Error: offset = %"PRIuPTR", pte_count=%"PRIuPTR
320                ", src->size = %"PRIuGENSIZE", src->type = %d\n",
321                 offset, pte_count, get_size(src), src->type);
322         return SYS_ERR_FRAME_OFFSET_INVALID;
323     }
324
325     // check mapping does not overlap leaf page table
326     if (slot + pte_count > 4096) {
327         return SYS_ERR_VM_MAP_SIZE;
328     }
329
330
331     if (slot >= ARM_L1_OFFSET(MEMORY_OFFSET)) {
332         printf("slot = %"PRIuCSLOT"\n",slot);
333         return SYS_ERR_VNODE_SLOT_RESERVED;
334     }
335
336     debug(SUBSYS_PAGING, "caps_map_l1: mapping %"PRIuPTR" L2 tables @%"PRIuCSLOT"\n",
337             pte_count, slot);
338     // Destination
339     lpaddr_t dest_lpaddr = gen_phys_to_local_phys(get_address(dest));
340     lvaddr_t dest_lvaddr = local_phys_to_mem(dest_lpaddr);
341
342     union l1_entry* entry = (union l1_entry*)dest_lvaddr + slot;
343
344     // Source
345     genpaddr_t src_gpaddr = get_address(src);
346     lpaddr_t   src_lpaddr = gen_phys_to_local_phys(src_gpaddr) + offset;
347
348     assert(aligned(src_lpaddr, 1u << 10));
349     assert((src_lpaddr < dest_lpaddr) || (src_lpaddr >= dest_lpaddr + 16384));
350
351     struct cte *src_cte = cte_for_cap(src);
352     src_cte->mapping_info.pte_count = pte_count;
353     src_cte->mapping_info.pte = dest_lpaddr + slot;
354     src_cte->mapping_info.offset = 0;
355
356     for (int i = 0; i < pte_count; i++, entry++)
357     {
358
359         entry->raw = 0;
360         entry->coarse.type   = L1_TYPE_COARSE_ENTRY;
361         entry->coarse.mb1    = 1;
362         entry->coarse.domain = 0;
363         entry->coarse.base_address =
364             (src_lpaddr + i * BASE_PAGE_SIZE / ARM_L1_SCALE) >> 10;
365         debug(SUBSYS_PAGING, "L1 mapping %"PRIuCSLOT". @%p = %08"PRIx32"\n",
366               slot + i, entry, entry->raw);
367     }
368
369     cp15_invalidate_tlb();
370
371     return SYS_ERR_OK;
372 }
373
374 static errval_t
375 caps_map_l2(struct capability* dest,
376             cslot_t            slot,
377             struct capability* src,
378             uintptr_t          kpi_paging_flags,
379             uintptr_t          offset,
380             uintptr_t          pte_count)
381 {
382     assert(0 == (kpi_paging_flags & ~KPI_PAGING_FLAGS_MASK));
383
384     // ARM L2 has 256 entries, but we treat a 4K page as a consecutive
385     // region of L2 with a single index. 4K == 4 * 1K
386     if (slot >= (256 * 4)) {
387         panic("oops");
388         return SYS_ERR_VNODE_SLOT_INVALID;
389     }
390
391     if (src->type != ObjType_Frame && src->type != ObjType_DevFrame) {
392         panic("oops");
393         return SYS_ERR_WRONG_MAPPING;
394     }
395
396     // check offset within frame
397     if ((offset + BYTES_PER_PAGE > get_size(src)) ||
398         ((offset % BYTES_PER_PAGE) != 0)) {
399         panic("oops");
400         return SYS_ERR_FRAME_OFFSET_INVALID;
401     }
402
403     // check mapping does not overlap leaf page table
404     if (slot + pte_count > (256 * 4)) {
405         return SYS_ERR_VM_MAP_SIZE;
406     }
407
408     // Destination
409     lpaddr_t dest_lpaddr = gen_phys_to_local_phys(get_address(dest));
410     lvaddr_t dest_lvaddr = local_phys_to_mem(dest_lpaddr);
411
412     union l2_entry* entry = (union l2_entry*)dest_lvaddr + slot;
413     if (entry->small_page.type != L2_TYPE_INVALID_PAGE) {
414         panic("Remapping valid page.");
415     }
416
417     lpaddr_t src_lpaddr = gen_phys_to_local_phys(get_address(src) + offset);
418     if ((src_lpaddr & (BASE_PAGE_SIZE - 1))) {
419         panic("Invalid target");
420     }
421
422     struct cte *src_cte = cte_for_cap(src);
423     src_cte->mapping_info.pte_count = pte_count;
424     src_cte->mapping_info.pte = dest_lpaddr;
425     src_cte->mapping_info.offset = offset;
426
427     for (int i = 0; i < pte_count; i++) {
428         entry->raw = 0;
429
430         entry->small_page.type = L2_TYPE_SMALL_PAGE;
431         paging_set_flags(entry, kpi_paging_flags);
432         entry->small_page.base_address = (src_lpaddr + i * BYTES_PER_PAGE) >> 12;
433
434         entry++;
435
436         debug(SUBSYS_PAGING, "L2 mapping %08"PRIxLVADDR"[%"PRIuCSLOT"] @%p = %08"PRIx32"\n",
437                dest_lvaddr, slot, entry, entry->raw);
438     }
439
440     // Flush TLB if remapping.
441     cp15_invalidate_tlb();
442
443     return SYS_ERR_OK;
444 }
445
446 /// Create page mappings
447 errval_t caps_copy_to_vnode(struct cte *dest_vnode_cte, cslot_t dest_slot,
448                             struct cte *src_cte, uintptr_t flags,
449                             uintptr_t offset, uintptr_t pte_count)
450 {
451     struct capability *src_cap  = &src_cte->cap;
452     struct capability *dest_cap = &dest_vnode_cte->cap;
453
454     if (src_cte->mapping_info.pte) {
455         return SYS_ERR_VM_ALREADY_MAPPED;
456     }
457
458
459     if (ObjType_VNode_ARM_l1 == dest_cap->type) {
460         //printf("caps_map_l1: %zu\n", (size_t)pte_count);
461         return caps_map_l1(dest_cap, dest_slot, src_cap,
462                            flags,
463                            offset,
464                            pte_count
465                           );
466     }
467     else if (ObjType_VNode_ARM_l2 == dest_cap->type) {
468         //printf("caps_map_l2: %zu\n", (size_t)pte_count);
469         return caps_map_l2(dest_cap, dest_slot, src_cap,
470                            flags,
471                            offset,
472                            pte_count
473                           );
474     }
475     else {
476         panic("ObjType not VNode");
477     }
478 }
479
480 size_t do_unmap(lvaddr_t pt, cslot_t slot, size_t num_pages)
481 {
482     size_t unmapped_pages = 0;
483     union l2_entry *ptentry = (union l2_entry *)pt + slot;
484     for (int i = 0; i < num_pages; i++) {
485         ptentry++->raw = 0;
486         unmapped_pages++;
487     }
488     return unmapped_pages;
489 }
490
491 static inline void read_pt_entry(struct capability *pgtable, size_t slot, genpaddr_t *paddr)
492 {
493     assert(type_is_vnode(pgtable->type));
494     assert(paddr);
495
496     genpaddr_t gp = get_address(pgtable);
497     lpaddr_t lp = gen_phys_to_local_phys(gp);
498     lvaddr_t lv = local_phys_to_mem(lp);
499
500     switch (pgtable->type) {
501         case ObjType_VNode_ARM_l1:
502         {
503             union l1_entry *e = (union l1_entry*)lv;
504             *paddr = (genpaddr_t)(e->coarse.base_address) << 10;
505             return;
506         }
507         case ObjType_VNode_ARM_l2:
508         {
509             union l2_entry *e = (union l2_entry*)lv;
510             *paddr = (genpaddr_t)(e->small_page.base_address) << 12;
511             return;
512         }
513         default:
514             assert(!"Should not get here");
515     }
516 }
517
518 errval_t page_mappings_unmap(struct capability *pgtable, struct cte *mapping, size_t slot, size_t num_pages)
519 {
520     assert(type_is_vnode(pgtable->type));
521     //printf("page_mappings_unmap(%zd pages, slot = %zd)\n", num_pages, slot);
522
523     // get page table entry data
524     genpaddr_t paddr;
525     //lpaddr_t pte;
526     read_pt_entry(pgtable, slot, &paddr);
527     lvaddr_t pt = local_phys_to_mem(gen_phys_to_local_phys(get_address(pgtable)));
528
529     // get virtual address of first page
530     // TODO: error checking
531     genvaddr_t vaddr;
532     struct cte *leaf_pt = cte_for_cap(pgtable);
533     compile_vaddr(leaf_pt, slot, &vaddr);
534     //genvaddr_t vend = vaddr + num_pages * BASE_PAGE_SIZE;
535     // printf("vaddr = 0x%"PRIxGENVADDR"\n", vaddr);
536     // printf("num_pages = %zu\n", num_pages);
537
538     // get cap for mapping
539     /*
540     struct cte *mem;
541     errval_t err = lookup_cap_for_mapping(paddr, pte, &mem);
542     if (err_is_fail(err)) {
543         printf("page_mappings_unmap: %ld\n", err);
544         return err;
545     }
546     */
547     //printf("state before unmap: mapped_pages = %zd\n", mem->mapping_info.mapped_pages);
548     //printf("state before unmap: num_pages    = %zd\n", num_pages);
549
550     if (num_pages != mapping->mapping_info.pte_count) {
551         printf("num_pages = %zu, mapping = %zu\n", num_pages, mapping->mapping_info.pte_count);
552         // want to unmap a different amount of pages than was mapped
553         return SYS_ERR_VM_MAP_SIZE;
554     }
555
556     do_unmap(pt, slot, num_pages);
557
558     // flush TLB for unmapped pages
559     // TODO: selective TLB flush
560     cp15_invalidate_tlb();
561
562     // update mapping info
563     memset(&mapping->mapping_info, 0, sizeof(struct mapping_info));
564
565     return SYS_ERR_OK;
566 }
567
568 errval_t paging_modify_flags(struct capability *frame, uintptr_t offset,
569                              uintptr_t pages, uintptr_t kpi_paging_flags)
570 {
571     // check flags
572     assert(0 == (kpi_paging_flags & ~KPI_PAGING_FLAGS_MASK));
573
574     struct cte *mapping = cte_for_cap(frame);
575     struct mapping_info *info = &mapping->mapping_info;
576
577     /* Calculate location of page table entries we need to modify */
578     lvaddr_t base = local_phys_to_mem(info->pte) + offset;
579
580     for (int i = 0; i < pages; i++) {
581         union l2_entry *entry =
582             (union l2_entry *)base + i;
583         paging_set_flags(entry, kpi_paging_flags);
584     }
585
586     return paging_tlb_flush_range(mapping, offset, pages);
587 }
588
589 void paging_dump_tables(struct dcb *dispatcher)
590 {
591     lvaddr_t l1 = local_phys_to_mem(dispatcher->vspace);
592
593     for (int l1_index = 0; l1_index < ARM_L1_MAX_ENTRIES; l1_index++) {
594         // get level2 table
595         union l1_entry *l2 = ((union l1_entry *)l1) + l1_index;
596         if (L1_TYPE(l2->raw) == L1_TYPE_INVALID_ENTRY) { continue; }
597
598         if (L1_TYPE(l2->raw) == L1_TYPE_SECTION_ENTRY) {
599             genpaddr_t paddr = ((genpaddr_t)l2->section.base_address) << 20u;
600             printf("%d: 0x%"PRIxGENPADDR"\n", l1_index, paddr);
601             continue;
602         }
603
604         else if (L1_TYPE(l2->raw) != L1_TYPE_COARSE_ENTRY) {
605             printf("%d: 0x%"PRIx32" -> type = %d not handled\n", l1_index, l2->raw, L1_TYPE(l2->raw));
606             continue;
607         }
608
609         genpaddr_t ptable_gp = (genpaddr_t)(l2->coarse.base_address) << 10;
610         lvaddr_t ptable_lv = local_phys_to_mem(gen_phys_to_local_phys(ptable_gp));
611
612         for (int entry = 0; entry < ARM_L2_MAX_ENTRIES; entry++) {
613             union l2_entry *e =
614                 (union l2_entry *)ptable_lv + entry;
615             genpaddr_t paddr = (genpaddr_t)(e->small_page.base_address) << BASE_PAGE_BITS;
616             if (!paddr) {
617                 continue;
618             }
619             printf("%d.%d: 0x%"PRIxGENPADDR"\n", l1_index, entry, paddr);
620         }
621     }
622 }