Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0bbef2a
feat: support uefi-amd64
jclab-joseph Nov 13, 2023
e40103f
revert: runtime_unix.go
jclab-joseph Nov 21, 2023
e060454
test: add builder test for uefi-amd64 and add cpu in uefi-amd64.json
jclab-joseph Nov 26, 2023
4da9246
refactor: remove machineTicks
jclab-joseph Nov 26, 2023
1abdb9e
fix: add default x86 features for uefi-amd64
jclab-joseph Nov 26, 2023
199ba07
Merge branch 'release' into feat/uefi
sparques Jul 2, 2025
5ac07e3
get -gc=leaking working for UEFI
sparques Jul 5, 2025
f3229e8
get basic support for Graphics Output Protocol working
sparques Jul 5, 2025
2351b2e
add stub for scheduler=none for uefi target
sparques Jul 6, 2025
88562ae
fix alloc crash
sparques Jul 8, 2025
4e80c4c
fix shadow space / UEFI ABI calling
sparques Jul 10, 2025
4d00fa4
correct symbol name for ___chkstk_ms
sparques Jul 10, 2025
ff44a76
stub-out ___chkstk_ms again; causing more problems than it solves
sparques Jul 10, 2025
fed996b
Add 7, 8, and 9
sparques Jul 10, 2025
5290ff6
add go-friendlier GraphicsOutputProtocol() function
sparques Jul 10, 2025
7bbbf1d
add more idiomatic go errors for EFI_STATUSes
sparques Jul 10, 2025
44ec117
add clean up code supposedly required by UEFI spec
sparques Jul 10, 2025
94d278a
shuffle code around; add unknown efi error
sparques Jul 11, 2025
cfd2821
add runtime.buffered and runtime.getchar
sparques Jul 11, 2025
f544394
get os.Stdin working
sparques Jul 17, 2025
219dab7
add Init() for graphics to maybe wrestle some functionality out of mi…
sparques Jul 20, 2025
e0229a1
rough first pass at serial IO protocol; not confirmed working
sparques Jul 20, 2025
ed8210c
Add support for Simple Text in Ex protocol
sparques Jul 20, 2025
7468007
fix heap allocation to resolve erroneous out of memory issues
sparques Jul 20, 2025
9509b12
rewrite heap allocator again
sparques Jul 23, 2025
7a8d434
add convenience function for getting a key via Simple Text In Ex Prot…
sparques Jul 29, 2025
507fb60
implement os.Getenv(), os.Setenv(), and os.Eviron() via non-volatile …
sparques Jul 29, 2025
9595b4b
get os.Args working (works with flag package!)
sparques Jul 29, 2025
109441b
correct Serial IO implementation
sparques Aug 1, 2025
f25fb0c
make that whole cooperative scheduling thing work a bit better
sparques Aug 2, 2025
280bd26
add/correct documentation
sparques Aug 5, 2025
6d293a9
bug fix for Serial IO; start preliminary support for IPv4 / SNP
sparques Aug 16, 2025
25470f2
add Block IO Protocol and Disk IO Protocol
sparques Aug 16, 2025
d5f3883
basic simple file system protocol support
sparques Aug 20, 2025
d2c73a0
Merge branch 'release' into feat/uefi
sparques Aug 20, 2025
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
5 changes: 5 additions & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,10 @@ ifneq ($(WASM), 0)
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
$(TINYGO) build -size short -o wasm.wasm -target=wasm-unknown examples/hello-wasm-unknown
endif
$(TINYGO) build -size short -o test.exe -target=uefi-amd64 examples/empty
@$(MD5SUM) test.exe
$(TINYGO) build -size short -o test.exe -target=uefi-amd64 examples/time-offset
@$(MD5SUM) test.exe
# test various compiler flags
$(TINYGO) build -size short -o test.hex -target=pca10040 -gc=none -scheduler=none examples/blinky1
@$(MD5SUM) test.hex
Expand All @@ -943,6 +947,7 @@ endif
GOOS=windows GOARCH=arm64 $(TINYGO) build -size short -o test.exe ./testdata/cgo
GOOS=darwin GOARCH=amd64 $(TINYGO) build -size short -o test ./testdata/cgo
GOOS=darwin GOARCH=arm64 $(TINYGO) build -size short -o test ./testdata/cgo
$(TINYGO) build -size short -o test.exe -target=uefi-amd64 ./testdata/cgo
ifneq ($(OS),Windows_NT)
# TODO: this does not yet work on Windows. Somehow, unused functions are
# not garbage collected.
Expand Down
9 changes: 8 additions & 1 deletion builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -807,8 +807,15 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
ldflags = append(ldflags, dependency.result)
}
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
buildTags := config.BuildTags()
isWindowsLinker := config.GOOS() == "windows"
for _, tag := range buildTags {
if tag == "uefi" {
isWindowsLinker = true
}
}
ldflags = append(ldflags, "-mllvm", "-mattr="+config.Features()) // needed for MIPS softfloat
if config.GOOS() == "windows" {
if isWindowsLinker {
// Options for the MinGW wrapper for the lld COFF linker.
ldflags = append(ldflags,
"-Xlink=/opt:lldlto="+strconv.Itoa(speedLevel),
Expand Down
1 change: 1 addition & 0 deletions builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func TestClangAttributes(t *testing.T) {
"nintendoswitch",
"riscv-qemu",
"tkey",
"uefi-amd64",
"wasip1",
"wasip2",
"wasm",
Expand Down
141 changes: 141 additions & 0 deletions src/device/x86/cpu.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//go:build amd64

package x86

const (
// CPUID_TIME_STAMP_COUNTER
// EAX Returns processor base frequency information described by the
// type CPUID_PROCESSOR_FREQUENCY_EAX.
// EBX Returns maximum frequency information described by the type
// CPUID_PROCESSOR_FREQUENCY_EBX.
// ECX Returns bus frequency information described by the type
// CPUID_PROCESSOR_FREQUENCY_ECX.
// EDX Reserved.
CPUID_TIME_STAMP_COUNTER = 0x15

// CPUID_PROCESSOR_FREQUENCY
// EAX Returns processor base frequency information described by the
// type CPUID_PROCESSOR_FREQUENCY_EAX.
// EBX Returns maximum frequency information described by the type
// CPUID_PROCESSOR_FREQUENCY_EBX.
// ECX Returns bus frequency information described by the type
// CPUID_PROCESSOR_FREQUENCY_ECX.
// EDX Reserved.
CPUID_PROCESSOR_FREQUENCY = 0x16
)

type CpuExtendedFamily uint16

const (
// AMD
CPU_FAMILY_AMD_11H CpuExtendedFamily = 0x11
// Intel
CPU_FAMILY_INTEL_CORE CpuExtendedFamily = 6
CPU_MODEL_NEHALEM CpuExtendedFamily = 0x1e
CPU_MODEL_NEHALEM_EP CpuExtendedFamily = 0x1a
CPU_MODEL_NEHALEM_EX CpuExtendedFamily = 0x2e
CPU_MODEL_WESTMERE CpuExtendedFamily = 0x25
CPU_MODEL_WESTMERE_EP CpuExtendedFamily = 0x2c
CPU_MODEL_WESTMERE_EX CpuExtendedFamily = 0x2f
CPU_MODEL_SANDYBRIDGE CpuExtendedFamily = 0x2a
CPU_MODEL_SANDYBRIDGE_EP CpuExtendedFamily = 0x2d
CPU_MODEL_IVYBRIDGE_EP CpuExtendedFamily = 0x3a
CPU_MODEL_HASWELL_E3 CpuExtendedFamily = 0x3c
CPU_MODEL_HASWELL_E7 CpuExtendedFamily = 0x3f
CPU_MODEL_BROADWELL CpuExtendedFamily = 0x3d
)

func GetExtendedCpuFamily() CpuExtendedFamily {
var family CpuExtendedFamily
family = CpuExtendedFamily((stdCpuid1Eax >> 8) & 0x0f)
family += CpuExtendedFamily((stdCpuid1Eax >> 20) & 0xff)
return family
}

//export asmPause
func AsmPause()

//export asmReadRdtsc
func AsmReadRdtsc() uint64

//export asmCpuid
func AsmCpuid(index uint32, registerEax *uint32, registerEbx *uint32, registerEcx *uint32, registerEdx *uint32) int

var maxCpuidIndex uint32
var stdVendorName0 uint32
var stdCpuid1Eax uint32
var stdCpuid1Ebx uint32
var stdCpuid1Ecx uint32
var stdCpuid1Edx uint32

func init() {
AsmCpuid(0, &maxCpuidIndex, &stdVendorName0, nil, nil)
AsmCpuid(1, &stdCpuid1Eax, &stdCpuid1Ebx, &stdCpuid1Ecx, &stdCpuid1Edx)
}

func GetMaxCpuidIndex() uint32 {
return maxCpuidIndex
}

func IsIntel() bool {
return stdVendorName0 == 0x756e6547
}

func IsIntelFamilyCore() bool {
return IsIntel() && GetExtendedCpuFamily() == CPU_FAMILY_INTEL_CORE
}

func IsAmd() bool {
return stdVendorName0 == 0x68747541
}

func InternalGetPerformanceCounterFrequency() uint64 {
if maxCpuidIndex >= CPUID_TIME_STAMP_COUNTER {
return CpuidCoreClockCalculateTscFrequency()
}

return 0
}

func CpuidCoreClockCalculateTscFrequency() uint64 {
var TscFrequency uint64
var CoreXtalFrequency uint64
var RegEax uint32
var RegEbx uint32
var RegEcx uint32

AsmCpuid(CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, nil)

// If EAX or EBX returns 0, the XTAL ratio is not enumerated.
if (RegEax == 0) || (RegEbx == 0) {
return 0
}

// If ECX returns 0, the XTAL frequency is not enumerated.
// And PcdCpuCoreCrystalClockFrequency defined should base on processor series.
//
if RegEcx == 0 {
// Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.
// https://github.com/torvalds/linux/blob/master/tools/power/x86/turbostat/turbostat.c
if IsIntelFamilyCore() {
switch GetExtendedCpuFamily() {
case 0x5F: // INTEL_FAM6_ATOM_GOLDMONT_D
CoreXtalFrequency = 25000000
case 0x5C: // INTEL_FAM6_ATOM_GOLDMONT
CoreXtalFrequency = 19200000
case 0x7A: // INTEL_FAM6_ATOM_GOLDMONT_PLUS
CoreXtalFrequency = 19200000
default:
CoreXtalFrequency = 24000000
}
} else {
return 0
}
} else {
CoreXtalFrequency = uint64(RegEcx)
}

// Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
TscFrequency = ((CoreXtalFrequency * uint64(RegEbx)) + (uint64(RegEax) / 2)) / uint64(RegEax)
return TscFrequency
}
59 changes: 59 additions & 0 deletions src/device/x86/cpu_amd64.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.section .text

.global asmPause
asmPause:
pause
ret

.global asmReadRdtsc
asmReadRdtsc:
rdtsc
shlq $0x20, %rdx
orq %rdx, %rax
ret

// @param Index The 32-bit value to load into EAX prior to invoking the CPUID
// instruction.
// @param RegisterEax A pointer to the 32-bit EAX value returned by the CPUID
// instruction. This is an optional parameter that may be NULL.
// @param RegisterEbx A pointer to the 32-bit EBX value returned by the CPUID
// instruction. This is an optional parameter that may be NULL.
// @param RegisterEcx A pointer to the 32-bit ECX value returned by the CPUID
// instruction. This is an optional parameter that may be NULL.
// @param RegisterEdx A pointer to the 32-bit EDX value returned by the CPUID
// instruction. This is an optional parameter that may be NULL.
// @return Index.
.global asmCpuid
asmCpuid:
// rcx = Index
// rdx = RegisterEax
// r8 = RegisterEbx
// r9 = RegisterEcx
// rsp + 0x28 = RegisterEdx
pushq %rbx

mov %ecx, %eax // eax <- index
pushq %rax // save Index on stack

pushq %rdx // RegisterEax
cpuid

test %r9, %r9 // RegisterEcx
jz .SkipEcx
mov %ecx, (%r9)
.SkipEcx:
popq %rcx // RegisterEax
jrcxz .SkipEax
mov %eax, (%rcx)
.SkipEax:
mov %r8, %rcx // RegisterEbx
jrcxz .SkipEbx
mov %ebx, (%rcx)
.SkipEbx:
mov 0x38(%rsp), %rcx // 0x28 + 0x10
jrcxz .SkipEdx
mov %edx, (%rcx)
.SkipEdx:
popq %rax // restore Index to rax as return value
popq %rbx
ret
7 changes: 7 additions & 0 deletions src/internal/task/task_none_uefi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build scheduler.none && uefi

package task

//go:export tinygo_task_exit
func task_exit() {
}
2 changes: 1 addition & 1 deletion src/internal/task/task_stack_amd64.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build scheduler.tasks && amd64 && !windows
//go:build scheduler.tasks && amd64 && !windows && !uefi

package task

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build scheduler.tasks && amd64 && windows
//go:build scheduler.tasks && amd64 && (windows || uefi)

package task

Expand Down
17 changes: 17 additions & 0 deletions src/machine/uefi/arch_x86.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//go:build i386 || amd64

package uefi

import "device/x86"

func Ticks() uint64 {
return x86.AsmReadRdtsc()
}

func CpuPause() {
x86.AsmPause()
}

func getTscFrequency() uint64 {
return x86.InternalGetPerformanceCounterFrequency()
}
Loading
Loading