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.
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>
14 #include <l4/re/util/cap_alloc>
15 #include <l4/sys/debugger.h>
16 #include <l4/vcpu/vcpu>
18 #include <l4/re/error_helper>
20 #include <l4/sys/task>
22 #include <l4/sys/vcpu.h>
32 static L4::Cap<L4::Irq> irq;
34 static char thread_stack[8 << 10];
35 static char hdl_stack[8 << 10];
37 static L4::Cap<L4::Task> vcpu_task;
38 static L4vcpu::Vcpu *vcpu;
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[];
45 #if defined(ARCH_x86) || defined(ARCH_amd64)
47 static unsigned long gs;
48 static unsigned long ds;
53 ".global my_super_code \t\n"
54 ".global my_super_code_excp \t\n"
55 ".global my_super_code_excp_after \t\n"
57 "1: add $4, %eax \t\n"
70 "my_super_code_excp: \t\n"
72 "my_super_code_excp_after: \t\n"
81 static void setup_user_state_arch(L4vcpu::Vcpu *v)
83 asm volatile ("mov %%gs, %0" : "=r"(gs));
84 asm volatile ("mov %%ds, %0" : "=r"(ds));
94 static void handler_prolog()
96 asm volatile ("mov %0, %%es \t\n"
99 : : "r"(ds), "r"(gs));
102 #elif defined(ARCH_arm)
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"
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"
129 static void setup_user_state_arch(L4vcpu::Vcpu *) { }
130 static void handler_prolog() {}
132 #elif defined(ARCH_ppc32)
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"
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"
151 static void setup_user_state_arch(L4vcpu::Vcpu *) { }
152 static void handler_prolog() {}
154 #error Add your architecture.
158 static void handler(void)
162 vcpu->state()->clear(L4_VCPU_F_EXCEPTIONS);
167 // very simple page-fault hanlding
168 // we're just replying with the only page we have, without checking any
170 if (vcpu->is_page_fault_entry())
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);
177 else if (vcpu->is_irq_entry())
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());
187 printf("Unclassifiable message\n");
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;
194 //printf("resume\n");
195 L4::Cap<L4::Thread> self;
196 self->vcpu_resume_commit(self->vcpu_resume_start());
201 static void vcpu_thread(void)
203 printf("Hello vCPU\n");
205 memset(hdl_stack, 0, sizeof(hdl_stack));
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
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
216 L4::Cap<L4::Thread> self;
220 vcpu->task(vcpu_task);
221 self->vcpu_resume_commit(self->vcpu_resume_start());
223 printf("IRET: failed!\n");
230 l4_utcb_t *u = l4_utcb();
231 L4::Cap<L4::Thread> vcpu_cap;
233 printf("vCPU example\n");
235 l4_debugger_set_object_name(l4re_env()->main_thread, "vcputest");
238 vcpu_task = chkcap(L4Re::Util::cap_alloc.alloc<L4::Task>(),
241 chksys(L4Re::Env::env()->factory()->create_task(vcpu_task,
244 l4_debugger_set_object_name(vcpu_task.cap(), "vcpu 'user' task");
246 /* new thread/vCPU */
247 vcpu_cap = chkcap(L4Re::Util::cap_alloc.alloc<L4::Thread>(),
250 l4_touch_rw(thread_stack, sizeof(thread_stack));
252 chksys(L4Re::Env::env()->factory()->create_thread(vcpu_cap), "create thread");
253 l4_debugger_set_object_name(vcpu_cap.cap(), "vcpu thread");
256 irq = chkcap(L4Re::Util::cap_alloc.alloc<L4::Irq>(),
258 chksys(L4Re::Env::env()->factory()->create_irq(irq), "irq");
259 l4_debugger_set_object_name(irq.cap(), "some irq");
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);
267 printf("VCPU: utcb = %p, vcpu = %p\n", vcpu_utcb, vcpu);
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());
274 attr.bind(vcpu_utcb, L4Re::This_task);
275 chksys(vcpu_cap->control(attr), "control");
277 chksys(vcpu_cap->ex_regs((l4_umword_t)vcpu_thread,
278 (l4_umword_t)thread_stack + sizeof(thread_stack),
281 chksys(L4Re::Env::env()->scheduler()->run_thread(vcpu_cap,
284 // Attach irq to our vCPU thread
285 chksys(irq->attach(2000, vcpu_cap));
287 // Send some IPCs to the vCPU
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);
292 // Some IRQ inbetween
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);
299 // finally, trigger IRQs