]> rtime.felk.cvut.cz Git - l4.git/blobdiff - l4/pkg/examples/sys/vcpu/vcpu.cc
update
[l4.git] / l4 / pkg / examples / sys / vcpu / vcpu.cc
index 0f7261455a418af77d463d5f4b4af036a998a982..7c3a07a4bac26f331a82859ea7f80f68ae5ca0b3 100644 (file)
@@ -6,12 +6,14 @@
 #include <l4/sys/ipc.h>
 #include <l4/sys/thread>
 #include <l4/sys/factory>
+#include <l4/sys/scheduler>
 #include <l4/sys/utcb.h>
 #include <l4/sys/kdebug.h>
 #include <l4/util/util.h>
 #include <l4/re/env>
 #include <l4/re/util/cap_alloc>
 #include <l4/sys/debugger.h>
+#include <l4/vcpu/vcpu>
 
 #include <l4/re/error_helper>
 
 
 
 using L4Re::chksys;
+using L4Re::chkcap;
 
 static L4::Cap<L4::Irq> irq;
 
 static char thread_stack[8 << 10];
 static char hdl_stack[8 << 10];
 
-static L4::Cap<L4::Thread> vcpu;
 static L4::Cap<L4::Task> vcpu_task;
+static L4vcpu::Vcpu *vcpu;
 
-typedef l4_vcpu_state_t SSA;
+const l4_addr_t super_code_map_addr = 0x10000;
+extern char my_super_code[];
+extern char my_super_code_excp[];
+extern char my_super_code_excp_after[];
+
+#if defined(ARCH_x86) || defined(ARCH_amd64)
 
-static SSA *vcpu_state;
-static l4_umword_t volatile *vcpu_psr;
 static unsigned long gs;
 static unsigned long ds;
 
-
-
-extern char my_super_code[];
-
-#if defined __amd64__ || defined __i386__
 asm
 (
-  ".p2align 12\n"
-  ".global my_super_code \n"
-  "my_super_code: \n"
-  "1: add $4, %eax; add $4, %eax; add $4, %eax; add $4, %eax; add $4, %eax; add $4, %eax; add $4, %eax; add $4, %eax; add $4, %eax; add $4, %eax; add $4, %eax; add $4, %eax; add $4, %eax; ud2a; add $4, %eax; add $4, %eax;add $4, %eax; add $4, %eax; jmp 1b \n"
+  ".p2align 12                      \t\n"
+  ".global my_super_code            \t\n"
+  ".global my_super_code_excp       \t\n"
+  ".global my_super_code_excp_after \t\n"
+  "my_super_code:                   \t\n"
+  "1: add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "my_super_code_excp:              \t\n"
+  "   ud2a                          \t\n"
+  "my_super_code_excp_after:        \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   add $4, %eax                  \t\n"
+  "   jmp 1b                        \t\n"
   );
 
 
-static void print_upc()
+static void setup_user_state_arch(L4vcpu::Vcpu *v)
 {
-  printf("upcall %lx %lx %lx\n", vcpu_state->r.trapno, vcpu_state->r.err, vcpu_state->r.pfa);
-}
-
-static void print_state()
-{
-  l4_umword_t psr = *vcpu_psr;
-  printf("EIP=%08lx ESP=%08lx PSR=%08lx\n"
-         "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n"
-         "ESI=%08lx EDI=%08lx EBP=%08lx\n"
-#ifndef __amd64__
-        "DS=%04lx ES=%04lx FS=%04lx GS=%04lx\n"
-#endif
-        "TAG=%08lx SRC=%08lx SPSR=%08lx\n",
-         vcpu_state->r.ip,
-         vcpu_state->r.sp,
-        psr,
-         vcpu_state->r.ax,
-         vcpu_state->r.bx,
-         vcpu_state->r.cx,
-         vcpu_state->r.dx,
-         vcpu_state->r.si,
-         vcpu_state->r.di,
-         vcpu_state->r.bp,
+  asm volatile ("mov %%gs, %0" : "=r"(gs));
+  asm volatile ("mov %%ds, %0" : "=r"(ds));
 #ifndef __amd64__
-         vcpu_state->r.ds,
-         vcpu_state->r.es,
-         vcpu_state->r.fs,
-         vcpu_state->r.gs,
+  v->r()->gs = ds;
+  v->r()->fs = ds;
+  v->r()->es = ds;
+  v->r()->ds = ds;
 #endif
-         vcpu_state->i.tag.raw,
-         vcpu_state->i.label,
-        vcpu_state->saved_state);
+  v->r()->ss = ds;
 }
 
-static bool is_page_fault(SSA const *v)
-{ return v->r.trapno == 0xe; }
-
-
-static void setup_user_state(SSA *v)
+static void handler_prolog()
 {
-  asm volatile ("mov %%gs, %0" : "=r"(gs));
-  asm volatile ("mov %%ds, %0" : "=r"(ds));
-  v->saved_state = 0x27;
-#ifndef __amd64__
-  v->r.gs = ds;
-  v->r.fs = ds;
-  v->r.es = ds;
-  v->r.ds = ds;
-#endif
-  v->r.ss = ds;
-  v->r.ip = 0x10000;
-  v->r.sp = 0x40000;
+  asm volatile ("mov %0, %%es \t\n"
+                "mov %0, %%ds \t\n"
+                "mov %1, %%gs \t\n"
+                : : "r"(ds), "r"(gs));
 }
 
-#elif defined __arm__
+#elif defined(ARCH_arm)
 asm
 (
-  ".p2align 12\n"
-  ".global my_super_code \n"
-  "my_super_code: \n"
-  "1: add r0, r0, #4 \n"
-  "   add r0, r0, #4 \n"
-  "   add r0, r0, #4 \n"
-  "   add r0, r0, #4 \n"
-  "   add r0, r0, #4 \n"
-  "   add r0, r0, #4 \n"
-  "   add r0, r0, #4 \n"
-  "   add r0, r0, #4; swi 0; mrc 8, 0, r0, cr7, cr14\n"
-  "   add r0, r0, #4 \n"
-  "   add r0, r0, #4 \n"
-  "   add r0, r0, #4 \n"
-  "   b 1b           \n"
+  ".p2align 12                      \t\n"
+  ".global my_super_code            \t\n"
+  ".global my_super_code_excp       \t\n"
+  ".global my_super_code_excp_after \t\n"
+  "my_super_code:                   \t\n"
+  "1: add r0, r0, #4                \t\n"
+  "   add r0, r0, #4                \t\n"
+  "   add r0, r0, #4                \t\n"
+  "   add r0, r0, #4                \t\n"
+  "   add r0, r0, #4                \t\n"
+  "   add r0, r0, #4                \t\n"
+  "   add r0, r0, #4                \t\n"
+  "   add r0, r0, #4               \t\n"
+  "my_super_code_excp:              \t\n"
+  "   swi 0                         \t\n"
+  "my_super_code_excp_after:        \t\n"
+  "   mrc 8, 0, r0, cr7, cr14       \t\n"
+  "   add r0, r0, #4                \t\n"
+  "   add r0, r0, #4                \t\n"
+  "   add r0, r0, #4                \t\n"
+  "   b 1b                          \t\n"
   );
 
 
-static void print_upc()
-{
-  printf("upcall %lx %lx\n", vcpu_state->r.err, vcpu_state->r.pfa);
-}
+static void setup_user_state_arch(L4vcpu::Vcpu *) { }
+static void handler_prolog() {}
 
-static void print_state()
-{
-  l4_umword_t psr = *vcpu_psr;
-  printf("R[00]: %08lx %08lx %08lx %08lx\n"
-         "R[04]: %08lx %08lx %08lx %08lx\n"
-         "R[08]: %08lx %08lx %08lx %08lx\n"
-         "R[12]: %08lx %08lx %08lx %08lx\n"
-        "PSR=%08lx\n"
-        "TAG=%08lx SRC=%08lx SPSR=%08lx\n",
-         vcpu_state->r.r[0],
-         vcpu_state->r.r[1],
-         vcpu_state->r.r[2],
-         vcpu_state->r.r[3],
-         vcpu_state->r.r[4],
-         vcpu_state->r.r[5],
-         vcpu_state->r.r[6],
-         vcpu_state->r.r[7],
-         vcpu_state->r.r[8],
-         vcpu_state->r.r[9],
-         vcpu_state->r.r[10],
-         vcpu_state->r.r[11],
-         vcpu_state->r.r[12],
-         vcpu_state->r.sp,
-         vcpu_state->r.lr,
-         vcpu_state->r.ip,
-         psr,
-         vcpu_state->i.tag.raw,
-         vcpu_state->i.label,
-        vcpu_state->saved_state);
-}
-
-static bool is_page_fault(SSA const *v)
-{ return (v->r.err & 0xf00000) == 0x300000; }
-
-static void setup_user_state(SSA *v)
-{
-  v->saved_state = 0x27;
-  v->r.ip = 0x10000;
-  v->r.sp = 0x40000;
-}
+#elif defined(ARCH_ppc32)
+asm
+(
+  ".p2align 12                      \t\n"
+  ".global my_super_code            \t\n"
+  ".global my_super_code_excp       \t\n"
+  ".global my_super_code_excp_after \t\n"
+  "my_super_code:                   \t\n"
+  "1: addi %r4, %r4, 4              \t\n"
+  "   addi %r4, %r4, 4              \t\n"
+  "   addi %r4, %r4, 4              \t\n"
+  "my_super_code_excp:              \t\n"
+  "   trap                          \t\n"
+  "my_super_code_excp_after:        \t\n"
+  "   addi %r4, %r4, 4              \t\n"
+  "   addi %r4, %r4, 4              \t\n"
+  "   addi %r4, %r4, 4              \t\n"
+  "   b 1b                          \t\n"
+  );
+static void setup_user_state_arch(L4vcpu::Vcpu *) { }
+static void handler_prolog() {}
+#else
+#error Add your architecture.
 #endif
 
 
 static void handler(void)
 {
+  handler_prolog();
 
-#if defined __amd64__ || defined __i386__
-  asm volatile (
-      "mov %0, %%es \t\n"
-      "mov %0, %%ds \t\n"
-      "mov %1, %%gs \t\n" : : "r"(ds), "r"(gs));
-#endif
-//upc:
-  print_upc();
-#if 0
-  l4_umword_t psr = *vcpu_psr;
-#endif
-  print_state();
+  vcpu->state()->clear(L4_VCPU_F_EXCEPTIONS);
 
-#if 0
-  *vcpu_psr |= 1;
-  if (psr & 2)
-    {
-      vcpu_state->tag = l4_ipc_wait(l4_utcb(), &vcpu_state->label, L4_IPC_NEVER); //L4_IPC_RECV_TIMEOUT_0);
-      goto upc;
+  if (0)
+    vcpu->print_state();
 
+  // very simple page-fault hanlding
+  // we're just replying with the only page we have, without checking any
+  // values
+  if (vcpu->is_page_fault_entry())
+    {
+      vcpu_task->map(L4Re::This_task, l4_fpage((l4_addr_t)my_super_code,
+                                               L4_PAGESHIFT, L4_FPAGE_RWX),
+                                               super_code_map_addr);
+      vcpu->saved_state()->add(L4_VCPU_F_PAGE_FAULTS);
     }
-#endif
-
-  l4_addr_t a = (l4_addr_t)my_super_code;
-
-  if (is_page_fault(vcpu_state))
+  else if (vcpu->is_irq_entry())
     {
-      vcpu_task->map(L4Re::This_task, l4_fpage(a, 12, L4_FPAGE_RWX), 0x10000);
+      // We use the label 2000 for our IRQ
+      if (vcpu->i()->label == 2000)
+        printf("Our triggered IRQ\n");
+      else if (vcpu->i()->label == 0)
+        // direct IPC message to vCPU without
+        // going through an IPCgate, label is set to 0
+        printf("IPC: %lx\n", vcpu->i()->tag.label());
+      else
+        printf("Unclassifiable message\n");
     }
+  else
+  // we should also check the exception number here
+    if (vcpu->r()->ip == (l4_addr_t)my_super_code_excp - (l4_addr_t)my_super_code + super_code_map_addr)
+      vcpu->r()->ip += my_super_code_excp_after - my_super_code_excp;
 
-  vcpu_state->saved_state |= L4_VCPU_F_PAGE_FAULTS;
-
-  printf("resume\n");
+  //printf("resume\n");
   L4::Cap<L4::Thread> self;
-  self.invalidate();
   self->vcpu_resume_commit(self->vcpu_resume_start());
   while(1)
     ;
@@ -225,114 +200,110 @@ static void handler(void)
 
 static void vcpu_thread(void)
 {
-  //*vcpu_psr |= 2;
-  printf("HELLO VCPU\n");
+  printf("Hello vCPU\n");
+
   memset(hdl_stack, 0, sizeof(hdl_stack));
-  setup_user_state(vcpu_state);
+
+  setup_user_state_arch(vcpu);
+  vcpu->saved_state()->set(L4_VCPU_F_USER_MODE
+                           | L4_VCPU_F_EXCEPTIONS
+                           | L4_VCPU_F_PAGE_FAULTS
+                           | L4_VCPU_F_IRQ);
+  vcpu->r()->ip = super_code_map_addr;
+  vcpu->r()->sp = 0x40000; // actually doesn't matter, we're not using any
+                           // stack memory in our code
 
   L4::Cap<L4::Thread> self;
+
   printf("IRET\n");
-  vcpu_state->user_task = vcpu_task.cap();
+
+  vcpu->task(vcpu_task);
   self->vcpu_resume_commit(self->vcpu_resume_start());
-  printf("IRET uh?!\n");
 
-  *vcpu_psr |= 3;
+  printf("IRET: failed!\n");
   while (1)
-    {
-    }
-
-  l4_msgtag_t x;
-  while (1) {
-    x = l4_ipc_call(0x1234 << L4_CAP_SHIFT, l4_utcb(), l4_msgtag(0, 0, 0, 0), L4_IPC_NEVER);
-    l4_sleep(1000);
-    outstring("An int3 -- you should see this\n");
-    outnstring("345", 3);
-  }
-
+    ;
 }
 
 int main(void)
 {
-  l4_msgtag_t tag;
   l4_utcb_t *u = l4_utcb();
-  l4_exc_regs_t exc;
-  l4_umword_t mr0, mr1;
+  L4::Cap<L4::Thread> vcpu_cap;
 
   printf("vCPU example\n");
 
   l4_debugger_set_object_name(l4re_env()->main_thread, "vcputest");
 
   // new task
-  vcpu_task = L4Re::Util::cap_alloc.alloc<L4::Task>();
-  if (!vcpu_task.is_valid())
-    return 2;
+  vcpu_task = chkcap(L4Re::Util::cap_alloc.alloc<L4::Task>(),
+                     "Task cap alloc");
 
-  chksys(L4Re::Env::env()->factory()->create_task(vcpu_task, l4_fpage_invalid()), "create task");
-  l4_debugger_set_object_name(vcpu_task.cap(), "vcpu task");
+  chksys(L4Re::Env::env()->factory()->create_task(vcpu_task,
+                                                  l4_fpage_invalid()),
+         "create task");
+  l4_debugger_set_object_name(vcpu_task.cap(), "vcpu 'user' task");
 
-  /* new thread */
-  vcpu = L4Re::Util::cap_alloc.alloc<L4::Thread>();
-  if (!vcpu.is_valid())
-    return 1;
+  /* new thread/vCPU */
+  vcpu_cap = chkcap(L4Re::Util::cap_alloc.alloc<L4::Thread>(),
+                    "vCPU cap alloc");
 
   l4_touch_rw(thread_stack, sizeof(thread_stack));
 
-  chksys(L4Re::Env::env()->factory()->create_thread(vcpu), "create thread");
-  l4_debugger_set_object_name(vcpu.cap(), "vcpu thread");
+  chksys(L4Re::Env::env()->factory()->create_thread(vcpu_cap), "create thread");
+  l4_debugger_set_object_name(vcpu_cap.cap(), "vcpu thread");
 
-  // use two consecurity UTCBs
+  // get an IRQ
+  irq = chkcap(L4Re::Util::cap_alloc.alloc<L4::Irq>(),
+               "Irq cap alloc");
+  chksys(L4Re::Env::env()->factory()->create_irq(irq), "irq");
+  l4_debugger_set_object_name(irq.cap(), "some irq");
+
+  // use two consecutive UTCBs
   l4_utcb_t *vcpu_utcb  = (l4_utcb_t *)l4re_env()->first_free_utcb;
-  vcpu_state = reinterpret_cast<SSA*>((l4_umword_t)vcpu_utcb + L4_UTCB_OFFSET);
-  vcpu_state->entry_sp = (l4_umword_t)hdl_stack + sizeof(hdl_stack);
-  vcpu_state->entry_ip = (l4_umword_t)handler;
-  vcpu_psr = &vcpu_state->state;
+  vcpu = L4vcpu::Vcpu::vcpu_from_utcb(vcpu_utcb);
+  vcpu->entry_sp((l4_umword_t)hdl_stack + sizeof(hdl_stack));
+  vcpu->entry_ip((l4_umword_t)handler);
 
-  printf("VCPU: utcb = %p, vcpu_state = %p\n", vcpu_utcb, vcpu_state);
+  printf("VCPU: utcb = %p, vcpu = %p\n", vcpu_utcb, vcpu);
 
-  // control thread
+  // Create and start vCPU thread
   L4::Thread::Attr attr;
   attr.pager(L4::cap_reinterpret_cast<L4::Thread>(L4Re::Env::env()->rm()));
   attr.exc_handler(L4Re::Env::env()->main_thread());
   attr.vcpu_enable(1);
   attr.bind(vcpu_utcb, L4Re::This_task);
+  chksys(vcpu_cap->control(attr), "control");
 
-  chksys(vcpu->control(attr), "control");
-
-  // launch thread
-  tag = vcpu->ex_regs((l4_umword_t)vcpu_thread,
-                      (l4_umword_t)thread_stack + sizeof(thread_stack),
-                      0);
+  chksys(vcpu_cap->ex_regs((l4_umword_t)vcpu_thread,
+                           (l4_umword_t)thread_stack + sizeof(thread_stack),
+                           0));
 
+  chksys(L4Re::Env::env()->scheduler()->run_thread(vcpu_cap,
+                                                   l4_sched_param(2)));
 
-  chksys(irq->attach(200, vcpu));
+  // Attach irq to our vCPU thread
+  chksys(irq->attach(2000, vcpu_cap));
 
-  if (l4_msgtag_has_error(tag))
-    return 3;
-  l4_sleep(10);
-  for (int i = 0; i < 20; ++i)
-    {
-      l4_ipc_send(vcpu.cap(), u, l4_msgtag(10 + i, 0, 0, 0), L4_IPC_NEVER);
-    }
+  // Send some IPCs to the vCPU
   l4_sleep(10);
   for (int i = 0; i < 20; ++i)
-    {
-      l4_ipc_send(vcpu.cap(), u, l4_msgtag(40 + i, 0, 0, 0), L4_IPC_NEVER);
-    }
+    l4_ipc_send(vcpu_cap.cap(), u, l4_msgtag(10 + i, 0, 0, 0), L4_IPC_NEVER);
 
-  /* Pager/Exception loop */
-  if (l4_msgtag_has_error(tag = l4_ipc_receive(vcpu.cap(), u, L4_IPC_NEVER)))
-    {
-      printf("l4_ipc_receive failed");
-      return 1;
-    }
+  // Some IRQ inbetween
+  irq->trigger();
 
-  memcpy(&exc, l4_utcb_exc(), sizeof(exc));
-  mr0 = l4_utcb_mr()->mr[0];
-  mr1 = l4_utcb_mr()->mr[1];
+  l4_sleep(10);
+  for (int i = 21; i < 40; ++i)
+    l4_ipc_send(vcpu_cap.cap(), u, l4_msgtag(10 + i, 0, 0, 0), L4_IPC_NEVER);
 
-  for (;;)
+  // finally, trigger IRQs
+  while (1)
     {
+      irq->trigger();
+      l4_sleep(500);
     }
 
+
+  l4_sleep_forever();
   return 0;
 }