2

I've been writing a somewhat basic bootloader and it works like a peach in bochs. However, on my actual machine, a few instructions get scrambled and the bootloader fails. I've diagnosed the disease but don't have a good cure. It seems that the BIOS (UEFI in compatibility mode, by the way) is looking for a Bios Parameter Block (BPB), cannot find one (because I didn't make one), and outrageously overwrites certain bytes, thereby messing up the bootloader. My current way to fix it is to start my assembly off by reserving (zeroing) the first 50 bytes of my program with

resb 50

This is not a good solution, however. It's a huge waste of space, considering a bootloader is only 512 bytes. That's about 10% of space wasted! So here's my question:

Is there a better way to circumvent/stop/disable the bios from overwriting parts of the bootloader? What's the best way to get the most bytes out of my bootloader?

travisjayday
  • 784
  • 6
  • 16
  • You need to create a BPB at the beginning of your bootloader so that the BIOS doesn't over write your code. As wlel some BIOSes will refuse to load a bootloader if it doesn't find certain specific instructions at the beginning of a bootloader (A JMP is usually the best bet). Some BIOSes may even try to determine if there is a valid BPB by checking the contents and some BIOSes just over write blindly. – Michael Petch Aug 17 '17 at 15:02
  • The above is assuming that you are using USB Floppy emulation. If using USB HDD emulation you may find you don't need the BPB but you may require a valid partition table with a partition marked as bootable for it to be recognized. – Michael Petch Aug 17 '17 at 15:11
  • 1
    A DOS 4.0 BPB can be found in this [SO Answer](https://stackoverflow.com/a/43787939/3857942) (written in NASM) in the code under the section _Complete Example with Int 13h Extension Checks_ . The example creates a fake 1.44MB Floppy BPB. The _BPB_ includes the JMP. So everything from the `boot:` label to the `main` lable is the BPB – Michael Petch Aug 17 '17 at 15:15
  • Thanks Michael for the example. So I suppose I'll have to write a BPB if I want my BIOS to cooperate. Oh well, I wanted to avoid that but it seems I have no other option. – travisjayday Aug 17 '17 at 15:15
  • You can't avoid it. This is something hat is well known and people writing boot sectors have to accept on modern hardware especially USB bootable devices. A person can write a lot in 450 or so odd bytes which is way more than enough to bootstrap the second stage of a bootloader. – Michael Petch Aug 17 '17 at 15:18
  • I'm actually writing a basic game and I'm hoping I can fit it all in the first sector without any extra bootstrapping and what not. but if it gets too big I'll learn more about bootstrapping and set up the program differently – travisjayday Aug 17 '17 at 15:21
  • If you don't care about real file systems you can simply write a bootloader in the first sector that reads the next sectors from the disk containing your game and then jump to it. BIOS interrupt Int 13h/ah=2 can read sectors from a disk: http://www.ctyme.com/intr/rb-0607.htm – Michael Petch Aug 17 '17 at 15:27
  • A BIOS should only modify the BPB if it detects an BPB and it should only detect a BPB if the boot sector starts with a JMP instruction. If the BIOS is unconditionally modifying the BPB, even if there isn't a JMP instruction, then having a `RESB 50` directive at the start won't solve the problem. Those reserved bytes will still be modified and cause unpredictable behaviour when executed. You might want to double check whether the BIOS is actually unconditionally modifying your bootsector or if you have some other problem with your code. – Ross Ridge Aug 17 '17 at 15:44
  • @RossRidge : I can tell you that many BIOSes these days will arbitrarily over write the BPB area even if there isn't even a JMP at the start (generally this applies to USB Floppy emulation). I have a Lenovo laptop from 2012 that exhibits this very behavior. It is also a behavior that has manifested itself in many SO question over the past couple years with the same issue. Some BIOSes will look for a JMP and assume the lack of one as non bootable media and won't do anything. It seems though assuming there is a BPB all the time is a path of least resistance for firmware/BIOS developers. – Michael Petch Aug 17 '17 at 15:50
  • 1
    You might have a look at https://stackoverflow.com/questions/42141662/how-does-the-bios-know-what-type-of-bpb-is-present/42144059#42144059 – David Hoelzer Aug 17 '17 at 16:27
  • Your comments have been insightful. I'm thinking about asking a separate question but maybe you can push me in the right direction real quick. How can you dynamically allocate memory (for a buffer) in an assembly bootloader? The BIOS doesn't seem to have a service for that, and I need to allocate an offscreen buffer for double buffering purposes. Is there a way to implement a C-style malloc routine? – travisjayday Aug 17 '17 at 16:29
  • Just pick a memory area you aren't using that lies between physical address 0x00520 and about 0x9C000. There is no BIOS malloc routine. You can manage memory the way you want. But I recommend explicitly setting the stack (SS:SP) somewhere you know won't be overwritten by your own code. – Michael Petch Aug 17 '17 at 16:32
  • Wow, thanks! It's weird, I couldn't find anything on that. Do you have a source for that memory range by any chance? – travisjayday Aug 17 '17 at 16:38
  • 1
    Not really a source, but the Interrupt vector table runs between 0x00000 and 0x00400. Between 0x00400 and 0x00500 is the [BIOS Data Area](http://stanislavs.org/helppc/bios_data_area.html). That link lays out lower memory. On original IBM systems the area between 0x00500 and 0x00520 was also used. That is why I usually don't put code below 0x00520. As for 0x9C000 this was a simplification. 0xA0000 is usually [graphics video memory](http://flint.cs.yale.edu/feng/cos/resources/BIOS/mem.htm) so you want to use anything less than that. – Michael Petch Aug 17 '17 at 17:01
  • 1
    You may ask why I didn't say 0x00520 to 0xA0000. This was a simplification of sorts. Just below 0xA0000 is the Extended BIOS Data Area (EBDA) on many computers. Often it is just 1k but on the rare occasion over the years it has been as much as 8 to 16k. On the safe side I reduced 0xA0000 to 0x9C000 to account for a possible 16kb EBDA. Unless you are on a buggy computer the size of the area can be queried. Was just easier to save the hassle and make it easier on you by using 0x9C000. This of course assumes you ar eon a machine with at least 640kb of conventional RAM. – Michael Petch Aug 17 '17 at 17:03

1 Answers1

-3

Try to use the linear framebuffer and modify the display start address for buffering. public document: vbe3.pdf from vesa dot org (register/login)

  • What does the linear frame buffer have to do with bootloader and what the BIOS does to the BPB in the memory address range of 0x07c00 to 0x07e00? – Michael Petch Aug 17 '17 at 17:48
  • @Dirk hmm, I don't know. I'm already using the linear VGA display mode, and I'm going to use a second buffer in memory instead of switching addresses (I'm not sure if it's possible with regular VGA and not VESA). And Michael's right, this doesn't have much to do with the original question – travisjayday Aug 17 '17 at 17:53