/* Miscelaneous functions Copyright (C) 1996 David Miller 1996 Pete A. Zaitcev 1996,1997 Jakub Jelinek This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 #include void silo_fatal(const char *msg) { printf("\nFatal error: %s\n", msg); } char *silo_v0_device(char *imagename) { if (((imagename[0] == 's' && strchr ("dt", imagename[1])) || (imagename[0] == 'x' && strchr ("dy", imagename[1])) || (imagename[0] == 'f' && imagename[1] == 'd') || (imagename[0] == 'l' && imagename[1] == 'e') || (imagename[0] == 'i' && imagename[1] == 'e')) && imagename[2] == '(') { return strchr (imagename, ')'); } else return 0; } char *seed_part_into_device (char *device, int part) { static char buffer[256]; strcpy (buffer, device); if (prom_vers != PROM_V0) { char *p = strchr (buffer, ':'); if (!p) { p = strchr (buffer, 0); *p++ = ':'; } else p++; *p++ = 'a' + part - 1; *p = 0; } else { int i = strlen (device); char *p; if (i >= 4 && buffer[2] == '(' && buffer[i - 1] == ')') { if (i == 4) { strcpy (buffer + 3, "0,0,"); buffer [7] = '0' + part - 1; strcpy (buffer + 8, ")"); } else { p = strchr (buffer + 3, ','); if (!p) { strcpy (buffer + i - 1, ",0,"); buffer [i + 2] = '0' + part - 1; strcpy (buffer + i + 3, ")"); } else { p = strchr (p + 1, ','); if (!p) { buffer [i - 1] = ','; buffer [i] = '0' + part - 1; strcpy (buffer + i + 1, ")"); } else { *p = '0' - part - 1; strcpy (p + 1, ")"); } } } } } return buffer; } static char barg_buf[1024]; char barg_out[1024]; void silo_set_bootargs(char *params, char *device) { char *q, *r; char **p; int iter, i; /* * We expect a kernel to extract a command line * from our dead body promptly, if the arguments are longer than 90 or so. */ if (params) { q = params; r = barg_out; /* Remove unnecessary spaces */ do { while (*q == ' ') q++; if (!*q) break; if (r != barg_out) *r++ = ' '; while (*q && *q != ' ') *r++ = *q++; } while (*q); *r = 0; } else *barg_out = 0; switch (prom_vers) { case PROM_V0: if (strlen (barg_out) > 100 - 12) { p = (*(romvec->pv_v0bootargs))->argv; p [0] = "silo()"; q = barg_out; for (iter = 1; iter < 7; iter++) { while (*q == ' ') q++; if (!*q) { p [iter] = 0; continue; } r = q; while (*r && *r != ' ') r++; if (!p[iter] || strlen (p[iter]) != r - q || strncmp (q, p[iter], r - q)) { if (*r) *r++ = 0; p [iter] = q; } q = r; } while (*q == ' ') q++; if (*q) p [7] = q; else p [7] = 0; return; } else { q = (*(romvec->pv_v0bootargs))->args; p = (*(romvec->pv_v0bootargs))->argv; p[0] = q; if (!device) { strcpy (q, "silo()"); q += 7; strcpy (q, barg_out); } else { strcpy (q, device); q = strchr (q, 0); strcpy (q, barg_out); r = strchr (q, ' '); if (!r) r = strchr (q, 0); else { *r = 0; r++; } (*(romvec->pv_v0bootargs))->kernel_file_name = q; (*(romvec->pv_v0bootargs))->boot_dev[0] = device[0]; (*(romvec->pv_v0bootargs))->boot_dev[1] = device[1]; q = device + 3; i = 0; while (*q != ',' && *q != ')') { i = i * 10 + *q - '0'; q++; } if (*q == ',') q++; (*(romvec->pv_v0bootargs))->boot_dev_ctrl = i; i = 0; while (*q != ',' && *q != ')') { i = i * 10 + *q - '0'; q++; } if (*q == ',') q++; (*(romvec->pv_v0bootargs))->boot_dev_unit = i; i = 0; while (*q != ',' && *q != ')') { i = i * 10 + *q - '0'; q++; } (*(romvec->pv_v0bootargs))->dev_partition = i; q = r; } for (i = 1; i < 7; i++) { if (*q) { r = strchr (q, ' '); if (r) { *r = 0; r++; } else r = strchr (q, 0); p[i] = q; q = r; } else p[i] = 0; } if (*q) p[7] = q; else p[7] = 0; return; } case PROM_V2: case PROM_V3: if (strlen (barg_out) < 128) strcpy (*romvec->pv_v2bootargs.bootargs, barg_out); else *romvec->pv_v2bootargs.bootargs = barg_out; if (device) strcpy (*romvec->pv_v2bootargs.bootpath, device); break; case PROM_P1275: break; } } char *silo_get_bootargs(int full) { int iter; char *cp, *q; char **p; switch (prom_vers) { case PROM_V0: p = (*(romvec->pv_v0bootargs))->argv; cp = barg_buf; *cp = 0; if (p [0]) { for (iter = 0; iter < 8; iter++) { q = p [iter]; if (q) { if (!iter && !full) { q = silo_v0_device(q); if (q && !q[1]) continue; else if (q) q++; else q = p [iter]; } strcpy (cp, q); cp += strlen (cp); *cp++ = ' '; } else break; } if (cp != barg_buf) cp[-1] = 0; } break; case PROM_V2: case PROM_V3: if (!full) q = barg_buf; else { strcpy (barg_buf, *romvec->pv_v2bootargs.bootpath); q = strchr (barg_buf, 0); } if (*romvec->pv_v2bootargs.bootargs) { if (full) *q++ = ' '; strcpy (q, *romvec->pv_v2bootargs.bootargs); } else if (!full) *q = 0; break; case PROM_P1275: if (!full) q = barg_buf; else { iter = prom_getproperty (prom_chosen, "bootpath", barg_buf, 510); if (iter != -1) if (iter && !barg_buf [iter - 1]) q = barg_buf + iter - 1; else q = barg_buf + iter; else q = barg_buf; } iter = prom_getproperty (prom_chosen, "bootargs", full ? q + 1 : q, 512); if (iter == -1 || !iter) *q = 0; else { if (full) *q = ' '; if (q [iter + 1]) q [iter + 1] = 0; } break; } return barg_buf; } void silo_show_bootargs(void) { printf("Kernel args: %s\n", silo_get_bootargs(0)); } unsigned char *silo_find_linux_HdrS(char *base, int len) { /* Ugly magic to find HdrS, we dig into first jmp gokernel */ char *p = base + ((*(unsigned short *) (base+2)) << 2) - 512; char *q; q = base+8; if (*q == 'H' && q[1] == 'd' && q[2] == 'r' && q[3] == 'S') return (unsigned char *)q; if (p >= base + len || p <= base) return 0; for (q = p + 512; p < q; p += 4) { if (*p == 'H' && p[1] == 'd' && p[2] == 'r' && p[3] == 'S') return (unsigned char *)p; } return 0; } static struct idp_struct idprm; /* Here is the master table of Sun machines which use some implementation * of the Sparc CPU and have a meaningful IDPROM machtype value that we * know about. See asm/machines.h for empirical constants. */ struct SMM { char *name; char *package; enum arch architecture; unsigned char id_machtype; } Machines[NUM_SUN_MACHINES] = { /* First, Sun4's */ { "Sun 4/100 Series", "sun4", sun4, (SM_SUN4 | SM_4_110) }, { "Sun 4/200 Series", "sun4", sun4, (SM_SUN4 | SM_4_260) }, { "Sun 4/300 Series", "sun4", sun4, (SM_SUN4 | SM_4_330) }, { "Sun 4/400 Series", "sun4", sun4, (SM_SUN4 | SM_4_470) }, /* Now, Sun4c's */ { "SparcStation 1", "SUNW,Sun_4_60", sun4c, (SM_SUN4C | SM_4C_SS1) }, { "SparcStation IPC", "SUNW,Sun_4_40", sun4c, (SM_SUN4C | SM_4C_IPC) }, { "SparcStation 1+", "SUNW,Sun_4_65", sun4c, (SM_SUN4C | SM_4C_SS1PLUS) }, { "SparcStation SLC", "SUNW,Sun_4_20", sun4c, (SM_SUN4C | SM_4C_SLC) }, { "SparcStation 2", "SUNW,Sun_4_75", sun4c, (SM_SUN4C | SM_4C_SS2) }, { "SparcStation ELC", "SUNW,Sun_4_25", sun4c, (SM_SUN4C | SM_4C_ELC) }, { "SparcStation IPX", "SUNW,Sun_4_50", sun4c, (SM_SUN4C | SM_4C_IPX) }, /* Finally, early Sun4m's */ { "SparcSystem 600", "SUNW,Sun_4_600", sun4m, (SM_SUN4M | SM_4M_SS60) }, { "SparcStation 10/20", "sun4m", sun4m, (SM_SUN4M | SM_4M_SS50) }, { "SparcStation 4/5", "sun4m", sun4m, (SM_SUN4M | SM_4M_SS40) }, /* One entry for the OBP arch's which are sun4d, sun4e, sun4u and newer sun4m's */ { "OBP based system", "sun4m", sun4m, (SM_SUN4M_OBP | 0x0) } }; char *get_systype(void) { static char system_name[128]; int i; for(i = 0; i < NUM_SUN_MACHINES; i++) if(Machines[i].id_machtype == idprm.id_machtype) { if(idprm.id_machtype!=(SM_SUN4M_OBP | 0x0)) return Machines[i].name; else { prom_getproperty(prom_root_node, "banner-name", system_name, sizeof(system_name)); return system_name; } } return "Unknown Sparc"; } char *get_syspackage(void) { static char system_name[128]; int i; *system_name = 0; prom_getproperty(prom_root_node, "name", system_name, sizeof(system_name)); if (*system_name) return system_name; for(i = 0; i < NUM_SUN_MACHINES; i++) if(Machines[i].id_machtype == idprm.id_machtype) { return Machines[i].package; } return "sun4c"; } void get_idprom(void) { prom_getproperty (prom_root_node, "idprom", (char *)&idprm, sizeof (idprm)); } void print_message (char *msg) { char *p = msg, *q = 0; int curly; int i; while (*p) { while (*p && *p != '$') p++; if (!*p) break; *p = 0; printf ("%s", msg); msg = p; *p++ = '$'; if ((curly = (*p == '{'))) p++; if (!strncmp (p, "ARCH", 4)) { switch (silo_get_architecture()) { case sun4: q = "SUN4"; break; case sun4c: q = "SUN4C"; break; case sun4d: q = "SUN4D"; break; case sun4m: q = "SUN4M"; break; case sun4e: q = "SUN4E"; break; case sun4p: q = "SUN4P"; break; case sun4u: q = "SUN4U"; break; default: break; } printf ("%s", q); p += 4; } else if (!strncmp (p, "PROM", 4)) { switch (prom_vers) { case PROM_V0: printf ("0"); break; case PROM_V2: printf ("2"); break; case PROM_V3: printf ("3"); break; case PROM_P1275: printf ("IEEE"); break; } p += 4; } else if (!strncmp (p, "ETHER", 5)) { for (i = 0; i < 6; i++) printf ("%x%x%s", ((unsigned char)idprm.id_eaddr[i]) >> 4, idprm.id_eaddr[i] & 0xf, i == 5 ? "" : ":"); p += 5; } else if (!strncmp (p, "SYSTYPE", 7)) { printf ("%s", get_systype ()); p += 7; } else continue; if (curly && *p == '}') p++; msg = p; } if (*msg) printf ("%s", msg); } void silo_set_prollargs(char *params, unsigned int kbase, int ksize) { struct silo_to_proll { char magic[4]; /* SiPR */ int kern_base; /* Always 256K so far. But who knows... */ int kern_size; int xxx; char kern_args[256]; } *p; int *v; /* * Old, bad way: * p = ((struct silo_to_proll *) 0x40000) - sizeof (struct silo_to_proll); * * New way allows to warn if PROLL is not cooperative. */ v = (int *) 0x4000; if (v[2] != 0x5377) { printf ("PROLL does not accept arguments\n"); return; } /* PROLL's base address is floating often. Mask the linking address off. */ p = (struct silo_to_proll *)(v[3] & (0x40000-1)); if (p->magic[0] != 'L' || p->magic[1] != 'R') { printf ("Bad magic in PROLL parameter"); return; } p->magic[0] = 'S'; p->magic[1] = 'i'; p->magic[2] = 'L'; p->magic[3] = 'o'; p->kern_base = kbase; /* Hopefuly >= 0x40000 */ p->kern_size = ksize; p->xxx = 0; strcpy(p->kern_args, params); } enum arch silo_get_architecture(void) { char buffer[] = "sun4c "; int i; if (prom_vers == PROM_P1275) { i = prom_getchild(prom_root_node); if ((i = prom_searchsiblings(i, "MicroSPARC-IIep")) != 0) { return sun4p; } buffer[4] = 'u'; } i = prom_getproperty (prom_root_node, "compatability", buffer, 8); if (!i || i == -1) i = prom_getproperty (prom_root_node, "compatible", buffer, 8); switch (buffer[4]) { case 'c': return sun4c; case 'm': return sun4m; case 'd': return sun4d; case 'e': return sun4e; case 'v': sun4v_cpu = 1; /* FALLTHRU */ case 'u': return sun4u; default: for(i = 0; i < NUM_SUN_MACHINES; i++) if(Machines[i].id_machtype == idprm.id_machtype) return Machines[i].architecture; return sununknown; } } .