top | item 22684881

Getting started with bare-metal assembly

422 points| a7b3fa | 6 years ago |johv.dk

181 comments

order
[+] rixrax|6 years ago|reply
I think one great way to do this is to get a Commodore 64 emulator (or Atari 2600 etc) and start writing and learning 6502 assy. Arguably its one of the last instruction sets that was designed with humans writing code in assembly (and not in some higher level language) making it excellent learning language. You can readily run your code in emulators and for not too much $$$ you can pick a real hardware from EBay to really run it on HW.

And once You think you’ve run hw to its limits there are plentiful demos and examples around to blow your mind watching what people have been able to do with these machines (often in obscure ways).

[+] mksaunders|6 years ago|reply
Commodore 64, sure, but I wouldn't recommend the Atari 2600 for beginners! I wrote a small game for the 2600 years ago, and it's a tricky little machine. It doesn't even have a video frame buffer, so you have to do things on the fly, depending on which line of the screen is being beamed (think of old-school CRTs).

Indeed, a whole book was written about it: https://en.wikipedia.org/wiki/Racing_the_Beam

The 2600 is fascinating and fun to code for, but for asm newbies I'd recommend the C64 or NES...

[+] pizza234|6 years ago|reply
I've always been skeptical of using retro machines to learn low-level programming.

While the processors are simple, making non-trivial programs is hard, because the machines as a whole have lot of limitations, making programming very intricate, compared to more modern systems (say, 16-bit 80x86, but I guess even Amiga and so on).

If the target it challenge for the sake of challenge, then nothing makes those machines special, I mean, one can code directly in machine code if that's the intention :-)

[+] inetknght|6 years ago|reply
> And once You think you’ve run hw to its limits there are plentiful demos and examples around to blow your mind watching what people have been able to do with these machines (often in obscure ways).

What blew my mind was using a modern C++ compiler to build optimized software for that old hardware. Here's an example with the Commodore 64 [0].

[0]: https://www.youtube.com/watch?v=zBkNBP00wJE

[+] smabie|6 years ago|reply
I learned mips in a college class and quite enjoyed it. How does mips compare to C64 asm? I don't know any other asm besides mips (unless zachtronics games count) and but have been playing around with the idea of writing a simple asm OS. Would C64 asm be a good choice? I've also heard that m68k asm is nice. How do the three compare?
[+] pjmlp|6 years ago|reply
I think it is more up to date to grab a Arduino, ESP32, Raspberry Pi, Hydra based console, and program it like the old days.
[+] heinrichhartman|6 years ago|reply
Does anyone know how to circumvent UEFI?

When the CPU starts, it will start reading instructions from a hard-coded address on the memory bus / EPROM somewhere, right? How can I directly control these bytes?

I don't want some proprietary firmware sit between me and the CPU.

If it's not possible on hardware because "secure boot", or whatever, this should at least be possible in emulators like QEMU.

Does anyone know how to do that? ... or clear up my misconceptions? :)

[+] pjc50|6 years ago|reply
In QEMU it's dead simple, you have control of everything; I believe that it boots into https://github.com/qemu/qemu/tree/master/pc-bios

A physical machine will still, despite everything, start executing at FFFF:0000 in "real mode", and the code run there will be found in a physical EEPROM. Some of these are socketed (although this is less common these days). So you can get in there and fiddle with the pre-boot code.

See https://www.drdobbs.com/parallel/booting-an-intel-architectu...

There is no way round the Management Engine, a source of distress to some. Oh, and you won't have any DRAM until you've run the DRAM training and turned that on, the early BIOS gets to use the cache as a scratchpad instead. See https://blog.asset-intertech.com/test_data_out/2014/11/memor...

If you like bare metal work with decent processing power ARM is probably the place to start.

[+] kryptiskt|6 years ago|reply
Below UEFI is the BIOS, or the firmware formerly known as the BIOS. There is a project to make an open source firmware for PCs: https://www.coreboot.org. It works on a selection of newish motherboards.

You can't really start completely from scratch in an understandable way on Intel platforms, and it's iffy on ARM. Because setting up the DRAM requires some insane magic, where it doesn't really help if you can see the source.

[+] duskwuff|6 years ago|reply
> I don't want some proprietary firmware sit between me and the CPU.

No, you do.

A significant part of what that firmware does is initializing low-level hardware, like the system's memory controller. Replicating that is probably well beyond your abilities.

[+] stefan_|6 years ago|reply
That is not really a thing anymore, most processors now have burned-in ROM from the vendor that they boot into first.

If you really want to understand and control a processor when it boots from nothing, you should look into a FPGA RISC-V development board.

[+] korethr|6 years ago|reply
Go check out the Coreboot project. They're about as low-level and bare metal as you can get, because Coreboot is not running on the board firmware, it is the board firmware. And as an open source project, they document all the various things they have to do in order to initialize all the hardware on a board and have it ready to be used.

You are generally correct in your assumption: that once the CPU comes out of reset, it will reach for a particular memory address to begin execution. Some will directly begin execution from a fixed address. A sibling pjc50 comment mentions, on x86, the CPU will be in 16-bit real-mode and begin fetching instructions from FFFF:0000. Other architectures, work slightly differently. Motorola 68k fetch the first 4 bytes from 0x00000000, loads them into the program counter register, and then jumps there to begin execution.

As you saw, the child of a pjc50's comment explains how to pass your code directly to the beginning of the CPU's execution in QEMU. If you want to do this with actual metal, various classic chips of yore (z80, 6502, 68k, etc) and their documentation are relatively easy to get. A nice thing about those older CPUs, is that their memory interfaces are rather simple compared to today. You can wire up a very basic system with the CPU, an EPROM, an SRAM chip, and maybe a couple other chips as glue logic, all on a basic breadboard. And then you really can control those first bytes of executed code, on actual metal.

[+] Wowfunhappy|6 years ago|reply
I really hate to be the downer here, but have you heard of Intel's Management Engine? :(
[+] 0xff00ffee|6 years ago|reply
Not exactly bare metal when you've got UEFI in there.

In the embedded world, Bare Metal means you control the first byte executed by the CPU when it comes out of POST, and aren't using any kind of operating system or proxy loader in between. But it gets kinda fuzzy, because RToS is still "bare metal" and you have full access to the source-code.

[+] waynecochran|6 years ago|reply
That's not really bare metal either. You should be directly manipulating the electrons flowing through the material :)
[+] saagarjha|6 years ago|reply
If you want to go down a different rabbit hole than being "bare-metal" while still being in UEFI, take a look at EFI Byte Code: it's a strange and arcane little virtual machine that you can use to write cross-platform UEFI drivers. Here's a simple emulator for it: https://github.com/yabits/ebcvm
[+] kahlonel|6 years ago|reply
I recommend anyone just starting with bare-metal assembly to get an STM32F0 board and write assembly programs for it. I'm just gonna plug my super small toy RTOS I wrote for Cortex-M0 a while ago.

https://github.com/kahlonel/rt0s

[+] 0xff00ffee|6 years ago|reply
CubeMX is the best config manager I've ever used, the clocking interface alone should be mandatory for all embedded companies.

I have still yet to really need an RTOS, even for BLE.

[+] newswasboring|6 years ago|reply
Just an aside, but it always felt weird to me that we call is bare-metal while the actual code runs on mostly semiconductors.

I am very glad that in my bachelor program our microcontrollers class actually made us hand enter hex codes in a kit. It got tedious after a while (maybe it should have been for only a few weeks not the whole semester), but it gave me a weird sense of being one with the machine. And it has as awesome ice breaker when talking with older programmers. For some of them I am the only one of my age that they have met who has ever done this. Another thing is it helped me sort of see the flow of it and encouraged optimization.

(I don't want to give too much credit to my college, they did it not as some great pedagogical trick but to save money and laziness)

[+] GeorgeTirebiter|6 years ago|reply
Bare metal comes from mainframe days. The largest systems like IBM 360-67 and others were called "Big Iron" - see https://www.ibm.com/ibm/history/ibm100/us/en/icons/system360... for NASA's moonshot-era Big Iron. You could run programs on OS/360 or you could, if daring, run code directly on the machine, on the "Bare Metal". It's quite common to run 1-card programs on the Computer History Museum's IBM 1401 --- which was not really considered 'Big Iron' at the time, although today we call it a 'Mainframe' https://computerhistory.org/exhibits/ibm1401/
[+] tyingq|6 years ago|reply
I think it might come from auto body shop terminology. We would remove layers of paint or rust and get down to the "bare metal" for prep work. That "down to the bare metal" phrase was very commonly used.

That is to say "no layers" or "right on the substrate".

Just a guess though.

[+] caspper69|6 years ago|reply
My first actual programming class was on an Intel 8085 kit, and I have to say that hand-assembling on pre-printed carbon sheets was pretty cool. It has served me well in my career to have started at that level.
[+] abhishekjha|6 years ago|reply
We also pogrammed the 8085 machine very recently(2015). It was a very weird feeling realising all the myriad of abstactions come down to basic load/store/arithmetic/logical instructions. Had fun implementing squaring a number whose result wouldn't fit in a register.

EDIT: It was 8085 kit, not 8086.

[+] stan_rogers|6 years ago|reply
Hasn't always been semiconductors... or electronics at all, for that matter. That just happens to be the current majority physical implementation, where metal is a little scarcer than it used to be.
[+] cptnapalm|6 years ago|reply
A couple of years ago, I was learning PDP-11 assembly on 2.11 BSD and enjoying it, but then the old textbook got to the point of system calls. I couldn't get anything working properly, so eventually I found something else to do. I did very much like it though.

Also, TIS-100 from Zachtronics (the assembly language game you never asked for!) I think made assembly type programming less intimidating.

[+] fmakunbound|6 years ago|reply
It used to be way easier. Something like this:

    debug hn.com

    a 100
    mov dx, 200
    mov ah, 9
    int 21
    mov ax, 4c00
    int 21

    a 200
    db "Hello, World$"
    
    w 300
    q
Replace 100 with 0 and write it to the first sector of a disk and you had a bootable program (BIOS interrupts only, of course).

Edit: Geezus. It's just an example of how accessible getting something running in assembly language was compared to all the qemu, UEFI stuff in the article.

[+] 0xff00ffee|6 years ago|reply
int 21h uses ...

A BIOS CALL. :)

Still not bare metal.

:)

(I'm totally gatekeeping for laughs: write your own BIOS you noob!)

[+] gruturo|6 years ago|reply
Wasn't int21h a call to MS-DOS functions? (Also understood by Windows)

I'm not sure it would work if you stuck this in a boot sector.

[+] basementcat|6 years ago|reply
I'm just tickled that someone can post a snippet of x86 assembly on HN and several people start pointing out perceived issues with it.
[+] greyhair|6 years ago|reply
You can explore the same world easily in AVR, ARM M0/4, or PIC. And really be running on bare metal.
[+] mlang23|6 years ago|reply
Does anyone know if qemu and OVMF can be made to work in plain text mode? I just tried but qemu wants GTK by default, and when I pass -curses I get a message that the screen is in 640 x 480 graphics mode. Is UEFI really that complex that it doesnt allow for plain console access?
[+] a7b3fa|6 years ago|reply
Try '-nographic'. It can be a bit wonky IME, but good enough for the basics.
[+] DoofusOfDeath|6 years ago|reply
At first I thought this would be a story about DIY metalwork projects during quarantine.
[+] liquidify|6 years ago|reply
I always wanted to do this stuff, but classes just never taught it. I think some of the ECE students got some classes which taught some assembly, but not us lowly CS people.
[+] commandlinefan|6 years ago|reply
FYI if you're trying to follow along - it appears that QEMU doesn't (for some reason) run on a headless workstation. You'll have to have X installed.
[+] ngcc_hk|6 years ago|reply
Any instruction to run this under macOS. Qemu can run of course. But ovmf.fd (or install from edk2) seems no clear instruction under macOS.
[+] classified|6 years ago|reply
Is there another level of assembly than bare-metal?
[+] underthensun|6 years ago|reply
Love playing with Assembly and bare-metal :)
[+] djmips|6 years ago|reply
Why are assembly related topics so popular on Hacker News? I don't see pursuit of this topic happening in my anecdata of programmers I interact with in day to day life.
[+] Koshkin|6 years ago|reply
I am not sure if using heavily microcoded CPU instructions qualifies as "bare metal programming."