]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/plr/server/src/fault_handlers/pagefault.cc
update
[l4.git] / l4 / pkg / plr / server / src / fault_handlers / pagefault.cc
1 /*
2  * pagefault.cc --
3  *
4  *     Implementation of page fault handling.
5  *
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.
11  */
12
13 #include "../constants.h"
14 #include "../log"
15 #include "../exceptions"
16 #include "../memory"
17 #include "../emulation"
18 #include "../app_loading"
19 #include "../locking.h"
20 #include "../configuration"
21 #include "syscalls_handler.h"
22
23 #include "observers.h"
24
25 #include <l4/sys/kdebug.h>
26 #include <l4/util/bitops.h>
27
28 extern l4_addr_t __libc_l4_gettime;
29
30 static int pf_write  = 0; // statistical counter
31 static int pf_mapped = 0; // statistical counter
32 static int pf_kip    = 0; // statistical counter
33
34 #define MSG() DEBUGf(Romain::Log::Memory) << "[" << i->id() << "] "
35 #define MSGt(t) DEBUGf(Romain::Log::Faults) << "[" << t->vcpu() << "] "
36
37 /*****************************************************************
38  *                  Page Fault Handling                          *
39  *****************************************************************/
40 DEFINE_EMPTY_STARTUP(PageFaultObserver)
41
42 void Romain::PageFaultObserver::status() const
43 {
44         INFO() << "Page faults so far: mapped " << pf_mapped << " write emu "
45                << pf_write << " kip " << pf_kip;
46 }
47
48 Romain::Observer::ObserverReturnVal
49 Romain::PageFaultObserver::notify(Romain::App_instance *i, Romain::App_thread *t,
50                                   Romain::Thread_group* tg, Romain::App_model *a)
51 {
52         if (!t->vcpu()->is_page_fault_entry())
53                 return Romain::Observer::Ignored;
54
55         if (t->unhandled_pf()) {
56                 enter_kdebug("unhandled pf");
57         }
58
59         L4vcpu::Vcpu *vcpu = t->vcpu();
60
61         bool write_pf = vcpu->r()->err & 0x2;
62         l4_addr_t pfa = vcpu->r()->pfa;
63
64         Measurements::GenericEvent *ev = Romain::_the_instance_manager->logbuf()->next();
65         ev->header.tsc         = Romain::_the_instance_manager->logbuf()->getTime(Log::logLocalTSC);
66         ev->header.vcpu        = (l4_uint32_t)t->vcpu();
67         ev->header.type        = Measurements::Pagefault;
68         ev->data.pf.address    = pfa;
69         ev->data.pf.rw         = write_pf ? 1 : 0;
70         ev->data.pf.localbase  = 0;
71         ev->data.pf.remotebase = 0;
72
73         MSGt(t) << (write_pf ? "\033[31mwrite\033[0m" : "\033[34;1mread\033[0m")
74               << " page fault @ 0x" << std::hex << pfa;
75
76         Romain::Region_map::Base::Node n = a->rm()->find(pfa);
77         MSGt(t) << "rm_find(" << std::hex << pfa << ") = " << n;
78         if (n) {
79                 a->rm()->lazy_map_region(n, i->id());
80
81                 /*
82                  * Lazily establish region handlers for replicas
83                  */
84                 MSGt(t) << "[" << std::hex
85                         << n->second.local_region(i->id()).start() << " - "
86                         << n->second.local_region(i->id()).end() << "] ==> "
87                         << "[" << n->first.start() << " - "
88                         << n->first.end() << "]";
89                 MSGt(t) << "   DS " << std::hex <<  n->second.memory(i->id()).cap();
90
91                 if (write_pf && (always_readonly() ||
92                                 (n->second.writable() == Romain::Region_handler::Read_only_emulate_write))) {
93                         ++pf_write;
94                         /* XXX: can we use a static object here instead? */
95                         AppModelAddressTranslator *aat = new AppModelAddressTranslator(a, i);
96                         Romain::WriteEmulator(vcpu, aat).emulate();
97                         delete aat;
98                         // writes are emulated, no need to map here at all
99                         // -> XXX actually, we could also map() here, because if the client
100                         //        writes to memory, it's most probably going to read this
101                         //        data at a later point in time, too
102
103                         /*
104                          * For emulated operations single-stepping won't work, because
105                          * the real instruction is never executed in the target AS. Therefore,
106                          * we need to inject a "virtual" INT1 into the manager here.
107                          */
108                         if (t->vcpu()->r()->flags & TrapFlag)
109                                 t->set_pending_trap(1);
110                 } else {
111                         ++pf_mapped;
112
113                         l4_addr_t offset_in_region = l4_trunc_page(pfa - n->first.start());
114                         MSGt(t) << "offs in region: " << std::hex << offset_in_region;
115                         
116                         // set flags properly, only check ro(), because else we'd already ended
117                         // up in the emulation branch above
118                         unsigned pageflags           = n->second.is_ro() ? L4_FPAGE_RO : L4_FPAGE_RW;
119                         unsigned map_size            = L4_PAGESIZE;
120                         unsigned size_left_in_region = n->first.end() - (n->first.start() + offset_in_region);
121
122 #if 0
123 #define MAX_MAP_SHIFT 0
124                         for (unsigned x = 1; x < MAX_MAP_SHIFT; ++x) {
125                                 if (size_left_in_region >= (1 << (L4_PAGESHIFT + x)))
126                                         map_size *= 2;
127                         }
128 #undef MAX_MAP_SHIFT
129 #endif
130                         ev->data.pf.localbase  = n->second.local_region(i->id()).start() + offset_in_region;
131                         ev->data.pf.remotebase = n->first.start() + offset_in_region;
132
133                         i->map(n->second.local_region(i->id()).start() + offset_in_region, // local addr
134                                    n->first.start() + offset_in_region,                        // remote addr
135                                    pageflags, map_size);
136                 }
137
138         } else if ((a->prog_info()->kip <= pfa) && (pfa < a->prog_info()->kip + L4_PAGESIZE)) {
139             ++pf_kip;
140             MSGt(t) << "KIP access ";
141             /* XXX ??? */
142                 MSGt(t) << std::hex << __libc_l4_gettime << " " <<  *(l4_addr_t*)__libc_l4_gettime;
143             t->set_unhandled_pf();
144         } else {
145                 ERROR() << "Unhandled page fault @ address 0x" << std::hex << pfa
146                         << " PC @ 0x" << vcpu->r()->ip;
147                 t->set_unhandled_pf();
148         }
149
150         /*
151          * XXX: For now, tell the manager to let all instances perform their fault handling
152          *      independently. In fact, we could however also handle all faults upon first
153          *      occurrence and return Replicatable here.
154          */
155         MSGt(t) << "Page faults so far: mapped " << pf_mapped << " write emu " << pf_write << " kip " << pf_kip;
156
157         return Romain::Observer::Finished;
158 }
159
160
161 Romain::PageFaultObserver::PageFaultObserver()
162 {
163         char const *ro = ConfigStringValue("general:page_fault_handling");
164
165         if (ro && (strcmp(ro, "ro") == 0)) {
166                 _readonly = true;
167         } else {
168                 _readonly = false;
169         }
170 }