150 lines
5 KiB
Forth
150 lines
5 KiB
Forth
\ *****************************************************************************
|
|
\ * Copyright (c) 2004, 2008 IBM Corporation
|
|
\ * All rights reserved.
|
|
\ * This program and the accompanying materials
|
|
\ * are made available under the terms of the BSD License
|
|
\ * which accompanies this distribution, and is available at
|
|
\ * http://www.opensource.org/licenses/bsd-license.php
|
|
\ *
|
|
\ * Contributors:
|
|
\ * IBM Corporation - initial implementation
|
|
\ ****************************************************************************/
|
|
|
|
\ this is a C-to-Forth translation from the translate
|
|
\ address code in the client
|
|
\ with extensions to handle different sizes of #size-cells
|
|
|
|
\ this tries to figure out if it is a PCI device what kind of
|
|
\ translation is wanted
|
|
\ if prop_type is 0, "reg" property is used, otherwise "assigned-addresses"
|
|
: pci-address-type ( node address prop_type -- type )
|
|
-rot 2 pick ( prop_type node address prop_type )
|
|
0= IF
|
|
swap s" reg" rot get-property ( prop_type address data dlen false )
|
|
ELSE
|
|
swap s" assigned-addresses" rot get-property ( prop_type address data dlen false )
|
|
THEN
|
|
IF 2drop -1 EXIT THEN 4 / 5 /
|
|
\ advance (phys-addr(3) size(2)) steps
|
|
0 DO
|
|
\ BARs and Expansion ROM must be in assigned-addresses...
|
|
\ so if prop_type is 0 ("reg") and a config space offset is set
|
|
\ we skip this entry...
|
|
dup l@ FF AND 0<> ( prop_type address data cfgspace_offset? )
|
|
3 pick 0= ( prop_type address data cfgspace_offset? reg_prop? )
|
|
AND NOT IF
|
|
2dup 4 + ( prop_type address data address data' )
|
|
2dup @ 2 pick 8 + @ + <= -rot @ >= and IF
|
|
l@ 03000000 and 18 rshift nip
|
|
( prop_type type )
|
|
swap drop ( type )
|
|
UNLOOP EXIT
|
|
THEN
|
|
THEN
|
|
\ advance in 4 byte steps and (phys-addr(3) size(2)) steps
|
|
4 5 * +
|
|
LOOP
|
|
3drop -1
|
|
;
|
|
|
|
: (range-read-cells) ( range-addr #cells -- range-value )
|
|
\ if number of cells != 1; do 64bit read; else a 32bit read
|
|
1 = IF l@ ELSE @ THEN
|
|
;
|
|
|
|
\ this functions tries to find a mapping for the given address
|
|
\ it assumes that if we have #address-cells == 3 that we are trying
|
|
\ to do a PCI translation
|
|
|
|
\ nac - #address-cells
|
|
\ nsc - #size-cells
|
|
\ pnac - parent #address-cells
|
|
|
|
: (map-one-range) ( type range pnac nsc nac address -- address true | address false )
|
|
\ only check for the type if nac == 3 (PCI)
|
|
over 3 = 5 pick l@ 3000000 and 18 rshift 7 pick <> and IF
|
|
>r 2drop 3drop r> false EXIT
|
|
THEN
|
|
\ get size
|
|
4 pick 4 pick 3 pick + 4 * +
|
|
\ get nsc
|
|
3 pick
|
|
\ read size
|
|
( type range pnac nsc nac address range nsc )
|
|
(range-read-cells)
|
|
( type range pnac nsc nac address size )
|
|
\ skip type if PCI
|
|
5 pick 3 pick 3 = IF
|
|
4 +
|
|
THEN
|
|
\ get nac
|
|
3 pick
|
|
( type range pnac nsc nac address size range nac )
|
|
\ read child-mapping
|
|
(range-read-cells)
|
|
( type range pnac nsc nac address size child-mapping )
|
|
dup >r dup 3 pick > >r + over <= r> or IF
|
|
\ address is not inside the mapping range
|
|
>r 2drop 3drop r> r> drop false EXIT
|
|
THEN
|
|
dup r> -
|
|
( type range pnac nsc nac address offset )
|
|
\ add the offset on the parent mapping
|
|
5 pick 5 pick 3 = IF
|
|
\ skip type if PCI
|
|
4 +
|
|
THEN
|
|
3 pick 4 * +
|
|
( type range pnac nsc nac address offset parent-mapping-address )
|
|
\ get pnac
|
|
5 pick
|
|
\ read parent mapping
|
|
(range-read-cells)
|
|
( type range pnac nsc nac address offset parent-mapping )
|
|
+ >r 3drop 3drop r> true
|
|
;
|
|
|
|
\ this word translates the given address starting from the node specified
|
|
\ in node; the word will return to the node it was started from
|
|
: translate-address ( node address -- address )
|
|
\ check for address type in "assigned-addresses"
|
|
2dup 1 pci-address-type ( node address type )
|
|
dup -1 = IF
|
|
\ not found in "assigned-addresses", check in "reg"
|
|
drop 2dup 0 pci-address-type ( node address type )
|
|
THEN
|
|
rot parent BEGIN
|
|
\ check if it is the root node
|
|
dup parent 0= IF 2drop EXIT THEN
|
|
( address type parent )
|
|
s" #address-cells" 2 pick get-property 2drop l@ >r \ nac
|
|
s" #size-cells" 2 pick get-property 2drop l@ >r \ nsc
|
|
s" #address-cells" 2 pick parent get-property 2drop l@ >r \ pnac
|
|
-rot ( node address type )
|
|
s" ranges" 4 pick get-property IF
|
|
3drop
|
|
ABORT" no ranges property; not translatable"
|
|
THEN
|
|
r> r> r> 3 roll
|
|
( node address type ranges pnac nsc nac length )
|
|
4 / >r 3dup + + >r 5 roll r> r> swap / 0 ?DO
|
|
( node type ranges pnac nsc nac address )
|
|
6dup (map-one-range) IF
|
|
nip leave
|
|
THEN
|
|
nip
|
|
\ advance ranges
|
|
4 roll
|
|
( node type pnac nsc nac address ranges )
|
|
4 pick 4 pick 4 pick + + 4 * + 4 -roll
|
|
LOOP
|
|
>r 2drop 2drop r> ( node type address )
|
|
swap rot parent ( address type node )
|
|
dup 0=
|
|
UNTIL
|
|
;
|
|
|
|
\ this words translates the given address starting from the current node
|
|
: translate-my-address ( address -- address' )
|
|
get-node swap translate-address
|
|
;
|