Author: wmb Date: 2008-01-31 11:15:58 +0100 (Thu, 31 Jan 2008) New Revision: 799
Modified: dev/geode/smi.fth Log: Geode SMI handler - the code is pretty tight now, using only one page of SMM RAM.
Modified: dev/geode/smi.fth =================================================================== --- dev/geode/smi.fth 2008-01-31 05:16:56 UTC (rev 798) +++ dev/geode/smi.fth 2008-01-31 10:15:58 UTC (rev 799) @@ -9,74 +9,65 @@
previous definitions
-h# 4000.0000 constant smm-base -h# 1.0000 constant smm-size +h# f.f000 constant smm-base +h# 1000 constant smm-size \ We use about 3K of this, 2K for stacks : +smm ( offset -- adr ) smm-base + ;
-h# 30 constant /smm-gdt -smm-size h# 100 - -dup constant smm-stack -dup constant smm-save-gdt 8 + -dup constant smm-gdtp 8 + -dup constant smm-gdt /smm-gdt + -dup constant smm-pdir la1+ +h# 28 constant /smm-gdt + +\ The handler code takes about h# 140 bytes + +\ The following save area + the SMM_HEADER (h# 30) takes about h# 100 +h# 200 +dup constant smm-save-gdt 8 + +dup constant smm-gdtp 8 + +dup constant smm-gdt /smm-gdt + +dup constant smm-pdir la1+ dup constant smm-forth-origin la1+ dup constant smm-forth-up la1+ +dup constant smm-forth-entry la1+
-dup constant smm-code16 h# a + -dup constant smm-data16 h# a + -dup constant smm-code32 h# a + -dup constant smm-data32 h# a + -dup constant smm-ds h# a + -dup constant smm-es h# a + -dup constant smm-fs h# a + -dup constant smm-gs h# a + -dup constant smm-ss h# a + -dup constant smm-cs h# a + -dup constant smm-esp la1+ -dup constant smm-sp wa1+ -drop +\ 10 bytes for each of 6 segment registers +dup constant smm-save-seg d# 60 + +dup constant smm-save-esp la1+ +dup constant smm-sp la1+ + \ 8x 4-byte general registers + config adr + cs3 + spare +h# 38 + constant smm-stack
-: set-descr ( base limit d.type sel offset -- ) - +smm 2>r format-descriptor ( d.descr r: sel adr ) - 2r@ 8 + w! ( d.descr r: sel adr ) - 2dup r> d! ( d.descr r: sel ) - r> smm-gdt + +smm d! ( ) +h# 300 constant smm-header + +: set-descr ( base limit d.type sel -- ) + >r format-descriptor ( d.descr r: sel ) + r> smm-gdt + +smm d! ( ) ;
: set-smm-descs ( -- ) - smm-base -1 code32 format-descriptor smm-gdt 8 + +smm d! \ Boosted code32 - - smm-base smm-size 1- code16 h# 10 smm-code16 set-descr - smm-base smm-size 1- data16 h# 18 smm-data16 set-descr - 0 -1 code32 h# 20 smm-code32 set-descr - 0 -1 data32 h# 28 smm-data32 set-descr - /smm-gdt 1- smm-gdtp +smm w! \ GDT limit +\ smm-base -1 code32 format-descriptor smm-gdt 8 + +smm d! \ Boosted code32 + smm-base smm-size 1- code16 h# 08 set-descr + smm-base smm-size 1- data16 h# 10 set-descr + 0 -1 code32 h# 18 set-descr + 0 -1 data32 h# 20 set-descr + /smm-gdt 1- smm-gdtp +smm w! \ GDT limit smm-gdt +smm smm-gdtp +smm wa1+ l! \ GDT base ;
nuser smi-sp0 nuser smi-rp0 -defer smi-return -: smi-exec ( -- ) - ." Forth SMI handler" cr - quit - smi-return -;
label smm-handler 16-bit
- cs: ds smm-ds #) svdc - cs: smm-data16 #) ds rsdc \ Now we have a data segment + cs: ds smm-save-seg d# 00 + #) svdc + cs: smm-gdt h# 10 + #) ds rsdc \ Now we have a data segment + es smm-save-seg d# 10 + #) svdc + fs smm-save-seg d# 20 + #) svdc + gs smm-save-seg d# 30 + #) svdc + ss smm-save-seg d# 40 + #) svdc + cs smm-save-seg d# 50 + #) svdc \ So we can get back to the boost segment
- es smm-es #) svdc - fs smm-fs #) svdc - gs smm-gs #) svdc - ss smm-ss #) svdc - smm-data16 #) ss rsdc \ Now we have a data segment + smm-gdt h# 10 + #) ss rsdc
- op: sp smm-esp #) mov + op: sp smm-save-esp #) mov smm-stack # sp mov \ Now we have a stack
op: pusha @@ -88,30 +79,18 @@ cr3 ax mov op: ax push sp smm-sp #) mov
-\ --- \ Get into protected mode using the same segments \ Don't bother with the IDT; we won't enable interrupts op: smm-save-gdt #) sgdt op: smm-gdtp #) lgdt
-\ Test< - \ Get into the 4G flat code-32 address space - cs smm-cs #) svdc \ So we can get back - smm-code32 #) cs rsdc \ 4G flat address space for code + cr0 ax mov 1 # al or ax cr0 mov \ Enter protected mode + op: here 7 + smm-handler - +smm h# 18 #) far jmp 32-bit - here 5 + +smm #) jmp \ Into unboosted segment
-nop nop nop nop nop nop nop - - cr0 ax mov 1 # al or ax cr0 mov \ Enter protected mode - here 2 + #) jmp - \ Reload segment registers with protected mode bits - cs: smm-data32 +smm #) ds rsdc - smm-data32 +smm #) ss rsdc - smm-data32 +smm #) es rsdc - smm-data32 +smm #) fs rsdc - smm-data32 +smm #) gs rsdc + op: h# 20 # ax mov + ax ds mov ax es mov ax fs mov ax gs mov ax ss mov
\ Turn on paging smm-pdir +smm #) ax mov @@ -121,6 +100,7 @@ \ Beginning of Forth-specific stuff smm-forth-origin +smm #) bx mov smm-forth-up +smm #) up mov + smm-forth-entry +smm #) ip mov
\ Exchange the stack and return stack pointer with the smi versions 'user sp0 sp mov @@ -132,13 +112,10 @@ sp 'user sp0 mov rp 'user rp0 mov
- \ Set the interpreter pointer - 'body smi-exec origin - # ip mov - bx ip add \ add current origin
cld c; -code (smi-return) +code (smi-return) \ This code field must be relocated after copying to SMM memory \ Exchange the stack and return stack pointer with the smi versions 'user sp0 sp mov 'user rp0 rp mov @@ -149,30 +126,24 @@ sp 'user sp0 mov rp 'user rp0 mov
-\ End of Forth-specific stuff + \ End of Forth-specific stuff
\ Turn off paging cr0 ax mov h# 8000.0000 invert # ax and ax cr0 mov \ Turn off Paging Enable bit
cr0 ax mov 1 invert # al and ax cr0 mov \ Enter real mode - here 2 + #) jmp
- - \ Reload segment registers with real mode bits - cs: smm-data16 +smm #) ss rsdc - cs: smm-data16 +smm #) ds rsdc - - \ Return to the boosted code-16 address space - smm-cs #) cs rsdc + smm-save-seg d# 50 + +smm #) cs rsdc 16-bit - here 2 + #) jmp \ 16-bit JMP zeros EIP[31:16] + op: here 5 + smm-base - #) jmp \ Decrease IP while increasing the segment register
-\ >Test + \ Reload data segment registers + cs: smm-gdt h# 10 + #) ss rsdc + cs: smm-gdt h# 10 + #) ds rsdc
op: smm-save-gdt #) lgdt
-\ --- smm-sp #) sp mov op: ax pop ax cr3 mov
@@ -182,86 +153,74 @@
op: popa
- op: smm-esp #) sp mov + op: smm-save-esp #) sp mov
- smm-ss #) ss rsdc - smm-gs #) gs rsdc - smm-fs #) fs rsdc - smm-es #) es rsdc - smm-ds #) ds rsdc + smm-save-seg d# 40 + #) ss rsdc + smm-save-seg d# 30 + #) gs rsdc + smm-save-seg d# 20 + #) fs rsdc + smm-save-seg d# 10 + #) es rsdc + smm-save-seg d# 00 + #) ds rsdc
rsm end-code here smm-handler - constant /smm-handler
+: smi-return ( -- ) [ ' (smi-return) smm-handler - +smm ] literal execute ; +defer handle-smi ' noop is handle-smi +create smm-exec ] handle-smi smi-return [ + : setup-smi ( -- ) - \ Map the SMM region to physical memory at e.0000 + \ This is how you would map the SMM region to physical memory at 4000.0000 \ This is a Base Mask Offset descriptor - the base address \ is 4000.0000 and to that is added the offset c00e.0000 \ to give the address 000e.0000 in the GLMC address space. - \ The mask is ffff.0000 , i.e. 64K - h# 2.c00e0.40000.ffff0. h# 1000.0026 msr! + \ The mask is ffff.f000 , i.e. 4K
- \ Put 64K SMM memory at 4000.0000 in the processor linear address space + \ This is unnecessary if the SMM memory is in a region that is + \ already mapped with a descriptor + \ h# 2.c00e0.40000.fffff. h# 1000.0026 msr! + + \ Put 4K SMM memory at 000f.f000 in the processor linear address space \ Cacheable in SMM mode, non-cacheable otherwise - h# 4000f.0.00.40000.1.01. h# 180e msr! + \ Depends on smm-base and smm-size + h# 000ff.0.00.000ff.1.01. h# 180e msr!
\ Base Limit \ smm-base smm-size 1- h# 133b msr! + \ The limit here must be large enough to cover the code address + \ between the time that we reenter real mode and the time we + \ reestablish the boosted descriptor. smm-base -1 h# 133b msr! \ Big limit
- smm-base smm-size + 0 h# 132b msr! \ Offset of SMM Header + smm-base smm-header + 0 h# 132b msr! \ Offset of SMM Header
h# 18. h# 1301 msr! \ Enable IO and software SMI
- smm-base dup smm-size -1 mmu-map + \ Unnecessary if already in mapped memory + \ smm-base dup smm-size -1 mmu-map
smm-handler smm-base /smm-handler move
+ \ Relocate the code field of the code word that is embedded in the sequence ['] (smi-return) smm-handler - +smm ( cfa-adr ) dup ta1+ swap token!
set-smm-descs cr3@ smm-pdir +smm l! + origin smm-forth-origin +smm l! + smm-exec smm-forth-entry +smm l! up@ smm-forth-up +smm l! - h# 1000 +smm smi-sp0 ! - h# 2000 +smm smi-rp0 ! + h# 800 +smm smi-sp0 ! + h# c00 +smm smi-rp0 ! ; -: do-smi-return ( -- ) - ['] (smi-return) smm-handler - +smm execute -; -' do-smi-return is smi-return
+: smi-interact ( -- ) ." In SMI" cr quit ; +' smi-interact is handle-smi + : enable-virtual-pci ( -- ) h# 5000.2012 msr@ swap h# 8002 or swap h# 5000.2002 msr! \ Virtualize devices f and 1 h# 5000.2002 msr@ swap 8 invert and swap h# 5000.2002 msr! \ Enable SSMI for config accesses ;
- -code smi smint ax push c; - -\ Forth stuff -[ifdef] notyet -[then] - -[ifdef] notyet -XXX code to return from Forth -[then] - -[ifdef] notyet - \ We are running in a segment that is identity mapped - cr0 ax mov h# 8000.0000 invert # ax and ax cr0 mov \ Turn off Paging Enable bit -[then] - -label emita - op: dx dx xor dx dx xor - h# 3fd # dx mov - begin dx al in h# 20 # al and 0<> until - h# 41 # al mov h# f8 # dl mov al dx out - begin again -\ h# 3fd # dx mov -\ begin dx al in h# 20 # al and 0<> until -end-code -here emita - constant /emita -: puta ( adr -- ) emita swap /emita move ; +code smi smint c;