Hacker News new | ask | show | jobs
by ksaj 1054 days ago
I did some experimenting with RPi assembler a handful of years back, since I used to do a lot of x86 assembler throughout the 90's. If you're interested, here are 6 completely different ways to print Hello World in Assembler for the Raspberry Pi.

https://github.com/ksaj/helloworld

I kept the code as close to each other in format and style as possible, so comparisons are easier to make. I don't really know the benefits and drawbacks to each method, but they are there and available, so I sleuthed them out and got them working.

2 comments

> Hello World bypassing clib altogether, and talking direcly to the hardware. Apparently this is a no-no, even if it is theoretically more efficient. The bare-metal and OS dev folk are pretty much limited to using this method until their kernel boots and provides other methods, like those covered already.

This doesn't seem quite right; the code doesn't use libc, but it talks to kernel and not directly to hardware. On Linux I don't think direct syscalls are in any way "no-no". But most importantly it still doesn't work on bare-metal; indeed, the hardware has no concept of stdout

"Software Interrupt (SWI) functions are functions that run in Supervisor Mode of ARM7™ and ARM9™ core and are interrupt protected."

also

"This means that the processor state changes to ARM, the processor mode changes to Supervisor, the CPSR is saved to the Supervisor Mode SPSR, and execution branches to the SWI vector"

I'll have to go into that further. I was under the impression it was similar to the x86 OUT opcode. So is it more akin to a "direct syscall" then?

I wrote a longer answer in response to your other comment. It has a lot of explanation that I see from this comment is likely not needed for you. I’m pasting it here, anyway. I’m no expert in ARM assembler but it appears that SWI 0, later renamed SVC[1], is how you make system calls in ARM Linux[2]. That would make it equivalent to x86 syscall. In other words, it’s the underlying mechanism that libc uses to ask the kernel to output some data. In this case you are calling the write[3] system call (selected by r7=4) with the arguments (r0:fd=1 - file descriptor 1 – i.e. stdout, r1:buf - the address of the data to write, r2:count=14). The kernel then does whatever is necessary to accomplish that write. It could be talking to the video core to update the text console or the contents of a window. It could be passing it to its lower networking layers for sending over an existing network connection for an ssh connection.

It’s pretty fundamental to the Linux kernel that you can’t access any hardware directly unless things have been set up specially to allow it in a limited way. If you really want to deal directly with the hardware, you either have to convince the kernel to allow you to, or run without an operating system. In that latter case, it’s on you to drive all of the hardware. And there’s actually quite a lot of hardware involved in getting stuff displayed on a raspberry pi screen.

[1]: https://developer.arm.com/documentation/qrc0001/latest/ [2]: https://man7.org/linux/man-pages/man2/syscall.2.html [3]: https://man7.org/linux/man-pages/man2/write.2.html

Thanks! I'll check out your other response as well.
Direct to the hardware would be initializing the frame buffer and writing there. Which means that you need to have all the glyphs and then look them up and write them into the frame buffer.

This is what we used to do with 8 bit computers that didn’t have a hardware text mode. You might be able to look up the bitmaps in the ROM, otherwise it’s time to define them all yourself.

Using a direct system call would be like calling a ROM routine or an OS routine to print characters. You’d either call the routine or invoke a software interrupt.

Check my reply earlier in the thread. I was working under the assumption that SWI is akin to x86's OUT opcode. Maybe you can decode the quoted stuff and set my brain straight.
SWI is just software interrupt. Gets trapped by supervisor mode. Then the registers can be decoded by the kernel to implement the correct syscall. Old school real mode x86 equivalent would be an INT instruction.

If you want to do straight to the hardware bare metal then you need to do something like this (https://www.rpi4os.com/part5-framebuffer/) but you’re going to have to do all the other system init work that a modern system needs. Old computers were simpler!

That would definitely be far outside the scope of what I was trying to accomplish with all the helloworlds. Although I could do it and list it as the most needlessly complicated version.