/********************************************************************** * Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. * * All Rights Reserved. * * Reference "/usr/src/COPYRIGHT" for applicable restrictions. * **********************************************************************/ /* * SCCSID: @(#)boot.c 3.2 7/11/87 * * ULTRIX-11 V2.1 stand-alone bootstrap (Boot:) * * Boot is loaded into low memory by the primary bootstrap * and started via jump to location zero. * It then relocates itelf to hi memory (64 kw boundry) * and executes in hi memory in user mode. * The files to be booted are loaded into low memory * and executed in kernel mode. * The following types of files can be loaded: * * Type 407 - non separated I & D space * Standalone programs, such as scat, mkfs, & restor only. * Type 407 Unix files CANNOT be loaded ! * Type 411 - separated I & D space * Type 411 Unix files only ! * No type 411 standalone programs. * Type 430 - overlay files * Type 430 Unix overlay text files only ! * No type 430 standalone files. * Type 431 - Split I & D space overlay * No other type files can be loaded ! * * Fred Canter * * We now also have support for the following Unix files: * Type 450 - Non-split I & D, up to 15 overlays * Type 451 - Split I & D, up to 15 overlays * Support is #ifdef'ed with K450. BIGKERNEL must also be defined * to load these. With BIGKERNEL defined the overall size can be * up to 198Kb-0200, rather than 128K-0200. This also means you * need 256K to boot... * * Dave Borman */ #if defined(K450) && !defined(BIGKERNEL) #define BIGKERNEL #endif #include <sys/param.h> #include <sys/ino.h> #include <sys/inode.h> #include <sys/filsys.h> #include <sys/dir.h> #define SEP_ID /* so we get the right addr for KDSA6 in seg.h */ #include <sys/seg.h> #include <sys/tty.h> #include <sys/devmaj.h> #include <sys/conf.h> #include <sys/utsname.h> #include "ra_saio.h" #include "saio.h" #include <a.out.h> /* * These are defined in seg.h now. * #define KDSA6 ((physadr)0172374) * #define KISA6 ((physadr)0172354) */ #define KISD0 ((physadr)0172300) #define MAXNBUF 72 /* Maximum number of I/O buffers, if CPU has UB map */ /* Also defined in /usr/src/cmd/sysgen/sysgen.h */ struct nlist nl[] = { { "_el_prcw" }, #define X_EL_PRCW 0 { "_cputype" }, #define X_CPUTYPE 1 { "_sepid" }, #define X_SEPID 2 { "_maxmem" }, #define X_MAXMEM 3 { "_ubmaps" }, #define X_UBMAPS 4 { "_nmser" }, #define X_NMSER 5 { "_cdreg" }, #define X_CDREG 6 { "_rn_ssr3" }, #define X_RN_SSR3 7 { "_mmr3" }, #define X_MMR3 8 { "_cpereg" }, #define X_CPEREG 9 { "ova" }, #define X_OVA 10 { "_ndh11" }, #define X_NDH11 11 { "_dh11" }, #define X_DH11 12 { "_nkl11" }, #define X_NKL11 13 { "_ndl11" }, #define X_NDL11 14 { "_kl11" }, #define X_KL11 15 { "_dz_cnt" }, #define X_DZ_CNT 16 { "_dz_tty" }, #define X_DZ_TTY 17 { "_ntty" }, #define X_NTTY 18 { "_tty_ts" }, #define X_TTY_TS 19 { "_pbaddr" }, #define X_PBADDR 20 { "_nbuf" }, #define X_NBUF 21 { "_mb_end" }, #define X_MB_END 22 { "_nuh11" }, #define X_NUH11 23 { "_uh11" }, #define X_UH11 24 { "_io_csr" }, #define X_IO_CSR 25 { "_rootdev" }, #define X_ROOTDEV 26 { "_swapdev" }, #define X_SWAPDEV 27 { "_pipedev" }, #define X_PIPEDEV 28 { "_el_dev" }, #define X_EL_DEV 29 { "dmp_dn" }, #define X_DMP_DN 30 { "dmp_csr" }, #define X_DMP_CSR 31 { "dmp_rx" }, #define X_DMP_RX 32 { "_ub_end" }, #define X_UB_END 33 { "_bpaddr" }, #define X_BPADDR 34 { "_maplock" }, #define X_MAPLOCK 35 { "klin" }, #define X_KLIN 36 { "klou" }, #define X_KLOU 37 { "raio" }, #define X_RAIO 38 { "tsio" }, #define X_TSIO 39 { "uhin" }, #define X_UHIN 40 { "uhou" }, #define X_UHOU 41 { "dzin" }, #define X_DZIN 42 { "dzou" }, #define X_DZOU 43 { "_nodev" }, #define X_NODEV 44 { "_nulldev" }, #define X_NULLDEV 45 { "_bdevsw" }, #define X_BDEVSW 46 { "_cdevsw" }, #define X_CDEVSW 47 { "_icode" }, #define X_ICODE 48 { "_szicode" }, #define X_SZICODE 49 { "_generic" }, #define X_GENERIC 50 { "_swplo" }, #define X_SWPLO 51 { "_nswap" }, #define X_NSWAP 52 { "_el_sb" }, #define X_EL_SB 53 { "_el_nb" }, #define X_EL_NB 54 { "hkio" }, #define X_HKIO 55 { "hpio" }, #define X_HPIO 56 { "rlio" }, #define X_RLIO 57 { "rpio" }, #define X_RPIO 58 { "ovd" }, #define X_OVD 59 { "ovend" }, #define X_OVEND 60 { "tmio" }, #define X_TMIO 61 { "htio" }, #define X_HTIO 62 { "_nht" }, #define X_NHT 63 { "_nts" }, #define X_NTS 64 { "_ntm" }, #define X_NTM 65 { "_tk_ctid" }, #define X_TK_CTID 66 { "_nuda" }, #define X_NUDA 67 { "_nra" }, #define X_NRA 68 { "_ra_ctid" }, #define X_RA_CTID 69 { "tkio" }, #define X_TKIO 70 { "_utsname" }, #define X_UTSNAME 71 /*GMM*/ { "_ntk" }, #define X_NTK 72 { "" }, }; /* * "sepid" is set up by M.s and indicates the class * of CPU being used, i.e., seperate I & D space * or I space only. * * sepid = 1, for separate I & D space CPU's. * sepid = 0, for non-separate I & D space CPU's. * */ /* * WHEN BOOT LOADS SDLOAD * The following two variables are used to pass the boot device * ID from Boot: to sdload. Because both programs use M.s these * variables have the same address in both programs. * The boot device ID tells sdload where to find the boot and * stand-alone programs. * * WHEN SDLOAD LOADS BOOT * They contain the root device ID and kernel name and * cause Boot: to auto-boot ??(0,0)??unix. * ?? = rd, hp, hk, etc. * If boot not loaded by sdload they are zero. */ int sdl_bdn; /* two char device name (ht, ts, mt, rx, md, tk) */ int sdl_bdu; /* bood device unit number */ /* * WHEN BOOT LOADS SDLOAD * The following two variables are used to pass the load device ID * to sdload. This tells sdload where to find the root and /usr * file systems. The boot and load devices can be different, e.g., * for the ULCM-16, boot is the memory disk and load is the floppy. * Again, this kludge works because both programs use M.s, which * ensures that the addresses of the variables are the same in both * programs. * * WHEN SDLOAD LOADS BOOT * Sdload uses these locations to pass the load device ID back to boot. * This allows the gktape() routine to automatically select the type * of tape to be used when booting the generic kernel, just prior to * setup phase 1. The load device ID is ignored if it is invalid or * not a magtape. */ int sdl_ldn; int sdl_ldu; int bdcode; /* boot device type */ int bdunit; /* booted from unit number */ int bdmtil; /* mscp media type ID low */ int bdmtih; /* mscp media type ID high */ int bdcsr; /* boot device CSR address */ /* passed from block zero boot */ struct devsw *ldp; /* pointer to devsw entry for load device */ int ld_bmaj; /* Selected load device for generic kernel */ char gline[50]; /* holds magtape name, see gktape() */ int sepid; int ubmaps; int cputype; int cdreg; int nmser; unsigned maxmem; unsigned maxseg; int el_prcw; int rn_ssr3; int mmr3; int cpereg; int pbaddr; char line[100]; char bootfs[] = "??(#,0)unix\0"; /* auto-boot of unix */ char sdl_ld[] = "??(#,0)sdload\0"; /* Install command - load sdload */ char sdl_sap[20]; /* filled in later with ??(#,0)saprog */ char md_scf[] = "md(0,0)syscall\0"; char rx_scf[] = "rx(0,0)syscall\0"; char mt_scf[] = "ht(0,0)syscall\0"; char dk_scf[] = "hp(0,0)/sas/syscall\0"; #ifdef UMAX char init[] = "??(#,0)/etc/init\0"; #endif UMAX int magic; int saflags; /* SA program flag bits (see a.out.h) */ extern struct ra_drv ra_drv[3][4]; /* see ra_saio.h (size must be 3 by 4) */ int ra_openf[]; int rl_openf; int first; int helpmsg; int scload; /* syscall file loaded */ int sdlflag; /* sdload program, don't need syscall */ /* also, must pass boot device ID to sdload */ int rabflag; /* rabads program does not need syscall */ int autounit = 1; /* modify kernel to run on unit number booted from */ int autocsr = 1; /* modify kernel to use CSR from devsw[] entry */ #define CBSIZ 2048 /* Copy Buffer size */ #define CBCNT (512/(CBSIZ/512)) /* # of records to copy */ char copybuf[CBSIZ]; /* Buffer for copying to memory disk */ /* * Boot device type codes * Passed to Boot: form block zero boot via M.s */ #define BC_RA 2 #define BC_HP 3 #define BC_HK 4 #define BC_RL 5 #define BC_RP 6 #define BC_RK 7 #define BC_ML 8 #define BC_HT 9 #define BC_TS 10 #define BC_TM 11 #define BC_TK 12 /* * WARNING: * * The values in this structure MUST match those in sysgen. * See the sdfsl[] initialization in /usr/src/cmd/sysgen/sg_tab.c. * I will take the heat for not using a header file -- Fred Canter. * The reasons are: the structures are not exactly the same, * these values are only used when booting a generic kernel, and * I was pressed for time. * * CAUTION: * * The values for swplo and el_sb must not exceed 16 bit quantities, * mpti() has trouble loading a long. This is a safe kludge because * the values are small. * * System Disk File System Layout * * If, and only if, booting a generic kernel, these values are used * to set the root, pipe, swap, and error log devices, swap and error * log starting block number and length. * Three "hp" entries due to different disk types, code selects the * correct entry. Two "rd" entries for the same reason. */ struct sdfsl { char *sdf_type; /* ULTRIX-11 device menmonic */ char sdf_root; /* rootdev - disk partition */ char sdf_pipe; /* pipedev - disk partition */ char sdf_swap; /* swapdev - disk partition */ char sdf_elog; /* elogdev - disk partition */ unsigned sdf_swplo; /* swplo - swap area start block */ int sdf_nswap; /* nswap - swap area length */ unsigned sdf_elsb; /* el_sb - error log start block */ int sdf_elnb; /* el_nb - error log length */ } sdfsl[] = { "hk", 0, 0, 1, 1, 100, 2936, 0, 100, /* RK06/7 */ "hp", 0, 0, 2, 2, 200, 6070, 0, 200, /* RP04/5/6 */ "hp", 0, 0, 2, 2, 200, 5400, 0, 200, /* RM02/3 */ "hp", 0, 0, 2, 2, 300, 6388, 0, 300, /* RM05 */ "ra", 0, 0, 2, 2, 200, 6000, 0, 200, /* RA60/80/81 */ "rc", 0, 0, 1, 1, 200, 4000, 0, 200, /* RC25 */ "rd", 0, 0, 0, 0, 7500, 2200, 7460, 40, /* RD51 */ "rd", 0, 0, 2, 2, 100, 3000, 0, 100, /* RD32/52/53/54 */ "rd", 0, 0, 5, 5, 100, 3000, 0, 100, /* RD31 */ "rl", 0, 0, 0, 0, 8040, 2200, 8000, 40, /* RL01/2 */ "rp", 0, 0, 1, 1, 100, 3100, 0, 100, /* RP02/3 */ 0, }; /* * Boot options help message. */ char *options[] = { "", /* FARKLE: boot too big again!!!!! "To execute one of the boot options (listed below), enter the name", "of the option using only lowercase characters then press <RETURN>.", "SEE ALSO: Chapter 3 of the ULTRIX-11 System Management Guide.", " ULTRIX-11 Installation Guide.", "", "aus Enable/disable Auto Unit Select (default = enable)", " Allows booting of system from a disk drive other than unit", " zero (changes root device unit number in the booted kernel).", "", "acs Enable/disable Auto CSR Select (default = enable)", " Allows booting of disks with non standard CSR, by passing", " CSR from boot's device address table to the booted kernel.", "", "csr List and/or change a device's CSR address entry boot's", " device address table. Boot will prompt for device name.", "", "install Begin the auto-install procedure.", */ 0 }; char *gkt_help[] = { "You are booting a generic kernel. This kernel is configured with", "all possible software load devices. You need to specify which,", "if any, of the possible load devices you have. You should specify", "the device used to load the software from the distribution kit.", "", "If the system does not have a load device, just press <RETURN>.", "Otherwise, enter the ULTRIX-11 mnemonic for your load device:", "", " ht = TM02/3-TU16/TE16/TU77", " tm = TM11-TU10/TE10", " ts = TS11/TU80/TS05", " tk = TK50 (or TU81)", " rx = RX50", " rl = RL02", " rc = RC25", "", 0 }; main() { register struct devsw *dp; int i, j; int abflag; char *p; /* * Set the segflag for a 64k word boundry. */ #ifdef BIGKERNEL segflag = 3; #else BIGKERNEL segflag = 2; #endif BIGKERNEL /* * Check booted from device type and attempt to * auto-boot unix if possible. */ if(first == 0) { /* auto-boot first time thru only */ first++; /* * Load maxmem into the dv_csr field of the "md" * entry in the devsw[] table. This tells the memory * disk driver how much memory is available. * The maxmem value is set by the startup code (see M.s). */ for(i=0; devsw[i].dv_name; i++) if(match("md", devsw[i].dv_name)) break; if(devsw[i].dv_name != 0) devsw[i].dv_csr = maxmem; abflag = 1; if(sdl_bdn) { /* loaded by SDLOAD, auto-boot */ /* ??(#,0)unix */ bootfs[0] = sdl_bdn & 0177; bootfs[1] = (sdl_bdn >> 8) & 0177; bootfs[3] = sdl_bdu + '0'; goto boot; } } else abflag = 0; bootfs[3] = bdunit + '0'; /* All valid load devices fill in their name */ sdl_ld[0] = '?'; /* Say not booted from a valid load device */ sdl_ld[3] = bootfs[3]; switch(bdcode) { case BC_RA: /* UDA50, KDA50, RQDX, RC25 */ if((bdmtih == 022544) && ((bdmtil == 040063) || (bdmtil == 040064) || (bdmtil == 040065) || (bdmtil == 040040) || (bdmtil == 040066) || (bdmtil == 040037))) { bootfs[0] = 'r'; /* RD31/RD32/RD51/RD52/RD53/RD54 */ bootfs[1] = 'd'; } else if((bdmtih == 020144) && ((bdmtil == 030031) || (bdmtil == 031431))) { bootfs[0] = 'r'; /* RC25/RCF25 */ bootfs[1] = 'c'; sdl_ld[0] = 'r'; sdl_ld[1] = 'c'; } else if((bdmtih == 021244) && (bdmtil == 010074)) { bootfs[0] = 'r'; /* RA60 */ bootfs[1] = 'a'; } else if((bdmtih == 022544) && ((bdmtil == 010120) || (bdmtil == 010121))) { bootfs[0] = 'r'; /* RA80/RA81 */ bootfs[1] = 'a'; } else if((bdmtih == 022545) && ((bdmtil == 0100062) || (bdmtil == 0100041))) { sdl_ld[0] = 'r'; /* RX33/RX50 */ sdl_ld[1] = 'x'; bootfs[0] = 'r'; bootfs[1] = 'x'; abflag = 0; } else abflag = 0; break; case BC_HP: /* RM02/3/5, RP04/5/6 (first RH) */ bootfs[0] = 'h'; bootfs[1] = 'p'; break; case BC_HK: /* RK06/7 */ bootfs[0] = 'h'; bootfs[1] = 'k'; break; case BC_RL: /* RL01/2 */ bootfs[0] = 'r'; bootfs[1] = 'l'; sdl_ld[0] = 'r'; sdl_ld[1] = 'l'; break; case BC_RP: /* RP02/3 */ bootfs[0] = 'r'; bootfs[1] = 'p'; break; case BC_HT: /* TM02/3 */ abflag = 0; /* no auto-boot */ sdl_ld[0] = 'h'; sdl_ld[1] = 't'; bootfs[0] = 'h'; bootfs[1] = 't'; break; case BC_TS: /* TS11/TK25/TSV05/TU80 */ abflag = 0; /* no auto-boot */ sdl_ld[0] = 't'; sdl_ld[1] = 's'; bootfs[0] = 't'; bootfs[1] = 's'; break; case BC_TM: /* TM11 */ abflag = 0; /* no auto-boot */ sdl_ld[0] = 't'; sdl_ld[1] = 'm'; bootfs[0] = 't'; bootfs[1] = 'm'; break; case BC_TK: /* TK50/TU81 */ abflag = 0; /* no auto-boot */ sdl_ld[0] = 't'; sdl_ld[1] = 'k'; bootfs[0] = 't'; bootfs[1] = 'k'; break; case BC_RK: /* RK05 */ case BC_ML: /* ML11 */ /* FALL THROUGH */ default: /* no auto-boot */ abflag = 0; break; } boot: ctrlc(1); /* get rid of any extra CTRL/Cs */ ra_openf[0] = 0; ra_openf[1] = 0; ra_openf[2] = 0; rl_openf = 0; /* * Don't auto-boot RL02/RC25 distribution disks. * The magic cookie is a file called unix linked to boot, i.e., * unix will have a magic number of 0401 (stand-alone program), * which can't happen on a system disk. */ if(abflag && (bootfs[0]=='r') && ((bootfs[1]=='l')||(bootfs[1]=='c'))) { /* * If auto-booting via block zero boot, * use CSR passed from block zero boot via M.s. * If auto-booting via sdload, CSR is loaded by * sdload (devsw[] copied back). */ if(bdcsr && !sdl_bdn) { dp = (struct devsw *)dp_get(&bootfs); /* find CSR in devsw[] */ dp->dv_csr = bdcsr; } if((i = open(bootfs, 0)) >= 0) { if(getw(i) == 0401) abflag = 0; close(i); } } if((abflag == 0) && (helpmsg == 0)) { helpmsg++; printf("\n\nTo list options, type help then press <RETURN>"); } printf("\n\nBoot: "); if(abflag) { printf("%s", bootfs); printf(" (CTRL/C will abort auto-boot)\n"); for(j=0; bootfs[j]; j++) line[j] = bootfs[j]; /* * If auto-booting via block zero boot, * use CSR passed from block zero boot via M.s. * If auto-booting via sdload, CSR is loaded by * sdload (devsw[] copied back). */ if(bdcsr && !sdl_bdn) { dp = (struct devsw *)dp_get(&line); /* find CSR in devsw[] */ dp->dv_csr = bdcsr; } } else gets(line); if(line[0] == '\0') goto boot; if(cmds()) /* see if user typed a command (like csr) */ goto boot; i = open(line, 0); if(i < 0) { if(abflag) abflag = 0; goto boot; } if(ctrlc(0)) { /* CTRL/C abort */ abcancel: abflag = 0; goto boot; } if (copyunix(i)) goto abcancel; p = &line[7]; if(*p == '/') p++; if((abflag == 0) && (strcmp("unix", p) != 0) && ((magic == 0411) || (magic == 0430) || (magic == 0431) || (magic == 0450) || (magic == 0451))) { printf("\n\7\7\7WARNING:"); printf("\n The kernel must be named unix for proper "); printf("system operation!"); printf("\n Save the existing kernel, then rename %s to unix:",p); printf("\n # mv /unix /ounix"); printf("\n # mv /%s /unix or ln /%s /unix\n", p, p); } } copyunix(io) register io; { register addr,s; long totsiz; long phys; long ovaddr; unsigned phys_i; #ifndef K450 unsigned txtsiz,datsiz,bsssiz,ovsize; unsigned symsiz; unsigned ovsizes[8]; #else K450 unsigned txtsiz,datsiz,bsssiz; long ovsize; unsigned symsiz; unsigned maxov = 8; unsigned ovsizes[16]; #endif K450 int i,cnt; int pdr, psz; int sc; char *p; struct devsw *dp, *dpa; lseek(io, (off_t)0, 0); if(strcmp(&line[7], "boot") == 0) { /* loading boot from tape */ if((strncmp(line, "ht", 2) == 0) || (strncmp(line, "tm", 2) == 0) || (strncmp(line, "ts", 2) == 0) || (strncmp(line, "tk", 2) == 0)) for(i=0; i<512; i++) /* skip 2 MT boot blocks */ getw(io); } magic = getw(io); txtsiz = getw(io); datsiz = getw(io); bsssiz = getw(io); symsiz = getw(io); getw(io); /* a_entry (not used) */ saflags = getw(io); /* a_unused (see a.out.h) */ getw(io); /* ship over remainder of a.out header */ /* could be tape, use getw() instead of lseek */ switch (magic) { #ifdef BOOT411 case 0411: scload = 0; if(symsiz == 0) goto badst; if(nlist(line, nl) < 0) goto badnl; if(ctrlc(0)) goto errxit; if(nl[X_EL_PRCW].n_type == 0) goto badnl; /* * Print an error message if loading of a seperate * I and D space file is attempted on an I space * only CPU, such as 11/40. */ if(!sepid) { printf("\nCan't load sep I&D ( %o) files\n", magic); goto errxit; } /* * Check size of data segment, * it cannot be > 49088 bytes. * The size limit is 64 bytes less than * it could be in order to insure that there will * be an unmapped memory page just below the U block * in virtual data space. This allows for better * handling of stack overflow errors, stack has been * moved to below the user structure in the U block. */ if((datsiz + bsssiz) > 49088) { printf("\ndata segment too large (%d)\n", datsiz+bsssiz); goto errxit; } /* * DO NOT BOOT if the value of the symbol _mb_end * exists and is > 0120000, i.e., new buffers and * part of the protected data structures fall within * the forbidden zone. */ if (nl[X_MB_END].n_value > 0120000) goto mb_err; /* * DO NOT BOOT if _ub_end > (datsiz+8192), * data structures covered by the first unibus map * register are too large. */ if(ubmaps && (nl[X_UB_END].n_value > (datsiz+8192))) goto ub_err; /* * DO NOT BOOT if the processor has a unibus map * but the kernel is not configured to support it. * The symbol _maplock indicates map code included. */ if(ubmaps && (nl[X_MAPLOCK].n_type == 0)) goto ubm_err; #ifndef BIGKERNEL /* * When loading a seperate I and D space file, * move the kernel stack to the last 8 kb * section of the first 128 kb of memory. * This prevents the stack from overwriting unix. */ KDSA6->r[0] = 03600; #else BIGKERNEL KDSA6->r[0] = (segflag<<10) - 0200; #endif BIGKERNEL ssid(); /* Insure sep I & D space enabled */ setseg(0); if(ctrlc(0)) goto errxit; lseek(io, (long)(020+txtsiz), 0); for(addr=0; addr!=datsiz; addr+=2) { mtpi(getw(io),addr); } if(ctrlc(0)) goto errxit; clrseg(addr,bsssiz); setpar(); phys = (long)datsiz + (long)bsssiz + 63L; phys =/ 64; setseg((int)phys); if(ctrlc(0)) goto errxit; lseek(io, 020L, 0); for(addr=0; addr!=txtsiz; addr+=2) { mtpi(getw(io),addr); } if(ctrlc(0)) goto errxit; close(io); return(0); #endif BOOT411 #ifdef K450 case 0451: maxov = 16; #endif K450 case 0431: scload = 0; if(symsiz == 0) goto badst; if(nlist(line, nl) < 0) goto badnl; if(ctrlc(0)) goto errxit; if(nl[X_EL_PRCW].n_type == 0) goto badnl; /* * Print an error message if loading of a seperate * I and D space file is attempted on an I space * only CPU, such as 11/40. */ if(!sepid) { printf("\nCan't load sep I&D ( %o) files\n", magic); goto errxit; } /* * Check size of data segment, * it cannot be > 49088 bytes. * The size limit is 64 bytes less than * it could be in order to insure that there will * be an unmapped memory page just below the U block * in virtual data space. This allows for better * handling of stack overflow errors, stack has been * moved to below the user structure in the U block. */ if((datsiz + bsssiz) > 49088) { printf("\ndata segment too large (%d)\n", datsiz+bsssiz); goto errxit; } /* * DO NOT BOOT if the value of the symbol _mb_end * exists and is > 0120000, i.e., new buffers and * part of the protected data structures fall within * the forbidden zone. */ if (nl[X_MB_END].n_value > 0120000) goto mb_err; /* * DO NOT BOOT if _ub_end > (datsiz+8192), * data structures covered by the first unibus map * register are too large. */ if(ubmaps && (nl[X_UB_END].n_value > (datsiz+8192))) goto ub_err; /* * DO NOT BOOT if the processor has a unibus map * but the kernel is not configured to support it. * The symbol _maplock indicates map code included. */ if(ubmaps && (nl[X_MAPLOCK].n_type == 0)) goto ubm_err; /* * Check size of root text segment */ if(txtsiz < 0140000) { printf("\nRoot text segment too small (%u)\n", txtsiz); goto errxit; } if(txtsiz > 0160000) { printf("\nRoot text segment too large (%u)\n", txtsiz); goto errxit; } #ifndef BIGKERNEL /* * When loading a seperate I and D space file, * move the kernel stack to the last 8 kb * section of the first 128 kb of memory. * This prevents the stack from overwriting unix. */ KDSA6->r[0] = 03600; #else BIGKERNEL KDSA6->r[0] = (segflag<<10) - 0200; #endif BIGKERNEL ssid(); /* Insure sep I & D space enabled */ lseek(io, (long)020, 0); /* skip to overlay header */ #ifndef K450 for (i = 0, ovsize = 0; i < 8; i++) { #else K450 for (i = 0, ovsize = 0; i < maxov; i++) { #endif K450 ovsizes[i] = getw(io); ovsize += ovsizes[i]; } ovsize -= ovsizes[0]; if (ovsizes[0] > 020000) { printf("max overlay too big (0%o)\n", ovsizes[0]); goto errxit; } /* * DO NOT BOOT if the 0431 kernel is > 129024 bytes total, * this allows for a 2KB stack at the end of 128KB. */ totsiz = (long)datsiz+(long)bsssiz+(long)txtsiz; /* * If loading run time only kernel, only add size of * overlays actually loaded to total size. */ totsiz += (long)ovsize; #ifndef BIGKERNEL if(totsiz > 129024L) { #else BIGKERNEL /* max is 196096 bytes (512 byte kernel stack) */ if(totsiz > ((long)segflag<<16) - 01000) { #endif BIGKERNEL printf("\nTotal kernel size too large (%D)\n", totsiz); goto errxit; } setseg(0); if(ctrlc(0)) goto errxit; gktape(); /* If generic kernel, select magtape */ printf("\n%s: ", line); /* * Load data+bss segment at 0 */ printf("%u", datsiz+bsssiz); #ifndef K450 lseek(io, (long)(040L+(long)txtsiz+(long)ovsize), 0); #else K450 lseek(io, 020L + maxov * 2L + (long)txtsiz + ovsize, 0); #endif K450 for(addr=0; addr!=datsiz; addr+=2) mtpi(getw(io),addr); if(ctrlc(0)) goto errxit; clrseg(addr,bsssiz); setpar(); /* * Load root text segment */ phys = (long)datsiz + (long)bsssiz + 63L; phys &= ~077; setseg((int)(phys/64)); if(ctrlc(0)) goto errxit; printf("+%u", txtsiz); #ifndef K450 lseek(io, 040L, 0); #else K450 lseek(io, (020L + maxov * 2L), 0); #endif K450 for(addr=0; addr!=txtsiz; addr+=2) mtpi(getw(io),addr); /* * Load the overlay segments after * root text segment. */ phys += (long)txtsiz; #ifndef K450 lseek(io, (long)(040L+(long)txtsiz), 0); ovaddr = phys; for(i=1; i<8; i++) { #else K450 lseek(io, (020L + (maxov * 2L) +(long)txtsiz), 0); ovaddr = phys; for(i=1; i<maxov; i++) { #endif K450 setseg((int)(phys/64)); #ifndef BIGKERNEL KDSA6->r[0] = 03600; /* stack to end 128 kb */ /* not sure this is needed! */ #else BIGKERNEL KDSA6->r[0] = (segflag<<10) - 0200; #endif BIGKERNEL phys += ovsizes[i]; if(ctrlc(0)) goto errxit; if(ovsizes[i]) printf("+%u", ovsizes[i]); for(addr=0; addr<ovsizes[i]; addr += 2) mtpi(getw(io), addr); } printf("\n"); setseg(0); #ifndef BIGKERNEL KDSA6->r[0] = 03600; /* stack to end of 128 Kb */ #else BIGKERNEL KDSA6->r[0] = (segflag<<10) - 0200; #endif BIGKERNEL addr = nl[X_OVA].n_value; /* _ova is where overlay tables are */ #ifndef K450 for(i=0; i<8; i++) { #else K450 for(i=0; i<maxov; i++) { #endif K450 if(i == 0) mtpi(0, addr); else { mtpi((int)(ovaddr/64), addr); ovaddr += ovsizes[i]; } addr += 2; } #ifndef K450 for(i=0; i<8; i++) { /* overlay descriptor table */ #else K450 addr = nl[X_OVD].n_value; for(i=0; i<maxov; i++) { #endif K450 if(i && (ovsizes[i] != 0)) mtpi((((ovsizes[i]/64)-1)<<8) | RO, addr); else mtpi(0, addr); addr += 2; } #ifdef K450 addr = nl[X_OVEND].n_value; #endif K450 mtpi((int)(phys/64), addr); /* start of free memory */ phys = (long)datsiz + (long)bsssiz + 63L; phys &= ~077; setseg((int)(phys/64)); #ifndef BIGKERNEL KDSA6->r[0] = 03600; /* stack to end of 128 KB */ #else BIGKERNEL KDSA6->r[0] = (segflag<<10) - 0200; #endif BIGKERNEL if(ctrlc(0)) goto errxit; close(io); return(0); case 0401: /* all ULTRIX-11 stand alone programs are now 0401 */ case 0407: /* (hopefully) allow user written SA programs to run */ /* * If the file has a symbol table, assume it is unix * which can't be loaded. */ if(symsiz) { printf("\nCan't load ( %o) unix files\n", magic); goto errxit; } /* * If loading a 407 type file on a separate I & D space * type CPU, disable separate I & D space. */ if(sepid) { setseg(0); snsid(); /* disable sep I & D space */ } if(ctrlc(0)) goto errxit; /* * Check SA program load flags to see * if special loading needed. */ if(saflags & SA_SDLOAD) { sdlflag = 1; /* say loading sdload program */ /* save boot device ID to pass to sdload */ sdl_bdn = (line[1] << 8) | line[0]; /* device name */ sdl_bdu = line[3]; /* unit number */ /* save load device ID to pass to sdload */ sdl_ldn = (bootfs[1] << 8) | bootfs[0]; /* device name */ sdl_ldu = bootfs[3]; /* unit number */ } else sdlflag = 0; if(saflags & SA_RABADS) rabflag = 1; /* say loading sdload program */ else rabflag = 0; phys_i = txtsiz+datsiz; for (addr = 0; addr != phys_i; addr += 2) mtpi(getw(io),addr); if(ctrlc(0)) goto errxit; clrseg(addr, bsssiz); if(ctrlc(0)) goto errxit; close(io); if(sdlflag || rabflag) { /* sdload program, don't need syscall */ /* also, pass boot & load device IDs */ /* works because addresses same in both prog's */ if(rabflag == 0) { mtpi(sdl_bdn, &sdl_bdn); mtpi(sdl_bdu, &sdl_bdu); mtpi(sdl_ldn, &sdl_ldn); mtpi(sdl_ldu, &sdl_ldu); } /* * Copy the devsw[].dv_csr from this program to * the syscall segment of the stand-alone program. * This updates any CSR address changes. * location 100 in rabads/sdload has addr of devsw [] */ dpa = mfpi(0100); for(dp = &devsw; dp->dv_name; dp++, dpa++) mtpi(dp->dv_csr, (char *)&dpa->dv_csr); } if((saflags&SA_SCSEG) == 0) return(0); /* SA prog doesn't need syscall segment */ /* * MUST LOAD SYSCALL EVERY TIME (OH HECK DARN!) * This is because there is no clean way to clear * the RA open flag (ra_openf). Thus, causing the second * program (using RA disks) loaded to fail because the RA * driver does not init the MSCP controller. * The code remains in the hope that it will get fixed someday. if(scload) return(0); /* syscall already loaded */ /* * Load /sas/syscall file at 64KB, * system calls for all 401 type standalone programs. */ i = (line[1] << 8) | line[0]; /* two char device name */ switch(i) { case 'md': /* md (memory disk) */ cnt = 6; p = &md_scf; break; case 'rx': /* rx */ cnt = 6; p = &rx_scf; break; case 'ht': /* ht */ case 'tm': /* tm */ case 'ts': /* ts */ case 'tk': /* tk */ cnt = 4; p = &mt_scf; break; case 'hk': /* hk */ case 'hm': /* hm */ case 'hp': /* hp */ case 'ml': /* ml */ case 'ra': /* ra */ case 'rc': /* rc */ case 'rd': /* rd */ case 'rk': /* rk */ case 'rl': /* rl */ case 'rp': /* rp */ cnt = 6; p = &dk_scf; break; default: /* * NON DOCUMENTED ERROR MESSAGE! * For debugging purposes only. This can't * happen to a real life user. */ printf("\nCan't load syscall (bad device)\n"); return(1); } for(i=0; i<cnt; i++) *(p+i) = line[i]; sc = open(p, 0); if(sc < 0) { printf("\nCan't open %s file\n", p); errxit1: close(sc); return(1); } setseg(02000); /* 64 KB */ lseek(sc, (off_t)0, 0); getw(sc); txtsiz = getw(sc); datsiz = getw(sc); bsssiz = getw(sc); symsiz = getw(sc); getw(sc); getw(sc); getw(sc); phys_i = txtsiz+datsiz; for (addr = 0; addr != phys_i; addr += 2) mtpi(getw(sc),addr); /* * Copy the devsw[].dv_csr from this program to * the syscall segment of the stand-alone program. * This updates any CSR address changes. */ dpa = mfpi(0); /* syscall loc 0 has address of devsw */ for(dp = &devsw; dp->dv_name; dp++, dpa++) mtpi(dp->dv_csr, (char *)&dpa->dv_csr); if(ctrlc(0)) { scload = 0; goto errxit1; } /* Clears entire program not just bss segment ????? */ /* Not needed anyway. */ /* clrseg(addr, bsssiz); */ setseg(0); if(sepid) snsid(); /* Insure KISA7 set to I/O space */ scload++; /* say syscall file loaded */ close(sc); return(0); #ifdef K450 case 0450: maxov = 16; #endif K450 case 0430: /* overlayed text */ scload = 0; if(symsiz == 0) goto badst; if(nlist(line, nl) < 0) goto badnl; if(ctrlc(0)) goto errxit; if(nl[X_EL_PRCW].n_type == 0) goto badnl; /* * DO NOT BOOT if the value of the symbol _mb_end * is 0 or > 0120000, i.e., part of the protected * data structures fall within the forbidden zone. */ if ((nl[X_MB_END].n_value == 0) || (nl[X_MB_END].n_value > 0120000)) goto mb_err; /* * DO NOT BOOT if _ub_end > (060000+datsiz+8192), * data structures covered by the first unibus map * register are too large. */ if(ubmaps && (nl[X_UB_END].n_value > (060000+datsiz+8192))) goto ub_err; /* * DO NOT BOOT if the processor has a unibus map * but the kernel is not configured to support it. * The symbol _maplock indicates map code included. */ if(ubmaps && (nl[X_MAPLOCK].n_type == 0)) goto ubm_err; /* * If loading an overlay text kernel on a separate * I & D space CPU, disable separate I & D space. */ if (sepid) snsid(); /* * check for consistency */ if (txtsiz < 020000) { printf("text segment too small (0%o)\n", txtsiz); goto errxit; } if (txtsiz > 040000) { printf("text segment too big (0%o)\n", txtsiz); goto errxit; } if (datsiz + bsssiz > 060000) { printf("data segment too big (0%o)\n", datsiz + bsssiz); goto errxit; } if(ctrlc(0)) goto errxit; lseek(io, (long) 020, 0); /* skip to overlay header */ #ifndef K450 for (i = 0, ovsize = 0; i < 8; i++) { #else K450 for (i = 0, ovsize = 0; i < maxov; i++) { #endif K450 ovsizes[i] = getw(io); ovsize += ovsizes[i]; } ovsize -= ovsizes[0]; if (ovsizes[0] > 020000) { printf("max overlay too big (0%o)\n", ovsizes[0]); goto errxit; } gktape(); /* If generic kernel, select magtape */ printf("\n%s: ", line); ovsizes[0] = 0; /* * load text segment at zero */ printf("%u", txtsiz); setseg(0); for (addr = 0; addr < txtsiz; addr +=2) mtpi(getw(io), addr); /* * load data segment at 24Kb */ if(ctrlc(0)) goto errxit; printf("+%u", datsiz+bsssiz); phys = 060000L; setseg((int)(phys/64)); #ifndef K450 lseek(io, 040L + (long)txtsiz + (long)ovsize, 0); #else K450 lseek(io, 020L + (maxov * 2L) + (long)txtsiz + ovsize, 0); #endif K450 for (addr = 0; addr < datsiz; addr += 2) mtpi(getw(io), addr); /* * clear bss */ if(ctrlc(0)) goto errxit; clrseg(addr, bsssiz); phys += datsiz + bsssiz; phys = (phys + 077) & ~077; /* * new buffering scheme doesn't have pbaddr, and * so we don't want to do this stuff. */ if (nl[X_PBADDR].n_value) { pbaddr = phys/64; phys += 8192; /* * clear buffers */ setseg(pbaddr); clrseg(0, 8192); } /* * load the overlays after the bss * except for overlay 1, which is loaded at 16Kb */ #ifndef K450 lseek(io, (long)(040+txtsiz), 0); ovaddr = phys; for (i = 1; i < 8; i++) { #else K450 lseek(io, 020L + maxov * 2L + (long)txtsiz, 0); ovaddr = phys; for (i = 1; i < maxov; i++) { #endif K450 if (i == 1) setseg(040000/64); else { setseg((int)(phys/64)); #ifndef BIGKERNEL /* * When loading an overlay text kernel, * move the kernel stack to the last 8 kb * section of the first 128 kb of memory. * This prevents the stack from overwriting unix. */ KISA6->r[0] = 03600; #else BIGKERNEL KISA6->r[0] = (segflag<<10) - 0200; #endif BIGKERNEL phys += ovsizes[i]; } if(ctrlc(0)) goto errxit; if(ovsizes[i]) printf("+%u", ovsizes[i]); for (addr = 0; addr < ovsizes[i]; addr += 2) mtpi(getw(io), addr); } printf("\n"); /* * build the overlay address and descriptor * tables for the kernel. */ setseg(0); #ifndef BIGKERNEL /* * When loading an overlay text kernel, * move the kernel stack to the last 8 kb * section of the first 128 kb of memory. * This prevents the stack from overwriting unix. */ KISA6->r[0] = 03600; #else BIGKERNEL KISA6->r[0] = (segflag<<10) - 0200; #endif BIGKERNEL addr = nl[X_OVA].n_value;/* _ova, overlay tables start here */ #ifndef K450 for (i = 0; i < 8; i++) { #else K450 for (i = 0; i < maxov; i++) { #endif K450 if (i == 1) mtpi(040000/64, addr); else { mtpi((int)(ovaddr/64), addr); ovaddr += ovsizes[i]; } addr += 2; } #ifndef K450 for (i = 0; i < 8; i++) { #else K450 addr = nl[X_OVD].n_value; /* overlay descriptors */ for (i = 0; i < maxov; i++) { #endif K450 if (ovsizes[i] != 0) mtpi((((ovsizes[i]/64)-1)<<8) | RO, addr); else mtpi(0, addr); addr += 2; } #ifdef K450 addr = nl[X_OVEND].n_value; #endif K450 mtpi((int)(phys/64), addr); /* start of free memory */ /* * Correct the page length field in the last * data space PDR to reflect the actual size * of the data space segement so that data will not * overlap the overlay text segments which * are loaded immediately after data space. */ i = datsiz + bsssiz; pdr = 3 + (i / 8192); psz = i % 8192; if(psz > 0) { psz += 077; psz &= ~077; psz <<= 2; psz -= 0400; KISD0->r[pdr] = (psz | 6); } /* * Although separate I & D space was disabled above, * must call snsid() again to reset KISA7 to map to * I/O space, because setseg(); changes it. */ if(sepid) snsid(); setpar(); if(ctrlc(0)) goto errxit; close(io); return(0); default: printf("Can't load %o files\n", magic); goto errxit; } /* NOT REACHED */ /* * The following error messages and error exits * were moved here from the "case 0411:" code above * so that some of the cases could be conditionally included. */ badst: printf("\nUnix symbol table missing\n"); errxit: close(io); return(1); badnl: printf("\nCan't access namelist in %s\n", line); goto errxit; mb_err: printf("\nMAPPED BUFFERS - forbidden zone violation"); printf("\n_mb_end = %o\n", nl[X_MB_END].n_value); goto errxit; ub_err: printf("\nUNIBUS MAP - forbidden zone violation"); printf("\n_ub_end = %o\n", nl[X_UB_END].n_value); goto errxit; ubm_err: printf("\nUNIBUS MAP - no support code in kernel"); goto errxit; } /* * Load the CPU descriptive parameters in locore. * Initialize TTY structures. */ setpar() { register i; int j, k; register char *p; register struct tty *ttysp; unsigned int ms; int addr, addr2; int nkl11, ndl11, ndh11, dz_cnt, ntty, nttys, nuh11; int nbuf, nb; int icode, szicode; int io, sum, ts, ds; struct devsw *dp; int rootdev, swapdev, pipedev, el_dev; struct sdfsl *sdp; int generic, sd_bmaj; union { /* GMM */ int cpuint[SYS_NMLN/2]; char cpuname[SYS_NMLN]; } cpustr; if(nl[X_GENERIC].n_value) generic = 1; else generic = 0; /* * OLD 0430 kernels ONLY! * Check the value of nbuf, for the overlay kernel only * if 16 boot is ok * if < 16 print warning & boot * if > 16 print warning & no boot. */ nbuf = mfpi(nl[X_NBUF].n_value); if(magic == 0430 && nl[X_PBADDR].n_value) { if(nbuf != 16) printf("\nWARNING, nbuf is %d MUST be 16\n", nbuf); if(nbuf > 16) for( ;; ) ; } /* * If CPU has unibus map and nbuf > MAXNBUF, reduce nbuf * to MAXNBUF (max that can be mapped with available registers). */ if(ubmaps && (nbuf > MAXNBUF)) { nbuf = MAXNBUF; printf("\nUNIBUS MAP REGISTER LIMIT EXCEEDED: too many buffers!"); printf("\nReducing number of buffers to %d!\n", MAXNBUF); } /* * If new mapped buffer kernels (411, 430, 431), * compare the number of buffers with the available * memory and cut back if needed. * * CAUTION: this code must match the code in * /usr/src/cmd/sysgen/sg_ccf.c - g_gnb() */ if(nl[X_BPADDR].n_value) { ms = maxmem / 16; nb = nbuf; if(ms < 248) { printf("\nCANNOT BOOT ULTRIX-11: "); printf("less than 248K bytes of memory!\n"); for( ;; ) ; } if(nb < 16) { printf("\nCANNOT BOOT ULTRIX-11: "); printf("less than 16 buffers!\n"); for( ;; ) ; } if((ms >= 248) && (ms <= 256) && (nb > 40)) nbuf = 40; else if((ms > 256) && (ms < 384) && (nb > 50)) nbuf = 50; else if((ms >= 384) && (ms < 512) && (nb > 100)) nbuf = 100; else if((ms >= 512) && (ms < 768) && (nb > 200)) nbuf = 200; else if((ms >= 768) && (ms < 1024) && (nb > 250)) nbuf = 250; else if(nb > 300) nbuf = 300; if(nb != nbuf) { printf("\nTOO MANY BUFFERS FOR %dK bytes of memory!", ms); printf("\nReducing number of buffers to %d!\n", nbuf); } } /* * Set up the TTY structure logical assignments, i.e., * * console * all other KL's * DL's * DH's * DHU/DHV's * DZ's * * The parameter `ntty' is the number of available TTY structures, * `ntty' now always matches the number of communications ports. */ nuh11=nkl11=ndl11=ndh11=dz_cnt=ntty = 0; if(nl[X_NDH11].n_value) /* ndh11 */ ndh11 = mfpi(nl[X_NDH11].n_value); if(nl[X_NKL11].n_value) /* nkl11 */ nkl11 = mfpi(nl[X_NKL11].n_value); if(nl[X_NDL11].n_value) /* ndl11 */ ndl11 = mfpi(nl[X_NDL11].n_value); if(nl[X_DZ_CNT].n_value) /* dz_cnt */ dz_cnt = mfpi(nl[X_DZ_CNT].n_value); if(nl[X_NTTY].n_value) /* ntty */ ntty = mfpi(nl[X_NTTY].n_value); if(nl[X_NUH11].n_value) /* nuh11 */ nuh11 = mfpi(nl[X_NUH11].n_value); if((nkl11==0)||(ntty==0)|| (nl[X_TTY_TS].n_value==0)||(nl[X_KL11].n_value==0)) { printf("\nCan't assign TTY structures in %s\n", line); return; } #ifdef UMAX icode = nl[X_ICODE].n_value; /* address of icode[] in machdep.c */ szicode = mfpi(nl[X_SZICODE].n_value); /* size of icode[] */ icode += (szicode - 4); /* address of UMAX in icode[] */ if(UMAX != mfpi(icode)) /* match UMAX limit */ return; /* will cause system to hang */ init[0] = line[0]; /* ??(#,0)/etc/init - init pathname */ init[1] = line[1]; init[3] = line[3]; io = open(init, 0); if(io < 0) return; /* system will hang */ getw(io); ts = getw(io); ds = getw(io); getw(io); getw(io); getw(io); getw(io); getw(io); sum = 0; for(i=0; i<(ts/2); i++) sum += getw(io); for(i=0; i<(ds/2); i++) sum += getw(io); close(io); if(sum != 0) return; /* system will hang */ #endif UMAX nttys = 0; ttysp = nl[X_TTY_TS].n_value; /* points to first TTY structure */ for(i=0; i<nkl11; i++) { /* console and KL's */ if(nttys >= ntty) goto loadpar; mtpi(ttysp, (nl[X_KL11].n_value + (sizeof(int)*i))); ttysp++; nttys++; } if(ndl11) /* DL's */ for(i=nkl11; i<(nkl11+ndl11); i++) { if(nttys >= ntty) goto loadpar; mtpi(ttysp, (nl[X_KL11].n_value + (sizeof(int)*i))); ttysp++; nttys++; } if(ndh11) /* DH's */ for(i=0; i<ndh11; i++) { if(nttys >= ntty) goto loadpar; mtpi(ttysp, (nl[X_DH11].n_value + (sizeof(int)*i))); ttysp++; nttys++; } if(nuh11) /* DH's */ for(i=0; i<nuh11; i++) { if(nttys >= ntty) goto loadpar; mtpi(ttysp, (nl[X_UH11].n_value + (sizeof(int)*i))); ttysp++; nttys++; } if(dz_cnt) /* DZ's */ for(i=0; i<dz_cnt; i++) { if(nttys >= ntty) goto loadpar; mtpi(ttysp, (nl[X_DZ_TTY].n_value + (sizeof(int)*i))); ttysp++; nttys++; } loadpar: /* * If autocsr enabled, * modify the booted kernel to use the disk CSR * address from the devsw[] entry. */ /* RESTRICTION - only works for first MSCP disk cntlr */ /* EXCEPT - for RX50 as load device (uses second cntlr, some times) */ if(autocsr || generic) { dp = (struct devsw *)dp_get(&line); sd_bmaj = dp->dv_bmaj; addr = nl[X_IO_CSR].n_value; /* addr of io_csr[] */ addr += (dp->dv_rmaj * 2); /* index to CSR */ if(dp->dv_rmaj == RA_RMAJ) { /* If MSCP disk cntlr */ addr = mfpi(addr); /* io_csr[] points to ra_csr[] */ addr2 = addr+2; /* points to 2nd MSCP cntrl CSR */ } mtpi(dp->dv_csr, addr); if(nl[X_DMP_CSR].n_value) /* fix crash dump dev CSR */ mtpi(dp->dv_csr, nl[X_DMP_CSR].n_value); } /* * If autounit enabled, * modify the booted kernel to run from the unit * specified in the boot command line, i.e., ra(#,0)unix. * Change rootdev, swapdev, pipedev, and el_dev, if they * are on the same major device as the boot device. */ if(autounit || generic) { dp = (struct devsw *)dp_get(&line); /* find dev in devsw[] */ if(generic == 0) { rootdev = fixdev(dp, dp->dv_bmaj, mfpi(nl[X_ROOTDEV].n_value)); swapdev = fixdev(dp, dp->dv_bmaj, mfpi(nl[X_SWAPDEV].n_value)); pipedev = fixdev(dp, dp->dv_bmaj, mfpi(nl[X_PIPEDEV].n_value)); el_dev = fixdev(dp, dp->dv_rmaj, mfpi(nl[X_EL_DEV].n_value)); } else { if((sdp = sdp_set(dp)) == 0) { printf("\n%s: fatal generic kernel boot error!", line); printf("\nCan't find boot device drive type!\n"); return; } rootdev = fixdev(dp,dp->dv_bmaj,(dp->dv_bmaj<<8)|sdp->sdf_root); pipedev = fixdev(dp,dp->dv_bmaj,(dp->dv_bmaj<<8)|sdp->sdf_pipe); swapdev = fixdev(dp,dp->dv_bmaj,(dp->dv_bmaj<<8)|sdp->sdf_swap); el_dev = fixdev(dp,dp->dv_rmaj,(dp->dv_rmaj<<8)|sdp->sdf_elog); } mtpi(rootdev, nl[X_ROOTDEV].n_value); mtpi(swapdev, nl[X_SWAPDEV].n_value); mtpi(pipedev, nl[X_PIPEDEV].n_value); mtpi(el_dev, nl[X_EL_DEV].n_value); /* change crash dump device unit #, unless it is RX50 */ if(nl[X_DMP_DN].n_value && (nl[X_DMP_RX].n_value == 0)) { i = line[3] - '0'; mtpi(i, nl[X_DMP_DN].n_value); } } /* * If booting generic kernel, * load swplo, nswap, el_sb, and el_nb. * NOTE: swplo and el_sb are longs, but we only * load the low word, safe because values small. */ if(generic) { mtpi(sdp->sdf_swplo, nl[X_SWPLO].n_value+2); mtpi(sdp->sdf_nswap, nl[X_NSWAP].n_value); mtpi(sdp->sdf_elsb, nl[X_EL_SB].n_value+2); mtpi(sdp->sdf_elnb, nl[X_EL_NB].n_value); } mtpi(sepid, nl[X_SEPID].n_value); mtpi(ubmaps, nl[X_UBMAPS].n_value); mtpi(cputype, nl[X_CPUTYPE].n_value); mtpi(nmser, nl[X_NMSER].n_value); mtpi(cdreg, nl[X_CDREG].n_value); mtpi(maxmem, nl[X_MAXMEM].n_value); mtpi(nbuf, nl[X_NBUF].n_value); mtpi(el_prcw, nl[X_EL_PRCW].n_value); mtpi(rn_ssr3, nl[X_RN_SSR3].n_value); mtpi(mmr3, nl[X_MMR3].n_value); mtpi(cpereg, nl[X_CPEREG].n_value); if(nl[X_PBADDR].n_value) /* pbaddr only in old 0430 type kernel */ mtpi(pbaddr, nl[X_PBADDR].n_value); /* * Fill in the machine name in the ustname structure (PDP-11/##). */ for(j=0; j<(SYS_NMLN/2); j++) cpustr.cpuint[j] = 0; sprintf(&cpustr.cpuname, "PDP-11/%d", cputype); for(j=0; j<(SYS_NMLN/2); j++) mtpi(cpustr.cpuint[j], nl[X_UTSNAME].n_value+(SYS_NMLN*4)+(j*2)); /* * If booting a generic kernel, * load system disk interrupt vector. * Also, zap the bdevsw and cdevsw entries for * all but the system disk. * * sd_bmaj is set to system disk's block major device * number, see autounit code above. */ if(generic) { switch(sd_bmaj) { case HP_BMAJ: mtpi(nl[X_HPIO].n_value, 0254); /* vector */ mtpi(0240, 0254+2); /* br5 */ break; case HK_BMAJ: mtpi(nl[X_HKIO].n_value, 0210); /* vector */ mtpi(0240, 0210+2); /* br5 */ break; case RA_BMAJ: mtpi(nl[X_RAIO].n_value, 0154); /* vector */ mtpi(0240, 0154+2); /* br5 */ if(ld_bmaj != RA_BMAJ) /* don't need 2nd MSCP cntlr */ zapra2(addr2); /* zap second MSCP cntlr */ break; case RL_BMAJ: mtpi(nl[X_RLIO].n_value, 0160); /* vector */ mtpi(0240, 0160+2); /* br5 */ break; case RP_BMAJ: mtpi(nl[X_RPIO].n_value, 0254); /* vector */ mtpi(0240, 0254+2); /* br5 */ break; default: /* CANNOT HAPPEN, would fail before we get here */ return; } /* ldp points to devsw entry for load device */ switch(ld_bmaj) { case RA_BMAJ: /* Load device is RX50 or RC25 */ if(ldp->dv_flags&DV_RX) { /* load device = RX50 */ /* * RX50 is the load device, must determine if * second MSCP cntlr in generic kernel will be needed. * Zap the CSR of 2nd cntlr if not needed. * * If system disk is RD, RX already config on cntlr 0. * If system disk not MSCP, config RX on MSCP cntlr 0. * If system disk RA or RC, config RX on MSCP cnltr 1. */ if(strcmp("rd", sdp->sdf_type) == 0) { zapra2(addr2); /* zap second MSCP cntlr */ break; /* system disk is RD */ } else if(sd_bmaj != RA_BMAJ) { mtpi(nl[X_RAIO].n_value, 0154); /* vector */ mtpi(0240, 0154+2); /* br5+cntlr0 */ zapra2(addr2); /* zap second MSCP cntlr */ } else { mtpi(nl[X_RAIO].n_value, 0150); /* vector */ mtpi(0241, 0150+2); /* br5+cnltr1 */ /* for(i=0; devsw[i].dv_name; i++) /* 2nd cntlr CSR */ /* if(strcmp("rx", devsw[i].dv_name) == 0) */ /* break; */ /* mtpi(devsw[i].dv_csr, addr2); /* load CSR */ mtpi(ldp->dv_csr, addr2); /* load CSR */ /* ^- value set above */ } } if(ldp->dv_flags&DV_RC) { /* load device = RC25 */ /* * RC25 is the load device, must determine if * second MSCP cntlr in generic kernel will be needed. * Zap the CSR of 2nd cntlr if not needed. * * If system disk is RC, RC already config on cntlr 0. * If system disk not MSCP, config RC on MSCP cntlr 0. * If system disk RA or RD, config RC on MSCP cnltr 1. */ if(strcmp("rc", sdp->sdf_type) == 0) { zapra2(addr2); /* zap second MSCP cntlr */ break; /* system disk is RC */ } else if(sd_bmaj != RA_BMAJ) { mtpi(nl[X_RAIO].n_value, 0154); /* vector */ mtpi(0240, 0154+2); /* br5+cntlr0 */ zapra2(addr2); /* zap second MSCP cntlr */ } else { mtpi(nl[X_RAIO].n_value, 0150); /* vector */ mtpi(0241, 0150+2); /* br5+cnltr1 */ /* for(i=0; devsw[i].dv_name; i++) /* 2nd cntlr CSR */ /* if(strcmp("rc", devsw[i].dv_name) == 0) */ /* break; */ /* mtpi(devsw[i].dv_csr, addr2); /* load CSR */ mtpi(ldp->dv_csr, addr2); /* load CSR */ /* ^- value set above */ } } break; case RL_BMAJ: mtpi(nl[X_RLIO].n_value, 0160); /* vector */ mtpi(0240, 0160+2); /* br5 */ break; case HT_BMAJ: mtpi(nl[X_HTIO].n_value, 0224); /* vector */ mtpi(0240, 0224+2); /* br5 */ break; case TS_BMAJ: mtpi(nl[X_TSIO].n_value, 0224); /* vector */ mtpi(0240, 0224+2); /* br5 */ break; case TM_BMAJ: mtpi(nl[X_TMIO].n_value, 0224); /* vector */ mtpi(0240, 0224+2); /* br5 */ break; case TK_BMAJ: mtpi(nl[X_TKIO].n_value, 0260); /* vector */ mtpi(0240, 0260+2); /* br5 */ break; default: /* -1, load dev not present or not selected */ break; } if(sd_bmaj != HP_BMAJ) zapdev(0, HP_BMAJ, HP_RMAJ); if(sd_bmaj != HK_BMAJ) zapdev(0, HK_BMAJ, HK_RMAJ); if((sd_bmaj != RA_BMAJ) && (ld_bmaj != RA_BMAJ)) zapdev(0, RA_BMAJ, RA_RMAJ); if((sd_bmaj != RL_BMAJ) && (ld_bmaj != RL_BMAJ)) zapdev(0, RL_BMAJ, RL_RMAJ); if(sd_bmaj != RP_BMAJ) zapdev(0, RP_BMAJ, RP_RMAJ); if(ld_bmaj != HT_BMAJ) { zapdev(0, HT_BMAJ, HT_RMAJ); if(nl[X_NHT].n_value) mtpi(0, nl[X_NHT].n_value); } if(ld_bmaj != TS_BMAJ) { zapdev(0, TS_BMAJ, TS_RMAJ); if(nl[X_NTS].n_value) mtpi(0, nl[X_NTS].n_value); } if(ld_bmaj != TM_BMAJ) { zapdev(0, TM_BMAJ, TM_RMAJ); if(nl[X_NTM].n_value) mtpi(0, nl[X_NTM].n_value); } if(ld_bmaj != TK_BMAJ) { zapdev(0, TK_BMAJ, TK_RMAJ); if(nl[X_NTK].n_value) mtpi(0, nl[X_NTK].n_value); } } } /* * This function replaces the bdevsw[] and cdevsw[] entries * for a device with nodev() or nulldev(), to make it appear * to the kernel as if the device was not configured. This * prevents the kernel from accessing non-existent devices, * all possible devices are configured into the run time only kernel. * * The following is bad coding practice, but I will take the heat for it. * Fred Canter 1/19/85 * The format of the bdevsw and cdevsw structures are hardwired into * the code below. If the format changes, boot will break. To cover that * unlikely event, a warning message was added to /usr/include/sys/conf.h, * where the bdevsw and cdevsw structures are defined. * * dev device type code * bmaj block major device number (-1 if no block major) * rmaj raw major device number */ zapdev(dev, bmaj, rmaj) { register int i, j; i = nl[X_CDEVSW].n_value; /* address of cdevsw[0] */ i += (rmaj * sizeof(struct cdevsw)); /* address of device's entry */ for(j=0; j<5; j++) { /* zap driver entry points */ mtpi(nl[X_NODEV].n_value, i); i += 2; } mtpi(nl[X_NULLDEV].n_value, i); /* zap stop routine entry */ i += 2; mtpi(0, i); /* zap tty struct pointer */ if(bmaj < 0) return; /* not block mode device */ i = nl[X_BDEVSW].n_value; /* address of bdevsw[0] */ i += (bmaj * sizeof(struct bdevsw)); /* address of device's entry */ for(j=0; j<3; j++) { /* zap driver entry points */ mtpi(nl[X_NODEV].n_value, i); i += 2; } mtpi(0, i); /* zap device's table addr */ } /* * Check for a character typed on the console terminal. * Return 1 if it is CRTL/C, 0 otherwise. * If argment (clr) is nonzero, clear the console KL * receive CSR to get rid of any extra CTRL/C or other * garbage characters. */ struct kldev { int klrcsr, klrbuf; int kltcsr, kltbuf; }; struct kldev *KLCSR {0177560}; ctrlc(clr) { if(clr) KLCSR->klrcsr = 0; if(KLCSR->klrcsr & 0200) if((KLCSR->klrbuf & 0177) == '\03') { printf("^C"); return(1); } return(0); } match(s1,s2) register char *s1,*s2; { register cc; cc = DIRSIZ; while (cc--) { if (*s1 != *s2) return(0); if (*s1++ && *s2++) continue; else return(1); } return(1); } /* * Check for and execute user commands. * Return 0 if no command or command is install, * otherwise return 1. */ cmds() { int i, j, k; int fi, fo; long boff; if(match("help", line)) goto c_help; if(match("csr", line)) goto c_csr; if(match("aus", line)) goto c_aus; if(match("acs", line)) goto c_acs; if(match("install", line)) goto c_instal; return(0); c_help: for(i=0; options[i]; i++) { if(options[i] == -1) { printf("\n\nPress <RETURN> to continue:"); while(getchar() != '\n') ; } else printf("\n%s", options[i]); } return(1); c_aus: printf("\nAuto unit select <y or n> ? "); gets(line); if(match("y", line) || match("yes", line)) { autounit = 1; return(1); } else if(match("n", line) || match("no", line)) { autounit = 0; return(1); } else goto c_aus; c_acs: printf("\nAuto CSR select <y or n> ? "); gets(line); if(match("y", line) || match("yes", line)) { autocsr = 1; return(1); } else if(match("n", line) || match("no", line)) { autocsr = 0; return(1); } else goto c_acs; c_csr: printf("\nList all current CSR addresses <y or n> ? "); gets(line); if(match("no", line) || match("n", line)) goto c_csr1; if(match("yes", line) || match("y", line)) { printf("\nDevice CSR Address"); printf("\n------ -----------"); for(i=0; devsw[i].dv_name; i++) { if(devsw[i].dv_flags&DV_MD) continue; /* memory disk - no CSR */ printf("\n%s %o",devsw[i].dv_name,devsw[i].dv_csr); } printf("\n"); } else goto c_csr; c_csr1: printf("\nEnter device name or press <RETURN> for no change.\n"); printf("\nDevice < "); for(i=0; devsw[i].dv_name; i++) { if(devsw[i].dv_flags&DV_MD) continue; /* memory disk - no CSR */ printf("%s ", devsw[i].dv_name); } printf(">: "); gets(line); if(line[0] == '\0') goto c_csr3; for(i=0; devsw[i].dv_name; i++) { if(devsw[i].dv_flags&DV_MD) continue; /* memory disk - no CSR */ if(match(line, devsw[i].dv_name)) break; } if(devsw[i].dv_name == 0) goto c_csr1; printf("\nEnter new CSR address or press <RETURN> for no change.\n"); printf("\nCSR <%o>: ", devsw[i].dv_csr); gets(line); if(line[0] == '\0') goto c_csr3; j = 0; for(k=0; line[k]; k++) { j = j << 3; j |= line[k] & 7; } c_csr2: printf("\nNew (%s) CSR address is %o <y or n> ? ", devsw[i].dv_name, j); gets(line); if(match("y", line) || match("yes", line)) devsw[i].dv_csr = j; else if(match("n", line) || match("no", line)) goto c_csr3; else goto c_csr2; c_csr3: return(1); /* * Install command, do some setup here then * return 0. This will cause sdload to be loaded as if * the user had typed ??(#,0)sdload. */ c_instal: if(sdl_ld[0] == '?') { /* Not booted from a valid load device */ printf("\nSorry - install only allowed from distr media!\n"); return(1); } for(i=0; i<50; i++) { /* copy ??(#,0)sdload to line */ line[i] = sdl_ld[i]; if(line[i] == '\0') break; } if((sdl_ld[0] == 'r') && ((sdl_ld[1] == 'c') || (sdl_ld[1] == 'l'))) return(0); /* RL02/RC25 - don't use memory disk */ if(maxmem >= 8192) { /* use memory disk if CPU has 512 KB */ printf("\nCopying auto-install programs to memory disk...\n"); sprintf(sdl_sap, "??(#,0)saprog"); sdl_sap[0] = sdl_ld[0]; sdl_sap[1] = sdl_ld[1]; sdl_sap[3] = sdl_ld[3]; if((sdl_sap[0] == 'r') && (sdl_sap[1] == 'x')) sdl_sap[7] = '\0'; if((fi = open(sdl_sap, 0)) < 0) { printf("\nCan't open %s!\n", sdl_sap); return(1); } if((fo = open("md(0,0)", 1)) < 0) { printf("\nCan't open md(0,0)!\n"); return(1); } for(i=0; i<CBCNT; i++) { boff = (long)i * (long)CBSIZ; lseek(fi, (long)boff, 0); if(read(fi, (char *)©buf, CBSIZ) < 0) { printf("\n%s: read error\n", sdl_sap); return(1); } lseek(fo, (long)boff, 0); if(write(fo, (char *)©buf, CBSIZ) < 0) { printf("\nmd(0,0): write error\n"); return(1); } } line[0] = 'm'; line[1] = 'd'; line[3] = '0'; } return(0); } /* * Modify the unit number portion of a major/minor * device specification, if the major device number matches. */ fixdev(dp, maj, dev) struct devsw *dp; { int unit; unit = line[3] - '0'; if((dev >> 8) != maj) return(dev); /* no change */ if(dp->dv_flags & DV_NPDSK) /* non-partitioned disk */ return((dev & ~0377) | unit); /* minor = unit */ else return((dev & ~070) | (unit << 3)); } /* * Search the devsw[] table for the device name * located in the first two characters of str[]. * If found return pointer ot devsw entry, if not * found return -1. */ dp_get(str) char *str; { register struct devsw *dp; char bdname[4]; bdname[0] = str[0]; bdname[1] = str[1]; bdname[2] = '\0'; for(dp = &devsw; dp->dv_name; dp++) if(match(&bdname, dp->dv_name)) break; if(dp->dv_name == 0) return(-1); else return(dp); } /* * Find the system disk type in sdfsl[] and return a pointer * to its system disk layout entry. Return 0 if disk cannot * be found. Some magic needed if disk is "hp", because RP04/5/6, * RM02/3, and RM05 have different layouts. * The HP drive type is found in hpxdt[], see /usr/sys/sas/hp.c. * We assume drive type is in hpxdt[0] because the kernel is the only * file that is open during a boot, may be two file descriptors (nlist) * but they should both be for the kernel. * Same magic for "rd", because RD51, RD31, and RD52/RD53/RD54 disk layouts * have been changed and are also now different. */ extern int hpxdt[2]; #define RP04 020 #define RP05 021 #define RP06 022 #define RM02 025 #define RM03 024 #define RM05 027 /* MSCP disk types in ra_saio.h */ sdp_set(dp) register struct devsw *dp; { register struct sdfsl *sdp; register int unit; for(sdp=sdfsl; sdp->sdf_type; sdp++) if(match(dp->dv_name, sdp->sdf_type)) break; if(sdp->sdf_type == 0) return(0); if(match("hp", sdp->sdf_type)) { switch(hpxdt[0]) { case RP04: case RP05: case RP06: break; case RM02: case RM03: sdp++; break; case RM05: sdp += 2; break; default: sdp = 0; break; } } if(match("rd", sdp->sdf_type)) { unit = line[3] - '0'; /* rd(#,0)unix */ if(unit >= 4) return(0); switch(ra_drv[dp->dv_cn][unit].ra_dt) { case RD51: break; case RD31: sdp += 2; break; case RD32: case RD52: case RD53: case RD54: sdp++; break; default: sdp = 0; break; } } return(sdp); } /* * gktape - generic kernel load device select routine. * * The generic kernel has all possible system disks and * magtapes configured. This routine selects the load device. * * If boot was loaded by sdload magtape ID is in sdl_ldn. * Otherwise, ask the user to select the load device. * * TODO: * Should set up the crash dump device. This will require all * crash dump device code be configured into the generic kernel, * and boot will need a duplicate of the crash dump disk table * in sysgen (sg_tab.c). */ gktape() { register struct devsw *dp; register int i; ld_bmaj = -1; /* say no load device */ if(nl[X_GENERIC].n_value == 0) return; /* not a generic kernel */ if(sdl_bdn) { /* boot loaded by sdload */ gline[0] = sdl_ldn & 0177; gline[1] = (sdl_ldn >> 8) & 0177; gline[2] = '\0'; if((dp = (struct devsw *)dp_get(&gline)) != -1) if((dp->dv_flags&DV_TAPE) || (dp->dv_flags&DV_RX) || (dp->dv_flags&DV_RC) || (dp->dv_flags&DV_RL)) ld_bmaj = dp->dv_bmaj; } else { /* ask user to select load dev */ while(1) { printf("\nLoad device (? for help, <RETURN> if none)"); printf(" < ht tm ts tk rx rl rc > ? "); gets(gline); if(gline[0] == '\0') return; /* user says no load dev */ if(match("?", gline) || match("help", gline)) { for(i=0; gkt_help[i]; i++) printf("\n%s", gkt_help[i]); continue; } if((dp = (struct devsw *)dp_get(&gline)) == -1) { printf("\n%s - bad device!\n", gline); continue; } if(((dp->dv_flags&DV_TAPE)==0) && ((dp->dv_flags&DV_RX)==0) && ((dp->dv_flags&DV_RC)==0) && ((dp->dv_flags&DV_RL)==0)) { printf("\n%s - invalid load device!\n", gline); continue; } ld_bmaj = dp->dv_bmaj; break; } } ldp = dp; /* save devsw entry pointer */ } /* * Routine to ZAP the second MSCP disk controller in it will not * be used. Set nuda to 0, nra[1] to 0, ra_ctid[1] to -1. * Set the CSR address in io_csr to 0160000 (never responds). * * Unions for dealing with character arrays nra[] & ra_ctid[]. * Assumes byte ordering, but that is just though! * * (addr) is address of 2nd cntlr's entry in io_csr[] array. */ zapra2(addr) { register int i; union { int w[2]; char c[4]; } nra; union { int w[2]; char c[4]; } ra_ctid; mtpi(0160000, addr); /* zap CSR address (no response) */ i = mfpi(nl[X_NUDA].n_value); /* get current value of _nuda */ if(i > 1) /* if more than one cntlr configed */ mtpi(1, nl[X_NUDA].n_value); /* clobber all but first */ nra.w[0] = mfpi(nl[X_NRA].n_value); /* zap nra[1] to zero */ nra.w[1] = mfpi(nl[X_NRA].n_value + sizeof(int)); nra.c[1] = 0; mtpi(nra.w[0], nl[X_NRA].n_value); mtpi(nra.w[1], nl[X_NRA].n_value + sizeof(int)); ra_ctid.w[0] = mfpi(nl[X_RA_CTID].n_value); /* zap ra_ctid[1] to -1 */ ra_ctid.w[1] = mfpi(nl[X_RA_CTID].n_value + sizeof(int)); ra_ctid.c[1] = 0377; mtpi(ra_ctid.w[0], nl[X_RA_CTID].n_value); mtpi(ra_ctid.w[1], nl[X_RA_CTID].n_value + sizeof(int)); }