[HN Gopher] Proposal: Add bare metal support to Go
       ___________________________________________________________________
        
       Proposal: Add bare metal support to Go
        
       Author : rbanffy
       Score  : 49 points
       Date   : 2025-05-07 19:44 UTC (3 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | Someone wrote:
       | FTA:                 // printk emits a single 8-bit character to
       | standard output       //       //go:linkname printk
       | runtime.printk       func printk(c byte)
       | 
       | So, printing "Hello, world!", necessarily will have to make 13
       | calls to this function. I think I would have required a _printk_
       | that prints an array of bytes. I expect that can be significantly
       | faster on lots of hardware.
       | 
       | In contrast, there's                 // getRandomData generates
       | len(b) random bytes and writes them into b       //
       | //go:linkname getRandomData runtime.getRandomData       func
       | getRandomData(b []byte)
       | 
       | Here, they seem to acknowledge that it can be faster to make a
       | single call.
        
         | jeroenhd wrote:
         | The method for printing uses an Intel UART driver to print
         | characters. AFAIK, the standard low level UART generally only
         | does single character transfers unless you write a (relatively)
         | complex driver.
         | 
         | Rendering per string is better per string, but I'm not so sure
         | how bad the difference is when it comes to UART but I doubt the
         | system has enough throughput for the first implementation to
         | matter.
        
           | 90s_dev wrote:
           | I wonder if this is related to that bare metal bios os post
           | from a week or so ago. I asked the author why he used tty asm
           | calls to print instead of calling int 10 directly and he said
           | it was more efficient, but for different reasons.
           | 
           | https://news.ycombinator.com/item?id=43873822
        
         | ronsor wrote:
         | Arguably `printk(c byte)` should be `printck(c byte)`, and
         | there should be a separate `printk(s []byte)` that handles an
         | array of bytes.
         | 
         | If `printk` isn't implemented, then fall back to repeated calls
         | of `printck`.
        
         | timewizard wrote:
         | > Here, they seem to acknowledge that it can be faster to make
         | a single call.
         | 
         | It calls the internal Fill function to fill 4 bytes of the
         | slice at a time. That calls the rng assembly stub function
         | which uses 'rdrand' to get 32bits of random data. Which gets
         | called len(b)/4 times.
         | 
         | I don't think they did it for speed but rather to be more
         | idiomatic.
         | 
         | Anyways, OSDev has had a "Go Bare Bones" page for quite a
         | while:
         | 
         | https://wiki.osdev.org/Go_Bare_Bones
        
       | jasonthorsness wrote:
       | We use 'scratch' containers for many of our Go applications, so
       | they have no user-space stuff other than our application binary.
       | It reduces exposure for security vulnerabilities. This proposal
       | seems to be taking that approach to the extreme - not even a
       | kernel. Super-interesting; I wonder if it could run on cloud VMs?
       | How tiny could the image become?
        
         | jasonthorsness wrote:
         | Looks like Tamago targets multiple VM runtimes
         | https://github.com/usbarmory/tamago?tab=readme-ov-file
        
         | veggieroll wrote:
         | How do you handle temp file space, timezone data, and other
         | things that a minimal image provide?
        
           | kfreds wrote:
           | Temp file space: Use RAM, or talk to host storage over
           | Virtio.
           | 
           | Timezone data etc: You would have to fetch that over the
           | network, or from a metadata API such as the one Firecracker
           | provides to VM guests.
        
           | fpoling wrote:
           | Services rarely need timezone done. So if one is OK with
           | supporting only UTC, Go runtime works fine without any
           | timezene data.
           | 
           | We use a minimal image to run in on AWS Nitro VM and it
           | contains only kernel, init.d, the Go application file and TLS
           | certificate roots with the root filesystem mounted over
           | tmpfs.
           | 
           | Note that Nitro VM uses a custom kernel provided by AWS so
           | the new proposal is not relevant for us. But if we could run
           | Go directly in that VM, it will surely makes things faster
           | and saves like 10% memory overhead. And it will also avoid
           | OOM killer and few other bad unwanted interactions between Go
           | runtime and Linux kernel memory management.
        
         | kfreds wrote:
         | > This proposal seems to be taking that approach to the extreme
         | - not even a kernel.
         | 
         | To be fair, there is a kernel - the Go runtime. But since there
         | is no privilege separation it classifies as a unikernel.
         | Performance gains should be expected compared to a system where
         | you have to copy data to/from guest VM kernel space to guest VM
         | user space.
         | 
         | > I wonder if it could run on cloud VMs?
         | 
         | Yes. TamaGo currently runs in KVM guests with the following
         | VMMs: Cloud Hypervisor, Firecracker microvm, QEMU microvm.
         | 
         | > How tiny could the image become?
         | 
         | Roughly the same size as your current Go binary. TamaGo doesn't
         | add much.
        
           | ignoramous wrote:
           | > _To be fair, there is a kernel - the Go runtime._
           | 
           | I like Anil Madhavapeddy's definition for such setups. A
           | compiler that just refuses to stop:                 MirageOS
           | is a system written in pure OCaml where not only do common
           | network protocols and file systems and high-level things like
           | web servers and web stacks can all be expressed in OCaml but
           | the compiler just refuses to stop ... compiler, instead of
           | stopping and generating a binary that you then run inside
           | Linux or Windows, will continue to specialize the application
           | that it is compiling and ... emit a full operating system
           | that can just boot by itself.
           | 
           | https://signalsandthreads.com/what-is-an-operating-system /
           | https://archive.vn/yLfkq
        
       ___________________________________________________________________
       (page generated 2025-05-07 23:01 UTC)