Welcome to The Fiwix Project
Your small UNIX-like kernel
1 /* 2 * fiwix/kernel/cpu.c 3 * 4 * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/asm.h> 9 #include <fiwix/kernel.h> 10 #include <fiwix/utsname.h> 11 #include <fiwix/pic.h> 12 #include <fiwix/pit.h> 13 #include <fiwix/cpu.h> 14 #include <fiwix/timer.h> 15 #include <fiwix/stdio.h> 16 #include <fiwix/string.h> 17 18 char UTS_MACHINE[_UTSNAME_LENGTH + 1]; 19 20 static struct cpu_type intel[] = { 21 { 4, 22 { "i486 DX", "i486 DX", "i486 SX", "i486 DX/2", 23 "i486 SL", "i486 SX/2", NULL, "i486 DX/2 WBE", 24 "i486 DX/4", NULL, NULL, NULL, NULL, NULL, NULL, NULL } 25 }, 26 { 5, 27 { NULL, "Pentium 60/66", "Pentium 75-200", "Pentium ODfor486", 28 "PentiumMMX", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 29 NULL, NULL, NULL } 30 }, 31 { 6, 32 { NULL, "Pentium Pro", NULL, "Pentium II", NULL, "Pentium II", 33 "Intel Celeron", "Pentium III", "Pentium III", NULL, 34 "Pentium III Xeon", "Pentium III", NULL, NULL, NULL, NULL } 35 } 36 }; 37 38 static const char *cpu_flags[] = { 39 "FPU", "VME", "DE", "PSE", "TSC", "MSR", "PAE", "MCE", "CX8", "APIC", 40 "10", "SEP", "MTRR", "PGE", "MCA", "CMOV", "PAT", "PSE-36", "PSN", 41 "CLFSH", "20", "DS", "ACPI", "MMX", "FXSR", "SSE", "SSE2", "SS", 42 "HTT", "TM", "30", "PBE" 43 }; 44 45 static unsigned long int detect_cpuspeed(void) 46 { 47 unsigned long long int tsc1, tsc2; 48 49 outport_b(MODEREG, SEL_CHAN2 | LSB_MSB | TERM_COUNT | BINARY_CTR); 50 outport_b(CHANNEL2, (OSCIL / HZ) & 0xFF); 51 outport_b(CHANNEL2, (OSCIL / HZ) >> 8); 52 outport_b(PS2_SYSCTRL_B, inport_b(PS2_SYSCTRL_B) | ENABLE_SDATA | ENABLE_TMR2G); 53 54 tsc1 = 0; 55 tsc1 = get_rdtsc(); 56 57 while(!(inport_b(PS2_SYSCTRL_B) & 0x20)); 58 59 tsc2 = 0; 60 tsc2 = get_rdtsc(); 61 62 outport_b(PS2_SYSCTRL_B, inport_b(PS2_SYSCTRL_B) & ~(ENABLE_SDATA | ENABLE_TMR2G)); 63 64 return (tsc2 - tsc1) * HZ; 65 } 66 67 /* 68 * These are the 2nd and 3rd level cache values according to Intel Processor 69 * Identification and the CPUID Instruction. 70 * Application Note 485. Document Number: 241618-031. September 2006. 71 */ 72 static void show_cache(int value) 73 { 74 switch(value) { 75 /* 2nd level cache */ 76 case 0x39: 77 case 0x3B: 78 case 0x41: 79 case 0x79: 80 cpu_table.cache = "128KB L2"; 81 break; 82 case 0x3A: 83 cpu_table.cache = "192KB L2"; 84 break; 85 case 0x3C: 86 case 0x42: 87 case 0x7A: 88 case 0x82: 89 cpu_table.cache = "256KB L2"; 90 break; 91 case 0x3D: 92 cpu_table.cache = "384KB L2"; 93 break; 94 case 0x3E: 95 case 0x43: 96 case 0x7B: 97 case 0x7F: 98 case 0x83: 99 case 0x86: 100 cpu_table.cache = "512KB L2"; 101 break; 102 case 0x44: 103 case 0x78: 104 case 0x7C: 105 case 0x84: 106 case 0x87: 107 cpu_table.cache = "1MB L2"; 108 break; 109 case 0x45: 110 case 0x7D: 111 case 0x85: 112 cpu_table.cache = "2MB L2"; 113 break; 114 115 /* 3rd level cache */ 116 case 0x22: 117 cpu_table.cache = "512KB L3"; 118 break; 119 case 0x23: 120 cpu_table.cache = "1MB L3"; 121 break; 122 case 0x25: 123 cpu_table.cache = "2MB L3"; 124 break; 125 case 0x29: 126 case 0x46: 127 cpu_table.cache = "4MB L3"; 128 break; 129 case 0x49: 130 cpu_table.cache = "4MB L3 & L2"; 131 break; 132 case 0x4A: 133 cpu_table.cache = "6MB L3"; 134 break; 135 case 0x47: 136 case 0x4B: 137 cpu_table.cache = "8MB L3"; 138 break; 139 case 0x4C: 140 cpu_table.cache = "12MB L3"; 141 break; 142 case 0x4D: 143 cpu_table.cache = "16MB L3"; 144 break; 145 default: 146 break; 147 } 148 } 149 150 static void check_cache(int maxcpuid) 151 { 152 int n, maxcpuids; 153 154 maxcpuids = 1; 155 if(maxcpuid >= 2) { 156 for(n = 0; n < maxcpuids; n++) { 157 tlbinfo(); 158 maxcpuids = _tlbinfo_eax & 0xFF; 159 show_cache((_tlbinfo_eax >> 8) & 0xFF); 160 show_cache((_tlbinfo_eax >> 16) & 0xFF); 161 show_cache((_tlbinfo_eax >> 24) & 0xFF); 162 if(!(_tlbinfo_ebx & RESERVED_DESC)) { 163 show_cache(_tlbinfo_ebx & 0xFF); 164 show_cache((_tlbinfo_ebx >> 8) & 0xFF); 165 show_cache((_tlbinfo_ebx >> 16) & 0xFF); 166 show_cache((_tlbinfo_ebx >> 24) & 0xFF); 167 } 168 if(!(_tlbinfo_ecx & RESERVED_DESC)) { 169 show_cache(_tlbinfo_ecx & 0xFF); 170 show_cache((_tlbinfo_ecx >> 8) & 0xFF); 171 show_cache((_tlbinfo_ecx >> 16) & 0xFF); 172 show_cache((_tlbinfo_ecx >> 24) & 0xFF); 173 } 174 if(!(_tlbinfo_edx & RESERVED_DESC)) { 175 show_cache(_tlbinfo_edx & 0xFF); 176 show_cache((_tlbinfo_edx >> 8) & 0xFF); 177 show_cache((_tlbinfo_edx >> 16) & 0xFF); 178 show_cache((_tlbinfo_edx >> 24) & 0xFF); 179 } 180 } 181 } 182 } 183 184 int get_cpu_flags(char *buffer, int offset) 185 { 186 int n, size; 187 unsigned int mask; 188 189 size = sprintk(buffer + offset, "flags :"); 190 for(n = 0, mask = 1; n < 32; n++, mask <<= 1) { 191 if(_cpuflags & mask) { 192 size += sprintk(buffer + offset + size, " %s", cpu_flags[n]); 193 } 194 } 195 size += sprintk(buffer + offset + size, "\n"); 196 return size; 197 } 198 199 void cpu_init(void) 200 { 201 unsigned int n; 202 int maxcpuid; 203 204 memset_b(&cpu_table, 0, sizeof(cpu_table)); 205 cpu_table.model = -1; 206 cpu_table.stepping = -1; 207 208 printk("cpu - -\t"); 209 cpu_table.family = cpuid(); 210 if(!cpu_table.family) { 211 cpu_table.has_cpuid = 1; 212 maxcpuid = get_cpu_vendor_id(); 213 cpu_table.vendor_id = _vendorid; 214 if(maxcpuid >= 1) { 215 signature_flags(); 216 cpu_table.family = _cputype; 217 cpu_table.flags = _cpuflags; 218 if(!strcmp((char *)_vendorid, "GenuineIntel")) { 219 printk("Intel "); 220 for(n = 0; n < sizeof(intel) / sizeof(struct cpu_type); n++) { 221 if(intel[n].cpu == _cputype) { 222 cpu_table.model_name = !intel[n].name[(((int)_cpusignature >> 4) & 0xF)] ? NULL : intel[n].name[(((int)_cpusignature >> 4) & 0xF)]; 223 break; 224 } 225 } 226 if(cpu_table.model_name) { 227 printk("%s", cpu_table.model_name); 228 } else { 229 printk("processor"); 230 } 231 } else if(!strcmp((char *)_vendorid, "AuthenticAMD")) { 232 printk("AMD processor"); 233 } else { 234 printk("x86"); 235 } 236 if(_cpuflags & CPU_TSC) { 237 cpu_table.hz = detect_cpuspeed(); 238 printk(" at %d.%d Mhz", (cpu_table.hz / 1000000), ((cpu_table.hz % 1000000) / 100000)); 239 check_cache(maxcpuid); 240 if(cpu_table.cache) { 241 printk(" (%s)", cpu_table.cache); 242 } 243 } 244 printk("\n"); 245 printk("\t\t\t\tvendorid=%s ", _vendorid); 246 cpu_table.model = (_cpusignature >> 4) & 0xF; 247 cpu_table.stepping = _cpusignature & 0xF; 248 printk("model=%d stepping=%d\n", cpu_table.model, cpu_table.stepping); 249 } 250 if(!brand_str()) { 251 cpu_table.model_name = _brandstr; 252 if(cpu_table.model_name[0]) { 253 printk("\t\t\t\t%s\n", cpu_table.model_name); 254 } 255 } 256 } else { 257 printk("80%d86\n", cpu_table.family); 258 cpu_table.has_cpuid = 0; 259 } 260 strcpy(UTS_MACHINE, "i386"); 261 strncpy(sys_utsname.machine, UTS_MACHINE, _UTSNAME_LENGTH); 262 cpu_table.has_fpu = getfpu(); 263 }