Isn't 07C0:0000, the same physical address on x86 machines as 0000:7C00?
Asked Answered
D

1

6

Reason for my question is that Starman seems to believe the GRUB Legacy author's explanation (see for the following inexplicable code:

7C4B EA507C0000    JMP     0000:7C50  ; Long Jump to the next instruction
                                      ; because some bogus BIOSes jump to
                                      ; 07C0:0000 instead of 0000:7C00.

When I perform the Intel-specified algorithm for constructing effective addresses on the first memory reference, I multiply 07C0: by 16 (effectively left shifting it four bits or one half-byte). Then I add the offset of :0000 and get the decimal address 31,744.

If I left shift the segment of the second memory reference four bits I still have 0000: and the offset of :7C00 still addresses the location 31,744. So my gut reaction is the author of this GRUB Legacy boot sector code is pulling our leg. Regardless of the form of the memory reference made by any BIOS, if the effective address calculates to decimal 31,744, then it seems there is no problem that this Long Jump is solving.

On the assumption that the code's author merely expressed a bogus physical memory location in a way which seems to be the same physical location as was correct, I started to think about how one would deal with a BIOS that sent one to the wrong address. The five byte Long Jump does not appear to be the solution to anything. Five NOPs would serve the same purpose (in fact, simply beginning the boot sector code five bytes earlier and eliminating the Long Jump would have the same effect as a Long Jump to the next instruction).

If the BIOS jumps to the correct location (7C00), no problem. If the BIOS jumps to a location above 7C00, then no code loaded at 7C00 can fix that problem. If the BIOS jumps to a location between 7C00 and 7C4B, then data stored in that area (or instuctions being interpreted with bytes missing from them) will likely cause a crash. Should the BIOS jump to exactly 7C4B, the TEST instruction will have been over-written (by the Long Jump) and the JNZ to 7C54 will be executed based on the last math performed in the BIOS.

For BIOS jumps below 7C4B, again mis-aligned instructions are likely to cause a crash. With good luck, some portion of the boot sector code will be executed. The results of such execution will depend on exactly what "bogus" memory address the BIOS does jump to. So is the author of this boot sector code pulling our leg with a story about "bogus BIOS's that jump to the wrong location"?

I note in Luke Luo's BLOG, that the GRUB2 boot sector, although different from the GRUB Legacy boot sector, retains this inexplicable Long Jump. So if the original author of the GRUB Legacy boot sector was playing a joke on us, it's a pretty successful joke (it has survived a complete re-write of GRUB). I'm left with the choice of believing an incredible assertion about some un-named BIOS and a solution to such a problem that seems to actually do nothing or believing that the author of the original boot sector was playing a joke on us.

Luke Luo seems to accept the writing of NOP instructions to 7C66 and 7C67, as evidence that he does not have a BIOS that jumps to the wrong location. The GRUB2 boot sector that was written to my Flash Drive by Linux Mint 13, has these same NOPs. However the GRUB2 boot sector written to my laptop's hard drive (by Debian Etch) has a short jump to the next instruction written at 7C66 and 7C67 (note that Luke Luo shows us that the original boot sector stored at /usr/lib/grub/i386-pc/boot.img has the Debian value). Both alternatives have the same effect (execute the instruction that follows them), so both boot sectors work. Neither has the efficiency I would expect in a boot sector where there are only about 450 bytes available for code that must load another sector and execute it (including error messages for when something goes wrong with that simple operation and the eight-byte address of the sector itself).

So am I missing something, or have I identified a kludge that should be eliminated from the GRUB boot sector (to make room for more meaningful code)?

Desmund answered 4/1, 2017 at 17:0 Comment(5)
Some time ago I wrote a Stackoverflow Q&A about a situation where not having that far jump can yield the wrong results in a bootloader. It really depends on how the bootloader code is written. Some bootloader developers out of an abundance of caution add the FAR JMP to explicitly set CS to the value they want so that they don't run into problems, but it may not be necessary if their code never relies on a particular value in CSAldehyde
Think "abundance of caution" covers it. Without further identification of the BIOS with this problem one cannot even verify that it still exists. In the days when we had no choice but to get our BIOS with our hardware, this would be the solution to a BIOS vendor that does not know how to code. Today I would hope the solution would be to replace the BIOS.Desmund
When did the situation change that the BIOS did not come with the hardware? Every motherboard I've bought in the last several years has come with a built-in BIOS. And even with virtual machines, the VM vendor still writes the BIOS implementation.Toting
Not suggesting that hardware (or virtual machines) comes without BIOS. Only that if a BIOS has a significant malfunction, one does not need to hope for the vendor to correct it, in today's market. One could transition to Open Firmware. Perhaps it's unfair to regard this behavior as a malfunction (more of a pecadillo - if one accepts the premise that upon boot one is entitled to assume that one is at address 7C00, that DL contains the boot drive and that NO OTHER REGISTER IS NECESSARILY INITIALIZED). Would be interesting to examine the code of the "bogus" BIOS, to see why CS was not set.Desmund
I wouldn't say the BIOS has a significant malfunction. The lack of a BIOS standard doc through the 80s IMHO lead to ambiguities.After about the 90s the rule of thumb for bootloader writers was definitely to not assume any of the registers (including CS) was a specific value. It didn't help that in 1995 Phoenix and IBM put out a the eltorito spec that suggested 0x07c0 was the traditional segment (not 0x0000) so often you'll see older BIOSes boot CD-ROM and jump to 0x07c0:0x0000 . On the same system you may find floppy boots and the JMP is to 0x0000:0x7c00. Some versions of BOCHS do this too.Aldehyde
M
7

You are missing the difference in actual state of CPU (while the physical address is the same one, that's correct).

When BIOS does JMP 0000:7C00:

your first instruction is located at cs=0000, ip=7C00, and your machine code has to be compiled for this kind of relocation, whenever it does any absolute addressing, like for example mov ax,cs:[myTable] (then myTable can be something like 0x7F00).

When BIOS does JMP 07C0:0000:

your first instruction is located at cs=07C0, ip=0000, so things like myTable will be more like 0x0300.

Thus the first long jump at the beginning of code will "normalize" the same physical address 31,744 into expected cs:ip form, making the rest of absolute addresses in the bootloader code work correctly.

Mispronounce answered 4/1, 2017 at 17:8 Comment(5)
That's what I thought, but I didn't find any segment override prefix in the assembly code. The next instructions initialize DS to [0000]. Did you spot where in the code it makes a difference ? Maybe is it just a left over of previous code...Precessional
@Precessional I didn't check particular source, as even if the particular bootloader will operate only with ds: and relative jumps, it's still a bit "toxic" trap for anyone in future who will try to modify it. So I would still recommend this practice even for code which doesn't rely on cs value.Mispronounce
@Precessional and now I did take a look, and didn't find any problem. So it looks as the jump is really only precaution in this case (I took only quick ~5min look, no serious code review). Then again I'm not sure if additional 5B are worth of any risk. In some special case surely yes, but generally probably not.Mispronounce
@Precessional It's necessary for the JMP [7C42] instruction in your first link's disassembly of the boot sector to work. This a near indirect jump, so it only changes IP and not CS. The offset at DS:7C42 is 8000, so if CS was 07C0 instead of 0000, the code would jump to 07C0:8000 instead of the intended 0000:8000 It would have been trivially possible to design the boot sector so this wouldn't be necessary, but it looks like there's a lot that could be improved.Brutalize
@RossRidge thank you, for this educating comment :) It is the missing piece to make this answer complete.Precessional

© 2022 - 2024 — McMap. All rights reserved.