diff options
author | Sven Schnelle <svens@stackframe.org> | 2011-06-17 20:47:08 +0200 |
---|---|---|
committer | Sven Schnelle <svens@stackframe.org> | 2011-06-18 10:02:22 +0200 |
commit | 47b3fb403d5b7f7fc756d3567bacf66ea0c1b9e9 (patch) | |
tree | 375973c6898210b806b5a971f1691e7ba63d626b /src/cpu/x86/smm | |
parent | 00d46499a2b4a62af4ad5c22e229460d4da13449 (diff) |
SMM: flush caches after disabling caching
Fixes spurious SMI crashes i've seen, and ACPI/SMM interaction.
For reference, the mail i've sent to ML with the bugreport:
whenever i've docked/undocked the thinkpad from the docking station,
i had to do that twice to get the action actually to happen.
First i thought that would be some error in the ACPI code. Here's a
short explanation how docking/undocking works:
1) ACPI EC Event 0x37 Handler is executed (EC sends event 0x37 on dock)
2) _Q37 does a Trap(SMI_DOCK_CONNECT). Trap is declared as follows:
a) Store(Arg0, SMIF) // SMIF is in the GNVS Memory Range
b) Store(0, 0x808) // Generates I/O Trap to SMM
c) // SMM is executed
d) Return (SMIF) // Return Result in SMIF
I've verified that a) is really executed with ACPI debugging in the
Linux Kernel. It writes the correct value to GNVS Memory. After that,
i've logged the SMIF value in SMM, which contains some random (or
former) value of SMIF.
So i've added the GNVS area to /proc/mtrr which made things work.
I've also tried a wbinvd() in SMM code, with the same result.
After reading the src/cpu/x86/smm/smmhandler.S code, i've recognized
that it starts with:
movw $(smm_gdtptr16 - smm_handler_start +
SMM_HANDLER_OFFSET), %bx
data32 lgdt %cs:(%bx)
movl %cr0, %eax
andl $0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */
orl $0x60000001, %eax /* CD, NW, PE = 1 */
movl %eax, %cr0
/* Enable protected mode */
data32 ljmp $0x08, $1f
...which disables caching in SMM code, but doesn't flush the cache.
So the problem is:
- the linux axpi write to the SMIF GNVS Area will be written to Cache,
because GNVS is WB
- the SMM code runs with cache disabled, and fetches SMIF directly from
Memory, which is some other value
Possible Solutions:
- enable cache in SMM (yeah, cache poisoning...)
- flush caches in SMM (really expensive)
- mark GNVS as UC in Memory Map (will only work if OS
really marks that Area as UC. Checked various vendor BIOSes, none
of them are marking NVS as UC. So this seems rather uncommon.)
- flush only the cache line which contains GNVS. Would fix this
particular problem, but users/developers could see other Bugs like
this. And not everyone likes to debug such problems. So i won't like
this solution.
Change-Id: Ie60bf91c5fd1491bc3452d5d9b7fc8eae39fd77a
Signed-off-by: Sven Schnelle <svens@stackframe.org>
Reviewed-on: http://review.coreboot.org/39
Tested-by: build bot (Jenkins)
Diffstat (limited to 'src/cpu/x86/smm')
-rw-r--r-- | src/cpu/x86/smm/smmhandler.S | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/src/cpu/x86/smm/smmhandler.S b/src/cpu/x86/smm/smmhandler.S index 3dd0b14c5a..450aa538f8 100644 --- a/src/cpu/x86/smm/smmhandler.S +++ b/src/cpu/x86/smm/smmhandler.S @@ -83,6 +83,7 @@ smm_handler_start: andl $0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */ orl $0x60000001, %eax /* CD, NW, PE = 1 */ movl %eax, %cr0 + wbinvd /* Enable protected mode */ data32 ljmp $0x08, $1f |