static void handle_trap(int pid, union uml_pt_regs *regs) { int err, syscall_nr, status; syscall_nr = PT_SYSCALL_NR(regs->skas.regs); UPT_SYSCALL_NR(regs) = syscall_nr; if(syscall_nr < 1){ relay_signal(SIGTRAP, regs); return; } err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); if(err < 0) panic("handle_trap - nullifying syscall failed errno = %d\n", errno); err = ptrace(PTRACE_SYSCALL, pid, 0, 0); if(err < 0) panic("handle_trap - continuing to end of syscall failed, " "errno = %d\n", errno); CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) panic("handle_trap - failed to wait at end of syscall, " "errno = %d, status = %d\n", errno, status); handle_syscall(regs); }
/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu) { int err, status; /* Mark this as a syscall */ UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs); if (!local_using_sysemu) { err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); if(err < 0) panic("handle_trap - nullifying syscall failed errno = %d\n", errno); err = ptrace(PTRACE_SYSCALL, pid, 0, 0); if(err < 0) panic("handle_trap - continuing to end of syscall failed, " "errno = %d\n", errno); CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP + 0x80)) panic("handle_trap - failed to wait at end of syscall, " "errno = %d, status = %d\n", errno, status); } handle_syscall(regs); }
// Poll for incoming messages and send responses. void run_server() { // Struct for reading the syscall over the channel syscall_req_t syscall_req; syscall_rsp_t syscall_rsp; int fd_read, fd_write; int ret = init_syscall_server(&fd_read, &fd_write); if(ret < 0) error(ret, "Could not open file desciptors for communication\n"); printf("Server started...."); // Continuously read in data from the channel socket while(1) { syscall_req.payload_len = 0; syscall_req.payload = NULL; syscall_rsp.payload_len = 0; syscall_rsp.payload = NULL; debug("\nWaiting for syscall...\n"); read_syscall_req(fd_read, &syscall_req); debug("Processing syscall: %d\n", syscall_req.header.id); handle_syscall(&syscall_req, &syscall_rsp); debug("Writing response: %d\n", syscall_req.header.id); write_syscall_rsp(fd_write, &syscall_rsp); if(syscall_req.payload != NULL) free(syscall_req.payload); if(syscall_rsp.payload != NULL) free(syscall_rsp.payload); } }
pid_t handle_events_until_dump_trap(pid_t wait_for) { while (true) { event_t e = wait_event(wait_for); if (e.signo == SIGTRAP) { if (is_dump_sigtrap(e.tid)) { clear_trap(e.tid); return e.tid; } else if (is_hook_sigtrap(e.tid)) { assert(tracer_state == TRACER_LOCKED || tracer_state == TRACER_FIRSTTOUCH); clear_trap(e.tid); tracer_lock_range(e.tid); continue; } else { // If we arrive here, it is a syscall handle_syscall(e.tid); ptrace_syscall(e.tid); continue; } } else if (e.signo == SIGSEGV) { void *addr = round_to_page(e.sigaddr); switch (tracer_state) { case TRACER_UNLOCKED: /* We should never get a sigsegv in unlocked state ! */ errx(EXIT_FAILURE, "SIGSEGV at %p before locking memory during capture\n", e.sigaddr); case TRACER_FIRSTTOUCH: firsttouch_handler(e.tid, addr); break; case TRACER_LOCKED: mru_handler(e.tid, addr); break; case TRACER_DUMPING: dump_handler(e.tid, addr); break; default: assert(false); /* we should never be here */ } ptrace_syscall(e.tid); } else if (e.signo == SIGSTOP) { /* A new thread is starting, ignore this event, next wait_event call will unblock the thread once its parents registers it in tids array */ } else if (e.signo == SIGWINCH) { /* Ignore signal SIGWINCH, tty resize */ ptrace_syscall(e.tid); continue; } else { errx(EXIT_FAILURE, "Unexpected signal in wait_sigtrap: %d\n", e.signo); } } debug_print("%s", "\n"); }
void handle_trap(struct interrupt_frame *frame) { unsigned int address; int trap_cause = __builtin_nyuzi_read_control_reg(CR_TRAP_CAUSE); switch (trap_cause & 0xf) { case TT_PAGE_FAULT: case TT_ILLEGAL_STORE: address = __builtin_nyuzi_read_control_reg(CR_TRAP_ADDR); enable_interrupts(); if (!handle_page_fault(address, (trap_cause & 0x10) != 0)) { // Jump to user_copy fault handler if set if (fault_handler[current_hw_thread()] != 0) frame->pc = fault_handler[current_hw_thread()]; else bad_fault(frame); } disable_interrupts(); break; case TT_SYSCALL: // Enable interrupts address = __builtin_nyuzi_read_control_reg(CR_TRAP_ADDR); enable_interrupts(); frame->gpr[0] = handle_syscall(frame->gpr[0], frame->gpr[1], frame->gpr[2], frame->gpr[3], frame->gpr[4], frame->gpr[5]); frame->pc += 4; // Next instruction disable_interrupts(); break; case TT_INTERRUPT: handle_interrupt(frame); break; default: bad_fault(frame); } }
void catbox_syscall_handle(struct trace_context *ctx, struct traced_child *kid) { int syscall; struct user_regs_struct regs; pid_t pid; pid = kid->pid; ptrace(PTRACE_GETREGS, pid, 0, ®s); syscall = regs.REG_CALL; if (kid->in_syscall) { // returning from syscall if (syscall == 0xbadca11) { // restore real call number, and return our error code regs.REG_ERROR = kid->error_code; regs.REG_CALL = kid->orig_call; ptrace(PTRACE_SETREGS, pid, 0, ®s); } kid->in_syscall = 0; } else { // entering syscall kid->in_syscall = 1; // skip extra sigtrap from execve call if (syscall == __NR_execve) { kid->in_execve = 1; goto out; } int ret = handle_syscall(ctx, pid, syscall); if (ret != 0) { kid->error_code = ret; kid->orig_call = regs.REG_CALL; if (!ctx->collect_only) { // prevent the call by giving an invalid call number regs.REG_CALL = 0xbadca11; ptrace(PTRACE_SETREGS, pid, 0, ®s); } } } out: // continue tracing ptrace(PTRACE_SYSCALL, pid, 0, 0); }
void catbox_syscall_handle(struct trace_context *ctx, struct traced_child *kid) { int syscall; struct user_regs_struct regs; pid_t pid; pid = kid->pid; ptrace(PTRACE_GETREGS, pid, 0, ®s); syscall = regs.orig_eax; if (kid->in_syscall) { // returning from syscall if (syscall == 0xbadca11) { // restore real call number, and return our error code ptrace(PTRACE_POKEUSER, pid, 44, kid->orig_eax); ptrace(PTRACE_POKEUSER, pid, 24, kid->error_code); } kid->in_syscall = 0; } else { // entering syscall // skip extra sigtrap from execve call if (syscall == __NR_execve) { kid->in_execve = 1; goto out; } int ret = handle_syscall(ctx, pid, syscall); if (ret != 0) { kid->error_code = ret; kid->orig_eax = regs.orig_eax; // prevent the call by giving an invalid call number ptrace(PTRACE_POKEUSER, pid, 44, 0xbadca11); } kid->in_syscall = 1; } out: // continue tracing ptrace(PTRACE_SYSCALL, pid, 0, 0); }
void syscall_loop(seL4_CPtr ep) { while (1) { //dprintf(3, "looping\n"); seL4_Word badge; seL4_Word label; seL4_MessageInfo_t message; message = seL4_Wait(ep, &badge); //dprintf(3, "badge=0x%x\n", badge); label = seL4_MessageInfo_get_label(message); if(badge & IRQ_EP_BADGE){ /* Interrupt */ if (badge & IRQ_BADGE_NETWORK) { network_irq(); } if (badge & IRQ_BADGE_TIMER) { int ret = timer_interrupt(); if (ret != CLOCK_R_OK) { //What now? } } }else if(label == seL4_VMFault){ /* Page fault */ dprintf(3, "user with pid = %d, 0x%08x is having a vmfault\n", badge & ~USER_EP_BADGE, badge); set_cur_proc(badge & ~USER_EP_BADGE); handle_pagefault(); }else if(label == seL4_NoFault) { /* System call */ dprintf(3, "user with pid = %d, 0x%08x is making a syscall\n", badge & ~USER_EP_BADGE, badge); set_cur_proc(badge & ~USER_EP_BADGE); handle_syscall(badge, seL4_MessageInfo_get_length(message) - 1); }else{ dprintf(3, "Rootserver got an unknown message\n"); } } }
void soft_interrupt_entry(regs *r) { const int int_num = regs_intnum(r); ASSERT(!are_interrupts_enabled()); if (int_num == SYSCALL_SOFT_INTERRUPT) DEBUG_check_preemption_enabled_for_usermode(); push_nested_interrupt(int_num); disable_preemption(); if (int_num == SYSCALL_SOFT_INTERRUPT) { enable_interrupts_forced(); { handle_syscall(r); } disable_interrupts_forced(); /* restore IF = 0 */ } else { /* * General rule: fault handlers get control with interrupts disabled but * they are supposed to call enable_interrupts_forced() ASAP. */ handle_fault(r); /* Faults are expected to return with interrupts disabled. */ ASSERT(!are_interrupts_enabled()); } enable_preemption(); pop_nested_interrupt(); if (int_num == SYSCALL_SOFT_INTERRUPT) DEBUG_check_preemption_enabled_for_usermode(); }
static int sigchld_handler(sd_event_source *es, const struct signalfd_siginfo *si, void *vmpid) { (void)es; pid_t mpid = *(pid_t *)vmpid; if (si->ssi_signo != SIGCHLD) ERROR("parent: unexpected signal"); while (true) { int status; pid_t spid = waitpid(-mpid, &status, WNOHANG | __WALL); NONNEGATIVE(spid); if (!spid) break; if (WIFEXITED(status) && spid == mpid) { FINISH(POE_SUCCESS, WEXITSTATUS(status), NULL); } else if (WIFSIGNALED(status) && spid == mpid) { FINISH(POE_SIGNALED, -1, "Program terminated with signal %d (%s)", WTERMSIG(status), strsignal(WTERMSIG(status))); } else if (WIFSTOPPED(status)) { int e = status >> 16 & 0xff; switch (e) { case PTRACE_EVENT_SECCOMP: handle_syscall(spid); break; case PTRACE_EVENT_CLONE: case PTRACE_EVENT_FORK: case PTRACE_EVENT_VFORK: ptrace(PTRACE_CONT, spid, 0, 0); break; default: ptrace(PTRACE_CONT, spid, 0, WSTOPSIG(status)); break; } } } return 0; }
int main(int argc, char **argv) { int sig, status, exit_code; pink_event_t event; struct child son; /* Parse arguments */ if (argc < 2) { fprintf(stderr, "Usage: %s program [argument...]\n", argv[0]); return EXIT_FAILURE; } /* Fork */ if ((son.pid = fork()) < 0) { perror("fork"); return EXIT_FAILURE; } else if (!son.pid) { /* child */ /* Set up for tracing */ if (!pink_trace_me()) { perror("pink_trace_me"); _exit(EXIT_FAILURE); } /* Stop and let the parent continue the execution. */ kill(getpid(), SIGSTOP); ++argv; execvp(argv[0], argv); perror("execvp"); _exit(-1); } else { waitpid(son.pid, &status, 0); event = pink_event_decide(status); assert(event == PINK_EVENT_STOP); /* Set up the tracing options. */ if (!pink_trace_setup(son.pid, PINK_TRACE_OPTION_SYSGOOD | PINK_TRACE_OPTION_EXEC)) { perror("pink_trace_setup"); pink_trace_kill(son.pid); return EXIT_FAILURE; } /* Figure out the bitness of the traced child. */ son.bitness = pink_bitness_get(son.pid); if (son.bitness == PINK_BITNESS_UNKNOWN) err(1, "pink_bitness_get"); printf("Child %i runs in %s mode\n", son.pid, pink_bitness_name(son.bitness)); son.dead = son.insyscall = false; sig = exit_code = 0; for (;;) { /* At this point the traced child is stopped and needs * to be resumed. */ if (!pink_trace_syscall(son.pid, sig)) { perror("pink_trace_syscall"); return (errno == ESRCH) ? 0 : 1; } sig = 0; /* Wait for the child */ if ((son.pid = waitpid(son.pid, &status, 0)) < 0) { perror("waitpid"); return (errno == ECHILD) ? 0 : 1; } /* Check the event. */ event = pink_event_decide(status); switch (event) { case PINK_EVENT_SYSCALL: handle_syscall(&son); break; break; case PINK_EVENT_EXEC: /* Update bitness */ son.bitness = pink_bitness_get(son.pid); if (son.bitness == PINK_BITNESS_UNKNOWN) err(1, "pink_bitness_get"); else printf(" (Updating the bitness of child %i to %s mode)\n", son.pid, pink_bitness_name(son.bitness)); break; case PINK_EVENT_GENUINE: case PINK_EVENT_UNKNOWN: /* Send the signal to the traced child as it * was a genuine signal. */ sig = WSTOPSIG(status); break; case PINK_EVENT_EXIT_GENUINE: exit_code = WEXITSTATUS(status); printf("Child %i exited normally with return code %d\n", son.pid, exit_code); son.dead = true; break; case PINK_EVENT_EXIT_SIGNAL: exit_code = 128 + WTERMSIG(status); printf("Child %i exited with signal %d\n", son.pid, WTERMSIG(status)); son.dead = true; break; default: /* Nothing */ ; } if (son.dead) break; } return exit_code; } }
void handle_event(Event *event) { if (exiting == 1) { exiting = 2; debug(1, "ltrace about to exit"); ltrace_exiting(); } debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)", event->proc ? event->proc->pid : -1, event->type); /* If the thread group or an individual task define an overriding event handler, give them a chance to kick in. We will end up calling both handlers, if the first one doesn't sink the event. */ if (event->proc != NULL) { event = call_handler(event->proc, event); if (event == NULL) /* It was handled. */ return; /* Note: the previous handler has a chance to alter * the event. */ if (event->proc != NULL && event->proc->leader != NULL && event->proc != event->proc->leader) { event = call_handler(event->proc->leader, event); if (event == NULL) return; } } switch (event->type) { case EVENT_NONE: debug(1, "event: none"); return; case EVENT_SIGNAL: debug(1, "event: signal (%s [%d])", shortsignal(event->proc, event->e_un.signum), event->e_un.signum); handle_signal(event); return; case EVENT_EXIT: debug(1, "event: exit (%d)", event->e_un.ret_val); handle_exit(event); return; case EVENT_EXIT_SIGNAL: debug(1, "event: exit signal (%s [%d])", shortsignal(event->proc, event->e_un.signum), event->e_un.signum); handle_exit_signal(event); return; case EVENT_SYSCALL: debug(1, "event: syscall (%s [%d])", sysname(event->proc, event->e_un.sysnum), event->e_un.sysnum); handle_syscall(event); return; case EVENT_SYSRET: debug(1, "event: sysret (%s [%d])", sysname(event->proc, event->e_un.sysnum), event->e_un.sysnum); handle_sysret(event); return; case EVENT_ARCH_SYSCALL: debug(1, "event: arch_syscall (%s [%d])", arch_sysname(event->proc, event->e_un.sysnum), event->e_un.sysnum); handle_arch_syscall(event); return; case EVENT_ARCH_SYSRET: debug(1, "event: arch_sysret (%s [%d])", arch_sysname(event->proc, event->e_un.sysnum), event->e_un.sysnum); handle_arch_sysret(event); return; case EVENT_CLONE: case EVENT_VFORK: debug(1, "event: clone (%u)", event->e_un.newpid); handle_clone(event); return; case EVENT_EXEC: debug(1, "event: exec()"); handle_exec(event); return; case EVENT_BREAKPOINT: debug(1, "event: breakpoint"); handle_breakpoint(event); return; case EVENT_NEW: debug(1, "event: new process"); handle_new(event); return; default: fprintf(stderr, "Error! unknown event?\n"); exit(1); } }
void main_loop(int return_on_sigret) { /* main_loop returns only if return_on_sigret == 1 && rt_sigreturn is invoked. see also: rt_sigsuspend */ while (task_run() == 0) { /* dump_instr(); */ /* print_regs(); */ uint64_t exit_reason; vmm_read_vmcs(VMCS_RO_EXIT_REASON, &exit_reason); switch (exit_reason) { case VMX_REASON_VMCALL: printk("reason: vmcall\n"); assert(false); break; case VMX_REASON_EXC_NMI: { /* References: * - Intel SDM 27.2.2, Table 24-15: Information for VM Exits Due to Vectored Events */ uint64_t exc_info; vmm_read_vmcs(VMCS_RO_VMEXIT_IRQ_INFO, &exc_info); int int_type = (exc_info & 0x700) >> 8; switch (int_type) { default: assert(false); case VMCS_EXCTYPE_EXTERNAL_INTERRUPT: case VMCS_EXCTYPE_NONMASKTABLE_INTERRUPT: /* nothing we can do, host os handles it */ continue; case VMCS_EXCTYPE_HARDWARE_EXCEPTION: /* including invalid opcode */ case VMCS_EXCTYPE_SOFTWARE_EXCEPTION: /* including break points, overflows */ break; } int exc_vec = exc_info & 0xff; switch (exc_vec) { case X86_VEC_PF: { /* FIXME */ uint64_t gladdr; vmm_read_vmcs(VMCS_RO_EXIT_QUALIFIC, &gladdr); printk("page fault: caused by guest linear address 0x%llx\n", gladdr); send_signal(getpid(), LINUX_SIGSEGV); } case X86_VEC_UD: { uint64_t instlen, rip; vmm_read_vmcs(VMCS_RO_VMEXIT_INSTR_LEN, &instlen); vmm_read_register(HV_X86_RIP, &rip); if (is_syscall(instlen, rip)) { int r = handle_syscall(); vmm_read_register(HV_X86_RIP, &rip); /* reload rip for execve */ vmm_write_register(HV_X86_RIP, rip + 2); if (return_on_sigret && r < 0) { return; } continue; } else if (is_avx(instlen, rip)) { uint64_t xcr0; vmm_read_register(HV_X86_XCR0, &xcr0); if ((xcr0 & XCR0_AVX_STATE) == 0) { unsigned int eax, ebx, ecx, edx; get_cpuid_count(0x0d, 0x0, &eax, &ebx, &ecx, &edx); if (eax & XCR0_AVX_STATE) { vmm_write_register(HV_X86_XCR0, xcr0 | XCR0_AVX_STATE); continue; } } } /* FIXME */ warnk("invalid opcode! (rip = %p): ", (void *) rip); unsigned char inst[instlen]; if (copy_from_user(inst, rip, instlen)) assert(false); for (uint64_t i = 0; i < instlen; ++i) fprintf(stderr, "%02x ", inst[i] & 0xff); fprintf(stderr, "\n"); send_signal(getpid(), LINUX_SIGILL); } case X86_VEC_DE: case X86_VEC_DB: case X86_VEC_BP: case X86_VEC_OF: case X86_VEC_BR: case X86_VEC_NM: case X86_VEC_DF: case X86_VEC_TS: case X86_VEC_NP: case X86_VEC_SS: case X86_VEC_GP: case X86_VEC_MF: case X86_VEC_AC: case X86_VEC_MC: case X86_VEC_XM: case X86_VEC_VE: case X86_VEC_SX: default: /* FIXME */ warnk("exception thrown: %d\n", exc_vec); uint64_t instlen, rip; vmm_read_vmcs(VMCS_RO_VMEXIT_INSTR_LEN, &instlen); vmm_read_register(HV_X86_RIP, &rip); fprintf(stderr, "inst: \n"); unsigned char inst[instlen]; if (copy_from_user(inst, rip, instlen)) assert(false); for (uint64_t i = 0; i < instlen; ++i) fprintf(stderr, "%02x ", inst[i] & 0xff); fprintf(stderr, "\n"); exit(1); /* TODO */ } break; } case VMX_REASON_EPT_VIOLATION: printk("reason: ept_violation\n"); uint64_t gpaddr; vmm_read_vmcs(VMCS_GUEST_PHYSICAL_ADDRESS, &gpaddr); printk("guest-physical address = 0x%llx\n", gpaddr); uint64_t qual; vmm_read_vmcs(VMCS_RO_EXIT_QUALIFIC, &qual); printk("exit qualification = 0x%llx\n", qual); if (qual & (1 << 7)) { uint64_t gladdr; vmm_read_vmcs(VMCS_RO_GUEST_LIN_ADDR, &gladdr); printk("guest linear address = 0x%llx\n", gladdr); int verify = 0; if (qual & (1 << 0)) { verify = VERIFY_READ; } else if (qual & (1 << 1)) { verify = VERIFY_WRITE; } else if (qual & (1 << 2)) { verify = VERIFY_EXEC; } if (!addr_ok(gladdr, verify)) { printk("page fault: caused by guest linear address 0x%llx\n", gladdr); send_signal(getpid(), LINUX_SIGSEGV); } } else { printk("guest linear address = (unavailable)\n"); } break; case VMX_REASON_CPUID: { uint64_t rax; vmm_read_register(HV_X86_RAX, &rax); unsigned eax, ebx, ecx, edx; __get_cpuid(rax, &eax, &ebx, &ecx, &edx); vmm_write_register(HV_X86_RAX, eax); vmm_write_register(HV_X86_RBX, ebx); vmm_write_register(HV_X86_RCX, ecx); vmm_write_register(HV_X86_RDX, edx); uint64_t rip; vmm_read_register(HV_X86_RIP, &rip); vmm_write_register(HV_X86_RIP, rip + 2); break; } case VMX_REASON_IRQ: { break; } case VMX_REASON_HLT: { break; } default: // See: Intel® 64 and IA-32 Architectures Software Developer’s Manual // Volume 3B: System Programming Guide, Part 2 // Order Number: 253669-033US // December 2009 // Section 21.9 VM-EXIT INFORMATION FIELDS // 21.9.1 Basic VM-Exit information // Exit reason if (exit_reason & (1<<31)) { exit_reason ^= (1<<31); printk("VM-entry failure exit reason: %llx\n", exit_reason); } else printk("other exit reason: %llx\n", exit_reason); if (exit_reason & VMX_REASON_VMENTRY_GUEST) check_vm_entry(); vmm_read_vmcs(VMCS_RO_EXIT_QUALIFIC, &qual); printk("exit qualification: %llx\n", qual); } } __builtin_unreachable(); }
word xqt( m6502* m, byte* j, word X ) { word Y = 0; /* INSTRUCTIONS */ if( CI == op_LDA_imm ) { Y++; byte new_a_value = j[X+Y]; #ifdef DEBUG fprintf(stderr, "$%0.4x | LDA:immediate <-- #%0.2x (was #%0.2x)\n", CADD, new_a_value, m->acc); #endif m->acc = new_a_value; Y++; } else if( CI == op_LDA_abs ) { Y++; word addr = ADDRGEN(j[Y],j[++Y]); #ifdef DEBUG fprintf(stderr, "$%0.4x | LDA:absolute <-- (byteAt: %0.4x (=%0.2x))\n", CADD, addr, m->memory[addr]); #endif m->acc = m->memory[addr]; Y++; } else if( CI == op_LDA_abx ) { Y++; word addr = (ADDRGEN(j[Y],j[++Y])) + m->ix; #ifdef DEBUG fprintf(stderr, "$%0.4x | LDA:absolute+x <-- (byteAt: %0.4x (=%0.2x))\n", CADD, addr, m->memory[addr]); #endif m->acc = m->memory[addr]; Y++; } else if( CI == op_LDA_idx ) { Y++; word addr = m->memory[(word)(ADDRGEN(j[Y],j[++Y]))+m->ix]; #ifdef DEBUG fprintf(stderr, "$%0.4x | LDA:indirect+x <-- (byteAt: %0.4x (=%0.2x))\n", CADD, addr, m->memory[addr]); #endif m->acc = m->memory[addr]; Y++; } else if( CI == op_STA_abs ) { Y++; word addr = ADDRGEN( j[CO], j[X+(++Y)]); #ifdef DEBUG fprintf(stderr, "$%0.4x | STA:absolute --> $%4x\n", CADD, addr); #endif if(addr == OUTCHAR_ADDR) m->OUTFLAG=ON; MEM(addr) = m->acc; ++Y; } else if( CI == op_STX_abs ) { Y++; word addr = ADDRGEN( j[CO], j[X+(++Y)]); #ifdef DEBUG fprintf(stderr, "$%0.4x | STX:absolute --> $%4x\n", CADD, addr); #endif if(addr == OUTCHAR_ADDR) m->OUTFLAG=ON; MEM(addr) = m->ix; ++Y; } else if( CI == op_CMP_imm ) { Y++; byte cmp_byte = j[CO]; #ifdef DEBUG fprintf(stderr, "$%0.4x | CMP:immediate #%0.2x = #%0.2x?...\n", CADD, cmp_byte, m->acc ); #endif if( cmp_byte == m->acc ) { m->ZEROFLAG = ON; m->NOTZEROFLAG = OFF; } else if( cmp_byte > m->acc ) { m->NOTZEROFLAG = ON; m->NOTZEROFLAG = OFF; } ++Y; } else if( CI == op_CMP_abs ) { Y++; word cmp_addr = ADDRGEN( j[Y], j[++Y]); byte cmp_byte = MEM(cmp_addr); if( cmp_byte == m->acc ) { m->ZEROFLAG = ON; m->NOTZEROFLAG = OFF; } else if( cmp_byte > m->acc ) { m->NOTZEROFLAG = ON; m->NOTZEROFLAG = OFF; } } else if( CI == op_BNE_rel ) { Y++; #ifdef DEBUG fprintf(stderr,"$%0.4x | BNE:relative <if_branch_addr:=+$%x> ", CADD, j[CO]); #endif if( m->ZEROFLAG == OFF ) { #ifdef DEBUG fprintf(stderr,"-:true; branching to addr: %0.2x...\n", X+Y+j[X+1]+1); #endif Y = X+Y+j[X+1]+1; X = 0; m->DID_CMP = OFF; return Y; } else { #ifdef DEBUG fprintf(stderr,"-:false; no_branch_taken"); #endif Y++; } #ifdef DEBUG fprintf(stderr,"\n"); #endif } else if( CI == op_BEQ_rel ) { Y++; #ifdef DEBUG fprintf(stderr,"$%0.4x | BEQ:relative <if_branch_addr:=$%0.2x> ", CADD, j[CO]); #endif if( m->ZEROFLAG == ON ) { #ifdef DEBUG fprintf(stderr, "-: branching>\n"); #endif Y=X+Y+j[X+1]+1; X=0; m->DID_CMP = OFF; return Y; } else { #ifdef DEBUG fprintf(stderr,"-/no_branch\n"); #endif } } else if( CI == op_DEC_abs ) { word addr = ADDRGEN( j[X+(++Y)], j[X+(++Y)] ); #ifdef DEBUG fprintf(stderr,"$%0.4x | INC:absolute_addr:$%0.4x! %0.2x => %0.2x\n", CADD, addr, MEM(addr), MEM(addr)-1); #endif if(addr == OUTCHAR_ADDR) m->OUTFLAG=ON; MEM(addr) -= 1; } else if( CI == op_INC_abs ) { word addr = ADDRGEN( j[X+(++Y)], j[X+(++Y)] ); #ifdef DEBUG fprintf(stderr,"$%0.4x | INC:absolute_addr:$%0.4x! #%0.2x => #%0.2x\n", CADD, addr, MEM(addr), MEM(addr)+1); #endif MEM(addr) += 1; } else if( CI == op_INX ) { #ifdef DEBUG fprintf(stderr,"$%0.4x | INX; x := #%0.2x -> #%0.2x\n", CADD, m->ix, m->ix+1 ); #endif m->ix += 1; } else if( CI == op_JMP_abs ) /* absolute (immediate) */ { word addr = ADDRGEN( j[X+(++Y)], j[X+(++Y)] ); #ifdef DEBUG fprintf(stderr,"$%0.4x | JMP:absolute_addr ------> jump_to:$%0.4x\n", CADD, addr); #endif X = addr; Y = 0; return addr; } else if( CI == op_JMP_ind ) /*indirect*/ { word addr_addr = ADDRGEN( j[X+(++Y)], j[X+(++Y)] ); word addr = MEM(addr_addr); #ifdef DEBUG fprintf(stderr,"$%0.4x | JMP:indirection! jump_to_value_of:$%0.4x (-*=>$%0.4x)\n", CADD, addr_addr, addr); #endif X = addr; Y = 0; return addr; } else if( CI == op_DIE ) { #ifdef DEBUG fprintf(stderr,"$%0.4x | EXIT\n", CADD); #endif return 0xFFFF; } /* IRQ handling!*/ else if( CI == op_BRK ) { m->stack_ptr++; m->stack[m->stack_ptr] = j[X+Y]; handle_syscall(m); } /* HANDLE OUTCHAR */ if( m->OUTFLAG == ON ) { #ifdef DEBUG fprintf(stderr, "$%0.4x | POLL_OUTCHAR_FOUND: '%c'\n", CO, m->memory[OUTCHAR_ADDR]); #else fputc(MEM(OUTCHAR_ADDR), stdout); #endif m->OUTFLAG=OFF; } /* HANDLE SYNC */ if( DOES_WAIT == 1 ) usleep(1000000/CPS); m->pc = X+Y; if(Y==0) Y=1; return Y+X; }
void execute_one_inst(processor_t* p, int prompt, int print_regs) { inst_t inst; /* fetch an instruction */ inst.bits = load_mem(p->pc, SIZE_WORD); /* interactive-mode prompt */ if(prompt) { if (prompt == 1) { printf("simulator paused, enter to continue..."); while(getchar() != '\n') ; } printf("%08x: ",p->pc); disassemble(inst); } switch (inst.rtype.opcode) /* could also use e.g. inst.itype.opcode */ { case 0x0: // opcode == 0x0 (SPECIAL) switch (inst.rtype.funct) { case 0x0: //opcode = 0x0 (SLL) p->R[inst.rtype.rd] = p->R[inst.rtype.rt] << inst.rtype.shamt; p->pc += 4; break; case 0x2: //opcode = 0x2 (SRL) p->R[inst.rtype.rd] = p->R[inst.rtype.rt] >> inst.rtype.shamt; p->pc += 4; break; case 0x3: //opcode = 0x3 (SRA) p->R[inst.rtype.rd] = (signed int)(p->R[inst.rtype.rt]) >> inst.rtype.shamt; p->pc += 4; break; case 0x8: //opcode = 0x8 (JR) p->pc = p->R[inst.rtype.rs]; break; case 0x9: //opcode = 0x9 (JALR) { int tmp = p->pc + 4; p->pc = p->R[inst.rtype.rs]; p->R[inst.rtype.rd] = tmp; } break; case 0xc: // funct == 0xc (SYSCALL) handle_syscall(p); p->pc += 4; break; case 0x21: //opcode = 0x21 (ADDU) p->R[inst.rtype.rd] = p->R[inst.rtype.rs] + p->R[inst.rtype.rt]; p->pc += 4; break; case 0x23: //opcode = 0x23 (SUBU) p->R[inst.rtype.rd] = p->R[inst.rtype.rs] - p->R[inst.rtype.rt]; p->pc += 4; break; case 0x24: //opcode = 0x24 (AND) p->R[inst.rtype.rd] = p->R[inst.rtype.rs] & p->R[inst.rtype.rt]; p->pc += 4; break; case 0x25: // funct == 0x25 (OR) p->R[inst.rtype.rd] = p->R[inst.rtype.rs] | p->R[inst.rtype.rt]; p->pc += 4; break; case 0x26: // funct == 0x26 (XOR) p->R[inst.rtype.rd] = p->R[inst.rtype.rs] ^ p->R[inst.rtype.rt]; p->pc += 4; break; case 0x27: // funct == 0x27 (NOR) p->R[inst.rtype.rd] = ~(p->R[inst.rtype.rs] ^ p->R[inst.rtype.rt]); p->pc += 4; break; case 0x2a: // funct == 0x2a (SLT) p->R[inst.rtype.rd] = (signed int)(p->R[inst.rtype.rs]) < (signed int)(p->R[inst.rtype.rt]); p->pc += 4; break; case 0x2b: // funct == 0x2b (SLTU) p->R[inst.rtype.rd] = p->R[inst.rtype.rs] < p->R[inst.rtype.rt]; p->pc += 4; break; default: // undefined funct fprintf(stderr, "%s: pc=%08x, illegal instruction=%08x\n", __FUNCTION__, p->pc, inst.bits); exit(-1); break; } break; case 0x2: // opcode == 0x2 (J) p->pc = ((p->pc+4) & 0xf0000000) | (inst.jtype.addr << 2); break; case 0x3: // opcode == 0x3 (JAL) p->R[31] = p->pc + 4; p->pc = ((p->pc+4) & 0xf0000000) | (inst.jtype.addr << 2); break; case 0x4: // opcode == 0x4 (BEQ) if (p->R[inst.itype.rs] == p->R[inst.itype.rt]) { p->pc += (4 + (((int16_t)inst.itype.imm) << 2)); } else { p->pc += 4; } break; case 0x5: // opcode == 0x5 (BNE) if (p->R[inst.itype.rs] != p->R[inst.itype.rt]) { p->pc += (4 + (((int16_t)inst.itype.imm) << 2)); } else { p->pc += 4; } break; case 0x9: // opcode == 0x9 (ADDIU) p->R[inst.itype.rt] = p->R[inst.itype.rs] + (int16_t)(inst.itype.imm); p->pc += 4; break; case 0xa: // opcode == 0xa (SLTI) p->R[inst.itype.rt] = (signed int)p->R[inst.itype.rs] < (int16_t)(inst.itype.imm); p->pc += 4; break; case 0xb: // opcode == 0xb (SLTIU) p->R[inst.itype.rt] = p->R[inst.itype.rs] < (int16_t)(inst.itype.imm); p->pc += 4; break; case 0xc: // opcode == 0xc (ANDI) p->R[inst.itype.rt] = p->R[inst.itype.rs] & inst.itype.imm; p->pc += 4; break; case 0xd: // opcode == 0xd (ORI) p->R[inst.itype.rt] = p->R[inst.itype.rs] | inst.itype.imm; p->pc += 4; break; case 0xe: // opcode == 0xe (XORI) p->R[inst.itype.rt] = p->R[inst.itype.rs] ^ inst.itype.imm; p->pc += 4; break; case 0xf: // opcode == 0xf (LUI) p->R[inst.itype.rt] = inst.itype.imm << 16; p->pc += 4; break; case 0x20: // opcode == 0x20 (LB) p->R[inst.itype.rt] = (int8_t)(load_mem(p->R[inst.itype.rs] + (int16_t)(inst.itype.imm), SIZE_BYTE)); p->pc += 4; break; case 0x21: // opcode == 0x21 (LH) p->R[inst.itype.rt] = (int16_t)(load_mem(p->R[inst.itype.rs] + (int16_t)(inst.itype.imm), SIZE_HALF_WORD)); p->pc += 4; break; case 0x23: // opcode == 0x23 (LW) p->R[inst.itype.rt] = (int32_t)load_mem(p->R[inst.itype.rs] + (int16_t)(inst.itype.imm), SIZE_WORD); p->pc += 4; break; case 0x24: // opcode == 0x24 (LBU) p->R[inst.itype.rt] = load_mem(p->R[inst.itype.rs] + (int16_t)(inst.itype.imm), SIZE_BYTE); p->pc += 4; break; case 0x25: // opcode == 0x25 (LHU) p->R[inst.itype.rt] = load_mem(p->R[inst.itype.rs] + (int16_t)(inst.itype.imm), SIZE_HALF_WORD); p->pc += 4; break; case 0x28: // opcode == 0x28 (SB) store_mem(p->R[inst.itype.rs] + (int16_t)(inst.itype.imm), SIZE_BYTE, p->R[inst.itype.rt]); p->pc += 4; break; case 0x29: // opcode == 0x29 (SH) store_mem(p->R[inst.itype.rs] + (int16_t)(inst.itype.imm), SIZE_HALF_WORD, p->R[inst.itype.rt]); p->pc += 4; break; case 0x2b: // opcode == 0x2b (SW) store_mem(p->R[inst.itype.rs] + (int16_t)(inst.itype.imm), SIZE_WORD, p->R[inst.itype.rt]); p->pc += 4; break; default: // undefined opcode fprintf(stderr, "%s: pc=%08x, illegal instruction: %08x\n", __FUNCTION__, p->pc, inst.bits); exit(-1); break; } // enforce $0 being hard-wired to 0 p->R[0] = 0; if(print_regs) print_registers(p); }
int vm_event(vm_t* vm, seL4_MessageInfo_t tag) { seL4_Word label; seL4_Word length; label = seL4_MessageInfo_get_label(tag); length = seL4_MessageInfo_get_length(tag); switch (label) { case SEL4_PFIPC_LABEL: { int err; fault_t* fault; fault = vm->fault; err = new_fault(fault); assert(!err); do { err = handle_page_fault(vm, fault); if (err) { return -1; } } while (!fault_handled(fault)); } break; case SEL4_EXCEPT_IPC_LABEL: { int err; assert(length == SEL4_EXCEPT_IPC_LENGTH); err = handle_syscall(vm, length); assert(!err); if (!err) { seL4_MessageInfo_t reply; reply = seL4_MessageInfo_new(0, 0, 0, 0); seL4_Reply(reply); } } break; case SEL4_USER_EXCEPTION_LABEL: { seL4_Word ip; int err; assert(length == SEL4_USER_EXCEPTION_LENGTH); ip = seL4_GetMR(0); err = handle_exception(vm, ip); assert(!err); if (!err) { seL4_MessageInfo_t reply; reply = seL4_MessageInfo_new(0, 0, 0, 0); seL4_Reply(reply); } } break; case SEL4_VGIC_MAINTENANCE_LABEL: { int idx; int err; assert(length == SEL4_VGIC_MAINTENANCE_LENGTH); idx = seL4_GetMR(EXCEPT_IPC_SYS_MR_R0); /* Currently not handling spurious IRQs */ assert(idx >= 0); err = handle_vgic_maintenance(vm, idx); assert(!err); if (!err) { seL4_MessageInfo_t reply; reply = seL4_MessageInfo_new(0, 0, 0, 0); seL4_Reply(reply); } } break; case SEL4_VCPU_FAULT_LABEL: { seL4_MessageInfo_t reply; seL4_UserContext regs; seL4_CPtr tcb; uint32_t hsr; int err; assert(length == SEL4_VCPU_FAULT_LENGTH); hsr = seL4_GetMR(EXCEPT_IPC_SYS_MR_R0); /* Increment the PC and ignore the fault */ tcb = vm_get_tcb(vm); err = seL4_TCB_ReadRegisters(tcb, false, 0, sizeof(regs) / sizeof(regs.pc), ®s); assert(!err); switch (hsr) { case HSR_WFI: case HSR_WFE: regs.pc += (regs.cpsr & BIT(5)) ? 2 : 4; err = seL4_TCB_WriteRegisters(tcb, false, 0, sizeof(regs) / sizeof(regs.pc), ®s); assert(!err); reply = seL4_MessageInfo_new(0, 0, 0, 0); seL4_Reply(reply); return 0; default: printf("Unhandled VCPU fault from [%s]: HSR 0x%08x\n", vm->name, hsr); print_ctx_regs(®s); return -1; } } break; default: /* What? Why are we here? What just happened? */ printf("Unknown fault from [%s]: label=0x%x length=0x%x\n", vm->name, label, length); return -1; } return 0; }
void execute_one_inst(processor_t* p, int prompt, int print_regs) { inst_t inst; /* fetch an instruction */ inst.bits = load_mem(p->pc, SIZE_WORD); /* interactive-mode prompt */ if(prompt) { if (prompt == 1) { printf("simulator paused, enter to continue..."); while(getchar() != '\n') ; } printf("%08x: ",p->pc); disassemble(inst); } uint32_t temp; switch (inst.rtype.opcode) /* could also use e.g. inst.itype.opcode */ { case 0x0: // opcode == 0x0 (SPECIAL) switch (inst.rtype.funct) { case 0x0: // funct == 0x0 (sll) p->R[inst.rtype.rd] = p->R[inst.rtype.rt] << inst.rtype.shamt; p->pc += 4; break; case 0x2: // funct == 0x0 (srl) p->R[inst.rtype.rd] = p->R[inst.rtype.rt] >> inst.rtype.shamt; p->pc += 4; break; case 0x3: // funct == 0x0 (sra) p->R[inst.rtype.rd] = (signed)p->R[inst.rtype.rt] >> inst.rtype.shamt; p->pc += 4; break; case 0x8: // funct == 0x8 (jr) p->pc = p->R[inst.rtype.rs]; break; case 0x9: // funct == 0x9 (jalr) temp = p->pc + 4; p->pc = p->R[inst.rtype.rs]; p->R[inst.rtype.rd] = temp; break; case 0x10: // funct == 0x10 (mfhi) p->R[inst.rtype.rd] = p->RHI; p->pc += 4; break; case 0x12: // funct == 0x12 (mflo) p->R[inst.rtype.rd] = p->RLO; p->pc += 4; break; case 0x18: // funct == 0x18 (mult) perform_mult(p->R[inst.rtype.rs], p->R[inst.rtype.rt], &(p->RHI), &(p->RLO)); p->pc += 4; break; case 0x21: // funct == 0x21 (addu) p->R[inst.rtype.rd] = p->R[inst.rtype.rs] + p->R[inst.rtype.rt]; p->pc += 4; break; case 0x23: // funct == 0x23 (subu) p->R[inst.rtype.rd] = p->R[inst.rtype.rs] - p->R[inst.rtype.rd]; p->pc += 4; break; case 0x24: // funct == 0x24 (and) p->R[inst.rtype.rd] = p->R[inst.rtype.rs] & p->R[inst.rtype.rt]; p->pc += 4; break; case 0x26: // funct == 0x26 (xor) p->R[inst.rtype.rd] = p->R[inst.rtype.rs] ^ p->R[inst.rtype.rt]; p->pc += 4; break; case 0x27: // funct == 0x27 (nor) p->R[inst.rtype.rd] = ~(p->R[inst.rtype.rs] | p->R[inst.rtype.rt]); p->pc += 4; break; case 0x2a: // funct == 0x2a (slt) p->R[inst.rtype.rd] = (signed)p->R[inst.rtype.rs] < (signed)p->R[inst.rtype.rt]; p->pc += 4; break; case 0x2b: // funct == 0x2a (sltu) p->R[inst.rtype.rd] = p->R[inst.rtype.rs] < p->R[inst.rtype.rt]; p->pc += 4; break; case 0xc: // funct == 0xc (SYSCALL) handle_syscall(p); p->pc += 4; break; case 0x25: // funct == 0x25 (OR) p->R[inst.rtype.rd] = p->R[inst.rtype.rs] | p->R[inst.rtype.rt]; p->pc += 4; break; default: // undefined funct fprintf(stderr, "%s: pc=%08x, illegal instruction=%08x\n", __FUNCTION__, p->pc, inst.bits); exit(-1); break; } break; case 0x3: // opcode == 0x3 (jal) p->R[31] = p->pc += 4; p->pc = ((p->pc+4) & 0xf0000000) | (inst.jtype.addr << 2); break; case 0x4: // opcode == 0x4 (beq) if (p->R[inst.itype.rs] == p->R[inst.itype.rt]) { p->pc += 4 + signext(inst.itype.imm)*4; } else { p->pc += 4; } break; case 0x5: // opcode == 0x4 (bne) if (p->R[inst.itype.rs] != p->R[inst.itype.rt]) { p->pc += 4 + signext(inst.itype.imm)*4; } else { p->pc += 4; } break; case 0x9: // opcode == 0x9 (addiu) p->R[inst.rtype.rt] = p->R[inst.itype.rs] + signext(inst.itype.imm); p->pc += 4; break; case 0xa: // opcode == 0xa (slti) p->R[inst.itype.rt] = (signed)p->R[inst.itype.rs] < signext(inst.itype.imm); p->pc += 4; break; case 0xb: // opcode == 0xb (sltiu) p->R[inst.rtype.rt] = (signed)p->R[inst.itype.rs] < signext(inst.itype.imm); p->pc += 4; break; case 0xc: // opcode == 0xc (andi) p->R[inst.rtype.rt] = p->R[inst.itype.rs] & zeroext(inst.itype.imm); p->pc += 4; break; case 0xe: // opcode == 0xe (xori) p->R[inst.rtype.rt] = p->R[inst.itype.rs] ^ zeroext(inst.itype.imm); p->pc += 4; break; case 0xf: // opcode == 0xf (lui) p->R[inst.rtype.rt] = inst.itype.imm << 16; p->pc += 4; break; case 0x20: // opcode == 0x20 (lb) p->R[inst.rtype.rt] = signext(load_mem(p->R[inst.itype.rs] + signext(inst.itype.imm), SIZE_BYTE)); p->pc += 4; break; case 0x23: // opcode == 0x23 (lw) p->R[inst.rtype.rt] = load_mem(p->R[inst.itype.rs] + signext(inst.itype.imm), SIZE_WORD); p->pc += 4; break; case 0x24: // opcode == 0x24 (lbu) p->R[inst.itype.rt] = zeroext(load_mem(p->R[inst.itype.rs] + signext(inst.itype.imm), SIZE_WORD)); p->pc += 4; break; case 0x28: // opcode == 0x28 (sb) store_mem(p->R[inst.itype.rs] + signext(inst.itype.imm), SIZE_BYTE, p->R[inst.itype.rt]); p->pc += 4; break; case 0x2b: // opcode == 0x20 (sw) store_mem(p->R[inst.itype.rs] + signext(inst.itype.imm), SIZE_WORD, p->R[inst.itype.rt]); p->pc += 4; break; case 0xd: // opcode == 0xd (ORI) p->R[inst.itype.rt] = (p->R[inst.itype.rs] | inst.itype.imm); p->pc += 4; break; case 0x2: // opcode == 0x2 (J) p->pc = ((p->pc+4) & 0xf0000000) | (inst.jtype.addr << 2); break; default: // undefined opcode fprintf(stderr, "%s: pc=%08x, illegal instruction: %08x\n", __FUNCTION__, p->pc, inst.bits); exit(-1); break; } // enforce $0 being hard-wired to 0 p->R[0] = 0; if(print_regs) { print_registers(p); } }