⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arch_smp.c

📁 newos is new operation system
💻 C
字号:
/*** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.** Distributed under the terms of the NewOS License.*/#include <boot/stage2.h>#include <kernel/kernel.h>#include <kernel/console.h>#include <kernel/debug.h>#include <kernel/vm.h>#include <kernel/kernel.h>#include <kernel/int.h>#include <kernel/smp.h>#include <kernel/smp_priv.h>#include <kernel/arch/cpu.h>#include <kernel/arch/vm.h>#include <kernel/arch/smp.h>#include <kernel/arch/i386/smp_priv.h>#include <kernel/arch/i386/timer.h>#include <string.h>#include <stdio.h>static int num_cpus = 1;static unsigned int *apic = NULL;static unsigned int cpu_apic_id[_MAX_CPUS] = { 0 };static unsigned int cpu_os_id[_MAX_CPUS] = { 0 };static unsigned int cpu_apic_version[_MAX_CPUS] = { 0 };static unsigned int *ioapic = NULL;static unsigned int apic_timer_tics_per_sec = 0;static int i386_timer_interrupt(void* data){	arch_smp_ack_interrupt();	return apic_timer_interrupt();}static int i386_ici_interrupt(void* data){	// gin-u-wine inter-cpu interrupt//	dprintf("inter-cpu interrupt on cpu %d\n", arch_smp_get_current_cpu());	arch_smp_ack_interrupt();	return smp_intercpu_int_handler();}static int i386_spurious_interrupt(void* data){	// spurious interrupt//	dprintf("spurious interrupt on cpu %d\n", arch_smp_get_current_cpu());	arch_smp_ack_interrupt();	return INT_NO_RESCHEDULE;}static int i386_smp_error_interrupt(void* data){	// smp error interrupt//	dprintf("smp error interrupt on cpu %d\n", arch_smp_get_current_cpu());	arch_smp_ack_interrupt();	return INT_NO_RESCHEDULE;}static unsigned int apic_read(unsigned int *addr){	return *addr;}static void apic_write(unsigned int *addr, unsigned int data){	*addr = data;}int arch_smp_init(kernel_args *ka){	dprintf("arch_smp_init: entry\n");	if(ka->num_cpus > 1) {		// setup some globals		num_cpus = ka->num_cpus;		apic = ka->arch_args.apic;		ioapic = ka->arch_args.ioapic;		memcpy(cpu_apic_id, ka->arch_args.cpu_apic_id, sizeof(ka->arch_args.cpu_apic_id));		memcpy(cpu_os_id, ka->arch_args.cpu_os_id, sizeof(ka->arch_args.cpu_os_id));		memcpy(cpu_apic_version, ka->arch_args.cpu_apic_version, sizeof(ka->arch_args.cpu_apic_version));		apic_timer_tics_per_sec = ka->arch_args.apic_time_cv_factor;		// setup regions that represent the apic & ioapic		vm_create_anonymous_region(vm_get_kernel_aspace_id(), "local_apic", (void *)&apic,			REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL);		vm_create_anonymous_region(vm_get_kernel_aspace_id(), "ioapic", (void *)&ioapic,			REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL);		// set up the local apic on the boot cpu		arch_smp_init_percpu(ka, 1);		// set up the interrupt handlers for local apic interrupts.		// they are mapped to absolute interrupts 0xfb-0xff, but the io handlers are all		// base 0x20, so subtract 0x20.		int_set_io_interrupt_handler(0xfb - 0x20, &i386_timer_interrupt, NULL, "lapic timer");		int_set_io_interrupt_handler(0xfd - 0x20, &i386_ici_interrupt, NULL, "ici");		int_set_io_interrupt_handler(0xfe - 0x20, &i386_smp_error_interrupt, NULL, "lapic smp error");		int_set_io_interrupt_handler(0xff - 0x20, &i386_spurious_interrupt, NULL, "lapic spurious");	} else {		num_cpus = 1;	}	return 0;}static int smp_setup_apic(kernel_args *ka){	unsigned int config;	/* set spurious interrupt vector to 0xff */	config = apic_read(APIC_SIVR) & 0xfffffc00;	config |= APIC_ENABLE | 0xff;	apic_write(APIC_SIVR, config);#if 0	/* setup LINT0 as ExtINT */	config = (apic_read(APIC_LINT0) & 0xffff1c00);	config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM;	apic_write(APIC_LINT0, config);	/* setup LINT1 as NMI */	config = (apic_read(APIC_LINT1) & 0xffff1c00);	config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP;	apic_write(APIC_LINT1, config);#endif	/* setup timer */	config = apic_read(APIC_LVTT) & ~APIC_LVTT_MASK;	config |= 0xfb | APIC_LVTT_M; // vector 0xfb, timer masked	apic_write(APIC_LVTT, config);	apic_write(APIC_ICRT, 0); // zero out the clock	config = apic_read(APIC_TDCR) & ~0x0000000f;	config |= APIC_TDCR_1; // clock division by 1	apic_write(APIC_TDCR, config);	/* setup error vector to 0xfe */	config = (apic_read(APIC_LVT3) & 0xffffff00) | 0xfe;	apic_write(APIC_LVT3, config);	/* accept all interrupts */	config = apic_read(APIC_TPRI) & 0xffffff00;	apic_write(APIC_TPRI, config);	config = apic_read(APIC_SIVR);	apic_write(APIC_EOI, 0);//	dprintf("done\n");	return 0;}int arch_smp_init_percpu(kernel_args *ka, int cpu_num){	// set up the local apic on the current cpu	dprintf("arch_smp_init_percpu: setting up the apic on cpu %d", cpu_num);	smp_setup_apic(ka);	return 0;}void arch_smp_send_broadcast_ici(void){	int config;	int_disable_interrupts();	config = apic_read(APIC_ICR1) & APIC_ICR1_WRITE_MASK;	apic_write(APIC_ICR1, config | 0xfd | APIC_ICR1_DELMODE_FIXED | APIC_ICR1_DESTMODE_PHYS | APIC_ICR1_DEST_ALL_BUT_SELF);	int_restore_interrupts();}void arch_smp_send_ici(int target_cpu){	int config;	int_disable_interrupts();	config = apic_read(APIC_ICR2) & APIC_ICR2_MASK;	apic_write(APIC_ICR2, config | cpu_apic_id[target_cpu] << 24);	config = apic_read(APIC_ICR1) & APIC_ICR1_WRITE_MASK;	apic_write(APIC_ICR1, config | 0xfd | APIC_ICR1_DELMODE_FIXED | APIC_ICR1_DESTMODE_PHYS | APIC_ICR1_DEST_FIELD);	int_restore_interrupts();}void arch_smp_ack_interrupt(void){	apic_write(APIC_EOI, 0);}#define MIN_TIMEOUT 1000int arch_smp_set_apic_timer(bigtime_t relative_timeout, int type){	unsigned int config;	unsigned int ticks;	if(apic == NULL)		return -1;	if(relative_timeout < MIN_TIMEOUT)		relative_timeout = MIN_TIMEOUT;	// calculation should be ok, since it's going to be 64-bit	ticks = ((relative_timeout * apic_timer_tics_per_sec) / 1000000);	int_disable_interrupts();	config = apic_read(APIC_LVTT) | APIC_LVTT_M; // mask the timer	apic_write(APIC_LVTT, config);	apic_write(APIC_ICRT, 0); // zero out the timer	config = apic_read(APIC_LVTT) & ~APIC_LVTT_M; // unmask the timer	if(type == HW_TIMER_ONESHOT)		config &= ~APIC_LVTT_TM; // clear the periodic bit	else		config |= APIC_LVTT_TM; // periodic	apic_write(APIC_LVTT, config);	dprintf("arch_smp_set_apic_timer: config 0x%x, timeout %Ld, tics/sec %d, tics %d\n", 		config, relative_timeout, apic_timer_tics_per_sec, ticks);	apic_write(APIC_ICRT, ticks); // start it up	int_restore_interrupts();	return 0;}int arch_smp_clear_apic_timer(void){	unsigned int config;	if(apic == NULL)		return -1;	int_disable_interrupts();	config = apic_read(APIC_LVTT) | APIC_LVTT_M; // mask the timer	apic_write(APIC_LVTT, config);	apic_write(APIC_ICRT, 0); // zero out the timer	int_restore_interrupts();	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -