\ ========== Copyright Header Begin ==========================================
\ Hypervisor Software File: clientif.fth
\ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
\ - Do no alter or remove copyright notices
\ - Redistribution and use of this software in source and binary forms, with
\ or without modification, are permitted provided that the following
\ - Redistribution of source code must retain the above copyright notice,
\ this list of conditions and the following disclaimer.
\ - Redistribution in binary form must reproduce the above copyright notice,
\ this list of conditions and the following disclaimer in the
\ documentation and/or other materials provided with the distribution.
\ Neither the name of Sun Microsystems, Inc. or the names of contributors
\ may be used to endorse or promote products derived from this software
\ without specific prior written permission.
\ This software is provided "AS IS," without a warranty of any kind.
\ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
\ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
\ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
\ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
\ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
\ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
\ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
\ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
\ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
\ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
\ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
\ You acknowledge that this software is not designed, licensed or
\ intended for use in the design, construction, operation or maintenance of
\ ========== Copyright Header End ============================================
id: @(#)clientif.fth 1.18 04/01/28
copyright: Copyright 1993-2002, 2004 Sun Microsystems, Inc. All Rights Reserved
copyright: Use is subject to license terms.
only forth also definitions
\ Access to Client Interface Arguments
defer carga+ ( adr n -- adr+n*cells )
defer /carg ( -- #cells )
defer /carg* ( n -- n*cells )
: #cargs ( -- n ) cif-struct 1 carga+ carg@ ;
: #crets ( -- n ) cif-struct 2 carga+ carg@ ;
: service-name ( -- adr,len ) cif-struct carg@ cscount ;
: args-adr ( -- arg-n ) cif-struct 3 carga+ ;
: is-cif-function? ( adr,len -- false | acf +-1 )
['] client-services behavior (search-wordlist)
\ Don't define client service methods using the old way any longer.
\ also client-services definitions headers caps @ caps on
\ : SUNW,failed ( -- failed? ) true ;
\ previous definitions headerless caps !
\ Now you can define this same routine by simply:
\ cif: SUNW,failed ( -- failed? ) true ;
\ this method takes the pain out of flipping the case sensitivity of a CIF
\ call and also ensures the method goes into the correct vocabulary.
\ It works by recording the current headers/headerless and caps state,
\ then setting then appropriately, moving to client-services and calling ':'
\ to create the word, then we restore the original state again.
: cif: \ name of headered routine with case sensitive name
headerless? dup >r if headers then
also client-services definitions
caps @ >r caps off : r> caps ! r> if headerless then
\ Client Interface Handler
defer cif-enter-hook ' noop is cif-enter-hook
defer cif-error-hook ' noop is cif-error-hook
defer cif-exit-hook ' noop is cif-exit-hook
??cr dup .name ." ( " #cargs 0 ?do #cargs i - pick .x loop ." -- "
#crets 0 ?do #crets i - pick .x loop
['] .cif( to cif-enter-hook
['] ).cif to cif-exit-hook
['] noop to cif-enter-hook
['] noop to cif-exit-hook
: do-cif ( adr -- result )
\ Push arguments on the stack
args-adr #cargs 1- /carg* bounds swap do
service-name is-cif-function? if ( args.. acf )
cif-enter-hook ( args.. acf )
catch 0<> ( rets.. error? )
cif-error-hook true ( args.. error )
\ Pop results from the stack
args-adr #cargs carga+ #crets /carg* bounds
\ Support functions for client interface services
: copy-out ( len,buf adr len1 -- len1 )
dup >r ( len,buf adr,len1 ) ( r: len1 )
2swap swap ( adr len1 buf,len ) ( r: len1 )
rot min cmove ( ) ( r: len1 )
: setnode ( nodeid | 0 -- )
dup 0= if drop ['] root-node then also execute
: options? ( -- flag ) 'properties token@ ['] options = ;
: null? ( cstr -- flag ) dup if c@ 0= else drop true then ;
: str>cstr ( adr len -- cstr )
tuck cstrbuf swap cmove cstrbuf + 0 swap c! cstrbuf
: &link>cstr ( alf -- acf cstr true | nullstr false )
dup >name name>string str>cstr ( acf cstr )
nullstring false ( cstr false )
false value canonical-properties?
: $canonical-property ( cstr -- adr len )
canonical-properties? if d# 31 min canon-prop $save 2dup lower then
: find-property ( cstr -- adr len false | acf true )
2dup current-properties (search-wordlist) dup if 2swap 2drop then
: first-property ( -- cstr )
current-properties >threads &link>cstr if nip then
: next-property ( cstr -- cstr )
\ Get the next property that has not been superceded by a
\ later redefinition of the same name.
dup >name n>link &link>cstr if ( acf acf' cstr )
\ Check to see if this is the most recent
\ version of the property with this name.
dup find-property if ( acf' cstr acf" )
rot tuck <> ( cstr acf" deleted? )
2drop swap false ( cstr acf' false )
then ( cstr acf" deleted? )
\ There are no more firmware-defined configuration variables;
\ find the first user-created environment variable
null$ next-env-var str>cstr ( cstr )
then ( cstr acf" deleted? )
\ The property returned by "find-property" has
\ a different acf than the one we're looking at,
\ even though they have the same name. We conclude
\ that the one we're looking at has been superceded,
\ and go back to try the next one.
\ The input string is not a firmware-defined configuration
\ variable; perhaps it is a user-created environment variable
next-env-var str>cstr ( cstr )
2drop nullstring ( cstr )
\ .cstr defined in fm/lib/util.fth
\ : .cstr ( cstr -- ) begin dup c@ ?dup while emit 1+ repeat drop ;
\ Generic Client Interface Services
only forth ( also hidden also forth ) also client-services definitions
cif: ci-properties ( -- ) true to canonical-properties? ;
cif: cs-properties ( -- ) false to canonical-properties? ;
cif: test ( service-name -- missing? ) cscount is-cif-function? 0= ;
cif: test-method ( method-cstr phandle -- missing? )
>r cscount r> find-method if drop false else true then
cif: child ( phandle -- phandle' )
0 'child ( last-nodeid &next-nodeid )
begin get-token? while ( last-nodeid next-nodeid )
nip dup execute ( next-nodeid )
'peer ( last-nodeid' &next-nodeid )
cif: peer ( phandle -- phandle' )
\ Select the first child of our parent
dup >parent also execute ( nodeid )
'child token@ execute ( nodeid )
dup current-device = if ( nodeid )
\ Argument node is first child of parent; return "no more nodes"
\ Search for the node preceding the argument node
'peer token@ 2dup <> ( nodeid next-nodeid flag )
while ( nodeid next-nodeid )
2drop current-device ( nodeid' )
cif: parent ( phandle -- phandle' )
dup ['] root-node = if ( root-phandle )
\ cif-buf passes client's buffer adr,len to the property 'get' routine
\ non-zero len and non-zero adr indicates this is a getprop and the
\ contains the adr,len. A non-zero len and zero adr indicates this
\ is a getproplen so that the property 'get' routine can optimise.
\ This mechanism is relied upon by the 'translations' property.
2variable cif-buf 0 0 cif-buf 2!
cif: getproplen ( cstr phandle -- len )
setnode find-property if ( acf )
>r r@ get r> decode nip ( len )
get-env-var if -1 else nip then ( len | -1 )
cif: instance-to-package ( ihandle -- phandle ) ihandle>phandle ;
cif: getprop ( len,buf cstr phandle -- size )
setnode find-property if ( len,buf acf )
>r 2dup swap ( len,buf buf,len )
2dup erase ( len,buf buf,len )
r@ get r> decode ( len,buf adr,len1 )
options? if ( len,buf name$ )
get-env-var if ( len,buf )
2over swap erase ( len,buf name$ )
cif: nextprop ( buf prev phandle -- 0|1 )
setnode ( buf prev-cstr )
dup null? if ( buf prev-cstr )
drop first-property ( buf first-cstr )
next-property ( buf next-cstr )
over >r ( buf cstr ) ( r: buf )
cscount 1+ ( buf adr,len )
r> null? if 0 else 1 then ( 0|1 )
cif: setprop ( len buf name phandle -- error|len' )
setnode find-property if ( buf-len buf-adr acf )
>r swap 1- 0 max ( buf-adr buf-len )
r@ set r@ get r> decode ( adr len )
else ( buf-len,adr name$ )
options? if ( buf-len,adr name$ )
2swap swap 2swap put-env-var ( len|-1 )
else ( buf-len,adr name$ )
cif: finddevice ( cstr -- phandle ) cscount locate-device ?dup drop ;
cif: instance-to-path ( len,buf ihandle -- len' )
cif: instance-to-interposed-path ( len,buf ihandle -- len' )
cif: package-to-path ( len,buf phandle -- len' )
cif: call-method ( arg-P .. ihandle cstr -- res-Q ... res-1 catch-result )
cscount rot ['] $call-method catch
cif: call-static-method ( arg-P .. phandle cstr -- res-Q ... res-1 result )
cscount rot ['] $call-static-method catch
cif: open ( cstr -- ihandle ) cscount open-dev ;
cif: close ( ihandle -- ) close-dev ;
cif: read ( len,addr ihandle -- len' )
>r swap " read" r> ['] $call-method catch if
cif: write ( len,addr ihandle -- len' )
>r swap " write" r> ['] $call-method catch if
cif: seek ( low,high ihandle -- status )
" seek" rot ['] $call-method catch if ( d.offset adr len nodeid )
\ set-symbol-lookup is defined in os/sun/symdebug.fth
cif: milliseconds ( -- ) get-msecs ;
cif: execute-buffer ( adr len -- ) 'execute-buffer execute ;
alias child child \ Make visible outside the client-services package
alias peer peer \ Make visible outside the client-services package
only forth also definitions
d# 32 buffer: nextprop-cstr
overload: next-property ( prev$ phandle -- false | next$ true )
nextprop-cstr dup d# 32 erase ( prev$ cstr )
swap cmove nextprop-cstr dup null? if ( prev-cstr )
drop first-property ( first-cstr )
next-property ( next-cstr )
dup null? if 2drop false else cscount true then