#include <syslinux/movebits.h>
#include <syslinux/bootrm.h>
+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,
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)
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 */