Skip to content

Commit 0bbef2a

Browse files
committed
feat: support uefi-amd64
1 parent 777048c commit 0bbef2a

32 files changed

+2716
-95
lines changed

GNUmakefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,10 @@ ifneq ($(WASM), 0)
770770
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
771771
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
772772
endif
773+
$(TINYGO) build -size short -o test.exe -target=uefi-amd64 examples/empty
774+
@$(MD5SUM) test.exe
775+
$(TINYGO) build -size short -o test.exe -target=uefi-amd64 examples/time-offset
776+
@$(MD5SUM) test.exe
773777
# test various compiler flags
774778
$(TINYGO) build -size short -o test.hex -target=pca10040 -gc=none -scheduler=none examples/blinky1
775779
@$(MD5SUM) test.hex
@@ -786,6 +790,7 @@ endif
786790
GOOS=windows GOARCH=arm64 $(TINYGO) build -size short -o test.exe ./testdata/cgo
787791
GOOS=darwin GOARCH=amd64 $(TINYGO) build -size short -o test ./testdata/cgo
788792
GOOS=darwin GOARCH=arm64 $(TINYGO) build -size short -o test ./testdata/cgo
793+
$(TINYGO) build -size short -o test.exe -target=uefi-amd64 ./testdata/cgo
789794
ifneq ($(OS),Windows_NT)
790795
# TODO: this does not yet work on Windows. Somehow, unused functions are
791796
# not garbage collected.

builder/build.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,15 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
740740
ldflags = append(ldflags, dependency.result)
741741
}
742742
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
743-
if config.GOOS() == "windows" {
743+
buildTags := config.BuildTags()
744+
isWindowsLinker := config.GOOS() == "windows"
745+
for _, tag := range buildTags {
746+
if tag == "uefi" {
747+
isWindowsLinker = true
748+
}
749+
}
750+
751+
if isWindowsLinker {
744752
// Options for the MinGW wrapper for the lld COFF linker.
745753
ldflags = append(ldflags,
746754
"-Xlink=/opt:lldlto="+strconv.Itoa(speedLevel),

src/device/x86/cpu.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
//go:build amd64
2+
3+
package x86
4+
5+
const (
6+
// CPUID_TIME_STAMP_COUNTER
7+
// EAX Returns processor base frequency information described by the
8+
// type CPUID_PROCESSOR_FREQUENCY_EAX.
9+
// EBX Returns maximum frequency information described by the type
10+
// CPUID_PROCESSOR_FREQUENCY_EBX.
11+
// ECX Returns bus frequency information described by the type
12+
// CPUID_PROCESSOR_FREQUENCY_ECX.
13+
// EDX Reserved.
14+
CPUID_TIME_STAMP_COUNTER = 0x15
15+
16+
// CPUID_PROCESSOR_FREQUENCY
17+
// EAX Returns processor base frequency information described by the
18+
// type CPUID_PROCESSOR_FREQUENCY_EAX.
19+
// EBX Returns maximum frequency information described by the type
20+
// CPUID_PROCESSOR_FREQUENCY_EBX.
21+
// ECX Returns bus frequency information described by the type
22+
// CPUID_PROCESSOR_FREQUENCY_ECX.
23+
// EDX Reserved.
24+
CPUID_PROCESSOR_FREQUENCY = 0x16
25+
)
26+
27+
type CpuExtendedFamily uint16
28+
29+
const (
30+
// AMD
31+
CPU_FAMILY_AMD_11H CpuExtendedFamily = 0x11
32+
// Intel
33+
CPU_FAMILY_INTEL_CORE CpuExtendedFamily = 6
34+
CPU_MODEL_NEHALEM CpuExtendedFamily = 0x1e
35+
CPU_MODEL_NEHALEM_EP CpuExtendedFamily = 0x1a
36+
CPU_MODEL_NEHALEM_EX CpuExtendedFamily = 0x2e
37+
CPU_MODEL_WESTMERE CpuExtendedFamily = 0x25
38+
CPU_MODEL_WESTMERE_EP CpuExtendedFamily = 0x2c
39+
CPU_MODEL_WESTMERE_EX CpuExtendedFamily = 0x2f
40+
CPU_MODEL_SANDYBRIDGE CpuExtendedFamily = 0x2a
41+
CPU_MODEL_SANDYBRIDGE_EP CpuExtendedFamily = 0x2d
42+
CPU_MODEL_IVYBRIDGE_EP CpuExtendedFamily = 0x3a
43+
CPU_MODEL_HASWELL_E3 CpuExtendedFamily = 0x3c
44+
CPU_MODEL_HASWELL_E7 CpuExtendedFamily = 0x3f
45+
CPU_MODEL_BROADWELL CpuExtendedFamily = 0x3d
46+
)
47+
48+
func GetExtendedCpuFamily() CpuExtendedFamily {
49+
var family CpuExtendedFamily
50+
family = CpuExtendedFamily((stdCpuid1Eax >> 8) & 0x0f)
51+
family += CpuExtendedFamily((stdCpuid1Eax >> 20) & 0xff)
52+
return family
53+
}
54+
55+
//export asmPause
56+
func AsmPause()
57+
58+
//export asmReadRdtsc
59+
func AsmReadRdtsc() uint64
60+
61+
//export asmCpuid
62+
func AsmCpuid(index uint32, registerEax *uint32, registerEbx *uint32, registerEcx *uint32, registerEdx *uint32) int
63+
64+
var maxCpuidIndex uint32
65+
var stdVendorName0 uint32
66+
var stdCpuid1Eax uint32
67+
var stdCpuid1Ebx uint32
68+
var stdCpuid1Ecx uint32
69+
var stdCpuid1Edx uint32
70+
71+
func init() {
72+
AsmCpuid(0, &maxCpuidIndex, &stdVendorName0, nil, nil)
73+
AsmCpuid(1, &stdCpuid1Eax, &stdCpuid1Ebx, &stdCpuid1Ecx, &stdCpuid1Edx)
74+
}
75+
76+
func GetMaxCpuidIndex() uint32 {
77+
return maxCpuidIndex
78+
}
79+
80+
func IsIntel() bool {
81+
return stdVendorName0 == 0x756e6547
82+
}
83+
84+
func IsIntelFamilyCore() bool {
85+
return IsIntel() && GetExtendedCpuFamily() == CPU_FAMILY_INTEL_CORE
86+
}
87+
88+
func IsAmd() bool {
89+
return stdVendorName0 == 0x68747541
90+
}
91+
92+
func InternalGetPerformanceCounterFrequency() uint64 {
93+
if maxCpuidIndex >= CPUID_TIME_STAMP_COUNTER {
94+
return CpuidCoreClockCalculateTscFrequency()
95+
}
96+
97+
return 0
98+
}
99+
100+
func CpuidCoreClockCalculateTscFrequency() uint64 {
101+
var TscFrequency uint64
102+
var CoreXtalFrequency uint64
103+
var RegEax uint32
104+
var RegEbx uint32
105+
var RegEcx uint32
106+
107+
AsmCpuid(CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, nil)
108+
109+
// If EAX or EBX returns 0, the XTAL ratio is not enumerated.
110+
if (RegEax == 0) || (RegEbx == 0) {
111+
return 0
112+
}
113+
114+
// If ECX returns 0, the XTAL frequency is not enumerated.
115+
// And PcdCpuCoreCrystalClockFrequency defined should base on processor series.
116+
//
117+
if RegEcx == 0 {
118+
// Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.
119+
// https://github.com/torvalds/linux/blob/master/tools/power/x86/turbostat/turbostat.c
120+
if IsIntelFamilyCore() {
121+
switch GetExtendedCpuFamily() {
122+
case 0x5F: // INTEL_FAM6_ATOM_GOLDMONT_D
123+
CoreXtalFrequency = 25000000
124+
case 0x5C: // INTEL_FAM6_ATOM_GOLDMONT
125+
CoreXtalFrequency = 19200000
126+
case 0x7A: // INTEL_FAM6_ATOM_GOLDMONT_PLUS
127+
CoreXtalFrequency = 19200000
128+
default:
129+
CoreXtalFrequency = 24000000
130+
}
131+
} else {
132+
return 0
133+
}
134+
} else {
135+
CoreXtalFrequency = uint64(RegEcx)
136+
}
137+
138+
// Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
139+
TscFrequency = ((CoreXtalFrequency * uint64(RegEbx)) + (uint64(RegEax) / 2)) / uint64(RegEax)
140+
return TscFrequency
141+
}

src/device/x86/cpu_amd64.S

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
.section .text
2+
3+
.global asmPause
4+
asmPause:
5+
pause
6+
ret
7+
8+
.global asmReadRdtsc
9+
asmReadRdtsc:
10+
rdtsc
11+
shlq $0x20, %rdx
12+
orq %rdx, %rax
13+
ret
14+
15+
// @param Index The 32-bit value to load into EAX prior to invoking the CPUID
16+
// instruction.
17+
// @param RegisterEax A pointer to the 32-bit EAX value returned by the CPUID
18+
// instruction. This is an optional parameter that may be NULL.
19+
// @param RegisterEbx A pointer to the 32-bit EBX value returned by the CPUID
20+
// instruction. This is an optional parameter that may be NULL.
21+
// @param RegisterEcx A pointer to the 32-bit ECX value returned by the CPUID
22+
// instruction. This is an optional parameter that may be NULL.
23+
// @param RegisterEdx A pointer to the 32-bit EDX value returned by the CPUID
24+
// instruction. This is an optional parameter that may be NULL.
25+
// @return Index.
26+
.global asmCpuid
27+
asmCpuid:
28+
// rcx = Index
29+
// rdx = RegisterEax
30+
// r8 = RegisterEbx
31+
// r9 = RegisterEcx
32+
// rsp + 0x28 = RegisterEdx
33+
pushq %rbx
34+
35+
mov %ecx, %eax // eax <- index
36+
pushq %rax // save Index on stack
37+
38+
pushq %rdx // RegisterEax
39+
cpuid
40+
41+
test %r9, %r9 // RegisterEcx
42+
jz .SkipEcx
43+
mov %ecx, (%r9)
44+
.SkipEcx:
45+
popq %rcx // RegisterEax
46+
jrcxz .SkipEax
47+
mov %eax, (%rcx)
48+
.SkipEax:
49+
mov %r8, %rcx // RegisterEbx
50+
jrcxz .SkipEbx
51+
mov %ebx, (%rcx)
52+
.SkipEbx:
53+
mov 0x38(%rsp), %rcx // 0x28 + 0x10
54+
jrcxz .SkipEdx
55+
mov %edx, (%rcx)
56+
.SkipEdx:
57+
popq %rax // restore Index to rax as return value
58+
popq %rbx
59+
ret

src/internal/task/task_stack_amd64.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build scheduler.tasks && amd64 && !windows
1+
//go:build scheduler.tasks && amd64 && !windows && !uefi
22

33
package task
44

src/internal/task/task_stack_amd64_windows.go renamed to src/internal/task/task_stack_amd64_winabi.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build scheduler.tasks && amd64 && windows
1+
//go:build scheduler.tasks && amd64 && (windows || uefi)
22

33
package task
44

src/machine/uefi/arch_x86.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//go:build i386 || amd64
2+
3+
package uefi
4+
5+
import "device/x86"
6+
7+
func Ticks() uint64 {
8+
return x86.AsmReadRdtsc()
9+
}
10+
11+
func CpuPause() {
12+
x86.AsmPause()
13+
}
14+
15+
func getTscFrequency() uint64 {
16+
return x86.InternalGetPerformanceCounterFrequency()
17+
}

src/machine/uefi/asm_amd64.S

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
.section .text
2+
3+
.global uefiCall0
4+
uefiCall0:
5+
pushq %rbp
6+
movq %rsp, %rbp
7+
callq *%rcx
8+
movq %rbp, %rsp
9+
popq %rbp
10+
ret
11+
12+
.global uefiCall1
13+
uefiCall1:
14+
pushq %rbp
15+
movq %rsp, %rbp
16+
movq %rcx, %rax // rax = fn
17+
movq %rdx, %rcx
18+
callq *%rax
19+
movq %rbp, %rsp
20+
popq %rbp
21+
ret
22+
23+
.global uefiCall2
24+
uefiCall2:
25+
pushq %rbp
26+
movq %rsp, %rbp
27+
movq %rcx, %rax // rax = fn
28+
movq %rdx, %rcx
29+
movq %r8, %rdx
30+
callq *%rax
31+
movq %rbp, %rsp
32+
popq %rbp
33+
ret
34+
35+
.global uefiCall3
36+
uefiCall3:
37+
pushq %rbp
38+
movq %rsp, %rbp
39+
movq %rcx, %rax // rax = fn
40+
movq %rdx, %rcx
41+
movq %r8, %rdx
42+
movq %r9, %r8
43+
callq *%rax
44+
movq %rbp, %rsp
45+
popq %rbp
46+
ret
47+
48+
.global uefiCall4
49+
uefiCall4:
50+
pushq %rbp
51+
movq %rsp, %rbp
52+
movq %rcx, %rax // rax = fn
53+
movq %rdx, %rcx
54+
movq %r8, %rdx
55+
movq %r9, %r8
56+
57+
movq 0x30(%rbp),%r9 // 0x08(return_address) + 0x08(pushq rbp) + 0x20
58+
59+
callq *%rax
60+
movq %rbp, %rsp
61+
popq %rbp
62+
ret
63+
64+
.global uefiCall5
65+
uefiCall5:
66+
pushq %rbp
67+
movq %rsp, %rbp
68+
subq $0x30,%rsp
69+
movq %rcx, %rax // rax = fn
70+
movq %rdx, %rcx // a
71+
movq %r8, %rdx // b
72+
movq %r9, %r8 // c
73+
movq 0x30(%rbp),%r9 // d
74+
movq 0x38(%rbp),%r10 // e
75+
movq %r10,0x20(%rsp)
76+
callq *%rax
77+
movq %rbp, %rsp
78+
popq %rbp
79+
ret
80+
81+
.global uefiCall6
82+
uefiCall6:
83+
pushq %rbp
84+
movq %rsp, %rbp
85+
subq $0x30,%rsp
86+
movq %rcx, %rax // rax = fn
87+
movq %rdx, %rcx // a
88+
movq %r8, %rdx // b
89+
movq %r9, %r8 // c
90+
movq 0x30(%rbp),%r9 // d
91+
movq 0x38(%rbp),%r10 // e
92+
movq %r10,0x20(%rsp)
93+
movq 0x40(%rbp),%r10 // f
94+
movq %r10,0x28(%rsp)
95+
callq *%rax
96+
movq %rbp, %rsp
97+
popq %rbp
98+
ret

src/machine/uefi/call.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package uefi
2+
3+
//go:nosplit
4+
//export uefiCall0
5+
func UefiCall0(fn uintptr) EFI_STATUS
6+
7+
//go:nosplit
8+
//go:export uefiCall1
9+
func UefiCall1(fn uintptr, a uintptr) EFI_STATUS
10+
11+
//go:nosplit
12+
//go:export uefiCall2
13+
func UefiCall2(fn uintptr, a uintptr, b uintptr) EFI_STATUS
14+
15+
//go:nosplit
16+
//go:export uefiCall3
17+
func UefiCall3(fn uintptr, a uintptr, b uintptr, c uintptr) EFI_STATUS
18+
19+
//go:nosplit
20+
//go:export uefiCall4
21+
func UefiCall4(fn uintptr, a uintptr, b uintptr, c uintptr, d uintptr) EFI_STATUS
22+
23+
//go:nosplit
24+
//go:export uefiCall5
25+
func UefiCall5(fn uintptr, a uintptr, b uintptr, c uintptr, d uintptr, e uintptr) EFI_STATUS
26+
27+
//go:nosplit
28+
//go:export uefiCall6
29+
func UefiCall6(fn uintptr, a uintptr, b uintptr, c uintptr, d uintptr, e uintptr, f uintptr) EFI_STATUS

0 commit comments

Comments
 (0)