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. 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?
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.
Best regards, Jaeyong
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.
vgasrc/vgaentry.S:
_rom_header_entry: jmp _optionrom_entry [...] _optionrom_entry: ENTRY_ARG_VGA vga_post [...]
src/optionroms.c:
// Execute a given option rom at the standard entry vector. void 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); start_preempt(); farcall16big(&br); finish_preempt(); }
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().
init_pcirom() lookup_hardcode() || map_pcirom() init_optionrom() callrom() ...
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.
Laszlo
On Wed, May 14, 2014 at 11:27:16AM +0000, Jaeyong Yoo wrote:
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. 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?
The vga bios is separate from the main bios. They are separate binaries and are placed in separate areas of memory. The main bios code is in the SeaBIOS src/ directory, while the vga bios code is (mainly) in the vgasrc/ directory.
QEMU places the vgabios in a PCI rom, and SeaBIOS copies it to memory (almost always 0xc0000).
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.
There is some info on using gdb with qemu in the SeaBIOS README file. To use it with SeaVGABIOS, replace "gdb out/rom16.o" with "gdb out/vgarom.o" and instead of adding 0xf0000 to your break points, add 0xc0000.
Also, I find this command quite useful for inspecting the vga bios assembler, and finding break points:
objdump -m i386 -M i8086 -M suffix -ldr out/vgarom.o | less
-Kevin