As a follow up to my post An ARM Bare Metal Hello World Using Musl I thought I’d give an update. A quick background. I’m trying to build a bare metal (no OS) framework that can use a stock Linux standard C library. To do this I’m building a small assembly infrastructure that traps the Linux system calls used by the library and deals with them. In my previous post, I got “hello world”. In this one, I’ve come a bit farther. I can read stdin, malloc() memory and do simple context switching. You can see the code I’m working on here. In this example, printf(), fgets() and malloc() is usable enough to be used for a simple context switching example.
Most of the example main program (THREAD is not defined yet: don’t get too excited):
long __syscall_ret(unsigned long r); long __syscall(long, ...); #define CONTEXT #if defined(CONTEXT) static void *main_sa; static void *context1_sa; static void *context2_sa; static int context(intptr_t arg1, intptr_t arg2) { void **context_sa = (void **)arg2; for ( ;; ) { printf("hello from context %" PRIdPTR "\n", arg1); __switch(context_sa, main_sa); } return 0; } #endif int main(int argc, char **argv) { printf("%s: hello world\n", argv[0]); int i = __syscall_ret(__syscall(0, 1, 2, 3, 4, 5, 6)); printf("__syscall(0) = %d, %s\n", i, strerror(errno)); #if defined(THREAD) int s; pthread_attr_t attr; s = pthread_attr_init(&attr); pthread_t id; if (s != 0) printf("pthread_attr_init: %s\n", strerror(errno)); s = pthread_create(&id, &attr, &thread, NULL); if (s != 0) printf("pthread_create: %s\n", strerror(errno)); #endif #if defined(CONTEXT) char *p = malloc(4096); context1_sa = p + 4096; __new_context(&context1_sa, context, Mode_SYS, NULL, 42, (intptr_t)&context1_sa); p = malloc(4096); context2_sa = p + 4096; __new_context(&context2_sa, context, Mode_SYS, NULL, 6809, (intptr_t)&context2_sa); // Let's do some context switching. __switch(&main_sa, context1_sa); __switch(&main_sa, context2_sa); __switch(&main_sa, context1_sa); __switch(&main_sa, context2_sa); __switch(&main_sa, context2_sa); #endif for ( ;; ) { char buffer[100]; fputs("prompt: ", stdout); fflush(stdout); fgets(buffer, sizeof(buffer), stdin); printf("got: %s", buffer); } }
The output:
~/ellcc/baremetal/arm] dev% qemu-system-arm -cpu any -M versatilepb -m 128M -nographic -kernel kernel.bin pulseaudio: set_sink_input_volume() failed pulseaudio: Reason: Invalid argument pulseaudio: set_sink_input_mute() failed pulseaudio: Reason: Invalid argument kernel: hello world unhandled system call (0) args: 1, 2, 3, 4, 5, 6 __syscall(0) = -1, Function not implemented hello from context 42 hello from context 6809 hello from context 42 hello from context 6809 hello from context 6809 prompt: hello world got: hello world
It’s almost starting to look like Posix at the bare metal level. Fun stuff.
A lot of what you are trying to do here is not exactly new. Back in the 1980s (yes, 1980s..) there were C compilers available for the 6502 MCU. They supported standard C libraries, although functions like printf() were somewhat limited and astoundingly slow. There was no OS at all; programs were all bare metal. I wrote the hardware bindings for Apple II, Commodore 64, and the like.
Hi Steve,
I had to chuckle when I read your comment. I think it was around 1980 when I first released the Introl-C compiler for the 6809. It subsequently evolved into compilers for the 68HC16, 68000 family, 68HC16 (yuck!) and 68HC12. Most of the users of those compilers worked on bare metal.
Yes, I’m reliving my youth. The tools are a bit shinier now.
-Rich
Hi All;
Rich and everyone, I am going to see IF I can DownLoad the various files, and Start where Rich started in this Project, and work my way to where He is at, at the present..
Trying to understand not only what He is Doing, but Why He is doing what He is doing..
Hopefully I can Learn something about the Whole Process, in the Process..
Since I am an Old Dog, there just might be a possibility that I could Learn some New Tricks..
Rich, What Files did You start with ???
THANK YOU Marty