[openfirmware] r1421 - cpu/x86/pc dev/geode dev/via

svn at openfirmware.info svn at openfirmware.info
Fri Oct 16 01:07:27 CEST 2009


Author: wmb
Date: 2009-10-16 01:07:26 +0200 (Fri, 16 Oct 2009)
New Revision: 1421

Added:
   dev/via/smi.fth
Modified:
   cpu/x86/pc/biosints.fth
   dev/geode/smi.fth
Log:
Via - initial checkin of SMI support.


Modified: cpu/x86/pc/biosints.fth
===================================================================
--- cpu/x86/pc/biosints.fth	2009-10-12 20:41:07 UTC (rev 1420)
+++ cpu/x86/pc/biosints.fth	2009-10-15 23:07:26 UTC (rev 1421)
@@ -4,23 +4,6 @@
 8 /l* buffer: init-regs
 h# 80 value bios-boot-dev#
 
-struct
-  2 field >rm-gs
-  2 field >rm-fs
-  2 field >rm-es
-  2 field >rm-ds
-  4 field >rm-edi
-  4 field >rm-esi
-  4 field >rm-ebp
-  4 field >rm-exx
-  4 field >rm-ebx
-  4 field >rm-edx
-  4 field >rm-ecx
-  4 field >rm-eax
-  4 field >rm-retaddr
-  2 field >rm-flags
-drop
-
 : rm-es@  caller-regs >rm-es w@  ;
 : rm-es!  caller-regs >rm-es w!  ;
 

Modified: dev/geode/smi.fth
===================================================================
--- dev/geode/smi.fth	2009-10-12 20:41:07 UTC (rev 1420)
+++ dev/geode/smi.fth	2009-10-15 23:07:26 UTC (rev 1421)
@@ -1303,8 +1303,20 @@
    loop
 ;
 
-
-\ : caller-regs  ( -- adr )  smm-sregs  ;
-\ : rm-buf  ( -- adr )  smm-rmbuf  ;
-
-\ : doit  setup-smi disk-name open-dev is disk-ih get-mbr usb-quiet  ff 21 pc! h# 380f  h# 7c18 w!  smi ;
+\ Layout of saved registers
+struct
+  2 field >rm-gs
+  2 field >rm-fs
+  2 field >rm-es
+  2 field >rm-ds
+  4 field >rm-edi
+  4 field >rm-esi
+  4 field >rm-ebp
+  4 field >rm-exx
+  4 field >rm-ebx
+  4 field >rm-edx
+  4 field >rm-ecx
+  4 field >rm-eax
+  4 field >rm-retaddr
+  2 field >rm-flags
+drop

Added: dev/via/smi.fth
===================================================================
--- dev/via/smi.fth	                        (rev 0)
+++ dev/via/smi.fth	2009-10-15 23:07:26 UTC (rev 1421)
@@ -0,0 +1,693 @@
+purpose: SMI setup and handler for Intel-compatible system management mode
+
+also assembler definitions
+: rsm    ( -- )  prefix-0f  h# aa asm8,  ;
+previous definitions
+
+\ Location of the SMM handler code...
+\ The general naming convention here is that smm-* refers to
+\ addresses within the memory that is set aside for SMI handling.
+\ smi-* refers to stuff in the Forth domain.
+
+h#    3.8000 constant smm-base0   \ Default after power up
+h#    a.0000 constant smm-base    \ We switch to this - hidden behind the VGA frame buffer
+h#    1.0000 constant smm-size
+
+: +smm-offset  h# 8000 +  ;
+: +smm  ( segment-relative-adr -- adr )  smm-base +  ;
+: -smm  ( adr -- segment-relative-adr )  smm-base -  ;
+
+\ This is a trick for using SMM to handle BIOS INTs.  The problem it solves
+\ is that Windows sometimes calls the BIOS from V86 mode instead of real mode.
+\ V86 mode prevents easy entry into protected mode (and we want to run OFW
+\ in protected mode), so we first trap into SMM by accessing some emulated
+\ registers, and run OFW code from SMM protected mode.  The following is a
+\ table of "INT handler" instruction sequences indexed by the INT number.
+
+label int-entry
+   16-bit
+   al  h# 30 #  out  iret  nop
+   al  h# 31 #  out  iret  nop
+   al  h# 32 #  out  iret  nop
+   al  h# 33 #  out  iret  nop
+   al  h# 34 #  out  iret  nop
+   al  h# 35 #  out  iret  nop
+   al  h# 36 #  out  iret  nop
+   al  h# 37 #  out  iret  nop
+   al  h# 38 #  out  iret  nop
+   al  h# 39 #  out  iret  nop
+   al  h# 3a #  out  iret  nop
+   al  h# 3b #  out  iret  nop
+   al  h# 3c #  out  iret  nop
+   al  h# 3d #  out  iret  nop
+   al  h# 3e #  out  iret  nop
+   al  h# 3f #  out  iret  nop
+end-code
+here int-entry -  constant /int-entry
+
+\ Data structures for the SMM gateway
+
+h# 28 constant /smm-gdt   \ GDT size - 4 entries plus nonce entry at beginning
+
+\ Protected mode selector values
+h#  8 constant smm-c16
+h# 10 constant smm-d16
+h# 18 constant smm-c32
+h# 20 constant smm-d32
+
+\ For stuff that grows down - add the offset first
+: smm-data ( offset "name" -- offset' )       constant  ;
+: 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
+                                 \ 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# fc00  pm-data 'int10-dispatch \ Array of instruction sequences for bouncing INTs through SMI
+
+\ fcxx - fcff available
+
+\ These locations are set once at installation time.  The entry code reads them.
+h# fd00 pm-data smm-pdir         \ Page directory pointer so we can enable paging
+h# fde4 pm-data smm-forth-base   \ Base address of the Forth dictionary
+h# fde8 pm-data smm-forth-up     \ Base address of the Forth user area
+h# fdec pm-data smm-forth-entry  \ Entry address of Forth SMI handler
+h# fdf0 pm-data smm-save-sp0     \ Exchanged with sp0 user variable
+h# fdf4 pm-data smm-save-rp0     \ Exchanged with rp0 user variable
+
+\ The following locations are for saving/restoring registers
+
+h# fdf8 pm-data  smm-save-cf8    \ Saved value of PCI config index
+
+\ The following locations are defined by the CPU
+
+\ h# fe00 .. 7ef7 - reserved
+
+h# fef8 smm-data smm-smbase
+h# fefc smm-data smm-revid
+h# fff0 smm-data smm-io-restart
+h# ff02 smm-data smm-hlt-restart
+
+h# ff04 smm-data smm-io-restart-edi
+h# ff08 smm-data smm-io-restart-ecx
+h# ff0c smm-data smm-io-restart-esi
+h# ff10 smm-data smm-io-restart-eip
+
+h# ff28 smm-data smm-cr4
+
+h# ff30 smm-data smm-es-limit
+h# ff34 smm-data smm-es-base
+h# ff38 smm-data smm-es-access
+
+h# ff3c smm-data smm-cs-limit
+h# ff40 smm-data smm-cs-base
+h# ff44 smm-data smm-cs-access
+
+h# ff48 smm-data smm-ss-limit
+h# ff4c smm-data smm-ss-base
+h# ff50 smm-data smm-ss-access
+
+h# ff54 smm-data smm-ds-limit
+h# ff58 smm-data smm-ds-base
+h# ff5c smm-data smm-ds-access
+
+h# ff60 smm-data smm-fs-limit
+h# ff64 smm-data smm-fs-base
+h# ff68 smm-data smm-fs-access
+
+h# ff6c smm-data smm-gs-limit
+h# ff70 smm-data smm-gs-base
+h# ff74 smm-data smm-gs-access
+
+h# ff84 smm-data smm-gdtr-limit
+
+h# ff88 smm-data smm-gdtr-base
+h# ff8c smm-data smm-gdtr-access
+
+h# ff90 smm-data smm-idtr-limit
+h# ff94 smm-data smm-idtr-base
+h# ff98 smm-data smm-idtr-access
+
+h# ff9c smm-data smm-tr-limit
+h# ffa0 smm-data smm-tr-base
+h# ffa4 smm-data smm-tr-access
+
+h# ffa8 smm-data smm-es
+h# ffac smm-data smm-cs
+h# ffb0 smm-data smm-ss
+h# ffb4 smm-data smm-ds
+h# ffb8 smm-data smm-fs
+h# ffbc smm-data smm-gs
+h# ffc0 smm-data smm-ldtr
+h# ffc4 smm-data smm-tr
+h# ffc8 smm-data smm-dr7
+h# ffcc smm-data smm-dr6
+h# ffd0 smm-data smm-eax
+h# ffd4 smm-data smm-ecx
+h# ffd8 smm-data smm-edx
+h# ffdc smm-data smm-ebx
+h# ffe0 smm-data smm-esp
+h# ffe4 smm-data smm-ebp
+h# ffe8 smm-data smm-esi
+h# ffec smm-data smm-edi
+h# fff0 smm-data smm-eip
+h# fff4 smm-data smm-eflags
+h# fff8 smm-data smm-cr3
+h# fffc smm-data smm-cr0
+
+\ 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).
+
+label smi-handler
+   16-bit
+  
+   \ 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
+   here /smm-gdt + #) jmp                          \ Jump past GDT - 2 bytes
+
+   /smm-gdt 1- w,   smm-base +smm-offset l,       \ GDT pointer - limit.w base.l
+
+   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
+
+   cs ax mov  ax ds mov
+
+wbinvd
+
+\ Get into protected mode using the same segments 
+\ Don't bother with the IDT; we won't enable interrupts
+   op: smm-gdt 2+ #) lgdt
+
+\ ascii a report
+
+   cr0 ax mov  1 # al or  ax cr0 mov   \ Enter protected mode
+
+   op: here 7 + smi-handler -  +smm +smm-offset   smm-c32 #)  far jmp
+   32-bit
+
+   \ Reload segment registers with protected mode selectors
+   op: smm-d32 # ax mov
+   ax ds mov  ax es mov  ax fs mov  ax gs mov  ax ss mov
+
+[ifdef] virtual-mode
+   \ Turn on paging
+   smm-pdir #)  ax  mov   ax cr3  mov	\ Set Page Directory Base Register
+   cr4 ax mov  h# 0000.0010 # ax or  ax cr4 mov	 \ Turn on PSE bit (allow 4M pages)
+   cr0 ax mov  h# 8000.0000 # ax or  ax cr0 mov	 \ Turn on Paging Enable bit
+[then]
+
+   h# cf8 #  dx   mov   \ Save PCI config address
+   dx        ax   in
+   ax  smm-save-cf8 #)  mov
+
+\ Beginning of Forth-specific stuff
+   smm-forth-base  #)  bx  mov
+   smm-forth-up    #)  up  mov
+   smm-forth-entry #)  ip  mov
+
+   \ Exchange the stack and return stack pointer with the smi versions
+   'user sp0 sp mov  smm-save-sp0 #) sp xchg  sp 'user sp0 mov
+   'user rp0 rp mov  smm-save-rp0 #) rp xchg  rp 'user rp0 mov
+
+   cld
+c;
+
+\ When the Forth SMI handler finishes, it calls (smi-return) to return
+\ to the context that invoked the SMI.  This is the inverse of smi-handler.
+
+code (smi-return)   \ This code field must be relocated after copying to SMM memory
+   cli
+
+   \ Exchange the stack and return stack pointer with the smi versions
+   'user sp0 sp mov  smm-save-sp0 #) sp xchg  sp 'user sp0 mov
+   'user rp0 rp mov  smm-save-rp0 #) rp xchg  rp 'user rp0 mov
+
+   \ End of Forth-specific stuff
+
+   smm-save-cf8 #)  ax  mov     \ Restore PCI config address
+   h# cf8 #  dx  mov
+   ax    dx  out
+
+[ifdef] virtual-mode
+   \ Turn off paging
+   cr0 ax mov  h# 8000.0000 invert # ax and  ax cr0 mov	 \ Turn off Paging Enable bit
+[then]
+
+   here 7 +  smi-handler - +smm-offset  smm-c16 #)  far jmp     \ Get into the boosted segment
+   16-bit
+
+   \ Now we are in protected mode executing from a 16-bit code segment
+   \ whose selector has a base of A0000.
+
+   smm-d16 # ax mov  ax ss mov  ax ds mov      \ Reload data and stack segments
+
+   cr0 ax mov  1 invert # al and  ax cr0 mov   \ Exit protected mode
+   here 7 +  smi-handler - +smm-offset  smm-base 4 rshift #)  far jmp    \ Set CS for real mode
+
+   wbinvd
+
+   rsm
+end-code
+here smi-handler - constant /smi-handler
+
+: smm@  ( offset -- n )  +smm @  ;
+
+\ Address of segment registers
+: 'smm-eax  ( -- adr )  smm-eax +smm  ;
+
+\ Finds a page table or page directory entry
+\ Implementation factor of (smm>physical)
+: >ptable  ( table vadr shift -- table' unmapped? )
+   rshift  h# ffc and + l@
+   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
+: (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 )
+   swap h# fff and +
+;
+' (smm>physical) to smm>physical
+
+: smm-map?  ( vadr -- )  smm>physical  .  ;
+
+\ Programs that write to the caller's data space should use this,
+\ as it works when called from paged V86 mode.
+: >caller-physical  ( vadr -- padr )
+   smm-cr0 smm@  h# 8000.0000 and  if  (smm>physical)  then
+;
+
+\ Turn address translation on or off for the following commands,
+\ so they can be used either for non-paged calling code like
+\ early bootloaders or for paged code that calls to us via a
+\ real mode gateway.
+
+: use-physical  ( -- )  ['] noop to smm>physical  ;
+: use-virtual   ( -- )  ['] (smm>physical) to smm>physical  ;
+
+\ Some simple glue code to help make the transition from assembly language
+\ to Forth and back.
+
+: smi-return  ( -- )  [ ' (smi-return) smi-handler -  +smm +smm-offset  ] literal  execute  ;
+defer handle-smi  ' noop is handle-smi
+create smm-exec  ] handle-smi smi-return [
+
+\ Set to true to display brief messages showing every entry to SMM
+false value smi-debug?
+
+\ Set to true to invoke the Forth debugger when the OS tries to suspend (S3)
+false value resume-debug?
+
+\ This is a stub SMI handler that just invokes the Forth command
+\ interpreter so you can poke around.  Normally handle-smi calls
+\ smi-dispatch to do all the virtualization work, instead of this.
+
+: smi-interact  ( -- )  ." In SMI" cr  interact  ;
+' smi-interact is handle-smi
+
+: smm-eax-c!  ( b -- )  'smm-eax c!  ;
+: smm-eax-c@  ( -- b )  'smm-eax c@  ;
+
+0 value rm-int@
+
+defer handle-bios-call
+
+: rm-sp  ( -- adr )  smm-esp +smm w@  smm-ss +smm w@ seg:off>  ;
+
+\ bios-int-smi is for accesses to the 0x30..0x3f I/O port bank that we "steal" for
+\ bouncing BIOS INTs into SMM.
+
+: bios-int-smi  ( -- )
+   \ 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!
+      \ Bias by -2 to point to INT instruction
+[ifdef] notyet
+      rm-sp >caller-physical l@ 2-  smm-retaddr l!
+[then]
+      handle-bios-call
+      smm-eflags +smm w@  rm-sp la1+ >caller-physical w!
+      exit
+   else
+      drop
+   then
+;
+
+\ This hook can be set to turn off devices that the firmware uses.
+\ It is called when the OS takes responsibility for power management
+\ by writing a 1 to bit 0 of the ACPI PM1_CNT .
+
+defer quiesce-devices  ' noop to quiesce-devices
+
+\ This is a gateway to get into real mode by going through SMM .
+\ 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  ;
+
+defer suspend-devices  ' noop to suspend-devices
+defer resume-devices   ' noop to resume-devices
+
+defer freeze-ps2    ' noop to freeze-ps2
+defer unfreeze-ps2  ' noop to unfreeze-ps2
+
+\ SMI breakpoints - simple (but very useful) debugging tool.
+
+variable sbpval
+variable sbpadr  sbpadr off
+defer sbp-hook
+
+: .9x  push-hex  9 u.r  pop-base  ;
+: .smir   ( offset -- )   smm@ .9x  ;
+: .smis   ( offset -- )   smm@ 5 u.r  ;
+
+
+\ Displays the saved register values
+
+: .smiregs   ( -- )
+   ."       EAX      EBX      ECX      EDX      ESI      EDI      EBP      ESP" cr
+     smm-eax .smir  smm-ebx .smir  smm-ecx .smir  smm-edx .smir
+     smm-esi .smir  smm-edi .smir  smm-ebp .smir  smm-esp .smir
+   cr
+   ." CS: "  smm-cs .smis
+   ."  DS: " smm-ds .smis
+   ."  ES: " smm-es .smis
+   ."  FS: " smm-fs .smis
+   ."  GS: " smm-gs .smis
+   ."  SS: " smm-ss .smis
+   cr
+;
+: .smipc  ( -- )  ." SMI at " smm-eip .smir cr ;
+' .smipc to sbp-hook
+
+: .callto  ( retadr -- )
+   dup  ['] smm>physical  catch  if  2drop exit  then  ( retadr pretadr )
+   dup 5 - c@ h# e8 <>  if  2drop exit  then           ( retadr pretadr )
+   4 - l@ + 9 u.r
+;
+
+\ Displays a subroutine call backtrace.  This pretty dependent on compiler
+\ code generation rules, so it might not work in some cases.
+
+: smm-trace  ( -- )
+   ."      EBP   RETADR   CALLTO" cr
+   smm-ebp smm@
+   begin  ?dup  while                           ( ebp )
+      dup 8 u.r  smm>physical                   ( padr )
+      dup la1+ l@ dup 9 u.r  .callto  cr        ( padr )
+      l@                                        ( ebp' )
+   repeat
+;
+
+: fixsbp  ( -- )
+   sbpadr @  if
+      sbpval @  sbpadr @ smm>physical  w!
+      sbpadr off
+   then
+;
+
+: unboost  ( adr -- adr' )  h# 7fff.ffff and  ;
+
+\ Set an SMI breakpoint at "adr".  You can only set one breakpoint.
+\ "adr" is either virtual or physical depending on whether you have
+\ previously executed "use-physical" or "use-virtual"
+
+: sbp  ( adr -- )
+   fixsbp
+   dup smm>physical w@  sbpval !  dup sbpadr !
+   h# 380f swap smm>physical w!
+;
+
+\ Disassemble starting from the breakpoint address
+
+: sdis  ( -- )  smm-eip smm@ smm>physical dis  ;
+
+\ Resume execution of the breakpointed code
+
+: sgo  ( -- )  ( smm-eip smm@ smm-next-eip! )  resume  ;
+
+: 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.
+
+: rm-setup  ( -- )
+[ifdef] notyet
+   rm-entry-adr >seg:off 2>r    ( off seg )
+
+   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
+
+   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 smm-esp +smm  l!
+
+   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# ffff smm-rmidt w!  0 smm-rmidt wa1+ l!  \ Limit and base
+
+   \ Interrupts are off because we are in SMM
+   rm-lidt
+[then]
+;
+\ : rm-init-program   ( eip -- )  rm-init-program  rm-return  ;
+
+\ Handler for software SMIs, i.e. for explicit execution of the
+\ SMINT instruction.  It's used for things like the rm-run facility
+\ and SMI breakpoints.
+
+: soft-smi  ( -- )
+   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
+   sbpadr @  if
+      sbpadr @ smm>physical  smm-pc smm>physical <>  if
+         ." Not at SMI breakpoint!" cr
+         .smipc
+         .smiregs
+      else
+         fixsbp
+      then
+      sbp-hook
+   then
+[then]
+
+   smi-interact
+;
+
+\ smi-dispatch is the top-level dispatcher for SMIs.  It looks
+\ at various MSRs to determine the SMI cause and invokes the
+\ corresponding subordinate handlers.
+
+: smi-dispatch  ( -- )
+   h# 28 acpi-w@                            ( events )
+   dup h# 0040 and  if  soft-smi      then  ( events )
+   dup h# 8000 and  if  bios-int-smi  then  ( events )
+   h# 28 acpi-w!   \ Ack all events         ( )
+
+   h# 2d acpi-b@ h# 2d acpi-b!  \ Ack the SMI
+;
+' smi-dispatch is handle-smi
+
+: .dt  ( adr limit -- )
+   1+  8 max  8  ?do                     ( gdt-adr )
+      dup i + d@  dup  if                ( gdt-adr descr )
+         i 3 u.r space .descriptor cr    ( gdt-adr )
+      else                               ( gdt-adr descr )
+         2drop                           ( gdt-adr )
+      then                               ( gdt-adr )
+   8 +loop                               ( gdt-adr )
+   drop
+;
+
+\ Debugging tool for displaying the saved Global Descriptor Table
+
+: .smm-gdt  ( -- )
+   smm-gdtr-base smm@ smm>physical  ( 'gdt gdt-adr )
+   swap w@                          ( gdt-adr gdt-limit )
+   .dt                              ( )
+;
+
+\ setup-rm-gateway initializes the real mode interrupt vector table
+\ so that real mode code can call BIOS INTs.
+
+\  setup-rm-gateway  ( -- ) Init this module
+\  caller-regs  ( -- adr )  Base address of incoming registers
+\  rm-int@      ( -- n )    Incoming interrupt number
+\  rm-buf       ( -- adr )  Base address of a real-mode accessible buffer
+\  rm-init-program  ( eip -- )  Setup to enter real mode program on next rm-return
+\  rm-return    ( -- )      Resume execution of real-mode caller.  Returns when program does a BIOS INT.
+\ Sequence:
+\  setup-rm-gateway  ( eip ) rm-enter  begin  handle-bios-call rm-return  again
+
+: setup-rm-gateway  ( -- )  \ XXX These config registers probably need to be fixed up during resume
+   h# 0030 h# 885e config-w!                       \ Set up PCS1 IO trap on ports 30-3f
+   h# 8864 config-b@  h# f0 or  h# 8864 config-b!  \ 16-byte range for PCS1
+   h# 8866 config-b@  h# 02 or  h# 8866 config-b!  \ Enable PCS1
+
+ \  h# 88e4 config-b@  h# 40 or  h# 88e4 config-b!  \ Enable PCS0 multifunction
+   h# 88e5 config-b@  h# 04 or  h# 88e5 config-b!  \ Enable PCS1 multifunction
+
+   h# 2b acpi-b@ h# 80 or  h# 2b acpi-b!           \ Enable SMI on access to PCS1
+
+   int-entry  'int10-dispatch  /int-entry move   
+
+   \ Prime the interrupt vector table with unused interrupt 1f
+   h# 100  0  do
+      'int10-dispatch h# f la+  i /l*  seg:off!
+   loop
+
+   \ Set interrupts 10-1f to go to entries 0-f in the int10-dispatch table
+   h# 10  0  do
+      'int10-dispatch i la+  h# 10 i + /l*  seg:off!
+   loop
+;
+
+\ Test routine that just puts an 'S' on the serial port when an SMI happens
+label show-smi
+   16-bit
+   ascii S report
+
+   \ Via specific
+   acpi-io-base h# 28 + # dx mov  dx al in  al dx out  \ Ack all events
+   acpi-io-base h# 2d + # dx mov  dx al in  al dx out  \ ACK SMI
+   rsm
+end-code
+here show-smi - constant /show-smi
+
+label move-smbase
+   16-bit
+\  ascii s report
+
+   \ Move SMBASE to the a0000 location
+   op: smm-base # ax mov
+   op: cs: ax smm-smbase #)  mov
+
+   \ Via specific
+   acpi-io-base h# 28 + # dx mov  dx al in  al dx out  \ Ack all events
+   acpi-io-base h# 2d + # dx mov  dx al in  al dx out  \ ACK SMI
+   rsm
+end-code
+here move-smbase - constant /move-smbase
+
+: via-relocate-smi  ( -- )
+\   show-smi 0 +smm  /show-smi move
+   move-smbase smm-base0  /move-smbase move
+   h# 2c acpi-w@     1 or h# 2c acpi-w!       \ Global SMI enable
+   h# 2a acpi-b@ h# 40 or h# 2a acpi-b!       \ Enable SMI on access to software SMI register
+   0 #smint                                   \ Trigger SMI
+;
+
+\ 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
+
+   h#  386 config-b@ 1 or h#  386 config-b!   \ Enable compatible SMM
+   h# 8fe6 config-b@ 3 or h# 8fe6 config-b!   \ Enable compatible and high SMM
+
+[ifdef] virtual-mode
+   cr3@ smm-pdir l!
+[then]
+
+   origin smm-forth-base l!
+   smm-exec smm-forth-entry l!
+   up@ smm-forth-up l!
+   smm-sp0 smm-save-sp0 !
+   smm-rp0 smm-save-rp0 !
+
+   smi-handler  smm-base +smm-offset  /smi-handler  move
+
+   \ Relocate the code field of the code word that is embedded in the sequence
+   ['] (smi-return) smi-handler -  +smm +smm-offset  ( cfa-adr )
+   dup ta1+ swap token!
+
+   via-relocate-smi
+
+   h#  383 config-b@ 1 invert and h#  383 config-b!   \ Hide A/Bxxxx range behind frame buffer
+;
+
+0 [if]
+: bios-release-smi  ( -- )
+   h# 2a acpi-b@ h# 20 or h# 2a acpi-b!       \ Enable SMI on BIOS Release
+   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




More information about the openfirmware mailing list