As a newbee in this space I got qemu-system-sparc[64] running on a linux machine.
Trying to find out how qemu and openbios work together I'm currently looking into building openbios-sparc64.
This goes with mixed success as https://www.openfirmware.info/OpenBIOS has nice description on how to build openbios, but there's a missing link as to how to harvest the openbios-sparc64 from this.
My build of openbios is done on an Ultra60(Sparc) machine that runs:
Linux ultra60 4.19.0-2-sparc64 #1 Debian 4.19.16-1 (2019-01-17) sparc64 GNU/Linux
with gcc --version
gcc (Debian 8.3.0-2) 8.3.0
It seems like the file openbios/obj-sparc64/openbios-builtin.elf may be the candidate to become openbios-sparc64??
When giving this a try, and moving openbios-builtin.elf to my x86 qemu machine, it crashes spectacularly with:
qemu: fatal: Trap 0x0064 while trap level (5) >= MAXTL (5), Error state
pc: 0000000000004c80 npc: 0000000000004c84
%g0-3: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%g4-7: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%o0-3: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%o4-7: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%l0-3: 00000000fff001e0 000001ff00000000 000001fff0080000 0000000000000000
%l4-7: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%i0-3: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%i4-7: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%f00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%f08: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%f16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%f24: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%f32: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%f40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%f48: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
%f56: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
pstate: 00000414 ccr: 44 (icc: -Z-- xcc: -Z--) asi: 00 tl: 5 pil: 0 gl: 2
tbr: 0000000000000000 hpstate: 0000000000000000 htba: 0000000000000000
cansave: 6 canrestore: 0 otherwin: 0 wstate: 0 cleanwin: 6 cwp: 7
fsr: 0000000000000000 y: 0000000000000000 fprs: 0000000000000000
On x86: Booting qemu with the provided openbios-sparc64 rom works flawless.
On the Ultra60: Running ./openbios-unix openbios-sparc64.dict seems to behave as expected:
Output device screen not found.
Input device keyboard not found.
Output device screen not found.
Type 'help' for detailed information
[unix] Booting default not supported.
Trying disk...
No valid state has been set by load or init-program
0 > help
To get openbios build, I had to make a small change in Makefile.target:
#CFLAGS+= -Werror
CFLAGS+= -Wno-error
To "fix":
Building OpenBIOS for sparc64
Building...
/usr/bin/xsltproc
error:
CC target/arch/unix/unix.o
CC target/arch/unix/boot.o
/sources/openbios/arch/unix/boot.c:101:6: error: redundant redeclaration of 'forth_fw_cfg_read_file' [-Werror=redundant-decls]
void forth_fw_cfg_read_file(void);
^~~~~~~~~~~~~~~~~~~~~~
In file included from ./target/include/asm/io.h:8,
from /sources/openbios/include/kernel/kernel.h:22,
from /sources/openbios/include/libopenbios/bindings.h:21,
from /sources/openbios/arch/unix/boot.c:6:
/sources/openbios/include/arch/common/fw_cfg.h:104:6: note: previous declaration of 'forth_fw_cfg_read_file' was here
void forth_fw_cfg_read_file(void);
^~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
Any pointers or suggestions to continue this journey are appreciated.
To help reading property listing also format assigned-addresses
property the same way as reg was already formatted.
Signed-off-by: BALATON Zoltan <balaton(a)eik.bme.hu>
---
Actually wanted to improve printing of ranges but I could not do that
this one is simpler though.
forth/admin/devices.fs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/forth/admin/devices.fs b/forth/admin/devices.fs
index 6f9e8ef..38f6ad6 100644
--- a/forth/admin/devices.fs
+++ b/forth/admin/devices.fs
@@ -417,7 +417,7 @@
\ This function hardwires data formats to particular node properties
: (.property-by-name) ( name-str name-len data len -- )
- 2over " reg" strcmp 0= if
+ 2over 2dup " reg" strcmp 0= -rot " assigned-addresses" strcmp 0= or if
my-#acells my-#scells 2swap .p-reg
2drop exit
then
--
2.13.7
Hello,
On Tue, 30 Jul 2019, BALATON Zoltan wrote:
> 3. Try to get some other OF implementation working like OpenFirmware. Based
> on previous work by Atar for the 40p this is possible although to do it
> cleanly may be more work and hindered by the need to do it in Forth
> completely. But Forth is needed to hack on OpenBIOS as well so once someone
> gets over that hurdle it does not matter. I've started looking at this
> posibility to find out how much work would this be that's why I was asking
> the question. I've compiled Atar's work which is now upstram in Mitch
> Bradley's tree and it worked well with 40p and even started with pegasos2 but
> of course it did not init the hardware correctly expecting to run on 40p
> (haven't tried with mac99 but I expect the same result). So OpenFirmware
> already works on PPC and has some QEMU specific drivers what we may need is
> porting drivers for mac specific and pegasos2 devices from OpenBIOS from C to
> Forth (or get equivalents from somewhere else) and think about how to pass
> the initial device tree similar to SLOF to avoid having to implement each
> board in OpenFirmware separately (although doing hardcoded board
> implementation like Atar's 40p might be a quick and dirty way to get it
> working with much less work).
I gave it a try playing with it for a few hours (without really knowing
what am I doing) just to get to know it better and see what's needed. So I
started by stripping down Atar's QEMU PReP port removing PReP specific
parts and just leaving a bare minimum to work on PowerPC and I actually
managed to build a ROM image that works with my pegasos2 emulation and
gets me an OF environment over diag serial port now:
$ qemu-system-ppc -M pegasos2 -bios ofw.rom -serial stdio
setup_mem_windows: Should enable region 14
Mapping pci1-io-win 0x0+0x2000000 @ 0xfe000000
setup_mem_windows: Should enable region 20
Type 'i' to interrupt stand-init sequence
First stand-init:
Calibrate
CIF buffers
DHCP init
memory node
Instruction cache on
Decrementer
Enable machine check exceptions
Set Memory Map
MMU
Root node
Data cache on
Fast CPU mode
PCI host bridge
CPU nodes
Keyboard overrides
Memory node
not found.
not found.
/pci/isa/serial@i2f8 not found.
/pci/isa/serial@i2f8 not found.
not found.
not found.
, Serial #0, 128 MiB memory installed
Open Firmware
Copyright (c) 1995-2000, FirmWorks.
Copyright (c) 2014,2017,2019 Artyom Tarasenko.
Type any key to interrupt automatic startup
6 5 4 3 2 1
Boot device: net Arguments:
Can't open boot device
ok show-devs
/dropin-fs
/null-nvram
/cpus
/<Unnamed>
/mmu
/memory@0
/aliases
/options
/openprom
/chosen
/packages
/cpus/PowerPC,603evARTHUR@0
/packages/ext2-file-system
/packages/disk-label
/packages/iso9660-file-system
/packages/fat-file-system
/packages/obp-tftp
/packages/deblocker
/packages/stringio
/packages/terminal-emulator
/packages/client-services
ok printenv
Variable Name Value Default Value
hrp-memmap? false false
virt-size 0x0 0xffffffff
virt-base 0x0 0xffffffff
real-size 0x0 0xffffffff
real-base 0x0 0xffffffff
real-mode? false false
diag-switch? false false
fcode-debug? false false
ip-address 255.255.255.255 255.255.255.255
ip-router
ip-domain
ip-netmask 255.255.255.0 255.255.255.0
ip-dns-server
local-mac-address? false false
oem-logo
oem-logo? false false
oem-banner
oem-banner? false false
output-device /pci/isa/serial@i2f8 /pci/isa/serial@i2f8
input-device /pci/isa/serial@i2f8 /pci/isa/serial@i2f8
load-base 4194304 4194304
boot-command boot boot
auto-boot? true true
watchdog-reboot? false false
diag-file
diag-device net net
boot-file
boot-device disk net disk net
ansi-terminal? true true
screen-#columns 80 80
screen-#rows 34 34
silent-mode? false false
use-nvramrc? false false
nvramrc
security-password
security-#badlogins 0
security-mode none
diag-switch? false false
ok dev /
ok .properties
#address-cells 00000001
ok dev openprom
ok .properties
model FirmWorks,3.0
aligned-allocator
relative-addressing
name openprom
ok dev /cpus/PowerPC,603evARTHUR
ok .properties
clock-frequency 05f5e100
reg 00000000
timebase-frequency 007de290
tlb-sets 00000080
tlb-size 00000100
d-cache-sets 00000080
d-cache-block-size 00000020
d-cache-size 00008000
i-cache-sets 00000080
i-cache-block-size 00000020
i-cache-size 00008000
device_type cpu
name PowerPC,603evARTHUR
ok
Of course it's only the start and has a lot of missing parts yet: does not
detect PCI bus and devices (I need to write a driver for the PCI host
similar to what Atar did for 40p), it misdetects the CPU (or it may be
hard coded somewhere), does not detect memory size (this is mentioned on
Atar's blog) and may have other defficiencies. But for a start it works
quite well and it was surprisingly easy to get it up thanks to previous
work. Given that the Pegasos2 is quite close to PReP and PC hardware most
of the drivers for PC like hardware are already there in OF, so maybe if I
can make a working driver for the system controller chip the rest would
just work or should be relatively easy to fix. So for the pegasos2 this
seems to be a viable alternative that may not be too hard to get working
if I limit the scope to just the pegasos2.
For Mac machines more drivers would need to be written as these are not
included in the open source OF version that was released for OLPC so only
those drivers are included which were needed for that. Therefore it would
be more work to write those missing drivers. We have USB driver (I've once
tried porting that to OpenBIOS[1]) so keyboard and mouse might work where
we have USB but we would still need drivers for uninorth and mac-io at
least to get something working but maybe others as well, I'm not sure.
For Sparc machines even CPU support is missing so it may be more difficult
to get that working. Or maybe not as this could be added based on some
other similar architecture: arm, mips and ppc are already there but these
do have a lot of Forth files so it may take a while to understand those. I
don't know Sparc hardware to tell what drivers may be needed.
But from Atar's blog on getting OF working for QEMU PReP/40p I got the
impression that Mitch Bradley (inventor of OpenFirmware and founder of
FirmWorks) did help him by releasing some additional drivers or sources
that he needed so maybe asking politely would not hurt and it may get
easier, unless there are legal hurdles in releasing additional sources.
Otherwise those need to be recreated but that may still be doable if
someone does not mind learning enough Forth to do it.
I'm not sure which is more work, getting OpenBIOS to the same level or
writing drivers for OpenFirmware but maybe for PPC machines it's not much
harder to rewrite the missing drivers. For Sparc I'm not sure, PPC support
was already there so I don't know what it takes to add a new cpu support.
Regards,
BALATON Zoltan
[1] One can follow the thread starting here:
https://mail.coreboot.org/pipermail/openbios/2014-May/008244.html
but basically the attempt to port OF driver to OpenBIOS ended with:
https://mail.coreboot.org/pipermail/openbios/2014-May/008281.html
some of those words are already there now but some are still missing.
I've ended up finishing the C driver which was finally added, even though
I only wanted to try qemu-system-ppc64 originally and did not plan to port
a USB driver. That's what I meant saying I end up having to do fixes
whenever I try something in OpenBIOS: like trying an FCode ROM the last
time. At least OpenFirmware implements the standard already perfectly so
we would only need to care about getting it to work with the machine and
not if it has everythung that might be needed by stuff using it (or at
least much less so than starting from scratch).
Hello,
I'm trying to find out what's missing to use an FCode ROM for the ati-vga
device to see how it would set up the card for MacOS. This has been done
before for other FCode ROMs e.g. here:
https://mail.coreboot.org/hyperkitty/list/openbios@openbios.org/thread/E7PF…
I can get some print out of compiling and defining new words by setting
fcode-debug? and ?fcode-verbose to true as above but this only gives me
what I can also get from detok but does not tell me where exactly it fails
during executing these words afterwards. What I get is that after a lot of
(compile), new-token and fcode# lines that define a lot of words it just
ends in one of these (the second?) when executed:
400514a : [ 0x8bc ]
400514c : [ 0x926 ]
byte-load: exception caught!
But how can I see what's inside this word that caused the exception?
There's the forth debugger I think to see or step through execution of
words but how can I add an undefined/unnamed word to the debug before the
the FCode runs?
Looking at the definition of this word in the detok output does not get me
further as it just calls more of these words defined in the FCode:
8512: b(:)
8513: (unnamed-fcode) [0x86a]
8515: (unnamed-fcode) [0x864]
8517: b(") ( len=7 )
" map-out"
8526: (unnamed-fcode) [0x91f]
8528: (unnamed-fcode) [0x86c]
8530: (unnamed-fcode) [0x866]
8532: b(") ( len=7 )
" map-out"
8541: (unnamed-fcode) [0x91f]
8543: 0
8544: b(to) (unnamed-fcode) [0x86c]
8547: 0
8548: b(to) (unnamed-fcode) [0x86a]
8551: b(;)
8552: new-token 0x926
so where can I get more details on execution of these words and the more
precise location of the exception?
Regards,
BALATON Zoltan
I think I’ll just wait for all this stuff to git into the master of Qemu and Openbios and try and see if I can work with it then.
> On Jul 30, 2019, at 8:38 AM, BALATON Zoltan <balaton(a)eik.bme.hu> wrote:
>
> On Tue, 30 Jul 2019, Jd Lyons wrote:
>> patches, I really don’t want to format and apply 30 patches from emails, mostly because I don’t know how to properly use the patch command……...
>
> If you have the 30 patches in emails then git am is the tool to apply them. Save them in an mbox folder in ascending order (or just cat the raw message sources together in one file which is what an mbox folder is), or it may also work with messages in a folder, then use git am to apply them. Check git am --help for more info.
>
> Apparently there was some formatting error in my patch as others got problem with that as well so sorry about that.
>
> Regards,
> BALATON Zoltan
This patchset started off with the aim of building the PCI-based machine
device trees downwards from the root node to avoid switching either the active
package and/or current instance at various points during the tree construction.
The basis for this was to try and remove all named nodes (those which are
placed at a given path) and instead build the hierarchy in order by using
new-device and finish-device as per the IEEE-1275 specification. This was
realised by creating a new BIND_NODE_METHODS() macro which is similar to
REGISTER_NAMED_NODE() except that it doesn't alter either the active package
or the current instance, and then working through the device tree from the
root converting all the devices for the PCI-based machines to use it.
Once this conversion has been completed for all devices beneath the PCI node,
it becomes possible to remove both the REGISTER_NAMED_NODE() and
REGISTER_NAMED_NODE_PHANDLE() macros to prevent future patches from accidentally
changing the tree construction order.
Next the x86, PPC and SPARC64 device tree roots were altered to set the active
package and current instance, allowing the remaining places where the PCI code
alters either of them to be removed.
At this point instance variables were working correctly, and I noticed that
there were several PCI devices which made use of C initialisation functions and/or
properties for initial configuration. These can now be replaced with instance
variables to keep everything simple and consistent.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland(a)ilande.co.uk>
v2:
- Fix up NVRAM initialisation so that -prom-env 'vga-ndrv?=false' works again
Mark Cave-Ayland (30):
libopenbios: introduce BIND_NODE_METHODS() macro
pc_kbd: convert to use BIND_NODE_METHODS() macro
pc_serial: convert to use BIND_NODE_METHODS() macro
floppy: convert to use BIND_NODE_METHODS() macro
ide: convert to use BIND_NODE_METHODS() macro
adb: convert to use BIND_NODE_METHODS() macro
escc: convert to use BIND_NODE_METHODS() macro
cuda: convert to use BIND_NODE_METHODS() macro
macio: convert to use BIND_NODE_METHODS() macro
pmu: convert to use BIND_NODE_METHODS() macro
usbhid: convert to use BIND_NODE_METHODS() macro
nvram: convert to use BIND_NODE_METHODS() macro
lsi: don't change active package when setting device alias
lsi: convert to use BIND_NODE_METHODS() macro
virtio: convert to use BIND_NODE_METHODS() macro
pci: convert to use BIND_NODE_METHODS() macro
pci: remove ob_pci_initialize() and ob_pci_empty_node
libopenbios: remove REGISTER_NAMED_NODE and
REGISTER_NAMED_NODE_PHANDLE macros
nvram: ensure that NVRAM configuration is separate from NVRAM node
creation
ppc: move New World uninorth and nvram device node creation to the
root device
ppc: set active package and current instance to root device node
before probe
SPARC64: set active package and current instance to root device node
before probe
x86: set active package and current instance to root device node
before probe
pci: remove explicit find-device from PCI devices
pci: remove explicit setting of my-self from PCI devices
pci: call set-args before configuring PCI device nodes
pc_serial: remove separate init word
pc_kbd: use instance value to initialise C instance parameter
lsi: use instance value to hold sd_private_t pointer
virtio: use instance value to initialise C instance parameter
arch/ppc/qemu/init.c | 13 +++
arch/sparc64/openbios.c | 6 ++
arch/x86/openbios.c | 9 +-
drivers/adb_bus.c | 57 +++++++-----
drivers/adb_kbd.c | 25 ++++--
drivers/adb_mouse.c | 31 ++++---
drivers/cuda.c | 158 ++++++++++++++++++++-------------
drivers/escc.c | 113 ++++++++++++++---------
drivers/floppy.c | 68 +++++++-------
drivers/ide.c | 123 +++++++++++++++----------
drivers/lsi.c | 65 +++++++-------
drivers/macio.c | 118 ++++++++++++------------
drivers/macio.h | 1 -
drivers/pc_kbd.c | 48 +++++-----
drivers/pc_serial.c | 32 +++----
drivers/pci.c | 123 ++++++++++++-------------
drivers/pmu.c | 152 +++++++++++++++++++++----------
drivers/usbhid.c | 16 ++--
drivers/virtio.c | 56 +++---------
include/drivers/drivers.h | 2 +
include/libopenbios/bindings.h | 19 ++--
include/packages/nvram.h | 4 +-
libopenbios/bindings.c | 10 +++
packages/nvram.c | 35 ++++++--
24 files changed, 744 insertions(+), 540 deletions(-)
--
2.20.1
I think old world Macs always booted in 640x480x8, but new world can boot at a higher screen resolution setup in NVRAM. The change in modes to 640x480x8 maybe for compatibility with Old World Macs.
I think reduced ATI ROM’s, that we removed the ‘NDRV’ so it would fit on a 64k EEROM always booted at 640x480x8 until the disk based “NDRV’ loaded. I don’t think anyone ever flashed a reduced Rage128 Pro ROM without the ‘NDRV’ sos I don’t really know how a new world Mac would handle that, if it could still set a higher screen resolution.
Maybe we can we can get some info from the sources of the linux r128 driver?
> On Jul 25, 2019, at 5:53 AM, BALATON Zoltan <balaton(a)eik.bme.hu> wrote:
>
> On Thu, 25 Jul 2019, Jd Lyons wrote:
>> I take it you’ve seen this:
>>
>> https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=2ahUKEw…
>
> Sure, that's what I use for register reference all the time (and is linked from my qmiga.osdn.io page although not directly to avoid possible copyright problems but the card page where the doc is available linked and I've told you that before and also hinted on that page. There are more docs available from the pages linked from my qmiga page, all those might have useful info (the prg and sdk guides too, even though they are for different cards but these are similar so some details are the same).
>
> However it does not explain what AMCGPIO is, only what are the bits in those regs or did I miss that part where it actually says what should be accessible via that register? From the access pattern it looks similar to GPIO_MONID where we have the EDID so maybe the card has another connector the DDC/EDID of which is accessed via the AMCGPIO reg? The FCode checks both but switches mode after reading AMCGPIO and before getting EDID from GPIO_MONID so maybe we need to add EDID to the AMCGPIO reg? But I don't know which bits to connect it. Probably one could find out by reading the detok-ed FCode source to see what it does with the EDID and how does it select mode or find an open source driver that accesses this to find out how this should work.
>
> But the problem currently is with the offset 8000 in the selected mode which the QEMU VGA emulation can't handle or I don't know how to make it handle. That's why picture is wrong at the moment. So either we should allow this offset or find out why FCode wants that and when it uses different mode is that better aligned then? Where does it get this 640x480x8 mode and shouldn't it use something higher by default? I don't know how MacOS works and what its default mode is.
>
> Regards,
> BALATON Zoltan
On Sun, 21 Jul 2019, Mark Cave-Ayland wrote:
> On 21/07/2019 15:16, BALATON Zoltan wrote:
>> OK I came up with the attched patch (on top of your previous series and set-args
>> patch) which is I think about what you've suggested. I kept ob_pci_map for existing
>> callers but renamed it to ob_pci_map_in to keep symmetry between ob_pci_map and
>> ob_pci_unmap with ob_pci_map now only doing mapping as its name suggests (although I
>> think this should still be simpler) and ob_pci_bus_map_in is doing its own address
>> decoding now. The previous ob_pci_map (now called ob_pci_map_in which is a C helper
>> for some of what map-in should do) can be cleaned up as you like. Also cleaned up
>> some white space (tab vs. spaces) but that's excluded from this patch for brevity.
>
> Now I'm really confused - I had a quick look at your patch and compared it with
Good that you're only confused now. :-) I was and still am confused about
it all the time so please bear with me.
> pci_config_*() words and they show that you can't memory map PCI config space on a
> Mac. So how did you get to the conclusion earlier in the thread that this was what
> was required?
Apparently I was confused... Now I realise that this usage of map-in in
FCode ROM really wants to map the IO BAR1. My confusion probably comes
from that after mapping it it uses config-b[!@] to tweak some regs so I
thought it may want config space. (I'm still confused though after reading
the description of map-in and addresses in the PCI binding doc. And we
probably will need access to config space if we want to implement config-*
words in Forth. We could add callbacks to C for those but that's not the
nicest way.)
>> But it does not seem to work yet:
>>
>> 0 > " /pci@f2000000/ATY" open-dev to my-self
>>>> ob_pci_bar_map_in idx=1fc5ac54
>>>> pci_bus_addr_to_host_addr space=2 ba=0x82000000
>>>> ob_pci_map: phys=0x82000000 size=16384
>>>> ob_pci_bar_map_in idx=1fc5ac54
>>>> pci_bus_addr_to_host_addr space=2 ba=0x81000000
>>>> ob_pci_map: phys=0x81000000 size=16777216
>> ?ok
>
> Here we see 2 MMIO BARs being mapped: one of 16K and another of 16M. And this happens
> as soon as you open the device? I think you'll have to explain more about your
> command line and how you are getting OpenBIOS to execute the FCode, since I can't
> tell if this is OpenBIOS or the FCode.
No FCode here, just started OpenBIOS with patched openbios-elf and typed
commands that I've seen in the FCode. All this comes from OpenBIOS, don't
ask me why it calls this for open-dev.
>> 0 > my-unit? ok
>> 3 > . 7800? ok
>> 2 > . 0? ok
>> 1 > . 0? ok
>> 0 > my-space? ok
>> 1 > . 7800? ok
>> 0 > my-address? ok
>> 2 > . 0? ok
>> 1 > . 0? ok
>> 0 > my-address h# 1000014 my-space + h# 100? ok
>> 4 > .s <4> 0 0 1007814 100
>> ?ok
>> 4 > " map-in" $call-parent
>>>> ob_pci_bar_map_in idx=1fc5ac54
>>>> pci_bus_addr_to_host_addr space=1 ba=0x0
>>>> ob_pci_map: phys=0xf2000000 size=256
>> ?ok
>
> This is trying to map an IO BAR with 256 bytes, but the phys address isn't going to
> be correct because OpenBIOS copies arch->io_base into *io_base (and also *mem_base
> for MMIO) during PCI configuration and advances that copy to hold the start of the
> next free address.
Where does OpenBIOS copy and advance these values and what do *io_base and
*mem_base refer to here? I assume the map-in word runs after the device
tree is already constucted so these should already be mapped and map-in
might just need to return a virt address for the already mapped bars.
> At a very minimum you're going to have to teach the PCI map-in how to use these
> values instead of making the assumption that the BAR has already been mapped by
Which values?
> ob_pci_configure_bar() and the address can be calculated by adding the BAR address to
> arch->io_base or arch->mem_base according to the space type. This is how
> pci_bus_addr_to_host_addr() currently works.
My patch called pci_bus_addr_to_host_addr in ob_pci_bus_map_in with the
space decoded from phys.hi on the stack yet the virt address came out
wrong at the end.
Now I've tried to do instead what SLOF's map-in does:
https://github.com/aik/SLOF/blob/master/slof/fs/pci-config-bridge.fs#L59
and ignore everything except phys.hi and get bar address from that like:
size = POP();
phys[0] = POP();
phys[1] = POP();
phys[2] = POP();
PCI_DPRINTF("%s idx=%p, hi=%"PRIx32", mid=%"PRIx32", lo=%"PRIx32", size="
FMT_ucell"\n", __func__, idx, phys[0], phys[1], phys[2], size);
pci_decode_phys_addr(phys, &flags, &space_code, &dev, ®, &addr);
/* Check if reg is actually a Base Address Reg */
if (reg < PCI_BASE_ADDR_0 ||
(reg > PCI_BASE_ADDR_5 && reg != PCI_ROM_ADDRESS)) {
PUSH(-1);
return;
}
addr = pci_config_read32(reg, dev);
PCI_DPRINTF("%s bar=%"PRIx32"\n", __func__, addr);
virt = ob_pci_map(addr, size);
but then bar==-1 (even for MMIO regions which were mapped before) so it
looks like it's not mapped at this point so map-in should program the BAR
reg or call another function for that?
> The other issue is that the PCI enumeration code will already have mapped the ATI
> BARs once so you'll have to come up with a solution so that if you detect an FCode
> ROM then the existing PCI configuration code is ignored. Otherwise you'll find that
> you have mapped the 16M MMIO BAR twice which is going to take quite a bit of MMIO
> memory and lead to more confusion.
Does it map then unmap the region without freeing the allocated MMIO
space? Or if it's still mapped we should just return a pointer to the
already mapped space. Could we just get that from assigned-addresses?
> Finally one other thing: I'm finding this thread really hard to follow - too much
> information is spread across too many emails, and the subject line isn't really
> helping me understand what topic we're following or where I can find related
> information. May I suggest that it makes sense to break this down into a series of
> smaller, more concise threads?
I've tried to do that but forgot to update the subject. This thread is now
about implementing map-in. The goal is still to run FCode ROMs but first
step is to get map-in working.
Thank you,
BALATON Zoltan
Hello,
This is an attempt to port ftd.fs for FDT unflattening from SLOF to
OpenBIOS. This compiles but I have not tried to feed it any fdt yet
because I'm sure it won't work yet as some words are wrong. The words I
had to implement for it (marked with a FIXME comment) should be reviewed
and checked if they could work and the set-unit word is still missing so
that needs to be implemented. Also 64bit stuff and claim usage should be
clarified. Those words that are copied and do work may have better
alternatives that I haven't found so could be replaced. Anyway this is a
start to try to get this done. Once it works it will expect an FDT in
memory at address fdt-start then the fdt-doit word at the end is an
example of how to unflatten that into an OF device-tree (at least that's
what SLOF does if I got that right).
Any insight or comments on this are welcome.
Regards,
BALATON Zoltan
diff --git a/forth/util/build.xml b/forth/util/build.xml
index 4839d2c..25e02db 100644
--- a/forth/util/build.xml
+++ b/forth/util/build.xml
@@ -11,6 +11,7 @@
<dictionary name="openbios" target="forth">
<object source="util.fs"/>
<object source="pci.fs"/>
+ <object source="fdt.fs"/>
<!-- We don't want/need these at the moment
<object source="apic.fs"/>
-->
diff --git a/forth/util/fdt.fs b/forth/util/fdt.fs
new file mode 100644
index 0000000..af29bba
--- /dev/null
+++ b/forth/util/fdt.fs
@@ -0,0 +1,586 @@
+\ *****************************************************************************
+\ * Copyright (c) 2011 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
+\ ****************************************************************************/
+\ Changes for OpenBIOS: BALATON Zoltan, 2019
+
+1 VALUE fdt-debug
+TRUE VALUE fdt-cas-fix?
+0 VALUE fdt-start
+
+struct
+ 4 field >fdth_magic
+ 4 field >fdth_tsize
+ 4 field >fdth_struct_off
+ 4 field >fdth_string_off
+ 4 field >fdth_rsvmap_off
+ 4 field >fdth_version
+ 4 field >fdth_compat_vers
+ 4 field >fdth_boot_cpu
+ 4 field >fdth_string_size
+ 4 field >fdth_struct_size
+constant /fdth
+
+h# d00dfeed constant OF_DT_HEADER
+h# 1 constant OF_DT_BEGIN_NODE
+h# 2 constant OF_DT_END_NODE
+h# 3 constant OF_DT_PROP
+h# 4 constant OF_DT_NOP
+h# 9 constant OF_DT_END
+
+\ Create some variables early
+0 value fdt-start-addr
+0 value fdt-struct
+0 value fdt-strings
+
+
+\ FIXME: review the following words which were added for OpenBIOS
+\ some of these copied verbatim from SLOF others try to implement
+\ alternatives
+\
+\ definitely wrong/missing: set-unit and claim disabled further below
+\
+\ may be wrong: find-node, and other related node words and 64bit stuff
+\ (SLOF seems to always be in 64bit mode and not sure if that's needed
+\ to parse FDT or could it be changed for 32bit as OpenBIOS does not
+\ define some words in 32bit mode.)
+
+: get-node ?active-package ;
+: set-node active-package! ;
+: node>path " ?" ; \ only used for debugging and errors
+: get-parent get-node parent ;
+: my-#address-cells my-#acells ;
+: get-property get-package-property ;
+: find-node ( path len -- phandle|0 )
+ find-dev 0= if \ find-dev returns ( phandle true | false )
+ 0
+ then
+;
+
+\ : set-space get-node dup >r node>space ! true r> node>space? ! ;
+\ : set-address
+\ my-#address-cells 1 ?DO
+\ get-node node>space i cells + ! LOOP
+\ ;
+: set-unit 3drop ; \ set-space set-address ;
+
+: str= ( str1 len1 str2 len2 -- equal? )
+ rot over <> IF 3drop false ELSE comp 0= THEN ;
+
+: from-cstring ( addr - len )
+ dup dup BEGIN c@ 0 <> WHILE 1 + dup REPEAT
+ swap -
+;
+
+: test-string ( param len -- true | false )
+ 0 ?DO
+ dup i + c@ \ Get character / byte at current index
+ dup 20 < swap 7e > OR IF \ Is it out of range 32 to 126 (=ASCII)
+ drop FALSE UNLOOP EXIT \ FALSE means: No ASCII string
+ THEN
+ LOOP
+ drop TRUE \ Only ASCII found --> it is a string
+;
+
+: find-substr ( basestr-ptr basestr-len substr-ptr substr-len -- pos )
+ \ if substr-len == 0 ?
+ dup 0 = IF
+ \ return 0
+ 2drop 2drop 0 exit THEN
+ \ if substr-len <= basestr-len ?
+ dup 3 pick <= IF
+ \ run J from 0 to "basestr-len"-"substr-len" and I from 0 to "substr-len"-1
+ 2 pick over - 1+ 0 DO dup 0 DO
+ \ substr-ptr[i] == basestr-ptr[j+i] ?
+ over i + c@ 4 pick j + i + c@ = IF
+ \ (I+1) == substr-len ?
+ dup i 1+ = IF
+ \ return J
+ 2drop 2drop j unloop unloop exit THEN
+ ELSE leave THEN
+ LOOP LOOP
+ THEN
+ \ if there is no match then exit with basestr-len as return value
+ 2drop nip
+;
+
+CREATE $catpad 400 allot
+: $cat ( str1 len1 str2 len2 -- str3 len3 )
+ >r >r dup >r $catpad swap move
+ r> dup $catpad + r> swap r@ move
+ r> + $catpad swap ;
+
+: split ( str len char -- left len right len )
+ >r 2dup r> findchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ;
+: generic-decode-unit ( str len ncells -- addr.lo ... addr.hi )
+ dup >r -rot BEGIN r@ WHILE r> 1- >r [char] , split 2swap
+ $number IF 0 THEN r> swap >r >r REPEAT r> 3drop
+ BEGIN dup WHILE 1- r> swap REPEAT drop ;
+: generic-encode-unit ( addr.lo ... addr.hi ncells -- str len )
+ 0 0 rot ?dup IF 0 ?DO rot (u.) $cat s" ," $cat LOOP 1- THEN ;
+: hex-decode-unit ( str len ncells -- addr.lo ... addr.hi )
+ base @ >r hex generic-decode-unit r> base ! ;
+: hex-encode-unit ( addr.lo ... addr.hi ncells -- str len )
+ base @ >r hex generic-encode-unit r> base ! ;
+
+64bit? [IF]
+: hex64-decode-unit ( str len ncells -- addr.lo ... addr.hi )
+ dup 2 <> IF
+ hex-decode-unit
+ ELSE
+ drop
+ base @ >r hex
+ $number IF 0 0 ELSE xlsplit THEN
+ r> base !
+ THEN
+;
+: hex64-encode-unit ( addr.lo ... addr.hi ncells -- str len )
+ dup 2 <> IF
+ hex-encode-unit
+ ELSE
+ drop
+ base @ >r hex
+ lxjoin (u.)
+ r> base !
+ THEN
+;
+[ELSE]
+: hex64-decode-unit hex-decode-unit ;
+: hex64-encode-unit hex-encode-unit ;
+: x@ l@ ;
+: xlsplit ( o -- quad.lo quad.hi )
+ dup h# ffffffff and swap d# 32 rshift
+ ;
+[THEN]
+
+\ functions to review end here, also see fdt-claim-reserve below
+
+
+: fdt-init ( fdt-start -- )
+ dup to fdt-start-addr
+ dup dup >fdth_struct_off l@ + to fdt-struct
+ dup dup >fdth_string_off l@ + to fdt-strings
+ drop
+;
+
+\ Dump fdt header for all to see and check FDT validity
+: fdt-check-header ( -- )
+ fdt-start-addr dup 0 = IF
+ ." No flat device tree !" cr drop -1 throw EXIT THEN
+ hex
+ fdt-debug IF
+ ." Flat device tree header at 0x" dup . s" :" type cr
+ ." magic : 0x" dup >fdth_magic l@ . cr
+ ." total size : 0x" dup >fdth_tsize l@ . cr
+ ." offset to struct : 0x" dup >fdth_struct_off l@ . cr
+ ." offset to strings: 0x" dup >fdth_string_off l@ . cr
+ ." offset to rsvmap : 0x" dup >fdth_rsvmap_off l@ . cr
+ ." version : " dup >fdth_version l@ decimal . hex cr
+ ." last compat vers : " dup >fdth_compat_vers l@ decimal . hex cr
+ dup >fdth_version l@ 2 >= IF
+ ." boot CPU : 0x" dup >fdth_boot_cpu l@ . cr
+ THEN
+ dup >fdth_version l@ 3 >= IF
+ ." strings size : 0x" dup >fdth_string_size l@ . cr
+ THEN
+ dup >fdth_version l@ 11 >= IF
+ ." struct size : 0x" dup >fdth_struct_size l@ . cr
+ THEN
+ THEN
+ dup >fdth_magic l@ OF_DT_HEADER <> IF
+ ." Flat device tree has incorrect magic value !" cr
+ drop -1 throw EXIT
+ THEN
+ dup >fdth_version l@ 10 < IF
+ ." Flat device tree has usupported version !" cr
+ drop -1 throw EXIT
+ THEN
+
+ drop
+;
+
+\ Fetch next tag, skip nops and increment address
+: fdt-next-tag ( addr -- nextaddr tag )
+ 0 ( dummy tag on stack for loop )
+ BEGIN
+ drop ( drop previous tag )
+ dup l@ ( read new tag )
+ swap 4 + swap ( increment addr )
+ dup OF_DT_NOP <> UNTIL ( loop until not nop )
+;
+
+\ Parse unit name and advance addr
+: fdt-fetch-unit ( addr -- addr $name )
+ dup from-cstring \ get string size
+ 2dup + 1 + 3 + fffffffc and -rot
+;
+
+\ Update unit with information from the reg property...
+\ ... this is required for the PCI nodes for example.
+: fdt-reg-unit ( prop-addr prop-len -- )
+ decode-phys ( prop-addr' prop-len' phys.lo ... phys.hi )
+ set-unit ( prop-addr' prop-len' )
+ 2drop
+;
+
+\ Lookup a string by index
+: fdt-fetch-string ( index -- str-addr str-len )
+ fdt-strings + dup from-cstring
+;
+
+: fdt-create-dec s" decode-unit" $CREATE , DOES> @ hex64-decode-unit ;
+: fdt-create-enc s" encode-unit" $CREATE , DOES> @ hex64-encode-unit ;
+
+\ Check whether array contains an zero-terminated ASCII string:
+: fdt-prop-is-string? ( addr len -- string? )
+ dup 1 < IF 2drop FALSE EXIT THEN \ Check for valid length
+ 1-
+ 2dup + c@ 0<> IF 2drop FALSE EXIT THEN \ Check zero-termination
+ test-string
+;
+
+\ Encode fdt property to OF property
+: fdt-encode-prop ( addr len -- )
+ 2dup fdt-prop-is-string? IF
+ 1- encode-string
+ ELSE
+ encode-bytes
+ THEN
+;
+
+\ Method to unflatten a node
+: fdt-unflatten-node ( start -- end )
+ \ this can and will recurse
+ recursive
+
+ \ Get & check first tag of node ( addr -- addr)
+ fdt-next-tag dup OF_DT_BEGIN_NODE <> IF
+ s" Weird tag 0x" type . " at start of node" type cr
+ -1 throw
+ THEN drop
+
+ new-device
+
+ \ Parse name, split unit address
+ fdt-fetch-unit
+ dup 0 = IF drop drop " /" THEN
+ 40 left-parse-string
+ \ Set name
+ device-name
+
+ \ Set preliminary unit address - might get overwritten by reg property
+ dup IF
+ " #address-cells" get-parent get-package-property IF
+ 2drop
+ ELSE
+ decode-int nip nip
+ hex-decode-unit
+ set-unit
+ THEN
+ ELSE 2drop THEN
+
+ \ Iterate sub tags
+ BEGIN
+ fdt-next-tag dup OF_DT_END_NODE <>
+ WHILE
+ dup OF_DT_PROP = IF
+ \ Found property
+ drop dup ( drop tag, dup addr : a1 a1 )
+ dup l@ dup rot 4 + ( fetch size, stack is : a1 s s a2)
+ dup l@ swap 4 + ( fetch nameid, stack is : a1 s s i a3 )
+ rot ( we now have: a1 s i a3 s )
+ fdt-encode-prop rot ( a1 s pa ps i)
+ fdt-fetch-string ( a1 s pa ps na ns )
+ 2dup s" reg" str= IF
+ 2swap 2dup fdt-reg-unit 2swap
+ THEN
+ property
+ + 8 + 3 + fffffffc and
+ ELSE dup OF_DT_BEGIN_NODE = IF
+ drop ( drop tag )
+ 4 -
+ fdt-unflatten-node
+ ELSE
+ drop -1 throw
+ THEN THEN
+ REPEAT drop \ drop tag
+
+ \ Create encode/decode unit
+ " #address-cells" get-node get-package-property IF ELSE
+ decode-int dup fdt-create-dec fdt-create-enc 2drop
+ THEN
+
+ finish-device
+;
+
+\ Start unflattening
+: fdt-unflatten-tree
+ fdt-debug IF
+ ." Unflattening device tree..." cr THEN
+ fdt-struct fdt-unflatten-node drop
+ fdt-debug IF
+ ." Done !" cr THEN
+;
+
+\ Find memory size
+: fdt-parse-memory
+ \ XXX FIXME Handle more than one memory node, and deal
+ \ with RMA vs. full access
+ " /memory@0" find-device
+ " reg" get-node get-package-property IF throw -1 THEN
+
+ \ XXX FIXME Assume one entry only in "reg" property for now
+ decode-phys 2drop decode-phys
+ my-#address-cells 1 > IF 20 << or THEN
+
+ fdt-debug IF
+ dup ." Memory size: " . cr
+ THEN
+ \ claim.fs already released the memory between 0 and MIN-RAM-SIZE,
+ \ so we've got only to release the remaining memory now:
+\ MIN-RAM-SIZE swap MIN-RAM-SIZE - release
+ 2drop device-end
+;
+
+\ FIXME: Find out if this is needed and what should it do
+: claim 3drop ;
+
+\ Claim fdt memory and reserve map
+: fdt-claim-reserve
+ fdt-start-addr
+ dup dup >fdth_tsize l@ 0 claim drop
+ dup >fdth_rsvmap_off l@ +
+ BEGIN
+ dup dup x@ swap 8 + x@
+ dup 0 <>
+ WHILE
+ fdt-debug IF
+ 2dup swap ." Reserve map entry: " . ." : " . cr
+ THEN
+ 0 claim drop
+ 10 +
+ REPEAT drop drop drop
+;
+
+\ The following functions are use to replace the FDT phandle and
+\ linux,phandle properties with our own OF1275 phandles...
+
+\ This is used to check whether we successfully replaced a phandle value
+0 VALUE (fdt-phandle-replaced)
+
+\ Replace phandle value in "interrupt-map" property
+: fdt-replace-interrupt-map ( old new prop-addr prop-len -- old new )
+ BEGIN
+ dup ( old new prop-addr prop-len prop-len )
+ WHILE
+ \ This is a little bit ugly ... we're accessing the property at
+ \ hard-coded offsets instead of analyzing it completely...
+ swap dup 10 + ( old new prop-len prop-addr prop-addr+10 )
+ dup l@ 5 pick = IF
+ \ it matches the old phandle value!
+ 3 pick swap l!
+ TRUE TO (fdt-phandle-replaced)
+ ELSE
+ drop
+ THEN
+ ( old new prop-len prop-addr )
+ 1c + swap 1c -
+ ( old new new-prop-addr new-prop-len )
+ REPEAT
+ 2drop
+;
+
+: (fdt-replace-phandles) ( old new propname propnamelen node -- )
+ get-property IF 2drop EXIT THEN
+ BEGIN
+ dup
+ WHILE ( old new prop-addr prop-len )
+ over l@
+ 4 pick = IF
+ 2 pick 2 pick l! \ replace old with new in place
+ TRUE TO (fdt-phandle-replaced)
+ THEN
+ 4 - swap 4 + swap
+ REPEAT
+ 2drop 2drop
+;
+
+\ Replace one phandle "old" with a phandle "new" in "node" and recursively
+\ in its child nodes:
+: fdt-replace-all-phandles ( old new node -- )
+ \ ." Replacing in " dup node>path type cr
+ >r
+ s" interrupt-map" r@ get-property 0= IF
+ ( old new prop-addr prop-len R: node )
+ fdt-replace-interrupt-map
+ THEN
+
+ 2dup s" interrupt-parent" r@ (fdt-replace-phandles)
+ 2dup s" ibm,gpu" r@ (fdt-replace-phandles)
+ 2dup s" ibm,npu" r@ (fdt-replace-phandles)
+ 2dup s" ibm,nvlink" r@ (fdt-replace-phandles)
+ 2dup s" memory-region" r@ (fdt-replace-phandles)
+
+ \ ... add more properties that have to be fixed here ...
+ r>
+ \ Now recurse over all child nodes: ( old new node )
+ child BEGIN
+ dup
+ WHILE
+ 3dup RECURSE
+ PEER
+ REPEAT
+ 3drop
+;
+
+\ Replace one FDT phandle "val" with a OF1275 phandle "node" in the
+\ whole tree:
+: fdt-update-phandle ( val node -- )
+ >r
+ FALSE TO (fdt-phandle-replaced)
+ r@ s" /" find-node ( val node root )
+ fdt-replace-all-phandles
+ (fdt-phandle-replaced) IF
+ r@ set-node
+ s" phandle" delete-property
+ s" linux,phandle" delete-property
+ ELSE
+ diagnostic-mode? IF
+ cr ." Warning: Did not replace phandle in " r@ node>path type cr
+ THEN
+ THEN
+r> drop
+;
+
+\ Check whether a node has "phandle" or "linux,phandle" properties
+\ and replace them:
+: fdt-fix-node-phandle ( node -- )
+ >r
+ s" phandle" r@ get-property 0= IF
+ decode-int nip nip
+ \ ." found phandle: " dup . cr
+ r@ fdt-update-phandle
+ THEN
+ r> drop
+;
+
+\ Recursively walk through all nodes to fix their phandles:
+: fdt-fix-phandles ( node -- )
+ \ ." fixing phandles of " dup node>path type cr
+ dup fdt-fix-node-phandle
+ child BEGIN
+ dup
+ WHILE
+ dup RECURSE
+ PEER
+ REPEAT
+ drop
+ device-end
+;
+
+: fdt-create-cas-node ( name -- )
+ 2dup
+ 2dup " memory@" find-substr 0 = IF
+ fdt-debug IF ." Creating memory@ " cr THEN
+ new-device
+ 2dup " @" find-substr nip device-name \ Parse the node name
+ 2dup
+ 2dup " @" find-substr rot over + 1 + -rot - 1 - \ Jump to addr afte "@"
+ parse-2int nip xlsplit set-unit \ Parse and set unit
+ finish-device
+ ELSE
+ 2dup " ibm,dynamic-reconfiguration-memory" find-substr 0 = IF
+ fdt-debug IF ." Creating ibm,dynamic-reconfiguration-memory " cr THEN
+ new-device
+ device-name
+ finish-device
+ ELSE
+ 2drop 2drop
+ false to fdt-cas-fix?
+ ." Node not supported " cr
+ EXIT
+ THEN
+ THEN
+
+ find-node ?dup 0 <> IF set-node THEN
+;
+
+: fdt-fix-cas-node ( start -- end )
+ recursive
+ fdt-next-tag dup OF_DT_BEGIN_NODE <> IF
+ ." Error " cr
+ false to fdt-cas-fix?
+ EXIT
+ THEN drop
+ fdt-fetch-unit
+ dup 0 = IF drop drop " /" THEN
+ 40 left-parse-string
+ 2swap ?dup 0 <> IF
+ nip
+ 1 + + \ Add the string len +@
+ ELSE
+ drop
+ THEN
+ fdt-debug IF ." Setting node: " 2dup type cr THEN
+ 2dup find-node ?dup 0 <> IF
+ set-node 2drop
+ ELSE
+ fdt-debug IF ." Node not found, creating " 2dup type cr THEN
+ fdt-create-cas-node
+ THEN
+ fdt-debug IF ." Current now: " pwd cr THEN
+ BEGIN
+ fdt-next-tag dup OF_DT_END_NODE <>
+ WHILE
+ dup OF_DT_PROP = IF
+ fdt-debug IF ." Found property " cr THEN
+ drop dup ( drop tag, dup addr : a1 a1 )
+ dup l@ dup rot 4 + ( fetch size, stack is : a1 s s a2)
+ dup l@ swap 4 + ( fetch nameid, stack is : a1 s s i a3 )
+ rot ( we now have: a1 s i a3 s )
+ fdt-encode-prop rot ( a1 s pa ps i)
+ fdt-fetch-string ( a1 s pa ps na ns )
+ property
+ fdt-debug IF ." Setting property done " cr THEN
+ + 8 + 3 + fffffffc and
+ ELSE dup OF_DT_BEGIN_NODE = IF
+ drop ( drop tag )
+ 4 -
+ fdt-fix-cas-node
+ get-parent set-node
+ fdt-debug IF ." Returning back " pwd cr THEN
+ ELSE
+ ." Error " cr
+ drop
+ false to fdt-cas-fix?
+ EXIT
+ THEN
+ THEN
+ REPEAT
+ drop \ drop tag
+;
+
+: fdt-fix-cas-success
+ fdt-cas-fix?
+;
+
+: fdt-doit
+ \ Bail out if no fdt
+ fdt-start 0 = IF
+ ." No fdt-start" cr
+ -1 throw
+ THEN
+ fdt-start fdt-init
+ fdt-check-header
+ fdt-unflatten-tree
+ fdt-parse-memory
+ fdt-claim-reserve
+ s" /" find-node fdt-fix-phandles
+;