Add support for viewing and manipulating LinuxBIOS CMOS settings
from Open Firmware.

Signed-off-by: Jens Freimann <jens@freimann.org>

Index: cpu/x86/pc/biosload/lbcmos.fth
===================================================================
--- cpu/x86/pc/biosload/lbcmos.fth	(Revision 0)
+++ cpu/x86/pc/biosload/lbcmos.fth	(Revision 0)
@@ -0,0 +1,246 @@
+purpose: Access LinuxBIOS CMOS settings
+
+fload ${BP}/cpu/x86/pc/biosload/cmos.fth
+
+variable cmos-param-length
+variable cmos-param-addr
+
+: .invalid ( -- ) ." Invalid argument" ;
+
+\ transforms bits from CMOS to a human readable form
+\ and vice versa
+: decode-baudrate ( baudrate-bits -- baudrate )
+    case
+        0 of 115200 endof
+        1 of 57600  endof
+        2 of 38400  endof
+        3 of 19200  endof
+        4 of 9600   endof
+        5 of 4800   endof
+        6 of 2400   endof
+        7 of 1200   endof
+          -1
+    endcase
+;
+
+: encode-baudrate ( baudrate -- true|false )
+    case
+        115200 of 0 endof
+        57600  of 1 endof
+        38400  of 2 endof
+        19200  of 3 endof
+        9600   of 4 endof
+        4800   of 5 endof
+        2400   of 6 endof
+        1200   of 7 endof
+        -1
+    endcase
+;
+
+: str-fallback " Fallback" ;
+: str-normal " Normal" ;
+
+: decode-boot-option ( boot-option-bits -- str-addr str-len )
+    case
+        0 of str-fallback endof
+        1 of str-normal   endof
+        " unknown"
+    endcase
+;
+
+: decode-last-boot ( last-boot-bits -- str-addr str-len )
+    decode-boot-option
+;
+
+\ Arguments for set-debug-level
+: lb-emergency 1 ;
+: lb-alert     2 ;
+: lb-critical  3 ;
+: lb-error     4 ;
+: lb-warning   5 ;
+: lb-notice    6 ;
+: lb-info      7 ;
+: lb-debug     8 ;
+: lb-spew      9 ;
+
+: decode-debug-level ( debuglevel-bits -- str-addr str-len )
+    case
+        1 of " Emergency" endof
+        2 of " Alert"     endof
+        3 of " Critical"  endof
+        4 of " Error"     endof
+        5 of " Warning"   endof
+        6 of " Notice"    endof
+        7 of " Info"      endof
+        8 of " Debug"     endof
+        9 of " Spew"      endof
+        " Unknown" 
+    endcase
+;
+
+\ Arguments for set-boot-option
+: lb-fallback 0 ;
+: lb-normal 1 ;
+
+: find-cmos-table ( -- addr true|false )
+    lbt-header-start /lbt-header-size + dup
+    l@
+    lb-tag-cmos-option-table =
+;
+
+: startbit@ ( addr -- startbit addr+8 )  8 + dup l@ ;
+
+: bitlength@ ( addr -- startbit )  swap 4 + l@ ;
+
+: compare-strings ( ? -- true|false )
+    dup 4 + l@
+    18 -
+    swap 18 +
+    dup 18 - swap rot
+    cmos-param-addr l@ cmos-param-length l@ rot drop comp
+    0=
+;
+
+: (find-cmos-parameter) ( -- )
+    dup 10 + l@ 72 <>               \ check if entry is reserved ( = r = 72 )
+    if
+        dup l@ h# c9 =    ( )
+        if                          \ its a LB_TAG_OPTION (0xc) entry
+            compare-strings
+            if startbit@ bitlength@ true true
+            else next-lbtrecord false false then
+        then
+    else next-lbtrecord false
+    then
+;
+
+: find-cmos-parameter ( str-len str-addr -- start-bit length true | false )
+    cmos-param-length l!
+    cmos-param-addr l!
+    lbt-header-start /lbt-header-size +
+    dup 8 +                             ( cmostbl-saddr size-first-entry-addr )
+    l@                                  ( cmostbl-saddr size-first-entry )
+    +                                   ( cmostbl-saddr next-entry-addr )
+    begin
+        (find-cmos-parameter)
+    until
+;
+
+: verify-cmos-byte ( val byte# -- true|false )  cmos@ = ;
+
+: calc-mask ( length remainder -- masked-byte )
+    swap                                            ( remainder length )
+    1 swap << 1 -
+    swap <<
+;
+
+: fetchmask ( remainder bitlength -- mask )
+    1 swap << 1 - swap      ( maxval remainder )
+    << h# ff swap -            ( mask )
+;
+
+: get-cmos ( str-addr str-len -- cmos-value|false )
+    find-cmos-parameter                 ( startbit bitlength )
+    if
+        swap 8 u/mod
+        swap dup >r swap                \ save remainder on rstack
+        cmos@ -rot
+        swap fetchmask
+        dup -rot
+        or
+        swap -
+        r> >>
+    else false
+    then
+;
+
+: set-cmos ( str-addr-name str-len-name -- true|false )
+    find-cmos-parameter                 ( boot-option start-bit bitfield-length )
+    if
+        swap
+        8 u/mod dup >r                  \ push divider on return stack
+        swap dup >r swap                \ push remainder (rem) on return stack
+        -rot calc-mask
+        swap
+        cmos@
+        2dup or nip swap -
+        swap r> <<                      \ shift left by rem bits
+        +                               \ add masked value to value currently in cmos so we don't
+                                        \ change any bits other than the intended ones
+        r> 2dup cmos!                   \ pop byte# from rstack and write byte to cmos
+        verify-cmos-byte
+    else
+        2drop false
+    then
+;
+
+\ words to fetch values from CMOS
+: cmos-baudrate@ ( -- baudrate )  " baud_rate" get-cmos ;
+: cmos-boot-index@ ( -- boot-index )  " boot_index" get-cmos ;
+: cmos-boot-option@ ( -- boot-option )  " boot_option" get-cmos ;
+: cmos-last-boot@ ( -- last-boot )  " last_boot"  get-cmos ;
+: cmos-debug-level@ ( -- baudrate )  " debug_level" get-cmos ;
+: cmos-boot-countdown@ ( -- boot-countdown )  " boot_countdown" get-cmos ;
+: cmos-checksum@ ( -- checksum )  " boot_countdown" get-cmos ;
+
+\ easy to use words for calling from the ok prompt
+: baudrate ( -- ) cmos-baudrate@ decode-baudrate . ;
+: debug-level ( -- ) cmos-debug-level@ decode-debug-level type ;
+: boot-option ( -- ) cmos-boot-option@ decode-boot-option type ;
+: last-boot ( -- ) cmos-last-boot@ decode-last-boot type ;
+: boot-countdown ( -- ) cmos-boot-countdown@ . ;
+: boot-index ( -- ) cmos-boot-index@ . ;
+: cmos-checksum ( -- ) cmos-checksum@ . ;
+
+\ words to set values in CMOS
+: set-boot-index ( boot-index -- true|false )
+    dup 0 1 between
+    if " boot_index" set-cmos
+    else drop false
+    then
+;
+
+: set-baudrate ( baudrate -- true|false )
+    encode-baudrate
+    dup 1 7 between
+    if " baud_rate" set-cmos
+    else drop false .invalid
+    then
+;
+
+: set-boot-option ( boot-option -- true|false )
+    dup 0 1 between
+    if " boot_option" set-cmos
+    else drop false .invalid
+    then
+;
+
+: set-last-boot ( last-boot -- true|false )
+    dup 0 1 between
+    if " last_boot" set-cmos
+    else drop false .invalid
+    then
+;
+
+: set-debug-level ( debug-level -- true|false )
+    dup 1 9 between
+    if " debug_level" set-cmos
+    else drop false .invalid
+    then
+;
+
+: set-boot-countdown ( boot-countdown -- true|false )
+    0 h# ff between
+    if " boot_countdown" set-cmos
+    else drop false .invalid
+    then
+;
+
+: set-checksum ( checksum -- true|false )
+    0 h# 400 between
+    if " checksum" set-cmos
+    else drop false .invalid
+    then
+;
+
+
