diff options
| author | H. Peter Anvin <hpa@zytor.com> | 2009-04-13 19:11:30 -0700 |
|---|---|---|
| committer | H. Peter Anvin <hpa@zytor.com> | 2009-04-13 19:11:30 -0700 |
| commit | f2ebe30cefa59def4bc590f3ced08465b839430e (patch) | |
| tree | 383fb040cd3624aa2d531c8dcd7dfd51579fe16d /com32/lib/syslinux/shuffle_rm.c | |
| parent | 3a1bc74b6c26b55a52459d9748375bf3aa15db37 (diff) | |
| download | syslinux-f2ebe30cefa59def4bc590f3ced08465b839430e.tar.gz | |
shuffler: work around KVM problem with the new shuffler
KVM uses V86 mode to simulate real mode. This causes problems with
the new shuffler. This changes the shuffler handover to be in
16-bit protected mode instead, and requires the stub to do the actual
entry to real mode. For the KVM hack to work, all segments must have:
(seg.base & 0xfff0000f) == 0 && seg.limit == 0xffff
As a result, we have to make sure the real-mode entry stub is
paragraph-aligned, lest we violate the first criterion.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'com32/lib/syslinux/shuffle_rm.c')
| -rw-r--r-- | com32/lib/syslinux/shuffle_rm.c | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/com32/lib/syslinux/shuffle_rm.c b/com32/lib/syslinux/shuffle_rm.c index 3ef8de7a..fd103d0f 100644 --- a/com32/lib/syslinux/shuffle_rm.c +++ b/com32/lib/syslinux/shuffle_rm.c @@ -51,7 +51,7 @@ int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist, bool sti; } *rp; int i, rv; - uint8_t handoff_code[5*5+8*6+1+5], *p; + uint8_t handoff_code[8+5*5+8*6+1+5], *p; struct syslinux_memmap *tmap; addr_t regstub, stublen; @@ -59,11 +59,15 @@ int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist, if (!tmap) return -1; - /* Search for a good place to put the real-mode register stub. - We prefer it as low as possible above 0x800. */ + /* + * Search for a good place to put the real-mode register stub. + * We prefer it as low as possible above 0x800. KVM barfs horribly + * if we're not aligned to a paragraph boundary, so set the alignment + * appropriately. + */ regstub = 0x800; stublen = sizeof handoff_code; - rv = syslinux_memmap_find(tmap, SMT_FREE, ®stub, &stublen); + rv = syslinux_memmap_find(tmap, SMT_FREE, ®stub, &stublen, 16); if (rv || (regstub > 0x100000 - sizeof handoff_code)) { /* @@ -74,7 +78,7 @@ int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist, */ regstub = 0x510; /* Try the 0x5xx segment... */ stublen = sizeof handoff_code; - rv = syslinux_memmap_find(tmap, SMT_FREE, ®stub, &stublen); + rv = syslinux_memmap_find(tmap, SMT_FREE, ®stub, &stublen, 16); if (!rv && (regstub > 0x100000 - sizeof handoff_code)) rv = -1; /* No acceptable memory found */ @@ -87,6 +91,12 @@ int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist, /* Build register-setting stub */ p = handoff_code; rp = (const struct syslinux_rm_regs_alt *)regs; + + *((uint32_t *)p) = 0xeac0220f; /* MOV CR0,EAX; JMP FAR */ + *((uint16_t *)(p+4)) = 8; /* Offset */ + *((uint16_t *)(p+6)) = regstub >> 4; /* Segment */ + p += 8; + for (i = 0; i < 6; i++) { if (i != 1) { /* Skip CS */ p[0] = 0xb8; /* MOV AX,imm16 */ @@ -111,8 +121,5 @@ int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist, sizeof handoff_code)) return -1; - /* Convert regstub to a CS:IP entrypoint pair */ - regstub = (SEG((void *)regstub) << 16) + OFFS((void *)regstub); - return syslinux_do_shuffle(fraglist, memmap, regstub, 0, bootflags); } |
