Hi, I am trying to modify the vcpu example of l4re-snapshot to switch registers to execute my C function.But It doesn't work. I have read some papers about l4linux tranplantion.and follow it . To switch the process, I fill the vcpu_state_t structure with its registers.and call vcpu_resume_commit action.Then Jump to the ASM Code. But problem arises when I want to jump from asm code to C function. What's the Problem? The Code is as following: /* * (c) 2009 Technische Universität Dresden * This file is part of TUD:OS, which is distributed under the terms of the * GNU General Public License 2. Please see the COPYING file for details. */ #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/re/util/kumem_alloc> #include <l4/sys/debugger.h> #include <l4/vcpu/vcpu> #include <l4/cxx/iostream>
#include <l4/re/error_helper>
#include <l4/sys/task> #include <l4/sys/irq> #include <l4/sys/vcpu.h>
#include <cstdlib> #include <cstdio> #include <cstring> #define PSR_T_BIT 0x00000000 #define SVC_MODE 0x00000013 #define PSR_E_BIT 0x00000200 #define PSR_I_BIT 0x00000000 #define USR_MODE 0x00000010 using L4Re::chksys; using L4Re::chkcap;
static L4::CapL4::Irq irq;
static char thread_stack[8 << 10]; static char hdl_stack[8 << 10]; static char idle_stack[8<<10]; static L4::CapL4::Task vcpu_task; static L4vcpu::Vcpu *vcpu;
const l4_addr_t super_code_map_addr = 0x10000; const l4_addr_t idle_code_map_addr = 0x20000; const l4_addr_t stack_map_addr = 0x12000; const l4_addr_t exit_map_addr=0x13000; extern char my_super_code[]; extern char my_super_code_excp[]; extern char my_super_code_excp_after[]; extern char exit_code[];
void idle_code(void) { ; while(1) { __asm__ volatile("swi 0"); l4_sleep(500); } } asm( ".global exit_code \t\n" "exit_code: \t\n" "b exit_code \t\n" );
asm volatile ( ".pushsection .text\n" ".p2align 12 \t\n" ".global my_super_code \t\n" "my_super_code: \t\n" " msr cpsr_c, r7\t\n" " mov lr, r6 \t\n" " mov pc, r5 \t\n" //" b my_super_code \t\n" ".popsection" ); static void setup_user_state_arch(L4vcpu::Vcpu *) { } static void handler_prolog() {}
static void handler(void) { handler_prolog();
vcpu->state()->clear(L4_VCPU_F_EXCEPTIONS); printf("hello handler\n"); //vcpu->print_state();
// very simple page-fault handling // we're just replying with the only page we have, without checking any // values if (vcpu->is_page_fault_entry()) { printf("page fault\n"); vcpu_task->map(L4Re::This_task, l4_fpage((l4_addr_t)my_super_code, L4_PAGESHIFT, L4_FPAGE_RWX), super_code_map_addr);
vcpu_task->map(L4Re::This_task, l4_fpage((l4_addr_t)idle_code, L4_PAGESHIFT, L4_FPAGE_RWX), idle_code_map_addr); vcpu_task->map(L4Re::This_task, l4_fpage((l4_addr_t)exit_code, L4_PAGESHIFT, L4_FPAGE_RWX), exit_map_addr);
vcpu->saved_state()->add(L4_VCPU_F_PAGE_FAULTS); } else if (vcpu->is_irq_entry()) { // 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 printf("unhandled exception\n");
printf("resume\n"); L4::CapL4::Thread self; self->vcpu_resume_commit(self->vcpu_resume_start()); //vcpu->state()->set(0); while(1) ; }
static void vcpu_thread(void) { printf("Hello vCPU\n"); l4_umword_t label; memset(hdl_stack, 0, sizeof(hdl_stack)); //memset(super_stack,0,sizeof(super_stack)); // memset(idle_stack,0,sizeof(idle_stack)); setup_user_state_arch(vcpu); l4_touch_rw(stack,sizeof(stack)); l4_touch_rw(idle_stack,sizeof(idle_stack)); vcpu->saved_state()->set(L4_VCPU_F_USER_MODE | L4_VCPU_F_EXCEPTIONS | L4_VCPU_F_PAGE_FAULTS | L4_VCPU_F_IRQ); vcpu->r()->flags=(l4_umword_t)SVC_MODE; vcpu->r()->r[7]=(l4_umword_t)SVC_MODE; vcpu->r()->r[0]=(l4_umword_t)0; vcpu->r()->r[4]=(l4_umword_t)(idle_stack+sizeof(idle_stack)-1); vcpu->r()->r[6]=(l4_umword_t)exit_map_addr; vcpu->r()->ip =(l4_umword_t)super_code_map_addr; vcpu->r()->r[5] = (l4_umword_t)idle_code_map_addr; vcpu->r()->sp = (l4_umword_t)0x30000; L4::CapL4::Thread self; printf("IRET\n"); vcpu->task(vcpu_task); self->vcpu_resume_commit(self->vcpu_resume_start()); printf("IRET: failed!\n"); while(1);
}
int run(void) { l4_utcb_t *u = l4_utcb(); L4::CapL4::Thread vcpu_cap;
printf("vCPU example\n");
l4_debugger_set_object_name(l4re_env()->main_thread, "vcputest");
// new task vcpu_task = chkcap(L4Re::Util::cap_alloc.allocL4::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 'user' task");
/* new thread/vCPU */ vcpu_cap = chkcap(L4Re::Util::cap_alloc.allocL4::Thread(), "vCPU cap alloc");
l4_touch_rw(thread_stack, sizeof(thread_stack)); //l4_touch_rw(hdl_stack,sizeof(hdl_stack)); chksys(L4Re::Env::env()->factory()->create_thread(vcpu_cap), "create thread"); l4_debugger_set_object_name(vcpu_cap.cap(), "vcpu thread");
// get an IRQ irq = chkcap(L4Re::Util::cap_alloc.allocL4::Irq(), "Irq cap alloc"); chksys(L4Re::Env::env()->factory()->create_irq(irq), "irq"); l4_debugger_set_object_name(irq.cap(), "some irq");
// get memory for vCPU state l4_addr_t kumem; if (0) kumem = (l4_addr_t)l4re_env()->first_free_utcb; else { if (L4Re::Util::kumem_alloc(&kumem, 0)) exit(1); } l4_utcb_t *vcpu_utcb = (l4_utcb_t *)kumem; vcpu = L4vcpu::Vcpu::cast(kumem + L4_UTCB_OFFSET); vcpu->entry_sp((l4_umword_t)hdl_stack + sizeof(hdl_stack)); vcpu->entry_ip((l4_umword_t)handler);
printf("VCPU: utcb = %p, vcpu = %p\n", vcpu_utcb, vcpu);
// Create and start vCPU thread L4::Thread::Attr attr; attr.pager(L4::cap_reinterpret_castL4::Thread(L4Re::Env::env()->rm())); attr.exc_handler(L4Re::Env::env()->main_thread()); attr.bind(vcpu_utcb, L4Re::This_task); chksys(vcpu_cap->control(attr), "control"); chksys(vcpu_cap->vcpu_control((l4_addr_t)vcpu), "enable VCPU");
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)));
// Attach irq to our vCPU thread chksys(irq->attach(2000, vcpu_cap));
// Send some IPCs to the vCPU l4_sleep(10); while (1) { // printf("triger irq\n"); // irq->trigger(); l4_sleep(500); }
l4_sleep_forever(); return 0; }
int main() { try { return run(); } catch (L4::Runtime_error &e) { L4::cerr << "FATAL uncought exception: " << e << "\nterminating...\n"; } catch (...) { L4::cerr << "FATAL uncought exception of unknown type\n" << "terminating...\n"; } return 1; }
Hi,
On Thu Aug 02, 2012 at 11:14:34 +0800, À×À×½¡ wrote:
Hi, I am trying to modify the vcpu example of l4re-snapshot to switch registers to execute my C function.But It doesn't work. I have read some papers about l4linux tranplantion.and follow it . To switch the process, I fill the vcpu_state_t structure with its registers.and call vcpu_resume_commit action.Then Jump to the ASM Code. But problem arises when I want to jump from asm code to C function. What's the Problem? The Code is as following:
#define SVC_MODE 0x00000013 #define USR_MODE 0x00000010
asm volatile ( ".pushsection .text\n" ".p2align 12 \t\n" ".global my_super_code \t\n" "my_super_code: \t\n" " msr cpsr_c, r7\t\n" " mov lr, r6 \t\n" " mov pc, r5 \t\n" //" b my_super_code \t\n" ".popsection" );
I think the problem is not the jump but the msr, which you cannot do in user-land and which you probably can safely remove.
Adam
l4-hackers@os.inf.tu-dresden.de