diff --git a/sys/arch/i386/i386/locore.s b/sys/arch/i386/i386/locore.s index 2c0079470b1a..6497c8b37412 100644 --- a/sys/arch/i386/i386/locore.s +++ b/sys/arch/i386/i386/locore.s @@ -1,4 +1,4 @@ -/* $NetBSD: locore.s,v 1.157 1996/11/18 01:06:10 fvdl Exp $ */ +/* $NetBSD: locore.s,v 1.158 1996/12/03 23:59:25 fvdl Exp $ */ /*- * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved. @@ -62,18 +62,24 @@ #include #include +/* + * override user-land alignment before including asm.h + */ +#define ALIGN_DATA .align 2 +#define ALIGN_TEXT .align 2,0x90 /* 4-byte boundaries, NOP-filled */ +#define SUPERALIGN_TEXT .align 4,0x90 /* 16-byte boundaries better for 486 */ +#define _ALIGN_TEXT ALIGN_TEXT +#include + #include + /* XXX temporary kluge; these should not be here */ #define IOM_BEGIN 0x0a0000 /* start of I/O memory "hole" */ #define IOM_END 0x100000 /* end of I/O memory "hole" */ #define IOM_SIZE (IOM_END - IOM_BEGIN) -#define ALIGN_DATA .align 2 -#define ALIGN_TEXT .align 2,0x90 /* 4-byte boundaries, NOP-filled */ -#define SUPERALIGN_TEXT .align 4,0x90 /* 16-byte boundaries better for 486 */ - /* NB: NOP now preserves registers so NOPs can be inserted anywhere */ /* XXX: NOP and FASTER_NOP are misleadingly named */ #ifdef DUMMY_NOPS /* this will break some older machines */ @@ -138,7 +144,13 @@ .set _APTD,(_APTmap + APTDPTDI * NBPG) .set _APTDpde,(_PTD + APTDPTDI * 4) # XXX 4 == sizeof pde -#define ENTRY(name) .globl _/**/name; ALIGN_TEXT; _/**/name: + +/* + * Non-profiled, profiled, and alternate entry points. + * + * XXX most entry points should be profilable. Due to ignorance of which + * are safe, only a few (bcopy, copyin, copyout) are profiled. + */ #define ALTENTRY(name) .globl _/**/name; _/**/name: /* @@ -146,10 +158,14 @@ */ .data - .globl _cpu,_cpu_vendor,_cold,_esym,_boothowto,_bootdev,_atdevbase + .globl _cpu,_cpu_id,_cpu_vendor,_cpuid_level,_cpu_feature + .globl _cold,_esym,_boothowto,_bootdev,_atdevbase .globl _cyloffset,_proc0paddr,_curpcb,_PTDpaddr,_biosbasemem .globl _biosextmem,_dynamic_gdt -_cpu: .long 0 # are we 386, 386sx, or 486 +_cpu: .long 0 # are we 386, 386sx, or 486, or Pentium, or.. +_cpu_id: .long 0 # saved from `cpuid' instruction +_cpu_feature: .long 0 # feature flags from 'cpuid' instruction +_cpuid_level: .long -1 # max. level accepted by 'cpuid' instruction _cpu_vendor: .space 16 # vendor string returned by `cpuid' instruction _cold: .long 1 # cold till we are not _esym: .long 0 # ptr to end of syms @@ -230,6 +246,26 @@ try386: /* Try to toggle alignment check flag; does not exist on 386. */ testl %eax,%eax jnz try486 + + /* + * Try the test of a NexGen CPU -- ZF will not change on a DIV + * instruction on a NexGen, it will on an i386. Documented in + * Nx586 Processor Recognition Application Note, NexGen, Inc. + */ + movl $0x5555,%eax + xorl %edx,%edx + movl $2,%ecx + jnz is386 + +isnx586: + /* + * Don't try cpuid, as Nx586s reportedly don't support the + * PSL_ID bit. + */ + movl $CPU_NX586,RELOC(_cpu) + jmp 2f + +is386: movl $CPU_386,RELOC(_cpu) jmp 2f @@ -269,8 +305,6 @@ is486: movl $CPU_486,RELOC(_cpu) jne 2f # yes; must not be Cyrix CPU movl $CPU_486DLC,RELOC(_cpu) # set CPU type - movl $0x69727943,RELOC(_cpu_vendor) # store vendor string - movb $0x78,RELOC(_cpu_vendor)+4 #ifndef CYRIX_CACHE_WORKS /* Disable caching of the ISA hole only. */ @@ -334,17 +368,16 @@ is486: movl $CPU_486,RELOC(_cpu) try586: /* Use the `cpuid' instruction. */ xorl %eax,%eax cpuid + movl %eax,RELOC(_cpuid_level) movl %ebx,RELOC(_cpu_vendor) # store vendor string movl %edx,RELOC(_cpu_vendor)+4 movl %ecx,RELOC(_cpu_vendor)+8 + movl $0, RELOC(_cpu_vendor)+12 movl $1,%eax cpuid - rorl $8,%eax # extract family type - andl $15,%eax - cmpl $5,%eax - jb is486 # less than a Pentium - movl $CPU_586,RELOC(_cpu) + movl %eax,RELOC(_cpu_id) # store cpu_id and features + movl %edx,RELOC(_cpu_feature) 2: /* @@ -561,7 +594,7 @@ begin: call _main -ENTRY(proc_trampoline) +NENTRY(proc_trampoline) pushl %ebx call %esi addl $4,%esp @@ -573,7 +606,7 @@ ENTRY(proc_trampoline) /* * Signal trampoline; copied to top of user stack. */ -ENTRY(sigcode) +NENTRY(sigcode) call SIGF_HANDLER(%esp) leal SIGF_SC(%esp),%eax # scp (the call may have clobbered the # copy at SIGF_SCP(%esp)) @@ -597,7 +630,7 @@ _esigcode: /*****************************************************************************/ #ifdef COMPAT_SVR4 -ENTRY(svr4_sigcode) +NENTRY(svr4_sigcode) call SVR4_SIGF_HANDLER(%esp) leal SVR4_SIGF_UC(%esp),%eax # ucp (the call may have clobbered the # copy at SIGF_UCP(%esp)) @@ -626,7 +659,7 @@ _svr4_esigcode: /* * Signal trampoline; copied to top of user stack. */ -ENTRY(linux_sigcode) +NENTRY(linux_sigcode) call LINUX_SIGF_HANDLER(%esp) leal LINUX_SIGF_SC(%esp),%ebx # scp (the call may have clobbered the # copy at SIGF_SCP(%esp)) @@ -653,7 +686,7 @@ _linux_esigcode: /* * Signal trampoline; copied to top of user stack. */ -ENTRY(freebsd_sigcode) +NENTRY(freebsd_sigcode) call FREEBSD_SIGF_HANDLER(%esp) leal FREEBSD_SIGF_SC(%esp),%eax # scp (the call may have clobbered # the copy at SIGF_SCP(%esp)) @@ -775,8 +808,8 @@ ENTRY(bcopyw) * bcopy(caddr_t from, caddr_t to, size_t len); * Copy len bytes. */ -ENTRY(bcopy) ALTENTRY(ovbcopy) +ENTRY(bcopy) pushl %esi pushl %edi movl 12(%esp),%esi @@ -853,10 +886,10 @@ ENTRY(copyout) ja _copy_fault #if defined(I386_CPU) -#if defined(I486_CPU) || defined(I586_CPU) +#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) cmpl $CPUCLASS_386,_cpu_class jne 3f -#endif /* I486_CPU || I586_CPU */ +#endif /* I486_CPU || I586_CPU || I686_CPU */ testl %eax,%eax # anything to do? jz 3f @@ -989,10 +1022,10 @@ ENTRY(copyoutstr) movl 20(%esp),%edx # edx = maxlen #if defined(I386_CPU) -#if defined(I486_CPU) || defined(I586_CPU) +#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) cmpl $CPUCLASS_386,_cpu_class jne 5f -#endif /* I486_CPU || I586_CPU */ +#endif /* I486_CPU || I586_CPU || I686_CPU */ /* Compute number of bytes in first page. */ movl %edi,%eax @@ -1054,7 +1087,7 @@ ENTRY(copyoutstr) jmp copystr_return #endif /* I386_CPU */ -#if defined(I486_CPU) || defined(I586_CPU) +#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) 5: /* * Get min(%edx, VM_MAXUSER_ADDRESS-%edi). */ @@ -1085,7 +1118,7 @@ ENTRY(copyoutstr) jae _copystr_fault movl $ENAMETOOLONG,%eax jmp copystr_return -#endif /* I486_CPU || I586_CPU */ +#endif /* I486_CPU || I586_CPU || I686_CPU */ /* * copyinstr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied); @@ -1290,10 +1323,10 @@ ENTRY(suword) movl $_fusufault,PCB_ONFAULT(%ecx) #if defined(I386_CPU) -#if defined(I486_CPU) || defined(I586_CPU) +#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) cmpl $CPUCLASS_386,_cpu_class jne 2f -#endif /* I486_CPU || I586_CPU */ +#endif /* I486_CPU || I586_CPU || I686_CPU */ movl %edx,%eax shrl $PGSHIFT,%eax # calculate pte address @@ -1331,10 +1364,10 @@ ENTRY(susword) movl $_fusufault,PCB_ONFAULT(%ecx) #if defined(I386_CPU) -#if defined(I486_CPU) || defined(I586_CPU) +#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) cmpl $CPUCLASS_386,_cpu_class jne 2f -#endif /* I486_CPU || I586_CPU */ +#endif /* I486_CPU || I586_CPU || I686_CPU */ movl %edx,%eax shrl $PGSHIFT,%eax # calculate pte address @@ -1373,10 +1406,10 @@ ENTRY(suswintr) movl $_fusubail,PCB_ONFAULT(%ecx) #if defined(I386_CPU) -#if defined(I486_CPU) || defined(I586_CPU) +#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) cmpl $CPUCLASS_386,_cpu_class jne 2f -#endif /* I486_CPU || I586_CPU */ +#endif /* I486_CPU || I586_CPU || I686_CPU */ movl %edx,%eax shrl $PGSHIFT,%eax # calculate pte address @@ -1407,10 +1440,10 @@ ENTRY(subyte) movl $_fusufault,PCB_ONFAULT(%ecx) #if defined(I386_CPU) -#if defined(I486_CPU) || defined(I586_CPU) +#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) cmpl $CPUCLASS_386,_cpu_class jne 2f -#endif /* I486_CPU || I586_CPU */ +#endif /* I486_CPU || I586_CPU || I686_CPU */ movl %edx,%eax shrl $PGSHIFT,%eax # calculate pte address @@ -1446,7 +1479,7 @@ ENTRY(subyte) * void lgdt(struct region_descriptor *rdp); * Change the global descriptor table. */ -ENTRY(lgdt) +NENTRY(lgdt) /* Reload the descriptor table. */ movl 4(%esp),%eax lgdt (%eax) @@ -1506,7 +1539,7 @@ ENTRY(longjmp) * setrunqueue(struct proc *p); * Insert a process on the appropriate queue. Should be called at splclock(). */ -ENTRY(setrunqueue) +NENTRY(setrunqueue) movl 4(%esp),%eax #ifdef DIAGNOSTIC cmpl $0,P_BACK(%eax) # should not be on q already @@ -1537,7 +1570,7 @@ ENTRY(setrunqueue) * remrunqueue(struct proc *p); * Remove a process from its queue. Should be called at splclock(). */ -ENTRY(remrunqueue) +NENTRY(remrunqueue) movl 4(%esp),%ecx movzbl P_PRIORITY(%ecx),%eax #ifdef DIAGNOSTIC @@ -1587,7 +1620,7 @@ ENTRY(idle) jmp _idle #ifdef DIAGNOSTIC -ENTRY(switch_error) +NENTRY(switch_error) pushl $1f call _panic /* NOTREACHED */ @@ -1978,16 +2011,16 @@ IDTVEC(align) * necessary, and resume as if we were handling a general protection fault. * This will cause the process to get a SIGBUS. */ -ENTRY(resume_iret) +NENTRY(resume_iret) ZTRAP(T_PROTFLT) -ENTRY(resume_pop_ds) +NENTRY(resume_pop_ds) movl $GSEL(GDATA_SEL, SEL_KPL),%eax movl %ax,%es -ENTRY(resume_pop_es) +NENTRY(resume_pop_es) movl $T_PROTFLT,TF_TRAPNO(%esp) jmp calltrap -ENTRY(alltraps) +NENTRY(alltraps) INTRENTRY calltrap: #ifdef DIAGNOSTIC @@ -2032,7 +2065,7 @@ calltrap: * This code checks for a kgdb trap, then falls through * to the regular trap code. */ -ENTRY(bpttraps) +NENTRY(bpttraps) INTRENTRY testb $SEL_RPL,TF_CS(%esp) jne calltrap @@ -2126,7 +2159,7 @@ ENTRY(bzero) stosb #if defined(I486_CPU) -#if defined(I386_CPU) || defined(I586_CPU) +#if defined(I386_CPU) || defined(I586_CPU) || defined(I686_CPU) cmpl $CPUCLASS_486,_cpu_class jne 8f #endif @@ -2181,7 +2214,7 @@ ENTRY(bzero) .data apmstatus: .long 0 .text -ENTRY(apmcall) +NENTRY(apmcall) pushl %ebp movl %esp,%ebp pushl %esi @@ -2255,7 +2288,7 @@ _biostramp_image_size: * * Fills in *regs with registers as returned by BIOS. */ -ENTRY(bioscall) +NENTRY(bioscall) pushl %ebp movl %esp,%ebp /* set up frame ptr */ diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index f2a68ceb5272..1b04980e2e33 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.215 1996/11/18 01:06:12 fvdl Exp $ */ +/* $NetBSD: machdep.c,v 1.216 1996/12/03 23:59:27 fvdl Exp $ */ /*- * Copyright (c) 1993, 1994, 1995, 1996 Charles M. Hannum. All rights reserved. @@ -418,57 +418,231 @@ allocsys(v) char cpu_model[120]; extern char version[]; -struct cpu_nameclass i386_cpus[] = { - { "i386SX", CPUCLASS_386 }, /* CPU_386SX */ - { "i386DX", CPUCLASS_386 }, /* CPU_386 */ - { "i486SX", CPUCLASS_486 }, /* CPU_486SX */ - { "i486DX", CPUCLASS_486 }, /* CPU_486 */ - { "Pentium", CPUCLASS_586 }, /* CPU_586 */ - { "Cx486DLC", CPUCLASS_486 }, /* CPU_486DLC (Cyrix) */ +/* + * Note: these are just the ones that may not have a cpuid instruction. + * We deal with the rest in a different way. + */ +struct cpu_nocpuid_nameclass i386_nocpuid_cpus[] = { + { CPUVENDOR_INTEL, "Intel", "386SX", CPUCLASS_386 }, /* CPU_386SX */ + { CPUVENDOR_INTEL, "Intel", "386DX", CPUCLASS_386 }, /* CPU_386 */ + { CPUVENDOR_INTEL, "Intel", "486SX", CPUCLASS_486 }, /* CPU_486SX */ + { CPUVENDOR_INTEL, "Intel", "486DX", CPUCLASS_486 }, /* CPU_486 */ + { CPUVENDOR_CYRIX, "Cyrix", "486DLC", CPUCLASS_486 }, /* CPU_486DLC */ + { CPUVENDOR_NEXGEN,"NexGen","586", CPUCLASS_586 }, /* CPU_NX586 */ }; +const char *classnames[] = { + "386", + "486", + "586", + "686" +}; + +const char *modifiers[] = { + "", + "OverDrive ", + "Dual ", + "" +}; + +struct cpu_cpuid_nameclass i386_cpuid_cpus[] = { + { + "GenuineIntel", + CPUVENDOR_INTEL, + "Intel", + /* Family 4 */ + { { + CPUCLASS_486, + { + "486DX", "486DX", "486DX", "486DX2", "486SL", + "486SX2", 0, "486DX2 W/B Enhanced", + "486DX4", 0, 0, 0, 0, 0, 0, 0, + "486" /* Default */ + } + }, + /* Family 5 */ + { + CPUCLASS_586, + { + 0, "Pentium", "Pentium (P54C)", + "Pentium (P24T)", "Pentium", "Pentium", 0, + "Pentium (P54C)", 0, 0, 0, 0, 0, 0, 0, 0, + "Pentium" /* Default */ + } + }, + /* Family 6 */ + { + CPUCLASS_686, + { + 0, "Pentium Pro", 0, 0, "Pentium Pro", 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + "Pentium Pro" /* Default */ + } + } } + }, + { + "AuthenticAMD", + CPUVENDOR_AMD, + "AMD", + /* Family 4 */ + { { + CPUCLASS_486, + { + 0, 0, 0, "Am486DX2 W/T", + 0, 0, 0, "Am486DX2 W/B", + "Am486DX4 W/T or Am5x86 W/T 150", + "Am486DX4 W/B or Am5x86 W/B 150", 0, 0, + 0, 0, "Am5x86 W/T 133/160", + "Am5x86 W/B 133/160", + "Am486 or Am5x86" /* Default */ + }, + }, + /* Family 5 */ + { + CPUCLASS_586, + { + "K5", "K5", 0, 0, 0, 0, "K6", + 0, 0, 0, 0, 0, 0, 0, 0, 0, + "K5 or K6", /* Default */ + }, + }, + /* Family 6, not yet available from AMD */ + { + CPUCLASS_686, + { + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + "Pentium Pro compatible" /* Default */ + }, + } } + }, + { + "CyrixInstead", + CPUVENDOR_CYRIX, + "Cyrix", + /* Family 4 */ + { { + CPUCLASS_486, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "486" /* Default */ + }, + }, + /* Family 5 */ + { + CPUCLASS_586, + { + 0, 0, "6x86", 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + "6x86" /* Default */ + } + }, + /* Family 6, not yet available from Cyrix */ + { + CPUCLASS_686, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "Pentium Pro compatible" /* Default */ + } + } } + } +}; + +#define CPUDEBUG + void identifycpu() { extern char cpu_vendor[]; + extern int cpu_id; + const char *name, *modifier, *vendorname; + int class = CPUCLASS_386, vendor, i, max; + int family, model, step, modif; + struct cpu_cpuid_nameclass *cpup = NULL; - printf("CPU: "); + if (cpuid_level == -1) { #ifdef DIAGNOSTIC - if (cpu < 0 || cpu >= (sizeof i386_cpus/sizeof(struct cpu_nameclass))) - panic("unknown cpu type %d\n", cpu); + if (cpu < 0 || cpu >= + (sizeof i386_nocpuid_cpus/sizeof(struct cpu_nocpuid_nameclass))) + panic("unknown cpu type %d\n", cpu); #endif - sprintf(cpu_model, "%s (", i386_cpus[cpu].cpu_name); - if (cpu_vendor[0] != '\0') { - strcat(cpu_model, cpu_vendor); - strcat(cpu_model, " "); + name = i386_nocpuid_cpus[cpu].cpu_name; + vendor = i386_nocpuid_cpus[cpu].cpu_vendor; + vendorname = i386_nocpuid_cpus[cpu].cpu_vendorname; + class = i386_nocpuid_cpus[cpu].cpu_class; + modifier = ""; + } else { + max = sizeof (i386_cpuid_cpus) / sizeof (i386_cpuid_cpus[0]); + modif = (cpu_id >> 12) & 3; + family = (cpu_id >> 8) & 15; + if (family < CPU_MINFAMILY) + panic("identifycpu: strange family value"); + model = (cpu_id >> 4) & 15; + step = cpu_id & 15; +#ifdef CPUDEBUG + printf("cpu0: family %x model %x step %x\n", family, model, + step); +#endif + + for (i = 0; i < max; i++) { + if (!strncmp(cpu_vendor, + i386_cpuid_cpus[i].cpu_id, 12)) { + cpup = &i386_cpuid_cpus[i]; + break; + } + } + + if (cpup == NULL) { + vendor = CPUVENDOR_UNKNOWN; + if (cpu_vendor[0] != '\0') + vendorname = &cpu_vendor[0]; + else + vendorname = "Unknown"; + if (family > CPU_MAXFAMILY) + family = CPU_MAXFAMILY; + class = family - 3; + modifier = ""; + name = ""; + } else { + vendor = cpup->cpu_vendor; + vendorname = cpup->cpu_vendorname; + modifier = modifiers[modif]; + if (family > CPU_MAXFAMILY) { + family = CPU_MAXFAMILY; + model = CPU_DEFMODEL; + } else if (model > CPU_MAXMODEL) + model = CPU_DEFMODEL; + i = family - CPU_MINFAMILY; + name = cpup->cpu_family[i].cpu_models[model]; + if (name == NULL) + name = cpup->cpu_family[i].cpu_models[CPU_DEFMODEL]; + class = cpup->cpu_family[i].cpu_class; + } } - cpu_class = i386_cpus[cpu].cpu_class; - switch(cpu_class) { - case CPUCLASS_386: - strcat(cpu_model, "386"); - break; - case CPUCLASS_486: - strcat(cpu_model, "486"); - break; - case CPUCLASS_586: - strcat(cpu_model, "586"); - break; - default: - strcat(cpu_model, "unknown"); /* will panic below... */ - break; - } - strcat(cpu_model, "-class CPU)"); - printf("%s\n", cpu_model); /* cpu speed would be nice, but how? */ + sprintf(cpu_model, "%s %s%s (%s-class)", vendorname, modifier, name, + classnames[class]); + printf("cpu0: %s\n", cpu_model); + + cpu_class = class; /* * Now that we have told the user what they have, * let them know if that machine type isn't configured. */ switch (cpu_class) { -#if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU) +#if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU) && !defined(I686_CPU) #error No CPU classes configured. #endif +#ifndef I686_CPU + case CPUCLASS_686: + printf("NOTICE: this kernel does not support Pentium Pro CPU class\n"); +#ifdef I586_CPU + printf("NOTICE: lowering CPU class to i586\n"); + cpu_class = CPUCLASS_586; + break; +#endif +#endif #ifndef I586_CPU case CPUCLASS_586: printf("NOTICE: this kernel does not support Pentium CPU class\n"); @@ -508,7 +682,7 @@ identifycpu() #endif } -#if defined(I486_CPU) || defined(I586_CPU) +#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) /* * On a 486 or above, enable ring 0 write protection. */