]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ux/kmem-ux.cpp
Update
[l4.git] / kernel / fiasco / src / kern / ux / kmem-ux.cpp
1 INTERFACE [ux]:
2
3 class Kernel_task;
4
5 EXTENSION class Kmem
6 {
7 protected:
8   static Pdir *kdir;    ///< Kernel page directory
9
10   friend class Kernel_task;
11 };
12
13 IMPLEMENTATION [ux]:
14
15 #include <cerrno>
16 #include <unistd.h>
17 #include <sys/mman.h>
18
19 #include "boot_info.h"
20 #include "kmem_alloc.h"
21 #include "emulation.h"
22
23
24 IMPLEMENT inline Mword Kmem::is_io_bitmap_page_fault(Address)
25 { return false; }
26
27 IMPLEMENT inline
28 Mword
29 Kmem::is_ipc_page_fault(Address addr, Mword error)
30 { return addr <= User_max && (error & PF_ERR_REMTADDR); }
31
32 IMPLEMENT inline NEEDS ["regdefs.h"]
33 Mword
34 Kmem::is_kmem_page_fault(Address addr, Mword error)
35 { return !(addr <= User_max && (error & PF_ERR_USERADDR)); }
36
37 /**
38  * Compute physical address from a kernel-virtual address.
39  * @param addr a virtual address
40  * @return corresponding physical address if a mappings exists.
41  *         -1 otherwise.
42  */
43 IMPLEMENT inline NEEDS["paging.h","std_macros.h"]
44 Address
45 Kmem::virt_to_phys (const void *addr)
46 {
47   Address a = reinterpret_cast<Address>(addr);
48
49   if (EXPECT_TRUE(Mem_layout::in_pmem(a)))
50     return Mem_layout::pmem_to_phys(a);
51
52   return kdir->virt_to_phys(a);
53 }
54
55 PUBLIC static inline 
56 Address Kmem::kernel_image_start()
57 { return Mem_layout::Kernel_start_frame; }
58
59 IMPLEMENT inline Address Kmem::kcode_start()
60 { return Mem_layout::Kernel_start_frame; }
61
62 IMPLEMENT inline Address Kmem::kcode_end()
63 { return Mem_layout::Kernel_end_frame; }
64
65 PUBLIC static FIASCO_INIT
66 void
67 Kmem::init_mmu(Cpu const &boot_cpu)
68 {
69   Kmem_alloc *const alloc = Kmem_alloc::allocator();
70
71   kdir = (Pdir*)alloc->alloc(Config::PAGE_SHIFT);
72   memset (kdir, 0, Config::PAGE_SIZE);
73
74   Pt_entry::have_superpages(boot_cpu.superpages());
75   if (boot_cpu.features() & FEAT_PGE)
76     Pt_entry::enable_global();
77
78   // set up the kernel mapping for physical memory.  mark all pages as
79   // referenced and modified (so when touching the respective pages
80   // later, we save the CPU overhead of marking the pd/pt entries like
81   // this)
82
83   // we also set up a one-to-one virt-to-phys mapping for two reasons:
84   // (1) so that we switch to the new page table early and re-use the
85   // segment descriptors set up by bootstrap.c.  (we'll set up our own
86   // descriptors later.)  (2) a one-to-one phys-to-virt mapping in the
87   // kernel's page directory sometimes comes in handy
88   kdir->map(0, Virt_addr(Mem_layout::Physmem), Virt_size(Mem_layout::pmem_size),
89             Pt_entry::Writable | Pt_entry::Referenced | Pt_entry::global(),
90             Pt_entry::super_level(), false, pdir_alloc(alloc));
91
92   // now switch to our new page table
93   Emulation::set_pdir_addr (Mem_layout::pmem_to_phys (kdir));
94
95   // map the cpu_page we allocated earlier just before io_bitmap
96   assert((Mem_layout::Io_bitmap & ~Config::SUPERPAGE_MASK) == 0);
97
98   if (boot_cpu.superpages()
99       && Config::SUPERPAGE_SIZE - (pmem_cpu_page & ~Config::SUPERPAGE_MASK) < 0x10000)
100     {
101       // can map as 4MB page because the cpu_page will land within a
102       // 16-bit range from io_bitmap
103       kdir->walk(Virt_addr(Mem_layout::Io_bitmap - Config::SUPERPAGE_SIZE),
104                  Pdir::Super_level, false, pdir_alloc(alloc)).
105         set_page(pmem_cpu_page & Config::SUPERPAGE_MASK,
106                  Pt_entry::Pse_bit
107                  | Pt_entry::Writable | Pt_entry::Referenced
108                  | Pt_entry::Dirty | Pt_entry::global());
109
110       cpu_page_vm = (pmem_cpu_page & ~Config::SUPERPAGE_MASK)
111                     + (Mem_layout::Io_bitmap - Config::SUPERPAGE_SIZE);
112     }
113   else
114     {
115       auto pt = kdir->walk(Virt_addr(Mem_layout::Io_bitmap - Config::PAGE_SIZE),
116                            Pdir::Depth, false, pdir_alloc(alloc));
117
118       pt.set_page(pmem_cpu_page,
119                   Pt_entry::Writable
120                   | Pt_entry::Referenced | Pt_entry::Dirty
121                   | Pt_entry::global());
122
123       cpu_page_vm = Mem_layout::Io_bitmap - Config::PAGE_SIZE;
124     }
125
126   if (mmap ((void *) cpu_page_vm, Config::PAGE_SIZE, PROT_READ 
127             | PROT_WRITE, MAP_SHARED | MAP_FIXED, Boot_info::fd(), pmem_cpu_page)
128       == MAP_FAILED)
129     printf ("CPU page mapping failed: %s\n", strerror (errno));
130
131   Cpu::init_tss (alloc_tss(sizeof(Tss)));
132
133 }
134