/* 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 #include #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... */ /*****************************************************************************/