4 * Implementation of page fault handling.
6 * (c) 2011-2012 Björn Döbel <doebel@os.inf.tu-dresden.de>,
7 * economic rights: Technische Universität Dresden (Germany)
8 * This file is part of TUD:OS and distributed under the terms of the
9 * GNU General Public License 2.
10 * Please see the COPYING-GPL-2 file for details.
13 #include "../constants.h"
15 #include "../exceptions"
17 #include "../emulation"
18 #include "../app_loading"
19 #include "../locking.h"
20 #include "../configuration"
22 #include "observers.h"
24 #include <l4/sys/kdebug.h>
25 #include <l4/util/bitops.h>
27 extern l4_addr_t __libc_l4_gettime;
29 static int pf_write = 0; // statistical counter
30 static int pf_mapped = 0; // statistical counter
31 static int pf_kip = 0; // statistical counter
33 #define MSG() DEBUGf(Romain::Log::Memory) << "[" << i->id() << "] "
34 #define MSGt(t) DEBUGf(Romain::Log::Faults) << "[" << t->vcpu() << "] "
36 /*****************************************************************
37 * Page Fault Handling *
38 *****************************************************************/
39 DEFINE_EMPTY_STARTUP(PageFaultObserver)
41 void Romain::PageFaultObserver::status() const
43 INFO() << "Page faults so far: mapped " << pf_mapped << " write emu "
44 << pf_write << " kip " << pf_kip;
47 Romain::Observer::ObserverReturnVal
48 Romain::PageFaultObserver::notify(Romain::App_instance *i, Romain::App_thread *t,
49 Romain::Thread_group* tg, Romain::App_model *a)
51 if (!t->vcpu()->is_page_fault_entry())
52 return Romain::Observer::Ignored;
54 if (t->unhandled_pf()) {
55 enter_kdebug("unhandled pf");
58 L4vcpu::Vcpu *vcpu = t->vcpu();
60 bool write_pf = vcpu->r()->err & 0x2;
61 l4_addr_t pfa = vcpu->r()->pfa;
63 MSGt(t) << (write_pf ? "\033[31mwrite\033[0m" : "\033[34;1mread\033[0m")
64 << " page fault @ 0x" << std::hex << pfa;
66 Romain::Region_map::Base::Node n = a->rm()->find(pfa);
67 MSGt(t) << "rm_find(" << std::hex << pfa << ") = " << n;
69 a->rm()->lazy_map_region(n, i->id());
72 * Lazily establish region handlers for replicas
74 MSGt(t) << "[" << std::hex
75 << n->second.local_region(i->id()).start() << " - "
76 << n->second.local_region(i->id()).end() << "] ==> "
77 << "[" << n->first.start() << " - "
78 << n->first.end() << "]";
79 MSGt(t) << " DS " << std::hex << n->second.memory(i->id()).cap();
81 if (write_pf && (always_readonly() ||
82 (n->second.writable() == Romain::Region_handler::Read_only_emulate_write))) {
84 /* XXX: can we use a static object here instead? */
85 AppModelAddressTranslator *aat = new AppModelAddressTranslator(a, i);
86 Romain::WriteEmulator(vcpu, aat).emulate();
88 // writes are emulated, no need to map here at all
89 // -> XXX actually, we could also map() here, because if the client
90 // writes to memory, it's most probably going to read this
91 // data at a later point in time, too
94 * For emulated operations single-stepping won't work, because
95 * the real instruction is never executed in the target AS. Therefore,
96 * we need to inject a "virtual" INT1 into the manager here.
98 if (t->vcpu()->r()->flags & TrapFlag)
99 t->set_pending_trap(1);
103 l4_addr_t offset_in_region = l4_trunc_page(pfa - n->first.start());
104 MSGt(t) << "offs in region: " << std::hex << offset_in_region;
106 // set flags properly, only check ro(), because else we'd already ended
107 // up in the emulation branch above
108 unsigned pageflags = n->second.is_ro() ? L4_FPAGE_RO : L4_FPAGE_RW;
109 unsigned map_size = L4_PAGESIZE;
110 unsigned size_left_in_region = n->first.end() - (n->first.start() + offset_in_region);
113 #define MAX_MAP_SHIFT 0
114 for (unsigned x = 1; x < MAX_MAP_SHIFT; ++x) {
115 if (size_left_in_region >= (1 << (L4_PAGESHIFT + x)))
121 i->map(n->second.local_region(i->id()).start() + offset_in_region, // local addr
122 n->first.start() + offset_in_region, // remote addr
123 pageflags, map_size);
126 } else if ((a->prog_info()->kip <= pfa) && (pfa < a->prog_info()->kip + L4_PAGESIZE)) {
128 MSGt(t) << "KIP access ";
130 MSGt(t) << std::hex << __libc_l4_gettime << " " << *(l4_addr_t*)__libc_l4_gettime;
131 t->set_unhandled_pf();
133 ERROR() << "Unhandled page fault @ address 0x" << std::hex << pfa
134 << " PC @ 0x" << vcpu->r()->ip;
135 t->set_unhandled_pf();
139 * XXX: For now, tell the manager to let all instances perform their fault handling
140 * independently. In fact, we could however also handle all faults upon first
141 * occurrence and return Replicatable here.
143 MSGt(t) << "Page faults so far: mapped " << pf_mapped << " write emu " << pf_write << " kip " << pf_kip;
145 return Romain::Observer::Finished;
149 Romain::PageFaultObserver::PageFaultObserver()
151 char const *ro = ConfigStringValue("general:page_fault_handling");
153 if (ro && (strcmp(ro, "ro") == 0)) {