From fb3df30d97e3824335a6c17fd8d49b9706b6b3c7 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 3 May 2022 01:26:18 +0300 Subject: [PATCH] added CPUID code from rbench and get_cpl to be used by the write-combining enable in gfx.c (again backported from rbench) --- .gitignore | 1 + src/cpuid.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cpuid.h | 96 +++++++++++++++++++++++++++++++++++ src/cpuid_s.asm | 131 +++++++++++++++++++++++++++++++++++++++++++++++ src/dos/audos.c | 3 +- src/dos/main.c | 5 ++ src/glut/main.c | 4 ++ src/sdl/main.c | 5 ++ src/util.h | 34 ++++++++++++- 9 files changed, 427 insertions(+), 3 deletions(-) create mode 100644 src/cpuid.c create mode 100644 src/cpuid.h create mode 100644 src/cpuid_s.asm diff --git a/.gitignore b/.gitignore index e86dd42..ac97839 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ Release *sdf demo *.zip +*.ZIP data *.a *.dll diff --git a/src/cpuid.c b/src/cpuid.c new file mode 100644 index 0000000..b67143a --- /dev/null +++ b/src/cpuid.c @@ -0,0 +1,151 @@ +#include +#include +#include "cpuid.h" + +static const char *cpuname(struct cpuid_info *cpu); +static const char *cpuvendor(struct cpuid_info *cpu); + +struct cpuid_info cpuid; + +void print_cpuid(struct cpuid_info *cpu) +{ + int i, col, len; + char buf[64]; + static const char *featstr[32] = { + "fpu", "vme", "dbgext", "pse", "tsc", "msr", "pae", "mce", + "cx8", "apic", "?", "sep", "mtrr", "pge", "mca", "cmov", + "pat", "pse36", "psn", "clf", "?", "dtes", "acpi", "mmx", + "fxsr", "sse", "sse2", "ss", "htt", "tm1", "ia64", "pbe"}; + static const char *feat2str[32] = { + "sse3", "pclmul", "dtes64", "monitor", "ds-cpl", "vmx", "smx", "est", + "tm2", "ssse3", "cid", "sdbg", "fma", "cx16", "etprd", "pdcm", + "?", "pcid", "dca", "sse41", "sse42", "x2apic", "movbe", "popcnt", + "?", "aes", "xsave", "osxsave", "avx", "f16c", "rdrand", "?"}; + + printf("CPU: %s - %s\n", cpuvendor(cpu), cpuname(cpu)); + printf("features:\n "); + col = 3; + for(i=0; i<32; i++) { + if(cpu->feat & (1 << i)) { + len = strlen(featstr[i]) + 1; + if(col + len >= 80) { + fputs("\n ", stdout); + col = 3; + } + col += printf(" %s", featstr[i]); + } + } + for(i=0; i<32; i++) { + if(cpu->feat2 & (1 << i)) { + len = strlen(feat2str[i]) + 1; + if(col + len >= 80) { + fputs("\n ", stdout); + col = 3; + } + col += printf(" %s", feat2str[i]); + } + } + putchar('\n'); +} + +static const char *fam4_models[16] = { + "486 DX 25/33", "486 DX 50", "486 SX", "486 DX/2", "486 SL", "486 SX/2", + 0, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB" +}; +static const char *fam5_models[16] = { + "Pentium 60/66", "Pentium 60/66", "Pentium 75-200", "OverDrive", "Pentium MMX", + 0, 0, "Mobile Pentium 75-200", "Mobile Pentium MMX", "Quark" +}; +static const char *fam6_models[16] = { + "Pentium Pro", "Pentium Pro", 0, "Pentium 2", "Pentium 2", "Pentium 2", + "Mobile Pentium 2", "Pentium 3", "Pentium 3", 0, "Pentium 3", "Pentium 3" +}; + + +static const char *cpuname(struct cpuid_info *cpu) +{ + int model, family; + char *rd, *wr; + + if(cpu->brandstr) { + /* unwank the string */ + rd = wr = cpu->brandstr; + while(*rd) { + if(rd[0] == '(' && rd[1] == 'T' && rd[2] == 'M' && rd[3] == ')') + rd += 4; + else if(rd[0] == '(' && rd[1] == 'R' && rd[2] == ')') + rd += 3; + if(rd != wr) *wr = *rd; + wr++; + rd++; + } + return cpu->brandstr; + } + + if(CPUID_EXTMODEL(cpu->id)) { + /* processors new enough to have an extended model, should also provide + * a brand string. If we end up here, we don't know what it is + */ + return "unknown"; + } + + model = CPUID_MODEL(cpu->id); + family = CPUID_FAMILY(cpu->id) | (CPUID_EXTFAMILY(cpu->id) << 4); + + switch(family) { + case 3: return "386"; + case 4: return fam4_models[model] ? fam4_models[model] : "486"; + case 5: return fam5_models[model] ? fam5_models[model] : "Pentium"; + case 6: return fam6_models[model] ? fam6_models[model] : "unknown"; + case 15: return "Pentium 4"; + default: + break; + } + return "unknown"; +} + +static const char *cpuvendor(struct cpuid_info *cpu) +{ + static char other[16]; + static const struct { const char *wank, *vendor; } unwanktab[] = { + {"GenuineIntel", "intel"}, + {"AuthenticAMD", "AMD"}, + {"AMDisbetter!", "AMD"}, + {"CentaurHauls", "IDT"}, + {"CyrixInstead", "Cyrix"}, + {"TransmetaCPU", "Transmeta"}, + {"GenuineTMx86", "Transmeta"}, + {"Geode by NSC", "NatSemi"}, + {"NexGenDriven", "NexGen"}, + {"RiseRiseRise", "Rise"}, + {"SiS SiS SiS ", "SiS"}, + {"UMC UMC UMC ", "UMC"}, + {"VIA VIA VIA ", "VIA"}, + {"Vortex86 SoC", "DM&P"}, + {" Shanghai ", "Zhaoxin"}, + {"HygonGenuine", "Hygon"}, + {"E2K MACHINE", "MCST Elbrus"}, + {"MiSTer A0486", "ao486"}, + {"bhyve bhyve ", "bhyve"}, + {" KVMKVMKVM ", "KVM"}, + {"TCGTCGTCGTCG", "qemu"}, + {"Microsoft Hv", "MS Hyper-V"}, + {" lrpepyh vr", "Parallels"}, + {"VMwareVMware", "VMware"}, + {"XenVMMXenVMM", "Xen"}, + {"ACRNACRNACRN", "ACRN"}, + {" QNXQVMBSQG ", "QNX Hypervisor"}, + {0, 0} + }; + + int i; + for(i=0; unwanktab[i].wank; i++) { + if(memcmp(cpu->vendor, unwanktab[i].wank, 12) == 0) { + return unwanktab[i].vendor; + } + } + + memcpy(other, cpu->vendor, 12); + other[12] = 0; + return other; +} diff --git a/src/cpuid.h b/src/cpuid.h new file mode 100644 index 0000000..5566f69 --- /dev/null +++ b/src/cpuid.h @@ -0,0 +1,96 @@ +#ifndef CPUID_H_ +#define CPUID_H_ + +#include "inttypes.h" + +struct cpuid_info { + uint32_t maxidx; /* 0: eax */ + char vendor[12]; /* 0: ebx, edx, ecx */ + uint32_t id; /* 1: eax */ + uint32_t rsvd0; /* 1: ebx */ + uint32_t feat; /* 1: edx */ + uint32_t feat2; /* 1: ecx */ + + char brandstr[48]; /* 80000002h-80000004h */ +}; + +extern struct cpuid_info cpuid; + +#define CPU_HAVE_MMX (cpuid.feat & CPUID_FEAT_MMX) +#define CPU_HAVE_MTRR (cpuid.feat & CPUID_FEAT_MTRR) + +#define CPUID_STEPPING(id) ((id) & 0xf) +#define CPUID_MODEL(id) (((id) >> 4) & 0xf) +#define CPUID_FAMILY(id) (((id) >> 8) & 0xf) +#define CPUID_EXTMODEL(id) (((id) >> 16) & 0xf) +#define CPUID_EXTFAMILY(id) (((id) >> 20) & 0xff) + +#define CPUID_FEAT_FPU 0x00000001 +#define CPUID_FEAT_VME 0x00000002 +#define CPUID_FEAT_DBGEXT 0x00000004 +#define CPUID_FEAT_PSE 0x00000008 +#define CPUID_FEAT_TSC 0x00000010 +#define CPUID_FEAT_MSR 0x00000020 +#define CPUID_FEAT_PAE 0x00000040 +#define CPUID_FEAT_MCE 0x00000080 +#define CPUID_FEAT_CX8 0x00000100 +#define CPUID_FEAT_APIC 0x00000200 + +#define CPUID_FEAT_SEP 0x00000800 +#define CPUID_FEAT_MTRR 0x00001000 +#define CPUID_FEAT_PGE 0x00002000 +#define CPUID_FEAT_MCA 0x00004000 +#define CPUID_FEAT_CMOV 0x00008000 +#define CPUID_FEAT_PAT 0x00010000 +#define CPUID_FEAT_PSE36 0x00020000 +#define CPUID_FEAT_PSN 0x00040000 +#define CPUID_FEAT_CLF 0x00080000 + +#define CPUID_FEAT_DTES 0x00200000 +#define CPUID_FEAT_ACPI 0x00400000 +#define CPUID_FEAT_MMX 0x00800000 +#define CPUID_FEAT_FXSR 0x01000000 +#define CPUID_FEAT_SSE 0x02000000 +#define CPUID_FEAT_SSE2 0x04000000 +#define CPUID_FEAT_SS 0x08000000 +#define CPUID_FEAT_HTT 0x10000000 +#define CPUID_FEAT_TM1 0x20000000 +#define CPUID_FEAT_IA64 0x40000000 +#define CPUID_FEAT_PBE 0x80000000 + +#define CPUID_FEAT2_SSE3 0x00000001 +#define CPUID_FEAT2_PCLMUL 0x00000002 +#define CPUID_FEAT2_DTES64 0x00000004 +#define CPUID_FEAT2_MONITOR 0x00000008 +#define CPUID_FEAT2_DS_CPL 0x00000010 +#define CPUID_FEAT2_VMX 0x00000020 +#define CPUID_FEAT2_SMX 0x00000040 +#define CPUID_FEAT2_EST 0x00000080 +#define CPUID_FEAT2_TM2 0x00000100 +#define CPUID_FEAT2_SSSE3 0x00000200 +#define CPUID_FEAT2_CID 0x00000400 +#define CPUID_FEAT2_SDBG 0x00000800 +#define CPUID_FEAT2_FMA 0x00001000 +#define CPUID_FEAT2_CX16 0x00002000 +#define CPUID_FEAT2_ETPRD 0x00004000 +#define CPUID_FEAT2_PDCM 0x00008000 + +#define CPUID_FEAT2_PCID 0x00020000 +#define CPUID_FEAT2_DCA 0x00040000 +#define CPUID_FEAT2_SSE41 0x00080000 +#define CPUID_FEAT2_SSE42 0x00100000 +#define CPUID_FEAT2_X2APIC 0x00200000 +#define CPUID_FEAT2_MOVBE 0x00400000 +#define CPUID_FEAT2_POPCNT 0x00800000 + +#define CPUID_FEAT2_AES 0x02000000 +#define CPUID_FEAT2_XSAVE 0x04000000 +#define CPUID_FEAT2_OSXSAVE 0x08000000 +#define CPUID_FEAT2_AVX 0x10000000 +#define CPUID_FEAT2_F16C 0x20000000 +#define CPUID_FEAT2_RDRAND 0x40000000 + +int read_cpuid(struct cpuid_info *info); +void print_cpuid(struct cpuid_info *info); + +#endif /* CPUID_H_ */ diff --git a/src/cpuid_s.asm b/src/cpuid_s.asm new file mode 100644 index 0000000..b7b9626 --- /dev/null +++ b/src/cpuid_s.asm @@ -0,0 +1,131 @@ + section .text +; foo_ are watcom functions, _foo are djgpp functions + +F_ID equ 0x200000 + + global read_cpuid + global _read_cpuid + global read_cpuid_ +read_cpuid_: + push eax + call check_cpuid + pop eax + jnc read_cpuid_nocheck + mov eax, -1 + ret + +_read_cpuid: +read_cpuid: + call check_cpuid + mov eax, [esp + 4] + jnc read_cpuid_nocheck + mov eax, -1 + ret + + ; determine if cpuid is available. avail: cf=0, not avail: cf=1 +check_cpuid: + pushf + pop eax + mov edx, eax ; keep a copy of the original eflags in edx + xor eax, F_ID + push eax + popf + pushf + pop eax + clc + cmp eax, edx + jnz .noerr + stc +.noerr: ret + + ; enter with the cpuid_info structure pointer in eax +read_cpuid_nocheck: + push ebp + mov ebp, esp + push ebx + push edi + push esi + push eax ; save the original struct pointer + sub esp, 8 + mov edi, eax ; struct pointer -> edi + + ; clear struct + cld + push edi + mov ecx, (32+48)/4 + xor eax, eax + rep stosd + pop edi + + xor eax, eax + mov [esp], eax ; current index + cpuid + + mov [edi], eax ; maxidx + ; clamp to the size of our cpuid_info structure + cmp eax, 1 + jbe .skipclamp + mov eax, 1 +.skipclamp: + mov [esp + 4], eax ; maximum index + + mov [edi + 4], ebx ; vendor name + mov [edi + 8], edx + mov [edi + 12], ecx + add edi, 16 + +.loop: mov eax, [esp] + inc eax + cmp eax, [esp + 4] + ja .loopend + mov [esp], eax + cpuid + mov [edi], eax + mov [edi + 4], ebx + mov [edi + 8], edx + mov [edi + 12], ecx + add edi, 16 + jmp .loop +.loopend: + ; try to retrieve the brand string (avail on P4 or newer) + mov eax, 80000000h + cpuid + test eax, 80000000h + jz .done ; no extended cpuid functions + cmp eax, 80000004h + jb .done ; no brand string available + + ; brand string available + mov esi, esp ; save esp to esi + mov esp, [esp + 8] ; esp <- original struct pointer + add esp, 32+48 ; offset to end of brandstr + mov eax, 80000004h + cpuid + push edx + push ecx + push ebx + push eax + mov eax, 80000003h + cpuid + push edx + push ecx + push ebx + push eax + mov eax, 80000002h + cpuid + push edx + push ecx + push ebx + push eax + mov esp, esi ; done restore esp + +.done: add esp, 8 + pop eax + pop esi + pop edi + pop ebx + pop ebp + xor eax, eax + ret + +; vi:ft=nasm: diff --git a/src/dos/audos.c b/src/dos/audos.c index 74376c6..2e6f376 100644 --- a/src/dos/audos.c +++ b/src/dos/audos.c @@ -1,5 +1,6 @@ -#ifndef NO_SOUND #include + +#ifndef NO_SOUND #include #include #include diff --git a/src/dos/main.c b/src/dos/main.c index 566d47e..d820c7b 100644 --- a/src/dos/main.c +++ b/src/dos/main.c @@ -10,6 +10,7 @@ #include "audio.h" #include "sball.h" #include "vmath.h" +#include "cpuid.h" static int handle_sball_event(sball_event *ev); static void recalc_sball_matrix(float *xform); @@ -38,6 +39,10 @@ int main(int argc, char **argv) __djgpp_nearptr_enable(); #endif + if(read_cpuid(&cpuid) == 0) { + print_cpuid(&cpuid); + } + init_logger("demo.log"); /* au_init needs to be called early, before init_timer, and also before diff --git a/src/glut/main.c b/src/glut/main.c index 824837e..8d19192 100644 --- a/src/glut/main.c +++ b/src/glut/main.c @@ -11,6 +11,7 @@ #include "cfgopt.h" #include "cgmath/cgmath.h" #include "util.h" +#include "cpuid.h" static void display(void); static void idle(void); @@ -101,6 +102,9 @@ int main(int argc, char **argv) glEnable(GL_TEXTURE_2D); glEnable(GL_CULL_FACE); + if(read_cpuid(&cpuid) == 0) { + print_cpuid(&cpuid); + } if(!set_video_mode(match_video_mode(FB_WIDTH, FB_HEIGHT, FB_BPP), 1)) { return 1; diff --git a/src/sdl/main.c b/src/sdl/main.c index f2487cf..784b208 100644 --- a/src/sdl/main.c +++ b/src/sdl/main.c @@ -9,6 +9,7 @@ #include "cfgopt.h" #include "sball.h" #include "vmath.h" +#include "cpuid.h" static void handle_event(SDL_Event *ev); static void toggle_fullscreen(void); @@ -65,6 +66,10 @@ int main(int argc, char **argv) SDL_WM_SetCaption("dosdemo/SDL", 0); SDL_ShowCursor(0); + if(read_cpuid(&cpuid) == 0) { + print_cpuid(&cpuid); + } + time_msec = 0; if(demo_init(argc, argv) == -1) { /*free(fb_pixels);*/ diff --git a/src/util.h b/src/util.h index 8a46036..5f3489f 100644 --- a/src/util.h +++ b/src/util.h @@ -106,6 +106,12 @@ void debug_break(void); void halt(void); #pragma aux halt = "hlt"; + +unsigned int get_cs(void); +#pragma aux get_cs = \ + "xor eax, eax" \ + "mov ax, cs" \ + value[eax]; #endif #ifdef __GNUC__ @@ -168,14 +174,25 @@ static void INLINE memset16(void *dest, uint16_t val, int count) : "%eax", "%ebx", "%ecx", "%edx") #define debug_break() \ - asm volatile ("int $3") + asm volatile("int $3") #define halt() \ asm volatile("hlt") + +static unsigned int INLINE get_cs(void) +{ + unsigned int res; + asm volatile ( + "xor %%eax, %%eax\n\t" + "mov %%cs, %0\n\t" + : "=a"(res) + ); + return res; +} #endif #ifdef _MSC_VER -void __inline memset16(void *dest, uint16_t val, int count) +static void __inline memset16(void *dest, uint16_t val, int count) { __asm { cld @@ -221,6 +238,19 @@ void __inline memset16(void *dest, uint16_t val, int count) do { \ __asm { int 3 } \ } while(0) + +static unsigned int __inline get_cs(void) +{ + unsigned int res; + __asm { + xor eax, eax + mov ax, cs + mov [res], ax + } + return res; +} #endif +#define get_cpl() ((int)(get_cs() & 7)) + #endif /* UTIL_H_ */ -- 1.7.10.4