The A20 setting is almost always enabled - only issue an outb() if the A20 is actually changing. This reduces the number of outb() calls.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/fw/smm.c | 6 ++++-- src/stacks.c | 4 +++- src/x86.h | 7 ++++--- 3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/src/fw/smm.c b/src/fw/smm.c index 178959c..d90e43a 100644 --- a/src/fw/smm.c +++ b/src/fw/smm.c @@ -109,7 +109,8 @@ handle_smi(u16 cs) dprintf(9, "smm cpu ret %x esp=%x\n", regs[3], regs[4]); memcpy(&smm->cpu, &smm->backup2, sizeof(smm->cpu)); memcpy(&smm->cpu.i32.eax, regs, sizeof(regs)); - set_a20(smm->backup_a20); + if (!smm->backup_a20) + set_a20(0); smm->cpu.i32.eip = regs[3]; } } else if (rev == SMM_REV_I64) { @@ -125,7 +126,8 @@ handle_smi(u16 cs) } else if ((u32)smm->cpu.i64.rcx == CALL32SMM_RETURNID) { memcpy(&smm->cpu, &smm->backup2, sizeof(smm->cpu)); memcpy(&smm->cpu.i64.rdi, regs, sizeof(regs)); - set_a20(smm->backup_a20); + if (!smm->backup_a20) + set_a20(0); smm->cpu.i64.rip = (u32)regs[4]; } } diff --git a/src/stacks.c b/src/stacks.c index 9fec2fb..f4d15ce 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -84,7 +84,9 @@ call32_post(void)
if (!CONFIG_CALL32_SMM || method != C16_SMM) { // Restore a20 - set_a20(GET_LOW(Call16Data.a20)); + u8 a20 = GET_LOW(Call16Data.a20); + if (!a20) + set_a20(0);
// Restore gdt and fs/gs struct descloc_s gdt; diff --git a/src/x86.h b/src/x86.h index a770e6f..4aea65c 100644 --- a/src/x86.h +++ b/src/x86.h @@ -258,9 +258,10 @@ static inline u8 get_a20(void) { }
static inline u8 set_a20(u8 cond) { - u8 val = inb(PORT_A20); - outb((val & ~A20_ENABLE_BIT) | (cond ? A20_ENABLE_BIT : 0), PORT_A20); - return (val & A20_ENABLE_BIT) != 0; + u8 val = inb(PORT_A20), a20_enabled = (val & A20_ENABLE_BIT) != 0; + if (a20_enabled != !!cond) + outb(val ^ A20_ENABLE_BIT, PORT_A20); + return a20_enabled; }
// x86.c