void gdb_pc_com_init(int com_port, struct termios *com_params) { int com_irq = com_port & 1 ? 4 : 3; /* Tell the generic serial GDB code how to send and receive characters. */ gdb_serial_recv = gdb_cons_getchar; gdb_serial_send = gdb_cons_putchar; gdb_com_port = com_port; /* Tell the GDB proxy trap handler to use the serial stub. */ gdb_signal = gdb_serial_signal; /* * Stick in gdb's special trap handler. * This gets called before base_trap_handlers is consulted. * If it returns zero, the normal handler is circumvented entirely; * if it returns nonzero, the normal handler runs next. */ base_trap_gdb_handler = gdb_trap_ss; /* * Initialize the serial port. * If no com_params were specified by the caller, * then default to base_raw_termios. * (If we just passed through the NULL, * then com_cons_init would default to base_cooked_termios, * which messes up the GDB remote debugging protocol.) */ if (com_params == 0) com_params = &base_raw_termios; com_cons_init(com_port, com_params); #ifdef KNIT set_irq_handler(com_irq,gdb_pc_com_intr); com_cons_enable_receive_interrupt(com_port); #else /* Hook the COM port's hardware interrupt. The com_cons itself uses only polling for communication; the interrupt is only used to allow the remote debugger to stop us at any point, e.g. when the user presses CTRL-C. */ fill_irq_gate(com_irq, (unsigned)gdb_pc_com_intr, KERNEL_CS, ACC_PL_K); /* Enable the COM port interrupt. */ com_cons_enable_receive_interrupt(com_port); pic_enable_irq(com_irq); #endif }
// 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(); } }