Example #1
0
INITCODE void arch_smp_init(void)
{
  cpu_id_t c;
  uint32_t *lapic_id;
  char *ap_code = (char *)0x9000;
  size_t size = &ap_boot_end - &ap_boot_start;
  struct ap_config *apcfg;

  /* FIXME DK: real-mode page must be reserved dynamically during mm initialization. */
  apcfg = (struct ap_config *)&ap_config;
  apcfg->page_addr = 0x9000;
  apcfg->jmp_rip = (uint32_t)((uint64_t)smp_start32 & 0xffffffffU);
  apcfg->gdtr.base += apcfg->page_addr;
  memcpy(&apcfg->gdt[APGDT_KCOFF_DESCR], &apcfg->gdt[APGDT_KCNORM_DESCR],
         sizeof(uint64_t));
  apcfg->gdt[APGDT_KCOFF_DESCR] |= (uint64_t)apcfg->page_addr << 16;

  /* Change bootstrap entry point (from kernel_main to main_smpap_routine) */
  *(uint64_t *)&kernel_jump_addr = (uint64_t)main_smpap_routine;
  /* And finally copy AP initialization code to the proper place */
  memcpy(ap_code, &ap_boot_start, size);

  /* ok setup new gdt */
  for_each_cpu(c) {
      int r;
    if (!c) {
      continue; /* Skip BSP CPU */
    }

    lapic_id = raw_percpu_get_var(lapic_ids, c);
    kprintf("SEND INIT IPI TO CPU %d, cpuid=%d\n", *lapic_id, c);
    if (lapic_init_ipi(*lapic_id)) {
        panic("Can't send init interrupt\n");
    }
    interrupts_disable();
    for (r = 0; r < 100; r++) {
        default_hwclock->delay(1000);
        if (is_cpu_online(c)) {
            kprintf("online!\n");
            break;
        }
    }

    interrupts_enable();
    if (!is_cpu_online(c)) {
        kprintf("f**k! => %d\n", is_cpu_online(c));
      for (;;);
      panic("CPU %d is not online\n", c);
    }
  }
}
Example #2
0
int smp_delete_all_threads(space_t * space)
{
    //IPI_PRINTF("%s (%x)\n", __FUNCTION__, victim);
    cpu_mailbox_t * mailbox = get_mailbox();
    for (dword_t cpu = 0; cpu < CONFIG_SMP_MAX_CPU; cpu++)
    {
	if (cpu == get_cpu_id())
	    continue;
	if (!is_cpu_online(cpu))
	    continue;

	mailbox->param[0] = (dword_t)space;
	dword_t status = mailbox->send_command(cpu, SMP_CMD_DELETE_ALL_THREADS);
	switch(status)
	{
	case MAILBOX_OK:
	    return 1;
	case MAILBOX_UNWIND_REMOTE:
	    /* we have to perform a remote unwind */
	    IPI_PRINTF("%s: remote unwind %x\n", mailbox->tcb);
	    unwind_ipc(mailbox->tcb);
	    break;
	case MAILBOX_ERROR:
	    enter_kdebug("smp_delete_task: error deleting task");
	    break;
	default:
	    enter_kdebug("smp_delete_task: unexpected return value");
	    break;
	}
    }
    return 0;
}
Example #3
0
void smp_startup_processors()
{

#define gdt_idx(x) ((x) >> 3)
    /* the kernel code - kernel_space_exec */
    smp_boot_gdt[gdt_idx(X86_KCS)].set_seg(0, ~0, 0, GDT_DESC_TYPE_CODE);
    /* kernel data - linear_kernel_space */
    smp_boot_gdt[gdt_idx(X86_KDS)].set_seg(0, ~0, 0, GDT_DESC_TYPE_DATA);

#if defined(CONFIG_DEBUG_TRACE_SMP)
    printf("smp_start_processors\n");
#endif
    memcpy((dword_t*)SMP_STARTUP_PAGE, (dword_t*)_start_smp, (dword_t)(_end_smp) - (dword_t)(_start_smp));
    //enter_kdebug("after smp-copy");
    wbinvd();

    for (dword_t cpu = 0; cpu < CONFIG_SMP_MAX_CPU; cpu++) 
    {
	// the boot cpu is not necessarily cpu 0
	if (cpu == get_boot_cpu())
	    continue;

	// start only processor which are in the processor map
	if (!(processor_map & (1 << cpu)))
	    continue;

	send_startup_ipi(cpu);

	// wait for cpu to be online - aprox. 100 * 100us = 
	for (int i=0; i<100; i++) {
	    udelay(100);
	    if (is_cpu_online(cpu)) break;
	}
	
	if (!is_cpu_online(cpu)) {
	    printf("CPU %d failed to start\n", cpu);
	}
	else
	{
	    printf("CPU %d is online\n", cpu);
	}
    }
    //enter_kdebug("startup done");
}
Example #4
0
/* returns:   0 = success
 *          < 0 = failure
 *          > 0 = partial success
 */
static int cpu_configure(cpu_set_t *cpu_set, size_t setsize, int configure)
{
	unsigned int cpu;
	int rc, current;
	size_t fails = 0;

	for (cpu = 0; cpu < setsize; cpu++) {
		if (!CPU_ISSET(cpu, cpu_set))
			continue;
		if (!path_exist(_PATH_SYS_CPU "/cpu%d", cpu)) {
			warnx(_("CPU %u does not exist"), cpu);
			fails++;
			continue;
		}
		if (!path_exist(_PATH_SYS_CPU "/cpu%d/configure", cpu)) {
			warnx(_("CPU %u is not configurable"), cpu);
			fails++;
			continue;
		}
		current = path_read_s32(_PATH_SYS_CPU "/cpu%d/configure", cpu);
		if ((current == 1) && (configure == 1)) {
			printf(_("CPU %u is already configured\n"), cpu);
			continue;
		}
		if ((current == 0) && (configure == 0)) {
			printf(_("CPU %u is already deconfigured\n"), cpu);
			continue;
		}
		if ((current == 1) && (configure == 0) && onlinecpus &&
		    is_cpu_online(cpu)) {
			warnx(_("CPU %u deconfigure failed (CPU is enabled)"), cpu);
			fails++;
			continue;
		}
		if (configure) {
			rc = path_write_str("1", _PATH_SYS_CPU "/cpu%d/configure", cpu);
			if (rc == -1) {
				warn(_("CPU %u configure failed"), cpu);
				fails++;
			} else
				printf(_("CPU %u configured\n"), cpu);
		} else {
			rc = path_write_str("0", _PATH_SYS_CPU "/cpu%d/configure", cpu);
			if (rc == -1) {
				warn(_("CPU %u deconfigure failed"), cpu);
				fails++;
			} else
				printf(_("CPU %u deconfigured\n"), cpu);
		}
	}

	return fails == 0 ? 0 : fails == setsize ? -1 : 1;
}
Example #5
0
void smp_flush_tlb()
{
#warning inefficient implementation of tlb shootdown
    cpu_mailbox_t * mailbox = get_mailbox();
    for (dword_t cpu = 0; cpu < CONFIG_SMP_MAX_CPU; cpu++)
    {
	if (cpu == get_cpu_id())
	    continue;
	if (!is_cpu_online(cpu))
	    continue;

	dword_t status = mailbox->send_command(cpu, SMP_CMD_FLUSH_TLB);
	if (status != MAILBOX_OK)
	    enter_kdebug("smp_flush_tlb");
    }
}
Example #6
0
static int cpu_configure(cpu_set_t *cpu_set, size_t setsize, int configure)
{
	unsigned int cpu;
	int rc, current;

	for (cpu = 0; cpu < setsize; cpu++) {
		if (!CPU_ISSET(cpu, cpu_set))
			continue;
		if (!path_exist(_PATH_SYS_CPU "/cpu%d", cpu)) {
			printf(_("CPU %d does not exist\n"), cpu);
			continue;
		}
		if (!path_exist(_PATH_SYS_CPU "/cpu%d/configure", cpu)) {
			printf(_("CPU %d is not configurable\n"), cpu);
			continue;
		}
		current = path_getnum(_PATH_SYS_CPU "/cpu%d/configure", cpu);
		if ((current == 1) && (configure == 1)) {
			printf(_("CPU %d is already configured\n"), cpu);
			continue;
		}
		if ((current == 0) && (configure == 0)) {
			printf(_("CPU %d is already deconfigured\n"), cpu);
			continue;
		}
		if ((current == 1) && (configure == 0) && onlinecpus &&
		    is_cpu_online(cpu)) {
			printf(_("CPU %d deconfigure failed "
				 "(CPU is enabled)\n"), cpu);
			continue;
		}
		if (configure) {
			rc = path_writestr("1", _PATH_SYS_CPU "/cpu%d/configure", cpu);
			if (rc == -1)
				printf(_("CPU %d configure failed (%m)\n"), cpu);
			else
				printf(_("CPU %d configured\n"), cpu);
		} else {
			rc = path_writestr("0", _PATH_SYS_CPU "/cpu%d/configure", cpu);
			if (rc == -1)
				printf(_("CPU %d deconfigure failed (%m)\n"), cpu);
			else
				printf(_("CPU %d deconfigured\n"), cpu);
		}
	}
	return EXIT_SUCCESS;
}
Example #7
0
void smp_move_thread(tcb_t * tcb, dword_t cpu)
{
    cpu_mailbox_t * mailbox = get_mailbox();
    //mailbox->command = SMP_CMD_THREAD_MOVE;
    mailbox->tcb = tcb;
    //mailbox->status = MAILBOX_NULL;
    mailbox->param[0] = tcb->queue_state;

    //IPI_PRINTF("smp move thread %p from cpu %d to cpu %d\n", tcb, tcb->cpu, cpu);

    /* do not move thread if already on cpu */
    if (tcb->cpu == cpu)
	return;

    /* do not migrate to inactive cpus */
    if (!is_cpu_online(cpu))
	return;

 retry_migration:

    if (tcb->cpu == get_cpu_id())
    {
	/* we have the thread - so, we can give it away */
	thread_dequeue_present(tcb);
	thread_dequeue_ready(tcb);
	thread_dequeue_wakeup(tcb);
	
	IPI_PRINTF("before thread put (current: %x, pdir=%x, tcb: %x)\n", 
		   get_current_tcb(), get_current_pagetable(), tcb);

	mailbox->send_command(cpu, SMP_CMD_THREAD_PUT);

	IPI_PRINTF("thread_put done (current: %x, pdir=%x, cpu: %d/%d)\n", 
		   get_current_tcb(), get_current_pagetable(), 
		   get_cpu_id(), get_apic_cpu_id());
    }
    else
    {
	/* we don't have the thread - ask the cpu */
	dword_t status;
	status = mailbox->send_command(tcb->cpu, SMP_CMD_THREAD_GET);
	
	/* thread may have moved meanwhile */
	if (status != MAILBOX_OK)
	    goto retry_migration;
	
	if (cpu == get_cpu_id())
	{
	    /* the thread comes to us */
	    tcb->cpu = cpu;
	    thread_adapt_queue_state(tcb, mailbox->param[1]);
	    /* adjust the page directory for this tcb */
	    //printf("pgdir: %x\n", tcb->page_dir);
	    thread_adapt_pagetable(tcb, get_cpu_id());
	    //printf("pgdir: %x\n", tcb->page_dir);
	}
	else
	{
	    status = mailbox->send_command(cpu, SMP_CMD_THREAD_PUT);
	    
	    if (status != MAILBOX_OK)
	    {
		enter_kdebug("3-cpu thread migration failed");
		return;
	    }
	}
    } 
}