aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-11-22 16:30:22 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2020-11-22 22:00:33 +0100
commit48ce78335a1445b01bd3cec499bdb07c2e5adfbf (patch)
tree376551baa5cc4a519e2b6829c5a7b03a6c5e2641
parentdocs: remove highlighting from cmd examples in readme (diff)
downloadwireguard-windows-48ce78335a1445b01bd3cec499bdb07c2e5adfbf.tar.xz
wireguard-windows-48ce78335a1445b01bd3cec499bdb07c2e5adfbf.zip
go-patches: add back hires windows timer patches
This adds back the high resolution timer patches, but with the addition of Alex's recent fix to branch to the old code in the event that 0x28(%gs) is zeroed out. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch4
-rw-r--r--go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch6
-rw-r--r--go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch4
-rw-r--r--go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch4
-rw-r--r--go-patches/0005-cmd-link-handle-grouped-resource-sections.patch4
-rw-r--r--go-patches/0006-Revert-release-branch.go1.15-runtime-detect-services.patch6
-rw-r--r--go-patches/0007-runtime-do-not-explicitly-exit-on-ctrl-handler.patch4
-rw-r--r--go-patches/0008-runtime-allow-callback-functions-with-up-to-8-argume.patch6
-rw-r--r--go-patches/0009-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch419
-rw-r--r--go-patches/0010-runtime-allow-for-usleep2HighRes-to-run-without-TLS-.patch91
10 files changed, 529 insertions, 19 deletions
diff --git a/go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch b/go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch
index e534d603..4a287ee7 100644
--- a/go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch
+++ b/go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch
@@ -1,7 +1,7 @@
From fde4a13eb5eba28ac546b10752b38a80f389cc5a Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Sun, 8 Nov 2020 02:48:09 +0100
-Subject: [PATCH 1/8] cmd/link: recognize arm header of PE objects
+Subject: [PATCH 01/10] cmd/link: recognize arm header of PE objects
The linker recognizes headers for 386 and amd64 PE objects, but not arm
objects. This is easily overlooked, since its the same as the 386 header
@@ -28,5 +28,5 @@ index 0366bc7a6f..f98668a7dc 100644
textp, rsrc, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.Syms.IncVersion(), f, pkg, length, pn)
if err != nil {
--
-2.29.1
+2.29.2
diff --git a/go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch b/go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch
index d47b079d..91d90f67 100644
--- a/go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch
+++ b/go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch
@@ -1,8 +1,8 @@
From a0a59fc25f4d8aef3c7bce38c84f04c504745f0e Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Sun, 8 Nov 2020 03:09:42 +0100
-Subject: [PATCH 2/8] cmd/link: deal with ADDR32NB relocations the same way as
- ADDR32 on arm
+Subject: [PATCH 02/10] cmd/link: deal with ADDR32NB relocations the same way
+ as ADDR32 on arm
As far as I can tell, the addend is the same for both of these, and in
this context we don't really care about setting or unsetting the thumb
@@ -27,5 +27,5 @@ index cf76741f43..5839a6a5f2 100644
rAdd = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rOff:])))
--
-2.29.1
+2.29.2
diff --git a/go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch b/go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch
index 4bc72361..8dfdcb7f 100644
--- a/go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch
+++ b/go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch
@@ -1,7 +1,7 @@
From e8142ab5e3b3a513683a8e3792e6197644547981 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Sun, 8 Nov 2020 03:20:36 +0100
-Subject: [PATCH 3/8] cmd/link: ignore SEH marking on PE objects
+Subject: [PATCH 03/10] cmd/link: ignore SEH marking on PE objects
Microsoft's linker looks at whether all input objects have an empty
section called @feat.00. If all of them do, then it enables SEH;
@@ -43,5 +43,5 @@ index 5839a6a5f2..b60b84ce9f 100644
if pesym.SectionNumber > 0 {
sect = f.Sections[pesym.SectionNumber-1]
--
-2.29.1
+2.29.2
diff --git a/go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch b/go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch
index 7ecf78af..f98fa79b 100644
--- a/go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch
+++ b/go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch
@@ -1,7 +1,7 @@
From 8255e115f325a58fd4746741f9f35c2f54d70d63 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Sun, 8 Nov 2020 11:11:27 +0100
-Subject: [PATCH 4/8] cmd/link: do not mark resource section as writable
+Subject: [PATCH 04/10] cmd/link: do not mark resource section as writable
Resources are immutable, and all other linkers set this section to be
read-only and not read-write. Fix this oversight by rmoving the writable
@@ -26,5 +26,5 @@ index c9cb25dbe5..ec5b6d5f52 100644
// relocation
--
-2.29.1
+2.29.2
diff --git a/go-patches/0005-cmd-link-handle-grouped-resource-sections.patch b/go-patches/0005-cmd-link-handle-grouped-resource-sections.patch
index 787eb408..2254b175 100644
--- a/go-patches/0005-cmd-link-handle-grouped-resource-sections.patch
+++ b/go-patches/0005-cmd-link-handle-grouped-resource-sections.patch
@@ -1,7 +1,7 @@
From 5d5d74f35dd3375cda8ef2ba8257547aad107ecb Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Sun, 8 Nov 2020 11:57:42 +0100
-Subject: [PATCH 5/8] cmd/link: handle grouped resource sections
+Subject: [PATCH 05/10] cmd/link: handle grouped resource sections
The Go PE linker does not support enough generalized PE logic to
properly handle .rsrc sections gracefully. Instead a few things are
@@ -313,5 +313,5 @@ index b60b84ce9f..08832ba552 100644
l.SetAttrOnList(s, true)
textp = append(textp, s)
--
-2.29.1
+2.29.2
diff --git a/go-patches/0006-Revert-release-branch.go1.15-runtime-detect-services.patch b/go-patches/0006-Revert-release-branch.go1.15-runtime-detect-services.patch
index 933a8a36..c2c63812 100644
--- a/go-patches/0006-Revert-release-branch.go1.15-runtime-detect-services.patch
+++ b/go-patches/0006-Revert-release-branch.go1.15-runtime-detect-services.patch
@@ -1,8 +1,8 @@
From e6b4c1b3beb4f843ed40abead27c8132d29a0db8 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Fri, 11 Sep 2020 13:04:11 +0200
-Subject: [PATCH 6/8] Revert "[release-branch.go1.15] runtime: detect services
- in signal handler"
+Subject: [PATCH 06/10] Revert "[release-branch.go1.15] runtime: detect
+ services in signal handler"
This reverts commit b1253d24e159129c778377c3a2a0bde15904a417.
---
@@ -131,5 +131,5 @@ index 769197db46..a584ada702 100644
}
return 0
--
-2.29.1
+2.29.2
diff --git a/go-patches/0007-runtime-do-not-explicitly-exit-on-ctrl-handler.patch b/go-patches/0007-runtime-do-not-explicitly-exit-on-ctrl-handler.patch
index 038f5d8e..42216e9a 100644
--- a/go-patches/0007-runtime-do-not-explicitly-exit-on-ctrl-handler.patch
+++ b/go-patches/0007-runtime-do-not-explicitly-exit-on-ctrl-handler.patch
@@ -1,7 +1,7 @@
From af4eb34d920c0c727041ebf587e0de608068ed59 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Tue, 14 Jul 2020 01:41:03 -0600
-Subject: [PATCH 7/8] runtime: do not explicitly exit on ctrl handler
+Subject: [PATCH 07/10] runtime: do not explicitly exit on ctrl handler
The default ctrl+c handler should process exits in situations where it
makes sense, like console apps, but not in situations where it doesn't,
@@ -45,5 +45,5 @@ index a584ada702..a62e941229 100644
}
--
-2.29.1
+2.29.2
diff --git a/go-patches/0008-runtime-allow-callback-functions-with-up-to-8-argume.patch b/go-patches/0008-runtime-allow-callback-functions-with-up-to-8-argume.patch
index 48188173..b0eb68f8 100644
--- a/go-patches/0008-runtime-allow-callback-functions-with-up-to-8-argume.patch
+++ b/go-patches/0008-runtime-allow-callback-functions-with-up-to-8-argume.patch
@@ -1,8 +1,8 @@
From 5a7c808cbacb8c0477395c5656c1eba3ef38cd6e Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Tue, 10 Nov 2020 21:42:36 +0100
-Subject: [PATCH 8/8] runtime: allow callback functions with up to 8 arguments
- on windows/arm
+Subject: [PATCH 08/10] runtime: allow callback functions with up to 8
+ arguments on windows/arm
Previously, windows/arm programs would abort when trying to use
functions that took callbacks with more than 4 arguments. This caused
@@ -56,5 +56,5 @@ index 256b5ff7f0..049c69ec88 100644
// uint32 tstart_stdcall(M *newm);
--
-2.29.1
+2.29.2
diff --git a/go-patches/0009-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch b/go-patches/0009-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch
new file mode 100644
index 00000000..3fbb1fee
--- /dev/null
+++ b/go-patches/0009-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch
@@ -0,0 +1,419 @@
+From 1a163f2e676e4664f2db3f614eb4168bda9d4fd8 Mon Sep 17 00:00:00 2001
+From: Alex Brainman <alex.brainman@gmail.com>
+Date: Sun, 19 Jul 2020 16:06:48 +1000
+Subject: [PATCH 09/10] runtime: use CreateWaitableTimerEx to implement usleep
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+@jstarks suggested that recent versions of Windows provide access to high resolution timers. See
+
+https://github.com/golang/go/issues/8687#issuecomment-656259353
+
+for details.
+
+I tried to run this C program on my Windows 10 computer
+
+```
+ #include <stdio.h>
+ #include <Windows.h>
+
+ #pragma comment(lib, "Winmm.lib")
+
+// Apparently this is already defined when I use msvc cl.
+//#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002;
+
+int usleep(HANDLE timer, LONGLONG d) {
+ LARGE_INTEGER liDueTime;
+ DWORD ret;
+ LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
+ LARGE_INTEGER Frequency;
+
+ QueryPerformanceFrequency(&Frequency);
+ QueryPerformanceCounter(&StartingTime);
+
+ liDueTime.QuadPart = d;
+ liDueTime.QuadPart = liDueTime.QuadPart * 10; // us into 100 of ns units
+ liDueTime.QuadPart = -liDueTime.QuadPart; // negative for relative dure time
+
+ if (!SetWaitableTimer(timer, &liDueTime, 0, NULL, NULL, 0)) {
+ printf("SetWaitableTimer failed: errno=%d\n", GetLastError());
+ return 1;
+ }
+
+ ret = WaitForSingleObject(timer, INFINITE);
+ if (ret != WAIT_OBJECT_0) {
+ printf("WaitForSingleObject failed: ret=%d errno=%d\n", ret, GetLastError());
+ return 1;
+ }
+
+ QueryPerformanceCounter(&EndingTime);
+ ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
+ ElapsedMicroseconds.QuadPart *= 1000000;
+ ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;
+
+ printf("delay is %lld us - slept for %lld us\n", d, ElapsedMicroseconds.QuadPart);
+
+ return 0;
+}
+
+int testTimer(DWORD createFlag)
+{
+ HANDLE timer;
+
+ timer = CreateWaitableTimerEx(NULL, NULL, createFlag, TIMER_ALL_ACCESS);
+ if (timer == NULL) {
+ printf("CreateWaitableTimerEx failed: errno=%d\n", GetLastError());
+ return 1;
+ }
+
+ usleep(timer, 1000LL);
+ usleep(timer, 100LL);
+ usleep(timer, 10LL);
+ usleep(timer, 1LL);
+
+ CloseHandle(timer);
+
+ return 0;
+}
+
+int main()
+{
+ printf("\n1. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is off\n");
+ testTimer(0);
+
+ printf("\n2. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is off\n");
+ testTimer(CREATE_WAITABLE_TIMER_HIGH_RESOLUTION);
+
+ timeBeginPeriod(1);
+
+ printf("\n3. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is on\n");
+ testTimer(0);
+
+ printf("\n4. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is on\n");
+ testTimer(CREATE_WAITABLE_TIMER_HIGH_RESOLUTION);
+}
+```
+
+and I see this output
+
+```
+1. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is off
+delay is 1000 us - slept for 4045 us
+delay is 100 us - slept for 3915 us
+delay is 10 us - slept for 3291 us
+delay is 1 us - slept for 2234 us
+
+2. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is off
+delay is 1000 us - slept for 1076 us
+delay is 100 us - slept for 569 us
+delay is 10 us - slept for 585 us
+delay is 1 us - slept for 17 us
+
+3. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is on
+delay is 1000 us - slept for 742 us
+delay is 100 us - slept for 893 us
+delay is 10 us - slept for 414 us
+delay is 1 us - slept for 920 us
+
+4. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is on
+delay is 1000 us - slept for 1466 us
+delay is 100 us - slept for 559 us
+delay is 10 us - slept for 535 us
+delay is 1 us - slept for 5 us
+```
+
+That shows, that indeed using CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
+will provide sleeps as low as about 500 microseconds, while our
+current approach provides about 1 millisecond sleep.
+
+New approach also does not require for timeBeginPeriod to be on,
+so this change solves long standing problem with go programs draining
+laptop battery, because it calls timeBeginPeriod.
+
+This change will only run on systems where
+CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag is available. If not
+available, the runtime will fallback to original code that uses
+timeBeginPeriod.
+
+This is how this change affects benchmark reported in issue #14790
+
+name               old time/op  new time/op  delta
+ChanToSyscallPing  1.05ms ± 2%  0.68ms ±11%  -35.43%  (p=0.000 n=10+10)
+
+The benchmark was run with GOMAXPROCS set to 1.
+
+Fixes #8687
+Updates #14790
+
+Change-Id: I5b97ba58289c088c17c05292e12e45285c467eae
+Reviewed-on: https://go-review.googlesource.com/c/go/+/248699
+Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
+TryBot-Result: Go Bot <gobot@golang.org>
+Trust: Alex Brainman <alex.brainman@gmail.com>
+Reviewed-by: Austin Clements <austin@google.com>
+---
+ src/runtime/os_windows.go | 73 ++++++++++++++++++++++++++++++++-
+ src/runtime/sys_windows_386.s | 36 ++++++++++++++++
+ src/runtime/sys_windows_amd64.s | 32 +++++++++++++++
+ src/runtime/sys_windows_arm.s | 5 +++
+ 4 files changed, 144 insertions(+), 2 deletions(-)
+
+diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
+index a62e941229..9dd140c952 100644
+--- a/src/runtime/os_windows.go
++++ b/src/runtime/os_windows.go
+@@ -21,6 +21,7 @@ const (
+ //go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll"
+ //go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll"
+ //go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll"
++//go:cgo_import_dynamic runtime._CreateWaitableTimerExW CreateWaitableTimerExW%4 "kernel32.dll"
+ //go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll"
+ //go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll"
+ //go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll"
+@@ -68,6 +69,7 @@ var (
+ _CreateIoCompletionPort,
+ _CreateThread,
+ _CreateWaitableTimerA,
++ _CreateWaitableTimerExW,
+ _DuplicateHandle,
+ _ExitProcess,
+ _FreeEnvironmentStringsW,
+@@ -151,6 +153,8 @@ type mOS struct {
+ waitsema uintptr // semaphore for parking on locks
+ resumesema uintptr // semaphore to indicate suspend/resume
+
++ highResTimer uintptr // high resolution timer handle used in usleep
++
+ // preemptExtLock synchronizes preemptM with entry/exit from
+ // external C code.
+ //
+@@ -402,11 +406,21 @@ const osRelaxMinNS = 60 * 1e6
+ // osRelax is called by the scheduler when transitioning to and from
+ // all Ps being idle.
+ //
+-// On Windows, it adjusts the system-wide timer resolution. Go needs a
++// Some versions of Windows have high resolution timer. For those
++// versions osRelax is noop.
++// For Windows versions without high resolution timer, osRelax
++// adjusts the system-wide timer resolution. Go needs a
+ // high resolution timer while running and there's little extra cost
+ // if we're already using the CPU, but if all Ps are idle there's no
+ // need to consume extra power to drive the high-res timer.
+ func osRelax(relax bool) uint32 {
++ if haveHighResTimer {
++ // If the high resolution timer is available, the runtime uses the timer
++ // to sleep for short durations. This means there's no need to adjust
++ // the global clock frequency.
++ return 0
++ }
++
+ if relax {
+ return uint32(stdcall1(_timeEndPeriod, 1))
+ } else {
+@@ -414,6 +428,42 @@ func osRelax(relax bool) uint32 {
+ }
+ }
+
++// haveHighResTimer indicates that the CreateWaitableTimerEx
++// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag is available.
++var haveHighResTimer = false
++
++// createHighResTimer calls CreateWaitableTimerEx with
++// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag to create high
++// resolution timer. createHighResTimer returns new timer
++// handle or 0, if CreateWaitableTimerEx failed.
++func createHighResTimer() uintptr {
++ const (
++ // As per @jstarks, see
++ // https://github.com/golang/go/issues/8687#issuecomment-656259353
++ _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002
++
++ _SYNCHRONIZE = 0x00100000
++ _TIMER_QUERY_STATE = 0x0001
++ _TIMER_MODIFY_STATE = 0x0002
++ )
++ return stdcall4(_CreateWaitableTimerExW, 0, 0,
++ _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
++ _SYNCHRONIZE|_TIMER_QUERY_STATE|_TIMER_MODIFY_STATE)
++}
++
++func initHighResTimer() {
++ if GOARCH == "arm" {
++ // TODO: Not yet implemented.
++ return
++ }
++ h := createHighResTimer()
++ if h != 0 {
++ haveHighResTimer = true
++ usleep2Addr = unsafe.Pointer(funcPC(usleep2HighRes))
++ stdcall1(_CloseHandle, h)
++ }
++}
++
+ func osinit() {
+ asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
+ usleep2Addr = unsafe.Pointer(funcPC(usleep2))
+@@ -429,6 +479,7 @@ func osinit() {
+
+ stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
+
++ initHighResTimer()
+ timeBeginPeriodRetValue = osRelax(false)
+
+ ncpu = getproccount()
+@@ -844,9 +895,20 @@ func minit() {
+ var thandle uintptr
+ stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
+
++ // Configure usleep timer, if possible.
++ var timer uintptr
++ if haveHighResTimer {
++ timer = createHighResTimer()
++ if timer == 0 {
++ print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n")
++ throw("CreateWaitableTimerEx when creating timer failed")
++ }
++ }
++
+ mp := getg().m
+ lock(&mp.threadLock)
+ mp.thread = thandle
++ mp.highResTimer = timer
+ unlock(&mp.threadLock)
+
+ // Query the true stack base from the OS. Currently we're
+@@ -884,6 +946,10 @@ func unminit() {
+ lock(&mp.threadLock)
+ stdcall1(_CloseHandle, mp.thread)
+ mp.thread = 0
++ if mp.highResTimer != 0 {
++ stdcall1(_CloseHandle, mp.highResTimer)
++ mp.highResTimer = 0
++ }
+ unlock(&mp.threadLock)
+ }
+
+@@ -976,9 +1042,12 @@ func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
+ return stdcall(fn)
+ }
+
+-// in sys_windows_386.s and sys_windows_amd64.s
++// In sys_windows_386.s and sys_windows_amd64.s.
+ func onosstack(fn unsafe.Pointer, arg uint32)
++
++// These are not callable functions. They should only be called via onosstack.
+ func usleep2(usec uint32)
++func usleep2HighRes(usec uint32)
+ func switchtothread()
+
+ var usleep2Addr unsafe.Pointer
+diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s
+index 9e1f40925d..4ac1527ab1 100644
+--- a/src/runtime/sys_windows_386.s
++++ b/src/runtime/sys_windows_386.s
+@@ -428,6 +428,42 @@ TEXT runtime·usleep2(SB),NOSPLIT,$20
+ MOVL BP, SP
+ RET
+
++// Runs on OS stack. duration (in 100ns units) is in BX.
++TEXT runtime·usleep2HighRes(SB),NOSPLIT,$36
++ // Want negative 100ns units.
++ NEGL BX
++ MOVL $-1, hi-4(SP)
++ MOVL BX, lo-8(SP)
++
++ get_tls(CX)
++ MOVL g(CX), CX
++ MOVL g_m(CX), CX
++ MOVL (m_mOS+mOS_highResTimer)(CX), CX
++ MOVL CX, saved_timer-12(SP)
++
++ MOVL $0, fResume-16(SP)
++ MOVL $0, lpArgToCompletionRoutine-20(SP)
++ MOVL $0, pfnCompletionRoutine-24(SP)
++ MOVL $0, lPeriod-28(SP)
++ LEAL lo-8(SP), BX
++ MOVL BX, lpDueTime-32(SP)
++ MOVL CX, hTimer-36(SP)
++ MOVL SP, BP
++ MOVL runtime·_SetWaitableTimer(SB), AX
++ CALL AX
++ MOVL BP, SP
++
++ MOVL $0, ptime-28(SP)
++ MOVL $0, alertable-32(SP)
++ MOVL saved_timer-12(SP), CX
++ MOVL CX, handle-36(SP)
++ MOVL SP, BP
++ MOVL runtime·_NtWaitForSingleObject(SB), AX
++ CALL AX
++ MOVL BP, SP
++
++ RET
++
+ // Runs on OS stack.
+ TEXT runtime·switchtothread(SB),NOSPLIT,$0
+ MOVL SP, BP
+diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s
+index 6c8eecd4e7..847542592b 100644
+--- a/src/runtime/sys_windows_amd64.s
++++ b/src/runtime/sys_windows_amd64.s
+@@ -457,6 +457,38 @@ TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$48
+ MOVQ 40(SP), SP
+ RET
+
++// Runs on OS stack. duration (in 100ns units) is in BX.
++TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$72
++ MOVQ SP, AX
++ ANDQ $~15, SP // alignment as per Windows requirement
++ MOVQ AX, 64(SP)
++
++ get_tls(CX)
++ MOVQ g(CX), CX
++ MOVQ g_m(CX), CX
++ MOVQ (m_mOS+mOS_highResTimer)(CX), CX // hTimer
++ MOVQ CX, 48(SP) // save hTimer for later
++ // Want negative 100ns units.
++ NEGQ BX
++ LEAQ 56(SP), DX // lpDueTime
++ MOVQ BX, (DX)
++ MOVQ $0, R8 // lPeriod
++ MOVQ $0, R9 // pfnCompletionRoutine
++ MOVQ $0, AX
++ MOVQ AX, 32(SP) // lpArgToCompletionRoutine
++ MOVQ AX, 40(SP) // fResume
++ MOVQ runtime·_SetWaitableTimer(SB), AX
++ CALL AX
++
++ MOVQ 48(SP), CX // handle
++ MOVQ $0, DX // alertable
++ MOVQ $0, R8 // ptime
++ MOVQ runtime·_NtWaitForSingleObject(SB), AX
++ CALL AX
++
++ MOVQ 64(SP), SP
++ RET
++
+ // Runs on OS stack.
+ TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
+ MOVQ SP, AX
+diff --git a/src/runtime/sys_windows_arm.s b/src/runtime/sys_windows_arm.s
+index 049c69ec88..eaceca4bc3 100644
+--- a/src/runtime/sys_windows_arm.s
++++ b/src/runtime/sys_windows_arm.s
+@@ -472,6 +472,11 @@ TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$0
+ MOVW R4, R13 // Restore SP
+ MOVM.IA.W (R13), [R4, R15] // pop {R4, pc}
+
++// Runs on OS stack. Duration (in 100ns units) is in R0.
++// TODO: neeeds to be implemented properly.
++TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$0
++ B runtime·abort(SB)
++
+ // Runs on OS stack.
+ TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
+ MOVM.DB.W [R4, R14], (R13) // push {R4, lr}
+--
+2.29.2
+
diff --git a/go-patches/0010-runtime-allow-for-usleep2HighRes-to-run-without-TLS-.patch b/go-patches/0010-runtime-allow-for-usleep2HighRes-to-run-without-TLS-.patch
new file mode 100644
index 00000000..582f585c
--- /dev/null
+++ b/go-patches/0010-runtime-allow-for-usleep2HighRes-to-run-without-TLS-.patch
@@ -0,0 +1,91 @@
+From 1edac4879e2d4a36d339353c151cb7b9871e135f Mon Sep 17 00:00:00 2001
+From: Alex Brainman <alex.brainman@gmail.com>
+Date: Sat, 21 Nov 2020 14:56:26 +1100
+Subject: [PATCH 10/10] runtime: allow for usleep2HighRes to run without TLS
+ setup
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This change adjusts usleep2HighRes so it does not crash when TLS is
+not configured. When g is not available, usleep2HighRes just calls
+usleep2 instead.
+
+Updates #8687
+
+Change-Id: Idbb80f7b71d1da350a6a7df7c49154eb1ffe29a8
+---
+ src/runtime/sys_windows_386.s | 11 ++++++++++-
+ src/runtime/sys_windows_amd64.s | 11 ++++++++++-
+ 2 files changed, 20 insertions(+), 2 deletions(-)
+
+diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s
+index 4ac1527ab1..310c4008e5 100644
+--- a/src/runtime/sys_windows_386.s
++++ b/src/runtime/sys_windows_386.s
+@@ -430,12 +430,15 @@ TEXT runtime·usleep2(SB),NOSPLIT,$20
+
+ // Runs on OS stack. duration (in 100ns units) is in BX.
+ TEXT runtime·usleep2HighRes(SB),NOSPLIT,$36
++ get_tls(CX)
++ CMPL CX, $0
++ JE gisnotset
++
+ // Want negative 100ns units.
+ NEGL BX
+ MOVL $-1, hi-4(SP)
+ MOVL BX, lo-8(SP)
+
+- get_tls(CX)
+ MOVL g(CX), CX
+ MOVL g_m(CX), CX
+ MOVL (m_mOS+mOS_highResTimer)(CX), CX
+@@ -464,6 +467,12 @@ TEXT runtime·usleep2HighRes(SB),NOSPLIT,$36
+
+ RET
+
++gisnotset:
++ // TLS is not configured. Call usleep2 instead.
++ MOVL $runtime·usleep2(SB), AX
++ CALL AX
++ RET
++
+ // Runs on OS stack.
+ TEXT runtime·switchtothread(SB),NOSPLIT,$0
+ MOVL SP, BP
+diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s
+index 847542592b..699a6e6ff2 100644
+--- a/src/runtime/sys_windows_amd64.s
++++ b/src/runtime/sys_windows_amd64.s
+@@ -459,11 +459,14 @@ TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$48
+
+ // Runs on OS stack. duration (in 100ns units) is in BX.
+ TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$72
++ get_tls(CX)
++ CMPQ CX, $0
++ JE gisnotset
++
+ MOVQ SP, AX
+ ANDQ $~15, SP // alignment as per Windows requirement
+ MOVQ AX, 64(SP)
+
+- get_tls(CX)
+ MOVQ g(CX), CX
+ MOVQ g_m(CX), CX
+ MOVQ (m_mOS+mOS_highResTimer)(CX), CX // hTimer
+@@ -489,6 +492,12 @@ TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$72
+ MOVQ 64(SP), SP
+ RET
+
++gisnotset:
++ // TLS is not configured. Call usleep2 instead.
++ MOVQ $runtime·usleep2(SB), AX
++ CALL AX
++ RET
++
+ // Runs on OS stack.
+ TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
+ MOVQ SP, AX
+--
+2.29.2
+