]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ux/emulation.cpp
update
[l4.git] / kernel / fiasco / src / kern / ux / emulation.cpp
1 /*
2  * Fiasco-UX
3  * Emulation Code for some processor internals (registers, instructions)
4  */
5
6 INTERFACE:
7
8 #include <types.h>
9 #include "mem_layout.h"
10
11 class Idt_entry;
12
13 struct Ldt_user_desc                    // work around glibc naming mess
14 {
15   unsigned int  entry_number;
16   unsigned long base_addr;
17   unsigned int  limit;
18   unsigned int  seg_32bit:1;
19   unsigned int  contents:2;
20   unsigned int  read_exec_only:1;
21   unsigned int  limit_in_pages:1;
22   unsigned int  seg_not_present:1;
23   unsigned int  useable:1;
24 };
25
26 class Pseudo_descriptor;
27
28 class Emulation
29 {
30 private:
31   static Address        _page_dir_addr          asm ("PAGE_DIR_ADDR");
32   static Address        _page_fault_addr        asm ("PAGE_FAULT_ADDR");
33   static Idt_entry const *_idt_base;
34   static unsigned short _idt_limit;
35   static unsigned       _host_tls_base;
36 };
37
38 IMPLEMENTATION:
39
40 #include <cassert>
41 #include <asm/unistd.h>
42 #include <sched.h>
43 #include "x86desc.h"
44
45 Address         Emulation::_page_dir_addr;
46 Address         Emulation::_page_fault_addr;
47 Idt_entry const *Emulation::_idt_base;
48 unsigned short  Emulation::_idt_limit;
49 unsigned        Emulation::_host_tls_base;
50
51 /**
52  * Return page directory base address (register cr3)
53  * @return Page Directory Base Address
54  */
55 PUBLIC static inline
56 Address
57 Emulation::pdir_addr()
58 {
59   return _page_dir_addr;
60 }
61
62 /**
63  * Set page directory base address (register cr3)
64  * @param addr New Page Directory Base Address
65  */
66 PUBLIC static inline
67 void
68 Emulation::set_pdir_addr (Address addr)
69 {
70   _page_dir_addr = addr;
71 }
72
73 /**
74  * Set page fault address (register cr2)
75  * @param addr Page Fault Address
76  */
77 PUBLIC static inline
78 void
79 Emulation::set_page_fault_addr (Address addr)
80 {
81   _page_fault_addr = addr;
82 }
83
84 /**
85  * Emulate LIDT instruction
86  * @param desc IDT pseudo descriptor
87  */
88 PUBLIC static inline NEEDS["x86desc.h"]
89 void
90 Emulation::lidt (Pseudo_descriptor *desc)
91 {
92   _idt_base  = reinterpret_cast<Idt_entry const *>(desc->base());
93   _idt_limit = desc->limit();
94 }
95
96 /**
97  * Emulate SIDT instruction
98  * @param desc IDT pseudo descriptor
99  */
100 PUBLIC static inline NEEDS["x86desc.h"]
101 void
102 Emulation::sidt (Pseudo_descriptor *desc)
103 {
104   *desc = Pseudo_descriptor((Address)_idt_base, _idt_limit);
105 }
106
107 PUBLIC static inline NEEDS["x86desc.h"]
108 Mword
109 Emulation::idt_vector (Mword trap, bool user)
110 {
111   Idt_entry const *gate = _idt_base + trap;
112
113   // IDT limit check
114   if (gate >= (_idt_base + _idt_limit))
115     return 0;
116
117   // Gate permission check
118   if (user && !(gate->access() & X86desc::Access_user))
119     return 0;
120
121   assert(gate->present());
122
123   return gate->offset();
124 }
125
126 PUBLIC static inline NEEDS["x86desc.h"]
127 bool
128 Emulation::idt_vector_present (Mword vector)
129 {
130   Idt_entry const *gate = _idt_base + vector;
131
132   if (gate >= (_idt_base + _idt_limit))
133     return false;
134
135   return gate->present();
136 }
137
138 PUBLIC static inline
139 Mword
140 Emulation::kernel_cs()
141 {
142   unsigned short cs;
143   asm volatile ("movw %%cs, %0" : "=g" (cs));
144   return cs;
145 }
146
147 PUBLIC static inline
148 Mword
149 Emulation::kernel_ss()
150 {
151   unsigned short ss;
152   asm volatile ("movw %%ss, %0" : "=g" (ss));
153   return ss;
154 }
155
156 PUBLIC static inline NEEDS [<asm/unistd.h>]
157 void
158 Emulation::modify_ldt (unsigned entry, unsigned long base_addr, unsigned limit)
159 {
160   Ldt_user_desc ldt;
161
162   ldt.entry_number    = entry;
163   ldt.base_addr       = base_addr;
164   ldt.limit           = limit;
165   ldt.seg_32bit       = 1;
166   ldt.contents        = 0;
167   ldt.read_exec_only  = 0;
168   ldt.limit_in_pages  = 0;
169   ldt.seg_not_present = 0;
170   ldt.useable         = 1;
171
172   asm volatile ("int $0x80" : : "a" (__NR_modify_ldt),
173                                 "b" (1),
174                                 "c" (&ldt), "m" (ldt),
175                                 "d" (sizeof (ldt)));
176 }
177
178 PUBLIC static
179 void
180 Emulation::set_host_tls_base(unsigned b)
181 {
182   _host_tls_base = b;
183 }
184
185 PUBLIC static inline
186 unsigned
187 Emulation::host_tls_base()
188 { return _host_tls_base; }
189
190 PUBLIC static inline
191 int
192 Emulation::get_thread_area(Ldt_user_desc *desc, unsigned entry_number)
193 {
194   int result;
195   desc->entry_number = entry_number;
196
197 #ifndef __NR_get_thread_area
198 #define __NR_get_thread_area 244
199 #endif
200   asm volatile ("int $0x80" : "=a" (result)
201                             : "0" (__NR_get_thread_area),
202                               "b" (desc), "m" (*desc));
203
204   if (EXPECT_FALSE(result == -38)) // -ENOSYS
205     printf("Your kernel does not support the get/set_thread_area system calls!\n"
206            "The requested feature will not work.\n");
207   return result;
208 }
209
210 PUBLIC static inline NEEDS [<asm/unistd.h>, <cassert>]
211 void
212 Emulation::thread_area_host (unsigned entry)
213 {
214   Ldt_user_desc desc;
215   int result;
216   enum { NUM_TLS = 3 };
217   static int called[NUM_TLS];
218
219 #ifndef __NR_set_thread_area
220 #define __NR_set_thread_area 243
221 #endif
222
223   assert(_host_tls_base <= entry && entry < (_host_tls_base + NUM_TLS));
224
225   if (called[entry - _host_tls_base])
226     return;
227
228   called[entry - _host_tls_base] = 1;
229
230   result = get_thread_area(&desc, entry);
231   assert(!result);
232
233   if (!desc.base_addr || !desc.limit)
234     {
235       desc.base_addr       = 2;
236       desc.limit           = 3;
237       desc.seg_32bit       = 1;
238       desc.contents        = 0;
239       desc.read_exec_only  = 0;
240       desc.limit_in_pages  = 0;
241       desc.seg_not_present = 0;
242       desc.useable         = 1;
243     }
244
245   asm volatile ("int $0x80" : "=a" (result)
246                             : "0" (__NR_set_thread_area),
247                               "b" (&desc), "m" (desc));
248
249   assert(!result);
250 }
251
252 // ------------------------------------------------------------------------
253 IMPLEMENTATION[ux && mp]:
254
255 PUBLIC static inline
256 int
257 Emulation::gettid()
258 {
259   int tid;
260   asm volatile("int $0x80" : "=a" (tid) : "0" (__NR_gettid) : "memory");
261   return tid;
262 }
263
264 PUBLIC static
265 int
266 Emulation::spawn_cpu_thread(Address ip)
267 {
268   int result;
269
270   asm volatile ("int $0x80         \t\n"
271                 "cmp $0, %%eax     \t\n"
272                 "jne 1f            \t\n"
273                 "jmp *%[ip]        \t\n"
274                 "1:                \t\n"
275                 : "=a" (result)
276                 : "0" (__NR_clone),
277                   "b" (CLONE_VM | CLONE_FILES),
278                   "c" (0),
279                   "d" (0),
280                   "D" (0),
281                   [ip] "r" (ip)
282                 : "memory");
283
284   assert(result > 0);
285   return result;
286 }