VOGONS


First post, by Chrisnoeding

User metadata
Rank Newbie
Rank
Newbie

Hi folks,

I'm in the middle of a stupid idea: I'm programming a DIY BIOS for the AMD Elan SC300, an 386SX SOC originally from 1993, but sold way longer. The SoC is placed on an old Behringer DDX3216 audiomixing console, so the hardware-part is fine and running flawlessly.

Up to now I got pretty far:
- the SOC itself, the DRAM and SRAM is initialized correctly (RAM-test is successful)
- all important BIOS interrupts are in place
- the integrated LC Display can already be controlled via my own INT10
- external UART chip is working
- CF Card is working and bootsector can be copied to RAM at offset 0x7C00 in segment 0x0000
- bootsector loads IO.SYS and (probably) MSDOS.SYS

The System loads an MS DOS6.22 copied to the 512MB CF Card which has been tested in my 486 before where it boots successful. CHS is set manually to C=1014, H=16 and S=63 as in my 486.

Now my problem:
The display shows "Starting MS-DOS..." followed by some more Interrupt-calls like INT15, INT14, INT17, INT12, some more Int13 (it loads more sectors) and INT1A.

Finally the system calls and stopps at INT15, where register AH is set by DOS to 0x41 and AL to 0x01. I responds to this with AX=0x8600 and I'm setting the flag-Register.

Well... And thats it. I'm right before loading the shell but I'm a bit lost. Only one single time I managed that the system calls two more INT1A, but I couldn't reproduce it.

Maybe there are some expert here, who can give me a hint, or have fun tinkering with this as well. Maybe it is an issue with the compiler (I'm using i686 gcc with Option -m16) or a problem with my memory-map.

If you have time, here is my repository on GitHub:
https://github.com/xn--nding-jua/DDX3216/tree/main/BIOS

Important thing: I started this project only three weeks ago just because of my curiosity. I already looked into Seabios, but they went different ways on implementing things...

So I'm looking forward for some ideas. Thank you 😀

Best regards
Chris

Reply 1 of 12, by rasz_pl

User metadata
Rank l33t
Rank
l33t

Ever since I got nerd sniped by a post about broken Zenith board Iv been playing with Zenith ZBIOS. This led to https://github.com/raszpl/Zenith_ZBIOS/
Recently I tried to understand more of the disk subsystem (something really weird about Zenith doing IO on ports in 333 range despite initial bios disk detection/verification happening thru standard 1F0h) and found https://github.com/640-KB/GLaDISK/ which pointed at https://github.com/640-KB/GLaBIOS
Maybe comparing what you are doing to https://github.com/640-KB/GLaBIOS (or maybe even my Zenith_ZBIOS dissasembly) will give you some hints.
edit: ignoring the hdd routines as neither GLaBIOS nor GLaDISK handle harddrives.

Quick glance and I already see interesting tidbits, like you arent using standard INT41 Disk Parameter Table format and rolled your own instead, understandable seeing you will only ever use CFs oevr pcmcia adapter 😀

https://github.com/raszpl/sigrok-disk FM/MFM/RLL decoder
https://github.com/raszpl/FIC-486-GAC-2-Cache-Module (AT&T Globalyst)
https://github.com/raszpl/386RC-16 ram board
https://github.com/raszpl/Zenith_ZBIOS Zenith Z-386 MFM-300 ZBIOS disassembly

Reply 2 of 12, by Chrisnoeding

User metadata
Rank Newbie
Rank
Newbie

Hi rasz_pl,
thanks for the two repositories. I will have a look at these.

You spotted the disk parameter table: I had a bug within this table, but fixing this didn't help. DOS still hangs on INT15.

It seems that it has some problems loading a single sector to 0x9B80 which is right below my BIOS-RAM-Segment at 0x9C00:

 INT  | AH | AL |  BX  |  CX  |  DX  |  ES
============================================
INT1A |
INT1A |
INT13 | 08 | 00 | 06F4 | 0000 | 0480 | 0070 <- get drive parameters for first harddisk (DL = 0x80)
INT13 | 08 | 00 | 0000 | 0000 | 0000 | 0000 <- get drive parameters for floppy (DL = 0x00)
INT13 | 15 | 00 | 0000 | 0000 | 0000 | 0000 <- get disk type of floppy (DL = 0x00)
INT13 | 08 | 09 | 0002 | 001F | 0080 | 0000 <- get drive parameters for first harddisk (DL = 0x80)

INT13 | 02 | 01 | 0200 | 0001 | 0080 | 9B80 <- here it tries to load another sector to 0x9B80
INT13 | 02 | 01 | 014E | 0001 | 0180 | 0070 <- load sector to 0x0070, offset 0x014E (somewhere in the conventional memory area)

INT13 | 08 | 81 | 0002 | 0010 | 0180 | 0000 <- get drive parameters for first harddisk (DL = 0x80)
INT13 | 02 | 01 | 0200 | 0001 | 0080 | 9B80 <- here it tries again

INT13 | 08 | 01 | 0103 | 0001 | 0180 | 0000 <- get drive parameters for first harddisk (DL = 0x80)
INT13 | 02 | 01 | 0200 | 0001 | 0080 | 9B80 <- and here the last time

INT15 | 41 | 01

Maybe this is a breadcrumb. DOS retries three times to load a sector. Obviously it tries to get information about the disk three times and try to reload the sector until it stops... strange.

Reply 3 of 12, by Chrisnoeding

User metadata
Rank Newbie
Rank
Newbie

Maybe one last addition to my last post: the bootsector is loading the first sector of DOS successfully into the RAM at segment 0x0070 with this interrupt-call:

INT13 | 02 | 01 | 014E | 0001 | 0180 | 0070

I checked the content of the RAM and I can see the ASCII-string "MSDOS5.0" at this segment 0x0070 and offset 0x014E + 3 Bytes...

I also checked the magic byte in segment 0x9B80 and offset 0x0200 + 510 bytes. Here I can see the 0xAA55. So I don't get it why DOS is retrying it three times and then fails...

Reply 4 of 12, by rasz_pl

User metadata
Rank l33t
Rank
l33t

I finally looked at details in your original post. "Starting MS-DOS..." so its loading DOS MBR just fine, but afaik INT15 ah=41 is not a normal interrupt any DOS should be calling. Are you sure you arent trying to run dedicated Compaq Convertible DOS version?https://mirror.math.princeton.edu/pub/oldlinu … tml/rb-1355.htm 😀

Confession - I never looked into what DOS does. For example how it knows how much ram is in the system in the first place. Should it call INT12, or does it read BDA 13h directly like a savage? I have tons of questions like that patiently waiting for a time I will finally play with a debugger 😀 btw how do you debug? just printf on tiny LCD? serial? JTAG? some emulator (supposedly Qemu+GDB works well for this)? I would love to use MartyPC for toying around because of its fantastic build-in debugger (https://martypc.blogspot.com/2023/07/emulator … 30-and-vga.html), but tragically its only 16bit 🙁

> 0x9B80 which is right below my BIOS-RAM-Segment at 0x9C00:

9B80,0200 = 0x9BA00? I remember reading MBR relocates itself and loads actual code again to 0x7C00. MBR is tiny so shouldnt be a problem decompiling to see whats going on.
0070, 014E = 0x084E? thats a really weird address, if anything I imagined it would be loading to 0x500

> I had a bug within this table, but fixing this didn't help.

Does it still tries fetching it 2 times when returning proper 16 byte EDPT?

https://github.com/raszpl/sigrok-disk FM/MFM/RLL decoder
https://github.com/raszpl/FIC-486-GAC-2-Cache-Module (AT&T Globalyst)
https://github.com/raszpl/386RC-16 ram board
https://github.com/raszpl/Zenith_ZBIOS Zenith Z-386 MFM-300 ZBIOS disassembly

Reply 5 of 12, by Chrisnoeding

User metadata
Rank Newbie
Rank
Newbie

At the current state I'm beyond loading data to 0x0500, 0x0700,... that's all done before. The INT15/AH=41 seems to be a "I give up" of DOS

The 0x9B80 is at the end of the conventional memory and I can influence this with the amount of RAM I'm telling DOS with INT12. At the moment I'm resrrving 16kB for my BIOS below 0xA0000. So that's the raeson why DOS places itself at 0x9B80.

Well, maybe I overlooked one thing: the BPB on my CF Card has been written on a 486 computer with LBA activated, so it says C=507, H=32 and S=63. On my BIOS I used C=1014, H=16, S=63.
DOS seems to Check the BIOS Settings against its BPB.

Sorrowly I cannot test it yet: since yesterday I'm in a Hospital, but I will give an update here, if this was the problem.

See you,
Chris

Reply 6 of 12, by rasz_pl

User metadata
Rank l33t
Rank
l33t
Chrisnoeding wrote on 2026-06-09, 05:53:

At the current state I'm beyond loading data to 0x0500, 0x0700,... that's all done before.

What do you mean? 0x0500 should be free ram, I didnt see any evidence of MBR trying to load anything there in your list.

Chrisnoeding wrote on 2026-06-09, 05:53:

The INT15/AH=41 seems to be a "I give up" of DOS

I dont think thats normal 😮

Chrisnoeding wrote on 2026-06-09, 05:53:

The 0x9B80 is at the end of the conventional memory

yes of course

Chrisnoeding wrote on 2026-06-09, 05:53:

and I can influence this with the amount of RAM I'm telling DOS with INT12.

your log didnt show any int12 invocations thus me wondering how dos does this, very likely there are versions reading BDA and more civilized versions calling int12

Chrisnoeding wrote on 2026-06-09, 05:53:

Well, maybe I overlooked one thing: the BPB on my CF Card has been written on a 486 computer with LBA activated, so it says C=507, H=32 and S=63. On my BIOS I used C=1014, H=16, S=63.
DOS seems to Check the BIOS Settings against its BPB.

Sounds plausible. I forgot to suggest trying to boot another hdd image made with for example in an emulator as a sanity check.
Btw Zenith ZBios has a tricks up its sleeves allowing one boot even from inactive partition. MFM-300 monitor command

B:		Boot from disk			B [{F|W}][{0|1|2|3}][:<partition>]

triggering special pass on loaded MBR marking selected partition Bootable in ram before executing MBR
https://github.com/raszpl/Zenith_ZBIOS/blob/0 … 03.2C.lst#L7457

Chrisnoeding wrote on 2026-06-09, 05:53:

I'm in a Hospital

hope you get well, health > hobby

PS: another homemade bios for homemade 486 chipset https://github.com/maniekx86/M8SBC-486/tree/main/bios

https://github.com/raszpl/sigrok-disk FM/MFM/RLL decoder
https://github.com/raszpl/FIC-486-GAC-2-Cache-Module (AT&T Globalyst)
https://github.com/raszpl/386RC-16 ram board
https://github.com/raszpl/Zenith_ZBIOS Zenith Z-386 MFM-300 ZBIOS disassembly

Reply 7 of 12, by Chrisnoeding

User metadata
Rank Newbie
Rank
Newbie

Hi,

This log shows only the last couple of Interrupts DOS has called. Before this, lot of other INTs already got called. And there DOS loads more sectors to 0x0500, 0x0700, 0x0900, 0x0B00 and to 0x1A5A (if I remember correctly). The MBR (located at 0x7C00) seems to load IO.SYS and MSDOS.SYS here.

INT12 has been loaded prior to this - I confirmed this by changing the amount of memory on register AX.

By the way: I'm debugging only using the LCD and the UART.

I will have a look at this 486 BIOS as well - thanks for the link. If I see no progress, I will give FreeDOS a try. But for now I have a couple of new things to try out next week. Thank you very much!

Bye

Reply 8 of 12, by Chrisnoeding

User metadata
Rank Newbie
Rank
Newbie

Hi rasz_pl,

thank you so much for your comments, links and ideas. I had a look at the mentioned 486-BIOS and found lot of similarities to my approach. I fixed some smaller bugs regarding the disk-parameter-tables and the interrupt-routines, but MS-DOS still didn't want to cooperate.

Then I tried FreeDOS in version 1.4 and this OS is booting "Straight to SHELL" 😁

The attachment DDX3216_FreeDOS_Shell.jpg is no longer available

The BIOS Bootprocess looks nice as well:

The attachment DDX3216_BIOS_Boot.jpg is no longer available

So maybe I'm checking why MS-DOS is so picky in the future, but for now I have a working solution and I can process with the userspace-programs now.

best regards
Chris

Reply 9 of 12, by rasz_pl

User metadata
Rank l33t
Rank
l33t

👍

edit:
https://github.com/xn--nding-jua/DDX3216/blob … OS/start.s#L156

mov     al, 0b00000100     // Bit4=1

typo during transcription?

https://github.com/raszpl/sigrok-disk FM/MFM/RLL decoder
https://github.com/raszpl/FIC-486-GAC-2-Cache-Module (AT&T Globalyst)
https://github.com/raszpl/386RC-16 ram board
https://github.com/raszpl/Zenith_ZBIOS Zenith Z-386 MFM-300 ZBIOS disassembly

Reply 10 of 12, by Chrisnoeding

User metadata
Rank Newbie
Rank
Newbie

Ah, good catch! I fixed this register according to the Reference Manual now, but did not change anything regarding DOS. In the meantime, I tested a different CF-Card, but DOS is still hanging. Anyway, FreeDOS is working fine and I have lot of things to do now with this system.

If you are interested, I put the story on my blog here: https://chrisdevblog.com/2026/06/08/running-d … -a-diy-x86-bios

bye,
Chris

Reply 11 of 12, by rasz_pl

User metadata
Rank l33t
Rank
l33t

Great writeup.
I have similar attitude towards AI. Good at explaining things I dont know at all/not understand/have a hard time getting right ... as long as I cross reference everything it generates because a LOT of it is garbage/purely made up 😀. Im very apprehensive letting it generate any code, my preferred workflow is writing code myself and asking couple different AI engines to point out all errors & potential bugs. Much faster than letting AI hallucinate bad code and then spending time cleaning it up. Even easy things like generating headers comes out full of errors when unsupervised. Stupid BDA/Cmos/IO enums https://github.com/raszpl/Zenith_ZBIOS/blob/m … ersion%203.2C.h took two AIs correcting each other then me fixing stuff afterwards, probably still has errors. Sure saved time, but uncertainty is not a good feeling.

You are missing one picture under
"Well, after a couple of hours reading the manual and more datasheets of the integrated devices, I was able to upload my ROM-image and successfully received characters at 9600 baud on my connected computer:"
or rather between. You have picture of flashing (onerom is pretty great, havent used PicoROM), but not of receiving data from SC300.

Some more ideas for debugging DOS:
- try different DOS versions, like Dos 3.3
- dump ram over serial. Should be fast enough at 115Kbit. Zero all ram before bootloader and LZ4 compress (super easy compression algo) snapshots when sending over serial to speed it up. Maybe even snapshots all ram below 640KB per every int13 + stack snapshot on every BIOS int. AI will help you walk the stack to see what DOS was doing.

Edit: I hope you dont mind me throwing https://chrisdevblog.com/2026/06/08/running-d … a-diy-x86-bios/ on Hackernews https://news.ycombinator.com/item?id=48520080 Nerds there love this stuff. Only after reading comments I realized I watched your Behringers X32/Ultranet videos 😁 Small world.

https://github.com/raszpl/sigrok-disk FM/MFM/RLL decoder
https://github.com/raszpl/FIC-486-GAC-2-Cache-Module (AT&T Globalyst)
https://github.com/raszpl/386RC-16 ram board
https://github.com/raszpl/Zenith_ZBIOS Zenith Z-386 MFM-300 ZBIOS disassembly

Reply 12 of 12, by Chrisnoeding

User metadata
Rank Newbie
Rank
Newbie

Hi,

Thanks for the nice feedback to the blog-entry - I added the missing pictures and fixed some typos. I appreciate mentioning my blog on Hackernews 😀 It was a pleasure to read the comments.

Yes, the world is small 😁 I'm very interested in several things related to digital devices and audio-mixing. With the OpenX32-project we made some nice progress now. Thats the reason I was curious about the predecessor of the X32 as well.

Good idea with the zlib-compressed memory-content. I will check this. In the meantime I've optimized the CF-card-reading and FreeDOS is booting within seconds now.

bye