VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

Is it smart to simply 'allocate' private memory for a BIOS option ROM by:
- Stealing base memory for a memory area to use
- Hooking an interrupt inside said base memory area, including some extra room for the data storage. The interrupt handler can then give a pointer to the data storage if requested (for example, by the actual interrupt handler in the option ROM).

The data allocation interrupt handler (that's actually at the stolen RAM block) can then be used by the option ROM to store:
- The hooked interrupt handler (so it can perform the original interrupt if the request isn't meant for itself).
- Extra data required by the option ROM to store.

For example, inside my IBM XT RTC option ROM (which provides interrupt 1Ah timing services on a XT with the 'XT RTC' installed, for example on the Samtron 88S, which my BIOS ROM implements for an XT machine) it uses this method to hook interrupt 1Ah (the actual time interrupt, handling the RTC functions) and interrupt 19h (bootstrap itself) and interrupt 15h (for it's data storage).
The INT15h function call used to return the data block's AX=FE00h. It just returns the address of the data block into DS:BX, clears the returned carry flag and swaps AH/AL to identify itself (AH=00h, AL=FEh). Although it hard-codes the BX addresss in the locations using it instead (as it can be guaranteed enough space for it).
The hooked interrupt handlers simply use the single flag (to enable it's functionality and POST properly) and the various INT1A/19/15h interrupt vectors stored inside of it. The INT15h handler is actually a direct copy of the one stored in the ROM, which is copied there to perform it's function (so it's executing from RAM).

The BIOS ROM using this method:
https://bitbucket.org/superfury/unipcemu_pcxtbios_at/

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 1 of 2, by mkarcher

User metadata
Rank l33t
Rank
l33t

Stealing base memory is the only officially supported method to allocate memory from an option ROM, so this is clearly "smart". You also already observed the issue you need to solve as well: You need to know the address at which your option ROM allocated its space, because when your option ROM is called at runtime, another ROM might have stolen additional memory, so the "end of memory" no longer points to your data area. Also, some option ROMs (or the mainboard BIOS) might have stolen memory before your option ROM was initialized, so you can't hardcode something like 9FFF, 9FF0 or 9FC0 as base address (and as you are talking about XTs, maybe that machine doesn't even have 640K). There are multiple ways to deal with the issue. The easiest scenario is that you just need memory for parameter tables (like the hard drive geometries) that are pointed to by some interrupt vector anyway (Int 41 and Int 46 in case of the hard drive parameters), and a similar approach can be taken if you just want to hook the EGA/VGA BIOS structures pointed to by the "save table pointer" inside the BIOS data area.

In your case, the simple approach does not work. You also shouldn't rely on some unused interrupt vector to be able to store your data segment (and you don't, which is good). Your INT 15 approach is a bit of a hack, though. As you are going to hook INT 1A anyway, why not put some INT 1A stuff into your main memory instead of INT 15 stuff? And while you are at it, your INT 1A code in RAM can then perform a FAR CALL into your INT 1A implementation in ROM, possibly alread loading DS. This approach would require you to patch your ROM base address into the RAM stub, but this is straightforward to achieve.

Reply 2 of 2, by superfury

User metadata
Rank l33t++
Rank
l33t++

Actually, INT15 and INT19 are hooked first, the old addresses stored into INT15, then once the INT19 hook is fired (POST starts booting), INT1A is hooked and stored as well, and INT19 hooking is put in permanently pass-through mode (as a one-shot using a flag) and the system time is updated (using the legacy time function in the hooked BIOS) with the retrieved RTC time using the new INT1A functionality, using the original BIOS to update the timestamp in the BDA using the function <02h of the original INT1A (don't remember which exactly, the set one at least).
My BIOS just handles the get/set RTC calls and translates them to/from the RTC chip (and the above initialization).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io