Author: wmb Date: 2009-11-13 23:53:08 +0100 (Fri, 13 Nov 2009) New Revision: 1477
Modified: cpu/x86/pc/biosints.fth cpu/x86/pc/olpc/security.fth cpu/x86/pc/olpc/via/addrs.fth cpu/x86/pc/olpc/via/sound.fth dev/geode/smi.fth dev/via/smi.fth Log: OLPC trac 9486 - Suite of fixes to the SMI handler and related BIOS emulation code.
Modified: cpu/x86/pc/biosints.fth =================================================================== --- cpu/x86/pc/biosints.fth 2009-11-13 22:51:37 UTC (rev 1476) +++ cpu/x86/pc/biosints.fth 2009-11-13 22:53:08 UTC (rev 1477) @@ -1,7 +1,7 @@ purpose: Emulate legacy PC BIOS real-mode INTs \ See license at end of file
-8 /l* buffer: init-regs +/rm-regs buffer: init-regs h# 80 value bios-boot-dev#
: rm-es@ caller-regs >rm-es w@ ; @@ -60,10 +60,24 @@
: rm-si@ caller-regs >rm-esi w@ ;
+[ifdef] >rm-retaddr : rm-retaddr@ caller-regs >rm-retaddr seg:off@ ; +[then] +[ifdef] >rm-eip +\ : rm-retaddr@ caller-regs >rm-eip @ ; +: rm-caller-sp caller-regs >rm-esp @ caller-regs >rm-ss w@ seg:off> ; +: rm-retaddr@ rm-caller-sp seg:off@ ; +: .rm-stack rm-caller-sp h# 40 wdump ; +[then]
+[ifdef] >rm-flags : rm-flags@ caller-regs >rm-flags w@ ; : rm-flags! caller-regs >rm-flags w! ; +[then] +[ifdef] >rm-eflags +: rm-flags@ caller-regs >rm-eflags @ ; +: rm-flags! caller-regs >rm-eflags ! ; +[then]
: rm-set-cf rm-flags@ 1 or rm-flags! ; : rm-clr-cf rm-flags@ 1 invert and rm-flags! ; @@ -110,7 +124,9 @@
: set-mode3 ( -- ) text-off \ Stop using OFW screen output +[ifdef] smi-access-fb smi-access-fb [then] " text-mode3" screen-ih $call-method +[ifdef] smi-unaccess-fb smi-unaccess-fb [then] ; \ VBE status: AL = 4f -> function supported else not supported \ AH = 0: success 1: fail 2: not supported in this config 3: invalid in this mode @@ -401,8 +417,10 @@ ;
: set-mode12 ( -- ) + text-off \ Stop using OFW output to screen +[ifdef] smi-access-fb smi-access-fb [then] " graphics-mode12" " screen-ih" eval $call-method - text-off \ Stop using OFW output to screen +[ifdef] smi-unaccess-fb smi-unaccess-fb [then] ; : set-video-mode ( mode -- ) case @@ -781,7 +799,7 @@
: get-conf ( -- ) sysconf rm-buf 8 move - rm-buf >seg:off 0 rm-es! rm-bx! + rm-buf >seg:off rm-es! rm-bx! 0 rm-ax! ;
@@ -792,10 +810,19 @@ endcase ;
+: gate-a20 ( -- ) + rm-al@ case + h# 00 of rm-set-cf endof \ Disable - We don't support disabling A20 + h# 01 of 0 rm-ah! endof \ Enable - We always leave it enabled, so return OK (00) status + h# 02 of 1 rm-ax! endof \ Status - Enabled (01) in AL , OK (00) in AH + h# 03 of 1 rm-bx! 0 rm-ah! endof \ Which - Port92 (01) in BX, OK (00) in AH + endcase +; : system-int ( -- ) \ INT 15 handler noshow rm-clr-cf rm-ah@ case + h# 24 of gate-a20 endof h# 91 of noshow 0 rm-ah! endof \ "pause" while waiting for I/O noop h# 53 of apm endof @@ -1061,17 +1088,18 @@ loaded is-mbr? if prep-rm loaded mbr-base swap move -\ init-regs /sregs+gregs erase - \ XXX + init-regs /rm-regs erase bios-boot-dev# init-regs >rm-edx c! \ DL exit then init-program ; +defer rm-go-hook ' noop to rm-go-hook \ " rm-go" ' boot-command set-config-string-default : execute-buffer ( adr len -- ) rm-prepped? if ( adr len ) 2drop ( ) + rm-go-hook \ usb-quiet ( ) init-regs mbr-base rm-run ( ) exit \ Precautionary; rm-run shouldn't return @@ -1141,8 +1169,10 @@ " xp" device-name : open bypass-bios-boot? if false exit then - " sd:1" ntfs? if - " sd:0" set-hd-boot + " ext:1" ntfs? if + " ext:0" set-hd-boot + " sound-end" evaluate + true exit then false @@ -1185,10 +1215,13 @@
label xx h# 99 # al mov al h# 80 # out begin again end-code here xx - constant /xx +: @.w ( -- ) w@ 5 u.r ; +: @.l ( -- ) @ 9 u.r ; : put-xx ( adr -- ) xx swap /xx move ; : .lreg ( adr -- adr' ) 4 - dup l@ 9 u.r ; : .wreg ( adr -- adr' ) 2 - dup w@ 5 u.r ; : .caller-regs ( -- ) +[ifdef] >rm-retaddr ." AX CX DX BX SP BP SI DI" cr caller-regs >rm-eax 4 + 8 0 do .lreg loop cr cr @@ -1197,6 +1230,27 @@ drop rm-retaddr@ 9 u.r 2 spaces rm-flags@ 5 u.r cr +[else] + ." AX BX CX DX BP SI DI SP" cr + caller-regs >rm-eax @.l + caller-regs >rm-ebx @.l + caller-regs >rm-ecx @.l + caller-regs >rm-edx @.l + caller-regs >rm-ebp @.l + caller-regs >rm-esi @.l + caller-regs >rm-edi @.l + caller-regs >rm-esp @.l + cr cr + ." CS DS ES FS GS SS PC FLAGS" cr + caller-regs >rm-cs @.w + caller-regs >rm-ds @.w + caller-regs >rm-es @.w + caller-regs >rm-fs @.w + caller-regs >rm-gs @.w + caller-regs >rm-ss @.w + rm-retaddr@ 9 u.r 2 spaces + rm-flags@ 5 u.r cr +[then] ;
: egadump ( -- )
Modified: cpu/x86/pc/olpc/security.fth =================================================================== --- cpu/x86/pc/olpc/security.fth 2009-11-13 22:51:37 UTC (rev 1476) +++ cpu/x86/pc/olpc/security.fth 2009-11-13 22:53:08 UTC (rev 1477) @@ -3,6 +3,15 @@
\ Specs at http://wiki.laptop.org/go/Firmware_Security
+patch noop suspend-interact suspend + +: rm-chain-visible ( -- ) + [ ' rm-go-hook behavior compile, ] \ Chain to old behavior + visible +; +' rm-chain-visible to rm-go-hook + + : ?unfreeze ( -- ) game-key@ button-check and if frozen? if unfreeze visible banner then
Modified: cpu/x86/pc/olpc/via/addrs.fth =================================================================== --- cpu/x86/pc/olpc/via/addrs.fth 2009-11-13 22:51:37 UTC (rev 1476) +++ cpu/x86/pc/olpc/via/addrs.fth 2009-11-13 22:53:08 UTC (rev 1477) @@ -73,6 +73,11 @@ h# e01c0 constant dbgp-adr h# e0200 constant madt-adr \ MADT is 5a bytes long h# e0280 constant hpet-adr + +h# e1000 constant smm-sp0 +h# e1400 constant smm-rp0 +h# e1800 constant smm-gdt + h# fc000 constant dsdt-adr h# fd000 constant ssdt-adr
@@ -82,6 +87,8 @@ h# fff48 constant video-mode-adr \ Saves display mode for resume code \ h# fff4c constant next-adr
+h# fff80 constant 'int10-dispatch + h# 4fff constant native-mode#
h# 3e.0000 constant inflate-base
Modified: cpu/x86/pc/olpc/via/sound.fth =================================================================== --- cpu/x86/pc/olpc/via/sound.fth 2009-11-13 22:51:37 UTC (rev 1476) +++ cpu/x86/pc/olpc/via/sound.fth 2009-11-13 22:53:08 UTC (rev 1477) @@ -1,8 +1,16 @@ -: audio-quiet ( -- ) - [ ' go-hook behavior compile, ] \ Chain to old behavior +: close-audio ( -- ) audio-ih if audio-ih close-dev 0 to audio-ih then ; +: audio-quiet ( -- ) + [ ' go-hook behavior compile, ] \ Chain to old behavior + close-audio +; ' audio-quiet to go-hook +: xp-wait-audio ( -- ) + [ ' rm-go-hook behavior compile, ] \ Chain to old behavior + sound-end close-audio +; +' xp-wait-audio to rm-go-hook
Modified: dev/geode/smi.fth =================================================================== --- dev/geode/smi.fth 2009-11-13 22:51:37 UTC (rev 1476) +++ dev/geode/smi.fth 2009-11-13 22:53:08 UTC (rev 1477) @@ -1319,4 +1319,4 @@ 4 field >rm-eax 4 field >rm-retaddr 2 field >rm-flags -drop +constant /rm-regs
Modified: dev/via/smi.fth =================================================================== --- dev/via/smi.fth 2009-11-13 22:51:37 UTC (rev 1476) +++ dev/via/smi.fth 2009-11-13 22:53:08 UTC (rev 1477) @@ -60,14 +60,14 @@ : pm-data ( offset "name" -- offset' ) +smm constant ;
\ Layout of SMM memory area: -h# 8000 smm-data smm-gdt \ Entry/exit handler code at the entry offset +\ h# 8000 smm-data smm-gdt \ Entry/exit handler code at the entry offset \ The GDT is embedded in the code wad \ The handler code takes about h# 160 bytes
-h# f400 pm-data smm-sp0 \ SMM Forth data stack - h# 400 bytes -h# f800 pm-data smm-rp0 \ SMM Forth return stack - h# 400 bytes +\ h# f400 pm-data smm-sp0 \ SMM Forth data stack - h# 400 bytes +\ h# f800 pm-data smm-rp0 \ SMM Forth return stack - h# 400 bytes
-h# fc00 pm-data 'int10-dispatch \ Array of instruction sequences for bouncing INTs through SMI +\ h# fc00 pm-data 'int10-dispatch \ Array of instruction sequences for bouncing INTs through SMI
\ fcxx - fcff available
@@ -123,8 +123,11 @@ h# ff70 smm-data smm-gs-base h# ff74 smm-data smm-gs-access
+h# ff78 smm-data smm-ldtr-limit +h# ff7c smm-data smm-ldtr-base +h# ff80 smm-data smm-ldtr-access + h# ff84 smm-data smm-gdtr-limit - h# ff88 smm-data smm-gdtr-base h# ff8c smm-data smm-gdtr-access
@@ -159,15 +162,53 @@ h# fff8 smm-data smm-cr3 h# fffc smm-data smm-cr0
+\ Layout of saved registers, used by biosints.fth + +: caller-regs ( -- adr ) smm-es +smm ; + +0 value rm-regs + +struct + 4 field >rm-es + 4 field >rm-cs + 4 field >rm-ss + 4 field >rm-ds + 4 field >rm-fs + 4 field >rm-gs + d# 16 + \ LDTR, TR, DR7, DR6 + 4 field >rm-eax + 4 field >rm-ecx + 4 field >rm-edx + 4 field >rm-ebx + 4 field >rm-esp + 4 field >rm-ebp + 4 field >rm-esi + 4 field >rm-edi + 4 field >rm-eip + 4 field >rm-eflags +constant /rm-regs + \ The basic SMI gateway. This code lives at (is copied to) smm-base + h# 8000. \ It executes when the processor enters System Management Mode (SMM) \ for whatever reason. It saves a bunch of state, sets up the world \ so Forth code can run (in 32-bit protected mode), and runs the Forth \ handler - typically "smi-dispatch" (via smm-exec and handle-smi).
+create smm-gdt-template + /smm-gdt 1- w, smm-gdt l, \ GDT pointer - limit.w base.l + 0 w, + + smm-base smm-size 1- code16 format-descriptor swap l, l, \ 8 - smm-c16 + smm-base smm-size 1- data16 format-descriptor swap l, l, \ 10 - smm-d16 + 0 -1 code32 format-descriptor swap l, l, \ 18 - smm-c32 + 0 -1 data32 format-descriptor swap l, l, \ 20 - smm-d32 + \ End of GDT + + label smi-handler 16-bit - + +0 [if] \ GDT (with jump tucked in at the beginning) \ We put the GDT right at the beginning and use the first entry (which \ cannot be used as a selector) for a 2-byte jmp and the 6-byte GDT pointer @@ -180,14 +221,19 @@ 0 -1 code32 format-descriptor swap l, l, \ 18 - smm-c32 0 -1 data32 format-descriptor swap l, l, \ 20 - smm-d32 \ End of GDT +[then]
cs ax mov ax ds mov
wbinvd
+0 [if] \ Get into protected mode using the same segments \ Don't bother with the IDT; we won't enable interrupts op: smm-gdt 2+ #) lgdt +[else] + ad: op: smm-gdt smm-base - #) lgdt +[then]
\ ascii a report
@@ -262,6 +308,7 @@ here smi-handler - constant /smi-handler
: smm@ ( offset -- n ) +smm @ ; +: smm! ( n offset -- ) +smm ! ;
\ Address of segment registers : 'smm-eax ( -- adr ) smm-eax +smm ; @@ -272,19 +319,43 @@ rshift h# ffc and + l@ dup h# fff invert and swap 1 and 0= ; +\ Finds a page table or page directory entry +\ Implementation factor of (smm>physical) +: >ptable64 ( table vadr shift -- table' unmapped? ) + rshift h# ff8 and + l@ \ Ignore high word for now + dup h# fff invert and swap 1 and 0= +;
\ Converts a virtual address to a physical address via the page tables \ This is used by debugging tools, so that we can look at OS resources \ via their virtual addresses while we are running with paging disabled. \ XXX need to handle mapped-at-pde-level defer smm>physical +: ?unmapped ( unmapped? -- ) +\ abort" Unmapped" + if ." Unmapped " debug-me then +; +: vadr>pframe64 ( vadr pdpt -- padr ) + over d# 27 >ptable64 ?unmapped ( vadr pdir ) + over d# 18 >ptable64 ?unmapped ( vadr ptab ) + over d# 9 >ptable64 ?unmapped ( vadr pframe ) +; +: vadr>pframe32 ( vadr pdir -- vadr pframe ) + over d# 20 >ptable ?unmapped ( vadr ptab ) + over d# 10 >ptable ?unmapped ( vadr pframe ) +; + : (smm>physical) ( vadr -- padr ) -\ smm-cr0 smm@ h# 8000.0000 and 0= if exit then - cr3@ ( vadr pdir ) - over d# 20 >ptable abort" Unmapped" ( vadr ptab ) - over d# 10 >ptable abort" Unmapped" ( vadr pframe ) + smm-cr3 smm@ ( vadr pdir ) + smm-cr4 smm@ h# 20 and if \ Physical Address Extension enabled + vadr>pframe64 + else + vadr>pframe32 + then swap h# fff and + + ; + ' (smm>physical) to smm>physical
: smm-map? ( vadr -- ) smm>physical . ; @@ -335,18 +406,25 @@ \ bios-int-smi is for accesses to the 0x30..0x3f I/O port bank that we "steal" for \ bouncing BIOS INTs into SMM.
+: caller-32bit? ( -- flag ) smm-cs-access smm@ h# 4000 and ; + +: caller-sp ( -- laddr ) + caller-32bit? if smm-esp smm@ else rm-sp then +; + : bios-int-smi ( -- ) + caller-32bit? if noop exit then \ Handle BIOS INTs that were bounced into SMM by accessing \ I/O ports 0x30..0x3f h# 58 acpi-w@ dup h# fff0 and h# 30 = if \ Via h# 20 - to rm-int@ - rm-sp la1+ >caller-physical w@ smm-eflags +smm w! + caller-sp la1+ >caller-physical w@ smm-eflags +smm w! \ Bias by -2 to point to INT instruction [ifdef] notyet - rm-sp >caller-physical l@ 2- smm-retaddr l! + rm-sp >caller-physical l@ 2- smm-eip l! [then] handle-bios-call - smm-eflags +smm w@ rm-sp la1+ >caller-physical w! + smm-eflags +smm w@ caller-sp la1+ >caller-physical w! exit else drop @@ -363,12 +441,9 @@ \ It's used to implement the ACPI "resume from S3" semantics that \ require jumping to a given address in real mode.
--1 value rm-entry-adr -0 value rm-regs - : #smint ( n -- ) h# 2f acpi-b! ; \ Via
-: rm-run ( 'gregs eip -- ) to rm-entry-adr to rm-regs h# f0 #smint ; +: rm-run ( 'gregs eip -- ) swap to rm-regs rm-regs >rm-eip ! h# f0 #smint ;
defer suspend-devices ' noop to suspend-devices defer resume-devices ' noop to resume-devices @@ -454,50 +529,60 @@ : l!++ ( adr l -- adr' ) over l! la1+ ; : w!++ ( adr w -- adr' ) over w! wa1+ ;
-[ifdef] notyet -code rm-lidt ( -- ) smm-rmidt #) lidt c; -[then] - \ rm-setup fudges the saved SMM state so that, instead of returning \ to the context that invoked the SMI, the next exit from SMM returns \ to the address "eip" in real mode. This is an implementation \ factor of the "rm-run" mechanism.
+: set-segment ( base limit access 'seg-save -- ) + >r ( base limit access ) + r@ 8 + smm! ( base limit ) \ Set access rights field + r@ smm! ( base ) \ Set limit field + r> 4 + smm! ( ) \ Set base field +; +: set-data-segment ( base 'seg-save -- ) + \ >r h# ffff h# 4093 r> set-segment + >r h# ffffffff h# 0092 r> set-segment +; + : rm-setup ( -- ) -[ifdef] notyet - rm-entry-adr >seg:off 2>r ( off seg ) + rm-regs >rm-eip @ >seg:off ( off seg ) + swap smm-eip smm! ( seg ) + dup smm-cs smm! ( seg ) + 4 lshift h# ffff h# 009a smm-cs-limit set-segment
- smm-header h# 30 - ( adr ) - h# 38 l!++ ( adr' ) \ SMM_CTL - 0 l!++ ( adr' ) \ I/O DATA - 0 l!++ ( adr' ) \ I/O ADDRESS, I/O SIZE - h# 938009 l!++ ( adr' ) \ SS_FLAGS, SMM Flags - h# ffff l!++ ( adr' ) \ CS_LIMIT - r@ 4 lshift l!++ ( adr' ) \ CS_BASE + rm-regs >rm-ds w@ dup smm-ds-limit set-data-segment smm-ds smm! + rm-regs >rm-es w@ dup smm-es-limit set-data-segment smm-es smm! + rm-regs >rm-fs w@ dup smm-fs-limit set-data-segment smm-fs smm! + rm-regs >rm-gs w@ dup smm-gs-limit set-data-segment smm-gs smm! + rm-regs >rm-ss w@ dup smm-ss-limit set-data-segment smm-ss smm!
- r> h# 9a wljoin l!++ ( adr' ) \ CS_FLAGS.CS_INDEX - r> l!++ ( adr' ) \ NEXT_IP - 0 l!++ ( adr' ) \ CURRENT_IP - h# 10 l!++ ( adr' ) \ CR0 - h# 2 l!++ ( adr' ) \ EFLAGS - h# 400 l!++ ( adr' ) \ DR7 - drop + 0 h# 3ff h# 82 smm-idtr-limit set-segment + 0 h# ffff h# 83 smm-tr-limit set-segment 0 smm-tr smm! + 0 0 h# 82 smm-ldtr-limit set-segment 0 smm-ldtr smm!
- 0 smm-esp +smm l! + \ gdtr - leave alone, GDT shouldn't matter in real mode + \ cr3 - leave alone, PDE base shouldn't matter with paging disabled
- smm-save-seg +smm - h# ffff l!++ h# 9300 l!++ 0 w!++ \ DS - h# ffff l!++ h# 9300 l!++ 0 w!++ \ ES - h# ffff l!++ h# 9300 l!++ 0 w!++ \ FS - h# ffff l!++ h# 9300 l!++ 0 w!++ \ GS - h# ffff l!++ h# 9300 l!++ 0 w!++ \ SS - drop + h# 10 smm-cr0 smm! \ Paging and Protected Mode off + h# 10 smm-cr4 smm! \ Page size extension on + h# ffff0ff0 smm-dr6 smm! \ Value after init (status register) + h# 400 smm-dr7 smm! \ Value after init - no breakpoints set
- h# ffff smm-rmidt w! 0 smm-rmidt wa1+ l! \ Limit and base + 0 smm-tr smm!
- \ Interrupts are off because we are in SMM - rm-lidt -[then] + 0 smm-io-restart smm! \ Clear IO-restart and HLT-restart + + rm-regs >rm-eflags @ 2 or smm-eflags smm! \ 2 bit is "Must Be One" + + rm-regs >rm-esp @ smm-esp smm! + rm-regs >rm-eax @ smm-eax smm! + rm-regs >rm-ebx @ smm-ebx smm! + rm-regs >rm-ecx @ smm-ecx smm! + rm-regs >rm-edx @ smm-edx smm! + rm-regs >rm-ebp @ smm-ebp smm! + rm-regs >rm-esi @ smm-esi smm! + rm-regs >rm-edi @ smm-edi smm! ; \ : rm-init-program ( eip -- ) rm-init-program rm-return ;
@@ -509,12 +594,11 @@ smi-debug? if ." SOFT" cr then h# 2f acpi-b@ h# f0 = if rm-setup - -1 to rm-entry-adr exit then
[ifdef] notyet - smm-pc smm-retaddr l! \ So .caller-regs will work + smm-pc smm-eip l! \ So .caller-regs will work sbpadr @ if sbpadr @ smm>physical smm-pc smm>physical <> if ." Not at SMI breakpoint!" cr @@ -633,6 +717,12 @@ 0 #smint \ Trigger SMI ;
+: smi-access-fb ( -- ) + h# 383 config-b@ 2 or h# 383 config-b! \ Direct SMM mode data accesses to A/Bxxxx range to frame buffer +; +: smi-unaccess-fb ( -- ) + h# 383 config-b@ 2 invert and h# 383 config-b! \ Restore SMM mode data accesses to A/Bxxxx range to memory +; \ Call this to enable SMI support : setup-smi ( -- ) h# 383 config-b@ 1 or h# 383 config-b! \ Enable A/Bxxxx range as memory instead of frame buffer @@ -650,6 +740,7 @@ smm-sp0 smm-save-sp0 ! smm-rp0 smm-save-rp0 !
+ smm-gdt-template smm-gdt /smm-gdt move smi-handler smm-base +smm-offset /smi-handler move
\ Relocate the code field of the code word that is embedded in the sequence @@ -667,27 +758,3 @@ 4 4 acpi-w! \ Trigger BIOS Release ; [then] - -\ Layout of saved registers, used by biosints.fth - -: caller-regs ( -- adr ) smm-es +smm ; - -struct - 4 field >rm-es - 4 field >rm-cs - 4 field >rm-ss - 4 field >rm-ds - 4 field >rm-fs - 4 field >rm-gs - d# 16 + \ LDTR, TR, DR7, DR6 - 4 field >rm-eax - 4 field >rm-edx - 4 field >rm-ecx - 4 field >rm-ebx - 4 field >rm-exx - 4 field >rm-ebp - 4 field >rm-esi - 4 field >rm-edi - 4 field >rm-retaddr \ EIP - 4 field >rm-flags -drop