// 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();
    }
}
Esempio n. 2
0
static int
rtc_data_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
		 uint32_t *eax, void *arg)
{
	int hour;
	time_t t;
	struct timeval cur, delta;

	static struct timeval last;
	static struct tm tm;

	if (bytes != 1)
		return (-1);

	gettimeofday(&cur, NULL);

	/*
	 * Increment the cached time only once per second so we can guarantee
	 * that the guest has at least one second to read the hour:min:sec
	 * separately and still get a coherent view of the time.
	 */
	delta = cur;
	timevalsub(&delta, &last);
	if (delta.tv_sec >= 1 && (status_b & RTCSB_HALT) == 0) {
		t = cur.tv_sec;
		localtime_r(&t, &tm);
		last = cur;
	}

	if (in) {
		switch (addr) {
		case RTC_SEC_ALARM:
			*eax = rtc_alarm.secs;
			break;
		case RTC_MIN_ALARM:
			*eax = rtc_alarm.mins;
			break;
		case RTC_HRS_ALARM:
			*eax = rtc_alarm.hours;
			break;
		case RTC_SEC:
			*eax = rtcout(tm.tm_sec);
			return (0);
		case RTC_MIN:
			*eax = rtcout(tm.tm_min);
			return (0);
		case RTC_HRS:
			if (status_b & RTCSB_24HR)
				hour = tm.tm_hour;
			else
				hour = (tm.tm_hour % 12) + 1;
			
			*eax = rtcout(hour);

			/*
			 * If we are representing time in the 12-hour format
			 * then set the MSB to indicate PM.
			 */
			if ((status_b & RTCSB_24HR) == 0 && tm.tm_hour >= 12)
				*eax |= 0x80;

			return (0);
		case RTC_WDAY:
			*eax = rtcout(tm.tm_wday + 1);
			return (0);
		case RTC_DAY:
			*eax = rtcout(tm.tm_mday);
			return (0);
		case RTC_MONTH:
			*eax = rtcout(tm.tm_mon + 1);
			return (0);
		case RTC_YEAR:
			*eax = rtcout(tm.tm_year % 100);
			return (0);
		case RTC_STATUSA:
			*eax = status_a;
			return (0);
		case RTC_STATUSB:
			*eax = status_b;
			return (0);
		case RTC_INTR:
			*eax = 0;
			return (0);
		case RTC_STATUSD:
			*eax = RTCSD_PWR;
			return (0);
		case RTC_NVRAM_START ... RTC_NVRAM_END:
			*eax = rtc_nvram[addr - RTC_NVRAM_START];
			return (0);
		default:
			return (-1);
		}
	}

	switch (addr) {
	case RTC_STATUSA:
		status_a = *eax & ~RTCSA_TUP;
		break;
	case RTC_STATUSB:
		/* XXX not implemented yet XXX */
		if (*eax & RTCSB_PINTR)
			return (-1);
		status_b = *eax;
		break;
	case RTC_STATUSD:
		/* ignore write */
		break;
	case RTC_SEC_ALARM:
		rtc_alarm.secs = *eax;
		break;
	case RTC_MIN_ALARM:
		rtc_alarm.mins = *eax;
		break;
	case RTC_HRS_ALARM:
		rtc_alarm.hours = *eax;
		break;
	case RTC_SEC:
	case RTC_MIN:
	case RTC_HRS:
	case RTC_WDAY:
	case RTC_DAY:
	case RTC_MONTH:
	case RTC_YEAR:
		/*
		 * Ignore writes to the time of day registers
		 */
		break;
	case RTC_NVRAM_START ... RTC_NVRAM_END:
		rtc_nvram[addr - RTC_NVRAM_START] = *eax;
		break;
	default:
		return (-1);
	}
	return (0);
}