diff --git a/.gitignore b/.gitignore
index 816f59df14e2a3e62303d98af67a091e8bd11f24..52263cdb803db2019c62874488fd748ba1eaba6f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ _testmain.go
 /src/go/build/zcgo.go
 /src/go/doc/headscan
 /src/internal/buildcfg/zbootstrap.go
+/src/internal/platform/zosarch.go
 /src/runtime/internal/sys/zversion.go
 /src/unicode/maketables
 /src/time/tzdata/zzipdata.go
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index e460b2d1cca616394cae8b13758e2df6adc31101..1d329ab9f14828a9bf3b329e093ca2e8e9158af4 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -626,14 +626,16 @@ var deptab = []struct {
 }{
 	{"cmd/go/internal/cfg", []string{
 		"zdefaultcc.go",
+	}},
+	{"go/build", []string{
+		"zcgo.go",
+	}},
+	{"internal/platform", []string{
 		"zosarch.go",
 	}},
 	{"runtime/internal/sys", []string{
 		"zversion.go",
 	}},
-	{"go/build", []string{
-		"zcgo.go",
-	}},
 	{"time/tzdata", []string{
 		"zzipdata.go",
 	}},
@@ -650,10 +652,10 @@ var gentab = []struct {
 	nameprefix string
 	gen        func(string, string)
 }{
+	{"zcgo.go", mkzcgo},
 	{"zdefaultcc.go", mkzdefaultcc},
 	{"zosarch.go", mkzosarch},
 	{"zversion.go", mkzversion},
-	{"zcgo.go", mkzcgo},
 	{"zzipdata.go", mktzdata},
 
 	// not generated anymore, but delete the file if we see it
@@ -1196,6 +1198,7 @@ var cleanlist = []string{
 	"runtime/internal/sys",
 	"cmd/cgo",
 	"cmd/go/internal/cfg",
+	"internal/platform",
 	"go/build",
 }
 
diff --git a/src/cmd/dist/buildgo.go b/src/cmd/dist/buildgo.go
index d6a3b8121435e2695769af3252d7edd76720bf79..2e8bb8c27d5247fcfb3b7f357e1634588a73a5c3 100644
--- a/src/cmd/dist/buildgo.go
+++ b/src/cmd/dist/buildgo.go
@@ -91,55 +91,19 @@ func defaultCCFunc(name string, defaultcc map[string]string) string {
 	return buf.String()
 }
 
-// mkzosarch writes zosarch.go for cmd/go.
-func mkzosarch(dir, file string) {
-	// sort for deterministic zosarch.go file
-	var list []string
-	for plat := range cgoEnabled {
-		list = append(list, plat)
-	}
-	sort.Strings(list)
-
-	var buf strings.Builder
-	fmt.Fprintf(&buf, "// Code generated by go tool dist; DO NOT EDIT.\n\n")
-	fmt.Fprintf(&buf, "package cfg\n\n")
-	fmt.Fprintf(&buf, "var OSArchSupportsCgo = map[string]bool{\n")
-	for _, plat := range list {
-		fmt.Fprintf(&buf, "\t%s: %v,\n", quote(plat), cgoEnabled[plat])
-	}
-	fmt.Fprintf(&buf, "}\n")
-
-	writefile(buf.String(), file, writeSkipSame)
-}
-
 // mkzcgo writes zcgo.go for the go/build package:
 //
 //	package build
-//	var cgoEnabled = map[string]bool{}
+//	const defaultCGO_ENABLED = <CGO_ENABLED>
 //
 // It is invoked to write go/build/zcgo.go.
 func mkzcgo(dir, file string) {
-	// sort for deterministic zcgo.go file
-	var list []string
-	for plat, hasCgo := range cgoEnabled {
-		if hasCgo {
-			list = append(list, plat)
-		}
-	}
-	sort.Strings(list)
-
 	var buf strings.Builder
 	fmt.Fprintf(&buf, "// Code generated by go tool dist; DO NOT EDIT.\n")
 	fmt.Fprintln(&buf)
 	fmt.Fprintf(&buf, "package build\n")
 	fmt.Fprintln(&buf)
 	fmt.Fprintf(&buf, "const defaultCGO_ENABLED = %s\n", quote(os.Getenv("CGO_ENABLED")))
-	fmt.Fprintln(&buf)
-	fmt.Fprintf(&buf, "var cgoEnabled = map[string]bool{\n")
-	for _, plat := range list {
-		fmt.Fprintf(&buf, "\t%s: true,\n", quote(plat))
-	}
-	fmt.Fprintf(&buf, "}\n")
 
 	writefile(buf.String(), file, writeSkipSame)
 }
diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go
index 932c509fa4db5a6eb7e708f0f2cd6fe969c29cf1..20f49ca744e17a5477dec3ae893f8aec1eb0df95 100644
--- a/src/cmd/dist/buildruntime.go
+++ b/src/cmd/dist/buildruntime.go
@@ -6,6 +6,7 @@ package main
 
 import (
 	"fmt"
+	"sort"
 	"strings"
 )
 
@@ -82,3 +83,26 @@ func mkobjabi(file string) {
 
 	writefile(buf.String(), file, writeSkipSame)
 }
+
+// mkzosarch writes zosarch.go for internal/platform.
+func mkzosarch(dir, file string) {
+	// sort for deterministic file contents.
+	var list []string
+	for plat := range cgoEnabled {
+		list = append(list, plat)
+	}
+	sort.Strings(list)
+
+	var buf strings.Builder
+	fmt.Fprintf(&buf, "// Code generated by go tool dist; DO NOT EDIT.\n")
+	fmt.Fprintln(&buf)
+	fmt.Fprintf(&buf, "package platform\n")
+	fmt.Fprintln(&buf)
+	fmt.Fprintf(&buf, "var osArchSupportsCgo = map[string]bool{\n")
+	for _, plat := range list {
+		fmt.Fprintf(&buf, "\t\t%s: %v,\n", quote(plat), cgoEnabled[plat])
+	}
+	fmt.Fprintf(&buf, "}\n")
+
+	writefile(buf.String(), file, writeSkipSame)
+}
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index e06991d726ef78291ab9f1ebec50f246b26c991e..c88e01c3de4e83880b246ad63a0fc8463254089b 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -121,6 +121,7 @@ func bootstrapBuildTools() {
 
 	mkbuildcfg(pathf("%s/src/internal/buildcfg/zbootstrap.go", goroot))
 	mkobjabi(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot))
+	mkzosarch("", pathf("%s/src/internal/platform/zosarch.go", goroot))
 
 	// Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
 	// We use a subdirectory of $GOROOT/pkg because that's the
diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go
index ed7bb6c4bbfe5ecd06e35da9e8288b92f644df26..edb82d01f55814bf8a9c24d912660a4d4c4cc2f0 100644
--- a/src/cmd/go/internal/cfg/cfg.go
+++ b/src/cmd/go/internal/cfg/cfg.go
@@ -141,6 +141,7 @@ func defaultContext() build.Context {
 		// (1) environment, (2) go/env file, (3) runtime constants,
 		// while go/build.Default.GOOS/GOARCH are derived from the preference list
 		// (1) environment, (2) runtime constants.
+		//
 		// We know ctxt.GOOS/GOARCH == runtime.GOOS/GOARCH;
 		// no matter how that happened, go/build.Default will make the
 		// same decision (either the environment variables are set explicitly
diff --git a/src/cmd/go/internal/work/action.go b/src/cmd/go/internal/work/action.go
index 123d994a9d349b389e453e5428d4d76ca2c9a7b8..de59c09d1abbf7a3bee276122879955cb1ae9acf 100644
--- a/src/cmd/go/internal/work/action.go
+++ b/src/cmd/go/internal/work/action.go
@@ -14,6 +14,7 @@ import (
 	"debug/elf"
 	"encoding/json"
 	"fmt"
+	"internal/platform"
 	"os"
 	"path/filepath"
 	"strings"
@@ -355,7 +356,7 @@ func closeBuilders() {
 }
 
 func CheckGOOSARCHPair(goos, goarch string) error {
-	if _, ok := cfg.OSArchSupportsCgo[goos+"/"+goarch]; !ok && cfg.BuildContext.Compiler == "gc" {
+	if !platform.BuildModeSupported(cfg.BuildContext.Compiler, "default", goos, goarch) {
 		return fmt.Errorf("unsupported GOOS/GOARCH pair %s/%s", goos, goarch)
 	}
 	return nil
diff --git a/src/cmd/go/internal/work/init.go b/src/cmd/go/internal/work/init.go
index 88a63282855abd93246af1b6c037c953972452c0..8242e32fef41c89d7357caa4da5c761937edee81 100644
--- a/src/cmd/go/internal/work/init.go
+++ b/src/cmd/go/internal/work/init.go
@@ -283,7 +283,7 @@ func buildModeInit() {
 		base.Fatalf("buildmode=%s not supported", cfg.BuildBuildmode)
 	}
 
-	if !platform.BuildModeSupported(cfg.BuildToolchainName, cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) {
+	if cfg.BuildBuildmode != "default" && !platform.BuildModeSupported(cfg.BuildToolchainName, cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) {
 		base.Fatalf("-buildmode=%s not supported on %s/%s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch)
 	}
 
diff --git a/src/cmd/go/note_test.go b/src/cmd/go/note_test.go
index 659366dcf97bdf4388e7dd6333ca7da7f2499ed7..ba7ec2a47bcc43f5faaaf3f6b489b66b32b6e1e0 100644
--- a/src/cmd/go/note_test.go
+++ b/src/cmd/go/note_test.go
@@ -5,7 +5,7 @@
 package main_test
 
 import (
-	"go/build"
+	"internal/testenv"
 	"runtime"
 	"testing"
 
@@ -32,7 +32,7 @@ func TestNoteReading(t *testing.T) {
 	}
 
 	switch {
-	case !build.Default.CgoEnabled:
+	case !testenv.HasCGO():
 		t.Skipf("skipping - no cgo, so assuming external linking not available")
 	case runtime.GOOS == "plan9":
 		t.Skipf("skipping - external linking not supported")
diff --git a/src/cmd/go/testdata/script/list_all_gobuild.txt b/src/cmd/go/testdata/script/list_all_gobuild.txt
index e0a47398bbd92f25d3561239eedd330e8067b299..92ad7d885660ecc4aaf1be84789b40643013bbf6 100644
--- a/src/cmd/go/testdata/script/list_all_gobuild.txt
+++ b/src/cmd/go/testdata/script/list_all_gobuild.txt
@@ -1,5 +1,6 @@
 # go list all should work with GOOS=linux because all packages build on Linux
 env GOOS=linux
+env GOARCH=amd64
 go list all
 
 # go list all should work with GOOS=darwin, but it used to fail because
diff --git a/src/cmd/go/testdata/script/tooltags.txt b/src/cmd/go/testdata/script/tooltags.txt
index 3076185bda728e8cd961c8b08450fc53e5da2dc9..27068eebaeb9590f91cd32dc667301085ef89b36 100644
--- a/src/cmd/go/testdata/script/tooltags.txt
+++ b/src/cmd/go/testdata/script/tooltags.txt
@@ -1,3 +1,5 @@
+env GOOS=linux
+
 env GOARCH=amd64
 env GOAMD64=v3
 go list -f '{{context.ToolTags}}'
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index 3abfb1461c02f5769d8878b1019d94b7ff1b15e1..6e781c924d297017152ee60db28c71d236e802b5 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -8,7 +8,6 @@ import (
 	"cmd/internal/notsha256"
 	"flag"
 	"fmt"
-	"go/build"
 	"internal/platform"
 	"internal/testenv"
 	"os"
@@ -253,7 +252,7 @@ func testDisasm(t *testing.T, srcfname string, printCode bool, printGnuAsm bool,
 func testGoAndCgoDisasm(t *testing.T, printCode bool, printGnuAsm bool) {
 	t.Parallel()
 	testDisasm(t, "fmthello.go", printCode, printGnuAsm)
-	if build.Default.CgoEnabled {
+	if testenv.HasCGO() {
 		testDisasm(t, "fmthellocgo.go", printCode, printGnuAsm)
 	}
 }
diff --git a/src/go/build/build.go b/src/go/build/build.go
index d20964e60b293b99c2e34b1db71a850b21edb9d1..dd6cdc903a21a816bd007e51c427bc19be2b1603 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -16,6 +16,7 @@ import (
 	"internal/godebug"
 	"internal/goroot"
 	"internal/goversion"
+	"internal/platform"
 	"io"
 	"io/fs"
 	"os"
@@ -345,7 +346,7 @@ func defaultContext() Context {
 	default:
 		// cgo must be explicitly enabled for cross compilation builds
 		if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
-			c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
+			c.CgoEnabled = platform.CgoSupported(c.GOOS, c.GOARCH)
 			break
 		}
 		c.CgoEnabled = false
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 4415b92a29593def5a7e5e1edea648f0d93addd8..c0f3cfd780f8cf305b72de72c20e515eb225b5b4 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -292,7 +292,7 @@ var depsRules = `
 	FMT, internal/goexperiment
 	< internal/buildcfg;
 
-	go/build/constraint, go/doc, go/parser, internal/buildcfg, internal/goroot, internal/goversion
+	go/build/constraint, go/doc, go/parser, internal/buildcfg, internal/goroot, internal/goversion, internal/platform
 	< go/build;
 
 	# databases
diff --git a/src/internal/platform/supported.go b/src/internal/platform/supported.go
index 01524fbcd77d1dd61e584c333b57be139c6755c8..57a86b054d3deb9a639558c4c4a79da2022b8148 100644
--- a/src/internal/platform/supported.go
+++ b/src/internal/platform/supported.go
@@ -126,6 +126,9 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
 	}
 
 	platform := goos + "/" + goarch
+	if _, ok := osArchSupportsCgo[platform]; !ok {
+		return false // platform unrecognized
+	}
 
 	switch buildmode {
 	case "archive":
@@ -237,3 +240,8 @@ func DefaultPIE(goos, goarch string, isRace bool) bool {
 	}
 	return false
 }
+
+// CgoSupported reports whether goos/goarch supports cgo.\n")
+func CgoSupported(goos, goarch string) bool {
+	return osArchSupportsCgo[goos+"/"+goarch]
+}