]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/examples/sys/vcpu/vcpu.cc
update
[l4.git] / l4 / pkg / examples / sys / vcpu / vcpu.cc
1 /*
2  * (c) 2009 Technische Universität Dresden
3  * This file is part of TUD:OS, which is distributed under the terms of the
4  * GNU General Public License 2. Please see the COPYING file for details.
5  */
6 #include <l4/sys/ipc.h>
7 #include <l4/sys/thread>
8 #include <l4/sys/factory>
9 #include <l4/sys/scheduler>
10 #include <l4/sys/utcb.h>
11 #include <l4/sys/kdebug.h>
12 #include <l4/util/util.h>
13 #include <l4/re/env>
14 #include <l4/re/util/cap_alloc>
15 #include <l4/sys/debugger.h>
16 #include <l4/vcpu/vcpu>
17
18 #include <l4/re/error_helper>
19
20 #include <l4/sys/task>
21 #include <l4/sys/irq>
22 #include <l4/sys/vcpu.h>
23
24 #include <cstdlib>
25 #include <cstdio>
26 #include <cstring>
27
28
29 using L4Re::chksys;
30 using L4Re::chkcap;
31
32 static L4::Cap<L4::Irq> irq;
33
34 static char thread_stack[8 << 10];
35 static char hdl_stack[8 << 10];
36
37 static L4::Cap<L4::Task> vcpu_task;
38 static L4vcpu::Vcpu *vcpu;
39
40 const l4_addr_t super_code_map_addr = 0x10000;
41 extern char my_super_code[];
42 extern char my_super_code_excp[];
43 extern char my_super_code_excp_after[];
44
45 #if defined(ARCH_x86) || defined(ARCH_amd64)
46
47 static unsigned long gs;
48 static unsigned long ds;
49
50 asm
51 (
52   ".p2align 12                      \t\n"
53   ".global my_super_code            \t\n"
54   ".global my_super_code_excp       \t\n"
55   ".global my_super_code_excp_after \t\n"
56   "my_super_code:                   \t\n"
57   "1: add $4, %eax                  \t\n"
58   "   add $4, %eax                  \t\n"
59   "   add $4, %eax                  \t\n"
60   "   add $4, %eax                  \t\n"
61   "   add $4, %eax                  \t\n"
62   "   add $4, %eax                  \t\n"
63   "   add $4, %eax                  \t\n"
64   "   add $4, %eax                  \t\n"
65   "   add $4, %eax                  \t\n"
66   "   add $4, %eax                  \t\n"
67   "   add $4, %eax                  \t\n"
68   "   add $4, %eax                  \t\n"
69   "   add $4, %eax                  \t\n"
70   "my_super_code_excp:              \t\n"
71   "   ud2a                          \t\n"
72   "my_super_code_excp_after:        \t\n"
73   "   add $4, %eax                  \t\n"
74   "   add $4, %eax                  \t\n"
75   "   add $4, %eax                  \t\n"
76   "   add $4, %eax                  \t\n"
77   "   jmp 1b                        \t\n"
78   );
79
80
81 static void setup_user_state_arch(L4vcpu::Vcpu *v)
82 {
83   asm volatile ("mov %%gs, %0" : "=r"(gs));
84   asm volatile ("mov %%ds, %0" : "=r"(ds));
85 #ifndef __amd64__
86   v->r()->gs = ds;
87   v->r()->fs = ds;
88   v->r()->es = ds;
89   v->r()->ds = ds;
90 #endif
91   v->r()->ss = ds;
92 }
93
94 static void handler_prolog()
95 {
96   asm volatile ("mov %0, %%es \t\n"
97                 "mov %0, %%ds \t\n"
98                 "mov %1, %%gs \t\n"
99                 : : "r"(ds), "r"(gs));
100 }
101
102 #elif defined(ARCH_arm)
103 asm
104 (
105   ".p2align 12                      \t\n"
106   ".global my_super_code            \t\n"
107   ".global my_super_code_excp       \t\n"
108   ".global my_super_code_excp_after \t\n"
109   "my_super_code:                   \t\n"
110   "1: add r0, r0, #4                \t\n"
111   "   add r0, r0, #4                \t\n"
112   "   add r0, r0, #4                \t\n"
113   "   add r0, r0, #4                \t\n"
114   "   add r0, r0, #4                \t\n"
115   "   add r0, r0, #4                \t\n"
116   "   add r0, r0, #4                \t\n"
117   "   add r0, r0, #4               \t\n"
118   "my_super_code_excp:              \t\n"
119   "   swi 0                         \t\n"
120   "my_super_code_excp_after:        \t\n"
121   "   mrc 8, 0, r0, cr7, cr14       \t\n"
122   "   add r0, r0, #4                \t\n"
123   "   add r0, r0, #4                \t\n"
124   "   add r0, r0, #4                \t\n"
125   "   b 1b                          \t\n"
126   );
127
128
129 static void setup_user_state_arch(L4vcpu::Vcpu *) { }
130 static void handler_prolog() {}
131
132 #elif defined(ARCH_ppc32)
133 asm
134 (
135   ".p2align 12                      \t\n"
136   ".global my_super_code            \t\n"
137   ".global my_super_code_excp       \t\n"
138   ".global my_super_code_excp_after \t\n"
139   "my_super_code:                   \t\n"
140   "1: addi %r4, %r4, 4              \t\n"
141   "   addi %r4, %r4, 4              \t\n"
142   "   addi %r4, %r4, 4              \t\n"
143   "my_super_code_excp:              \t\n"
144   "   trap                          \t\n"
145   "my_super_code_excp_after:        \t\n"
146   "   addi %r4, %r4, 4              \t\n"
147   "   addi %r4, %r4, 4              \t\n"
148   "   addi %r4, %r4, 4              \t\n"
149   "   b 1b                          \t\n"
150   );
151 static void setup_user_state_arch(L4vcpu::Vcpu *) { }
152 static void handler_prolog() {}
153 #else
154 #error Add your architecture.
155 #endif
156
157
158 static void handler(void)
159 {
160   handler_prolog();
161
162   vcpu->state()->clear(L4_VCPU_F_EXCEPTIONS);
163
164   if (0)
165     vcpu->print_state();
166
167   // very simple page-fault hanlding
168   // we're just replying with the only page we have, without checking any
169   // values
170   if (vcpu->is_page_fault_entry())
171     {
172       vcpu_task->map(L4Re::This_task, l4_fpage((l4_addr_t)my_super_code,
173                                                L4_PAGESHIFT, L4_FPAGE_RWX),
174                                                super_code_map_addr);
175       vcpu->saved_state()->add(L4_VCPU_F_PAGE_FAULTS);
176     }
177   else if (vcpu->is_irq_entry())
178     {
179       // We use the label 2000 for our IRQ
180       if (vcpu->i()->label == 2000)
181         printf("Our triggered IRQ\n");
182       else if (vcpu->i()->label == 0)
183         // direct IPC message to vCPU without
184         // going through an IPCgate, label is set to 0
185         printf("IPC: %lx\n", vcpu->i()->tag.label());
186       else
187         printf("Unclassifiable message\n");
188     }
189   else
190   // we should also check the exception number here
191     if (vcpu->r()->ip == (l4_addr_t)my_super_code_excp - (l4_addr_t)my_super_code + super_code_map_addr)
192       vcpu->r()->ip += my_super_code_excp_after - my_super_code_excp;
193
194   //printf("resume\n");
195   L4::Cap<L4::Thread> self;
196   self->vcpu_resume_commit(self->vcpu_resume_start());
197   while(1)
198     ;
199 }
200
201 static void vcpu_thread(void)
202 {
203   printf("Hello vCPU\n");
204
205   memset(hdl_stack, 0, sizeof(hdl_stack));
206
207   setup_user_state_arch(vcpu);
208   vcpu->saved_state()->set(L4_VCPU_F_USER_MODE
209                            | L4_VCPU_F_EXCEPTIONS
210                            | L4_VCPU_F_PAGE_FAULTS
211                            | L4_VCPU_F_IRQ);
212   vcpu->r()->ip = super_code_map_addr;
213   vcpu->r()->sp = 0x40000; // actually doesn't matter, we're not using any
214                            // stack memory in our code
215
216   L4::Cap<L4::Thread> self;
217
218   printf("IRET\n");
219
220   vcpu->task(vcpu_task);
221   self->vcpu_resume_commit(self->vcpu_resume_start());
222
223   printf("IRET: failed!\n");
224   while (1)
225     ;
226 }
227
228 int main(void)
229 {
230   l4_utcb_t *u = l4_utcb();
231   L4::Cap<L4::Thread> vcpu_cap;
232
233   printf("vCPU example\n");
234
235   l4_debugger_set_object_name(l4re_env()->main_thread, "vcputest");
236
237   // new task
238   vcpu_task = chkcap(L4Re::Util::cap_alloc.alloc<L4::Task>(),
239                      "Task cap alloc");
240
241   chksys(L4Re::Env::env()->factory()->create_task(vcpu_task,
242                                                   l4_fpage_invalid()),
243          "create task");
244   l4_debugger_set_object_name(vcpu_task.cap(), "vcpu 'user' task");
245
246   /* new thread/vCPU */
247   vcpu_cap = chkcap(L4Re::Util::cap_alloc.alloc<L4::Thread>(),
248                     "vCPU cap alloc");
249
250   l4_touch_rw(thread_stack, sizeof(thread_stack));
251
252   chksys(L4Re::Env::env()->factory()->create_thread(vcpu_cap), "create thread");
253   l4_debugger_set_object_name(vcpu_cap.cap(), "vcpu thread");
254
255   // get an IRQ
256   irq = chkcap(L4Re::Util::cap_alloc.alloc<L4::Irq>(),
257                "Irq cap alloc");
258   chksys(L4Re::Env::env()->factory()->create_irq(irq), "irq");
259   l4_debugger_set_object_name(irq.cap(), "some irq");
260
261   // use two consecutive UTCBs
262   l4_utcb_t *vcpu_utcb  = (l4_utcb_t *)l4re_env()->first_free_utcb;
263   vcpu = L4vcpu::Vcpu::vcpu_from_utcb(vcpu_utcb);
264   vcpu->entry_sp((l4_umword_t)hdl_stack + sizeof(hdl_stack));
265   vcpu->entry_ip((l4_umword_t)handler);
266
267   printf("VCPU: utcb = %p, vcpu = %p\n", vcpu_utcb, vcpu);
268
269   // Create and start vCPU thread
270   L4::Thread::Attr attr;
271   attr.pager(L4::cap_reinterpret_cast<L4::Thread>(L4Re::Env::env()->rm()));
272   attr.exc_handler(L4Re::Env::env()->main_thread());
273   attr.vcpu_enable(1);
274   attr.bind(vcpu_utcb, L4Re::This_task);
275   chksys(vcpu_cap->control(attr), "control");
276
277   chksys(vcpu_cap->ex_regs((l4_umword_t)vcpu_thread,
278                            (l4_umword_t)thread_stack + sizeof(thread_stack),
279                            0));
280
281   chksys(L4Re::Env::env()->scheduler()->run_thread(vcpu_cap,
282                                                    l4_sched_param(2)));
283
284   // Attach irq to our vCPU thread
285   chksys(irq->attach(2000, vcpu_cap));
286
287   // Send some IPCs to the vCPU
288   l4_sleep(10);
289   for (int i = 0; i < 20; ++i)
290     l4_ipc_send(vcpu_cap.cap(), u, l4_msgtag(10 + i, 0, 0, 0), L4_IPC_NEVER);
291
292   // Some IRQ inbetween
293   irq->trigger();
294
295   l4_sleep(10);
296   for (int i = 21; i < 40; ++i)
297     l4_ipc_send(vcpu_cap.cap(), u, l4_msgtag(10 + i, 0, 0, 0), L4_IPC_NEVER);
298
299   // finally, trigger IRQs
300   while (1)
301     {
302       irq->trigger();
303       l4_sleep(500);
304     }
305
306
307   l4_sleep_forever();
308   return 0;
309 }