summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openhackware/src/of.c
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/openhackware/src/of.c
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff)
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/openhackware/src/of.c')
-rw-r--r--qemu/roms/openhackware/src/of.c5450
1 files changed, 5450 insertions, 0 deletions
diff --git a/qemu/roms/openhackware/src/of.c b/qemu/roms/openhackware/src/of.c
new file mode 100644
index 000000000..33582c308
--- /dev/null
+++ b/qemu/roms/openhackware/src/of.c
@@ -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... */
+/*****************************************************************************/