diff --git a/src/gopheros/kernel/cpu/cpu_amd64.go b/src/gopheros/kernel/cpu/cpu_amd64.go index c757266..46cf66c 100644 --- a/src/gopheros/kernel/cpu/cpu_amd64.go +++ b/src/gopheros/kernel/cpu/cpu_amd64.go @@ -1,5 +1,9 @@ package cpu +var ( + cpuidFn = ID +) + // EnableInterrupts enables interrupt handling. func EnableInterrupts() @@ -21,3 +25,34 @@ func ActivePDT() uintptr // ReadCR2 returns the value stored in the CR2 register. func ReadCR2() uint64 + +// ID returns information about the CPU and its features. It +// is implemented as a CPUID instruction with EAX=leaf and +// returns the values in EAX, EBX, ECX and EDX. +func ID(leaf uint32) (uint32, uint32, uint32, uint32) + +// IsIntel returns true if the code is running on an Intel processor. +func IsIntel() bool { + _, ebx, ecx, edx := cpuidFn(0) + return ebx == 0x756e6547 && // "Genu" + edx == 0x49656e69 && // "ineI" + ecx == 0x6c65746e // "ntel" +} + +// PortWriteByte writes a uint8 value to the requested port. +func PortWriteByte(port uint16, val uint8) + +// PortWriteWord writes a uint16 value to the requested port. +func PortWriteWord(port uint16, val uint16) + +// PortWriteDword writes a uint32 value to the requested port. +func PortWriteDword(port uint16, val uint32) + +// PortReadByte reads a uint8 value from the requested port. +func PortReadByte(port uint16) uint8 + +// PortReadWord reads a uint16 value from the requested port. +func PortReadWord(port uint16) uint16 + +// PortReadDword reads a uint32 value from the requested port. +func PortReadDword(port uint16) uint32 diff --git a/src/gopheros/kernel/cpu/cpu_amd64.s b/src/gopheros/kernel/cpu/cpu_amd64.s index b654195..0f855c5 100644 --- a/src/gopheros/kernel/cpu/cpu_amd64.s +++ b/src/gopheros/kernel/cpu/cpu_amd64.s @@ -31,3 +31,50 @@ TEXT ·ReadCR2(SB),NOSPLIT,$0 MOVQ CR2, AX MOVQ AX, ret+0(FP) RET + +TEXT ·ID(SB),NOSPLIT,$0 + MOVQ leaf+0(FP), AX + CPUID + MOVL AX, ret+0(FP) + MOVL BX, ret+4(FP) + MOVL CX, ret+8(FP) + MOVL DX, ret+12(FP) + RET + +TEXT ·PortWriteByte(SB),NOSPLIT,$0 + MOVW port+0(FP), DX + MOVB val+0(FP), AX + BYTE $0xee // out al, dx + RET + +TEXT ·PortWriteWord(SB),NOSPLIT,$0 + MOVW port+0(FP), DX + MOVW val+0(FP), AX + BYTE $0x66 + BYTE $0xef // out ax, dx + RET + +TEXT ·PortWriteDword(SB),NOSPLIT,$0 + MOVW port+0(FP), DX + MOVL val+0(FP), AX + BYTE $0xef // out eax, dx + RET + +TEXT ·PortReadByte(SB),NOSPLIT,$0 + MOVW port+0(FP), DX + BYTE $0xec // in al, dx + MOVB AX, ret+0(FP) + RET + +TEXT ·PortReadWord(SB),NOSPLIT,$0 + MOVW port+0(FP), DX + BYTE $0x66 + BYTE $0xed // in ax, dx + MOVW AX, ret+0(FP) + RET + +TEXT ·PortReadDword(SB),NOSPLIT,$0 + MOVW port+0(FP), DX + BYTE $0xed // in eax, dx + MOVL AX, ret+0(FP) + RET diff --git a/src/gopheros/kernel/cpu/cpu_amd64_test.go b/src/gopheros/kernel/cpu/cpu_amd64_test.go new file mode 100644 index 0000000..8b951ef --- /dev/null +++ b/src/gopheros/kernel/cpu/cpu_amd64_test.go @@ -0,0 +1,29 @@ +package cpu + +import "testing" + +func TestIsIntel(t *testing.T) { + defer func() { + cpuidFn = ID + }() + + specs := []struct { + eax, ebx, ecx, edx uint32 + exp bool + }{ + // CPUID output from an Intel CPU + {0xd, 0x756e6547, 0x6c65746e, 0x49656e69, true}, + // CPUID output from an AMD Athlon CPU + {0x1, 68747541, 0x444d4163, 0x69746e65, false}, + } + + for specIndex, spec := range specs { + cpuidFn = func(_ uint32) (uint32, uint32, uint32, uint32) { + return spec.eax, spec.ebx, spec.ecx, spec.edx + } + + if got := IsIntel(); got != spec.exp { + t.Errorf("[spec %d] expected IsIntel to return %t; got %t", specIndex, spec.exp, got) + } + } +}