6

I am trying to learn operating system by diving into the low-level details of it. And the course I'm now on is MIT 6.828 Operating System Engineering. The lab asks students to trace into the BIOS for a few instructions. The first three assembly instructions of BIOS list as folllows:

0xffff0:    ljmp    $0xf000,$0xe05b
0xfe05b:    cmpl    $0x0,%cs:0x6c48
0xfe062:    jne     0xfd2e1

What I can't figure out is the second one: cmpl $0x0,%cs:0x6c48 . What does it do? Why need this condition before jmp to a specific place? I have searched on the web for a while, but still can't find an explanation. And what's trickier is that I find different people get different addresses to compare to, like 0x6ac8, 0x65a4 or 0x6c48 here.

Bicheng
  • 687
  • 8
  • 20
  • 3
    I suppose that's an implementation detail of your BIOS. It likely checks if this is a normal reset or a reset that is part of the BIOS initialisation routine, allowing the BIOS to get back to where it was before the reset. Since each BIOS does this in its own way, the address is going to be different on each BIOS. – fuz Dec 25 '19 at 14:31

1 Answers1

8

What exactly that comparison does will depend on the BIOS manufacturer, but it is clearly some flag for POST (Power on Self Test) processing. Some BIOSes may have completely different code that doesn't look anything like those instructions. Since you are using QEMU, the default BIOS being used is SeaBIOS. That cmpl is to determine if a reboot or a resume is being done:

As noted above, on emulators SeaBIOS handles the 0xFFFF0000:FFF0 machine startup execution vector. This vector is also called on machine faults and on some machine "resume" events. It can also be called (as 0xF0000:FFF0) by software as a request to reboot the machine (on emulators, coreboot, and CSM).

The SeaBIOS "resume and reboot" code handles these calls and attempts to determine the desired action of the caller. Code flow starts in 16bit mode in romlayout.S:reset_vector() which calls romlayout.S:entry_post() which calls romlayout.S:entry_resume() which calls resume.c:handle_resume(). Depending on the request the handle_resume() code may transition to 32bit mode.

You can look at the source code for the SeaBIOS for the entry_post code which is where the jmp $0xf000,$0xe05b takes you: .

        ORG 0xe05b
entry_post:
        cmpl $0, %cs:HaveRunPost                // Check for resume/reboot
        jnz entry_resume
        ENTRY_INTO32 _cfunc32flat_handle_post   // Normal entry point

If the 32-bit value at %cs:HaveRunPost is not zero then it is a resume operation, otherwise it is a reboot operation. The address of HaveRunPost or any internal BIOS variables may differ between one version of a SeaBIOS to another. This may because of changes to code between versions; compiler/compiler options used to build the ROM; BIOS features chosen etc.

Community
  • 1
  • 1
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • 2
    Now the question is how is this value is supposed to change, given that it's located in ROM. – Ross Ridge Dec 25 '19 at 18:39
  • 3
    @RossRidge : SeaBIOS temporarily makes the shadowed memory from 0xf0000 to 0x100000 writeable by changing the PAM settings through PCI configuration space (on intel) which allows modification of the HaveRunPost memory location. SeaBIOS's `make_bios_writable` function is used for that purpose as part of its shadow memory functionality. – Michael Petch Dec 25 '19 at 19:30
  • @MichaelPetch Thanks for your answer! But is this description right? "If the 32-bit value at %cs:HaveRunPost is not zero then it is a resume operation, otherwise it is a reboot operation." I mean, should the cases be classified into "resume/reboot" and "normal start" rather than "resume" and "reboot"? – Bicheng Dec 26 '19 at 04:53