__initfunc(void prom_init(void *cif_handler, void *cif_stack)) { char buffer[80], *p; int ints[3]; int node; int i = 0; prom_vers = PROM_P1275; prom_cif_init(cif_handler, cif_stack); prom_root_node = prom_getsibling(0); if((prom_root_node == 0) || (prom_root_node == -1)) prom_halt(); prom_chosen_node = prom_finddevice("/chosen"); if (!prom_chosen_node || prom_chosen_node == -1) prom_halt(); prom_stdin = prom_getint (prom_chosen_node, "stdin"); prom_stdout = prom_getint (prom_chosen_node, "stdout"); node = prom_finddevice("/openprom"); if (!node || node == -1) prom_halt(); prom_getstring (node, "version", buffer, sizeof (buffer)); prom_printf ("\n"); if (strncmp (buffer, "OBP ", 4)) goto strange_version; /* Version field is expected to be 'OBP xx.yy.zz date...' */ p = buffer + 4; while (p && isdigit(*p) && i < 3) { ints[i++] = simple_strtoul(p, NULL, 0); if ((p = strchr(p, '.')) != NULL) p++; } if (i != 3) goto strange_version; prom_rev = ints[1]; prom_prev = (ints[0] << 16) | (ints[1] << 8) | ints[2]; printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + 4); prom_meminit(); prom_ranges_init(); /* Initialization successful. */ return; strange_version: prom_printf ("Strange OBP version `%s'.\n", buffer); prom_halt (); }
/** * @brief Initializes the OpenBoot PROM interface on an early boot stage. * Before using any routines in the prom library, prom_init() must be * called. This should be one of the first things to be done on bootup, * since it provides the output sink and the prom version that it used * for feedback and debugging purposes. */ void prom_init() { node_chosen = prom_finddevice("/chosen"); if (!node_chosen || (int) node_chosen == -1) prom_exit(); if(prom_getprop(node_chosen, "stdout", &node_stdout, sizeof(node_stdout)) <= 0) node_stdout = 0; if(prom_getprop(node_stdin, "stdin", &node_stdin, sizeof(node_stdin)) <= 0) node_stdin = 0; node_root = prom_finddevice("/"); if (!node_root || (int) node_root == -1) { printk("Error: / device not found.\n"); prom_exit(); } if(prom_getprop(node_root, "compatible", prom_subarch, sizeof(prom_subarch)) <= 0) { printk("Note: compatible property not set.\n"); /* not important, we can check compatibility with the %ver register */ strncpy(prom_subarch, "unknown", 7); } node_obp = prom_finddevice("/openprom"); if (!node_obp || (int) node_obp == -1) { printk("Error: /openprom device not found.\n"); prom_exit(); } if(prom_getprop(node_obp, "version", prom_version, sizeof(prom_version)) <= 0) { printk("Error: /openprom version property not found.\n"); prom_exit(); } if(strncmp("OBP ", prom_version, 4)) { printk("Error: Unknown OpenPROM version.\n"); prom_exit(); } prom_getprop(node_chosen, "bootpath", prom_bootpath, sizeof(prom_bootpath)); prom_getprop(node_chosen, "bootargs", prom_bootargs, sizeof(prom_bootargs)); /* if we found stdout, we can now clear the screen for the boot messages */ if(node_stdout != 0) clear_screen(); }
/* * Hook for modifying the OS boot path. This hook allows us to handle * device arguments that the OS can't handle. */ void mangle_os_bootpath(char *bpath) { pnode_t node; char *stripped_pathname; node = prom_finddevice(bpath); if (prom_devicetype(node, "network") == 0) return; /* * The OS can't handle network device arguments * eg: boot net:promiscuous,speed=100,duplex=full * So, we remove any argument strings in the device * pathname we hand off to the OS for network devices. * * Internally, within boot, bpath is used to access * the device, but v2path (as the boot property "boot-path") * is the pathname passed to the OS. */ stripped_pathname = kmem_alloc(OBP_MAXPATHLEN, 0); prom_strip_options(bpath, stripped_pathname); v2path = stripped_pathname; }
/* * On ms-IIep all the interrupt registers, counters etc * are PCIC registers, so we need to map it early. */ static void bootstrapIIep(void) { extern struct sparc_bus_space_tag mainbus_space_tag; int node; bus_space_handle_t bh; pcireg_t id; if ((node = prom_opennode("/pci")) == 0 && (node = prom_finddevice("/pci")) == 0) panic("bootstrap: could not get pci " "node from prom"); if (bus_space_map2(&mainbus_space_tag, (bus_addr_t)MSIIEP_PCIC_PA, (bus_size_t)sizeof(struct msiiep_pcic_reg), BUS_SPACE_MAP_LINEAR, MSIIEP_PCIC_VA, &bh) != 0) panic("bootstrap: unable to map ms-IIep pcic registers"); /* verify that it's PCIC */ id = mspcic_read_4(pcic_id); if (PCI_VENDOR(id) != PCI_VENDOR_SUN && PCI_PRODUCT(id) != PCI_PRODUCT_SUN_MS_IIep) panic("bootstrap: PCI id %08x", id); }
static void __init read_obp_memory(const char *property, struct linux_prom64_registers *regs, int *num_ents) { int node = prom_finddevice("/memory"); int prop_size = prom_getproplen(node, property); int ents, ret, i; ents = prop_size / sizeof(struct linux_prom64_registers); if (ents > MAX_BANKS) { prom_printf("The machine has more %s property entries than " "this kernel can support (%d).\n", property, MAX_BANKS); prom_halt(); } ret = prom_getproperty(node, property, (char *) regs, prop_size); if (ret == -1) { prom_printf("Couldn't get %s property from /memory.\n"); prom_halt(); } /* Sanitize what we got from the firmware, by page aligning * everything. */ for (i = 0; i < ents; i++) { unsigned long base, size; base = regs[i].phys_addr; size = regs[i].reg_size; size &= PAGE_MASK; if (base & ~PAGE_MASK) { unsigned long new_base = PAGE_ALIGN(base); size -= new_base - base; if ((long) size < 0L) size = 0UL; base = new_base; } if (size == 0UL) { /* If it is empty, simply get rid of it. * This simplifies the logic of the other * functions that process these arrays. */ memmove(®s[i], ®s[i + 1], (ents - i - 1) * sizeof(regs[0])); i--; ents--; continue; } regs[i].phys_addr = base; regs[i].reg_size = size; } *num_ents = ents; sort(regs, ents, sizeof(struct linux_prom64_registers), cmp_p64, NULL); }
enum prom_output_device prom_query_output_device() { int st_p; char propb[64]; int propl; st_p = prom_inst2pkg(prom_stdout); propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb)); if (propl >= 0 && propl == sizeof("display") && strncmp("display", propb, sizeof("display")) == 0) return PROMDEV_OSCREEN; if(strncmp("serial", propb, 6)) return PROMDEV_O_UNK; /* FIXME: Is there any better way how to find out? */ memset(propb, 0, sizeof(propb)); st_p = prom_finddevice ("/options"); prom_getproperty(st_p, "output-device", propb, sizeof(propb)); /* * If we get here with propb == 'screen', we are on ttya, as * the PROM defaulted to this due to 'no input device'. */ if (!strncmp(propb, "screen", 6)) return PROMDEV_OTTYA; if (strncmp (propb, "tty", 3) || !propb[3]) return PROMDEV_O_UNK; switch (propb[3]) { case 'a': return PROMDEV_OTTYA; case 'b': return PROMDEV_OTTYB; default: return PROMDEV_O_UNK; } }
/* Query for input device type */ enum prom_input_device prom_query_input_device() { int st_p; char propb[64]; st_p = prom_inst2pkg(prom_stdin); if(prom_node_has_property(st_p, "keyboard")) return PROMDEV_IKBD; prom_getproperty(st_p, "device_type", propb, sizeof(propb)); if(strncmp(propb, "serial", 6)) return PROMDEV_I_UNK; /* FIXME: Is there any better way how to find out? */ memset(propb, 0, sizeof(propb)); st_p = prom_finddevice ("/options"); prom_getproperty(st_p, "input-device", propb, sizeof(propb)); /* * If we get here with propb == 'keyboard', we are on ttya, as * the PROM defaulted to this due to 'no input device'. */ if (!strncmp(propb, "keyboard", 8)) return PROMDEV_ITTYA; if (strncmp (propb, "tty", 3) || !propb[3]) return PROMDEV_I_UNK; switch (propb[3]) { case 'a': return PROMDEV_ITTYA; case 'b': return PROMDEV_ITTYB; default: return PROMDEV_I_UNK; } }
/* * This routine returns B_TRUE if the bootpath corresponds to * IP over IB driver. * * The format of the bootpath for the IP over IB looks like * /pci@1f,700000/pci@1/ib@0:port=1,pkey=8001,protocol=ip * * The minor node portion "port=1,pkey=8001,protocol=ip" represents * IP over IB driver. */ static boolean_t netboot_over_ib(char *bootpath) { char *temp; boolean_t ret = B_FALSE; pnode_t node = prom_finddevice(bootpath); int len; char devicetype[OBP_MAXDRVNAME]; /* Is this IB node ? */ len = prom_getproplen(node, OBP_DEVICETYPE); if (len <= 1 || len >= OBP_MAXDRVNAME) return (B_FALSE); (void) prom_getprop(node, OBP_DEVICETYPE, (caddr_t)devicetype); if (strncmp("ib", devicetype, 2) == 0) { /* Check for proper IP over IB string */ if ((temp = strstr(bootpath, ":port=")) != NULL) { if ((temp = strstr(temp, ",pkey=")) != NULL) if ((temp = strstr(temp, ",protocol=ip")) != NULL) { ret = B_TRUE; } } } return (ret); }
void load_platform_drivers(void) { dev_info_t *dip; /* dip of the isa driver */ pnode_t nodeid; /* * Install ISA driver. This is required for the southbridge IDE * workaround - to reset the IDE channel during IDE bus reset. * Panic the system in case ISA driver could not be loaded or * any problem in accessing its pci config space. Since the register * to reset the channel for IDE is in ISA config space!. */ nodeid = prom_finddevice(ONTARIO_IDE_PATHNAME); if (nodeid == OBP_BADNODE) { return; } dip = e_ddi_hold_devi_by_path(ONTARIO_ISA_PATHNAME, 0); if (dip == NULL) { cmn_err(CE_PANIC, "Could not install the isa driver\n"); return; } if (pci_config_setup(dip, &isa_handle) != DDI_SUCCESS) { cmn_err(CE_PANIC, "Could not get the config space of isa\n"); return; } }
/* * Returns the nodeid of /options. * Returns OBP_BADNODE if it doesn't exist. */ pnode_t prom_optionsnode(void) { static pnode_t node; if (node == 0) node = prom_finddevice("/options"); return (node); }
void ibd_init(void) { pnode_t chosen; char *mtuprop = "ipib-frame-size"; char *bcastprop = "ipib-broadcast"; char *addrprop = "ipib-address"; char *cidprop = "client-id"; int cidlen; uint8_t dhcpcid[DHCP_MAX_CID_LEN]; mac_state.mac_addr_len = IPOIB_ADDRL; mac_state.mac_addr_buf = bkmem_alloc(mac_state.mac_addr_len); if (mac_state.mac_addr_buf == NULL) prom_panic("ibd_init: Cannot allocate memory."); chosen = prom_finddevice("/chosen"); if (chosen == OBP_NONODE || chosen == OBP_BADNODE) prom_panic("ibd_init: Cannot find /chosen."); if (prom_getprop(chosen, addrprop, (caddr_t)mac_state.mac_addr_buf) != IPOIB_ADDRL) prom_panic("ibd_init: Cannot find /chosen:ipib-address\n."); if (prom_getprop(chosen, bcastprop, (caddr_t)&ibdbroadcastaddr) != IPOIB_ADDRL) prom_panic("ibd_init: Cannot find /chosen:ipib-broadcast\n."); if (((cidlen = prom_getproplen(chosen, cidprop)) <= 0) || (cidlen > DHCP_MAX_CID_LEN) || (prom_getprop(chosen, cidprop, (caddr_t)&dhcpcid) != cidlen)) prom_panic("ibd_init: Invalid /chosen:client-id\n."); dhcp_set_client_id(dhcpcid, cidlen); /* * Note that prom reports mtu including 20 bytes of * addressing information. */ if (prom_getprop(chosen, mtuprop, (caddr_t)&mac_state.mac_mtu) <= 0) mac_state.mac_mtu = IBDSIZE + IPOIB_ADDRL; /* * Tell upper layers that we can support a little * more. We will be taking off these 20 bytes at * the start before we invoke prom_write() to send * over the wire. */ mac_state.mac_arp_timeout = IBD_ARP_TIMEOUT; mac_state.mac_in_timeout = IBD_IN_TIMEOUT; mac_state.mac_arp = ibd_arp; mac_state.mac_rarp = ibd_revarp; mac_state.mac_header_len = ibd_header_len; mac_state.mac_input = ibd_input; mac_state.mac_output = ibd_output; }
/* * Returns the nodeid of /aliases. * /aliases exists in OBP >= 2.4 and in Open Firmware. * Returns OBP_BADNODE if it doesn't exist. */ pnode_t prom_alias_node(void) { static pnode_t node; if (node == 0) node = prom_finddevice("/aliases"); return (node); }
void __init prom_init(void *cif_handler, void *cif_stack) { phandle node; prom_cif_init(cif_handler, cif_stack); prom_chosen_node = prom_finddevice(prom_chosen_path); if (!prom_chosen_node || (s32)prom_chosen_node == -1) prom_halt(); prom_stdout = prom_getint(prom_chosen_node, "stdout"); node = prom_finddevice("/openprom"); if (!node || (s32)node == -1) prom_halt(); prom_getstring(node, "version", prom_version, sizeof(prom_version)); prom_printf("\n"); }
int prom_get_mmu_ihandle(void) { int node, ret; if (prom_mmu_ihandle_cache != 0) return prom_mmu_ihandle_cache; node = prom_finddevice(prom_chosen_path); ret = prom_getint(node, prom_mmu_name); if (ret == -1 || ret == 0) prom_mmu_ihandle_cache = -1; else prom_mmu_ihandle_cache = ret; return ret; }
int prom_get_mmu_ihandle(void) { int node, ret; if (mmu_ihandle_cache != 0) return mmu_ihandle_cache; node = prom_finddevice("/chosen"); ret = prom_getint(node, "mmu"); if(ret == -1 || ret == 0) mmu_ihandle_cache = -1; else mmu_ihandle_cache = ret; return ret; }
static int prom_get_memory_ihandle(void) { static int memory_ihandle_cache; int node, ret; if (memory_ihandle_cache != 0) return memory_ihandle_cache; node = prom_finddevice("/chosen"); ret = prom_getint(node, "memory"); if (ret == -1 || ret == 0) memory_ihandle_cache = -1; else memory_ihandle_cache = ret; return ret; }
boolean_t is_netdev(char *devpath) { pnode_t node = prom_finddevice(devpath); char *options; if ((node == OBP_NONODE) || (node == OBP_BADNODE)) return (B_FALSE); if (prom_devicetype(node, "network") != 0) return (B_TRUE); /* * For Infiniband, network device names will be of the * format XXX/ib@0:port=1,pkey=1234,protocol=ip[,YYY] where * XXX is typically /pci@8,700000/pci@1. The device_type * property will be "ib". */ if (prom_devicetype(node, "ib") != 0) { options = prom_path_options(devpath); if (options != NULL) { #define SEARCHSTRING ",protocol=ip" #define SEARCHSTRLEN strlen(SEARCHSTRING) if (strstr(options, ",protocol=ip,") != NULL) return (B_TRUE); while ((options = strstr(options, SEARCHSTRING)) != NULL) { char nextc; nextc = options[SEARCHSTRLEN]; if ((nextc == ',') || (nextc == 0)) return (B_TRUE); options += SEARCHSTRLEN; } } } return (B_FALSE); }
static int match_arch(const char *name) { static prom_handle root; static char model[256], *p; if (!root) { if (!(root = prom_finddevice("/"))) return 0; } if (!model[0]) { if (!prom_getprop(root, "compatible", model, sizeof(model))) return 0; } for (p = model; *p; p += strlen(p) + 1) { if (!strcasecmp(p, name)) return 1; } return 0; }
/* * Return the devinfo node to a boot device */ static dev_info_t * path_to_devinfo(char *path) { struct i_path_findnode fn; extern dev_info_t *top_devinfo; /* * Get the nodeid of the given pathname, if such a mapping exists. */ fn.dip = NULL; fn.nodeid = prom_finddevice(path); if (fn.nodeid != OBP_BADNODE) { /* * Find the nodeid in our copy of the device tree and return * whatever name we used to bind this node to a driver. */ ddi_walk_devs(top_devinfo, i_path_find_node, (void *)(&fn)); } #ifdef DEBUG /* * If we're bound to something other than the nodename, * note that in the message buffer and system log. */ if (fn.dip) { char *p, *q; p = ddi_binding_name(fn.dip); q = ddi_node_name(fn.dip); if (p && q && (strcmp(p, q) != 0)) { BMDPRINTF(("path_to_devinfo: %s bound to %s\n", path, p)); } } #endif /* DEBUG */ return (fn.dip); }
pnode_t prom_chosennode(void) { static pnode_t chosen; pnode_t node; if (chosen) return (chosen); node = prom_finddevice("/chosen"); if (node != OBP_BADNODE) return (chosen = node); prom_fatal_error("prom_chosennode: Can't find </chosen>\n"); /*NOTREACHED*/ /* * gcc doesn't recognize "NOTREACHED" and puts the warning. * To surpress it, returning an integer value is required. */ return ((pnode_t)0); }
/*ARGSUSED*/ char * kmdb_prom_get_ddi_prop(kmdb_auxv_t *kav, char *propname) { pnode_t node; ssize_t len; char *val; if ((node = prom_finddevice("/options")) == NULL) return (NULL); if ((len = prom_getproplen(node, propname)) < 0) return (NULL); val = mdb_alloc(len + 1, UM_SLEEP); if (prom_bounded_getprop(node, propname, val, len) != len) { mdb_free(val, len); return (NULL); } val[len] = '\0'; return (val); }
/* * translate a devfs pathname to one that will be acceptable * by the prom. In most cases, there is no translation needed. * For systems supporting generically named devices, the prom * may support nodes such as 'disk' that do not have any unit * address information (i.e. target,lun info). If this is the * case, the ddi framework will reject the node as invalid and * populate the devinfo tree with nodes froms the .conf file * (e.g. sd). In this case, the names that show up in /devices * are sd - since the prom only knows about 'disk' nodes, this * routine detects this situation and does the conversion * There are also cases such as pluto where the disk node in the * prom is named "SUNW,ssd" but in /devices the name is "ssd". * * If MPxIO is enabled, the translation involves following * pathinfo nodes to the "best" parent. * * return a 0 on success with the new device string in ret_buf. * Otherwise return the appropriate error code as we may be called * from the openprom driver. */ int i_devname_to_promname(char *dev_name, char *ret_buf, size_t len) { dev_info_t *dip, *pdip, *cdip, *alt_dip = NULL; mdi_pathinfo_t *pip = NULL; char *dev_path, *prom_path; char *unit_address, *minorname, *nodename; major_t major; char *rptr, *optr, *offline; size_t olen, rlen; int circ; int ret = 0; /* do some sanity checks */ if ((dev_name == NULL) || (ret_buf == NULL) || (strlen(dev_name) > MAXPATHLEN)) { return (EINVAL); } /* * Convert to a /devices name. Fail the translation if * the name doesn't exist. */ dev_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); if (resolve_devfs_name(dev_name, dev_path) != 0 || strncmp(dev_path, "/devices/", 9) != 0) { kmem_free(dev_path, MAXPATHLEN); return (EINVAL); } dev_name = dev_path + sizeof ("/devices") - 1; bzero(ret_buf, len); if (prom_finddevice(dev_name) != OBP_BADNODE) { /* we are done */ (void) snprintf(ret_buf, len, "%s", dev_name); kmem_free(dev_path, MAXPATHLEN); return (0); } /* * if we get here, then some portion of the device path is * not understood by the prom. We need to look for alternate * names (e.g. replace ssd by disk) and mpxio enabled devices. */ dip = e_ddi_hold_devi_by_path(dev_name, 0); if (dip == NULL) { cmn_err(CE_NOTE, "cannot find dip for %s", dev_name); kmem_free(dev_path, MAXPATHLEN); return (EINVAL); } prom_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); rlen = len; rptr = ret_buf; if (!MDI_CLIENT(dip)) { ret = i_devi_to_promname(dip, prom_path, &alt_dip); if (ret == 0) { minorname = strrchr(dev_name, ':'); if (minorname && (minorname[1] != '\0')) { (void) strcat(prom_path, minorname); } (void) snprintf(rptr, rlen, "%s", prom_path); } } else { /* * if get to here, means dip is a vhci client */ offline = kmem_zalloc(len, KM_SLEEP); /* offline paths */ olen = len; optr = offline; /* * The following code assumes that the phci client is at leaf * level. */ ndi_devi_enter(dip, &circ); while ((pip = mdi_get_next_phci_path(dip, pip)) != NULL) { /* * walk all paths associated to the client node */ bzero(prom_path, MAXPATHLEN); /* * replace with mdi_hold_path() when mpxio goes into * genunix */ MDI_PI_LOCK(pip); MDI_PI_HOLD(pip); MDI_PI_UNLOCK(pip); if (mdi_pi_pathname_obp(pip, prom_path) != NULL) { /* * The path has different obp path */ goto minor_pathinfo; } pdip = mdi_pi_get_phci(pip); ndi_hold_devi(pdip); /* * Get obp path name of the phci node firstly. * NOTE: if the alternate node of pdip exists, * the third argument of the i_devi_to_promname() * would be set to the alternate node. */ (void) i_devi_to_promname(pdip, prom_path, &alt_dip); if (alt_dip != NULL) { ndi_rele_devi(pdip); pdip = alt_dip; ndi_hold_devi(pdip); } nodename = ddi_node_name(dip); unit_address = MDI_PI(pip)->pi_addr; major = ddi_driver_major(dip); cdip = find_alternate_node(pdip, major); if (cdip) { nodename = ddi_node_name(cdip); } /* * node name + unitaddr to the prom_path */ (void) strcat(prom_path, "/"); (void) strcat(prom_path, nodename); if (unit_address && (*unit_address)) { (void) strcat(prom_path, "@"); (void) strcat(prom_path, unit_address); } if (cdip) { /* hold from find_alternate_node */ ndi_rele_devi(cdip); } ndi_rele_devi(pdip); minor_pathinfo: minorname = strrchr(dev_name, ':'); if (minorname && (minorname[1] != '\0')) { (void) strcat(prom_path, minorname); } if (MDI_PI_IS_ONLINE(pip)) { (void) snprintf(rptr, rlen, "%s", prom_path); rlen -= strlen(rptr) + 1; rptr += strlen(rptr) + 1; if (rlen <= 0) /* drop paths we can't store */ break; } else { /* path is offline */ (void) snprintf(optr, olen, "%s", prom_path); olen -= strlen(optr) + 1; if (olen > 0) /* drop paths we can't store */ optr += strlen(optr) + 1; } MDI_PI_LOCK(pip); MDI_PI_RELE(pip); if (MDI_PI(pip)->pi_ref_cnt == 0) cv_broadcast(&MDI_PI(pip)->pi_ref_cv); MDI_PI_UNLOCK(pip); } ndi_devi_exit(dip, circ); ret = 0; if (rlen > 0) { /* now add as much of offline to ret_buf as possible */ bcopy(offline, rptr, rlen); } kmem_free(offline, len); } /* release hold from e_ddi_hold_devi_by_path() */ ndi_rele_devi(dip); ret_buf[len - 1] = '\0'; ret_buf[len - 2] = '\0'; kmem_free(dev_path, MAXPATHLEN); kmem_free(prom_path, MAXPATHLEN); return (ret); }
/* * SunOS and Solaris /dev/openprom ioctl calls. */ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg, int node) { DATA *data = (DATA *) file->private_data; char buffer[OPROMMAXPARAM+1], *buf; struct openpromio *opp; unsigned long flags; int bufsize, len, error = 0; extern char saved_command_line[]; static int cnt; if (cmd == OPROMSETOPT) bufsize = getstrings((void *)arg, &opp); else bufsize = copyin((void *)arg, &opp); if (bufsize < 0) return bufsize; switch (cmd) { case OPROMGETOPT: case OPROMGETPROP: save_and_cli(flags); len = prom_getproplen(node, opp->oprom_array); restore_flags(flags); if (len <= 0 || len > bufsize) { error = copyout((void *)arg, opp, sizeof(int)); break; } save_and_cli(flags); len = prom_getproperty(node, opp->oprom_array, buffer, bufsize); restore_flags(flags); memcpy(opp->oprom_array, buffer, len); opp->oprom_array[len] = '\0'; opp->oprom_size = len; error = copyout((void *)arg, opp, sizeof(int) + bufsize); break; case OPROMNXTOPT: case OPROMNXTPROP: save_and_cli(flags); buf = prom_nextprop(node, opp->oprom_array, buffer); restore_flags(flags); len = strlen(buf); if (len == 0 || len + 1 > bufsize) { error = copyout((void *)arg, opp, sizeof(int)); break; } memcpy(opp->oprom_array, buf, len); opp->oprom_array[len] = '\0'; opp->oprom_size = ++len; error = copyout((void *)arg, opp, sizeof(int) + bufsize); break; case OPROMSETOPT: case OPROMSETOPT2: buf = opp->oprom_array + strlen(opp->oprom_array) + 1; len = opp->oprom_array + bufsize - buf; save_and_cli(flags); error = prom_setprop(options_node, opp->oprom_array, buf, len); restore_flags(flags); if (error < 0) error = -EINVAL; break; case OPROMNEXT: case OPROMCHILD: case OPROMSETCUR: if (bufsize < sizeof(int)) { error = -EINVAL; break; } node = *((int *) opp->oprom_array); save_and_cli(flags); switch (cmd) { case OPROMNEXT: node = __prom_getsibling(node); break; case OPROMCHILD: node = __prom_getchild(node); break; case OPROMSETCUR: break; } restore_flags(flags); data->current_node = node; *((int *)opp->oprom_array) = node; opp->oprom_size = sizeof(int); error = copyout((void *)arg, opp, bufsize + sizeof(int)); break; case OPROMPCI2NODE: error = -EINVAL; if (bufsize >= 2*sizeof(int)) { #ifdef CONFIG_PCI struct pci_dev *pdev; struct pcidev_cookie *pcp; pdev = pci_find_slot (((int *) opp->oprom_array)[0], ((int *) opp->oprom_array)[1]); pcp = pdev->sysdata; if (pcp != NULL && pcp->prom_node != -1 && pcp->prom_node) { node = pcp->prom_node; data->current_node = node; *((int *)opp->oprom_array) = node; opp->oprom_size = sizeof(int); error = copyout((void *)arg, opp, bufsize + sizeof(int)); } #endif } break; case OPROMPATH2NODE: save_and_cli(flags); node = prom_finddevice(opp->oprom_array); restore_flags(flags); data->current_node = node; *((int *)opp->oprom_array) = node; opp->oprom_size = sizeof(int); error = copyout((void *)arg, opp, bufsize + sizeof(int)); break; case OPROMGETBOOTARGS: buf = saved_command_line; len = strlen(buf); if (len > bufsize) { error = -EINVAL; break; } strcpy(opp->oprom_array, buf); opp->oprom_size = len; error = copyout((void *)arg, opp, bufsize + sizeof(int)); break; case OPROMU2P: case OPROMGETCONS: case OPROMGETFBNAME: if (cnt++ < 10) printk(KERN_INFO "openprom_sunos_ioctl: unimplemented ioctl\n"); error = -EINVAL; break; default: if (cnt++ < 10) printk(KERN_INFO "openprom_sunos_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg); error = -EINVAL; break; } kfree(opp); return error; }
int openpromioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) { struct opiocdesc *op; int node, optionsnode, len, ok, error, s; char *name, *value, *nextprop; optionsnode = prom_getoptionsnode(); /* All too easy... */ if (cmd == OPIOCGETOPTNODE) { *(int *)data = optionsnode; return (0); } /* Verify node id */ op = (struct opiocdesc *)data; node = op->op_nodeid; if (node != 0 && node != lastnode && node != optionsnode) { /* Not an easy one, must search for it */ s = splhigh(); ok = openpromcheckid(findroot(), node); splx(s); if (!ok) return (EINVAL); lastnode = node; } name = value = NULL; error = 0; switch (cmd) { case OPIOCGET: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; s = splhigh(); len = prom_proplen(node, name); splx(s); if (len > op->op_buflen) { error = ENOMEM; break; } op->op_buflen = len; /* -1 means no entry; 0 means no value */ if (len <= 0) break; value = malloc(len, M_TEMP, M_WAITOK); s = splhigh(); error = prom_getprop(node, name, 1, &len, &value); splx(s); if (error != 0) break; error = copyout(value, op->op_buf, len); break; case OPIOCSET: if ((flags & FWRITE) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; error = openpromgetstr(op->op_buflen, op->op_buf, &value); if (error) break; s = splhigh(); len = prom_setprop(node, name, value, op->op_buflen + 1); splx(s); if (len != op->op_buflen) error = EINVAL; break; case OPIOCNEXTPROP: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; s = splhigh(); nextprop = prom_nextprop(node, name); splx(s); len = strlen(nextprop); if (len > op->op_buflen) len = op->op_buflen; else op->op_buflen = len; error = copyout(nextprop, op->op_buf, len); break; case OPIOCGETNEXT: if ((flags & FREAD) == 0) return (EBADF); s = splhigh(); node = nextsibling(node); splx(s); *(int *)data = lastnode = node; break; case OPIOCGETCHILD: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); s = splhigh(); node = firstchild(node); splx(s); *(int *)data = lastnode = node; break; case OPIOCFINDDEVICE: if ((flags & FREAD) == 0) return (EBADF); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; node = prom_finddevice(name); if (node == 0 || node == -1) { error = ENOENT; break; } op->op_nodeid = lastnode = node; break; default: return (ENOTTY); } if (name) free(name, M_TEMP); if (value) free(value, M_TEMP); return (error); }
static void get_bootpath_from_prom(void) { struct btinfo_bootdev *bdev = NULL; char sbuf[OFPATHLEN], *cp; int chosen; /* * Grab boot path from PROM */ if ((chosen = OF_finddevice("/chosen")) == -1) return; bdev = lookup_bootinfo(BTINFO_BOOTDEV); if (bdev != NULL) { strcpy(ofbootpath, bdev->name); } else { if (OF_getprop(chosen, "bootpath", sbuf, sizeof(sbuf)) < 0) return; strcpy(ofbootpath, sbuf); } DPRINTF(ACDB_BOOTDEV, ("bootpath: %s\n", ofbootpath)); ofbootpackage = prom_finddevice(ofbootpath); /* * Strip partition or boot protocol */ cp = strrchr(ofbootpath, ':'); if (cp) { *cp = '\0'; ofbootpartition = cp+1; } cp = strrchr(ofbootpath, '@'); if (cp) { for (; cp != ofbootpath; cp--) { if (*cp == '/') { ofboottarget = cp+1; break; } } } DPRINTF(ACDB_BOOTDEV, ("bootpath phandle: 0x%x\n", ofbootpackage)); DPRINTF(ACDB_BOOTDEV, ("boot target: %s\n", ofboottarget ? ofboottarget : "<none>")); DPRINTF(ACDB_BOOTDEV, ("boot partition: %s\n", ofbootpartition ? ofbootpartition : "<none>")); /* Setup pointer to boot flags */ if (OF_getprop(chosen, "bootargs", sbuf, sizeof(sbuf)) == -1) return; strcpy(ofbootargs, sbuf); cp = ofbootargs; /* Find start of boot flags */ while (*cp) { while(*cp == ' ' || *cp == '\t') cp++; if (*cp == '-' || *cp == '\0') break; while(*cp != ' ' && *cp != '\t' && *cp != '\0') cp++; if (*cp != '\0') *cp++ = '\0'; } if (cp != ofbootargs) ofbootfile = ofbootargs; ofbootflags = cp; if (*cp != '-') return; for (;*++cp;) { int fl; fl = 0; BOOT_FLAG(*cp, fl); if (!fl) { printf("unknown option `%c'\n", *cp); continue; } boothowto |= fl; /* specialties */ if (*cp == 'd') { #if defined(KGDB) kgdb_break_at_attach = 1; #elif defined(DDB) Debugger(); #else printf("kernel has no debugger\n"); #endif } else if (*cp == 't') { /* turn on traptrace w/o breaking into kdb */ extern int trap_trace_dis; trap_trace_dis = 0; } } }
void __init prom_init(void *cif_handler, void *cif_stack) { char buffer[80], *p; int ints[3]; int node; int i = 0; int bufadjust; prom_vers = PROM_P1275; prom_cif_init(cif_handler, cif_stack); prom_root_node = prom_getsibling(0); if((prom_root_node == 0) || (prom_root_node == -1)) prom_halt(); prom_chosen_node = prom_finddevice("/chosen"); if (!prom_chosen_node || prom_chosen_node == -1) prom_halt(); prom_stdin = prom_getint (prom_chosen_node, "stdin"); prom_stdout = prom_getint (prom_chosen_node, "stdout"); node = prom_finddevice("/openprom"); if (!node || node == -1) prom_halt(); prom_getstring (node, "version", buffer, sizeof (buffer)); prom_printf ("\n"); if (strncmp (buffer, "OBP ", 4)) goto strange_version; /* * Version field is expected to be 'OBP xx.yy.zz date...' * However, Sun can't stick to this format very well, so * we need to check for 'OBP xx.yy.zz date...' and adjust * accordingly. -spot */ if (strncmp (buffer, "OBP ", 5)) bufadjust = 4; else bufadjust = 5; p = buffer + bufadjust; while (p && isdigit(*p) && i < 3) { ints[i++] = simple_strtoul(p, NULL, 0); if ((p = strchr(p, '.')) != NULL) p++; } if (i != 3) goto strange_version; prom_rev = ints[1]; prom_prev = (ints[0] << 16) | (ints[1] << 8) | ints[2]; printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + bufadjust); prom_meminit(); /* Initialization successful. */ return; strange_version: prom_printf ("Strange OBP version `%s'.\n", buffer); prom_halt (); }
/* * On sun4ms we have to do some nasty stuff here. We need to map * in the interrupt registers (since we need to find out where * they are from the PROM, since they aren't in a fixed place), and * disable all interrupts. We can't do this easily from locore * since the PROM is ugly to use from assembly. We also need to map * in the counter registers because we can't disable the level 14 * (statclock) interrupt, so we need a handler early on (ugh). * * NOTE: We *demand* the psl to stay at splhigh() at least until * we get here. The system _cannot_ take interrupts until we map * the interrupt registers. */ static void bootstrap4m(void) { int node; int nvaddrs, *vaddrs, vstore[10]; u_int pte; int i; extern void setpte4m(u_int, u_int); if ((node = prom_opennode("/obio/interrupt")) == 0 && (node = prom_finddevice("/obio/interrupt")) == 0) panic("bootstrap: could not get interrupt " "node from prom"); vaddrs = vstore; nvaddrs = sizeof(vstore)/sizeof(vstore[0]); if (prom_getprop(node, "address", sizeof(int), &nvaddrs, &vaddrs) != 0) { printf("bootstrap: could not get interrupt properties"); prom_halt(); } if (nvaddrs < 2 || nvaddrs > 5) { printf("bootstrap: cannot handle %d interrupt regs\n", nvaddrs); prom_halt(); } for (i = 0; i < nvaddrs - 1; i++) { pte = getpte4m((u_int)vaddrs[i]); if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE) { panic("bootstrap: PROM has invalid mapping for " "processor interrupt register %d",i); prom_halt(); } pte |= PPROT_S; /* Duplicate existing mapping */ setpte4m(PI_INTR_VA + (_MAXNBPG * i), pte); } cpuinfo.intreg_4m = (struct icr_pi *) (PI_INTR_VA + (_MAXNBPG * CPU_MID2CPUNO(bootmid))); /* * That was the processor register...now get system register; * it is the last returned by the PROM */ pte = getpte4m((u_int)vaddrs[i]); if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE) panic("bootstrap: PROM has invalid mapping for system " "interrupt register"); pte |= PPROT_S; setpte4m(SI_INTR_VA, pte); /* Now disable interrupts */ icr_si_bis(SINTR_MA); /* Send all interrupts to primary processor */ *((u_int *)ICR_ITR) = CPU_MID2CPUNO(bootmid); #ifdef DEBUG /* printf("SINTR: mask: 0x%x, pend: 0x%x\n", *(int*)ICR_SI_MASK, *(int*)ICR_SI_PEND); */ #endif }
void check_if_starfire(void) { int ssnode = prom_finddevice("/ssp-serial"); if (ssnode != 0 && ssnode != -1) this_is_starfire = 1; }
static void __init read_obp_memory(const char *property, struct linux_prom64_registers *regs, int *num_ents) { int node = prom_finddevice("/memory"); int prop_size = prom_getproplen(node, property); int ents, ret, i; ents = prop_size / sizeof(struct linux_prom64_registers); if (ents > MAX_BANKS) { prom_printf("The machine has more %s property entries than " "this kernel can support (%d).\n", property, MAX_BANKS); prom_halt(); } ret = prom_getproperty(node, property, (char *) regs, prop_size); if (ret == -1) { prom_printf("Couldn't get %s property from /memory.\n"); prom_halt(); } /* Sanitize what we got from the firmware, by page aligning * everything. */ for (i = 0; i < ents; i++) { unsigned long base, size; base = regs[i].phys_addr; size = regs[i].reg_size; size &= PAGE_MASK; if (base & ~PAGE_MASK) { unsigned long new_base = PAGE_ALIGN(base); size -= new_base - base; if ((long) size < 0L) size = 0UL; base = new_base; } regs[i].phys_addr = base; regs[i].reg_size = size; } for (i = 0; i < ents; i++) { if (regs[i].reg_size == 0UL) { int j; for (j = i; j < ents - 1; j++) { regs[j].phys_addr = regs[j+1].phys_addr; regs[j].reg_size = regs[j+1].reg_size; } ents--; i--; } } *num_ents = ents; sort(regs, ents, sizeof(struct linux_prom64_registers), cmp_p64, NULL); }
/* Initialize the memory lists based upon the prom version. */ void __init prom_meminit(void) { int node = 0; unsigned int iter, num_regs; node = prom_finddevice("/memory"); num_regs = prom_getproperty(node, "available", (char *) prom_reg_memlist, sizeof(prom_reg_memlist)); num_regs = (num_regs/sizeof(struct linux_prom64_registers)); for(iter=0; iter<num_regs; iter++) { prom_phys_avail[iter].start_adr = prom_reg_memlist[iter].phys_addr; prom_phys_avail[iter].num_bytes = prom_reg_memlist[iter].reg_size; prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1]; } prom_phys_avail[iter-1].theres_more = NULL; num_regs = prom_getproperty(node, "reg", (char *) prom_reg_memlist, sizeof(prom_reg_memlist)); num_regs = (num_regs/sizeof(struct linux_prom64_registers)); for(iter=0; iter<num_regs; iter++) { prom_phys_total[iter].start_adr = prom_reg_memlist[iter].phys_addr; prom_phys_total[iter].num_bytes = prom_reg_memlist[iter].reg_size; prom_phys_total[iter].theres_more = &prom_phys_total[iter+1]; } prom_phys_total[iter-1].theres_more = NULL; node = prom_finddevice("/virtual-memory"); num_regs = prom_getproperty(node, "available", (char *) prom_reg_memlist, sizeof(prom_reg_memlist)); num_regs = (num_regs/sizeof(struct linux_prom64_registers)); /* Convert available virtual areas to taken virtual * areas. First sort, then convert. */ for(iter=0; iter<num_regs; iter++) { prom_prom_taken[iter].start_adr = prom_reg_memlist[iter].phys_addr; prom_prom_taken[iter].num_bytes = prom_reg_memlist[iter].reg_size; prom_prom_taken[iter].theres_more = &prom_prom_taken[iter+1]; } prom_prom_taken[iter-1].theres_more = NULL; prom_sortmemlist(prom_prom_taken); /* Finally, convert. */ for(iter=0; iter<num_regs; iter++) { prom_prom_taken[iter].start_adr = prom_prom_taken[iter].start_adr + prom_prom_taken[iter].num_bytes; prom_prom_taken[iter].num_bytes = prom_prom_taken[iter+1].start_adr - prom_prom_taken[iter].start_adr; } prom_prom_taken[iter-1].num_bytes = -1UL - prom_prom_taken[iter-1].start_adr; /* Sort the other two lists. */ prom_sortmemlist(prom_phys_total); prom_sortmemlist(prom_phys_avail); /* Link all the lists into the top-level descriptor. */ prom_memlist.p1275_totphys=&prom_ptot_ptr; prom_memlist.p1275_prommap=&prom_ptak_ptr; prom_memlist.p1275_available=&prom_pavl_ptr; }