[SeaBIOS] Question about the relationship between bios.bin and vgabios.bin

Laszlo Ersek lersek at redhat.com
Wed May 14 14:19:12 CEST 2014

On 05/14/14 13:27, Jaeyong Yoo wrote:
> Hello Seabios!
> I started the thread from qemu-list and Laszlo suggested me to post the question here.
> In Seabios, the call-path of calling vgarom entry point is the following:
> handle_post() [src/post.c]
>   make_bios_writable() [src/fw/shadow.c]
>     make_bios_writable_intel()
>       __make_bios_writable_intel() -- shadows vgabios in C segment too
>   dopost() [src/post.c]
>     maininit()
>       vgarom_setup() [src/optionroms.c]
>         init_pcirom()
>           init_optionrom()
>             callrom()
>               __callrom()
>                 _rom_header_entry [vgasrc/vgaentry.S]
>                   vga_post() [vgasrc/vgainit.c]
> For me, it looks like seabios (bios.bin) calls a function, vga_post, that is supposed be
> in vgabios.bin. It makes me thinking that vgabios.bin is somehow embedded in bios.bin.

No, vgabios is a separate binary, formatted as a PCI option
("expansion") ROM. It starts with a special structure -- there's an
entry point field in it, which happens to contain a jump instruction.
Please check the functions and files that I listed in the above call tree.


          jmp _optionrom_entry
          ENTRY_ARG_VGA vga_post


  // Execute a given option rom at the standard entry vector.
  callrom(struct rom_header *rom, u16 bdf)
      __callrom(rom, OPTION_ROM_INITVECTOR, bdf);

  // Execute a given option rom.
  static void
  __callrom(struct rom_header *rom, u16 offset, u16 bdf)
      u16 seg = FLATPTR_TO_SEG(rom);
      dprintf(1, "Running option rom at %04x:%04x\n", seg, offset);

      struct bregs br;
      memset(&br, 0, sizeof(br));
      br.flags = F_IF;
      br.ax = bdf;
      br.bx = 0xffff;
      br.dx = 0xffff;
      br.es = SEG_BIOS;
      br.di = get_pnp_offset();
      br.code = SEGOFF(seg, offset);

The macro OPTION_ROM_INITVECTOR, passed as "offset" to __callrom,
matches the label "_rom_header_entry" in "vgasrc/vgaentry.S". In more
concrete terms, it is offset 3.

Basically, if you know where a well-formed option ROM is located in
memory, then you post it by simply jumping to its entry point (after
setting up some registers etc). The entry point to jump to is simply
offset 3 of the ROM. So, in:

>             callrom()
>               __callrom()
>                 _rom_header_entry [vgasrc/vgaentry.S]
>                   vga_post() [vgasrc/vgainit.c]

the __callrom()-->_rom_header_entry "call" does not happen by name. It
happens "blindly" in a sense, as if through a function pointer in C. I
omitted the farcall16big() function from the call chain (which actually
implements the jump) because it was not relevant for your purposes.

> But, in my case I use both bios.bin and vgabios.bin to booting up my guest OS (I'm using qemu).
> Apparently, I'm not clearly understanding the difference between vgabios inside bios.bin
> and vgabios-stdvga.bin. Could you tell me the difference?

vgabios is not "inside" bios.bin. It is not built into it. "bios.bin" is
loaded by qemu, placed at a special address, and executed.

"vgabios.bin", which is a separate output file of the SeaBIOS build
process, is also loaded by qemu, and presented as the PCI option ROM of
the VGA card. SeaBIOS first copies it below 1MB in RAM, and then posts
it. The copying ("mapping") happens in init_pcirom().

          lookup_hardcode() || map_pcirom()

> And, I'm trying to debug a vgabios.bin by examining with qemu+gdb. Especially, I'm trying to
> set the break-point to the entry point of vgabios.bin and I'm not quite sure how to do this
> since I don't know the address where vgabios.bin is loaded. I would appreciate if you give me
> some hint about this.

I have no clue if you can debug real mode code and/or set a breakpoint
on it, but the vgabios entry point (see "_rom_header_entry") should be
at C000:0003.


More information about the SeaBIOS mailing list