Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / of.c
diff --git a/qemu/roms/openhackware/src/of.c b/qemu/roms/openhackware/src/of.c
new file mode 100644 (file)
index 0000000..33582c3
--- /dev/null
@@ -0,0 +1,5450 @@
+/* Open firmware emulation.
+ *
+ * This is really simplistic. The first goal is to implement all stuff
+ * needed to boot Linux. Then, I'll try Darwin.
+ * Note that this emulation run in the host environment.
+ * There is no Forth interpreter, so standard bootloader cannot be launched.
+ * In the future, it will be nice to get a complete OpenFirmware implementation
+ * so that OSes can be launched exactly the way they are in the real world...
+ *
+ *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License V2
+ *   as published by the Free Software Foundation
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+
+//#define DEBUG_OF 1
+
+#if defined (DEBUG_OF)
+#define OF_DPRINTF(fmt, args...) \
+do { dprintf("%s: " fmt, __func__ , ##args); } while (0)
+#else
+#define OF_DPRINTF(fmt, args...) \
+do { } while (0)
+#endif
+
+#define PROT_READ  1
+#define PROT_WRITE 2
+
+typedef struct OF_transl_t OF_transl_t;
+struct OF_transl_t {
+    uint32_t virt;
+    uint32_t size;
+    uint32_t phys;
+    uint32_t mode;
+};
+
+typedef struct OF_env_t OF_env_t;
+struct OF_env_t {
+    uint32_t *stackp; /* Stack pointer          */
+    uint32_t *stackb; /* Stack base             */
+    uint32_t *funcp;  /* Function stack pointer */
+    uint32_t *funcb;  /* Function stack base    */
+};
+
+typedef struct OF_bustyp_t OF_bustyp_t;
+struct OF_bustyp_t {
+    const char *name;
+    int type;
+};
+
+typedef struct pci_address_t pci_address_t;
+struct pci_address_t {
+       uint32_t hi;
+       uint32_t mid;
+       uint32_t lo;
+};
+
+typedef struct pci_reg_prop_t pci_reg_prop_t;
+struct pci_reg_prop_t {
+       pci_address_t addr;
+       uint32_t size_hi;
+       uint32_t size_lo;
+};
+
+typedef struct pci_range_t pci_range_t;
+struct pci_range_t {
+       pci_address_t addr;
+       uint32_t phys;
+       uint32_t size_hi;
+       uint32_t size_lo;
+};
+
+/*****************************************************************************/
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_lds (uint8_t *dst, const void *address)
+{
+    const uint8_t *p;
+    uint8_t *_d = dst;
+
+    for (p = address; *p != '\0'; p++) {
+        *_d++ = *p;
+    }
+    *_d = '\0';
+    OF_DPRINTF("Loaded string %s\n", dst); 
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_sts (void *address, const uint8_t *src)
+{
+    const uint8_t *_s;
+    uint8_t *p = address;
+
+    OF_DPRINTF("Store string %s\n", src);
+    for (_s = src; *_s != '\0'; _s++) {
+        *p++ = *_s;
+    }
+    *p = '\0';
+}
+
+#define OF_DUMP_STRING(env, buffer)    \
+do {                                   \
+    unsigned char tmp[OF_NAMELEN_MAX]; \
+    OF_lds(tmp, buffer);               \
+    OF_DPRINTF("[%s]\n", tmp);         \
+} while (0)
+
+/*****************************************************************************/
+/* Forth like environmnent */
+#define OF_CHECK_NBARGS(env, nb)                                              \
+do {                                                                          \
+    int nb_args;                                                              \
+    nb_args = stackd_depth((env));                                            \
+    if (nb_args != (nb)) {                                                    \
+        printf("%s: Bad number of arguments (%d - %d)\n",                     \
+               __func__, nb_args, (nb));                                      \
+        bug();                                                                \
+        popd_all((env), nb_args);                                             \
+        pushd((env), -1);                                                     \
+        return;                                                               \
+    }                                                                         \
+} while (0)
+
+#define OF_STACK_SIZE 0x1000
+#define OF_FSTACK_SIZE 0x100
+__attribute__ (( section (".OpenFirmware_vars") ))
+uint8_t OF_stack[OF_STACK_SIZE];
+__attribute__ (( section (".OpenFirmware_vars") ))
+uint8_t OF_fstack[OF_FSTACK_SIZE];
+
+typedef void (*OF_cb_t)(OF_env_t *OF_env);
+
+static inline void _push (uint32_t **stackp, uint32_t data)
+{
+    //    OF_DPRINTF("%p 0x%0x\n", *stackp, data);
+    **stackp = data;
+    (*stackp)--;
+}
+
+static inline uint32_t _pop (uint32_t **stackp)
+{
+    (*stackp)++;
+    //    OF_DPRINTF("%p 0x%0x\n", *stackp, **stackp);
+    return **stackp;
+}
+
+static inline void _pop_all (uint32_t **stackp, int nb)
+{
+    int i;
+
+    for (i = 0; i < nb; i++)
+        (*stackp)++;
+}
+
+static inline int _stack_depth (uint32_t *stackp, uint32_t *basep)
+{
+    return basep - stackp;
+}
+
+static inline void pushd (OF_env_t *OF_env, uint32_t data)
+{
+    _push(&OF_env->stackp, data);
+}
+
+static inline uint32_t popd (OF_env_t *OF_env)
+{
+    return _pop(&OF_env->stackp);
+}
+
+static inline void popd_all (OF_env_t *OF_env, int nb)
+{
+    _pop_all(&OF_env->stackp, nb);
+}
+
+static inline int stackd_depth (OF_env_t *OF_env)
+{
+    return _stack_depth(OF_env->stackp, OF_env->stackb);
+}
+
+static inline void pushf (OF_env_t *OF_env, OF_cb_t *func)
+{
+    _push(&OF_env->funcp, (uint32_t)func);
+}
+
+static inline OF_cb_t *popf (OF_env_t *OF_env)
+{
+    return (OF_cb_t *)_pop(&OF_env->funcp);
+}
+
+static inline void popf_all (OF_env_t *OF_env, int nb)
+{
+    _pop_all(&OF_env->funcp, nb);
+}
+
+static inline int stackf_depth (OF_env_t *OF_env)
+{
+    return _stack_depth(OF_env->funcp, OF_env->funcb);
+}
+
+static inline void OF_env_init (OF_env_t *OF_env)
+{
+    OF_env->stackb = (uint32_t *)(OF_stack + OF_STACK_SIZE - 4);
+    OF_env->stackp = OF_env->stackb;
+    OF_env->funcb = (uint32_t *)(OF_fstack + OF_FSTACK_SIZE - 4);
+    OF_env->funcp = OF_env->funcb;
+}
+
+/* Forth run-time */
+__attribute__ (( section (".OpenFirmware") ))
+static void C_to_Forth (OF_env_t *env, void *p, OF_cb_t *cb)
+{
+    OF_cb_t *_cb;
+    uint32_t *u, *rets;
+    uint32_t i, n_args, n_rets, tmp;
+
+    //    OF_DPRINTF("enter\n");
+    /* Fill argument structure */
+    u = p;
+    n_args = *u++;
+    n_rets = *u++;
+    u += n_args;
+    rets = u;
+    //    OF_DPRINTF("n_args=%d n_rets=%d\n", n_args, n_rets);
+    /* Load arguments */
+    for (i = 0; i < n_args; i++)
+        pushd(env, *(--u));
+    pushf(env, cb);
+    while (stackf_depth(env) != 0) {
+        //        OF_DPRINTF("func stack: %p %p\n", env->funcb, env->funcp);
+        _cb = popf(env);
+        //        OF_DPRINTF("Next func: %p %d\n", cb, stackf_depth(env));
+        (*_cb)(env);
+    }
+    //    OF_DPRINTF("Back to C: n_args=%d n_rets=%d\n", n_args, n_rets);
+    /* Copy returned values */
+    for (i = 0; stackd_depth(env) != 0; i++) {
+        tmp = popd(env);
+        //        OF_DPRINTF("Store 0x%0x (%d)\n", tmp, tmp);
+        *rets++ = tmp;
+    }
+    for (; i < n_rets; i++)
+        *rets++ = 0;
+    OF_CHECK_NBARGS(env, 0);
+    //    OF_DPRINTF("done\n");
+}
+
+/*****************************************************************************/
+/* Memory pool (will be needed when it'll become native) */
+#if 0
+#define OF_INTBITS_LEN 128
+#define OF_INTPOOL_LEN (OF_INTBITS_LEN * 8)
+__attribute__ (( section (".OpenFirmware_vars") ))
+static uint32_t OF_int_pool[OF_INTPOOL_LEN];
+__attribute__ (( section (".OpenFirmware_vars") ))
+static uint8_t  OF_int_bits[OF_INTBITS_LEN];
+
+__attribute__ (( section (".OpenFirmware") ))
+static uint32_t *OF_int_alloc (unused OF_env_t *env)
+{
+    uint8_t tmp;
+    int i, j;
+
+    for (i = 0; i < OF_INTBITS_LEN; i++) {
+        tmp = OF_int_bits[i];
+        if (tmp == 0xFF)
+            continue;
+        for (j = 0; j < 7; j++) {
+            if ((tmp & 1) == 0) {
+                OF_int_bits[i] |= 1 << j;
+                return &OF_int_pool[(i << 3) | j];
+            }
+            tmp = tmp >> 1;
+        }
+    }
+    printf("ALERT: unable to \"allocate\" new integer\n");
+    
+    return NULL;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_int_free (unused OF_env_t *env,
+                         uint32_t *area)
+{
+    int i, j;
+
+    i = area - OF_int_pool;
+    j = i & 7;
+    i = i >> 3;
+    OF_int_bits[i] &= ~(1 << j);
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_free (unused OF_env_t *env, void *area)
+{
+    uint32_t *check;
+
+    /* Check if it's in our int pool */
+    check = area;
+    if (check >= OF_int_pool && check < (OF_int_pool + OF_INTPOOL_LEN)) {
+        OF_int_free(env, check);
+        return;
+    }
+#if 0
+    free(area);
+#endif
+}
+#endif
+
+/*****************************************************************************/
+/*                          Internal structures                              */
+/* Property value types */
+typedef struct OF_node_t OF_node_t;
+typedef struct OF_prop_t OF_prop_t;
+typedef struct OF_method_t OF_method_t;
+typedef struct OF_inst_t OF_inst_t;
+
+#define OF_ADDRESS_NONE ((uint32_t)(-1))
+
+/* Tree node */
+struct OF_node_t {
+    /* Parent node */
+    OF_node_t *parent;
+    /* Link to next node at the same level */
+    OF_node_t *next;
+    /* Link to children, if any */
+    OF_node_t *children, *child_last;
+    /* refcount */
+    int refcount;
+    /* The following ones belong to the package */
+    /* Package */
+    uint16_t pack_id;
+    /* links count */
+    uint16_t link_count;
+    uint16_t link_cur;
+    OF_node_t *link_ref;
+    /* Properties */
+    OF_prop_t *properties, *prop_last, *prop_name, *prop_address;
+    /* Methods */
+    OF_method_t *methods, *method_last;
+    /* private data */
+    void *private_data;
+    /* static data */
+    void *static_data;
+    /* instances */
+    OF_inst_t *instances, *inst_last;
+};
+
+/* Node property */
+struct OF_prop_t {
+    /* Link to next property */
+    OF_prop_t *next;
+    /* The node it belongs to */
+    OF_node_t *node;
+    /* property name */
+    const unsigned char *name;
+    /* property value len */
+    int vlen;
+    /* property value buffer */
+    char *value;
+    /* Property change callback */
+    void (*cb)(OF_env_t *OF_env, OF_prop_t *prop, const void *data, int len);
+};
+
+/* Node method */
+enum {
+    OF_METHOD_INTERNAL = 0,
+    OF_METHOD_EXPORTED,
+};
+
+struct OF_method_t {
+    /* Link to next method */
+    OF_method_t *next;
+    /* The package it belongs to */
+    OF_node_t *node;
+    /* method name */
+    unsigned char *name;
+    /* Method function pointer */
+    OF_cb_t func;
+};
+
+/* Package instance */
+struct OF_inst_t {
+    /* Link to next instance of the same package */
+    OF_inst_t *next;
+    /* Link to the parent instance */
+    OF_inst_t *parent;
+    /* The package it belongs to */
+    OF_node_t *node;
+    /* Instance identifier */
+    uint16_t inst_id;
+    /* Instance data */
+    void *data;
+};
+
+/* reg property */
+typedef struct OF_regprop_t OF_regprop_t;
+struct OF_regprop_t {
+    uint32_t address;
+    uint32_t size;
+};
+
+/* range property */
+typedef struct OF_range_t OF_range_t;
+struct OF_range_t {
+    uint32_t virt;
+    uint32_t size;
+    uint32_t phys;
+};
+
+/* Open firmware tree */
+#define OF_MAX_PACKAGE 256
+/* nodes and packages */
+__attribute__ (( section (".OpenFirmware_vars") ))
+static OF_node_t *OF_node_root;
+__attribute__ (( section (".OpenFirmware_vars") ))
+static uint16_t OF_pack_last_id = 0;
+__attribute__ (( section (".OpenFirmware_vars") ))
+static uint16_t inst_last_id = 0;
+/* To speed up lookup by id, we get a package table */
+__attribute__ (( section (".OpenFirmware_vars") ))
+static OF_node_t *OF_packages[OF_MAX_PACKAGE];
+__attribute__ (( section (".OpenFirmware_vars") ))
+static OF_node_t *OF_pack_active;
+
+static OF_prop_t *OF_prop_string_new (OF_env_t *env, OF_node_t *node,
+                                      const unsigned char *name,
+                                      const unsigned char *string);
+static OF_prop_t *OF_prop_int_new (OF_env_t *env, OF_node_t *node,
+                                   const unsigned char *name, uint32_t value);
+static OF_prop_t *OF_property_get (OF_env_t *env, OF_node_t *node,
+                                   const unsigned char *name);
+static uint16_t OF_pack_handle (OF_env_t *env, OF_node_t *node);
+
+__attribute__ (( section (".OpenFirmware_vars") ))
+static uint8_t *RTAS_memory;
+
+/*****************************************************************************/
+/*                           Node management                                 */
+/* Insert a new node */
+__attribute__ (( section (".OpenFirmware") ))
+static uint16_t OF_pack_new_id (unused OF_env_t *env, OF_node_t *node)
+{
+    uint16_t cur_id;
+
+    for (cur_id = OF_pack_last_id + 1; cur_id != OF_pack_last_id; cur_id++) {
+        if (cur_id == (uint16_t)(OF_MAX_PACKAGE))
+            cur_id = 1;
+        if (OF_packages[cur_id] == NULL) {
+            OF_packages[cur_id] = node;
+            OF_pack_last_id = cur_id;
+            return cur_id;
+        }
+    }
+
+    return (uint16_t)(-1);
+}
+
+static OF_node_t *OF_node_create (OF_env_t *env, OF_node_t *parent,
+                                  const unsigned char *name, uint32_t address)
+{
+    OF_node_t *new;
+
+    OF_DPRINTF("New node: %s\n", name);
+    new = malloc(sizeof(OF_node_t));
+    if (new == NULL) {
+        ERROR("%s can't alloc new node '%s'\n", __func__, name);
+        return NULL;
+    }
+    memset(new, 0, sizeof(OF_node_t));
+    new->parent = parent;
+    new->refcount = 1;
+    new->link_count = 1;
+    new->prop_name = OF_prop_string_new(env, new, "name", name);
+    if (new->prop_name == NULL) {
+        free(new);
+        ERROR("%s can't alloc new node '%s' name\n", __func__, name);
+        return NULL;
+    }
+    new->prop_address = OF_prop_int_new(env, new, "unit-address", address);
+    if (new->prop_address == NULL) {
+        free(new->prop_name->value);
+        free(new->prop_name);
+        free(new);
+        ERROR("%s can't alloc new node '%s' address\n", __func__, name);
+        return NULL;
+    }
+    /* Link it in parent tree */
+    if (parent != NULL) {
+        /* SHOULD LOCK */
+        if (parent->children == NULL) {
+            parent->children = new;
+        } else {
+            parent->child_last->next = new;
+        }
+        parent->child_last = new;
+    } else {
+        /* This is a bug and should never happen, but for root node */
+        if (strcmp(name, "device-tree") != 0)
+            ERROR("WARNING: parent of '%s' is NULL!\n", name);
+    }
+    //    OF_DPRINTF("New node: %s get id\n", name);
+
+    return new;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_node_new (OF_env_t *env, OF_node_t *parent,
+                               const unsigned char *name, uint32_t address)
+{
+    OF_node_t *new;
+
+    new = OF_node_create(env, parent, name, address);
+    if (new == NULL)
+        return NULL;
+    new->pack_id = OF_pack_new_id(env, new);
+    //    OF_DPRINTF("New node: %s id=0x%0x\n", name, new->pack_id);
+    OF_pack_active = new;
+
+    return new;
+}
+
+static inline OF_node_t *OF_node_parent (unused OF_env_t *env, OF_node_t *node)
+{
+    return node->parent;
+}
+
+/* Look for a node, given its name */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_node_get_child (OF_env_t *env, OF_node_t *parent,
+                                     const unsigned char *name,
+                                     uint32_t address)
+{
+    unsigned char tname[OF_NAMELEN_MAX];
+    OF_node_t *parse, *tmp;
+    OF_prop_t *prop_name, *prop_address;
+    uint32_t *addr_valp;
+    int len, i;
+
+    if (parent == OF_node_root) {
+       OF_DPRINTF("Look for node [%s]\n", name);
+    }
+    len = strlen(name);
+    memcpy(tname, name, len + 1);
+    for (i = len; i > 0; i--) {
+        if (tname[i - 1] == ',') {
+            tname[i - 1] = '\0';
+            len = i;
+            break;
+        }
+    }
+    for (parse = parent->children; parse != NULL; parse = parse->next) {
+        prop_name = parse->prop_name;
+        prop_address = parse->prop_address;
+        if (prop_address == NULL)
+            addr_valp = NULL;
+        else
+            addr_valp = (void *)prop_address->value;
+#if 0
+        OF_DPRINTF("node [%s] <=> [%s]\n", prop_name->value, tname);
+#endif
+        if (prop_name != NULL && strncmp(prop_name->value, tname, len) == 0 &&
+            (prop_name->value[len] == '\0') &&
+            (address == OF_ADDRESS_NONE || addr_valp == NULL ||
+             address == *addr_valp)) {
+            parse->refcount++;
+            return parse;
+        }
+#if 1
+        OF_DPRINTF("look in children [%s]\n", prop_name->value);
+#endif
+        tmp = OF_node_get_child(env, parse, tname, address);
+        if (tmp != NULL)
+            return tmp;
+#if 0
+        OF_DPRINTF("didn't find in children [%s]\n", prop_name->value);
+#endif
+    }
+    if (parent == OF_node_root) {
+        OF_DPRINTF("node [%s] not found\n", name);
+    }
+
+    return NULL;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_node_get (OF_env_t *env, const unsigned char *name)
+{
+    unsigned char tname[OF_NAMELEN_MAX];
+    unsigned char *addrp;
+    uint32_t address;
+
+    if (strcmp(name, "device_tree") == 0)
+        return OF_node_root;
+
+    strcpy(tname, name);
+    addrp = strchr(tname, '@');
+    if (addrp == NULL) {
+        address = OF_ADDRESS_NONE;
+    } else {
+        *addrp++ = '\0';
+        address = strtol(addrp, NULL, 16);
+    }
+
+    /* SHOULD LOCK */
+    return OF_node_get_child(env, OF_node_root, name, address);
+}
+
+/* Release a node */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_node_put (unused OF_env_t *env, OF_node_t *node)
+{
+    if (--node->refcount < 0)
+        node->refcount = 0;
+}
+
+/*****************************************************************************/
+/*                           Packages tree walk                              */
+__attribute__ (( section (".OpenFirmware") ))
+static uint16_t OF_pack_handle (unused OF_env_t *env, OF_node_t *node)
+{
+    if (node == NULL)
+        return 0;
+
+    return node->pack_id;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_pack_find_by_name (OF_env_t *env, OF_node_t *base,
+                                        const unsigned char *name)
+{
+    unsigned char tmp[OF_NAMELEN_MAX], *addrp;
+    const unsigned char *sl, *st;
+    OF_node_t *parse;
+    OF_prop_t *prop_name, *prop_address;
+    uint32_t address, *addr_valp;
+    int len;
+
+    OF_DPRINTF("Path [%s] in '%s'\n", name, base->prop_name->value);
+    st = name;
+    if (*st == '/') {
+        st++;
+    }
+    if (*st == '\0') {
+        /* Should never happen */
+        OF_DPRINTF("Done\n");
+        return base;
+    }
+    sl = strchr(st, '/');
+    if (sl == NULL) {
+        len = strlen(st);
+    } else {
+        len = sl - st;
+    }
+    memcpy(tmp, st, len);
+    tmp[len] = '\0';
+    addrp = strchr(tmp, '@');
+    if (addrp == NULL) {
+        address = OF_ADDRESS_NONE;
+    } else {
+        len = addrp - tmp;
+        *addrp++ = '\0';
+        address = strtol(addrp, NULL, 16);
+    }
+    OF_DPRINTF("Look for [%s] '%s' %08x\n", tmp, sl, address);
+    for (parse = base->children; parse != NULL; parse = parse->next) {
+        prop_name = parse->prop_name;
+        prop_address = parse->prop_address;
+        if (prop_address == NULL)
+            addr_valp = NULL;
+        else
+            addr_valp = (void *)prop_address->value;
+#if 0
+        OF_DPRINTF("Check [%s]\n", prop_name->value);
+#endif
+        if (prop_name == NULL) {
+            printf("ERROR: missing address in node, parent: '%s'\n",
+                   base->prop_name->value);
+            bug();
+        }
+        if (strncmp(prop_name->value, tmp, len) == 0 &&
+            prop_name->value[len] == '\0' &&
+            (address == OF_ADDRESS_NONE || addr_valp == NULL ||
+             address == *addr_valp)) {
+            OF_pack_active = parse;
+            if (sl == NULL) {
+                OF_DPRINTF("Done\n");
+                return parse;
+            }
+            OF_DPRINTF("Recurse: '%s'\n", sl + 1);
+            return OF_pack_find_by_name(env, parse, sl + 1);
+        }
+    }
+    OF_DPRINTF("Didn't found [%s]\n", tmp);
+
+    return NULL;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_pack_find (unused OF_env_t *env, uint16_t phandle)
+{
+    if (phandle > OF_MAX_PACKAGE)
+        return NULL;
+    if (OF_packages[phandle] == NULL) {
+        OF_DPRINTF("No package %0x\n", phandle);
+    } else {
+        OF_DPRINTF("return package: %0x %p [%s]\n", phandle,
+                   OF_packages[phandle],
+                   OF_packages[phandle]->prop_name->value);
+    }
+
+    return OF_packages[phandle];
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_pack_next (OF_env_t *env, uint16_t phandle)
+{
+    OF_node_t *node;
+
+    for (node = OF_pack_find(env, phandle); node != NULL; node = node->next) {
+        if (OF_pack_handle(env, node) != phandle)
+            break;
+    }
+#if 0
+    OF_DPRINTF("found node %p [%s]\n", node, node->prop_name->value);
+#endif
+
+    return node;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_pack_child (OF_env_t *env, uint16_t phandle)
+{
+    OF_node_t *node;
+
+    node = OF_pack_find(env, phandle);
+    if (node == NULL) {
+        ERROR("%s didn't find pack %04x\n", __func__, phandle);
+        return NULL;
+    }
+    node = node->children;
+#if 0
+    OF_DPRINTF("found node %p [%s]\n", node, node->prop_name->value);
+#endif
+
+    return node;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_pack_parent (OF_env_t *env, uint16_t phandle)
+{
+    OF_node_t *node;
+
+    node = OF_pack_find(env, phandle);
+    if (node == NULL) {
+        ERROR("%s didn't find pack %04x\n", __func__, phandle);
+        return NULL;
+    }
+    node = OF_node_parent(env, node);
+#if 0
+    OF_DPRINTF("found node %p [%s]\n", node, node->prop_name->value);
+#endif
+
+    return node;
+}
+
+/*****************************************************************************/
+/*                      Package properties management                        */
+/* Insert a new property */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_property_new (unused OF_env_t *env, OF_node_t *node,
+                                   const unsigned char *name,
+                                   const void *data, int len)
+{
+    OF_prop_t *prop;
+
+#ifdef DEBUG_OF
+    {
+        OF_prop_t *_prop;
+        _prop = OF_property_get(env, node, name);
+        if (_prop != NULL) {
+            printf("Property '%s' already present !\n", name);
+            bug();
+        }
+    }
+#endif
+    /* Allocate a new property */
+    prop = malloc(sizeof(OF_prop_t));
+    if (prop == NULL) {
+        ERROR("%s cannot allocate property '%s'\n", __func__, name);
+        return NULL;
+    }
+    memset(prop, 0, sizeof(OF_prop_t));
+    prop->name = strdup(name);
+    if (prop->name == NULL) {
+        free(prop);
+        ERROR("%s cannot allocate property '%s' name\n", __func__, name);
+        return NULL;
+    }
+    /* Fill it */
+    if (data != NULL && len > 0) {
+        prop->value = malloc(len);
+        if (prop->value == NULL) {
+            free(prop);
+            ERROR("%s cannot allocate property '%s' value\n", __func__, name);
+            return NULL;
+        }
+        prop->vlen = len;
+        memcpy(prop->value, data, len);
+    }
+    OF_DPRINTF("New property [%s] '%s'\n\t%p %p %d %p\n", name, prop->name, prop->name, data, len, prop->value);
+    /* Link it */
+    /* SHOULD LOCK */
+    if (node->properties == NULL)
+        node->properties = prop;
+    else
+        node->prop_last->next = prop;
+    node->prop_last = prop;
+    
+    return prop;
+}
+
+/* Find a property given its name */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_property_get (unused OF_env_t *env, OF_node_t *node,
+                                   const unsigned char *name)
+{
+    OF_prop_t *prop;
+    
+#if 0
+    OF_DPRINTF("Look for property [%s] in 0x%0x '%s'\n", name,
+               node->pack_id, node->prop_name->value);
+#endif
+    if (node == NULL)
+        return NULL;
+    /* *SHOULD LOCK* */
+    for (prop = node->properties; prop != NULL; prop = prop->next) {
+#if 0
+        OF_DPRINTF("property [%s] <=> [%s]\n", prop->name, name);
+#endif
+        if (strcmp(prop->name, name) == 0) {
+            return prop;
+        }
+    }
+#if 0
+    OF_DPRINTF("property [%s] not found in 0x%08x '%s'\n", name,
+               node->pack_id, node->prop_name->value);
+#endif
+
+    return NULL;
+}
+
+/* Change a property */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_property_set (OF_env_t *env, OF_node_t *node,
+                                   const unsigned char *name,
+                                   const void *data, int len)
+{
+    OF_prop_t *prop;
+    void *tmp;
+
+    if (node == NULL)
+        return NULL;
+    prop = OF_property_get(env, node, name);
+    if (prop != NULL) {
+        OF_DPRINTF("change property [%s]\n", name);
+        tmp = malloc(len);
+        if (tmp == NULL && len != 0) {
+            ERROR("%s cannot set property '%s'\n", __func__, name);
+            return NULL;
+        }
+        free(prop->value);
+        prop->value = tmp;
+        prop->vlen = len;
+        memcpy(prop->value, data, len);
+        if (prop->cb != NULL) {
+            (*prop->cb)(env, prop, data, len);
+        }
+    } else {
+        OF_DPRINTF("new property [%s]\n", name);
+        prop = OF_property_new(env, node, name, data, len);
+    }
+
+    return prop;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static int OF_property_len (OF_env_t *env, OF_node_t *node,
+                            const unsigned char *name)
+{
+    OF_prop_t *prop;
+
+    prop = OF_property_get(env, node, name);
+    if (prop == NULL)
+        return -1;
+    
+    return prop->vlen;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static unsigned char *hex2buf (unsigned char *buf, uint32_t value, int fill)
+{
+    int pos, d;
+    
+    buf[8] = '\0';
+    pos = 7;
+    if (value == 0) {
+        buf[pos--] = '0';
+    } else {
+        for (; value != 0; pos--) {
+            d = value & 0xF;
+            if (d > 9)
+            d += 'a' - '0' - 10;
+            buf[pos] = d + '0';
+            value = value >> 4;
+        }
+    }
+    if (fill != 0) {
+        for (; pos != -1; pos--) {
+            buf[pos] = '0';
+        }
+    }
+
+    return &buf[pos];
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static int OF_property_copy (OF_env_t *env, void *buffer, int maxlen,
+                             OF_node_t *node, const unsigned char *name)
+{
+    unsigned char tmp[OF_PROPLEN_MAX];
+    OF_prop_t *prop;
+    int len;
+
+    prop = OF_property_get(env, node, name);
+    if (prop == NULL) {
+        ERROR("%s cannot get property '%s' for %s\n", __func__, name,
+              node->prop_name->value);
+        return -1;
+    }
+    len = prop->vlen > maxlen ? maxlen : prop->vlen;
+    if (prop->value != NULL) {
+        tmp[0] = '0';
+        tmp[1] = 'x';
+        hex2buf(tmp + 2, *((uint32_t *)prop->value), 1);
+    } else {
+        *tmp = '\0';
+    }
+    OF_DPRINTF("copy property [%s] len=%d to %p len=%d\n",
+               name, prop->vlen, buffer, maxlen);
+    if (strcmp(name, "name") == 0) {
+        OF_DPRINTF("=> '%s'\n", prop->value);
+    }
+    memcpy(buffer, prop->value, len);
+    //    OF_DPRINTF("done\n");
+
+    return len;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_property_next (OF_env_t *env, OF_node_t *node,
+                                    const unsigned char *name)
+{
+    OF_prop_t *prop, *next;
+
+    if (name == NULL || *name == '\0') {
+        next = node->properties;
+    } else {
+        prop = OF_property_get(env, node, name);
+        if (prop == NULL) {
+            OF_DPRINTF("Property [%s] not found\n", name);
+            next = NULL;
+        } else {
+            next = prop->next;
+            /* Skip address if not set */
+            if (next == node->prop_address &&
+                *((uint32_t *)next->value) == OF_ADDRESS_NONE)
+                next = next->next;
+        }
+    }
+#if 0
+    OF_DPRINTF("Found property %p\n", next);
+#endif
+
+    return next;
+}
+
+/* Simplified helpers */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_prop_string_new (OF_env_t *env, OF_node_t *node,
+                                      const unsigned char *name,
+                                      const unsigned char *string)
+{
+#ifdef DEBUG_OF
+    {
+        OF_prop_t *prop;
+        prop = OF_property_get(env, node, name);
+        if (prop != NULL) {
+            printf("Property '%s' already present !\n", name);
+            bug();
+        }
+    }
+#endif
+    return OF_property_new(env, node, name,
+                           string, strlen(string) + 1);
+}
+
+/* convert '\1' char to '\0' */
+static OF_prop_t *OF_prop_string_new1 (OF_env_t *env, OF_node_t *node,
+                                       const unsigned char *name,
+                                       const unsigned char *string)
+{
+    int len, i;
+    OF_prop_t *ret;
+    unsigned char *str;
+
+    if (strchr(string, '\1') == NULL) {
+        return OF_prop_string_new(env, node, name, string);
+    } else {
+        len = strlen(string) + 1;
+        str = malloc(len);
+        if (!str)
+            return NULL;
+        memcpy(str, string, len);
+        for(i = 0; i < len; i++)
+            if (str[i] == '\1')
+                str[i] = '\0';
+        ret = OF_property_new(env, node, name,
+                              str, len);
+        free(str);
+        return ret;
+    }
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_prop_int_new (OF_env_t *env, OF_node_t *node,
+                                   const unsigned char *name, uint32_t value)
+{
+#ifdef DEBUG_OF
+    {
+        OF_prop_t *prop;
+        prop = OF_property_get(env, node, name);
+        if (prop != NULL) {
+            printf("Property '%s' already present !\n", name);
+            bug();
+        }
+    }
+#endif
+    return OF_property_new(env, node, name, &value, sizeof(uint32_t));
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_prop_string_set (OF_env_t *env, OF_node_t *node,
+                                      const unsigned char *name,
+                                      const unsigned char *string)
+{
+    const unsigned char *tmp;
+
+    tmp = strdup(string);
+    if (tmp == NULL) {
+        ERROR("%s cannot duplicate property '%s'\n", __func__, name);
+        return NULL;
+    }
+
+    return OF_property_set(env, node, name, tmp, strlen(string) + 1);
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_prop_int_set (OF_env_t *env, OF_node_t *node,
+                                   const unsigned char *name, uint32_t value)
+{
+    return OF_property_set(env, node, name, &value, sizeof(uint32_t));
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+unused
+static OF_prop_t *OF_set_compatibility (OF_env_t *env, OF_node_t *node,
+                                        const unsigned char *compat)
+{
+    return OF_prop_string_new(env, node, "compatible", compat);
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static inline void OF_property_set_cb (unused OF_env_t *OF_env,
+                                       OF_prop_t *prop,
+                                       void (*cb)(OF_env_t *OF_env,
+                                                  OF_prop_t *prop,
+                                                  const void *data, int len))
+{
+    prop->cb = cb;
+}
+
+/*****************************************************************************/
+/*                       Packages methods management                         */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_method_t *OF_method_new (unused OF_env_t *env, OF_node_t *node,
+                                   const unsigned char *name, OF_cb_t cb)
+{
+    OF_method_t *new;
+
+    new = malloc(sizeof(OF_method_t));
+    if (new == NULL) {
+        ERROR("%s cannot allocate method '%s'\n", __func__, name);
+        return NULL;
+    }
+    memset(new, 0, sizeof(OF_method_t));
+    new->node = node;
+    new->name = strdup(name);
+    if (new->name == NULL) {
+        free(new);
+        ERROR("%s cannot allocate method '%s' name\n", __func__, name);
+        return NULL;
+    }
+    OF_DPRINTF("new method name %p %s\n", new, new->name);
+    new->func = cb;
+    /* Link it */
+    /* *SHOULD LOCK* */
+    if (node->method_last == NULL)
+        node->methods = new;
+    else
+        node->method_last->next = new;
+    node->method_last = new;
+
+    return new;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_method_t *OF_method_get (unused OF_env_t *env, OF_node_t *node,
+                                   const unsigned char *name)
+{
+    OF_method_t *parse;
+
+    if (node == NULL) {
+        OF_DPRINTF("No method in NULL package !\n");
+        return NULL;
+    }
+#if 0
+    OF_DPRINTF("Look for method %s in package %0x\n",
+               name, node->pack_id);
+#endif
+    for (parse = node->methods; parse != NULL; parse = parse->next) {
+#if 0
+        OF_DPRINTF("check %p %p\n", parse, parse->name);
+        OF_DPRINTF("name=%s\n", parse->name);
+#endif
+        if (strcmp(parse->name, name) == 0)
+            return parse;
+    }
+
+    return NULL;
+}
+
+/*****************************************************************************/
+/*                     Packages instances management                         */
+__attribute__ (( section (".OpenFirmware") ))
+static uint16_t OF_inst_new_id (unused OF_env_t *env, OF_node_t *node)
+{
+    OF_inst_t *tmp_inst;
+    uint16_t cur_id;
+
+#if 0
+    OF_DPRINTF("[%s] %d\n", node->prop_name->value,
+               inst_last_id);
+#endif
+    for (cur_id = inst_last_id + 1;
+         cur_id != inst_last_id; cur_id++) {
+        if (cur_id == (uint16_t)(OF_MAX_PACKAGE))
+            cur_id = 0;
+        for (tmp_inst = node->instances; tmp_inst != NULL;
+             tmp_inst = tmp_inst->next) {
+            if (tmp_inst->inst_id == cur_id)
+                continue;
+        }
+        inst_last_id = cur_id;
+#if 1
+        OF_DPRINTF("0x%0x\n", cur_id);
+#endif
+        return cur_id;
+    }
+    OF_DPRINTF("no ID found\n");
+
+    return (uint16_t)(-1);
+}
+
+/* Create a new package's instance */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_inst_t *OF_instance_new (OF_env_t *env, OF_node_t *node)
+{
+    OF_inst_t *new, *parent;
+    uint16_t new_id;
+
+    /* TODO: recurse to root... */
+    new = malloc(sizeof(OF_inst_t));
+    if (new == NULL) {
+        ERROR("%s cannot allocate instance of '%s'\n", __func__,
+              node->prop_name->value);
+        return NULL;
+    }
+    memset(new, 0, sizeof(OF_inst_t));
+    if (OF_node_parent(env, node) != NULL) {
+        parent = OF_instance_new(env, OF_node_parent(env, node));
+        if (parent == NULL) {
+            free(new);
+            ERROR("%s cannot allocate instance of '%s' parent\n", __func__,
+                  node->prop_name->value);
+            return NULL;
+        }
+        new->parent = parent;
+    } else {
+        new->parent = NULL;
+    }
+    new_id = OF_inst_new_id(env, node);
+    if (new_id == (uint16_t)(-1)) {
+        free(new);
+        return NULL;
+    }
+    new->inst_id = new_id;
+    new->node = node;
+    /* Link it */
+    /* SHOULD LOCK */
+    if (node->inst_last == NULL)
+        node->instances = new;
+    else
+        node->inst_last->next = new;
+    node->inst_last = new;
+
+    return new;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static uint32_t OF_instance_get_id (unused OF_env_t *env, OF_inst_t *instance)
+{
+    OF_DPRINTF("p: %0x i: %0x\n", instance->node->pack_id, instance->inst_id);
+    return (instance->node->pack_id << 16) | instance->inst_id;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_inst_t *OF_inst_find (OF_env_t *env, uint32_t ihandle)
+{
+    OF_node_t *node;
+    OF_inst_t *parse;
+    uint16_t phandle = ihandle >> 16;
+
+    ihandle &= 0xFFFF;
+    OF_DPRINTF("p: %0x i: %0x\n", phandle, ihandle);
+    if (ihandle > OF_MAX_PACKAGE)
+        return NULL;
+    node = OF_pack_find(env, phandle);
+    if (node == NULL)
+        return NULL;
+    for (parse = node->instances; parse != NULL; parse = parse->next) {
+        if (parse->inst_id == ihandle)
+            return parse;
+    }
+
+    return NULL;
+}
+
+#if 0
+__attribute__ (( section (".OpenFirmware") ))
+static OF_inst_t *OF_inst_get_child (OF_env_t *env, OF_node_t *parent,
+                                     const uint32_t handle)
+{
+    OF_node_t *parse, *tmp;
+
+    for (parse = parent->children; parse != NULL; parse = parse->next) {
+        if (parse->pack_id == (handle >> 16)) {
+            return NULL;
+        }
+        tmp = OF_inst_get_child(env, parse, handle);
+        if (tmp != NULL)
+            return tmp;
+    }
+
+    return NULL;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_inst_t *OF_inst_get (OF_env_t *env, const unsigned char *name)
+{
+    return _OF_node_get(env, &OF_node_root);
+    
+}
+#endif
+
+#if 0
+__attribute__ (( section (".OpenFirmware") ))
+int get_node_name (OF_env_t *env, unsigned char *name,
+                   int len, OF_node_t *node)
+{
+    int tmp, total;
+    int i;
+
+    /* Set up manufacturer name */
+    total = 0;
+    tmp = 0;
+#if 0
+    if (OF_node_parent(env, node) == NULL ||
+        node->manufct != OF_node_parent(env, node)->manufct) {
+        tmp = strlen(node->manufct);
+        if ((tmp + 2) > len)
+            return -1;
+        memcpy(name, node->manufct, tmp);
+        name += tmp;
+    } else if (len < 2) {
+        return -1;
+    }
+    *name++ = ',';
+    len -= tmp + 1;
+    total += tmp + 1;
+#endif
+    /* Set up device model */
+    tmp = strlen(node->name);
+    if ((tmp + 2) > len)
+        return -1;
+    memcpy(name, node->model, tmp);
+    name += tmp;
+    *name++ = '@';
+    len -= tmp + 1;
+    total += tmp + 1;
+    /* Set up unit address */
+    tmp = strlen(node->address);
+    if ((tmp + 2) > len)
+        return -1;
+    memcpy(name, node->address, tmp);
+    name += tmp;
+    *name++ = ':';
+    len -= tmp + 1;
+    total += tmp + 1;
+    for (i = 0; node->arguments[i] != NULL; i++) {
+        if (i != 0)
+            *name++ = ',';
+        tmp = strlen(node->arguments[i]);
+        if ((tmp + 2) > len)
+            return -1;
+        memcpy(name, node->arguments[i], tmp);
+        name += tmp;
+        len -= tmp + 1;
+        total += tmp + 1;
+    }
+    *name = '\0';
+
+    return total;
+}
+#endif
+
+__attribute__ (( section (".OpenFirmware") ))
+static int OF_pack_get_path (OF_env_t *env, unsigned char *name,
+                             int len, OF_node_t *node)
+{
+    OF_prop_t *prop_name, *prop_address;
+    uint32_t address;
+    int tmp, nlen;
+
+    /* Recurse until we reach the root node */
+    OF_DPRINTF("look for [%s]\n", node->prop_name->value);
+    if (OF_node_parent(env, node) == NULL) {
+        name[0] = '/';
+        tmp = 0;
+        nlen = 1;
+    } else {
+        tmp = OF_pack_get_path(env, name, len, OF_node_parent(env, node));
+        /* Add node name */
+        prop_name = node->prop_name;
+        prop_address = node->prop_address;
+#if 1
+        OF_DPRINTF("Found [%s]\n", prop_name->value);
+#endif
+        if ((len - tmp) < 2) {
+            OF_DPRINTF("Buffer too short (%d 2)\n", len - tmp);
+            return 0;
+        }
+        if (prop_name == NULL) {
+            printf("No name in node !\n");
+            bug();
+        }
+        nlen = strlen(prop_name->value);
+#if 1
+        OF_DPRINTF("got '%s' for '%s' parent (%d %d)\n",
+                   name, prop_name->value, tmp, nlen);
+#endif
+        if (name[tmp - 1] != '/') {
+            name[tmp] = '/';
+            tmp++;
+        }
+        address = *((uint32_t *)prop_address->value);
+        if (address != OF_ADDRESS_NONE) {
+            if ((len - tmp - nlen) < 10) {
+                OF_DPRINTF("Buffer too short (%d %d)\n", len - tmp, nlen + 10);
+                return 0;
+            }
+        } else {
+            if ((len - tmp - nlen) < 1) {
+                OF_DPRINTF("Buffer too short (%d %d)\n", len - tmp, nlen + 1);
+                return 0;
+            }
+        }
+        memcpy(name + tmp, prop_name->value, nlen);
+        if (address != OF_ADDRESS_NONE) {
+            OF_DPRINTF("Add address 0x%08x\n", address);
+            sprintf(name + tmp + nlen, "@%x", address);
+            nlen += strlen(name + tmp + nlen);
+        } else {
+            OF_DPRINTF("No address....\n");
+        }
+    }
+    name[tmp + nlen] = '\0';
+    OF_DPRINTF("stored [%d]\n", tmp + nlen);
+    OF_DUMP_STRING(env, name);
+#if 1
+    OF_DPRINTF("name '%s' => '%s' %d\n",
+               node->properties->value, name, tmp + nlen);
+#endif
+
+    return tmp + nlen;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static int OF_inst_get_path (OF_env_t *env, unsigned char *name,
+                             int len, OF_inst_t *inst)
+{
+    return OF_pack_get_path(env, name, len, inst->node);
+}
+
+/*****************************************************************************/
+/*                       Open firmware C interface                           */
+static void OF_serial_write (OF_env_t *OF_env);
+static void OF_serial_read (OF_env_t *OF_env);
+static void OF_mmu_translate (OF_env_t *OF_env);
+static void OF_mmu_map (OF_env_t *OF_env);
+static void RTAS_instantiate (OF_env_t *RTAS_env);
+
+static OF_env_t *OF_env_main;
+
+/* Init standard OF structures */
+__attribute__ (( section (".OpenFirmware") ))
+int OF_init (void)
+{
+#if 0
+        "PowerMac3,1\0MacRISC\0Power Macintosh\0";
+        "PowerMac1,2\0MacRISC\0Power Macintosh\0";
+        "AAPL,PowerMac G3\0PowerMac G3\0MacRISC\0Power Macintosh\0";
+        "AAPL,PowerMac3,0\0MacRISC\0Power Macintosh\0";
+        "AAPL,Gossamer\0MacRISC\0Power Macintosh\0";
+#endif
+    OF_env_t *OF_env;
+    OF_node_t *als, *opt, *chs, *pks;
+    OF_inst_t *inst;
+    OF_range_t range;
+
+    OF_DPRINTF("start\n");
+    OF_env_main = malloc(sizeof(OF_env_t));
+    if (OF_env_main == NULL) {
+        ERROR("%s cannot allocate main OF env\n", __func__);
+        return -1;
+    }
+    //    memset(OF_env_main, 0, sizeof(OF_env_t));
+    OF_env = OF_env_main;
+    //    OF_env_init(OF_env);
+
+    OF_DPRINTF("start\n");
+    /* Set up standard IEEE 1275 nodes */
+    /* "/device-tree" */
+    OF_node_root = OF_node_new(OF_env, NULL, "device-tree", OF_ADDRESS_NONE);
+    if (OF_node_root == NULL) {
+        ERROR("Cannot create 'device-tree'\n");
+        return -1;
+    }
+    OF_prop_string_new(OF_env, OF_node_root, "device_type", "bootrom");
+    if (arch == ARCH_HEATHROW) {
+        const unsigned char compat_str[] =
+            "PowerMac1,1\0MacRISC\0Power Macintosh";
+        OF_property_new(OF_env, OF_node_root, "compatible",
+                        compat_str, sizeof(compat_str));
+    OF_prop_string_new(OF_env, OF_node_root,
+                           "model", "Power Macintosh");
+    } else {
+        const unsigned char compat_str[] =
+            "PowerMac3,1\0MacRISC\0Power Macintosh";
+    OF_property_new(OF_env, OF_node_root, "compatible",
+                    compat_str, sizeof(compat_str));
+        OF_prop_string_new(OF_env, OF_node_root,
+                           "model", "PowerMac3,1");
+    }
+#if 0
+    OF_prop_string_new(OF_env, OF_node_root, "copyright", copyright);
+#else
+    OF_prop_string_new(OF_env, OF_node_root, "copyright",
+            "Copyright 1983-1999 Apple Computer, Inc. All Rights Reserved");
+#endif
+    OF_prop_string_new(OF_env, OF_node_root, "system-id", "42");
+    OF_prop_int_new(OF_env, OF_node_root, "#address-cells", 1);
+    OF_prop_int_new(OF_env, OF_node_root, "#size-cells", 1);
+    OF_prop_int_new(OF_env, OF_node_root, "clock-frequency", 0x05F03E4D);
+    /* "/aliases" node */
+    als = OF_node_new(OF_env, OF_node_root, "aliases", OF_ADDRESS_NONE);
+    if (als == NULL) {
+        ERROR("Cannot create 'aliases'\n");
+        return -1;
+    }
+    /* "/chosen" node */
+    chs = OF_node_new(OF_env, OF_node_root, "chosen", OF_ADDRESS_NONE);
+    if (chs == NULL) {
+        ERROR("Cannot create 'choosen'\n");
+        return -1;
+    }
+    /* "/packages" node */
+    pks = OF_node_new(OF_env, OF_node_root, "packages", OF_ADDRESS_NONE);
+    if (pks == NULL) {
+        ERROR("Cannot create 'packages'\n");
+        return -1;
+    }
+    /* "/cpus" node */
+    {
+        OF_node_t *cpus;
+        cpus = OF_node_new(OF_env, OF_node_root, "cpus", OF_ADDRESS_NONE);
+        if (cpus == NULL) {
+            ERROR("Cannot create 'cpus'\n");
+            return -1;
+        }
+        OF_prop_int_new(OF_env, cpus, "#address-cells", 1);
+        OF_prop_int_new(OF_env, cpus, "#size-cells", 0);
+        OF_node_put(OF_env, cpus);
+    }
+    /* "/memory@0" node */
+    {
+        OF_node_t *mem;
+        mem = OF_node_new(OF_env, OF_node_root, "memory", 0);
+        if (mem == NULL) {
+            ERROR("Cannot create 'memory'\n");
+            return -1;
+        }
+        OF_prop_string_new(OF_env, mem, "device_type", "memory");
+        OF_prop_int_new(OF_env, chs, "memory", OF_pack_handle(OF_env, mem));
+        OF_node_put(OF_env, mem);
+    }
+    /* "/openprom" node */
+    {
+        OF_node_t *opp;
+        opp = OF_node_new(OF_env, OF_node_root, "openprom", OF_ADDRESS_NONE);
+        if (opp == NULL) {
+            ERROR("Cannot create 'openprom'\n");
+            return -1;
+        }
+        OF_prop_string_new(OF_env, opp, "device_type", "BootROM");
+        OF_prop_string_new(OF_env, opp, "model", "OpenFirmware 3");
+        OF_prop_int_new(OF_env, opp, "boot-syntax", 0x0001);
+        OF_property_new(OF_env, opp, "relative-addressing", NULL, 0);
+        OF_property_new(OF_env, opp, "supports-bootinfo", NULL, 0);
+        OF_prop_string_new(OF_env, opp, "built-on", stringify(BUILD_DATE));
+        OF_prop_string_new(OF_env, als, "rom", "/openprom");
+        OF_node_put(OF_env, opp);
+    }
+    /* "/options" node */
+    opt = OF_node_new(OF_env, OF_node_root, "options", OF_ADDRESS_NONE);
+    if (opt == NULL) {
+        ERROR("Cannot create 'options'\n");
+        return -1;
+    }
+    OF_prop_string_new(OF_env, opt, "little-endian?", "false");
+    OF_prop_string_new(OF_env, opt, "real-mode?", "false");
+    // Will play with this...
+    OF_prop_string_new(OF_env, opt, "security-mode", "none");
+    /* "/rom@ff800000" node */
+    {
+        OF_regprop_t regs;
+        OF_node_t *rom, *brom;
+
+        rom = OF_node_new(OF_env, OF_node_root, "rom", 0xff800000);
+        if (rom == NULL) {
+            ERROR("Cannot create 'rom'\n");
+            return -1;
+        }
+        regs.address = 0xFF800000;
+        regs.size = 0x00000000;
+        OF_property_new(OF_env, rom, "reg", &regs, sizeof(OF_regprop_t));
+        range.virt = 0xFF800000;
+        range.phys = 0xFF800000;
+        range.size = 0x00800000;
+        OF_property_new(OF_env, rom, "ranges", &range, sizeof(OF_range_t));
+        OF_prop_int_new(OF_env, rom, "#address-cells", 1);
+
+        /* "/rom/boot-rom@fff00000" node */
+        brom = OF_node_new(OF_env, rom, "boot-rom", 0xfff00000);
+        if (brom == NULL) {
+            ERROR("Cannot create 'boot-rom'\n");
+            return -1;
+        }
+        regs.address = 0xFFF00000;
+        regs.size = 0x00100000;
+        OF_property_new(OF_env, brom, "reg", &regs, sizeof(OF_regprop_t));
+        OF_prop_string_new(OF_env, brom, "write-characteristic", "flash");
+        OF_prop_string_new(OF_env, brom, "BootROM-build-date",
+                           stringify(BUILD_DATE) " at " stringify(BUILD_TIME));
+        OF_prop_string_new(OF_env, brom, "BootROM-version", BIOS_VERSION);
+        OF_prop_string_new(OF_env, brom, "copyright", copyright);
+        OF_prop_string_new(OF_env, brom, "model", BIOS_str);
+        OF_prop_int_new(OF_env, brom, "result", 0);
+#if 1
+        {
+            /* Hack taken 'as-is' from PearPC */
+            unsigned char info[] = {
+                0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
+                0x00, 0x01, 0x12, 0xf2, 0x19, 0x99, 0x08, 0x19,
+                0x94, 0x4e, 0x73, 0x27, 0xff, 0xf0, 0x80, 0x00,
+                0x00, 0x07, 0x80, 0x01, 0x00, 0x01, 0x12, 0xf2,
+                0x19, 0x99, 0x08, 0x19, 0xd7, 0xf3, 0xfc, 0x17,
+                0xff, 0xf8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02,
+                0x00, 0x01, 0x12, 0xf2, 0x19, 0x99, 0x08, 0x19,
+                0xbb, 0x10, 0xfc, 0x17,
+            };
+            OF_property_new(OF_env, brom, "info", info, sizeof(info));
+        }
+#endif
+        OF_node_put(OF_env, brom);
+        OF_node_put(OF_env, rom);
+    }
+#if 0
+    /* From here, hardcoded hacks to get a Mac-like machine */
+    /* XXX: Core99 does not seem to like this NVRAM tree */
+    /* "/nvram@fff04000" node */
+    {
+        OF_regprop_t regs;
+        OF_node_t *nvr;
+
+        nvr = OF_node_new(OF_env, OF_node_root, "nvram", 0xfff04000);
+        if (nvr == NULL) {
+            ERROR("Cannot create 'nvram'\n");
+            return -1;
+        }
+        OF_prop_string_new(OF_env, nvr, "device_type", "nvram");
+        /* XXX: use real NVRAM size instead */
+        OF_prop_int_new(OF_env, nvr, "#bytes", 0x2000);
+        OF_prop_string_new(OF_env, nvr, "compatible", "nvram,flash");
+        regs.address = 0xFFF04000;
+        regs.size = 0x00004000; /* Strange, isn't it ? */
+        OF_property_new(OF_env, nvr, "reg", &regs, sizeof(regs));
+        OF_prop_int_new(OF_env, chs, "nvram", OF_pack_handle(OF_env, nvr));
+        OF_node_put(OF_env, nvr);
+    }
+#endif
+    /* "/pseudo-hid" : hid emulation as Apple does */
+    {
+        OF_node_t *hid;
+
+        hid = OF_node_new(OF_env, OF_node_root,
+                          "pseudo-hid", OF_ADDRESS_NONE);
+        if (hid == NULL) {
+            ERROR("Cannot create 'pseudo-hid'\n");
+            return -1;
+        }
+        
+        /* "keyboard" node */
+        {
+            OF_node_t *kbd;
+            kbd = OF_node_new(OF_env, hid, "keyboard", OF_ADDRESS_NONE);
+            if (kbd == NULL) {
+                ERROR("Cannot create 'keyboard'\n");
+                return -1;
+            }
+            OF_prop_string_new(OF_env, kbd, "device_type", "keyboard");
+            OF_node_put(OF_env, kbd);
+        }
+        /* "mouse" node */
+        {
+            OF_node_t *mouse;
+            mouse = OF_node_new(OF_env, hid, "mouse", OF_ADDRESS_NONE);
+            if (mouse == NULL) {
+                ERROR("Cannot create 'mouse'\n");
+                return -1;
+            }
+            OF_prop_string_new(OF_env, mouse, "device_type", "mouse");
+            OF_node_put(OF_env, mouse);
+        }
+        /* "eject-key" node */
+        {
+            OF_node_t *ejk;
+            ejk = OF_node_new(OF_env, hid, "eject-key", OF_ADDRESS_NONE);
+            if (ejk == NULL) {
+                ERROR("Cannot create 'eject-key'\n");
+                return -1;
+            }
+            OF_prop_string_new(OF_env, ejk, "device_type", "eject-key");
+            OF_node_put(OF_env, ejk);
+        }
+        OF_node_put(OF_env, hid);
+    }
+    if (arch == ARCH_MAC99) {
+        OF_node_t *unin;
+        OF_regprop_t regs;
+
+        unin = OF_node_new(OF_env, OF_node_root,
+                           "uni-n", 0xf8000000);
+        if (unin == NULL) {
+            ERROR("Cannot create 'uni-n'\n");
+            return -1;
+        }
+        OF_prop_string_new(OF_env, unin, "device-type", "memory-controller");
+        OF_prop_string_new(OF_env, unin, "model", "AAPL,UniNorth");
+        OF_prop_string_new(OF_env, unin, "compatible", "uni-north");
+        regs.address = 0xf8000000;
+        regs.size = 0x01000000;
+        OF_property_new(OF_env, unin, "reg", &regs, sizeof(regs));
+        OF_prop_int_new(OF_env, unin, "#address-cells", 1);
+        OF_prop_int_new(OF_env, unin, "#size-cells", 1);
+        OF_prop_int_new(OF_env, unin, "device-rev", 3);
+        OF_node_put(OF_env, unin);
+    }
+    
+#if 1 /* This is mandatory for claim to work
+       * but I don't know where it should really be (in cpu ?)
+       */
+    {
+        OF_node_t *mmu;
+
+        /* "/mmu" node */
+        mmu = OF_node_new(OF_env, OF_node_root, "mmu", OF_ADDRESS_NONE);
+        if (mmu == NULL) {
+            ERROR("Cannot create 'mmu'\n");
+            return -1;
+        }
+        inst = OF_instance_new(OF_env, mmu);
+        if (inst == NULL) {
+            OF_node_put(OF_env, mmu);
+            ERROR("Cannot create 'mmu' instance\n");
+            return -1;
+        }
+        OF_prop_int_new(OF_env, chs, "mmu",
+                        OF_instance_get_id(OF_env, inst));
+        OF_method_new(OF_env, mmu, "translate", &OF_mmu_translate);
+        OF_method_new(OF_env, mmu, "map", &OF_mmu_map);
+        OF_node_put(OF_env, mmu);
+    }
+#endif
+
+    /* "/options/boot-args" node */
+    {
+        //        const unsigned char *args = "-v rootdev cdrom";
+        //const unsigned char *args = "-v io=0xffffffff";
+        const unsigned char *args = "-v";
+        /* Ask MacOS X to print debug messages */
+        //        OF_prop_string_new(OF_env, chs, "machargs", args);
+        //        OF_prop_string_new(OF_env, opt, "boot-command", args);
+        OF_prop_string_new(OF_env, opt, "boot-args", args);
+    }
+    
+    /* Release nodes */
+    OF_node_put(OF_env, opt);
+    OF_node_put(OF_env, pks);
+    OF_node_put(OF_env, chs);
+    OF_node_put(OF_env, als);
+    OF_node_put(OF_env, OF_node_root);
+    OF_DPRINTF("done\n");
+    
+    return 0;
+}
+
+/* Motherboard */
+#if 0 // For now, static values are used
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_mb (const unsigned char *model, const unsigned char **compats)
+{
+    OF_env_t *OF_env;
+    OF_node_t *root;
+    int i;
+    
+    OF_env = OF_env_main;
+    OF_DPRINTF("start\n");
+    root = OF_node_get(OF_env, "device_tree");
+    if (root == NULL) {
+        ERROR("Cannot get 'device-tree'\n");
+        return -1;
+    }
+    OF_DPRINTF("add model\n");
+    OF_prop_string_new(OF_env, OF_node_root, "model", model);
+    for (i = 0; i < 1 && compats[i] != NULL; i++) {
+        OF_DPRINTF("add compats %s\n", compats[i]);
+        OF_set_compatibility(OF_env, OF_node_root, compats[i]);
+    }
+    /* we don't implement neither "l2-cache" nor "cache" nodes */
+    OF_node_put(OF_env, root);
+    OF_DPRINTF("done\n");
+
+    return 0;
+}
+#endif
+
+/* CPU */
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_cpu (const unsigned char *name, int num, uint32_t pvr,
+                     uint32_t min_freq, uint32_t max_freq, uint32_t bus_freq,
+                     uint32_t tb_freq, uint32_t reset_io)
+{
+    unsigned char tmp[OF_NAMELEN_MAX];
+    OF_env_t *OF_env;
+    OF_node_t *cpus, *cpu, *l2c, *chs, *als;
+
+    OF_env = OF_env_main;
+    OF_DPRINTF("start\n");
+    cpus = OF_node_get(OF_env, "cpus");
+    if (cpus == NULL) {
+        ERROR("Cannot get 'cpus'\n");
+        return -1;
+    }
+    cpu = OF_node_new(OF_env, cpus, name, OF_ADDRESS_NONE);
+    if (cpu == NULL) {
+        OF_node_put(OF_env, cpus);
+        ERROR("Cannot create cpu '%s'\n", name);
+        return -1;
+    }
+    OF_prop_string_new(OF_env, cpu, "device_type", "cpu");
+    OF_prop_int_new(OF_env, cpu, "#address-cells", 0x00000001);
+    OF_prop_int_new(OF_env, cpu, "#size-cells", 0x00000000);
+    OF_prop_int_new(OF_env, cpu, "reg", num);
+    OF_prop_int_new(OF_env, cpu, "cpu-version", pvr);
+    OF_prop_int_new(OF_env, cpu, "clock-frequency", max_freq);
+    OF_prop_int_new(OF_env, cpu, "timebase-frequency", tb_freq);
+    OF_prop_int_new(OF_env, cpu, "bus-frequency", bus_freq);
+    OF_prop_int_new(OF_env, cpu, "min-clock-frequency", min_freq);
+    OF_prop_int_new(OF_env, cpu, "max-clock-frequency", max_freq);
+    OF_prop_int_new(OF_env, cpu, "tlb-size", 0x80);
+    OF_prop_int_new(OF_env, cpu, "tlb-sets", 0x40);
+    OF_prop_int_new(OF_env, cpu, "i-tlb-size", 0x40);
+    OF_prop_int_new(OF_env, cpu, "i-tlb-sets", 0x20);
+    OF_prop_int_new(OF_env, cpu, "i-cache-size", 0x8000);
+    OF_prop_int_new(OF_env, cpu, "i-cache-sets", 0x80);
+    OF_prop_int_new(OF_env, cpu, "i-cache-bloc-size", 0x20);
+    OF_prop_int_new(OF_env, cpu, "i-cache-line-size", 0x20);
+    OF_prop_int_new(OF_env, cpu, "d-tlb-size", 0x40);
+    OF_prop_int_new(OF_env, cpu, "d-tlb-sets", 0x20);
+    OF_prop_int_new(OF_env, cpu, "d-cache-size", 0x8000);
+    OF_prop_int_new(OF_env, cpu, "d-cache-sets", 0x80);
+    OF_prop_int_new(OF_env, cpu, "d-cache-bloc-size", 0x20);
+    OF_prop_int_new(OF_env, cpu, "d-cache-line-size", 0x20);
+    OF_prop_int_new(OF_env, cpu, "reservation-granule-size", 0x20);
+    OF_prop_int_new(OF_env, cpus, "soft-reset", reset_io);
+    OF_prop_string_new(OF_env, cpus, "graphics", "");
+    OF_prop_string_new(OF_env, cpus, "performance-monitor", "");
+    OF_prop_string_new(OF_env, cpus, "data-streams", "");
+    OF_prop_string_new(OF_env, cpu, "state", "running");
+    /* We don't implement:
+     * "dynamic-powerstep" & "reduced-clock-frequency"
+     * "l2cr-value"
+     */
+    /* Add L2 cache */
+    l2c = OF_node_new(OF_env, cpu, "l2cache", OF_ADDRESS_NONE);
+    if (l2c == NULL) {
+        ERROR("Cannot create 'l2cache'\n");
+        return -1;
+    }
+    OF_prop_string_new(OF_env, l2c, "device_type", "cache");
+    OF_prop_int_new(OF_env, l2c, "i-cache-size", 0x100000);
+    OF_prop_int_new(OF_env, l2c, "i-cache-sets", 0x2000);
+    OF_prop_int_new(OF_env, l2c, "i-cache-line-size", 0x40);
+    OF_prop_int_new(OF_env, l2c, "d-cache-size", 0x100000);
+    OF_prop_int_new(OF_env, l2c, "d-cache-sets", 0x2000);
+    OF_prop_int_new(OF_env, l2c, "d-cache-line-size", 0x40);
+    /* Register it in the cpu node */
+    OF_prop_int_new(OF_env, cpu, "l2-cache", OF_pack_handle(OF_env, l2c));
+    OF_node_put(OF_env, l2c);
+    /* Set it in "/chosen" and "/aliases" */
+    if (num == 0) {
+        OF_pack_get_path(OF_env, tmp, 512, cpu);
+        chs = OF_node_get(OF_env, "chosen");
+        if (chs == NULL) {
+            OF_node_put(OF_env, cpus);
+            ERROR("Cannot get 'chosen'\n");
+            return -1;
+        }
+        OF_prop_int_new(OF_env, chs, "cpu", OF_pack_handle(OF_env, cpu));
+        OF_node_put(OF_env, chs);
+        als = OF_node_get(OF_env, "aliases");
+        if (als == NULL) {
+            OF_node_put(OF_env, cpus);
+            ERROR("Cannot get 'aliases'\n");
+            return -1;
+        }
+        OF_prop_string_new(OF_env, als, "cpu", tmp);
+        OF_node_put(OF_env, als);
+    }
+    OF_node_put(OF_env, cpu);
+    OF_node_put(OF_env, cpus);
+    OF_DPRINTF("done\n");
+
+    return 0;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_translations (int nb, OF_transl_t *translations)
+{
+    OF_env_t *OF_env;
+    OF_node_t *cpus, *cpu;
+    OF_transl_t *new;
+    int i;
+
+    OF_env = OF_env_main;
+    OF_DPRINTF("start\n");
+    cpus = OF_node_get(OF_env, "cpus");
+    if (cpus == NULL) {
+        OF_node_put(OF_env, cpus);
+        ERROR("Cannot get 'cpus'\n");
+        return -1;
+    }
+    cpu = cpus->children;
+    new = malloc(nb * sizeof(OF_transl_t));
+    if (new == NULL) {
+        ERROR("Cannot create new translation\n");
+        return -1;
+    }
+    for (i = 0; i < nb; i++) {
+        new->virt = translations[i].virt;
+        new->size = translations[i].size;
+        new->phys = translations[i].phys;
+        new->mode = translations[i].mode;
+        OF_DPRINTF("%d\n", i);
+    }
+    OF_property_new(OF_env, cpu, "translations",
+                    new, nb * sizeof(OF_transl_t));
+    OF_node_put(OF_env, cpus);
+    OF_DPRINTF("done\n");
+    
+    return 0;
+}
+
+/* Memory ranges */
+typedef struct OF_mem_t OF_mem_t;
+struct OF_mem_t {
+    uint32_t start;
+    uint32_t size;
+};
+
+#define OF_MAX_MEMRANGES 16
+/* First entry is the whole known memory space */
+static OF_mem_t OF_mem_ranges[OF_MAX_MEMRANGES + 1];
+
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_memory (uint32_t memsize, unused uint32_t bios_size)
+{
+    OF_env_t *OF_env;
+    OF_node_t *mem;
+    OF_regprop_t regs[4];
+    int i;
+
+    OF_env = OF_env_main;
+    OF_DPRINTF("find node\n");
+    mem = OF_node_get(OF_env, "memory");
+    if (mem == NULL) {
+        ERROR("Cannot get 'memory'\n");
+        return -1;
+    }
+    OF_DPRINTF("Memory package: %04x\n", OF_pack_handle(OF_env, mem));
+    regs[0].address = 0x00000000;
+    regs[0].size = memsize;
+    regs[1].address = 0x00000000;
+    regs[1].size = 0x00000000;
+    regs[2].address = 0x00000000;
+    regs[2].size = 0x00000000;
+    regs[3].address = 0x00000000;
+    regs[3].size = 0x00000000;
+    OF_property_new(OF_env, mem, "reg", regs, 4 * sizeof(OF_regprop_t));
+#if 0
+#if 1
+    regs[0].address = 0x00000000;
+    regs[0].size = 0x05800000;
+    regs[1].address = 0x06000000;
+    regs[1].size = memsize - 0x06000000;
+    regs[2].address = 0x00000000;
+    regs[2].size = 0x00000000;
+    OF_property_new(OF_env, mem, "available",
+                    regs, 3 * sizeof(OF_regprop_t));
+#else
+    regs[0].address = 0x06000000;
+    regs[0].size = memsize - 0x06000000;
+    regs[1].address = 0x00000000;
+    regs[1].size = 0x00000000;
+    OF_property_new(OF_env, mem, "available",
+                    regs, 2 * sizeof(OF_regprop_t));
+#endif
+#endif
+    OF_node_put(OF_env, mem);
+#if 0
+    {
+        OF_node_t *mmu;
+        mmu = OF_node_get(OF_env, "mmu");
+        if (mmu == NULL) {
+            ERROR("Cannot get 'mmu'\n");
+            return -1;
+        }
+        regs[0].address = 0x00000000;
+        regs[0].size = memsize;
+        OF_property_new(OF_env, mmu, "reg", regs, sizeof(OF_regprop_t));
+        regs[0].address = 0x00000000;
+        regs[0].size = 0x05800000;
+        regs[1].address = 0x06000000;
+        regs[1].size = memsize - 0x06000000;
+        regs[2].address = 0x00000000;
+        regs[2].size = 0x00000000;
+        OF_property_new(OF_env, mmu, "available",
+                        regs, 3 * sizeof(OF_regprop_t));
+        OF_node_put(OF_env, mmu);
+    }
+#endif
+    /* Also update the claim areas */
+    OF_mem_ranges[0].start = 0x00000000;
+    OF_mem_ranges[0].size = memsize;
+    OF_mem_ranges[1].start = 0x58000000;
+    OF_mem_ranges[1].size = 0x08000000;
+    for (i = 2; i < OF_MAX_MEMRANGES + 1; i++) {
+        OF_mem_ranges[i].start = -1;
+        OF_mem_ranges[i].size = -1;
+    }
+    OF_DPRINTF("done\n");
+
+    return 0;
+}
+
+/* Linux kernel command line */
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_bootargs (const unsigned char *bootargs)
+{
+    OF_env_t *OF_env;
+    OF_node_t *chs;
+
+    OF_env = OF_env_main;
+    if (bootargs == NULL)
+        bootargs = "";
+    chs = OF_node_get(OF_env, "chosen");
+    if (chs == NULL) {
+        ERROR("Cannot get 'chosen'\n");
+        return -1;
+    }
+    OF_prop_string_set(OF_env, chs, "bootargs", bootargs);
+    //        OF_prop_string_set(OF_env, OF_node_root, "bootargs", "");
+    OF_node_put(OF_env, chs);
+
+    return 0;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void *OF_pci_device_new (OF_env_t *OF_env, OF_node_t *parent,
+                                pci_dev_t *dev, uint32_t address,
+                                uint16_t rev, uint32_t ccode,
+                                uint16_t min_grant, uint16_t max_latency)
+{
+    OF_node_t *node;
+
+    dprintf("register '%s' '%s' '%s' '%s' 0x%08x in '%s' 0x%08x\n",
+           dev->name, dev->type, dev->compat, dev->model, address,
+           parent->prop_name->value, *(uint32_t *)parent->prop_address->value);
+    node = OF_node_new(OF_env, parent, dev->name, address);
+    if (node == NULL)
+        return NULL;
+    OF_prop_int_new(OF_env, node, "vendor-id", dev->vendor);
+    OF_prop_int_new(OF_env, node, "device-id", dev->product);
+    OF_prop_int_new(OF_env, node, "revision-id", rev);
+    OF_prop_int_new(OF_env, node, "class-code", ccode);
+    OF_prop_int_new(OF_env, node, "min-grant", min_grant);
+    OF_prop_int_new(OF_env, node, "max-latency", max_latency);
+    if (dev->type != NULL)
+        OF_prop_string_new1(OF_env, node, "device_type", dev->type);
+    if (dev->compat != NULL)
+        OF_prop_string_new1(OF_env, node, "compatible", dev->compat);
+    if (dev->model != NULL)
+        OF_prop_string_new1(OF_env, node, "model", dev->model);
+    if (dev->acells != 0)
+        OF_prop_int_new(OF_env, node, "#address-cells", dev->acells);
+    if (dev->scells != 0)
+        OF_prop_int_new(OF_env, node, "#size-cells", dev->scells);
+    if (dev->icells != 0)
+        OF_prop_int_new(OF_env, node, "#interrupt-cells", dev->icells);
+    dprintf("Done %p %p\n", parent, node);
+    
+    return node;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+void *OF_register_pci_host (pci_dev_t *dev, uint16_t rev, uint32_t ccode,
+                            uint32_t cfg_base, uint32_t cfg_len,
+                            uint32_t mem_base, uint32_t mem_len,
+                            uint32_t io_base, uint32_t io_len,
+                            uint32_t rbase, uint32_t rlen,
+                            uint16_t min_grant, uint16_t max_latency)
+{
+    OF_env_t *OF_env;
+    pci_range_t ranges[3];
+    OF_regprop_t regs[1];
+    OF_node_t *pci_host, *als;
+    int nranges;
+    unsigned char buffer[OF_NAMELEN_MAX];
+
+    OF_env = OF_env_main;
+    dprintf("register PCI host '%s' '%s' '%s' '%s'\n",
+            dev->name, dev->type, dev->compat, dev->model);
+    pci_host = OF_pci_device_new(OF_env, OF_node_root, dev, cfg_base,
+                                 rev, ccode, min_grant, max_latency);
+    if (pci_host == NULL) {
+        ERROR("Cannot create pci host\n");
+        return NULL;
+    }
+    
+    als = OF_node_get(OF_env, "aliases");
+    if (als == NULL) {
+        ERROR("Cannot get 'aliases'\n");
+        return NULL;
+    }
+    sprintf(buffer, "/%s", dev->name);
+    OF_prop_string_set(OF_env, als, "pci", buffer);
+    OF_node_put(OF_env, als);
+    
+
+    regs[0].address = cfg_base;
+    regs[0].size = cfg_len;
+    OF_property_new(OF_env, pci_host, "reg", regs, sizeof(OF_regprop_t));
+    nranges = 0;
+    if (rbase != 0x00000000) {
+        ranges[nranges].addr.hi  = 0x02000000;
+        ranges[nranges].addr.mid = 0x00000000;
+        ranges[nranges].addr.lo  = rbase;
+        ranges[nranges].phys     = rbase;
+        ranges[nranges].size_hi  = 0x00000000;
+        ranges[nranges].size_lo  = rlen;
+        nranges++;
+    }
+    if (io_base != 0x00000000) {
+        ranges[nranges].addr.hi  = 0x01000000;
+        ranges[nranges].addr.mid = 0x00000000;
+        ranges[nranges].addr.lo  = 0x00000000;
+        ranges[nranges].phys     = io_base;
+        ranges[nranges].size_hi  = 0x00000000;
+        ranges[nranges].size_lo  = io_len;
+        nranges++;
+    }
+    if (mem_base != 0x00000000) {
+        ranges[nranges].addr.hi  = 0x02000000;
+        ranges[nranges].addr.mid = 0x00000000;
+        ranges[nranges].addr.lo  = mem_base;
+        ranges[nranges].phys     = mem_base;
+        ranges[nranges].size_hi  = 0x00000000;
+        ranges[nranges].size_lo  = mem_len;
+        nranges++;
+    }
+    OF_property_new(OF_env, pci_host, "ranges", ranges,
+                    nranges * sizeof(pci_range_t));
+
+    return pci_host;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+void *OF_register_pci_bridge (void *parent, pci_dev_t *dev,
+                              uint32_t cfg_base, uint32_t cfg_len,
+                              uint8_t devfn, uint8_t rev, uint32_t ccode,
+                              uint16_t min_grant, uint16_t max_latency)
+{
+    OF_env_t *OF_env;
+    OF_regprop_t regs[1];
+    OF_node_t *pci_bridge;
+
+    OF_env = OF_env_main;
+    OF_DPRINTF("register '%s' %08x '%s' '%s' '%s'\n",
+               dev->name, devfn >> 3, dev->type, dev->compat, dev->model);
+    dprintf("register PCI bridge '%s' %08x '%s' '%s' '%s'\n",
+            dev->name, devfn >> 3, dev->type, dev->compat, dev->model);
+    pci_bridge = OF_pci_device_new(OF_env, parent, dev, devfn >> 3,
+                                   rev, ccode, min_grant, max_latency);
+    if (pci_bridge == NULL) {
+        ERROR("Cannot create pci bridge\n");
+        return NULL;
+    }
+    regs[0].address = cfg_base;
+    regs[0].size = cfg_len;
+    OF_property_new(OF_env, pci_bridge, "reg", regs, sizeof(OF_regprop_t));
+
+    return pci_bridge;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+void *OF_register_pci_device (void *parent, pci_dev_t *dev,
+                              uint8_t devfn, uint8_t rev, uint32_t ccode,
+                              uint16_t min_grant, uint16_t max_latency)
+{
+    OF_env_t *OF_env;
+    OF_node_t *pci_dev;
+
+    OF_env = OF_env_main;
+    OF_DPRINTF("register '%s' %08x '%s' '%s' '%s'\n",
+               dev->name, devfn >> 3, dev->type, dev->compat, dev->model);
+    dprintf("register pci device '%s' %08x '%s' '%s' '%s'\n",
+               dev->name, devfn >> 3, dev->type, dev->compat, dev->model);
+    pci_dev = OF_pci_device_new(OF_env, parent, dev, devfn >> 3,
+                                rev, ccode, min_grant, max_latency);
+
+    return pci_dev;
+}
+
+/* XXX: suppress that, used for interrupt map init */
+OF_node_t *pci_host_node;
+uint32_t pci_host_interrupt_map[7 * 32];
+int pci_host_interrupt_map_len = 0;
+
+void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses)
+{
+    OF_env_t *OF_env;
+    OF_regprop_t regs[1];
+    
+    OF_env = OF_env_main;
+    regs[0].address = first_bus;
+    regs[0].size = nb_busses;
+    OF_property_new(OF_env, dev, "bus-range", regs, sizeof(OF_regprop_t));
+    pci_host_node = dev;
+}
+
+void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn,
+                             uint32_t *regions, uint32_t *sizes,
+                             int irq_line)
+{
+    OF_env_t *OF_env;
+    pci_reg_prop_t pregs[6], rregs[6];
+    uint32_t mask;
+    int i, j, k;
+
+    OF_env = OF_env_main;
+    /* XXX: only useful for VGA card in fact */
+    if (regions[0] != 0x00000000)
+        OF_prop_int_set(OF_env, dev, "address", regions[0] & ~0x0000000F);
+    for (i = 0, j = 0, k = 0; i < 6; i++) {
+        if (regions[i] != 0x00000000 && sizes[i] != 0x00000000) {
+            /* Generate "reg" property
+             */
+            if (regions[i] & 1) {
+                /* IO space */
+                rregs[j].addr.hi = 0x01000000;
+                mask = 0x00000001;
+            } else if (regions[i] & 4) {
+                /* 64 bits address space */
+                rregs[j].addr.hi = 0x83000000;
+                mask = 0x0000000F;
+#if 0
+            } else if ((regions[i] & 0xF) == 0x00) { /* ? */
+                /* Configuration space */
+                rregs[j].addr.hi = 0x00000000;
+                mask = 0x0000000F;
+#endif
+            } else {
+                /* 32 bits address space */
+                rregs[j].addr.hi = 0x82000000;
+                mask = 0x0000000F;
+            }
+            /* Set bus number */
+            rregs[j].addr.hi |= bus << 16;
+            /* Set device/function */
+            rregs[j].addr.hi |= devfn << 8;
+            /* Set register */
+#if 1
+            rregs[j].addr.hi |= 0x10 + (i * sizeof(uint32_t)); /* ? */
+#endif
+            /* Set address */
+            rregs[j].addr.mid = 0x00000000;
+            rregs[j].addr.lo = regions[i] & ~mask;
+            /* Set size */
+            rregs[j].size_hi = 0x00000000;
+            rregs[j].size_lo = sizes[i];
+#if 0
+            if ((rregs[j].addr.hi & 0x03000000) != 0x00000000)
+#endif
+            {
+                /* No assigned address for configuration space */
+                pregs[k].addr.hi = rregs[j].addr.hi; /* ? */
+                pregs[k].addr.mid = rregs[j].addr.mid;
+                pregs[k].addr.lo = rregs[j].addr.lo; /* ? */
+                pregs[k].size_hi = rregs[j].size_hi;
+                pregs[k].size_lo = rregs[j].size_lo;
+                k++;
+            }
+            j++;
+        }
+    }
+    if (j > 0) {
+        OF_property_new(OF_env, dev, "reg",
+                        rregs, j * sizeof(pci_reg_prop_t));
+    } else {
+        OF_property_new(OF_env, dev, "reg", NULL, 0);
+    }
+    if (k > 0) {
+        OF_property_new(OF_env, dev, "assigned-addresses",
+                        pregs, k * sizeof(pci_reg_prop_t));
+    } else {
+        OF_property_new(OF_env, dev, "assigned-addresses", NULL, 0);
+    }
+    if (irq_line >= 0) {
+        int i;
+        OF_prop_int_new(OF_env, dev, "interrupts", 1);
+        i = pci_host_interrupt_map_len;
+        pci_host_interrupt_map[i++] = (devfn << 8) & 0xf800;
+        pci_host_interrupt_map[i++] = 0;
+        pci_host_interrupt_map[i++] = 0;
+        pci_host_interrupt_map[i++] = 0;
+        pci_host_interrupt_map[i++] = 0; /* pic handle will be patched later */
+        pci_host_interrupt_map[i++] = irq_line;
+        if (arch != ARCH_HEATHROW) {
+            pci_host_interrupt_map[i++] = 1;
+        }
+        pci_host_interrupt_map_len = i;
+    }
+#if 1
+    {
+        OF_prop_t *prop_name = ((OF_node_t *)dev)->prop_name;
+
+        if (j > 0) {
+            dprintf("PCI device '%s' %d %d %d reg properties:\n",
+                    prop_name->value, bus, devfn >> 3, devfn & 7);
+            for (i = 0; i < j; i++) {
+                dprintf("  addr: %08x %08x %08x size: %08x %08x\n",
+                        rregs[i].addr.hi, rregs[i].addr.mid, rregs[i].addr.lo,
+                        rregs[i].size_hi, rregs[i].size_lo);
+            }
+        } else {
+            dprintf("PCI device '%s' %d %d %d has no reg properties:\n",
+                    prop_name->value, bus, devfn >> 3, devfn & 7);
+        }
+        if (k > 0) {
+            dprintf("PCI device '%s' %d %d %d "
+                    "assigned addresses properties:\n",
+                    prop_name->value, bus, devfn >> 3, devfn & 7);
+            for (i = 0; i < j; i++) {
+                dprintf("  addr: %08x %08x %08x size: %08x %08x\n",
+                        pregs[i].addr.hi, pregs[i].addr.mid, pregs[i].addr.lo,
+                        pregs[i].size_hi, pregs[i].size_lo);
+            }
+        } else {
+            dprintf("PCI device '%s' %d %d %d has no "
+                    "assigned addresses properties:\n",
+                    prop_name->value, bus, devfn >> 3, devfn & 7);
+        }
+    }
+#endif
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_bus (const unsigned char *name, uint32_t address,
+                     const unsigned char *type)
+{
+    unsigned char buffer[OF_NAMELEN_MAX];
+    OF_env_t *OF_env;
+    OF_node_t *bus, *als;
+    
+    OF_env = OF_env_main;
+    als = OF_node_get(OF_env, "aliases");
+    if (als == NULL) {
+        ERROR("Cannot get 'aliases'\n");
+        return -1;
+    }
+    bus = OF_node_new(OF_env, OF_node_root, name, address);
+    if (bus == NULL) {
+        OF_node_put(OF_env, als);
+        ERROR("Cannot create bus '%s'\n", name);
+        return -1;
+    }
+    OF_prop_string_set(OF_env, bus, "type", type);
+    sprintf(buffer, "/%s", name);
+    OF_prop_string_set(OF_env, als, name, buffer);
+    /* For ISA, should add DMA ranges */
+    OF_node_put(OF_env, bus);
+    OF_node_put(OF_env, als);
+
+    return 0;
+}
+
+// We will need to register stdin & stdout via the serial port
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_serial (const unsigned char *bus, const unsigned char *name,
+                        uint32_t io_base, unused int irq)
+{
+    unsigned char tmp[OF_NAMELEN_MAX];
+    OF_env_t *OF_env;
+    OF_node_t *busn, *srl, *als;
+
+    OF_env = OF_env_main;
+    als = OF_node_get(OF_env, "aliases");
+    if (als == NULL) {
+        ERROR("Cannot get 'aliases'\n");
+        return -1;
+    }
+    busn = OF_node_get(OF_env, bus);
+    srl = OF_node_new(OF_env, busn, name, io_base);
+    if (srl == NULL) {
+        OF_node_put(OF_env, als);
+        ERROR("Cannot create serial '%s'\n", name);
+        return -1;
+    }
+    OF_prop_string_set(OF_env, srl, "device_type", "serial");
+    OF_prop_string_set(OF_env, srl, "compatible", "pnpPNP,501");
+    switch (io_base) {
+    case 0x3F8:
+        OF_pack_get_path(OF_env, tmp, 512, srl);
+        OF_prop_string_new(OF_env, als, "com1", tmp);
+        break;
+    case 0x2F8:
+        OF_pack_get_path(OF_env, tmp, 512, srl);
+        OF_prop_string_new(OF_env, als, "com2", tmp);
+        break;
+    default:
+        break;
+    }
+    /* register read/write methods and create an instance of the package */
+    OF_method_new(OF_env, srl, "write", &OF_serial_write);
+    OF_method_new(OF_env, srl, "read", &OF_serial_read);
+    OF_node_put(OF_env, srl);
+    OF_node_put(OF_env, busn);
+    OF_node_put(OF_env, als);
+
+    return 0;
+}
+
+/* We will also need /isa/rtc */
+
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_stdio (const unsigned char *dev_in,
+                       const unsigned char *dev_out)
+{
+    OF_env_t *OF_env;
+    OF_node_t *chs, *ndev_in, *ndev_out, *kbd;
+    OF_inst_t *in_inst, *out_inst;
+    
+    OF_env = OF_env_main;
+    chs = OF_node_get(OF_env, "chosen");
+    if (chs == NULL) {
+        ERROR("Cannot get 'chosen'\n");
+        return -1;
+    }
+    ndev_in = OF_node_get(OF_env, dev_in);
+    ndev_out = OF_node_get(OF_env, dev_out);
+    in_inst = OF_instance_new(OF_env, ndev_in);
+    if (in_inst == NULL) {
+        OF_node_put(OF_env, ndev_out);
+        OF_node_put(OF_env, ndev_in);
+        OF_node_put(OF_env, chs);
+        ERROR("Cannot create in_inst\n");
+        return -1;
+    }
+    out_inst = OF_instance_new(OF_env, ndev_out);
+    if (out_inst == NULL) {
+        OF_node_put(OF_env, ndev_out);
+        OF_node_put(OF_env, ndev_in);
+        OF_node_put(OF_env, chs);
+        ERROR("Cannot create out_inst\n");
+        return -1;
+    }
+    OF_prop_int_set(OF_env, chs, "stdin",
+                    OF_instance_get_id(OF_env, in_inst));
+    OF_prop_int_set(OF_env, chs, "stdout",
+                    OF_instance_get_id(OF_env, out_inst));
+    kbd = OF_node_new(OF_env, ndev_in, "keyboard", OF_ADDRESS_NONE);
+    if (kbd == NULL) {
+        OF_node_put(OF_env, ndev_out);
+        OF_node_put(OF_env, ndev_in);
+        OF_node_put(OF_env, chs);
+        ERROR("Cannot create 'keyboard' for stdio\n");
+        return -1;
+    }
+    OF_prop_string_new(OF_env, kbd, "device_type", "keyboard");
+    OF_node_put(OF_env, kbd);
+    OF_DPRINTF("stdin h: 0x%0x out : 0x%0x\n",
+               OF_instance_get_id(OF_env, in_inst),
+               OF_instance_get_id(OF_env, out_inst));
+    OF_node_put(OF_env, ndev_out);
+    OF_node_put(OF_env, ndev_in);
+    OF_node_put(OF_env, chs);
+
+    return 0;
+}
+
+static void keylargo_ata(OF_node_t *mio, uint32_t base_address,
+                         uint32_t base, int irq1, int irq2, 
+                         uint16_t pic_phandle)
+{
+    OF_env_t *OF_env = OF_env_main;
+    OF_node_t *ata;
+    OF_regprop_t regs[2];
+
+    ata = OF_node_new(OF_env, mio, "ata-4", base);
+    if (ata == NULL) {
+        ERROR("Cannot create 'ata-4'\n");
+        return;
+    }
+    OF_prop_string_new(OF_env, ata, "device_type", "ata");
+#if 1
+    OF_prop_string_new(OF_env, ata, "compatible", "key2largo-ata");
+    OF_prop_string_new(OF_env, ata, "model", "ata-4");
+    OF_prop_string_new(OF_env, ata, "cable-type", "80-conductor");
+#else
+    OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata");
+    OF_prop_string_new(OF_env, ata, "model", "ata-4");
+#endif
+    OF_prop_int_new(OF_env, ata, "#address-cells", 1);
+    OF_prop_int_new(OF_env, ata, "#size-cells", 0);
+    regs[0].address = base;
+    regs[0].size = 0x00001000;
+#if 0 // HACK: Don't set up DMA registers
+    regs[1].address = 0x00008A00;
+    regs[1].size = 0x00001000;
+    OF_property_new(OF_env, ata, "reg",
+                    regs, 2 * sizeof(OF_regprop_t));
+#else
+    OF_property_new(OF_env, ata, "reg",
+                    regs, sizeof(OF_regprop_t));
+#endif
+    OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle);
+    regs[0].address = irq1;
+    regs[0].size = 0x00000001;
+    regs[1].address = irq2;
+    regs[1].size = 0x00000000;
+    OF_property_new(OF_env, ata, "interrupts",
+                    regs, 2 * sizeof(OF_regprop_t));
+    if (base == 0x1f000)
+        ide_pci_pmac_register(base_address + base, 0x00000000, ata);
+    else
+        ide_pci_pmac_register(0x00000000, base_address + base, ata);
+}
+
+void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size,
+                            void *private_data)
+{
+    unsigned char tmp[OF_NAMELEN_MAX];
+    OF_env_t *OF_env;
+    pci_reg_prop_t pregs[2];
+    OF_node_t *mio, *chs, *als;
+    uint16_t pic_phandle;
+    int rec_len;
+    OF_prop_t *mio_reg;
+
+    OF_DPRINTF("mac-io: %p\n", dev);
+    OF_env = OF_env_main;
+    chs = OF_node_get(OF_env, "chosen");
+    if (chs == NULL) {
+        ERROR("Cannot get 'chosen'\n");
+        return;
+    }
+    als = OF_node_get(OF_env, "aliases");
+    if (als == NULL) {
+        OF_node_put(OF_env, als);
+        ERROR("Cannot get 'aliases'\n");
+        return;
+    }
+    /* Mac-IO is mandatory for OSX to boot */
+    mio = dev;
+    mio->private_data = private_data;
+    pregs[0].addr.hi = 0x00000000;
+    pregs[0].addr.mid = 0x00000000;
+    pregs[0].addr.lo = 0x00000000;
+    pregs[0].size_hi = base_address;
+    pregs[0].size_lo = size;
+    mio_reg = OF_property_get(OF_env, mio, "reg");
+    if (mio_reg && mio_reg->vlen >= 5 * 4) {
+        pregs[0].addr.mid = ((pci_reg_prop_t *)mio_reg->value)->addr.hi;
+    }
+    OF_property_new(OF_env, mio, "ranges",
+                    &pregs, sizeof(pci_reg_prop_t));
+#if 0
+    pregs[0].addr.hi = 0x82013810;
+    pregs[0].addr.mid = 0x00000000;
+    pregs[0].addr.lo = 0x80800000;
+    pregs[0].size_hi = 0x00000000;
+    pregs[0].size_lo = 0x00080000;
+    OF_property_new(OF_env, mio, "assigned-addresses",
+                    &pregs, sizeof(pci_reg_prop_t));
+#endif
+
+    if (arch == ARCH_HEATHROW) {
+        /* Heathrow PIC */
+        OF_regprop_t regs;
+        OF_node_t *mpic;
+        const char compat_str[] = "heathrow\0mac-risc";
+
+        mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x10);
+        if (mpic == NULL) {
+            ERROR("Cannot create 'mpic'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, mpic, "device_type", "interrupt-controller");
+        OF_property_new(OF_env, mpic, "compatible", compat_str, sizeof(compat_str));
+        OF_prop_int_new(OF_env, mpic, "#interrupt-cells", 1);
+        regs.address = 0x10;
+        regs.size = 0x20;
+        OF_property_new(OF_env, mpic, "reg",
+                        &regs, sizeof(regs));
+        OF_property_new(OF_env, mpic, "interrupt-controller", NULL, 0);
+        pic_phandle = OF_pack_handle(OF_env, mpic);
+        OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle);
+        OF_node_put(OF_env, mpic);
+        rec_len = 6;
+    } else {
+    /* OpenPIC */
+        OF_regprop_t regs[4];
+        OF_node_t *mpic;
+        mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x40000);
+        if (mpic == NULL) {
+            ERROR("Cannot create 'mpic'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, mpic, "device_type", "open-pic");
+        OF_prop_string_new(OF_env, mpic, "compatible", "chrp,open-pic");
+        OF_property_new(OF_env, mpic, "interrupt-controller", NULL, 0);
+        OF_property_new(OF_env, mpic, "built-in", NULL, 0);
+        OF_prop_int_new(OF_env, mpic, "clock-frequency", 0x003F7A00);
+        OF_prop_int_new(OF_env, mpic, "#address-cells", 0);
+        OF_prop_int_new(OF_env, mpic, "#interrupt-cells", 2);
+        memset(regs, 0, 4 * sizeof(OF_regprop_t));
+        regs[0].address = 0x00040000;
+        regs[0].size = 0x00040000;
+        OF_property_new(OF_env, mpic, "reg",
+                        &regs, 1 * sizeof(OF_regprop_t));
+        pic_phandle = OF_pack_handle(OF_env, mpic);
+        OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle);
+        OF_node_put(OF_env, mpic);
+        rec_len = 7;
+    }
+
+    /* patch pci host table */
+    /* XXX: do it after the PCI init */
+    {
+        int i;
+        uint32_t tab[4];
+
+        for(i = 0; i < pci_host_interrupt_map_len; i += rec_len)
+            pci_host_interrupt_map[i + 4] = pic_phandle;
+#if 0
+        dprintf("interrupt-map:\n");
+        for(i = 0; i < pci_host_interrupt_map_len; i++) {
+            dprintf(" %08x", pci_host_interrupt_map[i]);
+            if ((i % rec_len) == (rec_len - 1))
+                dprintf("\n");
+        }
+        dprintf("\n");
+#endif
+        OF_property_new(OF_env, pci_host_node, "interrupt-map", 
+                        pci_host_interrupt_map, 
+                        pci_host_interrupt_map_len * sizeof(uint32_t));
+        tab[0] = 0xf800;
+        tab[1] = 0;
+        tab[2] = 0;
+        tab[3] = 0;
+        OF_property_new(OF_env, pci_host_node, "interrupt-map-mask", 
+                        tab, 4 * sizeof(uint32_t));
+    }
+#if 0
+    /* escc is useful to get MacOS X debug messages */
+    {
+        OF_regprop_t regs[8];
+        uint32_t irqs[6];
+        OF_node_t *scc, *chann;
+        scc = OF_node_new(OF_env, mio, "escc", 0x13000);
+        if (scc == NULL) {
+            ERROR("Cannot create 'escc'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, scc, "device_type", "escc");
+        OF_prop_string_new(OF_env, scc, "compatible", "chrp,es0");
+        OF_property_new(OF_env, scc, "built-in", NULL, 0);
+        OF_prop_int_new(OF_env, scc, "#address-cells", 1);
+        memset(regs, 0, 8 * sizeof(OF_regprop_t));
+        regs[0].address = 0x00013000;
+        regs[0].size = 0x00001000;
+        regs[1].address = 0x00008400;
+        regs[1].size = 0x00000100;
+        regs[2].address = 0x00008500;
+        regs[2].size = 0x00000100;
+        regs[3].address = 0x00008600;
+        regs[3].size = 0x00000100;
+        regs[4].address = 0x00008700;
+        regs[4].size = 0x00000100;
+        OF_property_new(OF_env, scc, "reg",
+                        regs, 5 * sizeof(OF_regprop_t));
+        OF_property_new(OF_env, scc, "ranges", NULL, 0);
+        /* Set up two channels */
+        chann = OF_node_new(OF_env, scc, "ch-a", 0x13020);
+        if (chann == NULL) {
+            ERROR("Cannot create 'ch-a'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, chann, "device_type", "serial");
+        OF_prop_string_new(OF_env, chann, "compatible", "chrp,es2");
+        OF_property_new(OF_env, chann, "built-in", NULL, 0);
+        OF_prop_int_new(OF_env, chann, "slot-names", 0);
+        OF_prop_int_new(OF_env, chann, "interrupt-parent", pic_phandle);
+        memset(regs, 0, 8 * sizeof(OF_regprop_t));
+        regs[0].address = 0x00013020;
+        regs[0].size = 0x00000001;
+        regs[1].address = 0x00013030;
+        regs[1].size = 0x00000001;
+        regs[2].address = 0x00013050;
+        regs[2].size = 0x00000001;
+        regs[3].address = 0x00008400;
+        regs[3].size = 0x00000100;
+        regs[4].address = 0x00008500;
+        regs[4].size = 0x00000100;
+        OF_property_new(OF_env, chann, "reg",
+                        regs, 5 * sizeof(OF_regprop_t));
+        /* XXX: tofix: those are regprops */
+        irqs[0] = 0x16;
+        irqs[1] = 0x01;
+        irqs[2] = 0x05;
+        irqs[3] = 0x00;
+        irqs[4] = 0x06;
+        irqs[5] = 0x00;
+        OF_property_new(OF_env, chann, "interrupts",
+                        irqs, 6 * sizeof(uint32_t));
+        OF_node_put(OF_env, chann);
+        chann = OF_node_new(OF_env, scc, "ch-b", 0x13000);
+        if (chann == NULL) {
+            ERROR("Cannot create 'ch-b'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, chann, "device_type", "serial");
+        OF_prop_string_new(OF_env, chann, "compatible", "chrp,es3");
+        OF_property_new(OF_env, chann, "built-in", NULL, 0);
+        OF_prop_int_new(OF_env, chann, "slot-names", 0);
+        OF_prop_int_new(OF_env, chann, "interrupt-parent", pic_phandle);
+        memset(regs, 0, 8 * sizeof(OF_regprop_t));
+        regs[0].address = 0x00013000;
+        regs[0].size = 0x00000001;
+        regs[1].address = 0x00013010;
+        regs[1].size = 0x00000001;
+        regs[2].address = 0x00013040;
+        regs[2].size = 0x00000001;
+        regs[3].address = 0x00008600;
+        regs[3].size = 0x00000100;
+        regs[4].address = 0x00008700;
+        regs[4].size = 0x00000100;
+        OF_property_new(OF_env, chann, "reg",
+                        regs, 5 * sizeof(OF_regprop_t));
+        /* XXX: tofix: those are regprops */
+        irqs[0] = 0x17;
+        irqs[1] = 0x01;
+        irqs[2] = 0x07;
+        irqs[3] = 0x00;
+        irqs[4] = 0x08;
+        irqs[5] = 0x00;
+        OF_property_new(OF_env, chann, "interrupts",
+                        irqs, 6 * sizeof(uint32_t));
+        OF_node_put(OF_env, chann);
+        OF_node_put(OF_env, scc);
+        /* MacOS likes escc-legacy */
+        scc = OF_node_new(OF_env, mio, "escc-legacy", 0x12000);
+        if (scc == NULL) {
+            ERROR("Cannot create 'escc-legacy'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, scc, "device_type", "escc-legacy");
+        OF_prop_string_new(OF_env, scc, "compatible", "chrp,es1");
+        OF_property_new(OF_env, scc, "built-in", NULL, 0);
+        OF_prop_int_new(OF_env, scc, "#address-cells", 1);
+        memset(regs, 0, 8 * sizeof(OF_regprop_t));
+        regs[0].address = 0x00012000;
+        regs[0].size = 0x00001000;
+        regs[1].address = 0x00008400;
+        regs[1].size = 0x00000100;
+        regs[2].address = 0x00008500;
+        regs[2].size = 0x00000100;
+        regs[3].address = 0x00008600;
+        regs[3].size = 0x00000100;
+        regs[4].address = 0x00008700;
+        regs[4].size = 0x00000100;
+        OF_property_new(OF_env, scc, "reg",
+                        regs, 8 * sizeof(OF_regprop_t));
+        OF_property_new(OF_env, scc, "ranges", NULL, 0);
+        /* Set up two channels */
+        chann = OF_node_new(OF_env, scc, "ch-a", 0x12004);
+        if (chann == NULL) {
+            ERROR("Cannot create 'ch-a'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, chann, "device_type", "serial");
+        OF_prop_string_new(OF_env, chann, "compatible", "chrp,es4");
+        OF_property_new(OF_env, chann, "built-in", NULL, 0);
+        OF_prop_int_new(OF_env, chann, "interrupt-parent", pic_phandle);
+        memset(regs, 0, 8 * sizeof(OF_regprop_t));
+        regs[0].address = 0x00012004;
+        regs[0].size = 0x00000001;
+        regs[1].address = 0x00012006;
+        regs[1].size = 0x00000001;
+        regs[2].address = 0x0001200A;
+        regs[2].size = 0x00000001;
+        regs[3].address = 0x00008400;
+        regs[3].size = 0x00000100;
+        regs[4].address = 0x00008500;
+        regs[4].size = 0x00000100;
+        OF_property_new(OF_env, chann, "reg",
+                        regs, 8 * sizeof(OF_regprop_t));
+        /* XXX: tofix: those are regprops */
+        irqs[0] = 0x16;
+        irqs[1] = 0x01;
+        irqs[2] = 0x05;
+        irqs[3] = 0x00;
+        irqs[4] = 0x06;
+        irqs[5] = 0x00;
+        OF_property_new(OF_env, chann, "interrupts",
+                        irqs, 6 * sizeof(uint32_t));
+        OF_node_put(OF_env, chann);
+        chann = OF_node_new(OF_env, scc, "ch-b", 0x12000);
+        if (chann == NULL) {
+            ERROR("Cannot create 'ch-b'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, chann, "device_type", "serial");
+        OF_prop_string_new(OF_env, chann, "compatible", "chrp,es5");
+        OF_property_new(OF_env, chann, "built-in", NULL, 0);
+        OF_prop_int_new(OF_env, chann, "interrupt-parent", pic_phandle);
+        memset(regs, 0, 8 * sizeof(OF_regprop_t));
+        regs[0].address = 0x00012000;
+        regs[0].size = 0x00000001;
+        regs[1].address = 0x00012002;
+        regs[1].size = 0x00000001;
+        regs[2].address = 0x00012008;
+        regs[2].size = 0x00000001;
+        regs[3].address = 0x00008600;
+        regs[3].size = 0x00000100;
+        regs[4].address = 0x00008700;
+        regs[4].size = 0x00000100;
+        OF_property_new(OF_env, chann, "reg",
+                        regs, 8 * sizeof(OF_regprop_t));
+        /* XXX: tofix: those are regprops */
+        irqs[0] = 0x17;
+        irqs[1] = 0x01;
+        irqs[2] = 0x07;
+        irqs[3] = 0x00;
+        irqs[4] = 0x08;
+        irqs[5] = 0x00;
+        OF_property_new(OF_env, chann, "interrupts",
+                        irqs, 6 * sizeof(uint32_t));
+        OF_node_put(OF_env, chann);
+        OF_node_put(OF_env, scc);
+    }
+#endif
+    /* Keylargo IDE controller: need some work (DMA problem ?) */
+    if (arch == ARCH_MAC99) {
+        keylargo_ata(mio, base_address, 0x1f000, 0x13, 0xb, pic_phandle);
+        keylargo_ata(mio, base_address, 0x20000, 0x14, 0xb, pic_phandle);
+    }
+#if 0
+    /* Timer */
+    {
+        OF_node_t *tmr;
+        OF_regprop_t regs[1];
+        tmr = OF_node_new(OF_env, mio, "timer", 0x15000);
+        if (tmr == NULL) {
+            ERROR("Cannot create 'timer'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, tmr, "device_type", "timer");
+        OF_prop_string_new(OF_env, tmr, "compatible", "keylargo-timer");
+        OF_prop_int_new(OF_env, tmr, "clock-frequency", 0x01194000);
+        regs[0].address = 0x00015000;
+        regs[0].size = 0x00001000;
+        OF_property_new(OF_env, tmr, "reg", regs, sizeof(OF_regprop_t));
+        OF_prop_int_new(OF_env, tmr, "interrupt-parent", pic_phandle);
+        regs[0].address = 0x00000020;
+        regs[0].size = 0x00000001;
+        OF_property_new(OF_env, tmr, "interrupts",
+                        regs, sizeof(OF_regprop_t));
+        OF_node_put(OF_env, tmr);
+    }
+#endif
+    /* VIA-PMU */
+    {
+        /* Controls adb, RTC and power-mgt (forget it !) */
+        OF_node_t *via, *adb;
+        OF_regprop_t regs[1];
+#if 0 // THIS IS A HACK AND IS COMPLETELY ABSURD !
+      // (but needed has Qemu doesn't emulate via-pmu).
+        via = OF_node_new(OF_env, mio, "via-pmu", 0x16000);
+        if (via == NULL) {
+            ERROR("Cannot create 'via-pmu'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, via, "device_type", "via-pmu");
+        OF_prop_string_new(OF_env, via, "compatible", "pmu");
+#else
+        via = OF_node_new(OF_env, mio, "via-cuda", 0x16000);
+        if (via == NULL) {
+            ERROR("Cannot create 'via-cuda'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, via, "device_type", "via-cuda");
+        OF_prop_string_new(OF_env, via, "compatible", "cuda");
+#endif
+        regs[0].address = 0x00016000;
+        regs[0].size = 0x00002000;
+        OF_property_new(OF_env, via, "reg", regs, sizeof(OF_regprop_t));
+        OF_prop_int_new(OF_env, via, "interrupt-parent", pic_phandle);
+        if (arch == ARCH_HEATHROW) {
+            OF_prop_int_new(OF_env, via, "interrupts", 0x12);
+        } else {
+        regs[0].address = 0x00000019;
+        regs[0].size = 0x00000001;
+        OF_property_new(OF_env, via, "interrupts",
+                        regs, sizeof(OF_regprop_t));
+        }
+        /* force usage of OF bus speeds */
+        OF_prop_int_new(OF_env, via, "BusSpeedCorrect", 1);
+#if 0
+        OF_prop_int_new(OF_env, via, "pmu-version", 0x00D0740C);
+#endif
+        {
+            OF_node_t *kbd, *mouse;
+        /* ADB pseudo-device */
+        adb = OF_node_new(OF_env, via, "adb", OF_ADDRESS_NONE);
+        if (adb == NULL) {
+            ERROR("Cannot create 'adb'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, adb, "device_type", "adb");
+#if 0
+        OF_prop_string_new(OF_env, adb, "compatible", "pmu-99");
+#else
+        OF_prop_string_new(OF_env, adb, "compatible", "adb");
+#endif
+        OF_prop_int_new(OF_env, adb, "#address-cells", 1);
+        OF_prop_int_new(OF_env, adb, "#size-cells", 0);
+        OF_pack_get_path(OF_env, tmp, 512, adb);
+        OF_prop_string_new(OF_env, als, "adb", tmp);
+
+            kbd = OF_node_new(OF_env, adb, "keyboard", 2);
+            if (kbd == NULL) {
+                ERROR("Cannot create 'kbd'\n");
+                goto out;
+            }
+            OF_prop_string_new(OF_env, kbd, "device_type", "keyboard");
+            OF_prop_int_new(OF_env, kbd, "reg", 2);
+
+            mouse = OF_node_new(OF_env, adb, "mouse", 3);
+            if (mouse == NULL) {
+                ERROR("Cannot create 'mouse'\n");
+                goto out;
+            }
+            OF_prop_string_new(OF_env, mouse, "device_type", "mouse");
+            OF_prop_int_new(OF_env, mouse, "reg", 3);
+            OF_prop_int_new(OF_env, mouse, "#buttons", 3);
+        }
+        {
+            OF_node_t *rtc;
+        
+        rtc = OF_node_new(OF_env, via, "rtc", OF_ADDRESS_NONE);
+        if (rtc == NULL) {
+            ERROR("Cannot create 'rtc'\n");
+            goto out;
+        }
+        OF_prop_string_new(OF_env, rtc, "device_type", "rtc");
+#if 0
+        OF_prop_string_new(OF_env, rtc, "compatible", "rtc,via-pmu");
+#else
+        OF_prop_string_new(OF_env, rtc, "compatible", "rtc");
+#endif
+        OF_node_put(OF_env, rtc);
+    }
+        //        OF_node_put(OF_env, via);
+    }
+    {
+        OF_node_t *pmgt;
+        pmgt = OF_node_new(OF_env, mio, "power-mgt", OF_ADDRESS_NONE);
+        OF_prop_string_new(OF_env, pmgt, "device_type", "power-mgt");
+        OF_prop_string_new(OF_env, pmgt, "compatible", "cuda");
+        OF_prop_string_new(OF_env, pmgt, "mgt-kind", "min-consumption-pwm-led");
+        OF_node_put(OF_env, pmgt);
+    }
+
+    if (arch == ARCH_HEATHROW) {
+        /* NVRAM */
+        OF_node_t *nvr;
+        OF_regprop_t regs;
+        nvr = OF_node_new(OF_env, mio, "nvram", 0x60000);
+        OF_prop_string_new(OF_env, nvr, "device_type", "nvram");
+        regs.address = 0x60000;
+        regs.size = 0x00020000;
+        OF_property_new(OF_env, nvr, "reg", &regs, sizeof(regs));
+        OF_prop_int_new(OF_env, nvr, "#bytes", 0x2000);
+        OF_node_put(OF_env, nvr);
+    }
+
+ out:
+    //    OF_node_put(OF_env, mio);
+    OF_node_put(OF_env, chs);
+    OF_node_put(OF_env, als);
+}
+
+void OF_finalize_pci_ide (void *dev, 
+                          uint32_t io_base0, uint32_t io_base1,
+                          uint32_t io_base2, uint32_t io_base3)
+{
+    OF_env_t *OF_env = OF_env_main;
+    OF_node_t *pci_ata = dev;
+    OF_node_t *ata, *atas[2];
+    int i;
+
+    OF_prop_int_new(OF_env, pci_ata, "#address-cells", 1);
+    OF_prop_int_new(OF_env, pci_ata, "#size-cells", 0);
+
+    /* XXX: Darwin handles only one device */
+    for(i = 0; i < 1; i++) {
+        ata = OF_node_new(OF_env, pci_ata, "ata-4", i);
+        if (ata == NULL) {
+            ERROR("Cannot create 'ata-4'\n");
+            return;
+        }
+        OF_prop_string_new(OF_env, ata, "device_type", "ata");
+        OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata");
+        OF_prop_string_new(OF_env, ata, "model", "ata-4");
+        OF_prop_int_new(OF_env, ata, "#address-cells", 1);
+        OF_prop_int_new(OF_env, ata, "#size-cells", 0);
+        OF_prop_int_new(OF_env, ata, "reg", i);
+        atas[i] = ata;
+    }
+    ide_pci_pc_register(io_base0, io_base1, io_base2, io_base3,
+                        atas[0], atas[1]);
+}
+
+/*****************************************************************************/
+/* Fake package */
+static void OF_method_fake (OF_env_t *OF_env)
+{
+    uint32_t ihandle;
+
+    ihandle = popd(OF_env);
+    OF_DPRINTF("ih: %0x %d\n", ihandle, stackd_depth(OF_env));
+    pushd(OF_env, ihandle);
+}
+
+static void OF_mmu_translate (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    uint32_t address, more;
+    uint32_t ihandle;
+
+    OF_CHECK_NBARGS(OF_env, 4);
+    /* As we get a 1:1 mapping, do nothing */
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    address = popd(OF_env);
+    more = popd(OF_env);
+    OF_DPRINTF("Translate address %0x %0x %0x\n", ihandle, address, more);
+    //    BAT_setup(3, more, address, 0x10000000, 1, 1, 2);
+    pushd(OF_env, address);
+    pushd(OF_env, 0x00000000);
+    pushd(OF_env, 0x00000000);
+    pushd(OF_env, 0);
+}
+
+static void OF_mmu_map (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    uint32_t address, virt, size;
+    uint32_t ihandle;
+
+    OF_CHECK_NBARGS(OF_env, 6);
+    /* As we get a 1:1 mapping, do nothing */
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    popd(OF_env);
+    size = popd(OF_env);
+    virt = popd(OF_env);
+    address = popd(OF_env);
+    OF_DPRINTF("Map %0x %0x %0x %0x\n", ihandle, address,
+               virt, size);
+    pushd(OF_env, 0);
+}
+
+/* Serial device package */
+static void OF_serial_write (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    OF_inst_t *inst;
+    OF_node_t *node;
+    uint32_t ihandle;
+    unsigned char *str;
+    int len;
+
+    OF_CHECK_NBARGS(OF_env, 4);
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    str = (void *)popd(OF_env);
+    len = popd(OF_env);
+    inst = OF_inst_find(OF_env, ihandle);
+    if (inst == NULL) {
+        pushd(OF_env, -1);
+        ERROR("Cannot get serial instance\n");
+        return;
+    }
+    node = inst->node;
+    //    OF_DPRINTF("args: %p str: %p\n", args, str);
+    /* XXX: should use directly the serial port
+     *      and have another console package.
+     */
+    console_write(str, len);
+    pushd(OF_env, 0);
+}
+
+static void OF_serial_read (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    char *dest;
+    uint32_t len;
+    uint32_t ihandle;
+    uint16_t phandle;
+    int ret, count;
+
+    OF_CHECK_NBARGS(OF_env, 4);
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    phandle = (ihandle >> 16) & 0xFFFF;
+    dest = (void *)popd(OF_env);
+    len = popd(OF_env);
+    ret = -1; /* Don't know why gcc thinks it might be uninitialized... */
+    for (count = 0; count < 1000; count++) {
+        ret = console_read(dest, len);
+        /* Stop if we read something or got an error */
+        if (ret != 0)
+            break;
+        /* Random sleep. Seems allright for serial port */
+        usleep(10000);
+    }
+    if (ret <= 0) {
+        pushd(OF_env, 0);
+    } else {
+        OF_DPRINTF("send '%s'\n", dest);
+        pushd(OF_env, ret);
+    }
+}
+
+typedef struct blockdev_inst_t {
+    int type;
+    union {
+        bloc_device_t *bd;
+        part_t *part;
+        inode_t *file;
+    } u;
+} blockdev_inst_t;
+
+static int OF_split_args (unsigned char *args, unsigned char **argv,
+                          int max_args)
+{
+    unsigned char *pos, *end;
+    int i;
+
+    pos = args;
+    end = pos;
+    for (i = 0; i < max_args && *pos != '\0' && end != NULL; i++) {
+        end = strchr(pos, ',');
+        if (end != NULL)
+            *end = '\0';
+        argv[i] = pos;
+        pos = end + 1;
+    }
+
+    return i;
+}
+
+static void OF_convert_path (unsigned char **path)
+{
+    unsigned char *pos;
+
+    OF_DPRINTF("%s: '%s'\n", __func__, *path);
+    for (pos = *path; *pos != '\0'; pos++) {
+        if (*pos == '\\')
+            *pos = '/';
+    }
+    OF_DPRINTF("%s: '%s'\n", __func__, *path);
+    pos = *path;
+#if 1
+    if (pos[0] == '/' && pos[1] == '/') {
+        pos += 2;
+        *path = pos;
+    }
+#else
+    for (; *pos == '/'; pos++)
+        continue;
+    *path = pos;
+#endif
+    OF_DPRINTF("%s: '%s'\n", __func__, *path);
+}
+
+/* Block devices package */
+static void OF_blockdev_open (OF_env_t *OF_env)
+{
+    unsigned char tmp[OF_NAMELEN_MAX];
+    unsigned char *args, *argv[4];
+    OF_inst_t *dsk_inst;
+    OF_node_t *dsk;
+    bloc_device_t *bd;
+    blockdev_inst_t *bdinst;
+    uint32_t ihandle;
+    uint16_t phandle;
+    int nargs, partnum;
+
+    OF_CHECK_NBARGS(OF_env, 2);
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    phandle = (ihandle >> 16) & 0xFFFF;
+    dsk_inst = OF_inst_find(OF_env, ihandle);
+    if (dsk_inst == NULL) {
+        ERROR("Disk not found (ih: %0x)\n", ihandle);
+        pushd(OF_env, -1);
+        return;
+    }
+    dsk = dsk_inst->node;
+    bd = dsk->private_data;
+    bdinst = malloc(sizeof(blockdev_inst_t));
+    if (bdinst == NULL) {
+        ihandle = -1;
+        ERROR("Cannot alloc blockdev instance\n");
+        goto out;
+    }
+    memset(bdinst, 0, sizeof(blockdev_inst_t));
+    OF_DPRINTF("called with args '%s'\n", args);
+    nargs = OF_split_args(args, argv, 4);
+    partnum = -1;
+    if (nargs > 0) {
+        partnum = strtol(argv[0], NULL, 10);
+        if (partnum > 0) {
+            OF_DPRINTF("Open partition... %d %d\n", partnum, nargs);
+            bdinst->type = 1;
+            bdinst->u.part = part_get(bd, partnum);
+            if (bdinst->u.part == NULL) {
+                OF_DPRINTF("Partition %d not found\n", partnum);
+                free(bdinst);
+                pushd(OF_env, -1);
+                return;
+            }
+            if (nargs > 1) {
+                /* TODO: open file */
+                bdinst->type = 2;
+                OF_DPRINTF("Open file... %d %d '%s'\n",
+                           partnum, nargs, argv[1]);
+                OF_convert_path(&argv[1]);
+                if (*argv[1] != '/') {
+                    sprintf(tmp, "%s/%s",
+                            fs_get_boot_dirname(part_fs(bdinst->u.part)),
+                            argv[1]);
+                    bdinst->u.file = fs_open(part_fs(bdinst->u.part), tmp);
+                } else {
+                    bdinst->u.file = fs_open(part_fs(bdinst->u.part), argv[1]);
+                }
+                if (bdinst->u.file == NULL) {
+#if 0
+                    bug();
+#endif
+                    pushd(OF_env, 0x00000000);
+                    ERROR("File not found '%s'\n", argv[1]);
+                    return;
+                }
+            }
+        }
+    }
+    if (nargs == 0 || partnum == 0) {
+        OF_DPRINTF("Open disk... %d %d\n", nargs, partnum);
+        bdinst->type = 0;
+        bdinst->u.bd = bd;
+    }
+    /* TODO: find partition &/| file */
+    dsk_inst->data = bdinst;
+    OF_node_put(OF_env, dsk);
+ out:
+    pushd(OF_env, ihandle);
+}
+
+static void OF_blockdev_seek (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    OF_inst_t *dsk_inst;
+    blockdev_inst_t *bdinst;
+    uint32_t posh, posl, bloc, pos, blocsize, tmp;
+    uint32_t ihandle;
+    uint16_t phandle;
+    int sh;
+
+    OF_CHECK_NBARGS(OF_env, 4);
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    phandle = (ihandle >> 16) & 0xFFFF;
+    posh = popd(OF_env);
+    posl = popd(OF_env);
+    dsk_inst = OF_inst_find(OF_env, ihandle);
+    if (dsk_inst == NULL) {
+        ERROR("Disk not found (ih: %0x)\n", ihandle);
+        pushd(OF_env, -1);
+        return;
+    }
+    bdinst = dsk_inst->data;
+    switch (bdinst->type) {
+    case 0:
+        blocsize = bd_seclen(bdinst->u.bd);
+        for (tmp = blocsize, sh = 0; tmp != 1; tmp = tmp / 2)
+            sh++;
+        bloc = ((posh  << (32 - sh)) | (posl / blocsize));
+        pos = posl % blocsize;
+        OF_DPRINTF("disk: bsize %08x %08x %08x => %08x %08x\n", blocsize,
+               posh, posl, bloc, pos);
+        pushd(OF_env, bd_seek(bdinst->u.bd, bloc, pos));
+        break;
+    case 1:
+        blocsize = part_blocsize(bdinst->u.part);
+        for (tmp = blocsize, sh = 0; tmp != 1; tmp = tmp / 2)
+            sh++;
+        bloc = ((posh  << (32 - sh)) | (posl / blocsize));
+        pos = posl % blocsize;
+        OF_DPRINTF("part: bsize %08x %08x %08x => %08x %08x\n", blocsize,
+               posh, posl, bloc, pos);
+        pushd(OF_env, part_seek(bdinst->u.part, bloc, pos));
+        break;
+    case 2:
+        blocsize = part_blocsize(fs_inode_get_part(bdinst->u.file));
+        for (tmp = blocsize, sh = 0; tmp != 1; tmp = tmp / 2)
+            sh++;
+        bloc = ((posh  << (32 - sh)) | (posl / blocsize));
+        pos = posl % blocsize;
+        OF_DPRINTF("file: bsize %08x %08x %08x => %08x %08x\n", blocsize,
+                   posh, posl, bloc, pos);
+        pushd(OF_env, fs_seek(bdinst->u.file, bloc, pos));
+        break;
+    }
+}
+
+static void OF_blockdev_read (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    OF_inst_t *dsk_inst;
+    blockdev_inst_t *bdinst;
+    void *dest;
+    uint32_t len;
+    uint32_t ihandle;
+    uint16_t phandle;
+
+    OF_CHECK_NBARGS(OF_env, 4);
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    phandle = (ihandle >> 16) & 0xFFFF;
+    dest = (void *)popd(OF_env);
+    len = popd(OF_env);
+    dsk_inst = OF_inst_find(OF_env, ihandle);
+    if (dsk_inst == NULL) {
+        ERROR("Disk not found (ih: %0x)\n", ihandle);
+        pushd(OF_env, -1);
+        return;
+    }
+    bdinst = dsk_inst->data;
+    set_check(0);
+    OF_DPRINTF("dest: %p len: %d %d\n", dest, len, bdinst->type);
+    switch (bdinst->type) {
+    case 0:
+        OF_DPRINTF("read disk\n");
+        pushd(OF_env, bd_read(bdinst->u.bd, dest, len));
+        break;
+    case 1:
+        OF_DPRINTF("read partition\n");
+        pushd(OF_env, part_read(bdinst->u.part, dest, len));
+        break;
+    case 2:
+        OF_DPRINTF("read file\n");
+        pushd(OF_env, fs_read(bdinst->u.file, dest, len));
+        break;
+    }
+    OF_DPRINTF("%08x %08x %08x %08x\n",
+               ((uint32_t *)dest)[0], ((uint32_t *)dest)[1],
+               ((uint32_t *)dest)[2], ((uint32_t *)dest)[3]);
+    OF_DPRINTF("%08x %08x %08x %08x\n",
+               ((uint32_t *)dest)[4], ((uint32_t *)dest)[5],
+               ((uint32_t *)dest)[6], ((uint32_t *)dest)[7]);
+        
+    set_check(1);
+}
+
+static void OF_blockdev_get_blocsize (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    OF_inst_t *dsk_inst;
+    blockdev_inst_t *bdinst;
+    uint32_t ihandle;
+    uint16_t phandle;
+    uint32_t blocsize;
+
+    OF_CHECK_NBARGS(OF_env, 2);
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    phandle = (ihandle >> 16) & 0xFFFF;
+    dsk_inst = OF_inst_find(OF_env, ihandle);
+    if (dsk_inst == NULL) {
+        ERROR("Disk not found (ih: %0x)\n", ihandle);
+        pushd(OF_env, -1);
+        return;
+    }
+    bdinst = dsk_inst->data;
+#if 0
+    switch (bdinst->type) {
+    case 0:
+        blocsize = bd_seclen(bdinst->u.bd);
+        break;
+    case 1:
+        blocsize = part_blocsize(bdinst->u.part);
+        break;
+    case 2:
+        blocsize = 512;
+        break;
+    }
+#else
+    blocsize = 512;
+#endif
+    pushd(OF_env, blocsize);
+    pushd(OF_env, 0);
+}
+
+static void OF_blockdev_dma_alloc (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    void *address;
+    uint32_t ihandle;
+    uint32_t size;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    size = popd(OF_env);
+    OF_DPRINTF("size: %08x\n", size);
+    mem_align(size);
+    address = malloc(size);
+    if (address != NULL)
+        memset(address, 0, size);
+    pushd(OF_env, (uint32_t)address);
+    pushd(OF_env, 0);
+}
+
+static void OF_blockdev_dma_free (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    void *address;
+    uint32_t ihandle;
+    uint32_t size;
+
+    OF_CHECK_NBARGS(OF_env, 4);
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    size = popd(OF_env);
+    address = (void *)popd(OF_env);
+    OF_DPRINTF("address: %p size: %08x\n", address, size);
+    free(address);
+    pushd(OF_env, 0);
+}
+
+void *OF_blockdev_register (void *parent, void *private,
+                            const unsigned char *type,
+                            const unsigned char *name, int devnum,
+                            const char *alias)
+{
+    unsigned char tmp[OF_NAMELEN_MAX], path[OF_NAMELEN_MAX], *pos;
+    OF_env_t *OF_env;
+    OF_node_t *dsk, *als;
+    int i;
+    
+    OF_env = OF_env_main;
+    dsk = OF_node_new(OF_env, parent, name, devnum);
+    if (dsk == NULL) {
+        ERROR("Cannot create blockdev '%s'\n", name);
+        return NULL;
+    }
+    OF_prop_string_new(OF_env, dsk, "device_type", "block");
+    OF_prop_string_new(OF_env, dsk, "category", type);
+    OF_prop_int_new(OF_env, dsk, "device_id", devnum);
+    OF_prop_int_new(OF_env, dsk, "reg", devnum);
+    OF_method_new(OF_env, dsk, "open", &OF_blockdev_open);
+    OF_method_new(OF_env, dsk, "seek", &OF_blockdev_seek);
+    OF_method_new(OF_env, dsk, "read", &OF_blockdev_read);
+    OF_method_new(OF_env, dsk, "block-size",
+                  &OF_blockdev_get_blocsize);
+    OF_method_new(OF_env, dsk, "dma-alloc", &OF_blockdev_dma_alloc);
+    OF_method_new(OF_env, dsk, "dma-free", &OF_blockdev_dma_free);
+    if (strcmp(type, "cdrom") == 0)
+        OF_method_new(OF_env, dsk, "eject", &OF_method_fake);
+    OF_method_new(OF_env, dsk, "close", &OF_method_fake);
+    dsk->private_data = private;
+    /* Set up aliases */
+    OF_pack_get_path(OF_env, path, OF_NAMELEN_MAX, dsk);
+    if (alias != NULL) {
+        als = OF_node_get(OF_env, "aliases");
+        if (als == NULL) {
+            ERROR("Cannot get 'aliases'\n");
+            return NULL;
+        }
+        strcpy(tmp, alias);
+        if (OF_property_copy(OF_env, NULL, 0, als, tmp) >= 0) {
+            pos = tmp + strlen(alias);
+            for (i = 0; ; i++) {
+                sprintf(pos, "%d", i);
+                if (OF_property_copy(OF_env, NULL, 0, als, tmp) < 0)
+                    break;
+            }
+        }
+        OF_DPRINTF("Set alias to %s\n", tmp);
+        OF_prop_string_new(OF_env, dsk, "alias", tmp);
+        OF_prop_string_new(OF_env, als, tmp, path);
+        OF_node_put(OF_env, als);
+    }
+    
+    return dsk;
+}
+
+void OF_blockdev_set_boot_device (void *disk, int partnum,
+                                  const unsigned char *file)
+{
+    unsigned char tmp[OF_NAMELEN_MAX], *pos;
+    OF_env_t *OF_env;
+    OF_node_t *dsk = disk, *opts, *chs;
+    
+    OF_env = OF_env_main;
+    
+    if (OF_property_copy(OF_env, tmp, OF_NAMELEN_MAX, dsk, "alias") < 0)
+        OF_pack_get_path(OF_env, tmp, OF_NAMELEN_MAX, dsk);
+    sprintf(tmp + strlen(tmp), ":%d", partnum);
+    /* OpenDarwin 6.02 seems to need this one */
+    opts = OF_node_get(OF_env, "options");
+    if (opts == NULL) {
+        ERROR("Cannot get 'options'\n");
+        return;
+    }
+    OF_prop_string_set(OF_env, OF_node_root, "boot-device", tmp);
+    OF_prop_string_set(OF_env, opts, "boot-device", tmp);
+    OF_DPRINTF("Set boot device to: '%s'\n", tmp);
+    OF_node_put(OF_env, opts);
+    /* Set the real boot path */
+    pos = tmp + strlen(tmp);
+    sprintf(pos, ",%s", file);
+    /* Convert all '/' into '\' in the boot file name */
+    for (; *pos != '\0'; pos++) {
+        if (*pos == '/')
+            *pos = '\\';
+    }
+    chs = OF_node_get(OF_env, "chosen");
+    if (chs == NULL) {
+        ERROR("Cannot get 'chosen'\n");
+        return;
+    }
+    OF_prop_string_set(OF_env, chs, "bootpath", tmp);
+    OF_DPRINTF("Set boot path to: '%s'\n", tmp);
+    OF_node_put(OF_env, chs);
+}
+
+/* Display package */
+static void OF_vga_draw_rectangle (OF_env_t *OF_env)
+{
+    const void *buf;
+    const unsigned char *args;
+    uint32_t posx, posy, width, height;
+    uint32_t ihandle;
+
+    OF_CHECK_NBARGS(OF_env, 7);
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    height = popd(OF_env);
+    width = popd(OF_env);
+    posy = popd(OF_env);
+    posx = popd(OF_env);
+    buf = (const void *)popd(OF_env);
+    OF_DPRINTF("x=%d y=%d h=%d ", posx, posy, width);
+    OF_DPRINTF("w=%d buf=%p\n", height, buf);
+    set_check(0);
+    vga_draw_buf(buf, width * vga_fb_bpp, posx, posy, width, height);
+    set_check(1);
+    pushd(OF_env, 0);
+}
+
+static void OF_vga_fill_rectangle (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    uint32_t color, posx, posy, width, height;
+    uint32_t ihandle;
+
+    OF_CHECK_NBARGS(OF_env, 7);
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    height = popd(OF_env);
+    width = popd(OF_env);
+    posy = popd(OF_env);
+    posx = popd(OF_env);
+    color = popd(OF_env);
+    OF_DPRINTF("x=%d y=%d\n", posx, posy);
+    OF_DPRINTF("h=%d w=%d c=%0x\n", width, height, color);
+    vga_fill_rect(posx, posy, width, height, color);
+    pushd(OF_env, 0);
+}
+
+static void OF_vga_set_width (OF_env_t *OF_env, OF_prop_t *prop,
+                              const void *data, int len)
+{
+    uint32_t width, height, depth;
+
+    if (len == sizeof(uint32_t)) {
+        width = *(uint32_t *)data;
+        OF_property_copy(OF_env, &height, 4, prop->node, "height");
+        OF_property_copy(OF_env, &depth, 4, prop->node, "depth");
+        vga_set_mode(width, height, depth);
+    }
+}
+
+static void OF_vga_set_height (OF_env_t *OF_env, OF_prop_t *prop,
+                               const void *data, int len)
+{
+    uint32_t width, height, depth;
+
+    if (len == sizeof(uint32_t)) {
+        OF_property_copy(OF_env, &width, 4, prop->node, "width");
+        height = *(uint32_t *)data;
+        OF_property_copy(OF_env, &depth, 4, prop->node, "depth");
+        vga_set_mode(width, height, depth);
+    }
+}
+
+static void OF_vga_set_depth (OF_env_t *OF_env, OF_prop_t *prop,
+                              const void *data, int len)
+{
+    uint32_t width, height, depth;
+
+    if (len == sizeof(uint32_t)) {
+        OF_property_copy(OF_env, &width, 4, prop->node, "width");
+        OF_property_copy(OF_env, &height, 4, prop->node, "height");
+        depth = *(uint32_t *)data;
+        vga_set_mode(width, height, depth);
+    }
+}
+
+void OF_vga_register (const unsigned char *name, unused uint32_t address,
+                      int width, int height, int depth,
+                      unsigned long vga_bios_addr, unsigned long vga_bios_size)
+{
+    OF_env_t *OF_env;
+    unsigned char tmp[OF_NAMELEN_MAX];
+    OF_node_t *disp, *chs, *als;
+    OF_prop_t *prop;
+    
+    OF_DPRINTF("Set frame buffer %08x %dx%dx%d\n",
+               address, width, height, depth);
+    OF_env = OF_env_main;
+    disp = OF_node_get(OF_env, name);
+    if (disp == NULL) {
+        ERROR("Cannot get display '%s'\n", name);
+        return;
+    }
+    prop = OF_prop_int_new(OF_env, disp, "width", width);
+    if (prop == NULL) {
+        OF_node_put(OF_env, disp);
+        ERROR("Cannot create display width property\n");
+        return;
+    }
+    OF_property_set_cb(OF_env, prop, &OF_vga_set_width);
+    prop = OF_prop_int_new(OF_env, disp, "height", height);
+    if (prop == NULL) {
+        OF_node_put(OF_env, disp);
+        ERROR("Cannot create display height property\n");
+        return;
+    }
+    OF_property_set_cb(OF_env, prop, &OF_vga_set_height);
+    switch (depth) {
+    case 8:
+        break;
+    case 15:
+        depth = 16;
+        break;
+    case 32:
+        break;
+    default:
+        /* OF spec this is mandatory, but we have no support for it */
+        printf("%d bits VGA isn't implemented\n", depth);
+        bug();
+        /* Never come here */
+        break;
+    }
+    prop = OF_prop_int_new(OF_env, disp, "depth", depth);
+    if (prop == NULL) {
+        ERROR("Cannot create display depth\n");
+        goto out;
+    }
+    OF_property_set_cb(OF_env, prop, &OF_vga_set_depth);
+    OF_prop_int_new(OF_env, disp, "linebytes", vga_fb_linesize);
+    OF_method_new(OF_env, disp, "draw-rectangle", &OF_vga_draw_rectangle);
+    OF_method_new(OF_env, disp, "fill-rectangle", &OF_vga_fill_rectangle);
+    OF_method_new(OF_env, disp, "color!", &OF_method_fake);
+    chs = OF_node_get(OF_env, "chosen");
+    if (chs == NULL) {
+        ERROR("Cannot get 'chosen'\n");
+        goto out;
+    }
+    OF_prop_int_new(OF_env, chs, "display", OF_pack_handle(OF_env, disp));
+    OF_node_put(OF_env, chs);
+    OF_pack_get_path(OF_env, tmp, 512, disp);
+    printf("Set display '%s' path to '%s'\n", name, tmp);
+    als = OF_node_get(OF_env, "aliases");
+    if (als == NULL) {
+        ERROR("Cannot get 'aliases'\n");
+        goto out;
+    }
+    OF_prop_string_new(OF_env, als, "screen", tmp);
+    OF_prop_string_new(OF_env, als, "display", tmp);
+    OF_node_put(OF_env, als);
+    /* XXX: may also need read-rectangle */
+
+    if (vga_bios_size >= 8) {
+        const uint8_t *p;
+        int size;
+        /* check the QEMU VGA BIOS header */
+        p = (const uint8_t *)vga_bios_addr;
+        if (p[0] == 'N' && p[1] == 'D' && p[2] == 'R' && p[3] == 'V') {
+            size = *(uint32_t *)(p + 4);
+            OF_property_new(OF_env, disp, "driver,AAPL,MacOS,PowerPC", 
+                            p + 8, size);
+        }
+    }
+ out:
+    OF_node_put(OF_env, disp);
+}
+
+/* Pseudo packages to make BootX happy */
+/* sl_words package */
+static void slw_set_output_level (OF_env_t *OF_env)
+{
+    OF_node_t *slw;
+    const unsigned char *args;
+    int level;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    popd(OF_env);
+    args = (void *)popd(OF_env);
+    level = popd(OF_env);
+    slw = OF_node_get(OF_env, "sl_words");
+    if (slw == NULL) {
+        pushd(OF_env, -1);
+    } else {
+        OF_DPRINTF("Set output level to: %d\n", level);
+        OF_prop_int_set(OF_env, slw, "outputLevel", level);
+        OF_node_put(OF_env, slw);
+        pushd(OF_env, 0);
+    }
+}
+
+#ifdef DEBUG_BIOS
+#define EMIT_BUFFER_LEN 256
+static unsigned char emit_buffer[EMIT_BUFFER_LEN];
+static int emit_pos = 0;
+#endif
+
+static void slw_emit (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    int c;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    popd(OF_env);
+    args = (void *)popd(OF_env);
+    c = popd(OF_env);
+    //    OF_DPRINTF("Emit char %d\n", c);
+#ifdef DEBUG_BIOS
+    if (emit_pos < EMIT_BUFFER_LEN - 1) {
+        emit_buffer[emit_pos++] = c;
+        //        outb(0xFF00, c);
+        outb(0x0F00, c);
+    } else {
+        emit_buffer[emit_pos] = '\0';
+    }
+#else
+    outb(0x0F00, c);
+#endif
+    pushd(OF_env, 0);
+}
+
+static void slw_cr (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+
+    OF_CHECK_NBARGS(OF_env, 2);
+    popd(OF_env);
+    args = (void *)popd(OF_env);
+    //    OF_DPRINTF("Emit CR char\n");
+    //    outb(0xFF01, '\n');
+    outb(0x0F01, '\n');
+#ifdef DEBUG_BIOS
+    emit_buffer[emit_pos] = '\0';
+    if (strcmp(emit_buffer, "Call Kernel!") == 0) {
+        /* Set qemu in debug mode:
+         * log in_asm,op,int,ioport,cpu
+         */
+        uint16_t loglevel = 0x02 | 0x10 | 0x80;
+        //        outw(0xFF02, loglevel);
+        outb(0x0F02, loglevel);
+    }
+    emit_pos = 0;
+#endif
+    pushd(OF_env, 0);
+}
+
+static void slw_init_keymap (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    OF_node_t *node;
+    OF_prop_t *prop;
+    uint32_t phandle, ihandle;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    ihandle = popd(OF_env);
+    args = (void *)popd(OF_env);
+    phandle = ihandle >> 16;
+    ihandle &= 0xFFFF;
+    OF_DPRINTF("\n");
+    node = OF_pack_find(OF_env, phandle);
+    if (node == NULL) {
+        ERROR("Cant' init slw keymap\n");
+        pushd(OF_env, -1);
+    } else {
+        prop = OF_property_get(OF_env, node, "keyMap");
+        if (prop == NULL) {
+            pushd(OF_env, -1);
+        } else {
+            pushd(OF_env, (uint32_t)prop->value);
+            pushd(OF_env, 0);
+        }
+    }
+}
+
+static void slw_update_keymap (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+
+    OF_CHECK_NBARGS(OF_env, 2);
+    popd(OF_env);
+    args = (void *)popd(OF_env);
+    OF_DPRINTF("\n");
+    pushd(OF_env, 0);
+}
+
+static void slw_spin (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    /* XXX: cur_spin should be in sl_words package */
+    static int cur_spin = 0;
+    int c;
+
+    OF_CHECK_NBARGS(OF_env, 2);
+    popd(OF_env);
+    args = (void *)popd(OF_env);
+    if (cur_spin > 15) {
+        c = RGB(0x30, 0x30, 0x50);
+    } else {
+        c = RGB(0x11, 0x11, 0x11);
+    }
+    c = vga_get_color(c);
+    vga_fill_rect((cur_spin % 15) * 5 + 280, 420, 4, 3, c);
+    cur_spin = (cur_spin + 1) & 31;
+    OF_DPRINTF("\n");
+    pushd(OF_env, -1);
+}
+
+static void slw_spin_init (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+
+    OF_CHECK_NBARGS(OF_env, 8);
+    popd(OF_env);
+    args = (void *)popd(OF_env);
+    popd(OF_env);
+    popd(OF_env);
+    popd(OF_env);
+    popd(OF_env);
+    popd(OF_env);
+    popd(OF_env);
+    pushd(OF_env, -1);
+}
+
+static void slw_pwd (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    popd(OF_env);
+    args = (void *)popd(OF_env);
+    OF_DPRINTF("\n");
+    pushd(OF_env, -1);
+}
+
+static void slw_sum (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    popd(OF_env);
+    args = (void *)popd(OF_env);
+    OF_DPRINTF("\n");
+    pushd(OF_env, -1);
+}
+
+/*****************************************************************************/
+/*                       Client program interface                            */
+/* Client interface services */
+static void OF_test (OF_env_t *OF_env);
+
+/* Device tree services */
+/* Get next package */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_peer (OF_env_t *OF_env)
+{
+    OF_node_t *node;
+    uint32_t phandle;
+
+    OF_CHECK_NBARGS(OF_env, 1);
+    phandle = popd(OF_env);
+    OF_DPRINTF("phandle 0x%0x\n", phandle);
+    if (phandle == 0)
+        node = OF_node_root;
+    else
+        node = OF_pack_next(OF_env, phandle);
+    if (node == NULL)
+        pushd(OF_env, 0);
+    else
+        pushd(OF_env, OF_pack_handle(OF_env, node));
+}
+
+/* Get first child package */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_child (OF_env_t *OF_env)
+{
+    OF_node_t *node;
+    uint32_t phandle;
+
+    OF_CHECK_NBARGS(OF_env, 1);
+    phandle = popd(OF_env);
+    OF_DPRINTF("phandle 0x%0x\n", phandle);
+    node = OF_pack_child(OF_env, phandle);
+    if (node == NULL)
+        pushd(OF_env, 0);
+    else
+        pushd(OF_env, OF_pack_handle(OF_env, node));
+}
+
+/* Get parent package */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_parent (OF_env_t *OF_env)
+{
+    OF_node_t *node;
+    uint32_t phandle;
+
+    OF_CHECK_NBARGS(OF_env, 1);
+    phandle = popd(OF_env);
+    OF_DPRINTF("phandle 0x%0x\n", phandle);
+    node = OF_pack_parent(OF_env, phandle);
+    if (node == NULL)
+        pushd(OF_env, 0);
+    else
+        pushd(OF_env, OF_pack_handle(OF_env, node));
+}
+
+/* Get package related to an instance */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_instance_to_package (OF_env_t *OF_env)
+{
+    uint32_t ihandle;
+
+    OF_CHECK_NBARGS(OF_env, 1);
+    ihandle = popd(OF_env);
+    OF_DPRINTF("ihandle 0x%0x\n", ihandle);
+    pushd(OF_env, (ihandle >> 16) & 0xFFFF);
+}
+
+/* Get property len */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_getproplen (OF_env_t *OF_env)
+{
+    unsigned char name[OF_NAMELEN_MAX], *namep;
+    OF_node_t *node;
+    uint32_t phandle;
+
+    OF_CHECK_NBARGS(OF_env, 2);
+    phandle = popd(OF_env);
+    namep = (unsigned char *)popd(OF_env);
+    OF_lds(name, namep);
+    OF_DPRINTF("phandle 0x%0x prop [%s]\n", phandle, name);
+    node = OF_pack_find(OF_env, phandle);
+    if (node == NULL)
+        pushd(OF_env, -1);
+    else
+        pushd(OF_env, OF_property_len(OF_env, node, name));
+}
+
+/* Get property */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_getprop (OF_env_t *OF_env)
+{
+    unsigned char name[OF_NAMELEN_MAX], *namep;
+    OF_node_t *node;
+    void *buffer;
+    uint32_t phandle;
+    int len, nb_args;
+
+    //    OF_CHECK_NBARGS(OF_env, 4);
+    nb_args = stackd_depth(OF_env);
+    phandle = popd(OF_env);
+    namep = (unsigned char *)popd(OF_env);
+    OF_lds(name, namep);
+    buffer = (void *)popd(OF_env);
+    if (nb_args == 3) {
+        /* This hack is needed to boot MacOS X panther (10.3) */
+        len = 1024;
+    } else {
+        len = popd(OF_env);
+    }
+    OF_DPRINTF("phandle 0x%0x prop [%s]\n", phandle, name);
+    OF_DPRINTF("buffer %p len %d\n", buffer, len);
+    node = OF_pack_find(OF_env, phandle);
+    if (node == NULL) {
+        len = -1;
+    } else {
+        len = OF_property_copy(OF_env, buffer, len, node, name);
+        if (len != -1) {
+            OF_DPRINTF("Copied %d bytes\n", len);
+        }
+    }
+    pushd(OF_env, len);
+}
+
+/* Check existence of next property */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_nextprop (OF_env_t *OF_env)
+{
+    unsigned char name[OF_NAMELEN_MAX], *namep;
+    OF_node_t *node;
+    OF_prop_t *next;
+    unsigned char *next_name;
+    uint32_t phandle;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    phandle = popd(OF_env);
+    namep = (unsigned char *)popd(OF_env);
+    OF_lds(name, namep);
+    OF_DPRINTF("phandle 0x%0x prop [%s]\n", phandle, name);
+    next_name = (unsigned char *)popd(OF_env);
+    node = OF_pack_find(OF_env, phandle);
+    if (node == NULL) {
+        pushd(OF_env, -1);
+    } else {
+        next = OF_property_next(OF_env, node, name);
+        if (next == NULL || next->name == NULL) {
+            OF_DPRINTF("No next property found [%s]\n", name);
+            pushd(OF_env, 0);
+        } else {
+            OF_DPRINTF("Return property name [%s]\n", next->name);
+            OF_sts(next_name, (void *)(next->name));
+            OF_DUMP_STRING(OF_env, next_name);
+            pushd(OF_env, strlen(next->name) + 1);
+        }
+    }
+}
+
+/* Set a property */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_setprop (OF_env_t *OF_env)
+{
+    unsigned char name[OF_NAMELEN_MAX], *namep;
+    unsigned char *value, *buffer;
+    OF_node_t *node;
+    OF_prop_t *prop;
+    uint32_t phandle;
+    int len;
+    int i;
+
+    OF_CHECK_NBARGS(OF_env, 4);
+    phandle = popd(OF_env);
+    namep = (unsigned char *)popd(OF_env);
+    OF_lds(name, namep);
+    OF_DPRINTF("phandle 0x%0x prop [%s]\n", phandle, name);
+    buffer = (unsigned char *)popd(OF_env);
+    len = popd(OF_env);
+    node = OF_pack_find(OF_env, phandle);
+    if (node == NULL) {
+        pushd(OF_env, -1);
+        ERROR("Cannot get pack %04x\n", phandle);
+        return;
+    }
+    value = malloc(len);
+    if (value == NULL && len != 0) {
+        pushd(OF_env, -1);
+        ERROR("%s: Cannot alloc property '%s' (%d)\n", __func__, name, len);
+        return;
+    }
+    for (i = 0; i < len; i++)
+        value[i] = buffer[i];
+    prop = OF_property_set(OF_env, node, name, value, len);
+    if (prop == NULL)
+        len = -1;
+   pushd(OF_env, len);
+}
+
+/* "canon" */
+
+/* Find a device given its path */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_get_alias (OF_env_t *OF_env, const unsigned char *name)
+{
+    unsigned char tmp[OF_NAMELEN_MAX], *pos, *st;
+    const unsigned char *alias, *npos;
+    OF_node_t *als, *node;
+    OF_prop_t *prop;
+
+    node = NULL;
+    strcpy(tmp, name);
+    for (st = tmp; *st == '/'; st++)
+        continue;
+    pos = strchr(st, '/');
+    if (pos == NULL) {
+        pos = strchr(st, ':');
+    }
+    if (pos != NULL) {
+        *pos = '\0';
+        npos = name + (pos - tmp);
+    } else {
+        npos = "";
+    }
+    OF_DPRINTF("Look for alias for '%s' => '%s' '%s'\n", name, tmp, npos);
+    als = OF_pack_find_by_name(OF_env, OF_node_root, "/aliases");
+    if (als == NULL) {
+        ERROR("Cannot get 'aliases'\n");
+        return NULL;
+    }
+    prop = OF_property_get(OF_env, als, tmp);
+    if (prop == NULL) {
+        OF_DPRINTF("No %s alias !\n", tmp);
+        goto out;
+    }
+    alias = prop->value;
+    OF_DPRINTF("Found alias '%s' '%s'\n", alias, npos);
+    sprintf(tmp, "%s%s", alias, npos);
+    node = OF_pack_find_by_name(OF_env, OF_node_root, tmp);
+    if (node == NULL) {
+        printf("%s alias is a broken link !\n", name);
+        goto out;
+    }
+    OF_node_put(OF_env, node);
+ out:
+    OF_node_put(OF_env, als);
+
+    return node;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_finddevice (OF_env_t *OF_env)
+{
+    unsigned char name[OF_NAMELEN_MAX], *namep;
+    OF_node_t *node;
+    int ret;
+
+    OF_CHECK_NBARGS(OF_env, 1);
+    namep = (unsigned char *)popd(OF_env);
+    OF_lds(name, namep);
+    OF_DPRINTF("name %p [%s]\n", namep, name);
+    /* Search first in "/aliases" */
+    node = OF_get_alias(OF_env, name);
+    if (node == NULL) {
+        node = OF_pack_find_by_name(OF_env, OF_node_root, name);
+    }
+    if (node == NULL)
+        ret = -1;
+    else
+        ret = OF_pack_handle(OF_env, node);
+    OF_DPRINTF("ret 0x%0x\n", ret);
+    pushd(OF_env, ret);
+}
+
+/* "instance-to-path */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_instance_to_path (OF_env_t *OF_env)
+{
+    void *buffer;
+    OF_inst_t *inst;
+    uint32_t ihandle;
+    int len;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    OF_DPRINTF("\n");
+    ihandle = popd(OF_env);
+    buffer = (void *)popd(OF_env);
+    len = popd(OF_env);
+    OF_DPRINTF("ihandle: 0x%0x len=%d\n", ihandle, len);
+    inst = OF_inst_find(OF_env, ihandle);
+    if (inst == NULL)
+        len = -1;
+    else
+        len = OF_inst_get_path(OF_env, buffer, len, inst) + 1;
+    OF_DUMP_STRING(OF_env, buffer);
+    pushd(OF_env, len);
+}
+
+/* "package-to-path" */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_package_to_path (OF_env_t *OF_env)
+{
+    void *buffer;
+    OF_node_t *node;
+    uint32_t phandle;
+    int len;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    OF_DPRINTF("\n");
+    phandle = popd(OF_env);
+    buffer = (void *)popd(OF_env);
+    len = popd(OF_env);
+    node = OF_pack_find(OF_env, phandle);
+    if (node == NULL)
+        len = -1;
+    else
+        len = OF_pack_get_path(OF_env, buffer, len, node) + 1;
+    OF_DUMP_STRING(OF_env, buffer);
+    pushd(OF_env, len);
+}
+
+/* Call a package's method */
+__attribute__ (( section (".OpenFirmware") ))
+static void _OF_callmethod (OF_env_t *OF_env, const unsigned char *name,
+                            uint32_t ihandle, const unsigned char *argp)
+{
+    OF_node_t *node;
+    OF_inst_t *inst;
+    OF_method_t *method;
+    OF_cb_t cb;
+
+    inst = OF_inst_find(OF_env, ihandle);
+    OF_DPRINTF("Attempt to call method [%s] of package instance 0x%0x\n",
+               name, ihandle);
+    if (inst == NULL) {
+        OF_DPRINTF("No instance %0x\n", ihandle);
+        pushd(OF_env, -1);
+        return;
+    }
+    node = inst->node;
+    method = OF_method_get(OF_env, node, name);
+    if (method != NULL) {
+        cb = method->func;
+    } else {
+        if (strcmp(name, "open") == 0) {
+            cb = &OF_method_fake;
+        } else {
+            printf("Method '%s' not found in '%s'\n",
+                   name, node->prop_name->value);
+            pushd(OF_env, -1);
+            bug();
+            return;
+        }
+    }
+#if 0
+    OF_DPRINTF("Push instance method %p (%p)...\n", &method->func,
+               &slw_emit);
+#endif
+    pushf(OF_env, &cb);
+    if (argp != NULL)
+        pushd(OF_env, (uint32_t)argp);
+    else
+        pushd(OF_env, 0x00000000);
+    pushd(OF_env, ihandle);
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static unsigned char *OF_get_args (unused OF_env_t *env, unsigned char *name)
+{
+    unsigned char *sd;
+
+    sd = strchr(name, ':');
+    if (sd == NULL)
+        return NULL;
+    *sd = '\0';
+
+    return sd + 1;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_callmethod (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    unsigned char name[OF_NAMELEN_MAX], *namep;
+    uint32_t ihandle;
+
+    OF_DPRINTF("\n\n\n#### CALL METHOD ####\n\n");
+    namep = (unsigned char *)popd(OF_env);
+    OF_lds(name, namep);
+    args = OF_get_args(OF_env, name);
+    ihandle = popd(OF_env);
+    _OF_callmethod(OF_env, name, ihandle, args);
+}
+
+/* Device IO services */
+/* Create a new instance of a device's package */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_open (OF_env_t *OF_env)
+{
+    const unsigned char *args;
+    unsigned char name[OF_NAMELEN_MAX], *namep;
+    OF_node_t *node;
+    OF_inst_t *inst;
+    uint32_t ihandle;
+
+    OF_CHECK_NBARGS(OF_env, 1);
+    namep = (unsigned char *)popd(OF_env);
+    OF_lds(name, namep);
+    OF_DPRINTF("package [%s]\n", name);
+    args = OF_get_args(OF_env, name);
+    node = OF_get_alias(OF_env, name);
+    if (node == NULL) {
+        node = OF_pack_find_by_name(OF_env, OF_node_root, name);
+    }
+    if (node == NULL) {
+        OF_DPRINTF("package not found !\n");
+        pushd(OF_env, -1);
+        return;
+    }
+    inst = OF_instance_new(OF_env, node);
+    if (inst == NULL) {
+        pushd(OF_env, -1);
+        ERROR("Cannot create package instance\n");
+        return;
+    }
+    ihandle = OF_instance_get_id(OF_env, inst);
+    /* If an "open" method exists in the package, call it */
+    OF_DPRINTF("package [%s] => %0x\n", name, ihandle);
+    OF_node_put(OF_env, node);
+    _OF_callmethod(OF_env, "open", ihandle, args);
+}
+
+/* De-instanciate a package */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_close (OF_env_t *OF_env)
+{
+    uint32_t ihandle;
+
+    OF_CHECK_NBARGS(OF_env, 1);
+    ihandle = popd(OF_env);
+    /* If an "close" method exists in the package, call it */
+    _OF_callmethod(OF_env, "close", ihandle, NULL);
+    /* XXX: Should free the instance */
+}
+
+/* "read" */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_read (OF_env_t *OF_env)
+{
+    uint32_t ihandle;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    ihandle = popd(OF_env);
+    OF_DPRINTF("ih: %0x\n", ihandle);
+    /* If a "read" method exists in the package, call it */
+    _OF_callmethod(OF_env, "read", ihandle, NULL);
+}
+
+/* Try call the "read" method of a device's package */
+/* "write" */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_write (OF_env_t *OF_env)
+{
+    uint32_t ihandle;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    ihandle = popd(OF_env);
+    //    OF_DPRINTF("ih: %0x\n", ihandle);
+    /* If a "write" method exists in the package, call it */
+    _OF_callmethod(OF_env, "write", ihandle, NULL);
+}
+
+/* "seek" */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_seek (OF_env_t *OF_env)
+{
+    uint32_t ihandle;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    ihandle = popd(OF_env);
+    OF_DPRINTF("ih: %0x\n", ihandle);
+    /* If a "seek" method exists in the package, call it */
+    _OF_callmethod(OF_env, "seek", ihandle, NULL);
+}
+
+/* Memory services */
+/* Claim some memory space */
+__attribute__ (( section (".OpenFirmware") ))
+uint32_t OF_claim_virt (uint32_t virt, uint32_t size, int *range)
+{
+    int i, keep = -1;
+
+    OF_DPRINTF("Claim %d bytes at 0x%0x\n", size, virt);
+    /* First check that the requested memory stands in the physical memory */
+    if (OF_mem_ranges[0].start > virt ||
+        (OF_mem_ranges[0].start + OF_mem_ranges[0].size) < (virt + size)) {
+        ERROR("not in memory: start 0x%0x virt 0x%0x end 0x%0x 0x%0x\n",
+              OF_mem_ranges[0].start, virt,
+              OF_mem_ranges[0].start + OF_mem_ranges[0].size,
+              virt + size);
+        return (uint32_t)(-1);
+    }
+    /* Now check that it doesn't overlap with already claimed areas */
+    for (i = 1; i < OF_MAX_MEMRANGES + 1; i++) {
+        if (OF_mem_ranges[i].start == (uint32_t)(-1) ||
+            OF_mem_ranges[i].size == (uint32_t)(-1)) {
+            if (keep == -1)
+                keep = i;
+            continue;
+        }
+        if (OF_mem_ranges[i].start == virt &&
+            (OF_mem_ranges[i].start + OF_mem_ranges[i].size) == (virt + size)) {
+            return virt;
+        }
+        if (!((OF_mem_ranges[i].start >= (virt + size) ||
+               (OF_mem_ranges[i].start + OF_mem_ranges[i].size) <= virt))) {
+            ERROR("overlap: start 0x%0x virt 0x%0x end 0x%0x 0x%0x\n",
+                  OF_mem_ranges[i].start, virt,
+                  OF_mem_ranges[i].start + OF_mem_ranges[i].size,
+                  virt + size);
+            /* Aie... */
+            return (uint32_t)(-1);
+        }
+    }
+    OF_DPRINTF("return range: %d\n", keep);
+    if (keep == -1) {
+        /* no more rooms */
+        ERROR("No more rooms\n");
+        return (uint32_t)(-1);
+    } else {
+        ERROR("Give range: start 0x%0x 0x%0x\n", virt, size);
+    }
+    if (range != NULL)
+        *range = keep;
+
+    return virt;
+}
+
+/* We always try to get the upper address we can */
+__attribute__ (( section (".OpenFirmware") ))
+static uint32_t OF_claim_size (uint32_t size, int align, int *range)
+{
+    uint32_t addr, max = (uint32_t)(-1);
+    int i;
+    
+    OF_DPRINTF("Try map %d bytes at 0x00000000\n", size);
+    if (OF_claim_virt(0, size, range) != (uint32_t)(-1))
+        max = 0;
+    for (i = 1; i < OF_MAX_MEMRANGES + 1; i++) {
+        if (OF_mem_ranges[i].start == (uint32_t)(-1) ||
+            OF_mem_ranges[i].size == (uint32_t)(-1))
+            continue;
+        addr = (OF_mem_ranges[i].start + OF_mem_ranges[i].size + align - 1) &
+            ~(align - 1);
+        OF_DPRINTF("Try map %d bytes at 0x%0x\n", size, addr);
+        if ((addr + 1) > (max + 1)) {
+            if (OF_claim_virt(addr, size, range) != (uint32_t)(-1))
+                max = addr;
+        }
+    }
+
+    return max;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_claim (OF_env_t *OF_env)
+{
+    uint32_t virt, size, addr;
+    int align;
+    int i, range;
+
+    OF_CHECK_NBARGS(OF_env, 3);
+    virt = popd(OF_env);
+    size = popd(OF_env);
+    align = popd(OF_env);
+    DPRINTF("virt 0x%0x size 0x%0x align %d\n", virt, size, align);
+    if (align == 0) {
+        addr = OF_claim_virt(virt, size, &range);
+    } else {
+        for (i = 1; i < align; i = i << 1)
+            continue;
+        align = i;
+        size = (size + align - 1) & ~(align - 1);
+        addr = OF_claim_size(size, align, &range);
+    }
+    if (addr == (uint32_t)-1) {
+        ERROR("No range match !\n");
+        pushd(OF_env, -1);
+    }
+    if (range != -1) {
+        OF_mem_ranges[range].start = addr;
+        OF_mem_ranges[range].size = size;
+    }
+    OF_DPRINTF("Give address 0x%0x\n", addr);
+    pushd(OF_env, addr);
+}
+
+/* release some previously claimed memory */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_release (OF_env_t *OF_env)
+{
+    uint32_t virt, size;
+    int i;
+
+    OF_CHECK_NBARGS(OF_env, 2);
+    virt = popd(OF_env);
+    size = popd(OF_env);
+    OF_DPRINTF("virt 0x%0x size 0x%0x\n", virt, size);
+    for (i = 0; i < OF_MAX_MEMRANGES; i++) {
+        if (OF_mem_ranges[i].start == virt && OF_mem_ranges[i].size == size) {
+            OF_mem_ranges[i].start = (uint32_t)(-1);
+            OF_mem_ranges[i].size = (uint32_t)(-1);
+            break;
+        }
+    }
+}
+
+/* Control transfer services */
+/* "boot" */
+
+/* Enter Open-Firmware interpreter */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_enter (OF_env_t *OF_env)
+{
+    int n_args;
+
+    n_args = stackd_depth(OF_env);
+    /* means that the bootloader has ended.
+     * So qemu will...
+     */
+    OF_DPRINTF("%d \n", n_args);
+    //    printf("Bootloader has quitted...\n");
+    //    abort();
+}
+
+/* Exit client program */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_exit (OF_env_t *OF_env)
+{
+    int n_args;
+
+    n_args = stackd_depth(OF_env);
+    /* means that the bootloader has ended.
+     * So qemu will...
+     */
+    OF_DPRINTF("%d \n", n_args);
+    //    printf("Bootloader has quitted...\n");
+    //    abort();
+}
+
+/* "chain" */
+
+/* User interface services */
+/* "interpret" */
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_interpret (OF_env_t *OF_env)
+{
+    const unsigned char *FString;
+    void *buf;
+    OF_inst_t *inst;
+    OF_node_t *pks, *slw, *chs, *disp;
+    uint32_t ihandle, crc;
+
+    OF_DPRINTF("\n");
+    //    OF_CHECK_NBARGS(OF_env, 1);
+    FString = (const void *)popd(OF_env);
+    crc = crc32(0, FString, strlen(FString));
+    OF_DPRINTF("\n\nOF INTERPRETER CALL:\n [%s]\n crc=%0x\n", FString, crc);
+    /* Do some hacks to make BootX happy */
+    switch (crc) {
+    case 0x225b6748: /* MacOS X 10.2 and OpenDarwin 1.41 */
+    case 0xb1cd4d25: /* OpenDarwin 6.02 */
+        /* Create "sl_words" package */
+        popd(OF_env);
+        /* Find "/packages" */
+        pks = OF_pack_find_by_name(OF_env, OF_node_root, "/packages");
+        if (pks == NULL) {
+            OF_node_put(OF_env, pks);
+            pushd(OF_env, -1);
+            ERROR("Cannot get '/packages'\n");
+            break;
+        }
+        slw = OF_node_new(OF_env, pks, "sl_words", OF_ADDRESS_NONE);
+        if (slw == NULL) {
+            OF_node_put(OF_env, pks);
+            pushd(OF_env, -1);
+            ERROR("Cannot create 'sl_words'\n");
+            break;
+        }
+        /* Create methods */
+        OF_method_new(OF_env, slw, "slw_set_output_level",
+                      &slw_set_output_level);
+        OF_method_new(OF_env, slw, "slw_emit", &slw_emit);
+        OF_method_new(OF_env, slw, "slw_cr", &slw_cr);
+        OF_method_new(OF_env, slw, "slw_init_keymap", &slw_init_keymap);
+        OF_method_new(OF_env, slw, "slw_update_keymap", &slw_update_keymap);
+        OF_method_new(OF_env, slw, "slw_spin", &slw_spin);
+        OF_method_new(OF_env, slw, "slw_spin_init", &slw_spin_init);
+        OF_method_new(OF_env, slw, "slw_pwd", &slw_pwd);
+        OF_method_new(OF_env, slw, "slw_sum", &slw_sum);
+        /* Init properties */
+        OF_prop_int_new(OF_env, slw, "outputLevel", 0);
+        OF_prop_int_new(OF_env, slw, "keyboardIH", 0);
+        {
+#if 0
+            OF_node_t *kbd;
+            kbd = OF_pack_find_by_name(OF_env, OF_node_root, "/keyboard");
+            if (kbd == NULL) {
+                OF_node_put(OF_env, pks);
+                pushd(OF_env, -1);
+                ERROR("Cannot get '/keyboard'\n");
+                break;
+            }
+            buf = malloc(0x20);
+            if (buf == NULL) {
+                OF_node_put(OF_env, pks);
+                pushd(OF_env, -1);
+                ERROR("Cannot allocate keyboard buff\n");
+                break;
+            }
+#else
+            buf = malloc(0x20);
+            if (buf == NULL) {
+                OF_node_put(OF_env, pks);
+                pushd(OF_env, -1);
+                ERROR("Cannot allocate keyboard buff\n");
+                break;
+            }
+            memset(buf, 0, 0x20);
+            OF_property_new(OF_env, slw, "keyMap", buf, 0x20);
+#endif
+        }
+        OF_prop_int_new(OF_env, slw, "screenIH", 0);
+        OF_prop_int_new(OF_env, slw, "cursorAddr", 0);
+        OF_prop_int_new(OF_env, slw, "cursorX", 0);
+        OF_prop_int_new(OF_env, slw, "cursorY", 0);
+        OF_prop_int_new(OF_env, slw, "cursorW", 0);
+        OF_prop_int_new(OF_env, slw, "cursorH", 0);
+        OF_prop_int_new(OF_env, slw, "cursorFrames", 0);
+        OF_prop_int_new(OF_env, slw, "cursorPixelSize", 0);
+        OF_prop_int_new(OF_env, slw, "cursorStage", 0);
+        OF_prop_int_new(OF_env, slw, "cursorTime", 0);
+        OF_prop_int_new(OF_env, slw, "cursorDelay", 0);
+        /* Instanciate sl_words */
+        inst = OF_instance_new(OF_env, slw);
+        if (inst == NULL) {
+            OF_node_put(OF_env, pks);
+            pushd(OF_env, -1);
+            ERROR("Cannot create sl_words instance\n");
+            break;
+        }
+        ihandle = OF_instance_get_id(OF_env, inst);
+        /* Release packages */
+        OF_node_put(OF_env, slw);
+        OF_node_put(OF_env, pks);
+        OF_DPRINTF("sl_words instance: %0x\n", ihandle);
+        /* Set return value */
+        if (crc == 0xb1cd4d25) /* Hack for OpenDarwin 6.02 */
+            pushd(OF_env, ihandle);
+        pushd(OF_env, ihandle);
+        pushd(OF_env, 0);
+        break;
+    case 0x233441d3: /* MacOS X 10.2 and OpenDarwin 1.41 */
+        /* Create "memory-map" pseudo device */
+        {
+            OF_node_t *map;
+            uint32_t phandle;
+
+        /* Find "/packages" */
+        chs = OF_pack_find_by_name(OF_env, OF_node_root, "/chosen");
+        if (chs == NULL) {
+            pushd(OF_env, -1);
+            ERROR("Cannot get '/chosen'\n");
+            break;
+        }
+            map = OF_node_new(OF_env, chs, "memory-map", OF_ADDRESS_NONE);
+            if (map == NULL) {
+                pushd(OF_env, -1);
+                ERROR("Cannot create 'memory-map'\n");
+                break;
+            }
+            phandle = OF_pack_handle(OF_env, map);
+            OF_node_put(OF_env, map);
+            OF_node_put(OF_env, chs);
+            pushd(OF_env, phandle);
+        pushd(OF_env, 0);
+        }
+        break;
+    case 0x32a2d18e: /* MacOS X 10.2 and OpenDarwin 6.02 */
+        /* Return screen ihandle */
+        disp = OF_get_alias(OF_env, "screen");
+        if (disp == NULL) {
+            pushd(OF_env, 0);
+            pushd(OF_env, -1);
+            ERROR("Cannot get 'screen' alias\n");
+            break;
+        }
+        inst = OF_instance_new(OF_env, disp);
+        if (inst == NULL) {
+            OF_node_put(OF_env, disp);
+            pushd(OF_env, 0);
+            pushd(OF_env, -1);
+            ERROR("Cannot create 'screen' instance\n");
+            break;
+        }
+        ihandle = OF_instance_get_id(OF_env, inst);
+        OF_node_put(OF_env, disp);
+        OF_DPRINTF("Return screen ihandle: %0x\n", ihandle);
+        pushd(OF_env, ihandle);
+        pushd(OF_env, 0);
+        break;
+    case 0xF3A9841F: /* MacOS X 10.2 */
+    case 0x76fbdf18: /* OpenDarwin 6.02 */
+        /* Set current display as active package */
+        disp = OF_get_alias (OF_env, "screen");
+        if (disp == NULL) {
+            pushd(OF_env, 0);
+            pushd(OF_env, -1);
+        }
+        OF_node_put(OF_env, disp);
+        break;
+    case 0x1c3bc93f: /* MacOS X 10.3 */
+        /* get-package-property if 0 0 then */
+        OF_getprop(OF_env);
+        {
+            uint32_t len;
+            len = popd(OF_env);
+            if (len == (uint32_t)-1)
+                len = 0;
+            pushd(OF_env, len);
+        }
+        break;
+    case 0x218d5ccb: /* yaboot */
+    case 0x27b32255:
+    case 0x05d332ef:
+    case 0xc7b5d3b5:
+        /* skip it */
+        break;
+    case 0xf541a878:
+    case 0x6a9b2be6:
+        /* Yaboot: set background color to black */
+        break;
+    case 0x846077fb:
+    case 0x299c2c5d: /* gentoo */
+        /* Yaboot: set foreground color to grey */
+        break;
+    case 0x4ad41f2d:
+        /* Yaboot: wait 10 ms: sure ! */
+        break;
+
+    default:
+        /* ERROR */
+        printf("Script: len=%d\n%s\n", (int)strlen(FString), FString);
+        printf("Call %0x NOT IMPLEMENTED !\n", crc);
+        bug();
+        break;
+    }
+    OF_DPRINTF("\n\nOF INTERPRETER CALL DONE\n\n");
+}
+
+/* "set-callback" */
+/* "set-symbol-lookup" */
+
+/* Time services */
+/* "milliseconds" */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_milliseconds (OF_env_t *OF_env)
+{
+#if 0
+    struct timeval tv;
+
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(OF_env, 0);
+    gettimeofday(&tv, NULL);
+    pushd(OF_env, (tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+#else
+    static uint32_t ms = 0;
+
+    OF_CHECK_NBARGS(OF_env, 0);
+    pushd(OF_env, ms);
+    usleep(10000); /* XXX: TOFIX: Random sleep */
+    ms += 10;
+#endif
+}
+
+/* Undocumented in IEEE 1275 */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_quiesce (OF_env_t *OF_env)
+{
+    OF_CHECK_NBARGS(OF_env, 0);
+    /* Should free all OF resources */
+    bd_reset_all();
+#if defined (DEBUG_BIOS)
+    {
+        uint16_t loglevel = 0x02 | 0x10 | 0x80;
+        //        outw(0xFF02, loglevel);
+        outb(0x0F02, loglevel);
+    }
+#endif
+}
+
+typedef struct OF_service_t OF_service_t;
+struct OF_service_t {
+    const unsigned char *name;
+    OF_cb_t cb;
+};
+
+static OF_service_t services[] = {
+    { "test",                &OF_test,                },
+    { "peer",                &OF_peer,                },
+    { "child",               &OF_child,               },
+    { "parent",              &OF_parent,              },
+    { "instance-to-package", &OF_instance_to_package, },
+    { "getproplen",          &OF_getproplen,          },
+    { "getprop",             &OF_getprop,             },
+    { "nextprop",            &OF_nextprop,            },
+    { "setprop",             &OF_setprop,             },
+    { "finddevice",          &OF_finddevice,          },
+    { "instance-to-path",    &OF_instance_to_path,    },
+    { "package-to-path",     &OF_package_to_path,     },
+    { "call-method",         &OF_callmethod,          },
+    { "open",                &OF_open,                },
+    { "open-package",        &OF_open,                },
+    { "close",               &OF_close,               },
+    { "read",                &OF_read,                },
+    { "write",               &OF_write,               },
+    { "seek",                &OF_seek,                },
+    { "claim",               &OF_claim,               },
+    { "release",             &OF_release,             },
+    { "enter",               &OF_enter,               },
+    { "exit",                &OF_exit,                },
+    { "interpret",           &OF_interpret,           },
+    { "milliseconds",        &OF_milliseconds,        },
+    { "quiesce",             &OF_quiesce,             },
+};
+
+/* Probe if a named service exists */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_test (OF_env_t *OF_env)
+{
+    unsigned char name[OF_NAMELEN_MAX], *namep;
+    uint32_t i;
+    int ret = -1;
+
+    OF_CHECK_NBARGS(OF_env, 1);
+    namep = (unsigned char *)popd(OF_env);
+    OF_lds(name, namep);
+    OF_DPRINTF("service [%s]\n", name);
+    for (i = 0; i < (sizeof(services) / sizeof(OF_service_t)); i++) {
+        if (strcmp(services[i].name, name) == 0) {
+            ret = 0;
+            break;
+        }
+    }
+    pushd(OF_env, ret);
+}
+
+/* Main entry point for PPC clients */
+__attribute__ (( section (".OpenFirmware") ))
+int OF_client_entry (void *p)
+{
+    unsigned char buffer[OF_NAMELEN_MAX];
+    OF_env_t OF_env;
+    OF_cb_t cb;
+    unsigned char *namep;
+    uint32_t i;
+
+    /* set our environment */
+    MMU_off();
+    OF_DPRINTF("Called with arg: %p\n", p);
+    /* Load function name string */
+    namep = (unsigned char *)(*(uint32_t *)p);
+    OF_lds(buffer, namep);
+    /* Find callback */
+    cb = NULL;
+    OF_DPRINTF("Look for service [%s]\n", buffer);
+    for (i = 0; i < (sizeof(services) / sizeof(OF_service_t)); i++) {
+        if (strcmp(services[i].name, buffer) == 0) {
+            cb = services[i].cb;
+            break;
+        }
+    }
+    if (cb == NULL) {
+        OF_DPRINTF("service [%s] not implemented\n", buffer);
+        //        bug();
+        return -1;
+    }
+#if 0
+    OF_DPRINTF("Service [%s] found\n", buffer);
+#endif
+    /* Set up stack *NON REENTRANT* */
+    OF_env_init(&OF_env);
+    /* Launch Forth glue */
+    C_to_Forth(&OF_env, (uint32_t *)p + 1, &cb);
+    OF_DPRINTF("done\n");
+    MMU_on();
+
+    return 0;
+}
+
+/*****************************************************************************/
+/* Run-time abstraction services */
+/* RTAS RAM is organised this way:
+ * RTAS_memory is given by the OS when instanciating RTAS.
+ * it's an 32 kB area divided in 2 zones:
+ * Up is a stack, used to call RTAS services
+ * Down is the variables area.
+ */
+
+__attribute__ (( section (".RTAS_vars") ))
+static OF_cb_t *RTAS_callbacks[32];
+#if 0
+__attribute__ (( section (".RTAS_vars") ))
+static uint8_t *RTAS_base;
+#endif
+
+/* RTAS is called in real mode (ie no MMU), privileged with all exceptions
+ * disabled. It has to preserve all registers except R3 to R12.
+ * The OS should ensure it's not re-entered.
+ */
+__attribute__ (( section (".RTAS") ))
+int RTAS_entry (void *p)
+{
+    OF_env_t RTAS_env;
+    uint32_t token;
+
+    OF_DPRINTF("Called with arg: %p\n", p);
+    /* set our environment */
+    token = *(uint32_t *)p;
+    /* Set up stack */
+    RTAS_env.stackb = (uint32_t *)(RTAS_memory + 0x8000 - 4);
+    RTAS_env.stackp = RTAS_env.stackb;
+    RTAS_env.funcb = (uint32_t *)(RTAS_memory + 0x8000 - OF_STACK_SIZE - 4);
+    RTAS_env.funcp = RTAS_env.funcb;
+    /* Call Forth glue */
+    C_to_Forth(&RTAS_env, (uint32_t *)p + 1, RTAS_callbacks[token & 0x3F]);
+    OF_DPRINTF("done\n");
+
+    return 0;
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_restart_rtas (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 0);
+    /* No implementation: return error */
+    pushd(RTAS_env, -1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_nvram_fetch (OF_env_t *RTAS_env)
+{
+    uint8_t *buffer;
+    int offset, length;
+    int i;
+
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 3);
+    offset = popd(RTAS_env);
+    buffer = (uint8_t *)popd(RTAS_env);
+    length = popd(RTAS_env);
+    for (i = 0; i < length; i++) {
+        if ((i + offset) >= NVRAM_get_size(nvram)) {
+            pushd(RTAS_env, -3);
+            return;
+        }
+        *buffer++ = NVRAM_read(nvram, i + offset);
+    }
+    pushd(RTAS_env, length);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_nvram_store (OF_env_t *RTAS_env)
+{
+    uint8_t *buffer;
+    int offset, length;
+    int i;
+
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 3);
+    offset = popd(RTAS_env);
+    buffer = (uint8_t *)popd(RTAS_env);
+    length = popd(RTAS_env);
+    for (i = 0; i < length; i++) {
+        if ((i + offset) >= NVRAM_get_size(nvram)) {
+            pushd(RTAS_env, -3);
+            return;
+        }
+        NVRAM_write(nvram, i + offset, *buffer++);
+    }
+    pushd(RTAS_env, length);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_get_time_of_day (OF_env_t *RTAS_env)
+{
+#if 0
+    struct tm tm;
+    time_t t;
+
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 0);
+    t = get_time();
+    localtime_r(&t, &tm);
+    pushd(RTAS_env, 0); /* nanoseconds */
+    pushd(RTAS_env, tm.tm_sec);
+    pushd(RTAS_env, tm.tm_min);
+    pushd(RTAS_env, tm.tm_hour);
+    pushd(RTAS_env, tm.tm_mday);
+    pushd(RTAS_env, tm.tm_mon);
+    pushd(RTAS_env, tm.tm_year);
+    pushd(RTAS_env, 0); /* status */
+#else
+    pushd(RTAS_env, 0);
+    pushd(RTAS_env, 0);
+    pushd(RTAS_env, 0);
+    pushd(RTAS_env, 0);
+    pushd(RTAS_env, 0);
+    pushd(RTAS_env, 0);
+    pushd(RTAS_env, 0);
+    pushd(RTAS_env, 0);
+#endif
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_set_time_of_day (OF_env_t *RTAS_env)
+{
+#if 0
+    struct tm tm;
+    time_t t;
+
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 7);
+    tm.tm_year = popd(RTAS_env);
+    tm.tm_mon = popd(RTAS_env);
+    tm.tm_mday = popd(RTAS_env);
+    tm.tm_hour = popd(RTAS_env);
+    tm.tm_min = popd(RTAS_env);
+    tm.tm_sec = popd(RTAS_env);
+    popd(RTAS_env); /* nanoseconds */
+    t = mktime(&tm);
+    set_time_offset(t);
+#endif
+    pushd(RTAS_env, 0); /* status */
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_set_time_for_power_on (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 7);
+    /* Do nothing */
+    pushd(RTAS_env, 0); /* status */
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_event_scan (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 4);
+    /* Pretend there are no new events */
+    pushd(RTAS_env, 1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_check_exception (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 6);
+    /* Pretend we found no exceptions */
+    pushd(RTAS_env, 1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_read_pci_config (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 2);
+    /* Hardware error */
+    pushd(RTAS_env, -1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_write_pci_config (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 3);
+    /* Hardware error */
+    pushd(RTAS_env, -1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_display_character (OF_env_t *RTAS_env)
+{
+    int c;
+
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 1);
+    c = popd(RTAS_env);
+#if 0
+    printf("%c", c);
+#else
+    outb(0x0F00, c);
+#endif
+    pushd(RTAS_env, 0);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_set_indicator (OF_env_t *RTAS_env)
+{
+    const unsigned char *name;
+    int indic, state;
+
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 3);
+    indic = popd(RTAS_env);
+    state = popd(RTAS_env);
+    switch (indic) {
+    case 1:
+        name = "tone frequency";
+        break;
+    case 2:
+        name = "tone volume";
+        break;
+    case 3:
+        name = "system power state";
+        break;
+    case 4:
+        name = "warning light";
+        break;
+    case 5:
+        name = "disk activity light";
+        break;
+    case 6:
+        name = "hexadecimal display unit";
+        break;
+    case 7:
+        name = "batery warning time";
+        break;
+    case 8:
+        name = "condition cycle request";
+        break;
+    case 9000 ... 9999:
+        name = "vendor specific";
+        break;
+    default:
+        pushd(RTAS_env, -3);
+        return;
+    }        
+    OF_DPRINTF("Set indicator %d [%s] to %d\n", indic, name, state);
+    pushd(RTAS_env, 0);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_get_sensor_state (OF_env_t *RTAS_env)
+{
+    const unsigned char *name;
+    int type, index;
+    int state;
+
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 2);
+    type = popd(RTAS_env);
+    index = popd(RTAS_env);
+    switch (index) {
+    case 1:
+        name = "key switch";
+        state = 1; /* Normal */
+        break;
+    case 2:
+        name = "enclosure switch";
+        state = 0; /* Closed */
+        break;
+    case 3:
+        name = "thermal sensor";
+        state = 40; /* in degrees Celsius (not too hot !) */
+        break;
+    case 4:
+        name = "lid status";
+        state = 1; /* Open */
+        break;
+    case 5:
+        name = "power source";
+        state = 0; /* AC */
+        break;
+    case 6:
+        name = "battery voltage";
+        state = 6; /* Let's have a moderated answer :-) */
+        break;
+    case 7:
+        name = "battery capacity remaining";
+        state = 3; /* High */
+        break;
+    case 8:
+        name = "battery capacity percentage";
+        state = 1000; /* 100 % */
+        break;
+    case 9:
+        name = "EPOW sensor";
+        state = 5; /* ? */
+        break;
+    case 10:
+        name = "battery condition cycle state";
+        state = 0; /* none */
+        break;
+    case 11:
+        name = "battery charge state";
+        state = 2; /* No current flow */
+        break;
+    case 9000 ... 9999:
+        name = "vendor specific";
+        state = 0;
+        break;
+    default:
+        pushd(RTAS_env, -3);
+        return;
+    }        
+    OF_DPRINTF("Pretend sensor %d [%s] is in state %d\n", index, name, state);
+    pushd(RTAS_env, state);
+    pushd(RTAS_env, 0);
+}
+
+#if 0 // No power management */
+__attribute__ (( section (".RTAS") ))
+static void RTAS_set_power_level (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_get_power_level (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_assume_power_management (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_relinquish_power_management (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+}
+#endif
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_power_off (OF_env_t *RTAS_env)
+{
+    printf("RTAS was asked to switch off\n");
+    OF_CHECK_NBARGS(RTAS_env, 2);
+    //    abort();
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_suspend (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 3);
+    /* Pretend we don't succeed */
+    pushd(RTAS_env, -1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_hibernate (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 3);
+    /* Pretend we don't succeed */
+    pushd(RTAS_env, -1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_system_reboot (OF_env_t *RTAS_env)
+{
+    printf("RTAS was asked to reboot\n");
+    OF_CHECK_NBARGS(RTAS_env, 0);
+    //    abort();
+}
+
+#if 0 // No power management nor SMP */
+__attribute__ (( section (".RTAS") ))
+static void RTAS_cache_control (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_freeze_time_base (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_thaw_time_base (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_stop_self (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_start_cpu (OF_env_t *RTAS_env)
+{
+    OF_DPRINTF("\n");
+}
+#endif
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_instantiate (OF_env_t *RTAS_env)
+{
+    const unsigned char *args;
+    uint32_t ihandle;
+    uint32_t base_address;
+
+    OF_DPRINTF("\n");
+    OF_CHECK_NBARGS(RTAS_env, 3);
+    ihandle = popd(RTAS_env);
+    args = (void *)popd(RTAS_env);
+    base_address = popd(RTAS_env);
+    memmove((void *)base_address, (void *)(&_RTAS_start),
+            (char *)(&_RTAS_data_end) - (char *)(&_RTAS_start));
+    OF_DPRINTF("base_address=0x%0x\n", base_address);
+    pushd(RTAS_env, base_address);
+    pushd(RTAS_env, 0);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_new_cb (OF_env_t *env, OF_node_t *rtas,
+                         const unsigned char *name,
+                         OF_cb_t cb, uint32_t *token_next)
+{
+    OF_prop_int_new(env, rtas, name, 0xabcd0000 | *token_next);
+    RTAS_callbacks[*token_next] = &cb;
+    (*token_next)++;
+}
+
+__attribute__ (( section (".RTAS") ))
+void RTAS_init (void)
+{
+    OF_env_t *RTAS_env;
+    OF_node_t *rtas, *chs;
+    OF_prop_t *stdout;
+    uint32_t token_next = 0, size;
+
+    RTAS_env = OF_env_main;
+    rtas = OF_node_new(RTAS_env, OF_node_root, "rtas", OF_ADDRESS_NONE);
+    if (rtas == NULL) {
+        ERROR("RTAS not found\n");
+        return;
+    }
+    size = ((char *)(&_RTAS_data_end) - (char *)(&_RTAS_start) + 0x0000FFFF) &
+        ~0x0000FFFF;
+    OF_DPRINTF("RTAS size: %d bytes (%d)\n", size,
+               (char *)(&_RTAS_data_end) - (char *)(&_RTAS_start));
+    OF_prop_int_new(RTAS_env, rtas, "rtas-size", size);
+    OF_prop_int_new(RTAS_env, rtas, "rtas-version", 1);
+    OF_prop_int_new(RTAS_env, rtas, "rtas-event-scan-rate", 0);
+    OF_prop_int_new(RTAS_env, rtas, "rtas-error-log-max", 0);
+    chs = OF_node_get(RTAS_env, "chosen");
+    if (chs == NULL) {
+        ERROR("choosen not found\n");
+        return;
+    }
+    stdout = OF_property_get(RTAS_env, chs, "stdout");
+    if (stdout == NULL) {
+        OF_node_put(RTAS_env, chs);
+        ERROR("stdout not found\n");
+        return;
+    }
+    OF_prop_int_new(RTAS_env, rtas, "rtas-display-device",
+                    *(uint32_t *)stdout->value);
+    /* RTAS tokens */
+    RTAS_new_cb(RTAS_env, rtas, "restart_rtas",
+                &RTAS_restart_rtas, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "nvram_fetch",
+                &RTAS_nvram_fetch, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "nvram_store",
+                &RTAS_nvram_store, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "get-time-of_day",
+                &RTAS_get_time_of_day, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "set-time-of-day",
+                &RTAS_set_time_of_day, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "set-time-for-power-on",
+                &RTAS_set_time_for_power_on, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "event-scan", &RTAS_event_scan, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "check-exception",
+                &RTAS_check_exception, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "read-pci-config",
+                &RTAS_read_pci_config, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "write-pci-config",
+                &RTAS_write_pci_config, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "display-character",
+                &RTAS_display_character, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "set-indicator",
+                &RTAS_set_indicator, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "get-sensor-state",
+                &RTAS_get_sensor_state, &token_next);
+#if 0 // No power management */
+    RTAS_new_cb(RTAS_env, rtas, "set-power-level",
+                &RTAS_set_power_level, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "get-power-level",
+                &RTAS_get_power_level, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "assume-power-management",
+                &RTAS_assume_power_management, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "relinquish-power-management",
+                &RTAS_relinquish_power_management, &token_next);
+#endif
+    RTAS_new_cb(RTAS_env, rtas, "power-off", &RTAS_power_off, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "suspend", &RTAS_suspend, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "hibernate", &RTAS_hibernate, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "system-reboot",
+                &RTAS_system_reboot, &token_next);
+#if 0 // No power management nor SMP */
+    RTAS_new_cb(RTAS_env, rtas, "cache-control",
+                &RTAS_cache_control, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "freeze_time_base",
+                &RTAS_freeze_time_base, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "thaw_time_base",
+                &RTAS_thaw_time_base, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "stop-self", &RTAS_stop_self, &token_next);
+    RTAS_new_cb(RTAS_env, rtas, "start-cpu", &RTAS_start_cpu, &token_next);
+#endif
+    /* missing
+     * "update-flash"
+     * "update-flash-and-reboot"
+     * "query-cpu-stopped-state" for SMP
+     */
+    OF_method_new(RTAS_env, rtas, "instantiate-rtas", &RTAS_instantiate);
+    OF_node_put(RTAS_env, rtas);
+    OF_node_new(RTAS_env, OF_node_root, "nomore", OF_ADDRESS_NONE);
+    DPRINTF("RTAS done\n");
+}
+
+/*****************************************************************************/
+/*                          That's all for now...                            */
+/*****************************************************************************/