From afa6e3dec454424863733317ea29ff20a718e277 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 22 Apr 2009 15:21:39 -0700 Subject: [PATCH] shuffle_rm: set up SS:ESP and segs as quickly as possible For extra paranoia's sake, set up SS:ESP immediately after the real-mode switch, and then set all the segment registers. Signed-off-by: H. Peter Anvin --- com32/lib/syslinux/shuffle_rm.c | 53 +++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/com32/lib/syslinux/shuffle_rm.c b/com32/lib/syslinux/shuffle_rm.c index 7eb3585..2496b88 100644 --- a/com32/lib/syslinux/shuffle_rm.c +++ b/com32/lib/syslinux/shuffle_rm.c @@ -39,6 +39,12 @@ #include #include +enum gpr_index { R_AX, R_CX, R_DX, R_BX, R_SP, R_BP, R_SI, R_DI }; +enum seg_index { R_ES, R_CS, R_SS, R_DS, R_FS, R_GS }; + +#define MOV_TO_SEG(S,R) (0xc08e + ((R) << 8) + ((S) << 11)) +#define MOV_TO_R32(R) (0xb866 + ((R) << 8)) + int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist, struct syslinux_memmap *memmap, uint16_t bootflags, @@ -54,6 +60,8 @@ int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist, uint8_t handoff_code[8+5*5+8*6+1+5], *p; struct syslinux_memmap *tmap; addr_t regstub, stublen; + /* Assign GPRs for each sreg, don't use AX and SP */ + static const uint8_t gpr_for_seg[6] = { R_CX, R_DX, R_BX, R_BP, R_SI, R_DI }; tmap = syslinux_target_memmap(fraglist, memmap); if (!tmap) @@ -92,24 +100,43 @@ int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist, 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; - + /* Set up GPRs with segment registers - don't use AX */ for (i = 0; i < 6; i++) { - if (i != 1) { /* Skip CS */ - p[0] = 0xb8; /* MOV AX,imm16 */ + if (i != R_CS) { + p[0] = 0xb8 + gpr_for_seg[i]; /* MOV reg,imm16 */ *(uint16_t *)(p+1) = rp->seg[i]; - *(uint16_t *)(p+3) = 0xc08e + (i << 11); /* MOV seg,AX */ - p += 5; + p += 3; } } + + /* Actual transition to real mode */ + *(uint32_t *)p = 0xeac0220f; /* MOV CR0,EAX; JMP FAR */ + *(uint16_t *)(p+4) = (p-handoff_code)+8; /* Offset */ + *(uint16_t *)(p+6) = regstub >> 4; /* Segment */ + p += 8; + + /* Load SS and ESP immediately */ + *(uint16_t *)p = MOV_TO_SEG(R_SS, R_BX); + *(uint16_t *)(p+2) = MOV_TO_R32(R_SP); + *(uint32_t *)(p+4) = rp->seg[R_SP]; + p += 8; + + /* Load the other segments */ + *(uint16_t *)p = MOV_TO_SEG(R_ES, R_CX); + p += 2; + *(uint16_t *)p = MOV_TO_SEG(R_DS, R_BP); + p += 2; + *(uint16_t *)p = MOV_TO_SEG(R_FS, R_SI); + p += 2; + *(uint16_t *)p = MOV_TO_SEG(R_GS, R_DI); + p += 2; + for (i = 0; i < 8; i++) { - p[0] = 0x66; /* MOV exx,imm32 */ - p[1] = 0xb8 + i; - *(uint32_t *)(p+2) = rp->gpr[i]; - p += 6; + if (i != R_SP) { + *(uint16_t *)p = MOV_TO_R32(i); /* MOV r32,imm32 */ + *(uint32_t *)(p+2) = rp->gpr[i]; + p += 6; + } } *p++ = rp->sti ? 0xfb : 0xfa; /* STI/CLI */ -- 2.7.4