$NetBSD: patch-an,v 1.4 2020/01/23 15:59:36 scole Exp $

--- src/netbsd/ssc-netbsd.c.orig	2010-11-04 05:01:51.000000000 +0000
+++ src/netbsd/ssc-netbsd.c	2020-01-23 08:47:10.550291867 -0800
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 1995-2007, Hewlett-Packard Development Company, L.P.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <util.h>
+#include <poll.h>
+#include <signal.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+/* XXX - B0 is defined in termios.h to mean 0 baud. B0 is also
+ *	 a macro defined in field.h. Undefine B0 here...
+ */
+#undef B0
+
+#include "std.h"
+#include "types.h"
+#include "bits.h"
+#include "exportui.h"
+#include "coreui.h"
+#include "fields.h"
+#include "libui.h"
+#include "sim.h"
+#include "state.h"
+#include "simmem.h"
+#include "ssc.h"
+
+#include "interruption.h"
+
+#include "netbsd/machdep-netbsd.h"
+
+extern char commandline[];
+extern unsigned int commandline_len;
+
+#ifdef NEW_MP
+extern REG os_boot_rendez_ip;
+extern REG os_boot_rendez_gp;
+#endif
+
+SscReqNode *sscHead = NULL;
+SscReqNode *sscPend = NULL;
+
+static struct {
+	short	type;
+	short	irrBit;
+} irptTbl[30];
+static unsigned int irptTop = 0;
+
+static pid_t console;
+static int fdin, fdout;
+static struct termios saved_tios;
+
+static void byteReverse(BYTE *, size_t);
+static void washBytes(BYTE *, size_t);
+
+static void sigchld_handler(int sig, siginfo_t *si, void *ctx)
+{
+	tcsetattr(fdin, TCSANOW, &saved_tios);
+	_exit(1);
+}
+
+static void restore_tios(void)
+{
+	int status;
+
+	tcsetattr(fdin, TCSANOW, &saved_tios);
+	if (console) {
+		kill(console, SIGKILL);
+		wait(&status);
+	}
+}
+
+static void init_console(int fin, int fout)
+{
+	struct termios tios;
+
+	tcgetattr(fin, &tios);
+	saved_tios = tios;
+	tios.c_lflag &= ~(ICANON|ECHO);
+	tios.c_iflag &= ~(ICRNL);	/* do not map CR to NL on input */
+	tcsetattr(fin, TCSANOW, &tios);
+	atexit(restore_tios);
+	fdin = fin;
+	fdout = fout;
+}
+
+static int xconsole()
+{
+	char name[PATH_MAX];
+	struct sigaction act;
+	char tty[PATH_MAX];
+	int namelen;
+	int master, slave;
+
+	if (openpty(&master, &slave, name, NULL, NULL) == -1)
+		goto fail;
+
+	console = fork();
+	switch (console) {
+	case -1:
+		goto fail;
+	case 0: /* child */
+		close(0);
+		close(1);
+		close(2);
+		close(master);
+
+		sprintf(tty, "-S%s/%d", name, slave); 
+		execlp("xterm", "xterm", tty, "-geo", "80x24", "-name",
+		    "xski console", (char *)NULL);
+		perror("execlp(\"xterm\", ...) failed.");
+		abort();
+
+	default: /* parent */
+		close(slave);
+		init_console(master, master);
+		act.sa_sigaction = sigchld_handler;
+		act.sa_flags = SA_NOCLDSTOP|SA_SIGINFO;
+		sigaction(SIGCHLD, &act, NULL);
+
+		/* Read the window ID. */
+		if (read(master, name, 128) == -1)
+			goto fail;
+
+		fcntl(master, F_SETFL, O_NONBLOCK);
+
+		break;
+	}
+
+	return 0;
+
+ fail:
+	progExit("Unable to create console window\n");
+	return -1;
+}
+
+static BOOL addSscReq(int fd, size_t size)
+{
+	SscReqNode *np, *p;
+	int prevcnt = 0;
+
+	if (!(np = malloc(sizeof *np)))
+		return NO;
+	for (p = sscPend; p; p = p->next)
+		prevcnt += p->irptcnt;
+	np->fd = fd;
+	np->count = size;
+	np->irptcnt = IO_IRPT_CNT - prevcnt;
+	np->next = 0;
+	if (sscHead) {
+		for (p = sscHead; p->next; p = p->next) ;
+		p->next = np;
+	} else
+		sscHead = np;
+
+	if (!sscPend)
+		sscPend = np;
+
+	return YES;
+}
+
+static void delSscReq(SscReqNode *p)
+{
+	SscReqNode *q = sscHead;
+
+	if (p != sscHead) {
+		while (q->next != p)
+			q = q->next;
+		q->next = p->next;
+	} else
+		sscHead = sscHead->next;
+
+	if (p == sscPend)
+		sscPend = sscPend->next;
+	free(p);
+}
+
+void pendSscIrpt(unsigned int type)
+{
+	unsigned i, reg, bit, vector;
+	REG *p = &IRR0;			/* assume IRR0-3 are contiguous */
+
+	for (i = 0; i < irptTop; i++) {
+		if (type == irptTbl[i].type) {
+			vector = irptTbl[i].irrBit;
+			if (vector == 1 || (vector >= 3 && vector <= 15))
+				continue;	/* ignore vectors 1 and 3-15 */
+
+			reg = vector >> 6 & 0x3;
+			bit = vector & 0x3F;
+			*(p + reg) |= (REG)1 << bit;
+		}
+	}
+
+	if (acceptIrpt())
+		intrsim = extint = YES;
+}
+
+static void byteReverse(BYTE *b, size_t len) {
+        BYTE tmpByte;
+        size_t start = 0;
+        size_t end = len - 1;
+
+        if ( len < 2 )
+                return;
+
+        while( start < end ) {
+                tmpByte = b[end];
+                b[end] = b[start];
+                b[start] = tmpByte;
+
+                start++;
+                end--;
+        }
+}
+
+/*
+ * reverse bytes when transfering between host & target if
+ * endianness differs.
+ * There are macros available such as FIX_BYTEORDER_* for
+ * HWORD 2 (H),  WORD 4 (W), ADDR/DWORD 8 (D),  QWORD 16 (Q)
+ * that could be used instead, but IMHO this function is more
+ * convenient for some cases
+ *
+ */
+static void washBytes(BYTE *b, size_t len) {
+#if BYTE_ORDER == BIG_ENDIAN
+	/* target little <=> host big */
+	if (!PSR_BE)
+		byteReverse(b, len);
+#else
+	/* target big <=> host little */
+	if (PSR_BE)
+		byteReverse(b, len);
+#endif
+}
+
+void doSSC(HWORD num, REG arg0, REG arg1, REG arg2, REG arg3, REG *ret)
+{
+	BOOL olddt = PSR_DT;
+
+	PSR_DT = 0;
+
+	switch (num) {
+	case SSC_CLOSE:
+		*ret = close(arg0);
+		break;
+
+	case SSC_CONSOLE_INIT: {
+		if (interface == BATCH)
+			init_console(0, 1);
+		else
+			xconsole();
+		break;
+	}
+
+	case SSC_EXIT:
+		GrWrtx (8, arg0, 0);
+		progExit("kernel exited with status %d\n", (int)arg0);
+		break;
+
+	case SSC_GENERATE_INTERRUPT:
+		pendSscIrpt(arg0);
+		break;
+
+	case SSC_GET_ARGS:
+		memBBWrt(arg0, commandline, commandline_len);
+
+		*ret = commandline_len;
+		break;
+
+	case SSC_GET_RTC: {
+		struct timeval tp;
+		struct timezone tzp;
+		struct tm *tm;
+		SscTime sscTime;
+
+		gettimeofday (&tp, &tzp);
+		tm = localtime((const time_t *)&tp.tv_sec);
+		sscTime.year = tm->tm_year;
+		sscTime.mon  = tm->tm_mon;
+		sscTime.mday = tm->tm_mday;
+		sscTime.hour = tm->tm_hour;
+		sscTime.min  = tm->tm_min;
+		sscTime.sec  = tm->tm_sec;
+		sscTime.msec = tp.tv_usec/1000;
+		sscTime.wday = tm->tm_wday;
+
+		sscTime.year = FIX_BYTEORDER_W(PSR_BE, sscTime.year);
+		sscTime.mon  = FIX_BYTEORDER_W(PSR_BE, sscTime.mon);
+		sscTime.mday = FIX_BYTEORDER_W(PSR_BE, sscTime.mday);
+		sscTime.hour = FIX_BYTEORDER_W(PSR_BE, sscTime.hour);
+		sscTime.min  = FIX_BYTEORDER_W(PSR_BE, sscTime.min);
+		sscTime.sec  = FIX_BYTEORDER_W(PSR_BE, sscTime.sec);
+		sscTime.msec = FIX_BYTEORDER_W(PSR_BE, sscTime.msec);
+		sscTime.wday = FIX_BYTEORDER_W(PSR_BE, sscTime.wday);
+
+		memBBWrtP(arg0, (BYTE *)&sscTime, sizeof(SscTime));
+		/* no return value */
+		break;
+	}
+
+	case SSC_GET_TOD: {
+		struct timeval tp;
+		struct timezone tzp;
+ 		SscTimeval tv;
+		SscTimezone tz;
+
+		gettimeofday (&tp, &tzp);
+ 		tv.ssc_Sec = tp.tv_sec;
+		tv.ssc_Usec = tp.tv_usec;
+		tz.ssc_Minuteswest = tzp.tz_minuteswest;
+		tz.ssc_Dsttime = tzp.tz_dsttime;
+
+ 		tv.ssc_Sec = FIX_BYTEORDER_W(PSR_BE, tv.ssc_Sec);
+		tv.ssc_Usec = FIX_BYTEORDER_W(PSR_BE, tv.ssc_Usec);
+		memBBWrtP(arg0, (BYTE *)&tv, sizeof(tv));
+
+		if (arg1 != 0) {
+			tz.ssc_Minuteswest = FIX_BYTEORDER_W(PSR_BE, tz.ssc_Minuteswest);
+			tz.ssc_Dsttime = FIX_BYTEORDER_W(PSR_BE, tz.ssc_Dsttime);
+			memBBWrtP(arg1, (BYTE *)&tz, sizeof(tz));
+		}
+		break;
+	}
+
+	case SSC_GETCHAR: {
+		int sz;
+		char buf[1];
+
+		sz = read(fdin, buf, 1);
+		*ret = (sz == 1) ? buf[0] : 0;
+		break;
+	}
+
+	case SSC_LOAD_SYMBOLS: {
+		char fn[PATH_MAX];
+		memBBRd(arg1, fn, 0);
+		*ret = (elfSymLoad(fn)) ? 0 : -1;
+		break;
+	}
+
+	case SSC_OPEN: {
+		int flags;
+		char fn[PATH_MAX];
+
+		memBBRd(arg0, fn, 0);
+		if (arg1 == SSC_READ_ACCESS)
+			flags = O_RDONLY;
+		else if (arg1 == SSC_WRITE_ACCESS)
+			flags = O_WRONLY;
+		else if (arg1 == (SSC_READ_ACCESS | SSC_WRITE_ACCESS))
+			flags = O_RDWR;
+		else
+			flags = -1;
+
+		*ret = (flags != -1) ? open(fn, flags) : -1;
+		break;
+	}
+
+	case SSC_PUTCHAR: {
+		char buf[1];
+
+		buf[0] = arg0;
+		write(fdout, buf, 1);
+		break;
+	}
+
+	case SSC_READ: {
+		SscDiskReq iov;
+		off_t filesize;
+		size_t size, ofs;
+		ADDR adr;
+		char *map;
+		int i;
+
+		*ret = 0;
+		
+		filesize = lseek(arg0, 0LL, SEEK_END);
+		if (filesize == -1 || arg3 > filesize) {
+			*ret = -1;
+			break;
+		}
+
+		size = 0;
+		adr = arg2;
+		for (i = 0; i < arg1; i++) {
+			memBBRd(adr, (BYTE *)&iov, sizeof(iov));
+			washBytes((BYTE *)&iov.addr, sizeof(iov.addr));
+			washBytes((BYTE *)&iov.len, sizeof(iov.len));
+
+			size += iov.len;
+			adr += sizeof(iov);
+		}
+
+		if (arg3 + size > filesize)
+			size = filesize - arg3;
+
+		map = mmap(0, size, PROT_READ, MAP_SHARED, arg0, arg3);
+		if (map == MAP_FAILED) {
+			*ret = -1;
+			break;
+		}
+
+		adr = arg2;
+		ofs = 0;
+		for (i = 0; i < arg1; i++) {
+			memBBRd(adr, (BYTE *)&iov, sizeof(iov));
+			washBytes((BYTE *)&iov.addr, sizeof(iov.addr));
+			washBytes((BYTE *)&iov.len, sizeof(iov.len));
+			
+			if (ofs + iov.len >= size)
+				iov.len = size - ofs;
+			memBBWrt(iov.addr, map + ofs, iov.len);
+
+			ofs += iov.len;
+			adr += sizeof(iov);
+		}
+
+		munmap(map, size);
+
+		if (!addSscReq(arg0, size))
+			*ret = -1;
+		break;
+	}
+
+	case SSC_WAIT_COMPLETION: {
+		SscDiskStat stat;
+		SscReqNode *p;
+
+		memBBRd(arg0, (BYTE *)&stat, sizeof(stat));
+		washBytes((BYTE *)&stat.fd, sizeof(stat.fd));
+		washBytes((BYTE *)&stat.count, sizeof(stat.count));
+		
+		*ret = -1;
+		for (p = sscPend; p; p = p->next) {
+			if (p->fd == stat.fd) {
+				stat.count = p->count;
+				delSscReq(p);
+				washBytes((BYTE *)&stat.fd, sizeof(stat.fd));
+				washBytes((BYTE *)&stat.count, sizeof(stat.count));
+				memBBWrt(arg0, (BYTE *)&stat, sizeof(stat));
+				*ret = 0;
+				break;
+			}
+		}
+		break;
+	}
+
+	case SSC_WRITE: {
+		SscDiskReq iov;
+		off_t filesize;
+		size_t size, ofs;
+		ADDR adr;
+		char *map;
+		int i;
+
+		filesize = lseek(arg0, 0LL, SEEK_END);
+		if (filesize == -1 || arg3 > filesize) {
+			*ret = -1;
+			break;
+		}
+
+		size = 0;
+		adr = arg2;
+		for (i = 0; i < arg1; i++) {
+			memBBRd(adr, (BYTE *)&iov, sizeof(iov));
+			washBytes((BYTE *)&iov.addr, sizeof(iov.addr));
+			washBytes((BYTE *)&iov.len, sizeof(iov.len));
+
+			size += iov.len;
+			adr += sizeof(iov);
+		}
+
+		if (arg3 + size > filesize)
+			size = filesize - arg3;
+
+		map = mmap(0, size, PROT_WRITE, MAP_SHARED, arg0, arg3);
+		if (map == MAP_FAILED) {
+			*ret = -1;
+			break;
+		}
+
+		adr = arg2;
+		ofs = 0;
+		for (i = 0; i < arg1; i++) {
+			memBBRd(adr, (BYTE *)&iov, sizeof(iov));
+			washBytes((BYTE *)&iov.addr, sizeof(iov.addr));
+			washBytes((BYTE *)&iov.len, sizeof(iov.len));
+
+			if (ofs + iov.len >= size)
+				iov.len = size - ofs;
+			memBBRd(iov.addr, map, iov.len);
+			
+			ofs += iov.len;
+			adr += sizeof(iov);
+		}
+
+		munmap(map, size);
+
+		if (!addSscReq(arg0, size))
+			*ret = -1;
+		break;
+	}
+
+#ifdef NEW_MP
+	case SSC_SAL_SET_VECTORS:
+		if (arg0 == 2) {
+			os_boot_rendez_ip=arg1;
+			os_boot_rendez_gp=arg2;
+		}
+		break;
+#endif
+
+	default:
+		progExit("SSC #%d: unimplemented call\n", num);
+		break;
+	}
+
+	PSR_DT = olddt;
+}
