Unix on Teensy 3.5

onre

Member
First, a disclaimer: I'm doing this for fun, not because it made any particular sense.

For background, I've dabbled with embedded systems as a hobby for some time. I've mostly made things that work together with my modular synthesizer setup. Lately I've been working on a one-hand chording keyboard for general text input and ended up writing a small multi-tasking library for it.

While writing that code, I remembered how I've read about the RetroBSD project, where an individual ported 2.11-BSD to the PIC32MX7 family of microcontrollers. I thought about how the PIC32MX7 and the Kinetis-K family aren't that different in concept and capacity, the biggest difference being the processor core architecture, which is MIPS on PIC32MX7 and ARM on Kinetis-K. Turns out that another individual had already ported RetroBSD to STM32F4, which is another Cortex-M based MCU family, very similar to Kinetis-K. Their work is called DiscoBSD, and, well, I had this long weekend which I spent mostly pasting things together from DiscoBSD and Teensyduino init code and writing the missing bits.

It gets this far now:

Code:
20241120 20:15:41    connected to /dev/ttyACM1    press C-z q to exit


DiscoBSD 2.3-current (TEENSY35) #92 561: Wed Nov 20 20:13:48 2024
     esp@tieteislaskin:/sys/mk64/teensy35
cpu: MK64FX512, 120 MHz, bus 60 MHz
oscillator: oscillating
usbuart0: USB, console
sd0: port sdio0
sd0: type SDHC, size 7822336 kbytes
sd0a: partition type b7, sector 2, size 204800 kbytes
sd0b: partition type b8, sector 409602, size 2048 kbytes
sd0c: partition type b7, sector 413698, size 204800 kbytes
phys mem  = 255 kbytes
user mem  = 191 kbytes
root dev  = (0,1)
swap dev  = (0,2)
root size = 204800 kbytes
swap size = 2048 kbytes
...and eternal silence falls, as of now. This is the point of first fork() where one branch becomes swapper (pid 0) and another becomes init (pid 1).

In case you want to take a look or play with it yourself, it's all here. Another disclaimer: it's a mess, I need to clean up both the tree and the commit history if I ever get this to actually run processes. It should more or less build with the Teensy toolchain. Set ARM_GCC_PREFIX to $HOME/.arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/arm-none-eabi, then run make MACHINE=mk64 MACHINE_ARCH=arm to build a ton of things. unix.hex should appear in sys/mk64/teensy35 and is flashable with the Teensy loader.

I'll post here if I get any farther.
 
Okay, we're definitely multitasking now.

Code:
20241123 03:32:07    connected to /dev/ttyACM0    press C-z q to exit


DiscoBSD 2.3-current (TEENSY35) #109 576: Sat Nov 23 03:31:54 EET 2024
     esp@tieteislaskin:/sys/mk64/teensy35
cpu: MK64FX512, 120 MHz, bus 60 MHz, MPU enabled, 12 regions
mpu: region 0: 00000000-ffffffff, RGDAAC0 0361f7df
oscillator: oscillating
uartusb0: USB, console
sd0: port sdio0
sd0: type SDHC, size 7822336 kbytes
sd0a: partition type b7, sector 2, size 204800 kbytes
sd0b: partition type b8, sector 409602, size 2048 kbytes
sd0c: partition type b7, sector 413698, size 204800 kbytes
phys mem  = 255 kbytes
user mem  = 191 kbytes
root dev  = (0,1)
swap dev  = (0,2)
root size = 204800 kbytes
swap size = 2048 kbytes
syscall! @ 0x00001d19
syscall! @ 0x00004b05
syscall! @ 0x00002611
syscall! @ 0x000025ad
syscall! @ 0x000034a1
syscall! @ 0x000034a1
syscall! @ 0x000034a1
syscall! @ 0x000034a1
syscall! @ 0x000034a1
syscall! @ 0x000034a1
syscall! @ 0x000036cd
syscall! @ 0x000036cd
syscall! @ 0x0000c28d
syscall! @ 0x00001a29
syscall! @ 0x000034a1
syscall! @ 0x000034a1
Those are entry point addresses in flash, 1d18 = execv, 4b04 = gettimeofday, 2610 = getuid, 25ac = getpid, 34a0 = sigaction, 36cc = sigprocmask, c28c = open, 1a28 = close... it is actually running something, even though I can't see the actual process output. Need to take another look at that console "driver" I cobbled together. I also (obviously) needed a root device of some sort, so I took the Teensy fork of the SdFat library, did a quick n dirty "C port" of the SD card access part of it and to my amazement it actually worked on the first try. Honestly, I know very little C++ and my method can be described as "remove everything that does not look like C".

I spent considerably more time trying to figure out what is corrupting my first process's u structure. The answer is: nothing. The code has relied on readily zeroed memory for almost four decades. So, a quick memset() addition to the early startup code to avoid accidentally zeroing the stack, too, and suddenly it seems like we're running multiple processes, simultaneously, on a single computer! What is this sorcery?🧙‍♂️

Joking aside, I've yet to see a character being printed from the userspace. At this rate we'll get there soon enough, though. Getting to this point this quickly did wonders for motivation. A week ago my knowledge of ARM processor specifics was of the level "um, I believe it is a RISC design" so it's been a rather deep dive. Unix is familiar, though. I think I need to buy a 4.x from the sale and get this going on that as well. TBH this does not look like a bad platform for certain sorts of projects.

Maybe solder a MAX3232 to every UART on board and have it run six terminals at once?
 
Code:
DiscoBSD 2.3-current (TEENSY35) #2 588: Fri Nov 29 11:17:32 EET 2024
     esp@tieteislaskin:/sys/mk64/teensy35
cpu: Kinetis K64, 120 MHz, bus 60 MHz
mpu: enabled, 12 regions
mpu: region 0: 0x00000000-0xffffffff flags 0x0061f7df
oscillator: oscillating
uart1: found, 64 tx/64 rx bytes FIFO, console
sd0: port sdio0
sd0: type SDHC, size 7822336 kbytes
sd0a: partition type b7, sector 2, size 204800 kbytes
sd0b: partition type b8, sector 409602, size 2048 kbytes
sd0c: partition type b7, sector 413698, size 204800 kbytes
phys mem  = 255 kbytes
user mem  = 191 kbytes
root dev  = (0,1)
swap dev  = (0,2)
root size = 204800 kbytes
swap size = 2048 kbytes
alive for = 1833 ms
init: starting /bin/sh
erase ^?, kill ^U, intr ^C
# ps aux
USER       PID NICE SZ TTY  TIME COMMAND
root         1   0  37 0    0:00  (-)
# ls -l /
total 12
lrw-rw-r--  1 root           13 Nov 29 01:02 .profile -> root/.profile
drwxrwxr-x  2 root         1024 Nov 29 01:02 bin
drwxrwxr-x  2 root         1024 Nov 29 01:02 etc
drwxrwxr-x  2 root         1024 Nov 29 01:02 home
drwxrwxr-x  2 root         1024 Nov 29 01:02 root
drwxrwxr-x  2 root         1024 Nov 29 01:02 sbin
drwxrwxr-x  9 root         1024 Nov 29 01:02 usr
drwxrwxr-x  6 root         1024 Nov 29 01:02 var
#

I can't be sure, but I'd guess this makes me the first person to run Unix on a Teensy?

Anyway, going to spend this evening cleaning up the tree and then see what bites me next. The UART driver needs improving at least - as Paul remarks in a Teensyduino serial1.c comment, the Kinetis UART is a bit weird.

So, what do we next? Does a middle-aged BSD need a USB stack? Framebuffer driver? Something else? Given the quality of Teensyduino code, it's rather trivial to get all that going - the bigger challenge is coming up with a nice way of how to represent all that in the userspace. I've long fancied for a /dev/ugpio which would allow the user to configure any bunch of GPIO pins in a more or less freeform manner, be it async bitbanging, interrupt-driven I/O or whatever is required by the problem at hand, and then just do file I/O on them.

Someone asked me whether I'm debugging this with JTAG or OpenOCD+gdb. I'm not sure whether or not to send the attached photo to them.
 

Attachments

  • teensy_bsd_debug.jpg
    teensy_bsd_debug.jpg
    90.2 KB · Views: 21
Now we are booting to multi-user mode, need to hook up another UART. Repository needs attention, I've been hacking together horrible code to get to this point, general idea being "I'll clean it later". There's a slight glitch in the UART driver still - I have hooked up a button to the board so I can manually trigger interrupts for debugging - turned out that pushing the button is required to get it to go multiuser. I think the culprit is in my uartopen(), need to look at how it is supposed to be done.

The two weird printouts are the debug strings printed by the interrupt handler, showing current systick count and swapin/swapout activity from last five seconds.

I'll post the rest of the source and the build artifacts once I get that ironed out, in case someone else wants to play with it too.
 

Attachments

  • teensy_bsd.png
    teensy_bsd.png
    70.3 KB · Views: 9
Back
Top