19

If there is some piece of PC compatible hardware where there are no (publicly) existing drivers for Linux, the only option is to access the disk with BIOS calls. I'm aware that this imposes restrictions on the maximum size of disk and/or partition to be used.

Has some old Linux Kernel featured such a driver? Searching online yields a lot of irrelevant hits about more modern systems and their particular booting challenges.

My goal is to be able to run Linux from the emulated disk on an old AS/400 IPCS card. OS drivers are available only for Windows NT 4 and 2k.

5
  • 3
    The issue is PC / PC compatible BIOS disk calls are real mode only so past something like GRUB in the early / pre-boot process they wouldn't be used by Linux.
    – Brian
    Commented Oct 2, 2020 at 17:10
  • 1
    The kernel cannot, actually; vesafb only calls the video BIOS once at boot, before the kernel is properly started (mode-switching is impossible afterwards), while uvesafb delegates BIOS calls to userspace. Commented Oct 2, 2020 at 17:39
  • Some calls can be done using something like ibx86 but mainly it was done for mode setting for displays as that wasn't standardized in hardware and varied a lot between different video chips/cards.
    – Brian
    Commented Oct 2, 2020 at 17:42
  • @user3840170 in older systems calling video BIOS actually worked fine; the VESA driver for X did this for a long time, and X had to use it to initialize a second graphics card. IIRC it doesn't work for disk BIOS services, because they need some tables that are only present in real mode.
    – dirkt
    Commented Oct 2, 2020 at 18:16
  • The link you provided suggested it was possible to run Linux on it with a USB floppy... I was also going to suggest looking into whether you could PXE boot is (diskless boot, and then possibly NFS mount if you needed to be able to write stuff) but it doesn't sound like it has a "real" network card to support that (though given it supports Netware, not positive) [Neither of these answer your question, but might be other things to look at for your underlying challenge]
    – Foon
    Commented Oct 2, 2020 at 19:44

2 Answers 2

21

At first, I was convinced that such a driver had never been written. But in fact, there was one; although it was never merged into upstream Linux. Thanks to @Joshua for pointing me to it.

The driver is part of Yggdrasil Linux/GNU/X, a LiveCD widely recognised as the first commercial Linux distribution. The source code for the driver is found for example within the directory /usr/src/linux/drivers/bios/ on the Fall 1994 release of the disc (and remains included in a patch form on the Winter 1997 software compilation CD), along with a driver that delegates CD-ROM accesses to MSCDEX. The README file included with the patch containing the driver makes it very clear how stable the driver was considered:

This driver is still experimental, it has worked for numerous people, but it has failed for others. Use at your own risk. I only recommend this to people who are interested in using it as a boot strap for developing new device drivers or for acessing some bios routines which need only be used rarely such as laptop power down functions.

The mechanism employed is pretty simple: each time the driver needs to perform a BIOS call, it switches into real mode, performs the call, then switches back into protected mode. This has all the drawbacks you would expect: any I/O operation would suspend every other thread of execution, the kernel had to perform extra copies between kernel memory and conventional memory, and if the BIOS invocation went off the rails, it took down the whole system. (Concurrency? SMP? Locking? Memory protection? What are you talking about? Ah, simpler times.)

Given the architecture of the kernel, this was the best one could do. The kernel has never had any facility to invoke 16-bit code from kernel mode during normal operation (after early boot); even the APM driver only ever supported the 32-bit protected-mode entry point. While support for 16-bit protected mode and virtual 8086 mode has been added, it was only ever driven by userspace, i.e. by DOSEMU, Wine and (userspace) VBE video drivers. The closest Linux got to a mechanism to enter virtual 8086 mode from kernel mode is in a patch for the vesafb driver in Linux 2.6.20 that was never merged into the upstream kernel; the patch’s successor, uvesafb, likewise invoked the video BIOS from userspace.

Although the BIOS and MSCDEX drivers were never merged upstream, the block device numbers they used were listed as reserved in the upstream kernel from version 1.3.22 (which was the first to even have a file listing all block device numbers: both the BIOS driver’s and the MSCDEX driver’s numbers are present) until their removal in 2.6.30.

As for “how it worked” in the other sense… the hard disk driver works surprisingly well, actually: no mysterious “tables” seem to be missing. I did some light testing in 86Box: after choosing a period-appropriate configuration, booting the system from an included LILO floppy image and activating the driver with bios_hd=1, it would access the raw disk, partitions and file systems just fine.

As for the MSCDEX CD driver, trying that one was… less successful. This is what I got when I booted into MS-DOS 6.22 in 86Box 3.5, then launched Yggdrasil from the CD with a provided batch file:

MSCDEX CD-Rom Driver Copyright (C) 1994 Yggdrasil Computing, Inc.
MSCDEX CD-Rom Driver found 1 Drive
drive letter found: D
— [irrelevant kernel logs cut] —
MSCDEX error: AX=0x15
MSCDEX: Invalid Drive or other error
MSCDEX: Checking drive D
MSCDEX Drive Status: 0x00000000 return status: 0x8102
MSCDEX Reset: status: 0x8102
MSCDEX error: AX=0x15
MSCDEX: Invalid Drive or other error
MSCDEX: Checking drive D
MSCDEX Drive Status: 0x00000000 return status: 0x8102
MSCDEX Reset: status: 0x8102
MSCDEX error: AX=0x15
MSCDEX: Invalid Drive or other error
MSCDEX: Checking drive D
MSCDEX Drive Status: 0x00000000 return status: 0x8102
MSCDEX Reset: status: 0x8102

And it just went on like that. And this was the only configuration where booting into Linux didn’t outright crash the emulated machine; I have not investigated if the emulator is to blame for this. Still, it was better than PCem, where it crashed the emulator itself. QEMU didn’t do better: it hung even earlier, while testing the hlt opcode.


If you want to run a more modern kernel, your best bet may be to write a driver for this device yourself: either via reverse-engineering or by creating a virtual 8086 mode monitor/emulator to run the BIOS-based driver in, like userspace VBE drivers do. (You may even attempt to port the Yggdrasil driver to modern kernels, but by no means will it be trivial, if possible at all: kernel APIs have changed significantly in the meantime.) In the general case, I expect the latter approach to be very fragile, as the ROM BIOS code may assume that it has the entirety of the hardware at its disposal, make all sorts of assumptions about its state, and attempt to perform operations that are difficult to emulate, especially from userspace code. In particular it may try to:

  • raise a System Management Interrupt (the BIOS on a laptop I am writing this on does that),
  • turn off interrupts to guarantee atomicity,
  • reconfigure the Programmable Interrupt Controller and other hardware,
  • perform DMA transfers,

And many other things. Most of these considerations usually do not apply to video BIOSes, as those usually confine themselves to operating on the video hardware itself. As such, they only require access to I/O ports and memory, and those are rather easy to provide.

Also note that the BIOS interrupt calls were not designed to be reentrant or execute under the supervision of a multitasking operating system (they were designed as drivers for DOS, after all). Given that, environments which do provide BIOS-based disk drivers are either single-tasking systems like DOS anyway or take some pains to ensure that BIOS calls have exclusive access to all the hardware (including the CPU) and do not interfere with anything else:

All of the above told, things are not hopeless: if you stick to a narrow goal of writing a driver that works with a specific BIOS whose behaviour is known so that you can apply workarounds specific to your firmware (as opposed to creating a fully general solution), there is a good chance it might actually work quite reliably. Especially if the BIOS comes from an option ROM on an extension card, as those are much less free to assume things about other hardware that may be present.

10
  • 2
    That’s a userspace driver, using the vm86 syscall; its existence doesn’t refute what I said. Video drivers can get away with executing BIOS calls from userspace, because the video BIOS tends to be relatively isolated from the rest of the firmware (e.g. the SMM handler); running it doesn’t require full ring 0 privileges, just I/O port access. I don’t understand why you downvoted a correct answer: a BIOS-based disk driver has never existed and for the reasons I listed, it’s not going to be trivial to write one. Commented Oct 3, 2020 at 17:46
  • 2
    The ‘kernel could equally well get away’—but didn’t. Were this so easy, uvesafb wouldn’t need a userspace helper. The kernel ‘could equally well get away’ not throwing away any tables (in fact, nothing in conventional memory is thrown away as far as I can see); it can set up any memory map it wants. The real difficulty is in ensuring the BIOS can access all the hardware it needs without disturbing anything else. And I never just said ‘it cannot be done’: I pointed to specific difficulties that will have to be overcome, which aren’t just ensuring some unspecified ‘tables’ are present. Commented Oct 4, 2020 at 5:35
  • 1
    Thanks @all for all the explanations and lively discussion! I did not expect to attract that much attention with my question. Apparently I was wrong. :-)
    – PoC
    Commented Oct 4, 2020 at 10:06
  • 1
    @dirkt: I'm confused. Why do the tables get thrown away when they survive when booting MS-DOS? The bottom 4KB of RAM is preserved in both cases as is the shave-off region at the top of 640KB should the memory range call say any was shaved off. As for the rest, I've never seen a Linux disk driver that used bios calls, but the old major/minor tables had reserved device ids for such a device. I think the idea was to not emulate it, but transfer back to real mode, call the BIOS interrupt, and transfer back.
    – Joshua
    Commented Dec 12, 2021 at 22:35
  • 1
    Just ran into this video. I can't verify but it looks like somebody actually did implement it, and that's why there was the reservation. youtu.be/Cynd0guSUvM?t=868
    – Joshua
    Commented Jul 21, 2023 at 3:59
7

It's perfectly possible for both userspace and the kernel to access the BIOS. In fact, the kernel offers a vm86 syscall, which is an emulation of real mode.

This syscall was used for a long time in the vesa driver for X (before it got replaced with the vesafb kernel driver; see e.g. here for some code), there are projects like Linux Real-Mode Interface which use it to provide a DPMI-like interface to real mode BIOS, etc.

However, the problem with using the BIOS calls for disk access is that those depend on in-memory tables that are not preserved when Linux boots – in particular because different BIOSes do this differently. Therefore it was much easier and cleaner for Linux to just provide its own drivers for disk access than to try to deal with this mess.

That's why the kernel never featured such a driver.

So for your particular case, you'd need to write the drivers in one way or other. You can either go through the trouble to figure out where how the BIOS of the IPCS stores the tables, or you can figure out how your existing drivers work. Both would presumably have some way to communicate with the AS/400 host to transfer blocks from and to the emulated disk. So reverse engineering is needed anyhow, and then you can write the Linux drivers for it.

This looks like a fun project, but it probably can be quite time consuming.

10
  • Providing in-memory tables is trivial: just mmap /dev/mem. Linux apparently preserves enough conventional memory to make projects like ‘DOS Subsystem for Linux’ actually somewhat viable. Preserving ‘in-memory tables’ is a non-issue. The real problem is keeping the BIOS from stepping on other drivers’ invariants. Commented Oct 4, 2020 at 7:48
  • The other thing is, vesafb cannot do mode switching at runtime, so it didn’t fully replace the X driver: X had to do mode switching (i.e. calling the video BIOS) on its own. The predecessor to uvesafb, vesafb-tng required invasive kernel patching to invoke 16-bit code from a kernel thread; this has never made its way upstream. uvesafb just calls vm86 from a userspace helper daemon. Commented Oct 4, 2020 at 7:50
  • @user3840170 Providing them is trivial, you don't even need /dev/mem for that. Capturing the existing tables at boot is not, because every BIOS does that differently. Which means the standard Linux boot just throws them out. And as your link shows, it's perfectly possible to invoke 16-bit code from a kernel thread. It's just not something you want in the Linux kernel, for architectural reasons. So the answer is not "it can't be done", the answer is "people don't do it because it's too ugly to make it work".
    – dirkt
    Commented Oct 4, 2020 at 10:05
  • @dirkt Reverse-Engineering might be fun but it's clearly far beyond my capabilities, in terms of skill, knowledge, patience, and time. Also, since at leat the #2850 is maxed out with 128 MB of ram, the driver in a current kernel (with a current userland) might be somewhat useless: Committed_as shows as little as 50 MB used in a minimal install, but apt-get update itself will not run with less than 256 MB.
    – PoC
    Commented Oct 4, 2020 at 10:09
  • @PoC Embedded variants of Linux run with a lot less RAM, so you can certainly tweak things. Also, the link you provided mentions that Linux drivers did exists, maybe they (and the Linux version they belonged to) can still be found somewhere?
    – dirkt
    Commented Oct 4, 2020 at 10:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .