SeaBIOS is coming close to exceeding 128K in size. Right now, it's approximately 107K on qemu with default options and 120K with full debugging and all options enabled.
SeaBIOS currently contends with option roms for space. Every byte that SeaBIOS uses is one less byte available for option roms. It's technically possible for SeaBIOS to exceed 128K, but it's likely that we'll start seeing option roms not fitting around that point.
It would also be nice to be able to do malloc_low allocations from the e-segment. This too requires freeing up space that SeaBIOS is currently using to store code.
I've been thinking of a few different ways to free up space. The most promising approach seems to be to relocate all or part of SeaBIOS' 32bit "flat" code. This 32bit code is larger than the segmented code (67K vs 40K) and it's the area that has been growing the most.
To relocate the code, the build can store a list of code that depends on a fixed address and then at runtime SeaBIOS can modify the code with the new address.
Some different permutations of this idea that I've come up with are:
1 - On boot, have SeaBIOS relocate all of it's 32bit code to permanent high ram.
CONS: Reserves memory that then can't be used by the OS (67K today).
CONS: SeaBIOS code is still limited to 256K size (c+d+e+f segments)
2 - Have the build separate out the POST code from other 32bit code (eg, boot & resume) and store the POST code in a separate CBFS/fw_cfg "file". During boot SeaBIOS would extract the separate POST code blob into temporary high ram and run it. Currently, the POST code is the bulk of the 32bit "flat" code (57K vs 10K).
CONS: It adds complexity during deployment as both the main SeaBIOS blob and the CBFS/fw_cfg POST blob would need to be copied.
3 - On boot, relocate only POST code to temporary high ram, and have SeaBIOS reset the machine if the POST code is ever rerun.
CONS: Requires a reliable way of resetting the machine.
CONS: SeaBIOS code is still limited to 256K size (c+d+e+f segments)
Any thoughts? I kinda prefer option 3. Resetting the machine on a rerun of POST would be a good thing to do anyway, as trying to re-post the machine has never really worked well. It does, however, make the build a bit more complex.
-Kevin
1 - On boot, have SeaBIOS relocate all of it's 32bit code to permanent high ram.
I have done some experimental reloc code for Coreboot. I took it from memtest86. Check how to do that. The best would be to simply add diferent base to segs. You have the physmem accessors anyway so maybe way to go here. Check FILO. I think it uses this.
2 - Have the build separate out the POST code from other 32bit code (eg, boot& resume) and store the POST code in a separate CBFS/fw_cfg "file". During boot SeaBIOS would extract the separate POST code blob into temporary high ram and run it. Currently, the POST code is the bulk of the 32bit "flat" code (57K vs 10K).
CONS: It adds complexity during deployment as both the main SeaBIOS blob and the CBFS/fw_cfg POST blob would need to be copied.
And relocation perhaps necessary because during resume you would need to place it in some reserved range.
3 - On boot, relocate only POST code to temporary high ram, and have SeaBIOS reset the machine if the POST code is ever rerun.
CONS: Requires a reliable way of resetting the machine. CONS: SeaBIOS code is still limited to 256K size (c+d+e+f segments)
Any thoughts? I kinda prefer option 3.
Yes looks good to me too (and easiest) How you deal with resume here?
Resetting the machine on a rerun of POST would be a good thing to do anyway, as trying to re-post the machine has never really worked well. It does, however, make the build a bit more complex.
Reseting the machine can be done in various ways:
http://lxr.linux.no/#linux+v2.6.35/arch/x86/kernel/reboot.c
What about other CPUs?
Thanks, Rudolf
On Sat, Aug 21, 2010 at 09:26:30PM +0200, Rudolf Marek wrote:
1 - On boot, have SeaBIOS relocate all of it's 32bit code to permanent high ram.
I have done some experimental reloc code for Coreboot. I took it from memtest86. Check how to do that.
I've looked through that code - I think there is an even simpler way. The linker knows exactly which parts of the code depend on a fixed address. (See: strip --strip-unneeded out/code32flat.o -o foo.o ; objdump -r foo.o ) The build can store this info and then the relocated code can be modified at runtime to live at its new address.
The best would be to simply add diferent base to segs. You have the physmem accessors anyway so maybe way to go here. Check FILO. I think it uses this.
I don't think modifying the segment registers will work well for SeaBIOS. The 32bit code has pointers to both absolute addresses (eg, BDA, interrupt table, malloc addresses) and relative addresses (eg, variables, function pointers). Having to distinguish between the two types in code would be a pain.
2 - Have the build separate out the POST code from other 32bit code (eg, boot& resume) and store the POST code in a separate CBFS/fw_cfg "file". During boot SeaBIOS would extract the separate POST code blob into temporary high ram and run it. Currently, the POST code is the bulk of the 32bit "flat" code (57K vs 10K).
CONS: It adds complexity during deployment as both the main SeaBIOS blob and the CBFS/fw_cfg POST blob would need to be copied.
And relocation perhaps necessary because during resume you would need to place it in some reserved range.
The boot and resume code would not live in the POST blob, so it shouldn't be a problem. (Resume is technically in POST, but the current code checks for resume very early on - I'd keep that the same and only extract the code that is done after the resume checks.) The resume code is really small - the 10K number above includes both boot and resume.
Code relocation would probably still be necessary though, as there isn't really a safe static place to put the POST blob even during a normal boot.
3 - On boot, relocate only POST code to temporary high ram, and have SeaBIOS reset the machine if the POST code is ever rerun.
CONS: Requires a reliable way of resetting the machine. CONS: SeaBIOS code is still limited to 256K size (c+d+e+f segments)
Any thoughts? I kinda prefer option 3.
Yes looks good to me too (and easiest) How you deal with resume here?
As above, don't relocate the boot and resume code (or any code reachable from it).
Resetting the machine on a rerun of POST would be a good thing to do anyway, as trying to re-post the machine has never really worked well. It does, however, make the build a bit more complex.
Reseting the machine can be done in various ways:
Thanks.
What about other CPUs?
Not sure what you mean here.
-Kevin
On Sun, Aug 22, 2010 at 08:54:35AM +0200, Rudolf Marek wrote:
What about other CPUs?
Not sure what you mean here.
It depends on reset types. Maybe halting other cpus would be good idea.
Oh - reset on SMP. Good point. We'd need to find a reset mechanism that worked even on SMP.
BTW, I tried the cf9, kbd controller, and triple fault reset on qemu. Unfortunately, cf9 doesn't do anything, and the other two only soft reset the cpu. A soft reset just causes POST to get called again in an infinite loop.
Anyone know of a way to reliably hard reset qemu?
Btw what about HMA? Maybe you can simply link the post code to HMA. And win 64kb. Bonus is that it is reachable from real mode.
Boot loaders and OSes assume they can use the memory immiediately above 1Meg - the BIOS isn't allowed to reserve it.
-Kevin
On Sun, Aug 22, 2010 at 01:25:10PM -0400, Kevin O'Connor wrote:
On Sun, Aug 22, 2010 at 08:54:35AM +0200, Rudolf Marek wrote:
What about other CPUs?
Not sure what you mean here.
It depends on reset types. Maybe halting other cpus would be good idea.
Oh - reset on SMP. Good point. We'd need to find a reset mechanism that worked even on SMP.
BTW, I tried the cf9, kbd controller, and triple fault reset on qemu. Unfortunately, cf9 doesn't do anything, and the other two only soft reset the cpu. A soft reset just causes POST to get called again in an infinite loop.
Anyone know of a way to reliably hard reset qemu?
kbd controller and triple fault should do hard reset on qemu. All devices and cpu are reset. Why do you think you see soft reset?
Btw what about HMA? Maybe you can simply link the post code to HMA. And win 64kb. Bonus is that it is reachable from real mode.
Boot loaders and OSes assume they can use the memory immiediately above 1Meg - the BIOS isn't allowed to reserve it.
-Kevin
SeaBIOS mailing list SeaBIOS@seabios.org http://www.seabios.org/mailman/listinfo/seabios
-- Gleb.
On 08/22/2010 09:19 PM, Gleb Natapov wrote:
kbd controller and triple fault should do hard reset on qemu. All devices and cpu are reset. Why do you think you see soft reset?
Triple fault by be wired to either INIT or RESET, so don't use that.
On Sun, Aug 22, 2010 at 09:19:59PM +0300, Gleb Natapov wrote:
On Sun, Aug 22, 2010 at 01:25:10PM -0400, Kevin O'Connor wrote:
Anyone know of a way to reliably hard reset qemu?
kbd controller and triple fault should do hard reset on qemu. All devices and cpu are reset. Why do you think you see soft reset?
The reset did not reset the ram at 0xc0000-0xfffff, and so it just infinitely loops. (The code I used is below.)
-Kevin
diff --git a/src/ioport.h b/src/ioport.h index ba099a7..5bd7f28 100644 --- a/src/ioport.h +++ b/src/ioport.h @@ -50,6 +50,7 @@ #define PORT_FD_DIR 0x03f7 #define PORT_SERIAL1 0x03f8 #define PORT_PCI_CMD 0x0cf8 +#define PORT_PCI_REBOOT 0x0cf9 #define PORT_PCI_DATA 0x0cfc #define PORT_BIOS_DEBUG 0x0402 #define PORT_QEMU_CFG_CTL 0x0510 diff --git a/src/pci.c b/src/pci.c index 611d0e2..115689d 100644 --- a/src/pci.c +++ b/src/pci.c @@ -215,3 +215,13 @@ int pci_find_init_device(const struct pci_device_id *ids, void *arg) } return -1; } + +void +pci_reboot(void) +{ + u8 v = inb(PORT_PCI_REBOOT) & ~6; + outb(v|2, PORT_PCI_REBOOT); /* Request hard reset */ + udelay(50); + outb(v|6, PORT_PCI_REBOOT); /* Actually do the reset */ + udelay(50); +} diff --git a/src/pci.h b/src/pci.h index 9c3108c..64bd43b 100644 --- a/src/pci.h +++ b/src/pci.h @@ -94,6 +94,7 @@ struct pci_device_id {
int pci_init_device(const struct pci_device_id *table, u16 bdf, void *arg); int pci_find_init_device(const struct pci_device_id *ids, void *arg); +void pci_reboot(void);
// pirtable.c void create_pirtable(void); diff --git a/src/post.c b/src/post.c index 56e5eb5..eb7bdcb 100644 --- a/src/post.c +++ b/src/post.c @@ -244,6 +244,8 @@ post(void) memmap_finalize(); }
+int HaveRunPost; + // 32-bit entry point. void VISIBLE32FLAT _start(void) @@ -253,9 +255,27 @@ _start(void) debug_serial_setup(); dprintf(1, "Start bios (version %s)\n", VERSION);
+ if (HaveRunPost) { + // This is a soft reboot - invoke a hard reboot. + dprintf(1, "Attempting a hard reboot\n"); + + // Try PCI 0xcf9 reboot + pci_reboot(); + + // Try keyboard controller reboot. + i8042_reboot(); + + // Try triple fault + asm volatile("int3"); + + panic("Could not reboot"); + } + // Allow writes to modify bios area (0xf0000) make_bios_writable();
+ HaveRunPost = 1; + // Perform main setup code. post();
diff --git a/src/ps2port.c b/src/ps2port.c index ccbd2f6..d1e6d48 100644 --- a/src/ps2port.c +++ b/src/ps2port.c @@ -51,7 +51,7 @@ i8042_wait_write(void) return -1; }
-int +static int i8042_flush(void) { dprintf(7, "i8042_flush\n"); @@ -102,7 +102,7 @@ __i8042_command(int command, u8 *param) return 0; }
-int +static int i8042_command(int command, u8 *param) { dprintf(7, "i8042_command cmd=%x\n", command); @@ -128,6 +128,18 @@ i8042_aux_write(u8 c) return i8042_command(I8042_CMD_AUX_SEND, &c); }
+void +i8042_reboot(void) +{ + int i; + for (i=0; i<10; i++) { + i8042_wait_write(); + udelay(50); + outb(0xfe, PORT_PS2_STATUS); /* pulse reset low */ + udelay(50); + } +} +
/**************************************************************** * Device commands. diff --git a/src/ps2port.h b/src/ps2port.h index afb0e78..dcae391 100644 --- a/src/ps2port.h +++ b/src/ps2port.h @@ -55,8 +55,7 @@ #define I8042_CTR_XLATE 0x40
// functions -int i8042_flush(void); -int i8042_command(int command, u8 *param); +void i8042_reboot(void); int ps2_kbd_command(int command, u8 *param); int ps2_mouse_command(int command, u8 *param); void ps2port_setup(void);
BTW, I tried the cf9,
This bit differs chipset to chipset.
kbd controller,
The port 92? or the 0xfe command?
Btw what about HMA? Maybe you can simply link the post code to HMA. And win 64kb. Bonus is that it is reachable from real mode.
Boot loaders and OSes assume they can use the memory immiediately above 1Meg - the BIOS isn't allowed to reserve it.
Yes but I thought we can use it for POST. So maybe reloc is not needed? In general case we can put the POST 32bit code right to 1MB...
Thanks Rudolf
-Kevin
On 08/21/2010 09:41 PM, Kevin O'Connor wrote:
SeaBIOS is coming close to exceeding 128K in size. Right now, it's approximately 107K on qemu with default options and 120K with full debugging and all options enabled.
SeaBIOS currently contends with option roms for space. Every byte that SeaBIOS uses is one less byte available for option roms. It's technically possible for SeaBIOS to exceed 128K, but it's likely that we'll start seeing option roms not fitting around that point.
It would also be nice to be able to do malloc_low allocations from the e-segment. This too requires freeing up space that SeaBIOS is currently using to store code.
I've been thinking of a few different ways to free up space. The most promising approach seems to be to relocate all or part of SeaBIOS' 32bit "flat" code. This 32bit code is larger than the segmented code (67K vs 40K) and it's the area that has been growing the most.
To relocate the code, the build can store a list of code that depends on a fixed address and then at runtime SeaBIOS can modify the code with the new address.
Some different permutations of this idea that I've come up with are:
1 - On boot, have SeaBIOS relocate all of it's 32bit code to permanent high ram.
CONS: Reserves memory that then can't be used by the OS (67K today). CONS: SeaBIOS code is still limited to 256K size (c+d+e+f segments)
2 - Have the build separate out the POST code from other 32bit code (eg, boot& resume) and store the POST code in a separate CBFS/fw_cfg "file". During boot SeaBIOS would extract the separate POST code blob into temporary high ram and run it. Currently, the POST code is the bulk of the 32bit "flat" code (57K vs 10K).
CONS: It adds complexity during deployment as both the main SeaBIOS blob and the CBFS/fw_cfg POST blob would need to be copied.
3 - On boot, relocate only POST code to temporary high ram, and have SeaBIOS reset the machine if the POST code is ever rerun.
CONS: Requires a reliable way of resetting the machine. CONS: SeaBIOS code is still limited to 256K size (c+d+e+f segments)
4 - Have the entry points switch immediately to 32-bit mode and call 32-bit unpaged code in 4G-2M+. Everything, for example the INT 13 code, would run in 32-bit mode from high memory.
PRO - unlimited memory PRO - less restrictions from .code16gcc, can easily handle far pointers (a single function will covert a far pointer to a real pointer) PRO - smaller code (since .code16gcc uses 32-bit code with lots of prefixes) PRO - easier to debug, since the tools are geared towards flat memory models (except for the thunk code) CON - slightly slower due to mode switching CON - a lot of work (but can make it incremental)
On Sun, Aug 22, 2010 at 01:37:48PM +0300, Avi Kivity wrote:
On 08/21/2010 09:41 PM, Kevin O'Connor wrote:
SeaBIOS is coming close to exceeding 128K in size. Right now, it's approximately 107K on qemu with default options and 120K with full debugging and all options enabled.
SeaBIOS currently contends with option roms for space. Every byte that SeaBIOS uses is one less byte available for option roms. It's technically possible for SeaBIOS to exceed 128K, but it's likely that we'll start seeing option roms not fitting around that point.
It would also be nice to be able to do malloc_low allocations from the e-segment. This too requires freeing up space that SeaBIOS is currently using to store code.
I've been thinking of a few different ways to free up space. The most promising approach seems to be to relocate all or part of SeaBIOS' 32bit "flat" code. This 32bit code is larger than the segmented code (67K vs 40K) and it's the area that has been growing the most.
To relocate the code, the build can store a list of code that depends on a fixed address and then at runtime SeaBIOS can modify the code with the new address.
Some different permutations of this idea that I've come up with are:
1 - On boot, have SeaBIOS relocate all of it's 32bit code to permanent high ram.
CONS: Reserves memory that then can't be used by the OS (67K today). CONS: SeaBIOS code is still limited to 256K size (c+d+e+f segments)
2 - Have the build separate out the POST code from other 32bit code (eg, boot& resume) and store the POST code in a separate CBFS/fw_cfg "file". During boot SeaBIOS would extract the separate POST code blob into temporary high ram and run it. Currently, the POST code is the bulk of the 32bit "flat" code (57K vs 10K).
CONS: It adds complexity during deployment as both the main SeaBIOS blob and the CBFS/fw_cfg POST blob would need to be copied.
3 - On boot, relocate only POST code to temporary high ram, and have SeaBIOS reset the machine if the POST code is ever rerun.
CONS: Requires a reliable way of resetting the machine. CONS: SeaBIOS code is still limited to 256K size (c+d+e+f segments)
4 - Have the entry points switch immediately to 32-bit mode and call 32-bit unpaged code in 4G-2M+. Everything, for example the INT 13 code, would run in 32-bit mode from high memory.
IIRC this was discussed already. Some applications call BIOS from vm16 mode so switch to 32-bin is impossible.
PRO - unlimited memory PRO - less restrictions from .code16gcc, can easily handle far pointers (a single function will covert a far pointer to a real pointer) PRO - smaller code (since .code16gcc uses 32-bit code with lots of prefixes) PRO - easier to debug, since the tools are geared towards flat memory models (except for the thunk code) CON - slightly slower due to mode switching CON - a lot of work (but can make it incremental)
-- error compiling committee.c: too many arguments to function
SeaBIOS mailing list SeaBIOS@seabios.org http://www.seabios.org/mailman/listinfo/seabios
-- Gleb.
On 08/22/2010 02:15 PM, Gleb Natapov wrote:
4 - Have the entry points switch immediately to 32-bit mode and call 32-bit unpaged code in 4G-2M+. Everything, for example the INT 13 code, would run in 32-bit mode from high memory.
IIRC this was discussed already. Some applications call BIOS from vm16 mode so switch to 32-bin is impossible.
Ugh. We could use the old 286 trick and reset the CPU to escape to real mode, but this isn't a viable solution (for example, how would we get back?)
On Sun, Aug 22, 2010 at 02:25:44PM +0300, Avi Kivity wrote:
On 08/22/2010 02:15 PM, Gleb Natapov wrote:
4 - Have the entry points switch immediately to 32-bit mode and call 32-bit unpaged code in 4G-2M+. Everything, for example the INT 13 code, would run in 32-bit mode from high memory.
IIRC this was discussed already. Some applications call BIOS from vm16 mode so switch to 32-bin is impossible.
Ugh. We could use the old 286 trick and reset the CPU to escape to real mode, but this isn't a viable solution (for example, how would we get back?)
It may not even be possible to reset the cpu as that may be blocked by the OS when the bios is in vm86 mode.
One could try invoking an SMI to get into 32bit mode, but that also has difficulties (eg, the OS could block that too, paging would have to be emulated, it could be a security problem).
Even with all its warts I think .code16gcc is the best route.
-Kevin
On 08/22/2010 07:08 PM, Kevin O'Connor wrote:
On Sun, Aug 22, 2010 at 02:25:44PM +0300, Avi Kivity wrote:
On 08/22/2010 02:15 PM, Gleb Natapov wrote:
4 - Have the entry points switch immediately to 32-bit mode and call 32-bit unpaged code in 4G-2M+. Everything, for example the INT 13 code, would run in 32-bit mode from high memory.
IIRC this was discussed already. Some applications call BIOS from vm16 mode so switch to 32-bin is impossible.
Ugh. We could use the old 286 trick and reset the CPU to escape to real mode, but this isn't a viable solution (for example, how would we get back?)
It may not even be possible to reset the cpu as that may be blocked by the OS when the bios is in vm86 mode.
Well, it's likely running with all ports open since the (guest) VMM does not know what the BIOS accesses.
btw, big real mode cannot be entered in vm86 mode. So anything involving that can safely be moved to upper memory 32-bit code.
One could try invoking an SMI to get into 32bit mode, but that also has difficulties (eg, the OS could block that too, paging would have to be emulated, it could be a security problem).
Even worse (from my perspective), kvm doesn't emulate SMM.
Even with all its warts I think .code16gcc is the best route.
For 16-bit runtime services, I agree. For POST and 32-bit runtime services, I think we can easily push the code to 4G-2M.
On Sun, Aug 22, 2010 at 07:23:30PM +0300, Avi Kivity wrote:
btw, big real mode cannot be entered in vm86 mode. So anything involving that can safely be moved to upper memory 32-bit code.
Only POST needs bigreal mode, and it should be no problem moving POST to high memory.
Even with all its warts I think .code16gcc is the best route.
For 16-bit runtime services, I agree. For POST and 32-bit runtime services, I think we can easily push the code to 4G-2M.
The 32bit runtime is also tricky, but thankfully it's under 2K of code and so it can be left in the f-segment.
I'm not sure what you mean by "4G-2M" - are you suggesting running XIP in the "flash" chip? This is possible in qemu/kvm, but it's not something you'd want to do on real hardware. Accesses to the flash chip are terribly slow - on real hardware you want to copy the code from flash to ram as soon as possible. (You typically want to compress everything in flash also.)
-Kevin
On 08/22/2010 08:02 PM, Kevin O'Connor wrote:
Even with all its warts I think .code16gcc is the best route.
For 16-bit runtime services, I agree. For POST and 32-bit runtime services, I think we can easily push the code to 4G-2M.
The 32bit runtime is also tricky, but thankfully it's under 2K of code and so it can be left in the f-segment.
I'm not sure what you mean by "4G-2M" - are you suggesting running XIP in the "flash" chip?
Yes.
This is possible in qemu/kvm, but it's not something you'd want to do on real hardware. Accesses to the flash chip are terribly slow - on real hardware you want to copy the code from flash to ram as soon as possible. (You typically want to compress everything in flash also.)
Typically I forget non-qemu constraints, sorry.
I see that ld has some support for overlays, perhaps we can use that?
On Sun, Aug 22, 2010 at 08:07:53PM +0300, Avi Kivity wrote:
I see that ld has some support for overlays, perhaps we can use that?
The overlay support is basically just another way of manipulating the run-time addresses of the code at build time. Unfortunately, it can only specify static addresses, and I don't think there is any safe static address that can be used (outside of 0xc0000-0xfffff).
-Kevin
On 08/22/2010 08:40 PM, Kevin O'Connor wrote:
On Sun, Aug 22, 2010 at 08:07:53PM +0300, Avi Kivity wrote:
I see that ld has some support for overlays, perhaps we can use that?
The overlay support is basically just another way of manipulating the run-time addresses of the code at build time. Unfortunately, it can only specify static addresses, and I don't think there is any safe static address that can be used (outside of 0xc0000-0xfffff).
Is that not useful? We can push, say the IDE and virtio drivers to overlay the same address range in the e/f segments, and have the stubs pull them in as necessary.
On Sun, Aug 22, 2010 at 09:18:43PM +0300, Avi Kivity wrote:
On 08/22/2010 08:40 PM, Kevin O'Connor wrote:
On Sun, Aug 22, 2010 at 08:07:53PM +0300, Avi Kivity wrote:
I see that ld has some support for overlays, perhaps we can use that?
The overlay support is basically just another way of manipulating the run-time addresses of the code at build time. Unfortunately, it can only specify static addresses, and I don't think there is any safe static address that can be used (outside of 0xc0000-0xfffff).
Is that not useful? We can push, say the IDE and virtio drivers to overlay the same address range in the e/f segments, and have the stubs pull them in as necessary.
And if you need both?
-- Gleb.
On 08/22/2010 09:21 PM, Gleb Natapov wrote:
On Sun, Aug 22, 2010 at 09:18:43PM +0300, Avi Kivity wrote:
On 08/22/2010 08:40 PM, Kevin O'Connor wrote:
On Sun, Aug 22, 2010 at 08:07:53PM +0300, Avi Kivity wrote:
I see that ld has some support for overlays, perhaps we can use that?
The overlay support is basically just another way of manipulating the run-time addresses of the code at build time. Unfortunately, it can only specify static addresses, and I don't think there is any safe static address that can be used (outside of 0xc0000-0xfffff).
Is that not useful? We can push, say the IDE and virtio drivers to overlay the same address range in the e/f segments, and have the stubs pull them in as necessary.
And if you need both?
That's the thing, the overlay is swapped dynamically.
You can't need both at the same time, since the BIOS runtime is single threaded.
On Sun, Aug 22, 2010 at 09:18:43PM +0300, Avi Kivity wrote:
On 08/22/2010 08:40 PM, Kevin O'Connor wrote:
On Sun, Aug 22, 2010 at 08:07:53PM +0300, Avi Kivity wrote:
I see that ld has some support for overlays, perhaps we can use that?
The overlay support is basically just another way of manipulating the run-time addresses of the code at build time. Unfortunately, it can only specify static addresses, and I don't think there is any safe static address that can be used (outside of 0xc0000-0xfffff).
Is that not useful? We can push, say the IDE and virtio drivers to overlay the same address range in the e/f segments, and have the stubs pull them in as necessary.
I guess you're describing a way of swapping parts of the BIOS in. It could be made to work, but seems very complicated.
Relocating the code isn't that bad. It should just be a matter of storing which parts of the code rely on a fixed address, and then updating those addresses at runtime. Something like:
// Info provided by build extern u32 Relocs[]; extern u32 NumRelocs; extern void *OrigCodeAddr; extern u32 CodeSize;
// Relocation code. memcpy(newaddr, OrigCodeAddr, CodeSize); for (i=0; i<NumRelocs; i++) *(u32*)(newaddr + Relocs[i]) += (newaddr - OrigCodeAddr);
If the code can be relocated, it should be okay to put it at the top of high memory. Relocating should be more transparent than "swapping" to developers, as it wouldn't impose any limits on what can code can call other code.
-Kevin
Kevin O'Connor wrote:
Relocating the code isn't that bad. It should just be a matter of storing which parts of the code rely on a fixed address, and then updating those addresses at runtime.
Hey, that sounds just like a dynamic linker.
//Peter
On 08/23/2010 01:57 AM, Kevin O'Connor wrote:
On Sun, Aug 22, 2010 at 09:18:43PM +0300, Avi Kivity wrote:
On 08/22/2010 08:40 PM, Kevin O'Connor wrote:
On Sun, Aug 22, 2010 at 08:07:53PM +0300, Avi Kivity wrote:
I see that ld has some support for overlays, perhaps we can use that?
The overlay support is basically just another way of manipulating the run-time addresses of the code at build time. Unfortunately, it can only specify static addresses, and I don't think there is any safe static address that can be used (outside of 0xc0000-0xfffff).
Is that not useful? We can push, say the IDE and virtio drivers to overlay the same address range in the e/f segments, and have the stubs pull them in as necessary.
I guess you're describing a way of swapping parts of the BIOS in. It could be made to work, but seems very complicated.
That's what overlay is, it used to be a hot method way back. Why do you think it's complicated? There's some support for it in ld.
Relocating the code isn't that bad. It should just be a matter of storing which parts of the code rely on a fixed address, and then updating those addresses at runtime. Something like:
// Info provided by build extern u32 Relocs[]; extern u32 NumRelocs; extern void *OrigCodeAddr; extern u32 CodeSize; // Relocation code. memcpy(newaddr, OrigCodeAddr, CodeSize); for (i=0; i<NumRelocs; i++) *(u32*)(newaddr + Relocs[i]) += (newaddr - OrigCodeAddr);
If the code can be relocated, it should be okay to put it at the top of high memory. Relocating should be more transparent than "swapping" to developers, as it wouldn't impose any limits on what can code can call other code.
Overlays are transparent too, you typically have stubs for overlaid code which call the overlay manager to swap the code in if necessary. These stubs are generated automatically.
Relocation should work as well, and indeed has less constraints, but needs more build support.
On Mon, Aug 23, 2010 at 08:37:16AM +0300, Avi Kivity wrote:
On 08/23/2010 01:57 AM, Kevin O'Connor wrote:
On Sun, Aug 22, 2010 at 09:18:43PM +0300, Avi Kivity wrote:
On 08/22/2010 08:40 PM, Kevin O'Connor wrote:
On Sun, Aug 22, 2010 at 08:07:53PM +0300, Avi Kivity wrote:
I see that ld has some support for overlays, perhaps we can use that?
The overlay support is basically just another way of manipulating the run-time addresses of the code at build time. Unfortunately, it can only specify static addresses, and I don't think there is any safe static address that can be used (outside of 0xc0000-0xfffff).
Is that not useful? We can push, say the IDE and virtio drivers to overlay the same address range in the e/f segments, and have the stubs pull them in as necessary.
I guess you're describing a way of swapping parts of the BIOS in. It could be made to work, but seems very complicated.
That's what overlay is, it used to be a hot method way back. Why do you think it's complicated? There's some support for it in ld.
It is not hot method any more for a reason though :) It is complicated because you need to decide at build time what can overlay with what.
Relocating the code isn't that bad. It should just be a matter of storing which parts of the code rely on a fixed address, and then updating those addresses at runtime. Something like:
// Info provided by build extern u32 Relocs[]; extern u32 NumRelocs; extern void *OrigCodeAddr; extern u32 CodeSize; // Relocation code. memcpy(newaddr, OrigCodeAddr, CodeSize); for (i=0; i<NumRelocs; i++) *(u32*)(newaddr + Relocs[i]) += (newaddr - OrigCodeAddr);
If the code can be relocated, it should be okay to put it at the top of high memory. Relocating should be more transparent than "swapping" to developers, as it wouldn't impose any limits on what can code can call other code.
Overlays are transparent too, you typically have stubs for overlaid code which call the overlay manager to swap the code in if necessary. These stubs are generated automatically.
Relocation should work as well, and indeed has less constraints, but needs more build support.
-- I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain.
SeaBIOS mailing list SeaBIOS@seabios.org http://www.seabios.org/mailman/listinfo/seabios
-- Gleb.
On 08/23/2010 10:30 AM, Gleb Natapov wrote:
That's what overlay is, it used to be a hot method way back. Why do you think it's complicated? There's some support for it in ld.
It is not hot method any more for a reason though :) It is complicated because you need to decide at build time what can overlay with what.
I agree relocation is simpler.
On 22.08.2010 19:02, Kevin O'Connor wrote:
I'm not sure what you mean by "4G-2M" - are you suggesting running XIP in the "flash" chip? This is possible in qemu/kvm, but it's not something you'd want to do on real hardware. Accesses to the flash chip are terribly slow - on real hardware you want to copy the code from flash to ram as soon as possible.
If you can switch on caching for the flash area and do it correctly, why would it be slow during POST? Of course you have to switch off caching of flash once you pass control to the bootloader, and then flash will be slow, but for initial POST it should work fine.
(You typically want to compress everything in flash also.)
Of course that's indeed a compelling argument.
Regards, Carl-Daniel
On Mon, Aug 23, 2010 at 12:33:24AM +0200, Carl-Daniel Hailfinger wrote:
On 22.08.2010 19:02, Kevin O'Connor wrote:
I'm not sure what you mean by "4G-2M" - are you suggesting running XIP in the "flash" chip? This is possible in qemu/kvm, but it's not something you'd want to do on real hardware. Accesses to the flash chip are terribly slow - on real hardware you want to copy the code from flash to ram as soon as possible.
If you can switch on caching for the flash area and do it correctly, why would it be slow during POST? Of course you have to switch off caching of flash once you pass control to the bootloader, and then flash will be slow, but for initial POST it should work fine.
(You typically want to compress everything in flash also.)
Of course that's indeed a compelling argument.
Caching flash would mitigate some of the slowness, but as you point out, it has complexities and is still not really a great solution. It's far simpler and more robust to copy the code to ram on real hardware. (In contrast, on qemu/kvm it's really quite simple to just jump into the extra copy of SeaBIOS at 0xfffe0000.)
-Kevin