8 static Pdir *kdir; ///< Kernel page directory
10 friend class Kernel_task;
19 #include "boot_info.h"
20 #include "kmem_alloc.h"
21 #include "emulation.h"
24 IMPLEMENT inline Mword Kmem::is_io_bitmap_page_fault(Address)
29 Kmem::is_ipc_page_fault(Address addr, Mword error)
30 { return addr <= User_max && (error & PF_ERR_REMTADDR); }
32 IMPLEMENT inline NEEDS ["regdefs.h"]
34 Kmem::is_kmem_page_fault(Address addr, Mword error)
35 { return !(addr <= User_max && (error & PF_ERR_USERADDR)); }
38 * Compute physical address from a kernel-virtual address.
39 * @param addr a virtual address
40 * @return corresponding physical address if a mappings exists.
43 IMPLEMENT inline NEEDS["paging.h","std_macros.h"]
45 Kmem::virt_to_phys (const void *addr)
47 Address a = reinterpret_cast<Address>(addr);
49 if (EXPECT_TRUE(Mem_layout::in_pmem(a)))
50 return Mem_layout::pmem_to_phys(a);
52 return kdir->virt_to_phys(a);
56 Address Kmem::kernel_image_start()
57 { return Mem_layout::Kernel_start_frame; }
59 IMPLEMENT inline Address Kmem::kcode_start()
60 { return Mem_layout::Kernel_start_frame; }
62 IMPLEMENT inline Address Kmem::kcode_end()
63 { return Mem_layout::Kernel_end_frame; }
65 PUBLIC static FIASCO_INIT
67 Kmem::init_mmu(Cpu const &boot_cpu)
69 Kmem_alloc *const alloc = Kmem_alloc::allocator();
71 kdir = (Pdir*)alloc->alloc(Config::PAGE_SHIFT);
72 memset (kdir, 0, Config::PAGE_SIZE);
74 Pt_entry::have_superpages(boot_cpu.superpages());
75 if (boot_cpu.features() & FEAT_PGE)
76 Pt_entry::enable_global();
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
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));
92 // now switch to our new page table
93 Emulation::set_pdir_addr (Mem_layout::pmem_to_phys (kdir));
95 // map the cpu_page we allocated earlier just before io_bitmap
96 assert((Mem_layout::Io_bitmap & ~Config::SUPERPAGE_MASK) == 0);
98 if (boot_cpu.superpages()
99 && Config::SUPERPAGE_SIZE - (pmem_cpu_page & ~Config::SUPERPAGE_MASK) < 0x10000)
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,
107 | Pt_entry::Writable | Pt_entry::Referenced
108 | Pt_entry::Dirty | Pt_entry::global());
110 cpu_page_vm = (pmem_cpu_page & ~Config::SUPERPAGE_MASK)
111 + (Mem_layout::Io_bitmap - Config::SUPERPAGE_SIZE);
115 auto pt = kdir->walk(Virt_addr(Mem_layout::Io_bitmap - Config::PAGE_SIZE),
116 Pdir::Depth, false, pdir_alloc(alloc));
118 pt.set_page(pmem_cpu_page,
120 | Pt_entry::Referenced | Pt_entry::Dirty
121 | Pt_entry::global());
123 cpu_page_vm = Mem_layout::Io_bitmap - Config::PAGE_SIZE;
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)
129 printf ("CPU page mapping failed: %s\n", strerror (errno));
131 Cpu::init_tss (alloc_tss(sizeof(Tss)));