diff --git a/compileopts/config.go b/compileopts/config.go index 7786cd2178..1c38078fae 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -482,7 +482,11 @@ func (c *Config) LinkerFlavor() string { // 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 { - return c.Target.ExtraFiles + files := append([]string(nil), c.Target.ExtraFiles...) + if c.Scheduler() == "tasks" && c.GOARCH() == "amd64" && slices.Contains(c.Target.BuildTags, "uefi") { + files = append(files, "src/internal/task/task_stack_amd64_windows.S") + } + return files } // DumpSSA returns whether to dump Go SSA while compiling (-dumpssa flag). Only diff --git a/src/internal/task/task_stack_amd64.go b/src/internal/task/task_stack_amd64.go index d252b1c50d..bfd18b5758 100644 --- a/src/internal/task/task_stack_amd64.go +++ b/src/internal/task/task_stack_amd64.go @@ -1,4 +1,4 @@ -//go:build scheduler.tasks && amd64 && !windows +//go:build scheduler.tasks && amd64 && !windows && !uefi package task diff --git a/src/internal/task/task_stack_amd64_winabi.go b/src/internal/task/task_stack_amd64_winabi.go new file mode 100644 index 0000000000..3b9c2e22db --- /dev/null +++ b/src/internal/task/task_stack_amd64_winabi.go @@ -0,0 +1,58 @@ +//go:build scheduler.tasks && amd64 && uefi + +package task + +// This is almost the same as task_stack_amd64.go, but with the extra rdi and +// rsi registers saved: UEFI on amd64 uses the Win64 ABI. + +import "unsafe" + +var systemStack uintptr + +// calleeSavedRegs is the list of registers that must be saved and restored when +// switching between tasks. Also see task_stack_amd64_windows.S that relies on +// the exact layout of this struct. +type calleeSavedRegs struct { + // rbx is placed here so the stack is correctly aligned when saving XMM regs. + rbx uintptr + xmm15 [2]uint64 + xmm14 [2]uint64 + xmm13 [2]uint64 + xmm12 [2]uint64 + xmm11 [2]uint64 + xmm10 [2]uint64 + xmm9 [2]uint64 + xmm8 [2]uint64 + xmm7 [2]uint64 + xmm6 [2]uint64 + rbp uintptr + rdi uintptr + rsi uintptr + r12 uintptr + r13 uintptr + r14 uintptr + r15 uintptr + + pc uintptr +} + +func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) { + s.sp = uintptr(unsafe.Pointer(r)) + r.pc = uintptr(unsafe.Pointer(&startTask)) + r.r12 = fn + r.r13 = uintptr(args) +} + +func (s *state) resume() { + swapTask(s.sp, &systemStack) +} + +func (s *state) pause() { + newStack := systemStack + systemStack = 0 + swapTask(newStack, &s.sp) +} + +func SystemStack() uintptr { + return systemStack +} diff --git a/src/runtime/sleep_custom_uefi.go b/src/runtime/sleep_custom_uefi.go new file mode 100644 index 0000000000..784f3b4f28 --- /dev/null +++ b/src/runtime/sleep_custom_uefi.go @@ -0,0 +1,14 @@ +//go:build scheduler.tasks && uefi + +package runtime + +//go:linkname gosched runtime.Gosched +func gosched() + +func schedulerSleepCustom(duration int64) bool { + deadline := ticks() + nanosecondsToTicks(duration) + for ticks() < deadline { + gosched() + } + return true +} diff --git a/targets/uefi-amd64.json b/targets/uefi-amd64.json index c594aecce6..da1f5943a3 100644 --- a/targets/uefi-amd64.json +++ b/targets/uefi-amd64.json @@ -6,7 +6,7 @@ "goos": "linux", "goarch": "amd64", "gc": "leaking", - "scheduler": "none", + "scheduler": "tasks", "linker": "ld.lld", "linker-flavor": "coff", "libc": "picolibc",