It doesn't look like support for FM TOWNS hardware was ever upstreamed into the official Linux kernel source, but Osamu Kurachi has been maintaining patches against Linux kernel versions up to the present-day Linux 6.7.0:
It took me a bit of hunting to find this page, so here's hoping Cohost's SEO juice makes it easier for the next person.
Just for fun, I built a kernel using the Linux 6.9 (nice) source and Kurachi's FM TOWNS patches, and booted it on my FM TOWNS SN. Something is wrong with the console driver though...
After trying a few different variants of kernel settings to no avail, I went to the source code. Unlike IBM-compatible PCs, the FM TOWNS doesn't have anything like a VGA adapter, and its custom graphics processor doesn't have a true text mode. But since the TOWNS port far predates the standard framebuffer console in modern Linux, the patch set instead heavily alters the vgacon text-mode console driver into an ad-hoc framebuffer console of sorts. The altered driver supports user-provided console fonts, like the standard VGA console driver does, and it initializes itself using the font in the FM TOWNS ROM. It does so using this loop:
static void ank_user_font_init(void)
{
unsigned long flags;
unsigned long code,i;
unsigned long ankbase, src_addr, dest_addr;
ankbase=((unsigned long) towns_vram_base) +(1024*512)+0x3d800;
for(code=1; code<0x100-2; code++) {
src_addr = ankbase + (code<<4);
dest_addr = ((unsigned long) ank_user_font8x16) + (code<<4);
if (code < 3) { // ank transfer wait
pr_info("ank xfer:code=%ld src=0x%lx dst=0x%lx: ",code, src_addr, dest_addr);
}
raw_spin_lock_irqsave(&vga_lock, flags);
__asm__("cld\n\t"
"movsl\n\t"
"movsl\n\t"
"movsl\n\t"
"movsl\n\t"
:
:"D" (dest_addr),
"S" (src_addr));
raw_spin_unlock_irqrestore(&vga_lock, flags);
for(i = 0; i < ANK_XFER_WAIT ; i++) outb(0, 0x6c); /* wait */
}
}
The asm immediately stood out to me. It copies the font information from ROM to the driver's user font buffer using four movsd (movsl in AT&T syntax) instructions, each of which loads four bytes from the address in the register ESI, stores a copy of them to the address in register EDI, then increments both ESI and EDI by four to point to the next value. The "D" (dest_addr), "S" (src_addr) constraints on the asm tell the compiler to assign the dest_addr variable to the EDI register and the src_addr to ESI. However, these are read-only constraints, and the movsl instruction modifies the registers. The compiler doesn't look into the contents of asm instructions, though, and continues to generate code assuming that it can still use the values in ESI and EDI that it put there before the assembly executed. The asm instruction also fails to indicate that it clobbers memory, so the compiler might move it around assuming it has no side effects.
Anyway, I replaced the above code with a memcpy, and now I can clearly see the kernel panic message. Time to figure out what's causing the panic… The 0F A2 instruction it's trapping on is a CPUID instruction, which came with the Pentium. It looks like it's trying to load microcode, which definitely isn't a thing for a 486 processor like this, so hopefully I just need to compile that part of the kernel out.