Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move CPUID functions into driver #24

Merged
merged 1 commit into from
Feb 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ build-kernel:
nasm -felf32 driver/a20/check_a20.asm -o check_a20.o
nasm -felf32 driver/a20/enable_a20.asm -o enable_a20.o
nasm -felf32 driver/pic/disable.asm -o pic_disable.o
nasm -felf32 driver/cpuid/cpuid.asm -o cpuid_asm.o
$(ARCH)-elf-as driver/gdt/gdt.asm -o gdt_asm.o
$(ARCH)-elf-as driver/idt/idt.asm -o idt_asm.o

Expand All @@ -32,6 +33,7 @@ build-kernel:
$(ARCH)-elf-gcc -c driver/pic/pic.c -o pic.o $(CFLAGS)
$(ARCH)-elf-gcc -c driver/gdt/gdt.c -o gdt.o $(CFLAGS)
$(ARCH)-elf-gcc -c driver/idt/idt.c -o idt.o $(CFLAGS)
$(ARCH)-elf-gcc -c driver/cpuid/cpuid.c -o cpuid.o $(CFLAGS)
$(ARCH)-elf-gcc -c driver/pit.c -o pit.o $(CFLAGS)
$(ARCH)-elf-gcc -c driver/nmi.c -o nmi.o $(CFLAGS)
$(ARCH)-elf-gcc -c driver/memory.c -o memory.o $(CFLAGS)
Expand Down
94 changes: 94 additions & 0 deletions driver/cpuid/cpuid.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
section .text

global _cpuid_clear
_cpuid_clear:
xor ebx, ebx
xor ecx, ecx
xor edx, edx
ret

global _cpuid_detect
_cpuid_detect:
pushfd ;Save EFLAGS
pushfd ;Store EFLAGS
xor dword [esp],0x00200000 ;Invert the ID bit in stored EFLAGS
popfd ;Load stored EFLAGS (with ID bit inverted)
pushfd ;Store EFLAGS again (ID bit may or may not be inverted)
pop eax ;eax = modified EFLAGS (ID bit may or may not be inverted)
xor eax,[esp] ;eax = whichever bits were changed
popfd ;Restore original EFLAGS
and eax,0x00200000 ;eax = zero if ID bit can't be changed, else non-zero
ret

;
; EAX=0x0
; https://en.wikipedia.org/wiki/CPUID#EAX=0:_Highest_Function_Parameter
;
; Gets the highest CPUID function supported by the processor.
global _cpuid_gethighestfunction
_cpuid_gethighestfunction:
mov eax, 0x0
cpuid
ret

;
; EAX=0x1
; https://en.wikipedia.org/wiki/CPUID#EAX=1:_Processor_Info_and_Feature_Bits
;
; Gets the processor signature.
global _cpuid_getsignature
_cpuid_getsignature:
xor ebx, ebx
xor ecx, ecx
xor edx, edx

mov eax, 0x1
cpuid
ret

; Gets misc. info about the processor.
global _cpuid_getmiscinfo
_cpuid_getmiscinfo:
xor ebx, ebx
xor ecx, ecx
xor edx, edx

mov eax, 0x1
cpuid
mov eax, ebx
ret

; Gets the original set of processor features.
global _cpuid_getfeatures
_cpuid_getfeatures:
xor ebx, ebx
xor ecx, ecx
xor edx, edx

mov eax, 0x1
cpuid
mov eax, edx
ret

; Gets the second set of processor features.
global _cpuid_getfeatures2
_cpuid_getfeatures2:
xor ebx, ebx
xor ecx, ecx
xor edx, edx

mov eax, 0x1
cpuid
mov eax, ecx
ret

;
; EAX=0x80000000
; https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Supported
;
; Gets the highest extended CPUID function supported by the processor.
global _cpuid_gethighestextendedfunction
_cpuid_gethighestextendedfunction:
mov eax, 0x80000000
cpuid
ret
211 changes: 211 additions & 0 deletions driver/cpuid/cpuid.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
#include <main.h>
#include <tools.h>
#include <logging.h>
#include <driver/cpuid.h>

extern void _cpuid_clear();
extern uint32_t _cpuid_detect();
extern uint32_t _cpuid_gethighestfunction();
extern uint32_t _cpuid_getsignature();
extern uint32_t _cpuid_getmiscinfo();
extern uint32_t _cpuid_getfeatures();
extern uint32_t _cpuid_getfeatures2();
extern uint32_t _cpuid_gethighestextendedfunction();

void cpuid_print_capabilities() {
char temp1[32];

// Determine if CPUID is even supported.
// A return value of 0 indicates CPUID is supported.
if(_cpuid_detect() != 0) {
// Get highest CPUID function supported
uint32_t highest_cpuidfunc = _cpuid_gethighestfunction();

// Print vendor ID if supported (should be).
log("Processor vendor: ");
char* cpuvendor[13];
cpuid_vendorstring(cpuvendor);
cpuvendor[12] = '\0';
log((char*)cpuvendor);
log("\n");

// Print processor info and feature bits if supported.
if (highest_cpuidfunc >= CPUID_GETFEATURES) {
// Get the processor signature.
uint32_t signature = _cpuid_getsignature();
log("Family ");
utoa((signature & 0x00000F00) >> 8, temp1, 10);
log(temp1);
log(", model ");
utoa((signature & 0x000000F0) >> 4, temp1, 10);
log(temp1);
log(", stepping ");
utoa(signature & 0x0000000F, temp1, 10);
log(temp1);
log("\n");

// Get processor features.
log("Supported features: ");

// EDX features.
uint32_t features = _cpuid_getfeatures();
if (features & 1)
log("FPU "); // Onboard x87 FPU.
if ((features >> 1) & 1)
log("VME "); // Virtual 8086 mode extensions.
if ((features >> 2) & 1)
log("DE "); // Debugging extensions.
if ((features >> 3) & 1)
log("PSE "); // Page Size Extension.
if ((features >> 4) & 1)
log("TSC "); // Time Stamp Counter.
if ((features >> 5) & 1)
log("MSR "); // Model-specific registers.
if ((features >> 6) & 1)
log("PAE "); // Physical Address Extension.
if ((features >> 7) & 1)
log("MCE "); // Machine Check Exception.
if ((features >> 8) & 1)
log("CX8 "); // CMPXCHG8 (compare-and-swap) instruction.
if ((features >> 9) & 1)
log("APIC "); // Onboard Advanced Programmable Interrupt Controller.
//if ((features >> 10) & 1)
// log(" "); // Reserved.
if ((features >> 11) & 1)
log("SEP "); // SYSENTER and SYSEXIT instructions.
if ((features >> 12) & 1)
log("MTRR "); // Memory Type Range Registers.
if ((features >> 13) & 1)
log("PGE "); // Page Global Enable bit in CR4.
if ((features >> 14) & 1)
log("MCA "); // Machine check architecture.
if ((features >> 15) & 1)
log("CMOV "); // Conditional move and FCMOV instructions.
if ((features >> 16) & 1)
log("PAT "); // Page Attribute Table.
if ((features >> 17) & 1)
log("PSE-36 "); // 36-bit page size extension.
if ((features >> 18) & 1)
log("PSN "); // Processor Serial Number.
if ((features >> 19) & 1)
log("CLFSH "); // CLFLUSH instruction.
//if ((features >> 20) & 1)
// log(" "); // Reserved.
if ((features >> 21) & 1)
log("DS "); // Debug store: save trace of executed jumps.
if ((features >> 22) & 1)
log("ACPI "); // Onboard thermal control MSRs for ACPI.
if ((features >> 23) & 1)
log("MMX "); // MMX instructions.
if ((features >> 24) & 1)
log("FXSR "); // FXSAVE, FXRESTOR instructions.
if ((features >> 25) & 1)
log("SSE "); // SSE instructions.
if ((features >> 26) & 1)
log("SSE2 "); // SSE2 instructions.
if ((features >> 27) & 1)
log("SS "); // CPU cache supports self-snoop.
if ((features >> 28) & 1)
log("HTT "); // Hyper-threading.
if ((features >> 29) & 1)
log("TM "); // Thermal monitor automatically limits temperature.
if ((features >> 30) & 1)
log("IA64 "); // IA64 processor emulating x86.
if ((features >> 31) & 1)
log("PBE "); // Pending Break Enable (PBE# pin) wakeup support.

// ECX features2.
uint32_t features2 = _cpuid_getfeatures2();
if (features2 & 1)
log("SSE3 "); // SSE3 instructions.
if ((features2 >> 1) & 1)
log("PCLMULQDQ "); // PCLMULQDQ support.
if ((features2 >> 2) & 1)
log("DTES64 "); // 64-bit debug store.
if ((features2 >> 3) & 1)
log("MONITOR "); // MONITOR and MWAIT instructions.
if ((features2 >> 4) & 1)
log("DS-CPL "); // CPL qualified debug store.
if ((features2 >> 5) & 1)
log("VMX "); // Virtual Machine eXtensions.
if ((features2 >> 6) & 1)
log("SMX "); // Safer Mode Extensions.
if ((features2 >> 7) & 1)
log("EST "); // Enhanced SpeedStep.
if ((features2 >> 8) & 1)
log("TM2 "); // Thermal Monitor 2.
if ((features2 >> 9) & 1)
log("SSSE3 "); // Supplemental SSE3 instructions.
if ((features2 >> 10) & 1)
log("CNXT-ID "); // L1 Context ID.
if ((features2 >> 11) & 1)
log("SDBG "); // Silicon Debug interface.
if ((features2 >> 12) & 1)
log("FMA "); // Fused multiply-add.
if ((features2 >> 13) & 1)
log("CX16 "); // CMPXCHG16B instruction.
if ((features2 >> 14) & 1)
log("XTPR "); // Can disable sending task priority messages.
if ((features2 >> 15) & 1)
log("PDCM "); // Perfmon & debug capability.
//if ((features2 >> 16) & 1)
// log(" "); // Reserved.
if ((features2 >> 17) & 1)
log("PCID "); // Process context identifiers.
if ((features2 >> 18) & 1)
log("DCA "); // Direct cache access for DMA writes.
if ((features2 >> 19) & 1)
log("SSE4.1 "); // SSE4.1 instructions.
if ((features2 >> 20) & 1)
log("SSE4.2 "); // SSE4.2 instructions.
if ((features2 >> 21) & 1)
log("X2APIC "); // x2APIC support.
if ((features2 >> 22) & 1)
log("MOVBE "); // MOVBE instruction (big-endian).
if ((features2 >> 23) & 1)
log("POPCNT "); // POPCNT instruction.
if ((features2 >> 24) & 1)
log("TSC-DEADLINE "); // APIC supports one-shot operation using a TSC deadline value.
if ((features2 >> 25) & 1)
log("AES "); // AES instruction set.
if ((features2 >> 26) & 1)
log("XSAVE "); // XSAVE, XRESTOR, XSETBV, XGETBV.
if ((features2 >> 27) & 1)
log("OSXSAVE "); // XSAVE enabled by OS.
if ((features2 >> 28) & 1)
log("AVX "); // Advanced Vector Extensions.
if ((features2 >> 29) & 1)
log("F16C "); // F16C (half-precision) FP support.
if ((features2 >> 30) & 1)
log("RDRND "); // RDRAND (on-chip random number generator) support.
if ((features2 >> 31) & 1)
log("HYPERVISOR "); // Running on a hypervisor (always 0 on a real CPU, but also with some hypervisors).

log("\n");
}

// Get highest extended CPUID function supported
uint32_t highestextended_cpuidfunc = _cpuid_gethighestextendedfunction();

// Does this processor support extended CPUID features?
if (highestextended_cpuidfunc >= CPUID_INTELFEATURES) {
char* cpuid[17];
cpuid_string(CPUID_INTELBRANDSTRING, cpuid);
cpuid[16] = '\0';
log((char*)cpuid);

cpuid_string(CPUID_INTELBRANDSTRINGMORE, cpuid);
cpuid[16] = '\0';
log((char*)cpuid);

cpuid_string(CPUID_INTELBRANDSTRINGEND, cpuid);
cpuid[16] = '\0';
log((char*)cpuid);
log("\n");
}
}
else {
// CPUID is not supported.
log("CPUID is not supported.\n");
}
}
12 changes: 8 additions & 4 deletions include/driver/cpuid.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
extern void _cpuid_clear();
extern void cpuid_print_capabilities();

enum cpuid_requests {
CPUID_GETVENDORSTRING,
CPUID_GETFEATURES,
Expand Down Expand Up @@ -71,7 +74,8 @@ enum {
CPUID_FEAT_EDX_PBE = 1 << 31
};

static inline int cpuid_vendorstring(uint32_t where[3]) {
static inline int cpuid_vendorstring(char* where[3]) {
_cpuid_clear();
asm volatile("cpuid":"=b"(*where),"=d"(*(where+1)),
"=c"(*(where+2)):"a"(CPUID_GETVENDORSTRING));
return (int)where[0];
Expand All @@ -87,8 +91,8 @@ static inline void cpuid(int code, uint32_t *a, uint32_t *d) {

/** issue a complete request, storing general registers output as a string
*/
static inline int cpuid_string(int code, uint32_t where[4]) {
static inline int cpuid_string(int code, char* where[4]) {
asm volatile("cpuid":"=a"(*where),"=b"(*(where+1)),
"=c"(*(where+2)),"=d"(*(where+3)):"a"(code));
"=c"(*(where+2)),"=d"(*(where+3)):"a"(code),"b"(0),"c"(0),"d"(0));
return (int)where[0];
}
}
1 change: 1 addition & 0 deletions include/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define TOOLS_H

extern char* itoa(int value, char* result, int base);
extern char* utoa(uint32_t value, char* result, int base);
extern size_t strlen(const char* str);

#endif
25 changes: 0 additions & 25 deletions src/boot.asm
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,6 @@ stack_top:

section .text

global _detect_cpuid
_detect_cpuid:
pushfd ;Save EFLAGS
pushfd ;Store EFLAGS
xor dword [esp],0x00200000 ;Invert the ID bit in stored EFLAGS
popfd ;Load stored EFLAGS (with ID bit inverted)
pushfd ;Store EFLAGS again (ID bit may or may not be inverted)
pop eax ;eax = modified EFLAGS (ID bit may or may not be inverted)
xor eax,[esp] ;eax = whichever bits were changed
popfd ;Restore original EFLAGS
and eax,0x00200000 ;eax = zero if ID bit can't be changed, else non-zero
ret

global _cpuid_string_supported
_cpuid_string_supported:
mov eax, 0x80000000
cpuid
cmp eax, 0x80000004
jb _cpuid_string_supported_errorret
xor eax, eax
ret
_cpuid_string_supported_errorret:
mov eax, 1
ret

global _enable_protected_mode
_enable_protected_mode:
mov eax, cr0
Expand Down
Loading