Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: all: add bare metal ARM support #46802

Closed
abarisani opened this issue Jun 17, 2021 · 42 comments
Closed

proposal: all: add bare metal ARM support #46802

abarisani opened this issue Jun 17, 2021 · 42 comments

Comments

@abarisani
Copy link

Hello,

I'd like to request reconsideration of our previous proposal (declined) as there have been new simplifications in our patch that should solve some, if not all, concerns previously raised.

Small recap: our TamaGo project adds support for vanilla Go runtime and packages execution on ARMv7 bare metal. Please see the original issue which remains valid in its initial description.

The main changes of our most recent integration are as follows:

  • we completely removed any ARM exception handling or low-level assembly, with the exception of rt0 entry point support (here and here, which is required and included in Go for all supported architectures and a CallOnG0 function to facilitate external integration of exception handlers (which is very similar to existing approaches).

  • all remaining code is simple "glue" code adapter from other supported architectures and to extend support of a new GOOS keyword

  • runtime support in os_tamago_arm.go is much reduced compared to the first proposed version and now consists only of stubs and simple "glue" code.

Overall our latest patch has ~4200 insertions over 133 files, however the overwhelming majority of changes are one-liners two add GOOS=tamago support, almost verbatim clones of existing code (lock_js.go > lock_tamago.go,, mem_plan9.go > mem_tamago.go) and os_tamago_arm.go remains the largest newly added file.

We think these changes should address the main concerns that resulted the rejection of our previous proposal.

Our new patch should not raise any longer concerns on chip erratas as it is as agnostic as possible in the low level management of SoC specific, or even ARM, architecture. It allows external packages to provide ARM support.

We demonstrated useful implementation of all Go packages, including os and net, for instance we successfully enable networking with gVisor in our Ethernet over USB driver.

Since our last issue we implemented a full Trusted Execution Environment (GoTEE) with this framework as well as a full OpenPGP/FIDO U2F smartcard (GoKey).

Others have expressed interest for running Go on the bare metal and we also received contributions which extend support to other platforms such as Raspberry PIs using the same original Go distribution patch.

Given the recent refactoring that takes chip errata concerns out of the way, provides a more minimal patch, and the recent demonstrations of what can be developed with this, I kindy ask re-consideration of our proposal.

Thanks!

@gopherbot gopherbot added this to the Proposal milestone Jun 17, 2021
@thanm
Copy link
Contributor

thanm commented Jun 17, 2021

Hello,

In the discussion of the previous proposal, there was some minimal talk about builders for GOOS=none, e.g. #37503 (comment) (which basically boils down to "Will there be a builder? Yes, there will be a builder.").

I think it would be useful to have a bit more concrete/detailed conversation about builder support.

To wit: suppose the proposal is accepted, and a GOOS=none builder is set up. Will this builder be capable of running "all.bash"? Will the builder provide full support for "gomote" operations? Suppose that someone from the Go team checks in a change to the compiler or linker, and a test fails on the GOOS=none builder. Who will look at that failure and how?

Thanks.

@abarisani
Copy link
Author

all.bash currently runs on all tamago-go releases, I think overall builder and linker tests can happen identically to other architectures.

The challenge would only be for runtime tests that are written in a manner that depends on an OS being present, I am not sure how this is currently handled for platforms like plan9 or js. What I can say is that this can run under qemu.

@bcmills
Copy link
Contributor

bcmills commented Jun 17, 2021

For JS, iOS, and Android, tests are run by having a separate host for builds and invoking the binaries using go_*_exec scripts:

~/go$ find . -name go_*_exec*
./misc/wasm/go_js_wasm_exec
./misc/ios/go_ios_exec.go
./misc/android/go_android_exec.go

Presumably the TamaGo builder would need a similar script.

@bcmills
Copy link
Contributor

bcmills commented Jun 17, 2021

The challenge would only be for runtime tests that are written in a manner that depends on an OS being present, I am not sure how this is currently handled for platforms like plan9 or js.

Plan 9 can run the actual Go toolchain, albeit slowly.

For JS, Android, and iOS, cmd/dist distinguishes between tests that build and invoke Go subprocesses and tests that should run directly on the builder. (Search for registerHostTest in src/cmd/dist.)

Test binaries that contain a mix of the two can use internal/testenv.MustHaveExec to mark that they need an OS capable of starting subprocesses. If there are other bits of OS functionality that could be missing, they may need additional testenv functions.

@abarisani
Copy link
Author

abarisani commented Jun 17, 2021

Understood, I see no problem in having a similar approach for TamaGo. We could provide an USB armory as separate host to receive the tests or maybe (easier) just have a script that spawns the test within qemu ?

@firelizzard18
Copy link
Contributor

This may be of interest to @tinygo-org

/cc @deadprogram @aykevl @justinclift

@rsc
Copy link
Contributor

rsc commented Jun 24, 2021

Why is it difficult to maintain this tree as a GitHub fork of golang/go?

@abarisani
Copy link
Author

It is currently not that difficult, but its inclusion upstream would help ensuring that a GOOS=none support is minded in relation to potentially breaking changes, that its quality is consistent with the rest of the Go distribution code and that it would remain available over time.

Secondarily it would also help promoting, and further develop, this use case among Go user base.

Allowing easier hooks to generic "GOOS=none" within Go can certainly spawn up more interesting uses beyond the specific TamaGo goals and implementation, so I think in general it would help the Go ecosystem.

@rsc
Copy link
Contributor

rsc commented Jun 25, 2021

What you are saying is that it would move the maintenance burden for this code off of your team and onto the Go contributors more generally. Saying "its inclusion upstream would help ensuring that a GOOS=none support is minded in relation to potentially breaking changes" is another way of saying "it would be yet another special case, little-used port that slows down maintenance and development of the primary ports", or perhaps of saying (without realizing it) "we don't intend to keep up with your changes and want you to do it".

Contribution of new ports are "free like a puppy", to use the old Sun line: they are a gift that will require significant time and effort to keep alive. We already have a bunch of those, and inevitably the contributors move on, leaving us responsible for either continued upkeep (which takes away time we could be working on changes that benefit far more users) or removing the port (which makes us the bad guys).

I would much rather figure out what is making it difficult to keep this port out of tree and fix those underlying issues. That would let you maintain the port as you see fit and decouple our development and yours. It would make clear who is responsible for ongoing maintenance and fixing issues. It would scale far better - we can't put every port into the main tree. And it would provide a model for the next niche port.

@mvdan
Copy link
Member

mvdan commented Jun 25, 2021

I don't have a strong opinion either way, but: how does GOOS=none compare to, say, GOARCH=loong64? If the point is to have someone responsible for its maintenance in-tree, perhaps Andrea would be up for that.

@abarisani
Copy link
Author

abarisani commented Jun 25, 2021

My team (more than once) expressed the firm intention to maintain this. Please stop saying that we want upstream inclusion to offload maintenance because this is simply not true.

This proposal specifically would ease integration of TamaGo like ports in Go, so the way I see it it specifically addresses the current challenges in doing so by acting as a generic ARM template and possibly in the future for other architectures.

This effort is to promote a generic framework and hooks to be accepted upstream with our contribution to maintain it.

@abarisani
Copy link
Author

Let me be more clear and re-state my thinking. I think our patch specifically helps addressing the challenges in creating new ports of this kind and this is why we think it should be upstreamed (with our firm intention to maintain it at least for ARM).

It is not the intention of our proposal to just "offload" this for our own convenience. We are excited about using Go on the bare metal, promote its use and help make it easy for all while preserving this possibility in the process.

@rsc
Copy link
Contributor

rsc commented Jun 25, 2021

I don't have a strong opinion either way, but: how does GOOS=none compare to, say, GOARCH=loong64? If the point is to have someone responsible for its maintenance in-tree, perhaps Andrea would be up for that.

This is a good question. Empirically, GOARCHes require far less work to maintain than GOOSes. From Go's point of view, architectures vary far less than operating systems do: GOARCH variations essentially never get in the way of new work, while GOOS variations often do. (The variation of "no operating system" would be particularly different. In fact, the current patch assumes a single-CPU system - there is no threading or interrupts or note implementation. This is going to limit its applicability. And of course scaling up to a proper multiprocessor implementation would be significantly more work and more code to maintain.)

My team (more than once) expressed the firm intention to maintain this. Please stop saying that we want upstream inclusion to offload maintenance because this is simply not true.

I appreciate the present intention to maintain the code. I don't doubt at all what you are saying about your current intentions. But suppose five years from now your priorities shift. In that case, we would be left with another port that we must either maintain ourselves or remove from the tree (as I laid out before). This is why we must be willing to take on maintenance of the port in order for it to land in the tree. The current variety of ports (again, especially GOOSes) already creates a real drag on being able to make important changes to, for example, the garbage collector and the scheduler.

For ports that we cannot commit to long-term maintenance of, keeping them out-of-tree would make the responsibility much clearer. For as long as you maintain them, they would work and keep up with Go. And if at some point priorities shift and that project was no longer maintained, it would be clear what was no longer maintained. Either way, again, the responsibilities are much clearer if the port is out-of-tree.

I realize that we don't have great support for out-of-tree ports right now. But again I think it is worth figuring out what we could do to make that better rather than default to continuing to add every possible new port to the main tree. Good support for out-of-tree ports would also provide a better path for ports that do eventually need to be removed from the main tree.

@mvdan
Copy link
Member

mvdan commented Jun 25, 2021

Good support for out-of-tree ports would also provide a better path for ports that do eventually need to be removed from the main tree.

I would like to see that future happen. The closest thing we have right now are first-class ports, but it's not quite the same as it still encourages all possible ports to live in a single place.

@abarisani
Copy link
Author

On contributors leaving or losing interest...well that can be used as an argument against pretty much any contribution can't it? If any maintainers lose interest on the code they maintain the problem would be identical. If there are others that can pick the work up fine, otherwise the feature would be dropped I guess. Certainly I can see upstream inclusion of a GOOS giving it better chance of getting more manpower than keeping it external. Not sure how anyone is supposed to counteract this argument to be honest...

On multiprocessor support, as the idea is for this GOOS to be a general template I am happy to adapt for easier integration of SMP CPUs, in fact this could be a great exercise on making it closer to what you ask in the first place (easy addition if external architectures in GOOS=none).

On GOOS being harder than a new GOARCH, I am not sure I agree 100%. Some architectures are fairly broad in their scope while this is very a very specific and unique GOOS which actually has no dependency on a specific OS.

So I think this effort, if generalized correctly, should not need too much maintenance in the long term or anyway its maintenance would be quite similar to what plan9/nacl/js are doing...in fact most of the complex bits are 100% cloned from these GOOSes.

If there is interest I am happy to ponder an abstraction that allows SMP to take place as that is a valid concern.

@ianlancetaylor
Copy link
Member

On contributors leaving or losing interest...well that can be used as an argument against pretty much any contribution can't it?

Not really. It can only be used as an argument against a change that the core Go team is not able to maintain. Relatively few changes fall into that category.

On GOOS being harder than a new GOARCH, I am not sure I agree 100%.

This isn't hypothetical, it's based on tracking the areas that take the most time for Go's compiler and runtime work over the last couple of years.

I personally don't feel very strongly about this particular proposal. But I hope we can all agree that it would be better if it were easier to maintain Go ports out of the main repository. That state is clearly better than where we are today in every respect, and it also addresses this proposal. So let's try to understand how much work that would be, and whether it is a feasible goal. Thanks.

@abarisani
Copy link
Author

I think we are confusing layers a little bit (including myself).

Our proposal is a generic GOOS=none which would create a generic layer to extend the same GOOS to any bare metal SoC/architecture with external packages (like we are doing with tamago).

Bare metal (a.k.a. supervisor/system mode) is different than a generic GOOS in user mode (e.g. linux, macOS) which typically relies on system calls.

While I do think that our work could be somewhat be adapted to be so generic that it would also allow arbitrary user mode GOOS architectures, I probably think it would not be the best or more efficient approach due to this fundamental differences in execution mode.

What I care about is promoting (and preserving) the fact that Go can be a prime language on OS-less embedded systems, and while I'd be pleased if our work could also help Go in achieving cleaner abstraction for arbitrary GOOSes, fundamentally I am not sure this patch would be the right beginning for it, as GOOS=none is likely very different than GOOS=<some_other_os_running_go_in_user_mode>.

@ALTree
Copy link
Member

ALTree commented Jun 25, 2021

So essentially your proposal is to just add a GOOS=none, which is actually a plugin mechanism that would let people implement support for a specific architecture (like ARM) using an external package? And then if you set GOOS=none and provide an external package like the one you linked above for ARM, you would be able to enable support for none/arm as a GOOS/GOARCH couple?

Because this is not very clear by reading this proposal. A few questions:

  • What does GOOS=none do if you don't provide the external architecture implementation? (I suppose nothing). So a builder would actually target a specific couple like none/arm, pull the third party ARM implementation from github, and run all.bash on that?
  • os_tamago_arm.go mentioned above (which actually you'd call os_none_arm.go I guess) makes me think that GOOS=none does not provide a completely independent pluggable interface for GOARCHs, you would still need to commit ARM-support stubs in the main Go repo, but they're basically empty, and then the real implementation is in the third party package. Then if we wanted none/riscv64 you'd need a small patch in the Go toolchain (with files like os_none_riscv64.go), and then a third party package would provide the actual riscv64 support. Is that right?
  • How do people working on the Go toolchain make sure they're not breaking none/whatever? Or they shouldn't care, because it's essentially an out-of-tree third-party port? Of course you could argue that out-of-tree ports face the same issue.

@firelizzard18
Copy link
Contributor

firelizzard18 commented Jun 25, 2021

TinyGo is both an LLVM-based compiler for Go, and a partial set of replacement stdlibs. So not really a full port as I understand it. If I understand correctly, if a given stdlib, such as runtime, is present in TinyGo's root, the compiler uses that in preference to the upstream version. Otherwise, the compiler uses the upstream version. GOOS=none could simplify TinyGo if it reduced upstream stdlib's dependence on running in user space.

How do people working on the Go toolchain make sure they're not breaking none/whatever?

It would be nice if there was a well defined API boundary, but something is better than nothing. Out-of-tree ports currently have no guarantee about stdlib internals, so Go toolchain developers not working about breaking out-of-tree GOOS=none ports won't be a change from the current status.

What does GOOS=none do if you don't provide the external architecture implementation?

Could be a stub implementation with just enough filled in to run tests?

@rminnich
Copy link
Contributor

Time will tell, but I think it may be unfair to characterize this as a niche.
I do recall ARM being characterized as a niche by some in the glibc community, including in this famous quote:
"Ulrich Drepper 2007-10-02 04:01:19 UTC
It's working fine everywhere but this carp architectures. I'm not going to make
the code perform worse just because of Arm. Providing your own copy of that
file if you care."

and now ARM deployments outnumber x86 deployments by at least 10x. But in the interim this attitude led to a full fork and eglibc.

Is tamago a niche use? Go on a new platform is a niche use by definition. But should tamago become useful in, e.g., silicon root of trust (SROT) applications such as the usbarmory, then tamago might well end up as widely deployed as all other Go platforms combined, since SROT is becoming ubiquitous (SROT is used in all new chromebooks, and will be used in all new servers). Future platforms will include at least one SROT, and some have more. Further, I'm starting to like tamago as a potential stack for Baseboard Management Controllers (BMC), as opposed to the gigantic, and vulnerable, Linux-based stack that is used today. This goes beyond SROT.

I understand your argument for forking golang. The Go team can only do so much. But you may be playing with fire here, because one way this can go is not "fork per unaccepted port", but "one community fork for all unaccepted ports", i.e., a new organization supporting the second-class ports. If enough momentum forms behind a "community Go fork" that's more friendly to new platforms, a new Go team outside Google might form. It would be friendlier to new ports as, e.g, Rust is, and the momentum and interest could move to community go. This is not a new story. Recall that the most commonly used BSD variant is not the original one.

I understand this is a tough situation, but you're in the enviable situation of having succeeded well enough that people want to use Go. While telling people to "just fork" is an option, forks have a way of diverging -- ref eglibc. Parallel organizations are created that can eventually outshine the original one.

I think you also need to define the rules by which a sufficiently successful/widely used platform can be brought into the upstream tree from community go. It can't look hopeless.

That said, in anticipation that tamago will still not be accepted, I've created this:

https://github.com/community-go/go

The intent is this be a common place to support unaccepted/deprecated ports, or ports not quite ready for upstream but that might make the jump, with the current example being tamago.

From this, we can try to learn how to make fork maintenance easy. Having maintained an out-of-tree port for several years for Harvey-OS, I can tell you it's anything but easy today; with luck we can improve the situation.

@mvdan
Copy link
Member

mvdan commented Jun 25, 2021

@rminnich if I might make a suggestion - best to not name the org "community-go", as that can confuse those stumbling upon it. Go as a projecy already has a community contributing to the golang org, after all. Perhaps something more specific like go-extra-ports?

@abarisani
Copy link
Author

abarisani commented Jun 25, 2021

So essentially your proposal is to just add a GOOS=none, which is actually a plugin mechanism that would let people implement support for a specific architecture (like ARM) using an external package? And then if you set GOOS=none and provide an external package like the one you linked above for ARM, you would be able to enable support for none/arm as a GOOS/GOARCH couple?

(taking the liberty to s/tamago/none/ while linking at tamago examples to show how this would look like)

Correct, the external package could then contribute:

  • the ARM architecture specific parts which are not covered by the standard Go distribution (for example the MMU configuration, these are generic ARM functions that however different projects might decide to implement in a different manner, or simply to add more features such as our support for ARM TrustZone) and which are also prone to errata (a problem highlighted in our previous proposal).

  • the SoC specific support (e.g. NXP i.MX6 vs Raspberry Pi), including SoC specific drivers.

  • the various board support packages.

  • whatever utility might be handy or required, such as DMA access.

Because this is not very clear by reading this proposal. A few questions:

  • What does GOOS=none do if you don't provide the external architecture implementation? (I suppose nothing). So a builder would actually target a specific couple like none/arm, pull the third party ARM implementation from github, and run all.bash on that?

Without the external packages there are no drivers, so it's impossible to do any meaningful I/O or use anything other then the CPU.

  • os_tamago_arm.go mentioned above (which actually you'd call os_none_arm.go I guess) makes me think that GOOS=none does not provide a completely independent pluggable interface for GOARCHs, you would still need to commit ARM-support stubs in the main Go repo, but they're basically empty, and then the real implementation is in the third party package. Then if we wanted none/riscv64 you'd need a small patch in the Go toolchain (with files like os_none_riscv64.go), and then a third party package would provide the actual riscv64 support. Is that right?

It's not completely independent, the following files would be GOARCH=arm dependent:

  • the very initial assembly which acts as entry point: rt0_none_arm.s, sys_none_arm.s. I believe these can be provided externally with a linker script, it would be less clean and convenient imho, but it can be done if desired.

  • asm_none_arm.s, a quite short syscall wrapper.

  • zsyscall_none_arm.go and zsysnum_none_arm.go are ARM specific, but would automatically generated from syscall_none.go, here we just copied what GO does for other architectures however I do think I could potentially refactor this to remove any ARM specific bits (as in the end I don't think there should be any).

  • this stub probably doesn't need to be in asm and ARM specific.

  • os_none_arm.go could be made non ARM specific (it isn't in fact) and be the main hook for external packages to add to the runtime (through go:linkname as we do now).

So I think I could make this completely independent from ARM if we really want to, otherwise even if we keep this scheme the patches for *_none_something else would be relatively simple and small to create and maintain.

  • How do people working on the Go toolchain make sure they're not breaking none/whatever? Or they shouldn't care, because it's essentially an out-of-tree third-party port? Of course you could argue that out-of-tree ports face the same issue.

I think the two most important pieces would be lock_none.go and mem_none.go (copied almost verbatim from js/wasm and plan9 respectively), however these are fairly self contained, with a clear goal and in my understanding they would entail a substantial change in the way Go works to be broken.

The residual risk would be for the runtime, or some other vital standard package, to start relying on OS specific (e.g. system calls) aspects to perform basic operations. What allows Go to be so suited to the bare metal is its almost non-existent reliance on system calls for most of its core operations, which is what allows us to bring in almost every package without worries. Unless a testsuite for GOOS=none, with a sample external architecture such as tamago+arm, is included in Go standard build process this is a risk that will always remain. I am not suggesting this should also be addressed, I am just noting it for the sake of discussion.

@ianlancetaylor
Copy link
Member

@rminnich I agree with @mvdan that naming a new project community-go is unhelpful. It's also premature.

Anyhow, I see two issues here. The first is whether we can provide a reasonably stable runtime API to support arbitrary ports. The second is whether we can provide a reasonably stable runtime API to support GOOS=none. The second seems likely to be easier than the first, given the number of plan9 and windows specific files across the standard library.

@rminnich
Copy link
Contributor

I removed community-go. If we do decide to go with a fork, it will likely then be go-extra-ports or something similar.

Also, apologies if the use of the ulrich drepper quote was offensive to anyone, I mainly used it to try and illustrate just how badly things can go wrong. I've been on any number of open source projects which forked when people could not come to agreement, and it's always sad to see. All things considered, I'd rather not see that happen.

@rsc
Copy link
Contributor

rsc commented Jun 27, 2021

The residual risk would be for the runtime, or some other vital standard package, to start relying on OS specific (e.g. system calls) aspects to perform basic operations. What allows Go to be so suited to the bare metal is its almost non-existent reliance on system calls for most of its core operations,

What about multithreading, or preemption? I see nothing in what you described as the latest patch that addresses either one. Those are core OS functionalities that Go does depend on. To the extent that the tamago port does not provide those, it is providing a sub-standard Go experience. In particular, not having the ability to run on multiple CPUs seems like a complete show-stopper to me. That's not going to age well at all. (Also, maybe I missed it but I don't even see how the code puts the CPU into idle mode to save power when there are no goroutines running.)

I understand that you can get something kind of working easily. That was the case when I did GOOS=tiny a long time ago too. But I also understand, from other projects, how much work it is to create and maintain a real operating system capable of actually using bare hardware well. That's a huge amount of added complexity for the Go team to accept ultimate responsibility for maintaining. And it is ultimately why, although it was a fun demo, we also removed GOOS=tiny a long time ago too.

As an administrative note, we are starting two Go team quiet weeks, which means I won't be replying on this issue again until July 12, to avoid having a discussion that others might want to take part in.

@abarisani
Copy link
Author

There are existing architectures in upstream Go without preemption or multithreading, in fact those architectures provided the very same code that we use right now (NaCl, js/wasm) in parts of our patch.

Regardless of this I already expressed intention in this issue to be explore how to make multithreading hooks possible.

Concerning preemption this is possible for external implementation as external packages can create timed interrupts and supervisors, we plan to demonstrate this in our GoTEE project.

This is not just a fun experiment, we have thousand of units in productions running secure elements using TamaGo.

Lowering frequency is handled externally by the application through functions we expose in our SoC driver, however I am not sure why this would be a concern for this discussion as SoC support and drivers would be an outside concern.

We have created full support for NXP i.MX6UL series and received external contributions for Raspberry Pi, to me this proves the effort in making this usable is not inconceivable.

The topics you are raising fall in what the external packages would require to implement and are not meant to be addressed or cared by the GOOS=none support (intentionally and for the reasons yourself raised initially).

So I guess now you are moving the discussion towards whether the whole Go in bare metal philosophy has merit or not rather then specific GOOS=none patch details?

The very initial concerns to this entire effort was that it would "clutter" upstream Go too much with hardware specific patterns that would be difficult to maintain and now that we moved everything out the concern is (despite one proved example of solid driver/SoC/CPU implementation) that those are external packages would be difficult or a bad experience?

I welcome all questions and clarifications on our proposal as I think this is due process, but I think we are going a little bit all over the place here and the feeling is that the mind is set on rejecting our proposal no matter what.

If the projects we are creating and supporting (listed earlier: GoKey, our bootloader, GoTEE, Armory Drive) created with TamaGo are not sufficient to prove that Go helps tremendously on the bare metal I am honestly not sure what would be.

@abarisani
Copy link
Author

abarisani commented Jun 27, 2021

On "how much work it is to create and maintain a real operating system capable of actually using bare hardware well.".

I think our patch shows how this would not be a concern of the Go team given that all actual hardware use is taken care of externally from the patch.

In fact that's the whole point of it.

@typeless
Copy link

I am also interested in such applications. But wouldn't it be better if the entire runtime package as a whole can be replaceable?
That would allow more freedom for the external ports and meanwhile not be at odds with the canonical one.
For many applications (like CLI tools), we don't need a heavyweight runtime supporting the scalability of 100K QPS but rather one with small footprint and fast startup time.

I would much rather figure out what is making it difficult to keep this port out of tree and fix those underlying issues.

A stable (or at least versioned), documented API between the compiler and the runtime and a command-line option of the toolchain to alter the runtime package?

@rminnich
Copy link
Contributor

OK, I think everyone is back, and I'd like to get this to some conclusion.

I don't detect acceptance for bare metal go, upstream. Instead, we've been encouraged to fork Go.

There are other ports that have hit a wall over the years, such as Harvey-OS. Rather than a fork-per-unaccepted-port, we're thinking it would be nice to have a common place to collect unaccepted ports. An unaccepted port is one which has never been accepted, or is no longer accepted, upstream, i.e. it has been demoted. The name go-ports has been suggested by several folks.

The rules would look something like this:

  • go-ports is a downstream fork, and superset of, the latest release
  • a go-ports port can be promoted to upstream, if it makes sense
  • an upstream port can be demoted from upstream but remain in go-ports, assuming a maintainer
  • anything on the main go-ports branch has to build
  • but there is no requirement that all ports pass all tests, though this is encouraged
  • ports that don't "just build" will be placed on a branch
  • ports that lose maintainers will be placed on a branch

The remaining question is where go-ports would live: is it an organization, e.g. github.com/go-ports/... or is it under golang, github.com/golang/go-ports?

@n2vi
Copy link

n2vi commented Aug 11, 2021

For what it's worth, those rules sound good to me. My present area of interest is a not-quite-bare-metal port of Go above seL4. Seeing worked out projects like TamaGo helps me dodge problems that others have seen and coped with.

github.com/go-ports/ would be preferable to avoid any misunderstanding about who provides support.

If the repository also helps the Go team monitor unexpected ways that Go is being used, that's a nice extra.

@rminnich
Copy link
Contributor

OK, it's done:
https://github.com/go-ports/go

Please let me know if I've messed anything up. I will try from here on out to do Tamago work on this repo.

@rsc
Copy link
Contributor

rsc commented Aug 16, 2021

Thanks for setting up go-ports/go. That seems like a great place to coordinate.

As I've noted before, if there are general things we can do to make out-of-tree ports easier, I'd be more than happy to see those proposed.

@rsc
Copy link
Contributor

rsc commented Aug 18, 2021

This proposal has been added to the active column of the proposals project
and will now be reviewed at the weekly proposal review meetings.
— rsc for the proposal review group

@beoran
Copy link

beoran commented Aug 18, 2021

As i said before on the previous issue, the current code of the Go compiler and runtime is often not structured modularly but relies an conditional compilation.

Support for out-of-tree ports would be a lot easier if a GOARCH or a GOOS could be provided by a (set of) package(s), perhaps even a go module, in stead of conditional compilation all over the code.

Yes, that means more abstraction, but it would make the go compiler and runtime easier to read and easier to work on. That alone would be a significant benefit.

@rsc
Copy link
Contributor

rsc commented Aug 25, 2021

Support for out-of-tree ports would be a lot easier if a GOARCH or a GOOS could be provided by a (set of) package(s), perhaps even a go module, in stead of conditional compilation all over the code.

What does this mean exactly?

@beoran
Copy link

beoran commented Aug 25, 2021

Maybe an example explains it better? For example: If we take a look at https://github.com/golang/go/tree/master/src/os, then we see that there are many files such as as dirent_aix.go, dirent_dragonfly.go, dirent_freebsd.go, dirent_js.go, dirent_linux.go, dirent_netbsd.go, dirent_openbsd.go, dirent_solaris.go, etc. This repeated for many functions, and selected though conditional compilation.

If in stead, the platforms could be separate directories, and thus, Go packages, then this could be refactored into, say, https://github.com/golang/go/tree/master/src/platform/aix/os, https://github.com/golang/go/tree/master/src/platform/dragonfly/os, etc. where all platform related functionality is grouped. The platforms packages could then even become go modules in separate repositories.

Then, adding a new platform could be as easy as making a new go module, and adding a bit of code in src/os, etc. to "hook it up" so to speak.

@rsc
Copy link
Contributor

rsc commented Aug 25, 2021

Based on the discussion above, this proposal seems like a likely decline.
— rsc for the proposal review group

@rsc
Copy link
Contributor

rsc commented Sep 1, 2021

No change in consensus, so declined.
— rsc for the proposal review group

@david-l-riley
Copy link

Support for out-of-tree ports would be a lot easier if a GOARCH or a GOOS could be provided by a (set of) package(s), perhaps even a go module, in stead of conditional compilation all over the code.

What does this mean exactly?

If I might extend this conversation just a bit, because this is definitely a topic of interest to me: it seems like we're talking about making things more modular such that different GOOS/GOARCH backends can be used, a la GCC and LLVM (which are also not exactly fully pluggable). I think that's a tremendously useful, if perhaps ambitious, concept. It would be decidedly easier to maintain out-of-tree port if the architecture/OS backends didn't need to drag the entirety of the compiler machinery with them.

But that would make it a lot easier for maintaining alternate ports out of tree. For example, I know there is already a sparc64 GOARCH, but it is only enabled for linux, and there is a solaris GOOS, but it is only enabled for amd64. There is an out-of-tree build of Go for Solaris/SPARC64 which I think was last updated around Go 1.8; I had a go at trying to update it a year ago and it seemed like a rather Herculean effort because a lot had changed in the surrounding code for other architectures.

I say this without a deep knowledge of the current compiler backend, of course, but I assume that this would be a pretty substantial change and something to be planned for several versions down the line if it were to happen. There would need to be, as someone mentioned upthread, a well-defined and versioned API between frontend and backends, which would presumably involve dicing up the current architecture rather more than it is now.

I do have some provisional interest in this, but I'm relatively green at Go contributions. Is there a place I should start if I want to propose an approach after doing further research?

@ianlancetaylor
Copy link
Member

The place to start is to look at the runtime package. Specifically look at the code that is built for a particular GOARCH, the code that is built for a particular GOOS, and the code that is built for a combination of a particular GOARCH/GOOS. That will describe a complex set of APIs that need to be implemented for any new target. Then try to figure out how those APIs could be supplied out of tree.

Actually a seperate GOARCH would be a big job requiring new assembler, compiler, and linker support. Probably best to focus on just GOOS to start.

@abarisani
Copy link
Author

Indeed, TamaGo also only targets GOOS and never touches GOARCH.

@david-l-riley
Copy link

Since this is a closed issue, I'd be happy to take the discussion to the golang-dev mailing list if that's a better place.

@rsc rsc moved this to Declined in Proposals Aug 10, 2022
@rsc rsc added this to Proposals Aug 10, 2022
@golang golang locked and limited conversation to collaborators Sep 10, 2022
@rsc rsc removed this from Proposals Oct 19, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests