historical/m0-applesillicon.git/xnu-qemu-arm64-5.1.0/roms/openbios/forth/device/pathres.fs
2024-01-16 11:20:27 -06:00

522 lines
12 KiB
Forth

\ tag: Path resolution
\
\ this code implements IEEE 1275-1994 path resolution
\
\ Copyright (C) 2003 Samuel Rydh
\
\ See the file "COPYING" for further information about
\ the copyright and warranty status of this work.
\
0 value interpose-ph
0 0 create interpose-args , ,
: expand-alias ( alias-addr alias-len -- exp-addr exp-len expanded? )
2dup
" /aliases" find-dev 0= if 2drop false exit then
get-package-property if
false
else
2swap 2drop
\ drop trailing 0 from string
dup if 1- then
true
then
;
\
\ 4.3.1 Resolve aliases
\
\ the returned string is allocated with alloc-mem
: pathres-resolve-aliases ( path-addr path-len -- path-addr path-len )
over c@ 2f <> if
200 here + >r \ abuse dictionary for temporary storage
\ If the pathname does not begin with "/", and its first node name
\ component is an alias, replace the alias with its expansion.
ascii / split-before \ (PATH_NAME, "/") -> (TAIL HEAD)
ascii : split-before \ (HEAD, ":") -> (ALIAS_ARGS AL_NAME)
expand-alias ( TAIL ALIAS_ARGS EXP_ALIAS_NAME expanded? )
if
2 pick 0<> if \ If ALIAS_ARGS is not empty
ascii / split-after \ (ALIAS_NAME, "/") -> (AL_TAIL AL_HEAD/)
2swap ( TAIL AL_HEAD/ AL_TAIL )
ascii : split-before \ (AL_TAIL, ":") -> (DEAD_ARGS AL_TAIL)
2swap 2drop ( TAIL AL_ARGS AL_HEAD ALIAS_TAIL )
2swap ( TAIL AL_ARGS AL_TAIL AL_HEAD )
r> tmpstrcat tmpstrcat >r
else
2swap 2drop \ drop ALIAS_ARGS
then
r> tmpstrcat drop
else
\ put thing back together again
r> tmpstrcat tmpstrcat drop
then
then
strdup
( path-addr path-len )
;
\
\ search struct
\
struct ( search information )
2 cells field >si.path
2 cells field >si.arguments
2 cells field >si.unit_addr
2 cells field >si.node_name
2 cells field >si.free_me
4 cells field >si.unit_phys
/n field >si.unit_phys_len
/n field >si.save-ihandle
/n field >si.save-phandle
/n field >si.top-ihandle
/n field >si.top-opened \ set after successful open
/n field >si.child \ node to match
constant sinfo.size
\
\ 4.3.6 node name match criteria
\
: match-nodename ( childname len sinfo -- match? )
>r
2dup r@ >si.node_name 2@
( [childname] [childname] [nodename] )
strcmp 0= if r> 3drop true exit then
\ does NODE_NAME contain a comma?
r@ >si.node_name 2@ ascii , strchr
if r> 3drop false exit then
( [childname] )
ascii , left-split 2drop r@ >si.node_name 2@
r> drop
strcmp if false else true then
;
\
\ 4.3.4 exact match child node
\
\ If NODE_NAME is not empty, make sure it matches the name property
: common-match ( sinfo -- )
>r
\ a) NODE_NAME nonempty
r@ >si.node_name 2@ nip if
" name" r@ >si.child @ get-package-property if -1 throw then
\ name is supposed to be null-terminated
dup 0> if 1- then
\ exit if NODE_NAME does not match
r@ match-nodename 0= if -2 throw then
then
r> drop
;
: (exact-match) ( sinfo -- )
>r
\ a) If NODE_NAME is not empty, make sure it matches the name property
r@ common-match
\ b) UNIT_PHYS nonempty?
r@ >si.unit_phys_len @ /l* ?dup if
\ check if unit_phys matches
" reg" r@ >si.child @ get-package-property if -3 throw then
( unitbytes propaddr proplen )
rot r@ >si.unit_phys -rot
( propaddr unit_phys proplen unitbytes )
swap over < if -4 throw then
comp if -5 throw then
else
\ c) both NODE_NAME and UNIT_PHYS empty?
r@ >si.node_name 2@ nip 0= if -6 throw then
then
r> drop
;
: exact-match ( sinfo -- match? )
['] (exact-match) catch if drop false exit then
true
;
\
\ 4.3.5 wildcard match child node
\
: (wildcard-match) ( sinfo -- match? )
>r
\ a) If NODE_NAME is not empty, make sure it matches the name property
r@ common-match
\ b) Fail if "reg" property exist
" reg" r@ >si.child @ get-package-property 0= if -7 throw then
\ c) Fail if both NODE_NAME and UNIT_ADDR are both empty
r@ >si.unit_phys_len @
r@ >si.node_name 2@ nip
or 0= if -1 throw then
\ SUCCESS
r> drop
;
: wildcard-match ( sinfo -- match? )
['] (wildcard-match) catch if drop false exit then
true
;
\
\ 4.3.3 match child node
\
\ used if package lacks a decode-unit method
: def-decode-unit ( str len -- unitaddr ... )
parse-hex
;
: get-decode-unit-xt ( phandle -- xt )
" decode-unit" rot find-method
0= if ['] def-decode-unit then
;
: find-child ( sinfo -- phandle )
>r
\ decode unit address string
r@ >si.unit_addr 2@ dup if
( str len )
active-package get-decode-unit-xt
depth 3 - >r execute depth r@ - r> swap
( ... a_lo ... a_hi olddepth n )
4 min 0 max
dup r@ >si.unit_phys_len !
( ... a_lo ... a_hi olddepth n )
r@ >si.unit_phys >r
begin 1- dup 0>= while
rot r> dup la1+ >r l!-be
repeat
r> 2drop
depth!
else
2drop
\ clear unit_phys
0 r@ >si.unit_phys_len !
\ r@ >si.unit_phys 4 cells 0 fill
then
( R: sinfo )
['] exact-match
begin dup while
active-package >dn.child @
begin ?dup while
dup r@ >si.child !
( xt phandle R: sinfo )
r@ 2 pick execute if 2drop r> >si.child @ exit then
>dn.peer @
repeat
['] exact-match = if ['] wildcard-match else 0 then
repeat
-99 throw
;
\
\ 4.3.2 Create new linked instance procedure
\
: link-one ( sinfo -- )
>r
active-package create-instance
dup 0= if -99 throw then
\ change instance parent
r@ >si.top-ihandle @ over >in.my-parent !
dup r@ >si.top-ihandle !
to my-self
\ b) set my-args field
r@ >si.arguments 2@ strdup my-self >in.arguments 2!
\ e) set my-unit field
r@ >si.unit_addr 2@ nip if
\ copy UNIT_PHYS to the my-unit field
r@ >si.unit_phys my-self >in.my-unit 4 cells move
else
\ set unit-addr from reg property
" reg" active-package get-package-property 0= if
\ ( ihandle prop proplen )
\ copy address to my-unit
4 cells min my-self >in.my-unit swap move
else
\ clear my-unit
my-self >in.my-unit 4 cells 0 fill
then
then
\ top instance has not been opened (yet)
false r> >si.top-opened !
;
: invoke-open ( sinfo -- )
" open" my-self ['] $call-method
catch if 3drop false then
0= if -99 throw then
true swap >si.top-opened !
;
\
\ 4.3.7 Handle interposers procedure (supplement)
\
: handle-interposers ( sinfo -- )
>r
begin
interpose-ph ?dup
while
0 to interpose-ph
active-package swap active-package!
\ clear unit address and set arguments
0 0 r@ >si.unit_addr 2!
interpose-args 2@ r@ >si.arguments 2!
r@ link-one
true my-self >in.interposed !
interpose-args 2@ free-mem
r@ invoke-open
active-package!
repeat
r> drop
;
\
\ 4.3.1 Path resolution procedure
\
\ close-dev ( ihandle -- )
\
: close-dev
begin
dup
while
dup >in.my-parent @
swap close-package
repeat
drop
;
: path-res-cleanup ( sinfo close? )
\ tear down all instances if close? is set
if
dup >si.top-opened @ if
dup >si.top-ihandle @
?dup if close-dev then
else
dup >si.top-ihandle @ dup
( sinfo ihandle ihandle )
dup if >in.my-parent @ swap then
( sinfo parent ihandle )
?dup if destroy-instance then
?dup if close-dev then
then
then
\ restore active-package and my-self
dup >si.save-ihandle @ to my-self
dup >si.save-phandle @ active-package!
\ free any allocated memory
dup >si.free_me 2@ free-mem
sinfo.size free-mem
;
: (path-resolution) ( context sinfo -- )
>r r@ >si.path 2@
( context pathstr pathlen )
\ this allocates a copy of the string
pathres-resolve-aliases
2dup r@ >si.free_me 2!
\ If the pathname, after possible alias expansion, begins with "/",
\ begin the search at the root node. Otherwise, begin at the active
\ package.
dup if \ make sure string is not empty
over c@ 2f = if
swap char+ swap /c - \ Remove the "/" from PATH_NAME.
\ Set the active package to the root node.
device-tree @ active-package!
then
then
r@ >si.path 2!
0 0 r@ >si.unit_addr 2!
0 0 r@ >si.arguments 2!
0 r@ >si.top-ihandle !
\ If there is no active package, exit this procedure, returning false.
( context )
active-package 0= if -99 throw then
\ Begin the creation of an instance chain.
\ NOTE--If, at this step, the active package is not the root node and
\ we are in open-dev or execute-device-method contexts, the instance
\ chain that results from the path resolution process may be incomplete.
active-package swap
( virt-active-node context )
begin
r@ >si.path 2@ nip \ nonzero path?
while
\ ( active-node context )
\ is this open-dev or execute-device-method context?
dup if
r@ link-one
over active-package <> my-self >in.interposed !
r@ invoke-open
r@ handle-interposers
then
over active-package!
r@ >si.path 2@ ( PATH )
ascii / left-split ( PATH COMPONENT )
ascii : left-split ( PATH ARGS NODE_ADDR )
ascii @ left-split ( PATH ARGS UNIT_ADDR NODE_NAME )
r@ >si.node_name 2!
r@ >si.unit_addr 2!
r@ >si.arguments 2!
r@ >si.path 2!
( virt-active-node context )
\ 4.3.1 i) pathname has a leading %?
r@ >si.node_name 2@ 2dup 2dup ascii % strchr nip = if
1- swap 1+ swap r@ >si.node_name 2!
" /packages" find-dev drop active-package!
r@ find-child
else
2drop
nip r@ find-child swap over
( new-node context new-node )
then
\ (optional: open any nodes between parent and child )
active-package!
repeat
( virt-active-node type )
dup if r@ link-one then
1 = if
dup active-package <> my-self >in.interposed !
r@ invoke-open
r@ handle-interposers
then
active-package!
r> drop
;
: path-resolution ( context path-addr path-len -- sinfo true | false )
\ allocate and clear the search block
sinfo.size alloc-mem >r
r@ sinfo.size 0 fill
\ store path
r@ >si.path 2!
\ save ihandle and phandle
my-self r@ >si.save-ihandle !
active-package r@ >si.save-phandle !
\ save context (if we take an exception)
dup
r@ ['] (path-resolution)
catch ?dup if
( context xxx xxx error )
r> true path-res-cleanup
\ rethrow everything except our "cleanup throw"
dup -99 <> if throw then
3drop
\ ( context ) throw an exception if this is find-device context
if false else -22 throw then
exit
then
\ ( context )
drop r> true
( sinfo true )
;
: open-dev ( dev-str dev-len -- ihandle | 0 )
1 -rot path-resolution 0= if false exit then
( sinfo )
my-self swap
false path-res-cleanup
( ihandle )
;
: execute-device-method
( ... dev-str dev-len met-str met-len -- ... false | ?? true )
2swap
2 -rot path-resolution 0= if 2drop false exit then
( method-str method-len sinfo )
>r
my-self ['] $call-method catch
if 3drop false else true then
r> true path-res-cleanup
;
: find-device ( dev-str dev-len -- )
2dup " .." strcmp 0= if
2drop
active-package dup if >dn.parent @ then
\ ".." in root note?
dup 0= if -22 throw then
active-package!
exit
then
0 -rot path-resolution 0= if false exit then
( sinfo )
active-package swap
true path-res-cleanup
active-package!
;
\ find-device, but without side effects
: (find-dev) ( dev-str dev-len -- phandle true | false )
active-package -rot
['] find-device catch if 3drop false exit then
active-package swap active-package! true
;
\ Tuck on a node at the end of the chain being created.
\ This implementation follows the interpose recommended practice
\ (v0.2 draft).
: interpose ( arg-str arg-len phandle -- )
to interpose-ph
strdup interpose-args 2!
;
['] (find-dev) to find-dev