diff options
Diffstat (limited to 'qemu/roms/openhackware/src/of.c')
-rw-r--r-- | qemu/roms/openhackware/src/of.c | 5450 |
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", ®s, 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", ®s, 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", ®s, 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", ®s, 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", + ®s, 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", + ®s, 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", ®s, 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... */ +/*****************************************************************************/ |