diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fa04a08363df79..043b1eccf7e10c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,6 +15,9 @@ jobs: - name: Compile Go with all.bash run: | cd src ; ./all.bash + - name: Run Go distribution tests under tamago/amd64 + run: | + GO_BUILDER_NAME=tamago GOOS=tamago GOARCH=amd64 ./bin/go tool dist test - name: Run Go distribution tests under tamago/arm run: | GO_BUILDER_NAME=tamago GOOS=tamago GOARCH=arm ./bin/go tool dist test diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 535f88e4fe614c..4946f5e9d9d126 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -1773,6 +1773,7 @@ var cgoEnabled = map[string]bool{ "plan9/amd64": false, "plan9/arm": false, "solaris/amd64": true, + "tamago/amd64": false, "tamago/arm": false, "tamago/riscv64": false, "windows/386": true, diff --git a/src/internal/platform/zosarch.go b/src/internal/platform/zosarch.go index 036cd994a39980..6fd0ffc31c69ff 100644 --- a/src/internal/platform/zosarch.go +++ b/src/internal/platform/zosarch.go @@ -54,6 +54,7 @@ var List = []OSArch{ {"plan9", "amd64"}, {"plan9", "arm"}, {"solaris", "amd64"}, + {"tamago", "amd64"}, {"tamago", "arm"}, {"tamago", "riscv64"}, {"wasip1", "wasm"}, @@ -110,6 +111,7 @@ var distInfo = map[OSArch]osArchInfo{ {"plan9", "amd64"}: {}, {"plan9", "arm"}: {}, {"solaris", "amd64"}: {CgoSupported: true}, + {"tamago", "amd64"}: {}, {"tamago", "arm"}: {}, {"tamago", "riscv64"}: {}, {"wasip1", "wasm"}: {}, diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 5676d0239e0b4b..4f6e824efa0c7f 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -305,7 +305,7 @@ const ( // // On other platforms, the user address space is contiguous // and starts at 0, so no offset is necessary. - arenaBaseOffset = 0xffff800000000000*goarch.IsAmd64 + 0x0a00000000000000*goos.IsAix + arenaBaseOffset = 0xffff800000000000*goarch.IsAmd64*(1-goos.IsTamago) + 0x0a00000000000000*goos.IsAix // A typed version of this constant that will make it into DWARF (for viewcore). arenaBaseOffsetUintptr = uintptr(arenaBaseOffset) diff --git a/src/runtime/mpagealloc_64bit.go b/src/runtime/mpagealloc_64bit.go index 281e3f59ec205b..9845a079b42b2a 100644 --- a/src/runtime/mpagealloc_64bit.go +++ b/src/runtime/mpagealloc_64bit.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build amd64 || arm64 || loong64 || mips64 || mips64le || ppc64 || ppc64le || (riscv64 && !tamago) || s390x +//go:build (amd64 && !tamago) || arm64 || loong64 || mips64 || mips64le || ppc64 || ppc64le || (riscv64 && !tamago) || s390x package runtime diff --git a/src/runtime/os_tamago.go b/src/runtime/os_tamago.go new file mode 100644 index 00000000000000..3646f672950e3b --- /dev/null +++ b/src/runtime/os_tamago.go @@ -0,0 +1,207 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build tamago + +package runtime + +import ( + "internal/runtime/atomic" + "unsafe" +) + +// see testing.testBinary +var testBinary string + +// Bloc allows to override the heap memory start address +var Bloc uintptr + +// the following functions must be provided externally +func hwinit() +func printk(byte) +func getRandomData([]byte) +func initRNG() + +// the following functions must be provided externally +// (but are already stubbed somewhere else in the runtime) +//func nanotime1() int64 + +// GetRandomData generates len(r) random bytes from the random source provided +// externally by the linked application. +func GetRandomData(r []byte) { + getRandomData(r) +} + +// CallOnG0 calls a function (func(off int)) on g0 stack. +// +// The function arguments must be passed through the following registers +// (rather than on the frame pointer): +// +// * R0: fn argument (vector table offset) +// * R1: fn pointer +// * R2: size of stack area reserved for caller registers +// * R3: caller program counter +func CallOnG0() + +// WakeG modifies a goroutine cached timer for time.Sleep (g.timer) to fire as +// soon as possible. +// +// The function arguments must be passed through the following registers +// (rather than on the frame pointer): +// +// * R0: G pointer +func WakeG() + +// stubs for unused/unimplemented functionality +type mOS struct{} +type sigset struct{} +type gsignalStack struct{} + +func goenvs() {} +func sigsave(p *sigset) {} +func msigrestore(sigmask sigset) {} +func clearSignalHandlers() {} +func sigblock(exiting bool) {} +func minit() {} +func unminit() {} +func mdestroy(mp *m) {} +func setProcessCPUProfiler(hz int32) {} +func setThreadCPUProfiler(hz int32) {} +func initsig(preinit bool) {} +func osyield() {} +func osyield_no_g() {} + +// May run with m.p==nil, so write barriers are not allowed. +// +//go:nowritebarrier +func newosproc(mp *m) { + throw("newosproc: not implemented") +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { + mp.gsignal = malg(32 * 1024) + mp.gsignal.m = mp +} + +func osinit() { + ncpu = 1 + physPageSize = 4096 + + if Bloc != 0 { + bloc = Bloc + blocMax = bloc + } else { + initBloc() + } +} + +func readRandom(r []byte) int { + initRNG() + getRandomData(r) + return len(r) +} + +func signame(sig uint32) string { + return "" +} + +//go:linkname os_sigpipe os.sigpipe +func os_sigpipe() { + throw("too many writes on closed pipe") +} + +//go:nosplit +func crash() { + *(*int32)(nil) = 0 +} + +//go:linkname syscall +func syscall(number, a1, a2, a3 uintptr) (r1, r2, err uintptr) { + switch number { + // SYS_WRITE + case 1: + r1 := write(a1, unsafe.Pointer(a2), int32(a3)) + return uintptr(r1), 0, 0 + default: + throw("unexpected syscall") + } + + return +} + +//go:nosplit +func write1(fd uintptr, buf unsafe.Pointer, count int32) int32 { + if fd != 1 && fd != 2 { + throw("unexpected fd, only stdout/stderr are supported") + } + + c := uintptr(count) + + for i := uintptr(0); i < c; i++ { + p := (*byte)(unsafe.Pointer(uintptr(buf) + i)) + printk(*p) + } + + return int32(c) +} + +//go:linkname syscall_now syscall.now +func syscall_now() (sec int64, nsec int32) { + sec, nsec, _ = time_now() + return +} + +//go:nosplit +func walltime() (sec int64, nsec int32) { + nano := nanotime() + sec = nano / 1000000000 + nsec = int32(nano % 1000000000) + return +} + +//go:nosplit +func usleep(us uint32) { + wake := nanotime() + int64(us)*1000 + for nanotime() < wake { + } +} + +//go:nosplit +func usleep_no_g(usec uint32) { + usleep(usec) +} + +// Exit can be provided externally by the linked application to provide an +// implementation for runtime.exit. +var Exit func(int32) + +func exit(code int32) { + if Exit != nil { + Exit(code) + } + + print("exit with code ", code, " halting\n") + + for { + // hang forever + } +} + +func exitThread(wait *atomic.Uint32) { + // We should never reach exitThread + throw("exitThread: not implemented") +} + +const preemptMSupported = false + +func preemptM(mp *m) { + // No threads, so nothing to do. +} + +// Stubs so tests can link correctly. These should never be called. +func open(name *byte, mode, perm int32) int32 { panic("not implemented") } +func closefd(fd int32) int32 { panic("not implemented") } +func read(fd int32, p unsafe.Pointer, n int32) int32 { panic("not implemented") } diff --git a/src/runtime/os_tamago_amd64.go b/src/runtime/os_tamago_amd64.go new file mode 100644 index 00000000000000..bff7973e9a51b9 --- /dev/null +++ b/src/runtime/os_tamago_amd64.go @@ -0,0 +1,30 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build tamago && amd64 + +package runtime + +// the following variables must be provided externally +var ramStart uint64 +var ramSize uint64 +var ramStackOffset uint64 + +// defined in asm_amd64.s +func cputicks() int64 + +// GetG returns the pointer to the current G and its P. +func GetG() (gp uint64, pp uint64) + +// MemRegion returns the start and end addresses of the physical RAM assigned +// to the Go runtime. +func MemRegion() (start uint64, end uint64) { + return ramStart, ramStart + ramSize +} + +// TextRegion returns the start and end addresses of the physical RAM +// containing the Go runtime executable instructions. +func TextRegion() (start uint64, end uint64) { + return uint64(firstmoduledata.text), uint64(firstmoduledata.etext) +} diff --git a/src/runtime/os_tamago_arm.go b/src/runtime/os_tamago_arm.go index 94b8ce786a8999..8cd05f3130e910 100644 --- a/src/runtime/os_tamago_arm.go +++ b/src/runtime/os_tamago_arm.go @@ -6,61 +6,14 @@ package runtime -import ( - "internal/runtime/atomic" - "unsafe" -) - -// see testing.testBinary -var testBinary string - -// Bloc allows to override the heap memory start address -var Bloc uintptr - // the following variables must be provided externally var ramStart uint32 var ramSize uint32 var ramStackOffset uint32 -// the following functions must be provided externally -func hwinit() -func printk(byte) -func getRandomData([]byte) -func initRNG() - -// the following functions must be provided externally -// (but are already stubbed somewhere else in the runtime) -//func nanotime1() int64 - -// GetRandomData generates len(r) random bytes from the random source provided -// externally by the linked application. -func GetRandomData(r []byte) { - getRandomData(r) -} - -// CallOnG0 calls a function (func(off int)) on g0 stack. -// -// The function arguments must be passed through the following registers -// (rather than on the frame pointer): -// -// * R0: fn argument (vector table offset) -// * R1: fn pointer -// * R2: size of stack area reserved for caller registers -// * R3: caller program counter -func CallOnG0() - // GetG returns the pointer to the current G and its P. func GetG() (gp uint32, pp uint32) -// WakeG modifies a goroutine cached timer for time.Sleep (g.timer) to fire as -// soon as possible. -// -// The function arguments must be passed through the following registers -// (rather than on the frame pointer): -// -// * R0: G pointer -func WakeG() - // MemRegion returns the start and end addresses of the physical RAM assigned // to the Go runtime. func MemRegion() (start uint32, end uint32) { @@ -73,70 +26,6 @@ func TextRegion() (start uint32, end uint32) { return uint32(firstmoduledata.text), uint32(firstmoduledata.etext) } -// stubs for unused/unimplemented functionality -type mOS struct{} -type sigset struct{} -type gsignalStack struct{} - -func goenvs() {} -func sigsave(p *sigset) {} -func msigrestore(sigmask sigset) {} -func clearSignalHandlers() {} -func sigblock(exiting bool) {} -func minit() {} -func unminit() {} -func mdestroy(mp *m) {} -func setProcessCPUProfiler(hz int32) {} -func setThreadCPUProfiler(hz int32) {} -func initsig(preinit bool) {} -func osyield() {} -func osyield_no_g() {} - -// May run with m.p==nil, so write barriers are not allowed. -// -//go:nowritebarrier -func newosproc(mp *m) { - throw("newosproc: not implemented") -} - -// Called to do synchronous initialization of Go code built with -// -buildmode=c-archive or -buildmode=c-shared. -// None of the Go runtime is initialized. -//go:nosplit -//go:nowritebarrierrec -func libpreinit() { - initsig(true) -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -func mpreinit(mp *m) { - mp.gsignal = malg(32 * 1024) - mp.gsignal.m = mp -} - -func osinit() { - ncpu = 1 - physPageSize = 4096 - - if Bloc != 0 { - bloc = Bloc - blocMax = bloc - } else { - initBloc() - } -} - -func readRandom(r []byte) int { - initRNG() - getRandomData(r) - return len(r) -} - -func signame(sig uint32) string { - return "" -} - func checkgoarm() { if goarm < 5 || goarm > 7 { print("runtime: tamago requires ARMv5 through ARMv7. Recompile using GOARM=5, GOARM=6 or GOARM=7.\n") @@ -149,103 +38,3 @@ func cputicks() int64 { // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. return nanotime() } - -//go:linkname os_sigpipe os.sigpipe -func os_sigpipe() { - throw("too many writes on closed pipe") -} - -//go:nosplit -func crash() { - *(*int32)(nil) = 0 -} - -//go:linkname syscall -func syscall(number, a1, a2, a3 uintptr) (r1, r2, err uintptr) { - switch number { - // SYS_WRITE - case 1: - r1 := write(a1, unsafe.Pointer(a2), int32(a3)) - return uintptr(r1), 0, 0 - default: - throw("unexpected syscall") - } - - return -} - -//go:nosplit -func write1(fd uintptr, buf unsafe.Pointer, count int32) int32 { - if fd != 1 && fd != 2 { - throw("unexpected fd, only stdout/stderr are supported") - } - - c := uintptr(count) - - for i := uintptr(0); i < c; i++ { - p := (*byte)(unsafe.Pointer(uintptr(buf) + i)) - printk(*p) - } - - return int32(c) -} - -//go:linkname syscall_now syscall.now -func syscall_now() (sec int64, nsec int32) { - sec, nsec, _ = time_now() - return -} - -//go:nosplit -func walltime() (sec int64, nsec int32) { - // TODO: probably better implement this in sys_tamago_arm.s for better - // performance - nano := nanotime() - sec = nano / 1000000000 - nsec = int32(nano % 1000000000) - return -} - -//go:nosplit -func usleep(us uint32) { - wake := nanotime() + int64(us)*1000 - for nanotime() < wake { - } -} - -//go:nosplit -func usleep_no_g(usec uint32) { - usleep(usec) -} - -// Exit can be provided externally by the linked application to provide an -// implementation for runtime.exit. -var Exit func(int32) - -func exit(code int32) { - if Exit != nil { - Exit(code) - } - - print("exit with code ", code, " halting\n") - - for { - // hang forever - } -} - -func exitThread(wait *atomic.Uint32) { - // We should never reach exitThread - throw("exitThread: not implemented") -} - -const preemptMSupported = false - -func preemptM(mp *m) { - // No threads, so nothing to do. -} - -// Stubs so tests can link correctly. These should never be called. -func open(name *byte, mode, perm int32) int32 { panic("not implemented") } -func closefd(fd int32) int32 { panic("not implemented") } -func read(fd int32, p unsafe.Pointer, n int32) int32 { panic("not implemented") } diff --git a/src/runtime/os_tamago_riscv64.go b/src/runtime/os_tamago_riscv64.go index a9bf6e14579cef..df4d54f20b224d 100644 --- a/src/runtime/os_tamago_riscv64.go +++ b/src/runtime/os_tamago_riscv64.go @@ -6,52 +6,17 @@ package runtime -import ( - "internal/runtime/atomic" - "unsafe" -) - -const _PAGESIZE uintptr = 0x1000 - -// see testing.testBinary -var testBinary string - -// Bloc allows to override the heap memory start address -var Bloc uintptr - // the following variables must be provided externally var ramStart uint64 var ramSize uint64 var ramStackOffset uint64 -// the following functions must be provided externally -func hwinit() -func printk(byte) -func getRandomData([]byte) -func initRNG() - -// the following functions must be provided externally -// (but are already stubbed somewhere else in the runtime) -//func nanotime1() int64 - -// GetRandomData generates len(r) random bytes from the random source provided -// externally by the linked application. -func GetRandomData(r []byte) { - getRandomData(r) -} +// defined in asm_riscv64.s +func cputicks() int64 // GetG returns the pointer to the current G and its P. func GetG() (gp uint64, pp uint64) -// WakeG modifies a goroutine cached timer for time.Sleep (g.timer) to fire as -// soon as possible. -// -// The function arguments must be passed through the following registers -// (rather than on the frame pointer): -// -// * T0: G pointer -func WakeG() - // MemRegion returns the start and end addresses of the physical RAM assigned // to the Go runtime. func MemRegion() (start uint64, end uint64) { @@ -63,160 +28,3 @@ func MemRegion() (start uint64, end uint64) { func TextRegion() (start uint64, end uint64) { return uint64(firstmoduledata.text), uint64(firstmoduledata.etext) } - -// stubs for unused/unimplemented functionality -type mOS struct{} -type sigset struct{} -type gsignalStack struct{} - -func goenvs() {} -func sigsave(p *sigset) {} -func msigrestore(sigmask sigset) {} -func clearSignalHandlers() {} -func sigblock(exiting bool) {} -func minit() {} -func unminit() {} -func mdestroy(mp *m) {} -func setProcessCPUProfiler(hz int32) {} -func setThreadCPUProfiler(hz int32) {} -func initsig(preinit bool) {} -func osyield() {} -func osyield_no_g() {} - -// May run with m.p==nil, so write barriers are not allowed. -// -//go:nowritebarrier -func newosproc(mp *m) { - throw("newosproc: not implemented") -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -func mpreinit(mp *m) { - mp.gsignal = malg(32 * 1024) - mp.gsignal.m = mp -} - -func osinit() { - ncpu = 1 - physPageSize = 4096 - - if Bloc != 0 { - bloc = Bloc - blocMax = bloc - } else { - initBloc() - } -} - -func readRandom(r []byte) int { - initRNG() - getRandomData(r) - return len(r) -} - -func signame(sig uint32) string { - return "" -} - -func cputicks() int64 - -//go:linkname os_sigpipe os.sigpipe -func os_sigpipe() { - throw("too many writes on closed pipe") -} - -//go:nosplit -func crash() { - *(*int32)(nil) = 0 -} - -//go:linkname syscall -func syscall(number, a1, a2, a3 uintptr) (r1, r2, err uintptr) { - switch number { - // SYS_WRITE - case 1: - r1 := write(a1, unsafe.Pointer(a2), int32(a3)) - return uintptr(r1), 0, 0 - default: - throw("unexpected syscall") - } - - return -} - -//go:nosplit -func write1(fd uintptr, buf unsafe.Pointer, count int32) int32 { - if fd != 1 && fd != 2 { - throw("unexpected fd, only stdout/stderr are supported") - } - - c := uintptr(count) - - for i := uintptr(0); i < c; i++ { - p := (*byte)(unsafe.Pointer(uintptr(buf) + i)) - printk(*p) - } - - return int32(c) -} - -//go:linkname syscall_now syscall.now -func syscall_now() (sec int64, nsec int32) { - sec, nsec, _ = time_now() - return -} - -//go:nosplit -func walltime() (sec int64, nsec int32) { - // TODO: probably better implement this in sys_tamago_riscv64.s for better - // performance - nano := nanotime() - sec = nano / 1000000000 - nsec = int32(nano % 1000000000) - return -} - -//go:nosplit -func usleep(us uint32) { - wake := nanotime() + int64(us)*1000 - for nanotime() < wake { - } -} - -//go:nosplit -func usleep_no_g(usec uint32) { - usleep(usec) -} - -// Exit can be provided externally by the linked application to provide an -// implementation for runtime.exit. -var Exit func(int32) - -func exit(code int32) { - if Exit != nil { - Exit(code) - } - - print("exit with code ", code, " halting\n") - - for { - // hang forever - } -} - -func exitThread(wait *atomic.Uint32) { - // We should never reach exitThread - throw("exitThread: not implemented") -} - -const preemptMSupported = false - -func preemptM(mp *m) { - // No threads, so nothing to do. -} - -// Stubs so tests can link correctly. These should never be called. -func open(name *byte, mode, perm int32) int32 { panic("not implemented") } -func closefd(fd int32) int32 { panic("not implemented") } -func read(fd int32, p unsafe.Pointer, n int32) int32 { panic("not implemented") } diff --git a/src/runtime/rt0_tamago_amd64.s b/src/runtime/rt0_tamago_amd64.s new file mode 100644 index 00000000000000..88faa79189fe07 --- /dev/null +++ b/src/runtime/rt0_tamago_amd64.s @@ -0,0 +1,32 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" + +#define SYS_mmap 9 + +TEXT _rt0_amd64_tamago(SB),NOSPLIT|NOFRAME,$0 + MOVW runtime·testBinary(SB), AX + CMPW AX, $0 + JA testing + + // cpuinit must be provided externally by the linked application for + // CPU initialization, it must call _rt0_tamago_start at completion + JMP cpuinit(SB) + +testing: + // when testing bare metal memory is mapped as OS virtual memory + MOVQ runtime·ramStart(SB), DI + MOVQ runtime·ramSize(SB), SI + MOVL $0x3, DX // PROT_READ | PROT_WRITE + MOVL $0x22, R10 // MAP_PRIVATE | MAP_ANONYMOUS + MOVL $0xffffffff, R8 + MOVL $0, R9 + MOVL $SYS_mmap, AX + SYSCALL + + JMP _rt0_tamago_start(SB) + +TEXT _rt0_tamago_start(SB),NOSPLIT|NOFRAME,$0 + JMP runtime·rt0_amd64_tamago(SB) diff --git a/src/runtime/rt0_tamago_arm.s b/src/runtime/rt0_tamago_arm.s index dd0702fd24ad30..42011f4ddeb11e 100644 --- a/src/runtime/rt0_tamago_arm.s +++ b/src/runtime/rt0_tamago_arm.s @@ -6,36 +6,15 @@ // for EABI, as we don't support OABI #define SYS_BASE 0x0 - #define SYS_mmap2 (SYS_BASE + 192) -TEXT _rt0_arm_tamago(SB),NOSPLIT,$0 - // Detect HYP mode and switch to SVC if necessary - WORD $0xe10f0000 // mrs r0, CPSR - AND $0x1f, R0, R0 // get processor mode - - CMP $0x10, R0 // USR mode - B.EQ check_testing // Skip initialization if USER mode - - CMP $0x1a, R0 // HYP mode - B.NE after_eret // Skip ERET if not HYP mode - - BIC $0x1f, R0 - ORR $0x1d3, R0 // AIF masked, SVC mode - MOVW $12(R15), R14 // add lr, pc, #12 (after_eret) - WORD $0xe16ff000 // msr SPSR_fsxc, r0 - WORD $0xe12ef30e // msr ELR_hyp, lr - WORD $0xe160006e // eret - -after_eret: - // Enter System Mode - WORD $0xe321f0df // msr CPSR_c, 0xdf - B runtime_start - -check_testing: +TEXT _rt0_arm_tamago(SB),NOSPLIT|NOFRAME,$0 MOVW runtime·testBinary(SB), R0 CMP $0, R0 - B.EQ runtime_start + + // cpuinit must be provided externally by the linked application for + // CPU initialization, it must call _rt0_tamago_start at completion + BL.EQ cpuinit(SB) // when testing bare metal memory is mapped as OS virtual memory MOVW runtime·ramStart(SB), R0 @@ -47,7 +26,9 @@ check_testing: MOVW $SYS_mmap2, R7 SWI $0 -runtime_start: + B _rt0_tamago_start(SB) + +TEXT _rt0_tamago_start(SB),NOSPLIT|NOFRAME,$0 MOVW runtime·ramStart(SB), R13 MOVW runtime·ramSize(SB), R1 MOVW runtime·ramStackOffset(SB), R2 diff --git a/src/runtime/rt0_tamago_riscv64.s b/src/runtime/rt0_tamago_riscv64.s index 46173a15e8153d..af720c4ad50ac9 100644 --- a/src/runtime/rt0_tamago_riscv64.s +++ b/src/runtime/rt0_tamago_riscv64.s @@ -2,28 +2,20 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "go_asm.h" -#include "go_tls.h" -#include "funcdata.h" #include "textflag.h" -#define t0 5 - -#define sie 0x104 -#define mstatus 0x300 -#define mie 0x304 - -#define CSRC(RS,CSR) WORD $(0x3073 + RS<<15 + CSR<<20) -#define CSRS(RS,CSR) WORD $(0x2073 + RS<<15 + CSR<<20) -#define CSRW(RS,CSR) WORD $(0x1073 + RS<<15 + CSR<<20) - #define SYS_mmap 222 // entry point for M privilege level instances TEXT _rt0_riscv64_tamago(SB),NOSPLIT|NOFRAME,$0 MOV runtime·testBinary(SB), T0 - BEQ T0, ZERO, start + BGT T0, ZERO, testing + + // cpuinit must be provided externally by the linked application for + // CPU initialization, it must call _rt0_tamago_start at completion + JMP cpuinit(SB) +testing: // when testing bare metal memory is mapped as OS virtual memory MOV runtime·ramStart(SB), A0 MOV runtime·ramSize(SB), A1 @@ -34,24 +26,10 @@ TEXT _rt0_riscv64_tamago(SB),NOSPLIT|NOFRAME,$0 MOV $SYS_mmap, A7 ECALL - JMP _rt0_riscv64_tamago_start(SB) - -start: - // Disable interrupts - MOV $0, T0 - CSRW (t0, sie) - CSRW (t0, mie) - MOV $0x7FFF, T0 - CSRC (t0, mstatus) - - // Enable FPU - MOV $(1<<13), T0 - CSRS (t0, mstatus) - - JMP _rt0_riscv64_tamago_start(SB) + JMP _rt0_tamago_start(SB) // entry point for S/U privilege level instances -TEXT _rt0_riscv64_tamago_start(SB),NOSPLIT|NOFRAME,$0 +TEXT _rt0_tamago_start(SB),NOSPLIT|NOFRAME,$0 MOV runtime·ramStart(SB), X2 MOV runtime·ramSize(SB), T1 MOV runtime·ramStackOffset(SB), T2 diff --git a/src/runtime/sys_tamago_amd64.s b/src/runtime/sys_tamago_amd64.s new file mode 100644 index 00000000000000..6c0960c0889701 --- /dev/null +++ b/src/runtime/sys_tamago_amd64.s @@ -0,0 +1,178 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +// System calls and other sys.stuff for arm, tamago +// + +#include "go_asm.h" +#include "go_tls.h" +#include "textflag.h" + +#define SYS_arch_prctl 158 + +TEXT runtime·rt0_amd64_tamago(SB),NOSPLIT|NOFRAME|TOPFRAME,$0 + // create istack out of the given (operating system) stack. + // _cgo_init may update stackguard. + MOVQ $runtime·g0(SB), DI + LEAQ (-64*1024)(SP), BX + MOVQ BX, g_stackguard0(DI) + MOVQ BX, g_stackguard1(DI) + MOVQ BX, (g_stack+stack_lo)(DI) + MOVQ SP, (g_stack+stack_hi)(DI) + + // find out information about the processor we're on + MOVL $0, AX + CPUID + CMPL AX, $0 + JE nocpuinfo + + CMPL BX, $0x756E6547 // "Genu" + JNE notintel + CMPL DX, $0x49656E69 // "ineI" + JNE notintel + CMPL CX, $0x6C65746E // "ntel" + JNE notintel + MOVB $1, runtime·isIntel(SB) + +notintel: + // Load EAX=1 cpuid flags + MOVL $1, AX + CPUID + MOVL AX, runtime·processorVersionInfo(SB) + +nocpuinfo: + LEAQ runtime·m0+m_tls(SB), DI + CALL runtime·settls(SB) + + // store through it, to make sure it works + get_tls(BX) + MOVQ $0x123, g(BX) + MOVQ runtime·m0+m_tls(SB), AX + CMPQ AX, $0x123 + JEQ 2(PC) + CALL runtime·abort(SB) +ok: + // set the per-goroutine and per-mach "registers" + get_tls(BX) + LEAQ runtime·g0(SB), CX + MOVQ CX, g(BX) + LEAQ runtime·m0(SB), AX + + // save m->g0 = g0 + MOVQ CX, m_g0(AX) + // save m0 to g0->m + MOVQ AX, g_m(CX) + + CLD // convention is D is always left cleared + + // Check GOAMD64 requirements + // We need to do this after setting up TLS, so that + // we can report an error if there is a failure. See issue 49586. +#ifdef NEED_FEATURES_CX + MOVL $0, AX + CPUID + CMPL AX, $0 + JE bad_cpu + MOVL $1, AX + CPUID + ANDL $NEED_FEATURES_CX, CX + CMPL CX, $NEED_FEATURES_CX + JNE bad_cpu +#endif + +#ifdef NEED_MAX_CPUID + MOVL $0x80000000, AX + CPUID + CMPL AX, $NEED_MAX_CPUID + JL bad_cpu +#endif + +#ifdef NEED_EXT_FEATURES_BX + MOVL $7, AX + MOVL $0, CX + CPUID + ANDL $NEED_EXT_FEATURES_BX, BX + CMPL BX, $NEED_EXT_FEATURES_BX + JNE bad_cpu +#endif + +#ifdef NEED_EXT_FEATURES_CX + MOVL $0x80000001, AX + CPUID + ANDL $NEED_EXT_FEATURES_CX, CX + CMPL CX, $NEED_EXT_FEATURES_CX + JNE bad_cpu +#endif + +#ifdef NEED_OS_SUPPORT_AX + XORL CX, CX + XGETBV + ANDL $NEED_OS_SUPPORT_AX, AX + CMPL AX, $NEED_OS_SUPPORT_AX + JNE bad_cpu +#endif + +#ifdef NEED_DARWIN_SUPPORT + MOVQ $commpage64_version, BX + CMPW (BX), $13 // cpu_capabilities64 undefined in versions < 13 + JL bad_cpu + MOVQ $commpage64_cpu_capabilities64, BX + MOVQ (BX), BX + MOVQ $NEED_DARWIN_SUPPORT, CX + ANDQ CX, BX + CMPQ BX, CX + JNE bad_cpu +#endif + + CALL runtime·check(SB) + + MOVL 24(SP), AX // copy argc + MOVL AX, 0(SP) + MOVQ 32(SP), AX // copy argv + MOVQ AX, 8(SP) + CALL runtime·hwinit(SB) + CALL runtime·osinit(SB) + CALL runtime·schedinit(SB) + + // create a new goroutine to start program + MOVQ $runtime·mainPC(SB), AX // entry + PUSHQ AX + CALL runtime·newproc(SB) + POPQ AX + + // start this M + CALL runtime·mstart(SB) + + CALL runtime·abort(SB) // mstart should never return + RET + +bad_cpu: + CALL runtime·exit(SB) + CALL runtime·abort(SB) + RET + +// GetG returns the pointer to the current G and its P. +TEXT runtime·GetG(SB),NOSPLIT,$0-16 + get_tls(CX) + MOVQ g(CX), AX + MOVQ AX, gp+0(FP) + + MOVQ (g_m)(AX), AX + MOVQ (m_p)(AX), AX + MOVQ AX, pp+8(FP) + + RET + +// This is needed by asm_amd64.s +TEXT runtime·settls(SB),NOSPLIT,$32 + ADDQ $8, DI // ELF wants to use -8(FS) + MOVQ DI, SI + MOVQ $0x1002, DI // ARCH_SET_FS + MOVQ $SYS_arch_prctl, AX + SYSCALL + CMPQ AX, $0xfffffffffffff001 + JLS 2(PC) + MOVL $0xf1, 0xf1 // crash + RET diff --git a/src/syscall/asm_tamago_amd64.s b/src/syscall/asm_tamago_amd64.s new file mode 100644 index 00000000000000..285ac91fd65afe --- /dev/null +++ b/src/syscall/asm_tamago_amd64.s @@ -0,0 +1,14 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" +#include "funcdata.h" + +// +// System calls for amd64,tamago +// + +// func Syscall(syscall uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr); +TEXT ·Syscall(SB),NOSPLIT,$0-56 + JMP runtime·syscall(SB) diff --git a/src/syscall/zsyscall_tamago_amd64.go b/src/syscall/zsyscall_tamago_amd64.go new file mode 100644 index 00000000000000..385b499f8de67f --- /dev/null +++ b/src/syscall/zsyscall_tamago_amd64.go @@ -0,0 +1,25 @@ +// mksyscall.pl -tags tamago,amd64 syscall_tamago.go +// Code generated by the command above; DO NOT EDIT. + +//go:build tamago && amd64 + +package syscall + +import "unsafe" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func write(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/src/syscall/zsyscall_tamago_riscv64.go b/src/syscall/zsyscall_tamago_riscv64.go index 8464fd8c493cb2..4099d17d62d86d 100644 --- a/src/syscall/zsyscall_tamago_riscv64.go +++ b/src/syscall/zsyscall_tamago_riscv64.go @@ -1,4 +1,4 @@ -// mksyscall.pl -tags tamago,arm syscall_tamago.go +// mksyscall.pl -tags tamago,riscv64 syscall_tamago.go // Code generated by the command above; DO NOT EDIT. //go:build tamago && riscv64 diff --git a/src/syscall/zsysnum_tamago_amd64.go b/src/syscall/zsysnum_tamago_amd64.go new file mode 100644 index 00000000000000..a326dda182d0c4 --- /dev/null +++ b/src/syscall/zsysnum_tamago_amd64.go @@ -0,0 +1,7 @@ +//go:build amd64 && tamago + +package syscall + +const ( + SYS_WRITE = 1 +) diff --git a/src/testing/testing_tamago.go b/src/testing/testing_tamago.go index 8dd831589b38b5..3d2073caeb0a7a 100644 --- a/src/testing/testing_tamago.go +++ b/src/testing/testing_tamago.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build tamago && (arm || riscv64) +//go:build tamago && (amd64 || arm || riscv64) package testing diff --git a/src/testing/testing_tamago_amd64.s b/src/testing/testing_tamago_amd64.s new file mode 100644 index 00000000000000..0adebbd620f672 --- /dev/null +++ b/src/testing/testing_tamago_amd64.s @@ -0,0 +1,61 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build tamago && amd64 + +#include "go_asm.h" +#include "textflag.h" + +#define CLOCK_REALTIME 0 + +#define SYS_write 1 +#define SYS_exit 60 +#define SYS_clock_gettime 228 +#define SYS_getrandom 318 + +TEXT cpuinit(SB),NOSPLIT|NOFRAME,$0 + +// func sys_clock_gettime() int64 +TEXT ·sys_clock_gettime(SB),NOSPLIT,$40-8 + SUBQ $16, SP // Space for results + + MOVL $CLOCK_REALTIME, DI + LEAQ 0(SP), SI + MOVQ $SYS_clock_gettime, AX + SYSCALL + + MOVQ 0(SP), AX // sec + MOVQ 8(SP), DX // nsec + ADDQ $16, SP + + IMULQ $1000000000, AX + ADDQ DX, AX + MOVQ AX, ns+0(FP) + + RET + +// func sys_exit(code int32) +TEXT ·sys_exit(SB), $0-4 + MOVL code+0(FP), DI + MOVL $SYS_exit, AX + SYSCALL + RET + +// func sys_write(c *byte) +TEXT ·sys_write(SB),NOSPLIT,$0-8 + MOVQ $1, DI // fd + MOVQ c+0(FP), SI // p + MOVL $1, DX // n + MOVL $SYS_write, AX + SYSCALL + RET + +// func sys_getrandom(b []byte, n int) +TEXT ·sys_getrandom(SB), $0-32 + MOVQ b+0(FP), DI + MOVQ n+24(FP), SI + MOVL $0, DX + MOVL $SYS_getrandom, AX + SYSCALL + RET diff --git a/src/testing/testing_tamago_arm.s b/src/testing/testing_tamago_arm.s index 91f01d9e788648..323fd38925d375 100644 --- a/src/testing/testing_tamago_arm.s +++ b/src/testing/testing_tamago_arm.s @@ -17,6 +17,8 @@ #define SYS_clock_gettime (SYS_BASE + 263) #define SYS_getrandom (SYS_BASE + 384) +TEXT cpuinit(SB),NOSPLIT|NOFRAME,$0 + // func sys_clock_gettime() int64 TEXT ·sys_clock_gettime(SB),NOSPLIT,$12-8 MOVW $CLOCK_REALTIME, R0 diff --git a/src/testing/testing_tamago_riscv64.s b/src/testing/testing_tamago_riscv64.s index 13835eaafb857a..0d17dfb98cd123 100644 --- a/src/testing/testing_tamago_riscv64.s +++ b/src/testing/testing_tamago_riscv64.s @@ -14,6 +14,8 @@ #define SYS_clock_gettime 113 #define SYS_getrandom 278 +TEXT cpuinit(SB),NOSPLIT|NOFRAME,$0 + // func sys_clock_gettime() int64 TEXT ·sys_clock_gettime(SB),NOSPLIT,$40-8 MOV $CLOCK_REALTIME, A0