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

📄 arch_cpu.c

📁 newos is new operation system
💻 C
字号:
/*** Copyright 2001-2004, Travis Geiselbrecht. All rights reserved.** Distributed under the terms of the NewOS License.*/#include <kernel/kernel.h>#include <kernel/cpu.h>#include <kernel/arch/cpu.h>#include <kernel/heap.h>#include <kernel/vm.h>#include <kernel/debug.h>#include <kernel/smp.h>#include <kernel/debug.h>#include <kernel/console.h>#include <kernel/arch/i386/selector.h>#include <kernel/arch/int.h>#include <kernel/arch/i386/interrupts.h>#include <newos/errors.h>#include <boot/stage2.h>#include <string.h>#include <stdio.h>#include <stdlib.h>/* a few debug functions that get added to the kernel debugger menu */static void dbg_in(int argc, char **argv);static void dbg_out(int argc, char **argv);static struct tss **tss;static int *tss_loaded;/* tss to switch to a special 'task' on the double fault handler */static struct tss double_fault_tss;static uint32 double_fault_stack[1024];static desc_table *gdt = 0;/* cpu vendor info */struct cpu_vendor_info {	const char *vendor;	const char *ident_string[2];};static const struct cpu_vendor_info vendor_info[VENDOR_NUM] = {	{ "Intel", { "GenuineIntel" } },	{ "AMD", { "AuthenticAMD" } },	{ "Cyrix", { "CyrixInstead" } },	{ "UMC", { "UMC UMC UMC" } },	{ "NexGen", { "NexGenDriven" } },	{ "Centaur", { "CentaurHauls" } },	{ "Rise", { "RiseRiseRise" } },	{ "Transmeta", { "GenuineTMx86", "TransmetaCPU" } },	{ "NSC", { "Geode by NSC" } },};/* fsave vs fxsave function pointers */static void (*fsave_swap_func)(void *old_fpu_state, void *new_fpu_state);static void (*fsave_func)(void *fpu_state);static void (*frstor_func)(void *fpu_state);int arch_cpu_preboot_init(kernel_args *ka){	write_dr3(0);	return 0;}static void make_feature_string(cpu_ent *cpu, char *str){	str[0] = 0;	if(cpu->arch.feature[FEATURE_COMMON] & X86_FPU)		strcat(str, "fpu ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_VME)		strcat(str, "vme ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_DE)		strcat(str, "de ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_PSE)		strcat(str, "pse ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_TSC)		strcat(str, "tsc ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_MSR)		strcat(str, "msr ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_PAE)		strcat(str, "pae ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_MCE)		strcat(str, "mce ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_CX8)		strcat(str, "cx8 ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_APIC)		strcat(str, "apic ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_SEP)		strcat(str, "sep ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_MTRR)		strcat(str, "mtrr ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_PGE)		strcat(str, "pge ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_MCA)		strcat(str, "mca ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_CMOV)		strcat(str, "cmov ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_PAT)		strcat(str, "pat ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_PSE36)		strcat(str, "pse36 ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_PSN)		strcat(str, "psn ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_CLFSH)		strcat(str, "clfsh ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_DS)		strcat(str, "ds ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_ACPI)		strcat(str, "acpi ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_MMX)		strcat(str, "mmx ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_FXSR)		strcat(str, "fxsr ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_SSE)		strcat(str, "sse ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_SSE2)		strcat(str, "sse2 ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_SS)		strcat(str, "ss ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_HTT)		strcat(str, "htt ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_TM)		strcat(str, "tm ");	if(cpu->arch.feature[FEATURE_COMMON] & X86_PBE)		strcat(str, "pbe ");	if(cpu->arch.feature[FEATURE_EXT] & X86_EXT_SSE3)		strcat(str, "sse3 ");	if(cpu->arch.feature[FEATURE_EXT] & X86_EXT_MONITOR)		strcat(str, "monitor ");	if(cpu->arch.feature[FEATURE_EXT] & X86_EXT_DSCPL)		strcat(str, "dscpl ");	if(cpu->arch.feature[FEATURE_EXT] & X86_EXT_EST)		strcat(str, "est ");	if(cpu->arch.feature[FEATURE_EXT] & X86_EXT_TM2)		strcat(str, "tm2 ");	if(cpu->arch.feature[FEATURE_EXT] & X86_EXT_CNXTID)		strcat(str, "cnxtid ");	if(cpu->arch.feature[FEATURE_EXT_AMD] & X86_AMD_EXT_SYSCALL)		strcat(str, "syscall ");	if(cpu->arch.feature[FEATURE_EXT_AMD] & X86_AMD_EXT_NX)		strcat(str, "nx ");	if(cpu->arch.feature[FEATURE_EXT_AMD] & X86_AMD_EXT_MMXEXT)		strcat(str, "mmxext ");	if(cpu->arch.feature[FEATURE_EXT_AMD] & X86_AMD_EXT_FFXSR)		strcat(str, "ffxsr ");	if(cpu->arch.feature[FEATURE_EXT_AMD] & X86_AMD_EXT_LONG)		strcat(str, "long ");	if(cpu->arch.feature[FEATURE_EXT_AMD] & X86_AMD_EXT_3DNOWEXT)		strcat(str, "3dnowext ");	if(cpu->arch.feature[FEATURE_EXT_AMD] & X86_AMD_EXT_3DNOW)		strcat(str, "3dnow ");}static int detect_cpu(kernel_args *ka, int curr_cpu) {	unsigned int data[4];	char vendor_str[17];	int i;	cpu_ent *cpu = get_cpu_struct(curr_cpu);	// clear out the cpu info data	cpu->arch.vendor = VENDOR_UNKNOWN;	cpu->arch.vendor_name = "UNKNOWN VENDOR";	cpu->arch.feature[FEATURE_COMMON] = 0;	cpu->arch.feature[FEATURE_EXT] = 0;	cpu->arch.feature[FEATURE_EXT_AMD] = 0;	cpu->arch.model_name[0] = 0;	// print some fun data	i386_cpuid(0, data);	// build the vendor string	memset(vendor_str, 0, sizeof(vendor_str));	*(unsigned int *)&vendor_str[0] = data[1];	*(unsigned int *)&vendor_str[4] = data[3];	*(unsigned int *)&vendor_str[8] = data[2];	// get the family, model, stepping	i386_cpuid(1, data);	cpu->arch.family = (data[0] >> 8) & 0xf;	cpu->arch.model = (data[0] >> 4) & 0xf;	cpu->arch.stepping = data[0] & 0xf;	dprintf("CPU %d: family %d model %d stepping %d, string '%s'\n",		curr_cpu, cpu->arch.family, cpu->arch.model, cpu->arch.stepping, vendor_str);	kprintf("CPU %d: family %d model %d stepping %d, string '%s'\n",		curr_cpu, cpu->arch.family, cpu->arch.model, cpu->arch.stepping, vendor_str);	// figure out what vendor we have here	for(i=0; i<VENDOR_NUM; i++) {		if(!strcmp(vendor_str, vendor_info[i].ident_string[0])) {			cpu->arch.vendor = i;			cpu->arch.vendor_name = vendor_info[i].vendor;			break;		}		if(!strcmp(vendor_str, vendor_info[i].ident_string[1])) {			cpu->arch.vendor = i;			cpu->arch.vendor_name = vendor_info[i].vendor;			break;		}	}	// see if we can get the model name	i386_cpuid(0x80000000, data);	if(data[0] >= 0x80000004) {		// build the model string		memset(cpu->arch.model_name, 0, sizeof(cpu->arch.model_name));		i386_cpuid(0x80000002, data);		memcpy(cpu->arch.model_name, data, sizeof(data));		i386_cpuid(0x80000003, data);		memcpy(cpu->arch.model_name+16, data, sizeof(data));		i386_cpuid(0x80000004, data);		memcpy(cpu->arch.model_name+32, data, sizeof(data));		// some cpus return a right-justified string		for(i = 0; cpu->arch.model_name[i] == ' '; i++)			;		if(i > 0) {			memmove(cpu->arch.model_name, 				&cpu->arch.model_name[i], 				strlen(&cpu->arch.model_name[i]) + 1);		}		dprintf("CPU %d: vendor '%s' model name '%s'\n", 			curr_cpu, cpu->arch.vendor_name, cpu->arch.model_name);		kprintf("CPU %d: vendor '%s' model name '%s'\n",			curr_cpu, cpu->arch.vendor_name, cpu->arch.model_name);	} else {		strcpy(cpu->arch.model_name, "unknown");	}	// load feature bits	i386_cpuid(1, data);	cpu->arch.feature[FEATURE_COMMON] = data[3]; // edx	cpu->arch.feature[FEATURE_EXT] = data[2]; // ecx	if(cpu->arch.vendor == VENDOR_AMD) {		i386_cpuid(0x80000001, data);		cpu->arch.feature[FEATURE_EXT_AMD] = data[3]; // edx	}	make_feature_string(cpu, cpu->arch.feature_string);	dprintf("CPU %d: features: %s\n", curr_cpu, cpu->arch.feature_string);	kprintf("CPU %d: features: %s\n", curr_cpu, cpu->arch.feature_string);	return 0;}int arch_cpu_init(kernel_args *ka){	setup_system_time(ka->arch_args.system_time_cv_factor);	return 0;}int arch_cpu_init_percpu(kernel_args *ka, int curr_cpu){	detect_cpu(ka, curr_cpu);	return 0;}int arch_cpu_init2(kernel_args *ka){	region_id rid;	struct tss_descriptor *tss_d;	unsigned int i;	// account for the segment descriptors	gdt = (desc_table *)ka->arch_args.vir_gdt;	vm_create_anonymous_region(vm_get_kernel_aspace_id(), "gdt", (void **)&gdt,		REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL);	i386_selector_init( gdt );  // pass the new gdt	tss = kmalloc(sizeof(struct tss *) * ka->num_cpus);	if(tss == NULL) {		panic("arch_cpu_init2: could not allocate buffer for tss pointers\n");		return ERR_NO_MEMORY;	}	tss_loaded = kmalloc(sizeof(int) * ka->num_cpus);	if(tss == NULL) {		panic("arch_cpu_init2: could not allocate buffer for tss booleans\n");		return ERR_NO_MEMORY;	}	memset(tss_loaded, 0, sizeof(int) * ka->num_cpus);	for(i=0; i<ka->num_cpus; i++) {		char tss_name[16];		sprintf(tss_name, "tss%d", i);		rid = vm_create_anonymous_region(vm_get_kernel_aspace_id(), tss_name, (void **)&tss[i],			REGION_ADDR_ANY_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED, LOCK_RW|LOCK_KERNEL);		if(rid < 0) {			panic("arch_cpu_init2: unable to create region for tss\n");			return ERR_NO_MEMORY;		}		memset(tss[i], 0, sizeof(struct tss));		tss[i]->ss0 = KERNEL_DATA_SEG;		// add TSS descriptor for this new TSS		tss_d = (struct tss_descriptor *)&gdt[6 + i];		tss_d->limit_00_15 = sizeof(struct tss) & 0xffff;		tss_d->limit_19_16 = 0; // not this long		tss_d->base_00_15 = (addr_t)tss[i] & 0xffff;		tss_d->base_23_16 = ((addr_t)tss[i] >> 16) & 0xff;		tss_d->base_31_24 = (addr_t)tss[i] >> 24;		tss_d->type = 0x9;		tss_d->zero = 0;		tss_d->dpl = 0;		tss_d->present = 1;		tss_d->avail = 0;		tss_d->zero1 = 0;		tss_d->zero2 = 1;		tss_d->granularity = 1;	}	/* set up the double fault tss */	memset(&double_fault_tss, 0, sizeof(double_fault_tss));	double_fault_tss.sp0 = (uint32)double_fault_stack + sizeof(double_fault_stack);	double_fault_tss.ss0 = KERNEL_DATA_SEG;	read_cr3(double_fault_tss.cr3); // copy the current cr3 to the double fault cr3	double_fault_tss.eip = (uint32)&trap8;	double_fault_tss.es = KERNEL_DATA_SEG;	double_fault_tss.cs = KERNEL_CODE_SEG;	double_fault_tss.ss = KERNEL_DATA_SEG;	double_fault_tss.ds = KERNEL_DATA_SEG;	double_fault_tss.fs = KERNEL_DATA_SEG;	double_fault_tss.gs = KERNEL_DATA_SEG;	double_fault_tss.ldt_seg_selector = KERNEL_DATA_SEG;	tss_d = (struct tss_descriptor *)&gdt[5];	tss_d->limit_00_15 = sizeof(struct tss) & 0xffff;	tss_d->limit_19_16 = 0; // not this long	tss_d->base_00_15 = (addr_t)&double_fault_tss & 0xffff;	tss_d->base_23_16 = ((addr_t)&double_fault_tss >> 16) & 0xff;	tss_d->base_31_24 = (addr_t)&double_fault_tss >> 24;	tss_d->type = 0x9; // tss descriptor, not busy	tss_d->zero = 0;	tss_d->dpl = 0;	tss_d->present = 1;	tss_d->avail = 0;	tss_d->zero1 = 0;	tss_d->zero2 = 1;	tss_d->granularity = 1;	i386_set_task_gate(8, DOUBLE_FAULT_TSS);	/* decide if we should use f* or fx* fpu save/restore instructions */	if(i386_check_feature(X86_FXSR, FEATURE_COMMON)) {		fsave_swap_func = &i386_fxsave_swap;		fsave_func = &i386_fxsave;		frstor_func = &i386_fxrstor;	} else {		fsave_swap_func = &i386_fsave_swap;		fsave_func = &i386_fsave;		frstor_func = &i386_frstor;	}	// enable lazy fpu	unsigned int cr0;	read_cr0(cr0);	cr0 |= 0x2; // monitor coprocessor bit	write_cr0(cr0);	// set up a few debug commands (in, out)	dbg_add_command(&dbg_in, "in", "read I/O port");	dbg_add_command(&dbg_out, "out", "write I/O port");	return 0;}bool i386_check_feature(uint32 feature, enum i386_feature_type type) {	cpu_ent *cpu = get_curr_cpu_struct();	return cpu->arch.feature[type] & feature;}desc_table *i386_get_gdt(void){	return gdt;}void i386_set_kstack(addr_t kstack){	int curr_cpu = smp_get_current_cpu();//	dprintf("i386_set_kstack: kstack 0x%x, cpu %d\n", kstack, curr_cpu);	if(tss_loaded[curr_cpu] == 0) {		short seg = (TSS + 8*curr_cpu);		asm("movw  %0, %%ax;"			"ltr %%ax;" : : "r" (seg) : "eax");		tss_loaded[curr_cpu] = 1;	}	tss[curr_cpu]->sp0 = kstack;//	dprintf("done\n");}void i386_save_fpu_context(void *fpu_state){	(*fsave_func)(fpu_state);}void i386_load_fpu_context(void *fpu_state){	(*frstor_func)(fpu_state);}void i386_swap_fpu_context(void *old_fpu_state, void *new_fpu_state){	(*fsave_swap_func)(old_fpu_state, new_fpu_state);}void arch_cpu_invalidate_TLB_range(addr_t start, addr_t end){	int num_pages = end/PAGE_SIZE - start/PAGE_SIZE;	while ( num_pages-- >= 0 ) {		invalidate_TLB(start);		start += PAGE_SIZE;	}}void arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages){	int i;	for(i=0; i<num_pages; i++) {		invalidate_TLB(pages[i]);	}}int arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr_t *fault_handler){	char *tmp = (char *)to;	char *s = (char *)from;	*fault_handler = (addr_t)&&error;	while(size--)		*tmp++ = *s++;	*fault_handler = 0;	return 0;error:	*fault_handler = 0;	return ERR_VM_BAD_USER_MEMORY;}int arch_cpu_user_strcpy(char *to, const char *from, addr_t *fault_handler){	*fault_handler = (addr_t)&&error;	while((*to++ = *from++) != '\0')		;	*fault_handler = 0;	return 0;error:	*fault_handler = 0;	return ERR_VM_BAD_USER_MEMORY;}int arch_cpu_user_strncpy(char *to, const char *from, size_t size, addr_t *fault_handler){	*fault_handler = (addr_t)&&error;	while(size-- && (*to++ = *from++) != '\0')		;	*fault_handler = 0;	return 0;error:	*fault_handler = 0;	return ERR_VM_BAD_USER_MEMORY;}int arch_cpu_user_memset(void *s, char c, size_t count, addr_t *fault_handler){	char *xs = (char *) s;	*fault_handler = (addr_t)&&error;	while (count--)		*xs++ = c;	*fault_handler = 0;	return 0;error:	*fault_handler = 0;	return ERR_VM_BAD_USER_MEMORY;}void arch_cpu_idle(void){	switch(smp_get_num_cpus()) {		case 0:			panic("You need at least 1 CPU to run NewOS\n");		case 1:			asm("hlt");		default:			break;	}}void arch_cpu_sync_icache(void *address, size_t len){	// instruction cache is always consistent on x86}static void dbg_in(int argc, char **argv){	int value;	int port;	if(argc < 2) {		dprintf("not enough args\nusage: %s (1|2|4) port\n", argv[0]);		return;	}	port = atoul(argv[2]);	switch(argv[1][0]) {		case '1':		case 'b':			value = in8(port);			break;		case '2':		case 'h':			value = in16(port);			break;		case '4':		case 'w':			value = in32(port);			break;		default:			dprintf("invalid width argument\n");			return;	}	dprintf("I/O port 0x%x = 0x%x\n", port, value);}static void dbg_out(int argc, char **argv){	int value;	int port;	if(argc < 3) {		dprintf("not enough args\nusage: %s (1|2|4) port value\n", argv[0]);		return;	}	port = atoul(argv[2]);	value = atoul(argv[3]);	switch(argv[1][0]) {		case '1':		case 'b':			out8(value, port);			break;		case '2':		case 'h':			out16(value, port);			break;		case '4':		case 'w':			out32(value, port);			break;		default:			dprintf("invalid width argument\n");			return;	}	dprintf("writing 0x%x to I/O port 0x%x\n", value, port);}

⌨️ 快捷键说明

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