/* Miscelaneous functions Copyright (C) 1996 David Miller 1996 Pete A. Zaitcev 1996 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "silo.h" #include #include void fatal (const char *msg) { printf ("\nFatal error: %s\n", msg); } char *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 (romvec->pv_romvers >= 2) { 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]; static char barg_out[1024]; void set_bootargs (struct linux_romvec *promvec, char *params, char *device) { char *q, *r, c; 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 (promvec->pv_romvers) { case 0: case 1: if (strlen (barg_out) > 100 - 12) { p = (*(promvec->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 = (*(promvec->pv_v0bootargs))->args; p = (*(promvec->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++; } (*(promvec->pv_v0bootargs))->kernel_file_name = q; (*(promvec->pv_v0bootargs))->boot_dev[0] = device[0]; (*(promvec->pv_v0bootargs))->boot_dev[1] = device[1]; q = device + 3; i = 0; while (*q != ',' && *q != ')') { i = i * 10 + *q - '0'; q++; } if (*q == ',') q++; (*(promvec->pv_v0bootargs))->boot_dev_ctrl = i; i = 0; while (*q != ',' && *q != ')') { i = i * 10 + *q - '0'; q++; } if (*q == ',') q++; (*(promvec->pv_v0bootargs))->boot_dev_unit = i; i = 0; while (*q != ',' && *q != ')') { i = i * 10 + *q - '0'; q++; } (*(promvec->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 2: case 3: if (strlen (barg_out) < 128) strcpy (*promvec->pv_v2bootargs.bootargs, barg_out); else *promvec->pv_v2bootargs.bootargs = barg_out; if (device) strcpy (*promvec->pv_v2bootargs.bootpath, device); break; } } char *get_bootargs (struct linux_romvec *promvec, int full) { int iter; char *cp, *q; char **p; switch (promvec->pv_romvers) { case 0: case 1: p = (*(promvec->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 = 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 2: case 3: if (!full) q = barg_buf; else { strcpy (barg_buf, *promvec->pv_v2bootargs.bootpath); q = strchr (barg_buf, 0); } if (*promvec->pv_v2bootargs.bootargs) { if (full) *q++ = ' '; strcpy (q, *promvec->pv_v2bootargs.bootargs); } else if (!full) *q = 0; break; } return barg_buf; } void show_bootargs (struct linux_romvec *promvec) { printf ("Kernel args: %s\n", get_bootargs (promvec, 0)); } unsigned char *find_linux_HdrS (int len) { /* Ugly magic to find HdrS, we dig into first jmp gokernel */ char *p = (char *) 0x4000 + ((*(unsigned short *) 0x4002) << 2) - 512; char *q; if (p >= (char *) 0x4000 + len || p <= (char *) 0x4000) return 0; for (q = p + 512; p < q; p += 4) { if (*p == 'H' && p[1] == 'd' && p[2] == 'r' && p[3] == 'S') return 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, 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; int curly; int i; for (;;) { while (*p && *p != '$') p++; if (*p == '$') { *p = 0; printf ("%s", msg); msg = p; *p++ = '$'; curly = (*p == '{'); if (curly) p++; if (!strncmp (p, "ARCH", 4)) { switch (get_architecture (romvec)) { 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 sun4u: q = "SUN4U"; break; } printf ("%s", q); p += 4; } else if (!strncmp (p, "PROM", 4)) { printf ("%d", romvec->pv_romvers); 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; } else { printf ("%s", msg); break; } } } enum arch get_architecture (struct linux_romvec *promvec) { char *buffer = "sun4c "; int 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 '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; } }