Skip to content

Commit

Permalink
x86: split off SMM helpers
Browse files Browse the repository at this point in the history
Move SMM helpers to smm_helper.c.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
  • Loading branch information
blueswirl committed Jun 28, 2012
1 parent 6bada5e commit ab109e5
Show file tree
Hide file tree
Showing 3 changed files with 309 additions and 285 deletions.
2 changes: 2 additions & 0 deletions target-i386/Makefile.objs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
obj-y += smm_helper.o
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o
obj-$(CONFIG_KVM) += kvm.o hyperv.o
obj-$(CONFIG_LINUX_USER) += ioport-user.o
Expand All @@ -10,3 +11,4 @@ $(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/svm_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/smm_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
285 changes: 0 additions & 285 deletions target-i386/op_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -1353,291 +1353,6 @@ void do_interrupt_x86_hardirq(CPUX86State *env1, int intno, int is_hw)
env = saved_env;
}

/* SMM support */

#if defined(CONFIG_USER_ONLY)

void do_smm_enter(CPUX86State *env1)
{
}

void helper_rsm(void)
{
}

#else

#ifdef TARGET_X86_64
#define SMM_REVISION_ID 0x00020064
#else
#define SMM_REVISION_ID 0x00020000
#endif

void do_smm_enter(CPUX86State *env1)
{
target_ulong sm_state;
SegmentCache *dt;
int i, offset;
CPUX86State *saved_env;

saved_env = env;
env = env1;

qemu_log_mask(CPU_LOG_INT, "SMM: enter\n");
log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);

env->hflags |= HF_SMM_MASK;
cpu_smm_update(env);

sm_state = env->smbase + 0x8000;

#ifdef TARGET_X86_64
for (i = 0; i < 6; i++) {
dt = &env->segs[i];
offset = 0x7e00 + i * 16;
stw_phys(sm_state + offset, dt->selector);
stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff);
stl_phys(sm_state + offset + 4, dt->limit);
stq_phys(sm_state + offset + 8, dt->base);
}

stq_phys(sm_state + 0x7e68, env->gdt.base);
stl_phys(sm_state + 0x7e64, env->gdt.limit);

stw_phys(sm_state + 0x7e70, env->ldt.selector);
stq_phys(sm_state + 0x7e78, env->ldt.base);
stl_phys(sm_state + 0x7e74, env->ldt.limit);
stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);

stq_phys(sm_state + 0x7e88, env->idt.base);
stl_phys(sm_state + 0x7e84, env->idt.limit);

stw_phys(sm_state + 0x7e90, env->tr.selector);
stq_phys(sm_state + 0x7e98, env->tr.base);
stl_phys(sm_state + 0x7e94, env->tr.limit);
stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);

stq_phys(sm_state + 0x7ed0, env->efer);

stq_phys(sm_state + 0x7ff8, EAX);
stq_phys(sm_state + 0x7ff0, ECX);
stq_phys(sm_state + 0x7fe8, EDX);
stq_phys(sm_state + 0x7fe0, EBX);
stq_phys(sm_state + 0x7fd8, ESP);
stq_phys(sm_state + 0x7fd0, EBP);
stq_phys(sm_state + 0x7fc8, ESI);
stq_phys(sm_state + 0x7fc0, EDI);
for (i = 8; i < 16; i++) {
stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
}
stq_phys(sm_state + 0x7f78, env->eip);
stl_phys(sm_state + 0x7f70, cpu_compute_eflags(env));
stl_phys(sm_state + 0x7f68, env->dr[6]);
stl_phys(sm_state + 0x7f60, env->dr[7]);

stl_phys(sm_state + 0x7f48, env->cr[4]);
stl_phys(sm_state + 0x7f50, env->cr[3]);
stl_phys(sm_state + 0x7f58, env->cr[0]);

stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
stl_phys(sm_state + 0x7f00, env->smbase);
#else
stl_phys(sm_state + 0x7ffc, env->cr[0]);
stl_phys(sm_state + 0x7ff8, env->cr[3]);
stl_phys(sm_state + 0x7ff4, cpu_compute_eflags(env));
stl_phys(sm_state + 0x7ff0, env->eip);
stl_phys(sm_state + 0x7fec, EDI);
stl_phys(sm_state + 0x7fe8, ESI);
stl_phys(sm_state + 0x7fe4, EBP);
stl_phys(sm_state + 0x7fe0, ESP);
stl_phys(sm_state + 0x7fdc, EBX);
stl_phys(sm_state + 0x7fd8, EDX);
stl_phys(sm_state + 0x7fd4, ECX);
stl_phys(sm_state + 0x7fd0, EAX);
stl_phys(sm_state + 0x7fcc, env->dr[6]);
stl_phys(sm_state + 0x7fc8, env->dr[7]);

stl_phys(sm_state + 0x7fc4, env->tr.selector);
stl_phys(sm_state + 0x7f64, env->tr.base);
stl_phys(sm_state + 0x7f60, env->tr.limit);
stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);

stl_phys(sm_state + 0x7fc0, env->ldt.selector);
stl_phys(sm_state + 0x7f80, env->ldt.base);
stl_phys(sm_state + 0x7f7c, env->ldt.limit);
stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);

stl_phys(sm_state + 0x7f74, env->gdt.base);
stl_phys(sm_state + 0x7f70, env->gdt.limit);

stl_phys(sm_state + 0x7f58, env->idt.base);
stl_phys(sm_state + 0x7f54, env->idt.limit);

for (i = 0; i < 6; i++) {
dt = &env->segs[i];
if (i < 3) {
offset = 0x7f84 + i * 12;
} else {
offset = 0x7f2c + (i - 3) * 12;
}
stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector);
stl_phys(sm_state + offset + 8, dt->base);
stl_phys(sm_state + offset + 4, dt->limit);
stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff);
}
stl_phys(sm_state + 0x7f14, env->cr[4]);

stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
stl_phys(sm_state + 0x7ef8, env->smbase);
#endif
/* init SMM cpu state */

#ifdef TARGET_X86_64
cpu_load_efer(env, 0);
#endif
cpu_load_eflags(env, 0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C |
DF_MASK));
env->eip = 0x00008000;
cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase,
0xffffffff, 0);
cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0);
cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0);
cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);

cpu_x86_update_cr0(env,
env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK |
CR0_PG_MASK));
cpu_x86_update_cr4(env, 0);
env->dr[7] = 0x00000400;
CC_OP = CC_OP_EFLAGS;
env = saved_env;
}

void helper_rsm(void)
{
target_ulong sm_state;
int i, offset;
uint32_t val;

sm_state = env->smbase + 0x8000;
#ifdef TARGET_X86_64
cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0));

for (i = 0; i < 6; i++) {
offset = 0x7e00 + i * 16;
cpu_x86_load_seg_cache(env, i,
lduw_phys(sm_state + offset),
ldq_phys(sm_state + offset + 8),
ldl_phys(sm_state + offset + 4),
(lduw_phys(sm_state + offset + 2) &
0xf0ff) << 8);
}

env->gdt.base = ldq_phys(sm_state + 0x7e68);
env->gdt.limit = ldl_phys(sm_state + 0x7e64);

env->ldt.selector = lduw_phys(sm_state + 0x7e70);
env->ldt.base = ldq_phys(sm_state + 0x7e78);
env->ldt.limit = ldl_phys(sm_state + 0x7e74);
env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;

env->idt.base = ldq_phys(sm_state + 0x7e88);
env->idt.limit = ldl_phys(sm_state + 0x7e84);

env->tr.selector = lduw_phys(sm_state + 0x7e90);
env->tr.base = ldq_phys(sm_state + 0x7e98);
env->tr.limit = ldl_phys(sm_state + 0x7e94);
env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;

EAX = ldq_phys(sm_state + 0x7ff8);
ECX = ldq_phys(sm_state + 0x7ff0);
EDX = ldq_phys(sm_state + 0x7fe8);
EBX = ldq_phys(sm_state + 0x7fe0);
ESP = ldq_phys(sm_state + 0x7fd8);
EBP = ldq_phys(sm_state + 0x7fd0);
ESI = ldq_phys(sm_state + 0x7fc8);
EDI = ldq_phys(sm_state + 0x7fc0);
for (i = 8; i < 16; i++) {
env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
}
env->eip = ldq_phys(sm_state + 0x7f78);
cpu_load_eflags(env, ldl_phys(sm_state + 0x7f70),
~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
env->dr[6] = ldl_phys(sm_state + 0x7f68);
env->dr[7] = ldl_phys(sm_state + 0x7f60);

cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48));
cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50));
cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58));

val = ldl_phys(sm_state + 0x7efc); /* revision ID */
if (val & 0x20000) {
env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff;
}
#else
cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
cpu_load_eflags(env, ldl_phys(sm_state + 0x7ff4),
~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
env->eip = ldl_phys(sm_state + 0x7ff0);
EDI = ldl_phys(sm_state + 0x7fec);
ESI = ldl_phys(sm_state + 0x7fe8);
EBP = ldl_phys(sm_state + 0x7fe4);
ESP = ldl_phys(sm_state + 0x7fe0);
EBX = ldl_phys(sm_state + 0x7fdc);
EDX = ldl_phys(sm_state + 0x7fd8);
ECX = ldl_phys(sm_state + 0x7fd4);
EAX = ldl_phys(sm_state + 0x7fd0);
env->dr[6] = ldl_phys(sm_state + 0x7fcc);
env->dr[7] = ldl_phys(sm_state + 0x7fc8);

env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
env->tr.base = ldl_phys(sm_state + 0x7f64);
env->tr.limit = ldl_phys(sm_state + 0x7f60);
env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;

env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
env->ldt.base = ldl_phys(sm_state + 0x7f80);
env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;

env->gdt.base = ldl_phys(sm_state + 0x7f74);
env->gdt.limit = ldl_phys(sm_state + 0x7f70);

env->idt.base = ldl_phys(sm_state + 0x7f58);
env->idt.limit = ldl_phys(sm_state + 0x7f54);

for (i = 0; i < 6; i++) {
if (i < 3) {
offset = 0x7f84 + i * 12;
} else {
offset = 0x7f2c + (i - 3) * 12;
}
cpu_x86_load_seg_cache(env, i,
ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
ldl_phys(sm_state + offset + 8),
ldl_phys(sm_state + offset + 4),
(ldl_phys(sm_state + offset) & 0xf0ff) << 8);
}
cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14));

val = ldl_phys(sm_state + 0x7efc); /* revision ID */
if (val & 0x20000) {
env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff;
}
#endif
CC_OP = CC_OP_EFLAGS;
env->hflags &= ~HF_SMM_MASK;
cpu_smm_update(env);

qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n");
log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
}

#endif /* !CONFIG_USER_ONLY */

void helper_into(int next_eip_addend)
{
int eflags;
Expand Down
Loading

0 comments on commit ab109e5

Please sign in to comment.