Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
DISCONTINUED:openSUSE:11.2
powerpc-utils
powerpc-utils-nvsetenv.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File powerpc-utils-nvsetenv.patch of Package powerpc-utils
cmds/Makefile | 6 cmds/nvsetenv.c | 561 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ doc/Makefile | 2 doc/nvsetenv.8 | 218 +++++++++++++++++++++ 4 files changed, 785 insertions(+), 2 deletions(-) --- a/cmds/Makefile +++ b/cmds/Makefile @@ -4,7 +4,7 @@ include ../rules.mk -CMDS = nvram lsprop +CMDS = nvram nvsetenv lsprop all: $(CMDS) @@ -12,6 +12,10 @@ nvram: nvram.o @echo "LD $(WORK_DIR)/$@" @$(CC) -o $@ $^ -ldl +nvsetenv: nvsetenv.o + @echo "LD $(WORK_DIR)/$@" + @$(CC) -o $@ $^ -ldl + lsprop: lsprop.o @echo "LD $(WORK_DIR)/$@" @$(CC) -o $@ $^ --- /dev/null +++ b/cmds/nvsetenv.c @@ -0,0 +1,561 @@ +/* nvsetnv.c + + used to set the Envenrioment variables in power macs NVram. + Decides via /proc/cpuinfo which type of machine is used. + + Copyright (C) 1996-1998 by Paul Mackerras. + nwcode: Copyright (C) 2000 by Klaus Halfmann + + see README for details +*/ + +#include <stdio.h> +#include <stdlib.h> +#define __USE_GNU 1 // need strnlen +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#define NVSTART 0x1800 // Start of ??? +#define NVSIZE 0x800 // Size of of the NVRam +#define MXSTRING 128 +#define N_NVVARS (int)(sizeof(nvvars) / sizeof(nvvars[0])) +#define NVMAGIC 0x1275 + +static int nvstr_used; +static char nvstrbuf[NVSIZE]; + +struct nvram { + unsigned short magic; /* 0x1275 */ + unsigned char char2; + unsigned char char3; + unsigned short cksum; + unsigned short end_vals; + unsigned short start_strs; + unsigned short word5; + unsigned long bits; + unsigned long vals[1]; +}; + +typedef union { + struct nvram nv; + char c[NVSIZE]; + unsigned short s[NVSIZE / 2]; +} nvbuftype; + +nvbuftype nvbuf; + +enum nvtype { + boolean, + word, + string +}; + +struct nvvar { + const char *name; + enum nvtype type; +} nvvars[] = { + { + "little-endian?", boolean}, { + "real-mode?", boolean}, { + "auto-boot?", boolean}, { + "diag-switch?", boolean}, { + "fcode-debug?", boolean}, { + "oem-banner?", boolean}, { + "oem-logo?", boolean}, { + "use-nvramrc?", boolean}, { + "real-base", word}, { + "real-size", word}, { + "virt-base", word}, { + "virt-size", word}, { + "load-base", word}, { + "pci-probe-list", word}, { + "screen-#columns", word}, { + "screen-#rows", word}, { + "selftest-#megs", word}, { + "boot-device", string}, { + "boot-file", string}, { + "diag-device", string}, { + "diag-file", string}, { + "input-device", string}, { + "output-device", string}, { + "oem-banner", string}, { + "oem-logo", string}, { + "nvramrc", string}, { +"boot-command", string},}; + + // Calculated number of variables +#define N_NVVARS (int)(sizeof(nvvars) / sizeof(nvvars[0])) + +union nvval { + unsigned long word_val; + char *str_val; +} nvvals[32]; + +// #define MXSTRING 128: +// #define N_NVVARS (int)(sizeof(nvvars) / sizeof(nvvars[0])) +// #define NVMAGIC 0x1275 + +/* CHRP NVRAM header */ +typedef struct { + unsigned char signature; + unsigned char cksum; + unsigned short len; + char name[12]; + // unsigned char data[0]; +} chrp_header; + +/* Check in proc/cpuinfo if this is a new world machine */ + +/* "pmac-generation" is only in /proc/cpuinfo >= 2.2.16. + * Check /proc/device-tree/compatible instead for bw compatibility - Hollis + */ +static int checkNewWorld(void) +{ + FILE *cpuf = fopen("/proc/device-tree/compatible", "r"); + char buf[256], *ret; + if (!cpuf) { + perror("Couldn't open /proc/device-tree/compatible"); + exit(EXIT_FAILURE); + } + + ret = fgets(buf, 255, cpuf); + if (!ret) { + perror("fgets"); + exit(EXIT_FAILURE); + } + fclose(cpuf); + + if (!strncmp(buf, "AAPL", 4)) + // saw AAPL, must be Old World + return 0; + return 1; +} + +/* seek NVRAM until common (OF) part + return the lenght of the part in case of sucess, + 0 otherwise. + chrph is set to the value of the "coommon" blocek eventually found + *nvstart is set to the seekpoint where common block starts. +*/ + +static int nvscan(int nvfd, chrp_header * chrph, int *nvstart) +{ + int start = 0; + + while (read(nvfd, chrph, sizeof(chrp_header)) == sizeof(chrp_header)) { + int size; + if (!chrph->len) + break; + size = chrph->len * 0x10 - sizeof(chrp_header); + if (!strncmp(chrph->name, "common", 7)) { + *nvstart = start; + return size; // seeked upto start + } + if (lseek(nvfd, size, SEEK_CUR) < 0) + break; + start += size + sizeof(chrp_header); + } + fprintf(stderr, "No common Block found\n"); + exit(EXIT_FAILURE); +} + +static char *nvload(int nvfd, int nvsize) +{ + char *nvbuf = malloc(nvsize); + ssize_t r, count = 0; + + if (!nvbuf) { + perror("Error allocating buffer"); + exit(EXIT_FAILURE); + } + + do { + r = read(nvfd, nvbuf + count, nvsize - count); + if (r < 0) { + perror("Error reading /dev/nvram"); + exit(EXIT_FAILURE); + } + count += r; + } while (count < nvsize && r); + + return nvbuf; +} + +static void print_vars(char *nvbuf, int nvsize) +{ + int i = 0; + + while (i < nvsize) { + int size = strnlen(nvbuf, nvsize); + if (size == 0) + break; + printf("%s\n", nvbuf); + nvbuf += (size + 1); // count 0-byte, too + } +} + +/* move memory around to insert the value. + * + * @param nvbufend byte AFTER the end of the buffer + * @param varsize length of the variable name + * @param buf byte where varaible NAME starts + * @param newval new value to replace old one + * @param foundsize lenght of varible + '=' + value + * @param equalpos position relative to buf where '=' was found + */ +static void insert_val(char *nvbufend, int varsize, char *buf, char *newval, int foundsize, int equalpos) +{ + int oldlen = foundsize - equalpos - 1; // account for the '=' + int newlen = strlen(newval); + char *valpos = buf + varsize + 1; + int delta = newlen - oldlen; + + if (delta > 0) // expand mem + memmove(valpos + newlen, valpos + oldlen, (nvbufend - valpos - newlen)); + else if (delta < 0) // shrink mem + { + memmove(valpos + newlen, valpos + oldlen, (nvbufend - valpos - oldlen)); + memset(nvbufend + delta, 0, -delta); + } + strncpy(valpos, newval, newlen); +} + +/* return position where variable is found, + * newval may be null. + */ + +static char *set_var(char *nvbuf, int nvsize, char *varname, char *newval) +{ + int i = 0; + int varsize = strlen(varname); + int equalpos; + while (i < nvsize) { + char *buf = &nvbuf[i]; + int foundsize = strnlen(buf, nvsize - i); + if (foundsize == 0) + break; + equalpos = (int)(strchr(buf, '=') - buf); + if (equalpos == varsize && !strncmp(buf, varname, equalpos)) { + if (newval) // set the value + insert_val(nvbuf + nvsize, varsize, buf, newval, foundsize, equalpos); + return buf; + } + i += foundsize + 1; // count 0-byte, too + } + return NULL; +} + +static void print_var(char *nvbuf, int nvsize, char *varname) +{ + char *buf = set_var(nvbuf, nvsize, varname, NULL); + if (buf) + printf("%s\n", buf); +} + +#if 0 +/* This fucntion is not used here, it is left + here for the curious */ + +static unsigned short chrp_checksum(chrp_header * hdr, char *nvbuf, int nvsize) +{ + unsigned char *ptr = (unsigned char *)&hdr->len; + unsigned char *end = ptr + sizeof(chrp_header); + unsigned short sum = hdr->signature; + // this in fact skips the checksum + for (; ptr < end; ptr++) + sum += *ptr; + while (sum > 0xFF) + sum = (sum & 0xFF) + (sum >> 8); + return sum; +} +#endif + +static void nvstore(int nvfd, char *nvbuf, int nvstart, int nvsize) +{ + // mmh, the checksum is calculated for the header only + // since we did not modify the header we can just ignore it. + size_t count = 0; + off_t w, seek = nvstart + sizeof(chrp_header); + w = lseek(nvfd, seek, SEEK_SET); + if (w != seek) { + fprintf(stderr, "Error seeking /dev/nvram\n"); + exit(EXIT_FAILURE); + } + + do { + w = write(nvfd, nvbuf + count, nvsize - count); + if (w < 0) { + perror("Error writing /dev/nvram"); + exit(EXIT_FAILURE); + } + count += w; + } while (count < (size_t)nvsize); +} + +/* print / set the New World NVRAM */ + +static void nvNew(int ac, char **av, int nvfd) +{ + int nvsize, nvstart; + chrp_header chrph; + char *nvbuf; + + nvsize = nvscan(nvfd, &chrph, &nvstart); + nvbuf = nvload(nvfd, nvsize); + + switch (ac) { + case 1: + print_vars(nvbuf, nvsize); + break; + + case 2: + print_var(nvbuf, nvsize, av[1]); + break; + + case 3: + set_var(nvbuf, nvsize, av[1], av[2]); + nvstore(nvfd, nvbuf, nvstart, nvsize); + break; + } +} + +static int nvcsum(void) +{ + int i; + unsigned c; + + c = 0; + for (i = 0; i < NVSIZE / 2; ++i) + c += nvbuf.s[i]; + c = (c & 0xffff) + (c >> 16); + c += (c >> 16); + return c & 0xffff; +} + +static void nvloadOld(int nvfd) +{ + int s; + ssize_t r, count = 0; + char *buf = (char *)&nvbuf; + + if ((off_t)-1 == lseek(nvfd, NVSTART, 0)) { + perror("Error seeking /dev/nvram"); + exit(EXIT_FAILURE); + } + + do { + r = read(nvfd, buf + count, NVSIZE - count); + if (r < 0) { + perror("Error reading /dev/nvram"); + exit(EXIT_FAILURE); + } + count += r; + } while (count < NVSIZE && r); + + if (nvbuf.nv.magic != NVMAGIC) + fprintf(stderr, "Warning: Bad magic number %x\n", nvbuf.nv.magic); + s = nvcsum(); + if (s != 0xffff) + fprintf(stderr, "Warning: checksum error (%x) on nvram\n", s ^ 0xffff); + +} + +static void nvstoreOld(int nvfd) +{ + char *p = (char *)&nvbuf; + size_t count = 0; + off_t w; + + if ((off_t)-1 == lseek(nvfd, NVSTART, 0)) { + perror("Error seeking /dev/nvram"); + exit(EXIT_FAILURE); + } + + do { + w = write(nvfd, p + count, NVSIZE - count); + if (w < 0) { + perror("Error writing /dev/nvram"); + exit(EXIT_FAILURE); + } + count += w; + } while (count < NVSIZE); +} + +static void nvunpackOld(void) +{ + int i; + unsigned long bmask; + int vi, off, len; + + nvstr_used = 0; + bmask = 0x80000000; + vi = 0; + for (i = 0; i < N_NVVARS; ++i) { + switch (nvvars[i].type) { + case boolean: + nvvals[i].word_val = (nvbuf.nv.bits & bmask) ? 1 : 0; + bmask >>= 1; + break; + case word: + nvvals[i].word_val = nvbuf.nv.vals[vi++]; + break; + case string: + off = nvbuf.nv.vals[vi] >> 16; + len = nvbuf.nv.vals[vi++] & 0xffff; + nvvals[i].str_val = nvstrbuf + nvstr_used; + memcpy(nvvals[i].str_val, nvbuf.c + off - NVSTART, (size_t) len); + nvvals[i].str_val[len] = (char)0; + nvstr_used += len + 1; + break; + } + } +} + +static void nvpackOld(void) +{ + int i, vi; + size_t off, len; + unsigned long bmask; + + bmask = 0x80000000; + vi = 0; + off = NVSIZE; + nvbuf.nv.bits = 0; + for (i = 0; i < N_NVVARS; ++i) { + switch (nvvars[i].type) { + case boolean: + if (nvvals[i].word_val != 0) + nvbuf.nv.bits |= bmask; + bmask >>= 1; + break; + case word: + nvbuf.nv.vals[vi++] = nvvals[i].word_val; + break; + case string: + len = strlen(nvvals[i].str_val); + off -= len; + memcpy(nvbuf.c + off, nvvals[i].str_val, len); + nvbuf.nv.vals[vi++] = ((off + NVSTART) << 16) + len; + break; + } + } + nvbuf.nv.magic = 0x1275; + nvbuf.nv.cksum = 0; + nvbuf.nv.end_vals = NVSTART + (unsigned)&nvbuf.nv.vals[vi] + - (unsigned)&nvbuf; + nvbuf.nv.start_strs = (unsigned short int)(off + NVSTART); + memset(&nvbuf.c[nvbuf.nv.end_vals - NVSTART], 0, (size_t) (nvbuf.nv.start_strs - nvbuf.nv.end_vals)); + nvbuf.nv.cksum = (unsigned short int)(~nvcsum()); +} + +static void print_varOld(int i, int indent) +{ + char *p; + + switch (nvvars[i].type) { + case boolean: + printf("%s", nvvals[i].word_val != 0 ? "true" : "false"); + break; + case word: + printf("0x%lx", nvvals[i].word_val); + break; + case string: + for (p = nvvals[i].str_val; *p; ++p) + if (*p != '\r') + putchar(*p); + else + printf("\n%*s", indent, ""); + break; + } + printf("\n"); +} + +static void parse_val(int i, char *str) +{ + char *endp; + + switch (nvvars[i].type) { + case boolean: + if (strcmp(str, "true") == 0) + nvvals[i].word_val = 1; + else if (strcmp(str, "false") == 0) + nvvals[i].word_val = 0; + else { + fprintf(stderr, "bad boolean value '%s' for %s\n", str, nvvars[i].name); + exit(EXIT_FAILURE); + } + break; + case word: + nvvals[i].word_val = strtoul(str, &endp, 16); + if (str == endp) { + fprintf(stderr, "bad hexadecimal value '%s' for %s\n", str, nvvars[i].name); + exit(EXIT_FAILURE); + } + break; + case string: + nvvals[i].str_val = str; + break; + } +} + +static void nvOld(int ac, char **av, int i, int nvfd) +{ + nvloadOld(nvfd); + nvunpackOld(); + + switch (ac) { + case 1: + for (i = 0; i < N_NVVARS; ++i) { + printf("%-16s", nvvars[i].name); + print_varOld(i, 16); + } + break; + + case 2: + print_varOld(i, 0); + break; + + case 3: + parse_val(i, av[2]); + nvpackOld(); + nvstoreOld(nvfd); + break; + } +} + +int main(int ac, char **av) +{ + int i = 0, nvfd, newWorld; + + if (ac > 3) { + fprintf(stderr, "Usage: %s [variable [value]]\n", av[0]); + exit(EXIT_FAILURE); + } + + newWorld = checkNewWorld(); + + if (!newWorld && ac >= 2) { + for (i = 0; i < N_NVVARS; ++i) + if (strcmp(av[1], nvvars[i].name) == 0) + break; + if (i >= N_NVVARS) { + fprintf(stderr, "%s: no variable called '%s'\n", av[1], av[1]); + exit(EXIT_FAILURE); + } + } + + nvfd = open("/dev/nvram", ac <= 2 ? O_RDONLY : O_RDWR); + if (nvfd < 0) { + perror("Couldn't open /dev/nvram"); + exit(EXIT_FAILURE); + } + + if (newWorld) + nvNew(ac, av, nvfd); + else + nvOld(ac, av, i, nvfd); + + close(nvfd); + exit(EXIT_SUCCESS); +} --- a/doc/Makefile +++ b/doc/Makefile @@ -4,7 +4,7 @@ include ../rules.mk -MANPAGES8 = snap.8 bootlist.8 ofpathname.8 +MANPAGES8 = snap.8 bootlist.8 ofpathname.8 nvsetenv.8 SUBDIRS = nvram --- /dev/null +++ b/doc/nvsetenv.8 @@ -0,0 +1,218 @@ +.if n .ds Q \&" +.if t .ds Q `` +.if n .ds U \&" +.if t .ds U '' +.TH "NVSETENV" 8 +.tr \& +.nr bi 0 +.nr ll 0 +.nr el 0 +.de DS +.. +.de DE +.. +.de Pp +.ie \\n(ll>0 \{\ +.ie \\n(bi=1 \{\ +.nr bi 0 +.if \\n(t\\n(ll=0 \{.IP \\(bu\} +.if \\n(t\\n(ll=1 \{.IP \\n+(e\\n(el.\} +.\} +.el .sp +.\} +.el \{\ +.ie \\nh=1 \{\ +.LP +.nr h 0 +.\} +.el .PP +.\} +.. +.SH NAME + +.Pp +\fBnvsetenv\fP - change/view OF's environment boot-variables +.Pp +.SH SYNOPSIS + +.Pp +\fBnvsetenv\fP [\fIvariable\fP [\fIvalue\fP]] +.Pp +.SH DESCRIPTION + +.Pp +\fBnvsetenv\fP is a program to adjust or view the Open Firmware (OF) +boot parameters stored in non-volatile (battery-powered) RAM on your +Macintosh computer. +\fBnvsetenv\fP will show the current values of all OF's environment +variables when no parameters are given. +.Pp +.SH OPTIONS + +.Pp +.nr ll +1 +.nr t\n(ll 2 +.if \n(ll>1 .RS +.IP "\fIvariable\fP" +.nr bi 1 +.Pp +nvsetenv will show current value of an OF's +variable, if no value is given +.IP "\fIvariable value\fP" +.nr bi 1 +.Pp +nvsetenv will set \fIvariable\fP to +\fIvalue\fP +.if \n(ll>1 .RE +.nr ll -1 +.Pp +.SH EXAMPLES + +.Pp +This example will set the boot device to the first SCSI disk on the +internal SCSI bus, using /vmlinux as boot image, trying to +use the third partition as root partition. +.DS +.sp +.ft RR +.nf + > nvsetenv boot-device \&"scsi-int/sd@0:0\&" + > nvsetenv boot-file \&" /vmlinux root=/dev/sda3\&" +.DE +.fi +.ec +.ft P +.sp +.Pp +Alternatives boot devices are: +.DS +.sp +.ft RR +.nf + scsi/sd@1:0 SCSI disk at ID 1 + ata/ata-disk@0:0 Internal IDE disk +.DE +.fi +.ec +.ft P +.sp +.Pp +You can also boot from a floppy, you need a XCOFF-format kernel image +(in this example: vmlinux.coff), copied to a HFS format high-density +(1.44Mb) floppy. +.DS +.sp +.ft RR +.nf + > nvsetenv boot-device \&"fd:vmlinux.coff\&" + > nvsetenv boot-file \&" root=/dev/sda3\&" +.DE +.fi +.ec +.ft P +.sp + +To return to MacOS, do: +.DS +.sp +.ft RR +.nf + > nvsetenv boot-device \&"/AAPL,ROM\&" +.DE +.fi +.ec +.ft P +.sp +.Pp +Valid values for \&"input-devices\&" are: +.DS +.sp +.ft RR +.nf + ttya Modem serial port + ttyb Printer serial port + kbd Keyboard + enet Ethernet interface +.DE +.fi +.ec +.ft P +.sp +.Pp +Valid values for \&"output-devices\&" are (machine and/or OF dependent): +.DS +.sp +.ft RR +.nf + screen Screen display (newer machines) + /chaos/control Screen display (7500, 7600 and 8500) + /bandit/ATY,264GT-B Screen display (6500) +.DE +.fi +.ec +.ft P +.sp +.Pp +OF is not designed to wait for your hard disk to spin up +(remember MacOS boots from ROM). +Use the following setting to have OF retry to boot from your disk +until is has spun up: +.DS +.sp +.ft RR +.nf + > nvsetenv boot-command \&"begin ['] boot catch 1000 ms cr again\&" +.DE +.fi +.ec +.ft P +.sp +.Pp +You only have to append an \&"S\&" to the \&"boot-file\&" variable to boot +Linux in single user mode. +.Pp +.SH FILES + +.Pp +\fBnvsetenv\fP +needs the following device: +.nr ll +1 +.nr t\n(ll 2 +.if \n(ll>1 .RS +.IP "\fI/dev/nvram\fP" +.nr bi 1 +.Pp +character device with major number 1yy +and minor number 10 +.IP "\fI/proc/cpuinfo\fP" +.nr bi 1 +.Pp +to identify New/Old-World machines +.if \n(ll>1 .RE +.nr ll -1 +.Pp +.SH BUGS + +.Pp +On NewWorld machines setting an undefined variable is not implemented. +.Pp +NewWorld machines contain binary values those are not specially treated. +.Pp +Also it is not a bug take care when setting special characters (\e\e) with +a shell. +.Pp +.SH FILES + +.Pp +macos(8) +.Pp +.SH AUTHORS + +.Pp +Paul Mackerras \f(CR<paulus@cs.anu.edu.au>\fP (program) +.Pp +Richard van Hees \f(CR<R.M.vanHees@fys.ruu.nl>\fP (documentation) +.Pp +Klaus Halfmann \f(CR<halfmann@libra.de>\fP +(NewWorld code, additional documentation) +.Pp
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor