void debugger(void) { extern u_int history[3]; extern int irq0_pending; static int in_debugger = 0; char buf[80], buf2[80], reg[4]; u_int i, j, k; if (in_debugger) return; in_debugger ++; no_exceptions = 1; #if 0 char *textbuf; textbuf = (char*)malloc(TEXT_SIZE); if (!textbuf) { leaveemu(ERR_MEM); } memcpy(textbuf, SCR_STATE.virt_address, TEXT_SIZE); #endif push_debug_flags(); DEBUG_OFF(); for(;;) { printf("\ndbg> "); if (fgets(buf, 80, stdin) == NULL) leaveemu(0); buf[strlen(buf)-1] = 0; /* kill \n */ if (*buf==0) { continue; } else if (!strcmp(buf, "help")) { usage(); } else if (!strcmp(buf, "r")) { show_regs(0, 0); } else if (!strcmp(buf, "logue")) { printf("prologue: 0x%08x\n", UAREA.u_entprologue); printf("epilogue: 0x%08x\n", UAREA.u_entepilogue); } else if (!strcmp(buf, "exc")) { printf("current exception: #0x%x, 0x%x\n", vm86s.trapno, vm86s.err); printf("pending guest exception: "); if (vmstate.exc) printf("#0x%x, 0x%x\n", vmstate.exc_vect, vmstate.exc_erc); else printf("none\n"); } else if (!strcmp(buf, "cr")) { show_cregs(); } else if (!strcmp(buf, "g")) { REG(eflags) &= ~TF_MASK; break; } else if (!strcmp(buf, "q") || !strcmp(buf, "quit")) { leaveemu(0); } else if (!strcmp(buf, "disks")) { print_disks(); } else if (!strcmp(buf, "ptmap")) { /* everything is in k to avoid overflows */ u_int granularity = 4*1024; u_int width = 64; printf("granularity: 0x%08x\n", granularity*1024); for (i=0; i < (4*1024*1024)/(width*granularity); i++) { u_int start = i*width*granularity; printf("0x%08x ", start*1024); for (j=0; j<width; j++) { int gp = 0, hp = 0; for (k=0; k < granularity/NBPG; k++) { u_int pte, err=0; pte = sys_read_pte(k*NBPG + (j*granularity + i*width*granularity)*1024, 0, vmstate.eid, &err); if (err == -E_NOT_FOUND) { err = pte = 0; } if (err == 0) { if (pte&1) { if (pte & PG_GUEST) gp = 1; else hp = 1; } } } if (!gp && !hp) printf("-"); else if (gp && hp) printf("+"); else if (gp && !hp) printf("g"); else printf("h"); } printf("\n"); } #if 0 } else if (!strcmp(buf, "memmap")) { memcheck_dump(); #endif } else if (sscanf(buf, "port %x", &i) == 1) { print_port(i); } else if (sscanf(buf, "int %x", &i) == 1) { pop_debug_flags(); push_debug_flags(); no_exceptions = 0; do_int(i); no_exceptions = 1; DEBUG_OFF(); } else if (sscanf(buf, "gdt %x", &i) == 1) { struct descr *sd; if (set_get_any(&vmstate.g_gdt_base, (u_int*)&sd)) { printf("no gdt is defined\n"); continue; } print_dt_entry(i, sd); } else if (sscanf(buf, "idt %x", &i) == 1) { print_dt_entry(i, (struct descr *)vmstate.g_idt_base); } else if (sscanf(buf, "ro %x", &i) == 1) { protect_range(PGROUNDDOWN(i), NBPG); } else if (sscanf(buf, "rw %x", &i) == 1) { unprotect_range(PGROUNDDOWN(i), NBPG); } else if (!strcmp(buf, "history")) { printf("most recent trap eip: %x %x %x\n", history[2], history[1], history[0]); } else if (!strcmp(buf, "irq")) { struct gate_descr *sg = (struct gate_descr *)vmstate.g_idt_base + hardware_irq_number(0); for (i=0; i<16; i++) { printf("irq %2d %s, handled by idt[%2d], function @ 0x%08x\n", i, irq_disabled(i) ? "disabled" : " enabled", hardware_irq_number(i), GATE_OFFSET(sg+i)); } } else if (sscanf(buf, "dump %x:%x %x", &i, &j, &k) == 2) { dump_memory((i<<4)+j, k); } else if (sscanf(buf, "dump %x:%x", &i, &j) == 2) { dump_memory((i<<4)+j, 0x80); } else if (sscanf(buf, "dump %x %x", &i, &j) == 2) { dump_memory(i, j); } else if (sscanf(buf, "dump %x", &i) == 1) { dump_memory(i, 0x80); } else if (!strcmp(buf, "dump")) { dump_memory(dump_offset, 0x80); } else if (sscanf(buf, "search %x %79s", &i, buf2) == 2) { search_memory(i, buf2); } else if (!strcmp(buf, "debug on")) { pop_debug_flags(); DEBUG_ON(); push_debug_flags(); } else if (!strcmp(buf, "debug off")) { pop_debug_flags(); DEBUG_OFF(); push_debug_flags(); } else if (sscanf(buf, "pte %x", &i) == 1) { Bit32u host_pte = 0; if (! (vmstate.cr[0] & PG_MASK)) { printf("guest paging not enabled\n"); printf("guest_phys_to_host_phys(0x%08x) = 0x%08x\n", i, guest_phys_to_host_phys(i)); } else { Bit32u gpte = guest_pte(i); printf("guest cr3 0x%08x\n", vmstate.cr[3]); printf("guest 0x%08x -> 0x%08x\n", i, gpte); printf("guest_phys_to_host_phys(0x%08x) = 0x%08x\n", gpte & ~PGMASK, guest_phys_to_host_phys(gpte & ~PGMASK)); } get_host_pte(i, &host_pte); printf("host 0x%08x -> 0x%08x\n", i, host_pte); } else if (sscanf(buf, "gp2hp %x", &i) == 1) { printf("&vmstate.gp2hp[0] = %p, 0x%x mappings\n", vmstate.gp2hp, vmstate.ppages); if (i<vmstate.ppages) printf("gp2hp[%x] = 0x%08x\n", i, vmstate.gp2hp[i]); } else if (!strcmp(buf, "cr3")) { u_int cr3; Set *set = &vmstate.cr3; printf("cr3 register: 0x%08x\n", vmstate.cr[3]); printf("cr3 set : "); for(set_iter_init(set); set_iter_get(set, &cr3); set_iter_next(set)) { printf("0x%08x ", cr3); } printf("\n"); } else if (!strcmp(buf, "dt")) { print_dt_mappings(); printf("h gdt base:lim 0x%08x:0x%04x\n", vmstate.h_gdt_base, vmstate.h_gdt_limit); printf("h idt base:lim 0x%08x:0x%04x\n", vmstate.h_idt_base, vmstate.h_idt_limit); } else if (!strcmp(buf, "memory")) { printf("0x%08x real physical pages (%3d megs)\n", PHYSICAL_PAGES, PHYSICAL_MEGS_RAM); printf("0x%08x fake physical pages (%3d megs)\n", vmstate.ppages, config.phys_mem_size/1024); #if 0 printf("Eavesdropping on Linux:\n"); printf("RAM %dk\n", *((Bit32u*)0x901e0)); printf("pointing device? 0x%x\n", *((Bit16u*)0x901ff)); printf("APM? 0x%x\n", *((Bit16u*)0x90040)); #endif ASSERT(vmstate.ppages == config.phys_mem_size*1024/NBPG); } else if (sscanf(buf, "%2s=%x", reg, &i) == 2 || sscanf(buf, "%3s=%x", reg, &i) == 2) { int r = reg_s2i(reg); if (r == -1) { printf("unknown register\n"); } else if (r==14) { REG(eip) = i; } else if (r<=REGNO_EDI) { set_reg(r, i, 4); /* normal regs */ } else { set_reg(r, i, 2); /* segment regs */ } } else { printf("huh?\n"); } } pop_debug_flags(); #if 0 if (debug_flags == 0) memcpy(SCR_STATE.virt_address, textbuf, TEXT_SIZE); free(textbuf); #endif REG(eflags) |= RF; in_debugger --; no_exceptions = 0; irq0_pending = 0; }
/* load an EXOS_MAGIC binary */ int __do_simple_load (int fd, struct Env *e) { // struct Uenv cu; u_int start_text_addr, start_text_pg; struct exec hdr; u_int text_size, data_size, bss_size, overlap_size; u_int envid = e->env_id; /* read a.out headers */ if (lseek(fd, 0, SEEK_SET) == -1 || read(fd, &hdr, sizeof(hdr)) != sizeof(hdr) || lseek(fd, sizeof(hdr) + hdr.a_text, SEEK_SET) == -1 || read(fd, &start_text_addr, sizeof(start_text_addr)) != sizeof(start_text_addr)) { errornf("Invalid executable format.\n"); } start_text_pg = PGROUNDDOWN(start_text_addr); text_size = hdr.a_text + sizeof(hdr); data_size = hdr.a_data; if (text_size % NBPG) { data_size += text_size % NBPG; text_size = PGROUNDDOWN(text_size); } bss_size = hdr.a_bss; if (!(data_size % NBPG)) overlap_size = 0; else { /* read in the page that contains both bss and inited data */ u_int temp_page; temp_page = (u_int)__malloc(NBPG); overlap_size = NBPG; if (temp_page == 0 || lseek(fd, text_size + PGROUNDDOWN(data_size), SEEK_SET) == -1 || read(fd, (void*)temp_page, data_size % NBPG) != data_size % NBPG || _exos_insert_pte (0, vpt[PGNO(temp_page)], start_text_pg + text_size + PGROUNDDOWN(data_size), 0, envid, 0, NULL) != 0) { _exos_self_unmap_page(0, temp_page); error("Error mmaping text segment\n"); } bzero((void*)temp_page + (data_size % NBPG), NBPG - (data_size % NBPG)); _exos_self_unmap_page(0, temp_page); __free((void*)temp_page); bss_size -= NBPG - (data_size % NBPG); bss_size = PGROUNDUP(bss_size); data_size = PGROUNDDOWN(data_size); } /* mmap the text segment readonly */ if ((u_int)__mmap((void*)start_text_pg, text_size, PROT_READ | PROT_EXEC, MAP_FILE | MAP_FIXED | MAP_COPY, fd, (off_t)0, 0, envid) != start_text_pg) { errornf("Error mmaping text segment\n"); } /* mmap the data segment read/write */ if ((u_int)__mmap((void*)(start_text_pg + text_size), data_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FILE | MAP_FIXED | MAP_COPY, fd, text_size, (off_t)0, envid) != start_text_pg + text_size) { errornf("Error mmaping data segment\n"); } #if 0 /* we set up a stack page later on when setting up arguments */ /* allocate a stack page */ if (_exos_insert_pte (0, PG_U|PG_W|PG_P, USTACKTOP-NBPG, 0, envid, 0, NULL) < 0) { errornf("could not allocate stack\n"); } #endif /* set the entry point */ assert(e->env_id == envid); e->env_tf.tf_eip = start_text_addr; return 1; }
//PAGEBREAK: 41 void trap(struct trapframe *tf) { if(tf->trapno == T_SYSCALL){ if(proc->killed) exit(); proc->tf = tf; syscall(); if(proc->killed) exit(); return; } switch(tf->trapno){ case T_IRQ0 + IRQ_TIMER: if(cpu->id == 0){ acquire(&tickslock); ticks++; wakeup(&ticks); release(&tickslock); } lapiceoi(); break; case T_IRQ0 + IRQ_IDE: ideintr(); lapiceoi(); break; case T_IRQ0 + IRQ_IDE+1: // Bochs generates spurious IDE1 interrupts. break; case T_IRQ0 + IRQ_KBD: kbdintr(); lapiceoi(); break; case T_IRQ0 + IRQ_COM1: uartintr(); lapiceoi(); break; case T_IRQ0 + 7: case T_IRQ0 + IRQ_SPURIOUS: cprintf("cpu%d: spurious interrupt at %x:%x\n", cpu->id, tf->cs, tf->eip); lapiceoi(); break; //PAGEBREAK: 13 default: if(proc == 0 || (tf->cs&3) == 0){ // In kernel, it must be our mistake. cprintf("unexpected trap %d from cpu %d eip %x (cr2=0x%x)\n", tf->trapno, cpu->id, tf->eip, rcr2()); panic("trap"); } if(tf->trapno == T_PGFLT){ char * mem; uint a; a = PGROUNDDOWN(rcr2()); if(a >= KERNBASE){ proc->killed = 1; break; } if(proc->sz >= KERNBASE){ return 0; } if(proc->sz < proc->old_sz) return proc->old_sz; mem = kalloc(); if(mem == 0){ cprintf("trap - pagefault: out of memory\n"); deallocuvm(proc->pgdir, proc->old_sz,proc->sz); break; } //clean the page memset(mem, 0, PGSIZE); mappages(proc->pgdir, (char*) a, PGSIZE, v2p(mem), PTE_W | PTE_U); break; } // In user space, assume process misbehaved. cprintf("pid %d %s: trap %d err %d on cpu %d " "eip 0x%x addr 0x%x--kill proc\n", proc->pid, proc->name, tf->trapno, tf->err, cpu->id, tf->eip, rcr2()); proc->killed = 1; } // Force process exit if it has been killed and is in user space. // (If it is still executing in the kernel, let it keep running // until it gets to the regular system call return.) if(proc && proc->killed && (tf->cs&3) == DPL_USER) exit(); // Force process to give up CPU on clock tick. // If interrupts were on while locks held, would need to check nlock. if(proc && proc->state == RUNNING && tf->trapno == T_IRQ0+IRQ_TIMER) yield(); // Check if the process has been killed since we yielded if(proc && proc->killed && (tf->cs&3) == DPL_USER) exit(); }
u_int __load_prog_fd(int fd, int _static, u_int envid) { u_int start_text_addr; struct exec hdr; u_int text_size, data_size, bss_size, overlap_size; u_int dynamic, start_text_pg; /* read a.out headers */ if (lseek(fd, 0, SEEK_SET) == -1 || read(fd, &hdr, sizeof(hdr)) != sizeof(hdr) || lseek(fd, sizeof(hdr) + hdr.a_text, SEEK_SET) == -1 || read(fd, &dynamic, sizeof(dynamic)) != sizeof(dynamic) || read(fd, &start_text_addr, sizeof(start_text_addr)) != sizeof(start_text_addr)) { fprintf(stderr,"Invalid executable format.\n"); errno = ENOEXEC; goto err; } start_text_pg = PGROUNDDOWN(start_text_addr); text_size = hdr.a_text + sizeof(hdr); data_size = hdr.a_data; if (text_size % NBPG) { data_size += text_size % NBPG; text_size = PGROUNDDOWN(text_size); } bss_size = hdr.a_bss; if (_static) { if (!(data_size % NBPG)) overlap_size = 0; else { /* read in the page that contains both bss and inited data */ u_int temp_page; temp_page = (u_int)__malloc(NBPG); overlap_size = NBPG; if (temp_page == 0 || lseek(fd, text_size + PGROUNDDOWN(data_size), SEEK_SET) == -1 || read(fd, (void*)temp_page, data_size % NBPG) != data_size % NBPG || _exos_insert_pte(0, vpt[PGNO(temp_page)], start_text_pg + text_size + PGROUNDDOWN(data_size), 0, envid, 0, NULL) != 0) { _exos_self_unmap_page(0, temp_page); __free((void*)temp_page); fprintf(stderr,"Error mmaping text segment\n"); goto err; } bzero((void*)temp_page + (data_size % NBPG), NBPG - (data_size % NBPG)); _exos_self_unmap_page(0, temp_page); __free((void*)temp_page); bss_size -= NBPG - (data_size % NBPG); bss_size = PGROUNDUP(bss_size); data_size = PGROUNDDOWN(data_size); } /* mmap the text segment readonly */ if ((u_int)__mmap((void*)start_text_pg, text_size, PROT_READ | PROT_EXEC, MAP_FILE | MAP_FIXED | MAP_COPY, fd, (off_t)0, 0, envid) != start_text_pg) { fprintf(stderr,"Error mmaping text segment\n"); goto err; } /* mmap the data segment read/write */ if ((u_int)__mmap((void*)(start_text_pg + text_size), data_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FILE | MAP_FIXED | MAP_COPY, fd, text_size, (off_t)0, envid) != start_text_pg + text_size) { fprintf(stderr,"Error mmaping data segment\n"); goto err; } } else { /* if dynamic... */ u_int mflags; if (!(data_size % NBPG)) overlap_size = 0; else { /* read in the page that contains both bss and inited data */ overlap_size = NBPG; if (_exos_self_insert_pte(0, PG_P | PG_W | PG_U, start_text_pg + text_size + PGROUNDDOWN(data_size), 0, NULL) < 0 || lseek(fd, text_size + PGROUNDDOWN(data_size), SEEK_SET) == -1 || read(fd, (void*)(start_text_pg + text_size + PGROUNDDOWN(data_size)), data_size % NBPG) != data_size % NBPG) { fprintf(stderr,"Error mmaping text segment\n"); goto err; } bzero((void*)(start_text_pg + text_size + data_size), NBPG - (data_size % NBPG)); bss_size -= NBPG - (data_size % NBPG); bss_size = PGROUNDUP(bss_size); data_size = PGROUNDDOWN(data_size); } /* mmap the text segment readonly */ mflags = MAP_FILE | MAP_FIXED; if (getenv("NO_DEMAND_LOAD")) mflags |= MAP_COPY; else mflags |= MAP_SHARED; if ((u_int)mmap((void*)start_text_pg, text_size, PROT_READ | PROT_EXEC, mflags, fd, (off_t)0) != start_text_pg) { fprintf(stderr,"Error mmaping text segment\n"); goto err; } /* mmap the data segment read/write */ if (!(mflags & MAP_COPY)) mflags = MAP_FILE | MAP_FIXED | MAP_PRIVATE; if ((u_int)mmap((void*)(start_text_pg + text_size), data_size, PROT_READ | PROT_WRITE | PROT_EXEC, mflags, fd, (off_t)text_size) != start_text_pg + text_size) { fprintf(stderr,"Error mmaping data segment: %d\n", errno); goto err; } /* mmap the bss as demand zero'd */ if ((u_int)mmap((void*)(start_text_pg + text_size + data_size + overlap_size), bss_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_FIXED | MAP_PRIVATE, (off_t)-1, 0) != start_text_pg + text_size + data_size + overlap_size) { fprintf(stderr,"Error mmaping bss\n"); goto err; } } return start_text_addr; err: return 0; }