Skip to content
Draft
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
11 changes: 7 additions & 4 deletions builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -842,22 +842,25 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
}
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
ldflags = append(ldflags, "-mllvm", "-mattr="+config.Features()) // needed for MIPS softfloat
if config.GOOS() == "windows" {
// Options for the MinGW wrapper for the lld COFF linker.
switch config.LinkerFlavor() {
case "coff":
// Options for driving ld.lld in PE/COFF mode.
ldflags = append(ldflags,
"-Xlink=/opt:lldlto="+strconv.Itoa(speedLevel),
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"))
} else if config.GOOS() == "darwin" {
case "darwin":
// Options for the ld64-compatible lld linker.
ldflags = append(ldflags,
"--lto-O"+strconv.Itoa(speedLevel),
"-cache_path_lto", filepath.Join(cacheDir, "thinlto"))
} else {
case "gnu":
// Options for the ELF linker.
ldflags = append(ldflags,
"--lto-O"+strconv.Itoa(speedLevel),
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"),
)
default:
return fmt.Errorf("unknown linker flavor: %s", config.LinkerFlavor())
}
if config.CodeModel() != "default" {
ldflags = append(ldflags,
Expand Down
1 change: 1 addition & 0 deletions builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func TestClangAttributes(t *testing.T) {
"nintendoswitch",
"riscv-qemu",
"tkey",
"uefi-amd64",
"wasip1",
"wasip2",
"wasm",
Expand Down
16 changes: 16 additions & 0 deletions compileopts/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,22 @@ func (c *Config) LDFlags() []string {
return ldflags
}

// LinkerFlavor returns how the configured linker should be driven.
// Usually this is derived from GOOS, but targets may override it explicitly.
func (c *Config) LinkerFlavor() string {
if c.Target.LinkerFlavor != "" {
return c.Target.LinkerFlavor
}
switch c.GOOS() {
case "windows":
return "coff"
case "darwin":
return "darwin"
default:
return "gnu"
}
}

// ExtraFiles returns the list of extra files to be built and linked with the
// executable. This can include extra C and assembly files.
func (c *Config) ExtraFiles() []string {
Expand Down
3 changes: 2 additions & 1 deletion compileopts/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ type TargetSpec struct {
Scheduler string `json:"scheduler,omitempty"`
Serial string `json:"serial,omitempty"` // which serial output to use (uart, usb, none)
Linker string `json:"linker,omitempty"`
RTLib string `json:"rtlib,omitempty"` // compiler runtime library (libgcc, compiler-rt)
LinkerFlavor string `json:"linker-flavor,omitempty"` // how to drive the configured linker (for example: gnu, coff, darwin)
RTLib string `json:"rtlib,omitempty"` // compiler runtime library (libgcc, compiler-rt)
Libc string `json:"libc,omitempty"`
AutoStackSize *bool `json:"automatic-stack-size,omitempty"` // Determine stack size automatically at compile time.
DefaultStackSize uint64 `json:"default-stack-size,omitempty"` // Default stack size if the size couldn't be determined at compile time.
Expand Down
48 changes: 48 additions & 0 deletions compileopts/target_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,51 @@ func TestOverrideProperties(t *testing.T) {
}

}

func TestConfigLinkerFlavor(t *testing.T) {
tests := []struct {
name string
target *TargetSpec
goos string
want string
}{
{
name: "default gnu",
target: &TargetSpec{},
goos: "linux",
want: "gnu",
},
{
name: "default coff",
target: &TargetSpec{},
goos: "windows",
want: "coff",
},
{
name: "default darwin",
target: &TargetSpec{},
goos: "darwin",
want: "darwin",
},
{
name: "target override",
target: &TargetSpec{
LinkerFlavor: "coff",
},
goos: "linux",
want: "coff",
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
config := &Config{
Options: &Options{GOOS: tc.goos},
Target: tc.target,
}
if got := config.LinkerFlavor(); got != tc.want {
t.Fatalf("LinkerFlavor() = %q, want %q", got, tc.want)
}
})
}
}
4 changes: 4 additions & 0 deletions examples/uefi-exit/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package main

func main() {
}
74 changes: 74 additions & 0 deletions src/device/x86/cpu.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//go:build amd64

package x86

const (
CPUIDTimeStampCounter = 0x15
CPUIDProcessorFrequency = 0x16
)

type CPUExtendedFamily uint16

const (
CPUFamilyIntelCore CPUExtendedFamily = 6
)

//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

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

func getExtendedCPUFamily() CPUExtendedFamily {
family := CPUExtendedFamily((stdCpuid1Eax >> 8) & 0x0f)
family += CPUExtendedFamily((stdCpuid1Eax >> 20) & 0xff)
return family
}

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

func isIntelFamilyCore() bool {
return isIntel() && getExtendedCPUFamily() == CPUFamilyIntelCore
}

func InternalGetPerformanceCounterFrequency() uint64 {
if maxCpuidIndex >= CPUIDTimeStampCounter {
return cpuidCoreClockCalculateTSCFrequency()
}
return 0
}

func cpuidCoreClockCalculateTSCFrequency() uint64 {
var eax uint32
var ebx uint32
var ecx uint32

AsmCpuid(CPUIDTimeStampCounter, &eax, &ebx, &ecx, nil)
if eax == 0 || ebx == 0 {
return 0
}

coreCrystalFrequency := uint64(ecx)
if coreCrystalFrequency == 0 {
if !isIntelFamilyCore() {
return 0
}
coreCrystalFrequency = 24000000
}

return ((coreCrystalFrequency * uint64(ebx)) + (uint64(eax) / 2)) / uint64(eax)
}
43 changes: 43 additions & 0 deletions src/device/x86/cpu_amd64.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
.section .text

.global asmPause
asmPause:
pause
ret

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

.global asmCpuid
asmCpuid:
pushq %rbx

mov %ecx, %eax
pushq %rax

pushq %rdx
cpuid

test %r9, %r9
jz .SkipEcx
mov %ecx, (%r9)
.SkipEcx:
popq %rcx
jrcxz .SkipEax
mov %eax, (%rcx)
.SkipEax:
mov %r8, %rcx
jrcxz .SkipEbx
mov %ebx, (%rcx)
.SkipEbx:
mov 0x40(%rsp), %rcx
jrcxz .SkipEdx
mov %edx, (%rcx)
.SkipEdx:
popq %rax
popq %rbx
ret
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()
}
86 changes: 86 additions & 0 deletions src/machine/uefi/asm_amd64.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
.section .text

.global uefiCall0
uefiCall0:
pushq %rbp
movq %rsp, %rbp
subq $0x20, %rsp
callq *%rcx
movq %rbp, %rsp
popq %rbp
ret

.global uefiCall1
uefiCall1:
pushq %rbp
movq %rsp, %rbp
subq $0x20, %rsp
movq %rcx, %rax
movq %rdx, %rcx
callq *%rax
movq %rbp, %rsp
popq %rbp
ret

.global uefiCall2
uefiCall2:
pushq %rbp
movq %rsp, %rbp
subq $0x20, %rsp
movq %rcx, %rax
movq %rdx, %rcx
movq %r8, %rdx
callq *%rax
movq %rbp, %rsp
popq %rbp
ret

.global uefiCall3
uefiCall3:
pushq %rbp
movq %rsp, %rbp
subq $0x20, %rsp
movq %rcx, %rax
movq %rdx, %rcx
movq %r8, %rdx
movq %r9, %r8
callq *%rax
movq %rbp, %rsp
popq %rbp
ret

.global uefiCall4
uefiCall4:
pushq %rbp
movq %rsp, %rbp
subq $0x20, %rsp
movq %rcx, %rax
movq %rdx, %rcx
movq %r8, %rdx
movq %r9, %r8
movq 0x30(%rbp), %r9
callq *%rax
movq %rbp, %rsp
popq %rbp
ret

.global uefiCall5
uefiCall5:
pushq %rbp
movq %rsp, %rbp
subq $0x30, %rsp
movq %rcx, %rax
movq %rdx, %rcx
movq %r8, %rdx
movq %r9, %r8
movq 0x30(%rbp), %r9
movq 0x38(%rbp), %r10
movq %r10, 0x20(%rsp)
callq *%rax
movq %rbp, %rsp
popq %rbp
ret

.global ___chkstk_ms
___chkstk_ms:
ret
25 changes: 25 additions & 0 deletions src/machine/uefi/call.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package uefi

//go:nosplit
//export uefiCall0
func UefiCall0(fn uintptr) EFI_STATUS

//go:nosplit
//go:export uefiCall1
func UefiCall1(fn uintptr, a uintptr) EFI_STATUS

//go:nosplit
//go:export uefiCall2
func UefiCall2(fn uintptr, a uintptr, b uintptr) EFI_STATUS

//go:nosplit
//go:export uefiCall3
func UefiCall3(fn uintptr, a uintptr, b uintptr, c uintptr) EFI_STATUS

//go:nosplit
//go:export uefiCall4
func UefiCall4(fn uintptr, a uintptr, b uintptr, c uintptr, d uintptr) EFI_STATUS

//go:nosplit
//go:export uefiCall5
func UefiCall5(fn uintptr, a uintptr, b uintptr, c uintptr, d uintptr, e uintptr) EFI_STATUS
Loading
Loading