static void exit_question() { Proc::cli(); exit_question_active = 1; Unsigned16 irqs = Pic::disable_all_save(); if (Config::getchar_does_hlt_works_ok) { Timer_tick::set_vectors_stop(); Timer_tick::enable(Cpu_number::boot_cpu()); // hmexit alway on CPU 0 Proc::sti(); } // make sure that we don't acknowledg the exit question automatically Kconsole::console()->change_state(Console::PUSH, 0, ~Console::INENABLED, 0); puts("\nReturn reboots, \"k\" enters L4 kernel debugger..."); char c = Kconsole::console()->getchar(); if (c == 'k' || c == 'K') { Pic::restore_all(irqs); kdb_ke("_exit"); } else { // It may be better to not call all the destruction stuff because of // unresolved static destructor dependency problems. So just do the // reset at this point. puts("\033[1mRebooting.\033[m"); } }
/** Page fault handler. This handler suspends any ongoing IPC, then sets up page-fault IPC. Finally, the ongoing IPC's state (if any) is restored. @param pfa page-fault virtual address @param error_code page-fault error code. */ PRIVATE bool Thread::handle_page_fault_pager(Thread_ptr const &_pager, Address pfa, Mword error_code, L4_msg_tag::Protocol protocol) { #ifndef NDEBUG // do not handle user space page faults from kernel mode if we're // already handling a request if (EXPECT_FALSE(!PF::is_usermode_error(error_code) && thread_lock()->test() == Thread_lock::Locked)) { kdb_ke("Fiasco BUG: page fault, under lock"); panic("page fault in locked operation"); } #endif if (EXPECT_FALSE((state() & Thread_alien))) return false; Lock_guard<Cpu_lock> guard(&cpu_lock); unsigned char rights; Kobject_iface *pager = _pager.ptr(space(), &rights); if (!pager) { WARN("CPU%d: Pager of %lx is invalid (pfa=" L4_PTR_FMT ", errorcode=" L4_PTR_FMT ") to %lx (pc=%lx)\n", current_cpu(), dbg_id(), pfa, error_code, _pager.raw(), regs()->ip()); LOG_TRACE("Page fault invalid pager", "pf", this, __fmt_page_fault_invalid_pager, Log_pf_invalid *l = tbe->payload<Log_pf_invalid>(); l->cap_idx = _pager.raw(); l->err = error_code; l->pfa = pfa); pager = this; // block on ourselves }
IMPLEMENT void* Vmem_alloc::page_alloc (void *address, Zero_fill zf, unsigned mode) { void *vpage = 0; Address page; vpage = Mapped_allocator::allocator()->alloc(Config::PAGE_SHIFT); if (EXPECT_FALSE(!vpage)) return 0; // insert page into master page table Pdir::Iter e = Kmem::kdir->walk(Virt_addr(address), 100, Mapped_allocator::allocator()); if (EXPECT_FALSE(e.e->valid())) { kdb_ke("page_alloc: address already mapped"); goto error; } if (e.shift() != Config::PAGE_SHIFT) goto error; if (zf == ZERO_FILL) memset(vpage, 0, Config::PAGE_SIZE); page = Mem_layout::pmem_to_phys((Address)vpage); *e.e = page | Pt_entry::Writable | Pt_entry::Dirty | Pt_entry::Valid | Pt_entry::Referenced | Pt_entry::global(); page_map (address, 0, zf, page); if (mode & User) e.e->add_attr(Pt_entry::User); return address; error: Mapped_allocator::allocator()->free(Config::PAGE_SHIFT, vpage); // 2^0 = 1 page return 0; }
// the kernel bootstrap routine PUBLIC void kernel_thread_t::bootstrap() { // Initializations done -- helping_lock_t can now use helping lock helping_lock_t::threading_system_active = true; // // set up my own thread control block // state_change (0, Thread_running); sched()->set_prio (config::kernel_prio); sched()->set_mcp (config::kernel_mcp); sched()->set_timeslice (config::default_time_slice); sched()->set_ticks_left (config::default_time_slice); present_next = present_prev = this; ready_next = ready_prev = this; // // set up class variables // for (int i = 0; i < 256; i++) prio_next[i] = prio_first[i] = 0; prio_next[config::kernel_prio] = prio_first[config::kernel_prio] = this; prio_highest = config::kernel_prio; timeslice_ticks_left = config::default_time_slice; timeslice_owner = this; // // install our slow trap handler // nested_trap_handler = base_trap_handler; base_trap_handler = thread_handle_trap; // // initialize FPU // set_ts(); // FPU ops -> exception // // initialize interrupts // irq_t::lookup(2)->alloc(this, false); // reserve cascade irq irq_t::lookup(8)->alloc(this, false); // reserve timer irq pic_enable_irq(2); // allow cascaded irqs // set up serial console if (! strstr(kmem::cmdline(), " -I-") && !strstr(kmem::cmdline(), " -irqcom")) { int com_port = console::serial_com_port; int com_irq = com_port & 1 ? 4 : 3; irq_t::lookup(com_irq)->alloc(this, false); // the remote-gdb interrupt pic_enable_irq(com_irq); // for some reason, we have to re-enable the com irq here if (config::serial_esc) com_cons_enable_receive_interrupt(); } // initialize the profiling timer bool user_irq0 = strstr(kmem::cmdline(), "irq0"); if (config::profiling) { if (user_irq0) { kdb_ke("options `-profile' and `-irq0' don't mix " "-- disabling `-irq0'"); } irq_t::lookup(0)->alloc(this, false); profile::init(); if (strstr(kmem::cmdline(), " -profstart")) profile::start(); } else if (! user_irq0) irq_t::lookup(0)->alloc(this, false); // reserve irq0 even though // we don't use it // // set up timer interrupt (~ 1ms) // while (rtcin(RTC_STATUSA) & RTCSA_TUP) ; // wait till RTC ready rtcout(RTC_STATUSA, RTCSA_DIVIDER | RTCSA_1024); // 1024 Hz // set up 1024 Hz interrupt rtcout(RTC_STATUSB, rtcin(RTC_STATUSB) | RTCSB_PINTR | RTCSB_SQWE); rtcin(RTC_INTR); // reset pic_enable_irq(8); // allow this interrupt // // set PCE-Flag in CR4 to enable read of performace measurement counters // in usermode. PMC were introduced in Pentium MMX and PPro processors. // #ifndef CPUF_MMX #define CPUF_MMX 0x00800000 #endif if(strncmp(cpu.vendor_id, "GenuineIntel", 12) == 0 && (cpu.family == CPU_FAMILY_PENTIUM_PRO || cpu.feature_flags & CPUF_MMX)) { set_cr4(get_cr4() | CR4_PCE); } // // allow the boot task to create more tasks // for (unsigned i = config::boot_taskno + 1; i < space_index_t::max_space_number; i++) { check(space_index_t(i).set_chief(space_index(), space_index_t(config::boot_taskno))); } // // create sigma0 // // sigma0's chief is the boot task space_index_t(config::sigma0_id.id.task). set_chief(space_index(), space_index_t(config::sigma0_id.id.chief)); sigma0 = new space_t(config::sigma0_id.id.task); sigma0_thread = new (&config::sigma0_id) thread_t (sigma0, &config::sigma0_id, config::sigma0_prio, config::sigma0_mcp); // push address of kernel info page to sigma0's stack vm_offset_t esp = kmem::info()->sigma0_esp; * reinterpret_cast<vm_offset_t*>(kmem::phys_to_virt(--esp)) = kmem::virt_to_phys(kmem::info()); sigma0_thread->initialize(kmem::info()->sigma0_eip, esp, 0, 0); // // create the boot task // // the boot task's chief is the boot task itself space_index_t(config::boot_id.id.task). set_chief(space_index(), space_index_t(config::boot_id.id.chief)); space_t *boot = new space_t(config::boot_id.id.task); thread_t *boot_thread = new (&config::boot_id) thread_t (boot, &config::boot_id, config::boot_prio, config::boot_mcp); boot_thread->initialize(0x200000, 0x200000, sigma0_thread, 0); // // the idle loop // for (;;) { // printf("I"); sti(); // enable irqs, otherwise idling is fatal if (config::hlt_works_ok) asm("hlt"); // stop the CPU, waiting for an int while (ready_next != this) // are there any other threads ready? schedule(); } }