\ ========== Copyright Header Begin ========================================== \ \ Hypervisor Software File: instance.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 \ conditions are met: \ \ - 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 \ any nuclear facility. \ \ ========== Copyright Header End ============================================ id: @(#)instance.fth 2.60 07/01/22 purpose: Create, destroy, and call package instances copyright: Copyright 2007 Sun Microsystems, Inc. All Rights Reserved copyright: Use is subject to license terms. \ Creation and destruction of device instances. Also package interface words. defer fm-hook ( adr len phandle -- adr len phandle ) ' noop is fm-hook : find-method ( adr len phandle -- false | acf true ) fm-hook (search-wordlist) ; : "open" " open" ; : $call-self ( adr len -- ) my-voc setup-method$ fm-hook $vexecute? if no-proc throw then ; [ifndef] package( transient : )package-macro ( -- ) r> is my-self ; : package(-macro ( ihandle -- ) my-self >r is my-self ; resident macro: package( package(-macro macro: )package )package-macro [then] : call-package ( ??? acf ihandle -- ??? ) package( execute )package ; : $call-method ( ??? adr len ihandle -- ??? ) package( $call-self )package ; : $call-parent ( adr len -- ) my-parent package( $call-self )package ; : (skip-interposed) ( -- ) begin interposed? while my-parent is my-self repeat ; : ihandle>phandle ( ihandle -- phandle ) package( (skip-interposed) my-voc )package ; : $call-static-method ( ??? adr len phandle -- ??? ) setup-method$ find-method 0= if no-proc throw then execute ; \ set-args is executed only during probing, at which time the active package \ corresponds to the current instance, thus '#adr-cells can be executed \ directly. : set-args ( arg-str reg-str -- ) current-device >r pop-device (decode-unit) r> push-device '#adr-cells @ ( arg-str phys .. #cells ) dup if swap to my-space 1- then ( arg-str phys .. #cells' ) addr my-adr0 swap /n* bounds ?do i ! /n +loop ( arg-str ) copy-args ; : get-package-property ( adr len phandle -- true | adr' len' false ) also execute get-property previous ; \ Used when executing from an open package instance. Finds a property \ associated with the current package. : get-my-property ( adr len -- true | adr' len' false ) my-voc get-package-property ; headerless 0 value interposer \ phandle of interposing package, if any 0 value ip-arg-adr \ arguments for interposing package 0 value ip-arg-len \ Internal factor of get-inherited-property. This factoring is necessary \ because we use "exit" to make the control flow easier. : (get-any) ( adr len -- true | adr' len' false ) begin my-self while ( adr len ) \ Search up parent chain my-voc current token! ( adr len ) 2dup get-my-property 0= if ( adr len adr' len' ) 2swap 2drop false exit ( adr' len' false ) \ Found then ( adr len ) my-parent is my-self ( adr len ) repeat ( adr len ) 2drop true ( true ) \ Not found ; headers \ Finds a property associated with the current package or with one of \ its parents. : get-inherited-property ( adr len -- true | adr' len' false ) current token@ >r my-self >r (get-any) r> is my-self r> current token! ; headerless : try-close ( -- ) " close" ['] $call-self catch if 2drop then ; headers : close-package ( ihandle -- ) package( try-close destroy-instance )package ; headerless : close-parents ( -- ) begin my-self while try-close destroy-instance repeat ; : close-chain ( -- ) destroy-instance close-parents ; headers : close-dev ( ihandle -- ) package( close-parents )package ; \ Extract the next (leftmost) component from the path name, updating the \ path variable to reflect the remainder of the path after the extracted \ component. : parse-component ( path$ -- path$ args$ devname$ ) ascii / left-parse-string ( path$' component$ ) ascii : left-parse-string ( path$ args$ devname$ ) dup 0= if 2drop " /" then ( path$ args$ devname$' ) ; : apply-method ( adr len -- no-such-method? ) my-voc setup-method$ fm-hook ['] $vexecute? catch ?dup if ( x x x errno ) \ executing method caused an error nip nip nip ( errno ) then ( ??? false | true | errno ) ; headerless d# 64 buffer: package-name-buf headers : my-unit-bounds ( -- end-adr start-adr ) addr my-unit-low '#adr-cells @ /n* bounds ; : set-my-unit ( phys.hi .. phys.lo -- ) my-unit-bounds ?do i ! /n +loop ; : set-default-unit ( -- ) get-unit 0= if unit-str>phys- set-my-unit then ; \ Set the my-unit fields in the instance record: \ If an address was given in path component, use it \ If not, use address in "reg" property of package \ Otherwise, use 0,0 : set-instance-address ( -- ) unit#-valid? if unit-bounds ?do i @ /n +loop set-my-unit else set-default-unit then ; headerless : (apply-method) ( adr len -- ??? ) apply-method if close-chain no-proc throw then ( ) ; : (open-node) ( -- ) "open" (apply-method) 0= if ( okay? ) close-chain p" open failed" throw ( ) then ; : encode-bytes+ ( adr1 len1 adr2 len2 -- adr1 len1+len2 ) encode-bytes encode+ ; : encode-number+ ( u adr,len -- adr,len' ) base @ >r hex rot (u.) encode-bytes+ r> base ! ; : make-node-alias ( nodeid name-str -- ) current-device >r ( nodeid name-str ) rot push-device ( name-str ) pwd$ ( name-str expansion-str ) r> push-device ( name-str expansion-str ) $devalias ( ) ; : (append-args) ( arg$ base$ -- base$' ) 2 pick if ( arg$ base$ ) " :" 2swap $add ( arg$ base$' ) then ( arg$ base$ ) $add ( base$ ) ; : (ihandle>path) ( no-interpose? str,len -- allow-interpose? str,len' ) recursive 2 pick if (skip-interposed) then ( flag str,len ) my-parent if ( flag str,len ) my-parent package( (ihandle>path) )package ( flag str,len ) my-voc push-device ( flag str,len ) interposed? if " %" else " /" then ( flag str,len' sep$ ) 2swap $add ( flag str,len' ) (append-name) ( flag str,len' ) support-node? @ if exit then ( flag str,len ) 2>r my-unit 2r> (append-unit) ( flag str,len' ) my-args 2swap (append-args) ( flag str,len' ) then ( flag str,len ) ; overload: (ihandle>path) ( ihandle flag -- str,len ) current-device my-self 2>r ( ihandle flag ) swap is my-self ( flag ) "temp 0 (ihandle>path) ( flag str,len ) 2r> is my-self push-device rot drop ( str,len ) ; headers \ ihandle>devname returns the device tree nodes for this ihandle : ihandle>devname ( ihandle -- adr,len ) 1 (ihandle>path) ; \ ihandle>devpath returns the full instance path, including interposed packages : ihandle>devpath ( ihandle -- adr,len ) 0 (ihandle>path) ; : phandle>devname ( phandle -- adr,len ) current-device >r ( phandle ) ( r: phandle' ) push-device pwd$ ( adr,len ) ( r: phandle' ) r> push-device ( adr,len ) ; : open-node ( -- ) recursive (open-node) interposer if interposer 0 to interposer push-package ip-arg-adr ip-arg-len new-instance true is interposed? open-node pop-package then ; : interpose ( args$ phandle -- ) to interposer to ip-arg-len to ip-arg-adr ; headerless : (no-proc) ( -- ) " Unimplemented procedure '" "temp pack >r ( ) saved-method$ 2@ r@ $cat ( ) saved-method-package @ dup if ( ) " ' in " r@ $cat phandle>devname ( str,len ) else ( ) drop " '" ( str,len ) then r@ $cat ( ) r> count ( str,len ) set-abort-message -2 ( -2 ) ; \ Resolve the forward references to no-proc ' (no-proc) is no-proc : open-parents ( parent-phandle end-phandle -- ) recursive \ Exit at null "parent" of root node 2dup = if 2drop exit then over >parent swap open-parents ( phandle ) push-device ( ) " " new-instance ( ) set-default-unit ( ) open-node ( ) ; \ Open packages between, but not including, "phandle" and the active package : select-node ( path$ -- path$' ) current-device >r parse-component ( path$ args$ devname$ ) noa-find-device ( path$ args$ ) current-device dup >parent r> open-parents ( path$ args$ my-phandle ) push-device ( path$ args$ ) new-instance ( path$ ) set-instance-address ( path$ ) ; \ Open pathname components until the last one, and then apply the indicated \ method to the last component. : open-path ( path$ -- ) ?dup if ( path$ ) \ Establish the initial parent null to current-device ( path$ ) 0 to interposer ?expand-alias select-node ( path$ ) begin dup while open-node select-node repeat ( path$' ) 2drop ( ) else ( adr ) not-found throw ( ) then ( ) ; headers : open-package ( args$ phandle -- ihandle ) push-package ( args$ ) new-instance ( ) "open" apply-method if false then if ( ) my-self my-parent is my-self ( ihandle ) else ( ) destroy-instance 0 ( 0 ) then ( ihandle ) pop-package ( ihandle ) ; : find-package ( name$ -- false | phandle true ) dup 0= if true else over c@ ascii / <> then ( name$ relative? ) if ( name$ ) " /packages/" package-name-buf pack $cat ( ) package-name-buf count ( name$' ) then ( name$' ) locate-device 0= ( false | phandle true ) ; : $open-package ( arg$ name$ -- ihandle ) find-package if open-package else 2drop 0 then ; headers : begin-open-dev ( path$ -- ihandle ) 0 package( current-device >r \ Since "catch/throw" saves and restores my-self, \ my-self will be 0 if a throw occurred. ['] open-path catch if 2drop then my-self ( ihandle ) r> push-device )package ( ihandle ) ; headerless : (open-dev) ( path$ -- ) open-path open-node ; headers : open-dev ( adr len -- ihandle | 0 ) 0 package( current-device >r \ Since "catch/throw" saves and restores my-self, \ my-self will be 0 if a throw occurred. ['] (open-dev) catch if 2drop then my-self ( ihandle ) r> push-device )package ( ihandle ) ; headerless : (execute-method) ( path$ method$ -- false | ??? true ) 2swap open-path (apply-method) ; \ Same as (execute-method), but use (open-dev) instead of open-path : (execute-method-opened) ( path$ method$ -- false | ??? true ) 2swap (open-dev) (apply-method) ; headers : execute-device-method ( path$ method$ -- false | ??? true ) 0 package( current-device >r ( path$ method$ ) ['] (execute-method) catch if ( x x x x ) 2drop 2drop false ( false ) else ( ??? ) close-chain true ( ??? true ) then ( false | ??? true ) device-end ( false | ??? true ) r> push-device )package ( false | ??? true ) ; \ Same as execute-device-method, but open device before calling method : execute-method-opened ( path$ method$ -- false | ??? true ) 0 package( current-device >r ( path$ method$ ) ['] (execute-method-opened) catch if ( x x x x ) 2drop 2drop false ( false ) else ( ??? ) close-parents true ( ??? true ) then ( false | ??? true ) device-end ( false | ??? true ) r> push-device )package ( false | ??? true ) ; \ Easier to use version of execute-device-method \ \ ex: apply selftest net \ : apply ( -- ??? ) \ method { devpath | alias } safe-parse-word safe-parse-word ( method$ devpath$ ) 2swap execute-device-method ( ??? success? ) 0= abort" apply failed." ( ??? ) ; h# 10 circular-stack: istack \ select-dev opens a package, sets my-self to that ihandle, pushes the \ old my-self on the instance stack, and pushes that package's vocabulary \ on the search order. unselect-dev undoes select-dev . : iselect ( ihandle -- ) dup 0= abort" Can't open device" ( ihandle ) my-self istack push is my-self also my-voc push-device ; : select-dev ( adr,len -- ) open-dev iselect ; : begin-select-dev ( adr,len -- ) begin-open-dev iselect ; : end-select-dev ( -- ) previous definitions my-parent istack pop is my-self close-dev ; : select ( "name" -- ) safe-parse-word select-dev ; : begin-select ( "name" -- ) safe-parse-word begin-select-dev ; : unselect-dev ( -- ) previous definitions my-self istack pop is my-self close-dev ; : begin-package ( arg-str reg-str parent-str -- ) select-dev new-device set-args ; : end-package ( -- ) finish-device unselect-dev ; : (execute-phandle-method) ( method-adr,len phandle -- ??? ) 0 to unit#-valid? ( method-adr,len phandle ) dup >parent null open-parents ( method-adr,len phandle ) push-device ( method-adr,len ) " " new-instance ( method-adr,len ) set-default-unit ( method-adr,len ) (apply-method) ( ???? ) ; headers : open-phandle ( phandle -- ihandle | 0 ) 0 package( ( phandle ) current-device >r ( phandle ) 0 to unit#-valid? ( phandle ) null ['] open-parents catch if ( x x error-code ) 3drop 0 ( 0 ) else ( ) my-self ( ihandle ) then ( ihandle | 0 ) r> push-device ( ihandle | 0 ) )package ( ihandle | 0 ) ; : execute-phandle-method ( method-adr,len phandle -- false | ??? true ) 0 package( ( method-adr,len phandle ) current-device >r ( method-adr,len phandle ) ['] (execute-phandle-method) catch if ( method-adr,len phandle err-code ) 3drop false ( false ) else ( ??? ) close-chain true ( ??? true ) then ( false | ??? true ) r> push-device ( false | ??? true ) )package ( false | ??? true ) ; : create-dev-instance ( arg$ phandle -- ihandle ) my-self >r ( arg$ phandle ) dup >parent open-phandle to my-self ( ) push-package new-instance set-instance-address pop-package ( ) my-self r> to my-self ( ihandle ) ; : destroy-dev-instance ( ihandle -- ) my-self >r to my-self ( ) destroy-instance my-self close-dev ( ) r> to my-self ( ) ; : .path ( ihandle -- ) dup if ihandle>devname type cr else drop then ; headerless