File powerpc-utils-nvsetenv.patch of Package powerpc-utils

 cmds/Makefile   |    6 
 cmds/nvsetenv.c |  558 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 doc/Makefile    |    2 
 doc/nvsetenv.8  |  218 +++++++++++++++++++++
 4 files changed, 782 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,558 @@
+/*	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 = 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
openSUSE Build Service is sponsored by