commit bd15c8cdcface9cbd7ddc13b78c501445a53d769
Author: Brian Swetland <swetland@frotz.net>
Date: Thu, 11 Jul 2013 18:09:44 -0700
OpenBLT snapshot from early 2000
Diffstat:
342 files changed, 40442 insertions(+), 0 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,27 @@
+/* $Id: //depot/blt/LICENSE#6 $
+**
+** Copyright 1999 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/Makefile b/Makefile
@@ -0,0 +1,41 @@
+BLTHOME := .
+include make.conf
+
+ifeq ($(BUILDLOG),)
+BUILDLOG := `pwd`/build.log
+endif
+
+SUBDIRS := lib kernel srv boot bin util
+
+image: log subdirs
+ ./util/bootmaker $(INIFILES) $(LOCALINIFILES) -o boot/openblt.boot
+
+floppy: subdirs
+ ./util/bootmaker $(INIFILES) $(LOCALINIFILES) -o boot/openblt.boot --floppy
+
+fimage: floppy
+ dd if=/dev/zero of=fd.img bs=1024 count=1440
+ dd if=boot/openblt.boot of=fd.img conv=notrunc
+
+bfloppy: floppy
+ dd if=boot/openblt.boot of=/dev/disk/floppy/raw bs=18k
+
+lfloppy: floppy
+ dd if=boot/openblt.boot of=/dev/fd0 bs=18k
+
+run: image
+ ./util/netboot boot/openblt.boot $(IP)
+
+go:
+ ./util/bootmaker $(INIFILES) $(LOCALINIFILES) -o boot/openblt.boot
+ ./util/netboot boot/openblt.boot $(IP)
+
+all:: log
+
+log::
+ @echo "### `date`" > $(BUILDLOG)
+
+clean::
+ @rm -f boot/openblt.boot
+
+include make.actions
diff --git a/bin/Makefile b/bin/Makefile
@@ -0,0 +1,7 @@
+BLTHOME := ../
+include $(BLTHOME)make.conf
+
+SUBDIRS := vfs_test bltsh ls cat tell validate \
+ fdisk mkdir uname winapp tests sysinfo
+
+include $(BLTHOME)make.actions
diff --git a/bin/bltsh/Makefile b/bin/bltsh/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := bltsh.c
+BINARY := bltsh.bin
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
+
diff --git a/bin/bltsh/bltsh.c b/bin/bltsh/bltsh.c
@@ -0,0 +1,132 @@
+/* $Id: //depot/blt/bin/bltsh/bltsh.c#12 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <blt/syscall.h>
+
+void grab_console(void);
+char **params;
+void __libc_init_console_input (void);
+
+void do_command(int argc, char **argv)
+{
+ struct stat s;
+ int thid;
+
+ if(!strcmp(argv[0], "exit")) os_terminate (1);
+
+ if(!stat(argv[0],&s)){
+ if((thid = execve(argv[0],argv,NULL)) > 0){
+ thr_wait(thid);
+ grab_console();
+ } else {
+ printf("bltsh: failed to execve(): %s\n", argv[0]);
+ }
+ } else {
+ /* try our "path" */
+ char *x = (char *) malloc(7 + strlen(argv[0]));
+
+ strcpy(x,"/boot/");
+ strcpy(x+6,argv[0]);
+ free(argv[0]);
+ argv[0] = x;
+
+ if(!stat(x,&s)){
+ if((thid = execve(argv[0],argv,NULL)) > 0){
+ thr_wait(thid);
+ grab_console();
+ } else {
+ printf("bltsh: failed to execve(): %s\n", argv[0]);
+ }
+ } else {
+ printf("bltsh: no such file or directory: %s\n", argv[0]);
+ }
+ }
+}
+
+int main (void)
+{
+ char line[256], *c;
+ int len, space, i, p_argc;
+
+ __libc_init_console_input ();
+ printf ("\n");
+
+ for (;;)
+ {
+ printf ("$ ");
+
+ *line = len = 0;
+ while (read (0, line + len++, 1) > 0)
+ {
+ if ((line[len - 1] == 8) && (len > 1)) /* BS */
+ len -= 2;
+ else if (line[len - 1] == '\n')
+ {
+ line[len-- - 1] = 0;
+ for (i = space = 0, p_argc = 2; i < len; i++)
+ if ((line[i] == ' ') && !space)
+ space = 1;
+ else if ((line[i] != ' ') && space)
+ {
+ p_argc++;
+ space = 0;
+ }
+ if ((*line != '#') && *line)
+ {
+ params = malloc (sizeof (char *) * p_argc);
+ c = line;
+ for (i = 0; i < p_argc - 1; i++)
+ {
+ for (len = 0; c[len] && (c[len] != ' '); len++) ;
+ params[i] = malloc (len + 1);
+ strlcpy (params[i], c, len + 1);
+ c += len + 1;
+ }
+ params[p_argc - 1] = NULL;
+
+ do_command(p_argc, params);
+
+ for(i=0;i<p_argc;i++)
+ free(params[i]);
+ free(params);
+ }
+ len = 0;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/bin/cat/Makefile b/bin/cat/Makefile
@@ -0,0 +1,8 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := cat.c
+BINARY := cat.bin
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
diff --git a/bin/cat/cat.c b/bin/cat/cat.c
@@ -0,0 +1,60 @@
+/* $Id: //depot/blt/bin/cat/cat.c#4 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int main (int argc, char **argv)
+{
+ char *buf;
+ int fd, res;
+
+ if (argc == 1)
+ {
+ printf ("cat: must specify a file\n");
+ return -1;
+ }
+ buf = malloc (256);
+ fd = open (argv[1], O_RDONLY, 0);
+ if (fd < 0)
+ {
+ printf ("cat: no such file or directory: %s\n", argv[1]);
+ return 0;
+ }
+ while ((res = read (fd, buf, 255)))
+ {
+ buf[res] = 0;
+ printf (buf);
+ }
+ close (fd);
+
+ return 0;
+}
+
diff --git a/bin/fdisk/Makefile b/bin/fdisk/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := fdisk.c
+BINARY := fdisk.bin
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
+
diff --git a/bin/fdisk/fdisk.c b/bin/fdisk/fdisk.c
@@ -0,0 +1,78 @@
+/* $Id: //depot/blt/bin/fdisk/fdisk.c#6 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <blt/blkdev.h>
+#include <blt/disk.h>
+
+const static char *def_device = "ide/0/0/raw";
+
+int main (int argc, char **argv)
+{
+ const char *devname;
+ unsigned char *buf;
+ int i;
+ blkdev_t *dev;
+ disk_t *disk;
+
+ if (argc == 1)
+ {
+ printf ("fdisk: no device specified; using default of %s\n",
+ def_device);
+ devname = def_device;
+ }
+ else
+ devname = argv[1];
+
+ blk_open (devname, 0, &dev);
+ if (dev == NULL)
+ {
+ printf ("fdisk: error opening %s\n", devname);
+ return 1;
+ }
+ buf = malloc (dev->blksize * 2);
+ blk_read (dev, buf, 0, 2);
+
+ disk = disk_alloc (dev);
+ for (i = 0; i < disk->numparts; i++)
+ printf ("partition %s%s, type %X%X, start = %d, size = %d\n",
+ disk_partition_name (disk, i),
+ disk_partition_name (disk, i)[1] ? "" : " ",
+ ((int) disk_partition_type (disk, i) & 0xff00) >> 8,
+ (int) disk_partition_type (disk, i) & 0xff,
+ (int) disk_partition_start (disk, i),
+ (int) disk_partition_size (disk, i));
+ disk_free (disk);
+
+ blk_close (dev);
+ free (buf);
+
+ return 0;
+}
+
diff --git a/bin/ls/Makefile b/bin/ls/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := ls.c
+BINARY := ls.bin
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
+
diff --git a/bin/ls/ls.c b/bin/ls/ls.c
@@ -0,0 +1,79 @@
+/* $Id: //depot/blt/bin/ls/ls.c#4 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+
+static int dirent_compare (const void *a, const void *b)
+{
+ const struct dirent *c, *d;
+
+ c = a, d = b;
+ return strcmp (c->d_name, d->d_name);
+}
+
+int main (int argc, char **argv)
+{
+ char *path;
+ int i, j, k, l, maxlen, maxnum;
+ struct dirent *ent[128];
+ DIR *dir;
+
+ path = (argc == 1) ? "/" : argv[1];
+ i = maxlen = 0;
+ dir = opendir (path);
+ if (dir == NULL)
+ {
+ printf ("ls: %s: no such file or directory\n", path);
+ return 0;
+ }
+ while ((ent[i] = readdir (dir)) != NULL)
+ {
+ maxlen = (strlen (ent[i]->d_name) > maxlen) ? strlen (ent[i]->d_name) :
+ maxlen;
+ i++;
+ }
+ closedir (dir);
+ maxnum = 80 / (maxlen + 2);
+ qsort (*ent, i, sizeof (struct dirent), dirent_compare);
+ for (k = 0; k < i; k+= j)
+ {
+ for (j = 0; ((j + k) < i) && (j < maxnum); j++)
+ {
+ printf ("%s", ent[j + k]->d_name);
+ for (l = strlen (ent[j + k]->d_name); l < (maxlen + 2); l++)
+ printf (" ");
+ }
+ printf ("\n");
+ }
+
+ return 0;
+}
+
diff --git a/bin/mkdir/Makefile b/bin/mkdir/Makefile
@@ -0,0 +1,8 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := mkdir.c
+BINARY := mkdir.bin
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
diff --git a/bin/mkdir/mkdir.c b/bin/mkdir/mkdir.c
@@ -0,0 +1,42 @@
+/* $Id: //depot/blt/bin/mkdir/mkdir.c#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+int main (int argc, char **argv)
+{
+ if (argc != 2)
+ {
+ printf ("usage: mkdir dirname\n");
+ return 1;
+ }
+ mkdir (argv[1], 755);
+ return 0;
+}
+
diff --git a/bin/pci/Makefile b/bin/pci/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+BINARY := pci.bin
+SRCS := pci.c
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
+
diff --git a/bin/pci/pci.c b/bin/pci/pci.c
@@ -0,0 +1,160 @@
+/* $Id$
+**
+** Copyright 1999 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <i386/io.h>
+
+#include "pci.h"
+
+uint32 read_pci(int bus, int dev, int func, int reg, int bytes)
+{
+ uint32 base;
+
+ union {
+ confadd c;
+ uint32 n;
+ } u;
+
+ u.c.enable = 1;
+ u.c.rsvd = 0;
+ u.c.bus = bus;
+ u.c.dev = dev;
+ u.c.func = func;
+ u.c.reg = reg & 0xFC;
+
+ outl(u.n,0xCF8);
+
+ base = 0xCFC + (reg & 0x03);
+
+ switch(bytes){
+ case 1: return inb(base);
+ case 2: return inw(base);
+ case 4: return inl(base);
+ default: return 0;
+ }
+}
+
+void write_pci(int bus, int dev, int func, int reg, uint32 v, int bytes)
+{
+ uint32 base;
+
+ union {
+ confadd c;
+ uint32 n;
+ } u;
+
+ u.c.enable = 1;
+ u.c.rsvd = 0;
+ u.c.bus = bus;
+ u.c.dev = dev;
+ u.c.func = func;
+ u.c.reg = reg & 0xFC;
+
+ base = 0xCFC + (reg & 0x03);
+ outl(u.n,0xCF8);
+ switch(bytes){
+ case 1: outb(v,base); break;
+ case 2: outw(v,base); break;
+ case 4: outl(v,base); break;
+ }
+
+}
+
+void probe(int bus, int dev, int func)
+{
+ union {
+ pci_cfg cfg;
+ uint32 word[4];
+ } x;
+ pci_cfg *cfg = &x.cfg;
+ uint32 v;
+ int i;
+ for(i=0;i<4;i++){
+ x.word[i] = read_pci(bus,dev,func,4*i,4);
+ }
+ if(cfg->vendor_id == 0xffff) return;
+
+ printf("Device Info: /bus/pci/%d/%d/%d\n",bus,dev,func);
+ printf(" * Vendor: %S Device: %S Class/SubClass/Interface %X/%X/%X\n",
+ cfg->vendor_id,cfg->device_id,cfg->base_class,cfg->sub_class,cfg->interface);
+ printf(" * Status: %S Command: %S BIST/Type/Lat/CLS: %X/%X/%X/%X\n",
+ cfg->status, cfg->command, cfg->bist, cfg->header_type,
+ cfg->latency_timer, cfg->cache_line_size);
+
+ switch(cfg->header_type & 0x7F){
+ case 0: /* normal device */
+ for(i=0;i<6;i++){
+ v = read_pci(bus,dev,func,i*4 + 0x10, 4);
+ if(v) {
+ int v2;
+ write_pci(bus,dev,func,i*4 + 0x10, 0xffffffff, 4);
+ v2 = read_pci(bus,dev,func,i*4+0x10, 4) & 0xfffffff0;
+ v2 = 1 + ~v2;
+ if(v & 1) {
+ printf(" * Base Register %d IO: %x (%x)\n",i,v&0xfff0,v2&0xffff);
+ } else {
+ printf(" * Base Register %d MM: %x (%x)\n",i,v&0xfffffff0,v2);
+ }
+ }
+ }
+ v = read_pci(bus,dev,func,0x3c,1);
+ if((v != 0xff) && (v != 0)) printf(" * Interrupt Line: %X\n",v);
+ break;
+ case 1:
+ printf(" * PCI <-> PCI Bridge\n");
+ break;
+ default:
+ printf(" * Unknown Header Type\n");
+ }
+
+ if(cfg->header_type & 0x80){
+ for(i=1;i<8;i++){
+ probe(bus,dev,i);
+ }
+ }
+
+// v = read_pci(bus,dev,func,0x3C);
+// printf(" * Lat/Gnt/IntPin/IntLine: %x\n",v);
+}
+
+int main (int argc, char **argv)
+{
+ int bus,dev;
+
+ for(bus=0;bus<255;bus++){
+ for(dev=0;dev<32;dev++) {
+ probe(bus,dev,0);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/bin/pci/pci.h b/bin/pci/pci.h
@@ -0,0 +1,31 @@
+
+typedef struct
+{
+ uchar reg:8;
+ uchar func:3;
+ uchar dev:5;
+ uchar bus:8;
+ uchar rsvd:7;
+ uchar enable:1;
+} confadd;
+
+typedef struct
+{
+ uint16 vendor_id;
+ uint16 device_id;
+
+ uint16 command;
+ uint16 status;
+
+ uint8 revision_id;
+ uint8 interface;
+ uint8 sub_class;
+ uint8 base_class;
+
+ uint8 cache_line_size;
+ uint8 latency_timer;
+ uint8 header_type;
+ uint8 bist;
+} pci_cfg;
+
+
diff --git a/bin/sysinfo/Makefile b/bin/sysinfo/Makefile
@@ -0,0 +1,11 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+BINARY := sysinfo.bin
+SRCS := sysinfo.cpp
+LIBS := -lposix -lblt -lc
+CXXFLAGS += -I ../../srv/pci
+CFLAGS += -I ../../srv/pci
+
+include $(BLTHOME)make.actions
+
diff --git a/bin/sysinfo/sysinfo.cpp b/bin/sysinfo/sysinfo.cpp
@@ -0,0 +1,90 @@
+#include <blt/Message.h>
+#include <blt/Connection.h>
+
+#include <blt/syscall.h>
+
+#include <stdio.h>
+
+#define PCI_STUB
+
+#include <pci.h>
+#include <string.h>
+#include <stdlib.h>
+
+using namespace BLT;
+
+int pci_dump(PCI *pci)
+{
+ Message msg;
+ pci_cfg cfg;
+ int n;
+
+ printf("bus dev func vndr devc cls sub ifc irq base[0] size[0] base[1] size[1] \n");
+ printf("---- ---- ---- ---- ---- ---- ---- ---- ---- -------- -------- -------- --------\n");
+
+ for(n=0;pci->get_nth_cfg(n,&cfg) == 0;n++){
+ printf("%U %U %U %S %S %U %U %U ",
+ cfg.bus, cfg.dev, cfg.func,
+ cfg.vendor_id, cfg.device_id,
+ cfg.base_class, cfg.sub_class, cfg.interface);
+ switch(cfg.header_type & 0x7f){
+ case 0:
+ printf("%U %x %x %x %x\n", cfg.irq,
+ cfg.base[0], cfg.size[0],
+ cfg.base[1], cfg.size[1]);
+ break;
+
+ case 1:
+ printf(" (pci <-> pci bridge)\n");
+ break;
+
+ default:
+ printf(" (unknown header type)\n");
+ }
+ }
+}
+
+void dump_rom(PCI *pci, int bus, int dev, int func)
+{
+ int i;
+ uchar *rom = (uchar *) 0xf0000000;
+
+ area_create(4096, 0, (void**) &rom, AREA_PHYSMAP);
+ printf("device: %d / %d / %d\n",bus,dev,func);
+
+ pci->write(bus,dev,func,0x30,0xf0000001,4);
+
+ for(i=0;i<256;i+=16){
+ printf("%S: %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X\n",
+ i, rom[i+0], rom[i+1], rom[i+2], rom[i+3],
+ rom[i+4], rom[i+5], rom[i+6], rom[i+7],
+ rom[i+8], rom[i+9], rom[i+10], rom[i+11],
+ rom[i+12], rom[i+13], rom[i+14], rom[i+15]);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ PCI *pci = PCI::FindService();
+
+ if(argc == 5){
+ char *cmd = argv[1];
+ int bus = atoi(argv[2]);
+ int dev = atoi(argv[3]);
+ int func = atoi(argv[4]);
+
+ if(!strcmp(cmd,"rom")){
+ dump_rom(pci,bus,dev,func);
+ }
+
+ return 0;
+ }
+
+ if(!pci) {
+ printf("sysinfo: cannot find pci service\n");
+ } else {
+ pci_dump(pci);
+ }
+
+ return 0;
+}
diff --git a/bin/tell/Makefile b/bin/tell/Makefile
@@ -0,0 +1,8 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := tell.c
+BINARY := tell.bin
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
diff --git a/bin/tell/tell.c b/bin/tell/tell.c
@@ -0,0 +1,50 @@
+/* Copyright 1999, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <blt/syscall.h>
+#include <blt/namer.h>
+
+int main (int argc, char **argv)
+{
+ char *text;
+ int i, loc_port, rem_port;
+ msg_hdr_t mh;
+
+ if (argc < 3)
+ {
+ printf ("tell: syntax: tell [server] [message]\n");
+ return 0;
+ }
+ text = malloc (256);
+ strlcpy (text, argv[1], 256);
+ strlcat (text, ":tell", 256);
+
+ rem_port = namer_find (text, 0);
+ if (rem_port < 1)
+ {
+ printf ("tell: no such server or server not using tell\n");
+ return 0;
+ }
+ loc_port = port_create (rem_port,"port");
+ strlcpy (text, argv[2], 256);
+ for (i = 3; i < argc; i++)
+ {
+ strlcat (text, " ", 256);
+ strlcat (text, argv[i], 256);
+ }
+
+ mh.src = loc_port;
+ mh.dst = rem_port;
+ mh.data = text;
+ mh.size = strlen (text) + 1;
+ old_port_send (&mh);
+ mh.src = rem_port;
+ mh.dst = loc_port;
+ old_port_recv (&mh);
+ return 0;
+}
+
diff --git a/bin/tests/Makefile b/bin/tests/Makefile
@@ -0,0 +1,10 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := tests.cpp
+CFLAGS += -fno-rtti -fno-exceptions -fno-rtti
+LIBS := -lposix -lblt -lc
+BINARY := tests.bin
+
+include $(BLTHOME)make.actions
+
diff --git a/bin/tests/tests.cpp b/bin/tests/tests.cpp
@@ -0,0 +1,125 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <blt/syscall.h>
+#include <blt/os.h>
+
+#define LOOK_ITS_A_RACE 1
+
+#if LOOK_ITS_A_RACE
+ int malloc_sem = -1;
+#endif
+
+//
+// Test malloc()
+//
+int malloc_thread(void*)
+{
+ for (int i = 0; i < 50000; i++){
+#if LOOK_ITS_A_RACE
+ sem_acquire(malloc_sem);
+#endif
+ free(malloc(10000));
+
+#if LOOK_ITS_A_RACE
+ sem_release(malloc_sem);
+#endif
+ }
+
+ printf("malloc thread finished\n");
+ os_terminate(0);
+ return 0;
+}
+
+void malloc_test(void)
+{
+ printf("starting malloc tests\n");
+#if LOOK_ITS_A_RACE
+ malloc_sem = sem_create(1,"malloc lock");
+#endif
+
+ for (int i = 0; i < 5; i++)
+ thr_create(malloc_thread, 0, "malloc_thread");
+}
+
+
+//
+// producer/consumer
+//
+struct cl_info {
+ char name[32];
+ int port;
+};
+
+int consumer(void *_p)
+{
+ int port = ((cl_info*) _p)->port;
+ char buffer[10];
+
+ for (;;) {
+ msg_hdr_t header;
+ header.src = 0;
+ header.dst = port;
+ header.data = buffer;
+ header.size = 10;
+ old_port_recv(&header);
+ printf("%s receive\n", ((cl_info*) _p)->name);
+ }
+}
+
+int producer(void *_p)
+{
+ int port = ((cl_info*) _p)->port;
+ char buffer[10];
+
+ for (;;) {
+ msg_hdr_t header;
+ header.src = port;
+ header.dst = port;
+ header.data = buffer;
+ header.size = 10;
+ old_port_send(&header);
+ printf("%s send\n", ((cl_info*) _p)->name);
+ }
+}
+
+void prodcons(int num_producers, int num_consumers)
+{
+ int port = port_create(0, "prodcons");
+ printf("%d producers, %d consumers\n", num_producers, num_consumers);
+ for (int i = 0; i < num_producers; i++) {
+ cl_info *scinfo = new cl_info;
+ snprintf(scinfo->name, 32, "producer %d", i + 1);
+ scinfo->port = port;
+ thr_create(producer, scinfo, scinfo->name);
+ }
+
+ for (int i = 0; i < num_consumers; i++) {
+ cl_info *scinfo = new cl_info;
+ snprintf(scinfo->name, 32, "consumer %d", i + 1);
+ scinfo->port = port;
+ thr_create(consumer, scinfo, scinfo->name);
+ }
+}
+
+
+int main()
+{
+ // Case 1: malloc tests.
+ // This crashes the kernel when more than 1 thread is doing malloc/
+ // free operations. Using only one thread, or using my own locks,
+ // reduces the problem, although I still see a reboot once in a while.
+ malloc_test();
+
+ // Case 2: single producer, single consumer
+ // The system quickly wedges when I do this.
+// prodcons(1, 1);
+
+ // case 3: multi-producer, single consumer
+ // The kernel code looks like it might not handle this case properly.
+// prodcons(2, 1);
+
+ // Case 4: multi-consumer, single producer
+// prodcons(1, 2);
+
+ return 0;
+}
diff --git a/bin/uname/Makefile b/bin/uname/Makefile
@@ -0,0 +1,8 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+BINARY := uname.bin
+OBJS := uname.o ../../lib/version.o
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
diff --git a/bin/uname/uname.c b/bin/uname/uname.c
@@ -0,0 +1,96 @@
+/* $Id: //depot/blt/bin/uname/uname.c#3 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+
+#define ATTR(attr, value) \
+ if (attr) \
+ { \
+ if (start) \
+ printf (" "); \
+ else \
+ start = 1; \
+ printf (value); \
+ }
+
+extern char *ostype, *osrelease, *osversion;
+
+int main (int argc, char **argv)
+{
+ int opt, any, start, machine, nodename, processor, system, release, version;
+
+ any = machine = nodename = processor = system = release = version = 0;
+ while ((opt = getopt (argc, argv, "amnpsrv")) != -1)
+ switch (opt)
+ {
+ case 'a':
+ any = machine = nodename = processor = system = release =
+ version = 1;
+ break;
+
+ case 'm':
+ any = machine = 1;
+ break;
+
+ case 'n':
+ any = nodename = 1;
+ break;
+
+ case 'p':
+ any = processor = 1;
+ break;
+
+ case 's':
+ any = system = 1;
+ break;
+
+ case 'r':
+ any = release = 1;
+ break;
+
+ case 'v':
+ any = version = 1;
+ break;
+
+ default:
+ return 1;
+ }
+
+ if (!any)
+ system = 1;
+ start = 0;
+ ATTR (system, ostype)
+ ATTR (nodename, "(noname)")
+ ATTR (release, osrelease)
+ ATTR (version, osversion)
+ ATTR (machine, "Intel")
+ printf ("\n");
+ return 0;
+}
+
diff --git a/bin/validate/Makefile b/bin/validate/Makefile
@@ -0,0 +1,8 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := validate.c
+BINARY := validate.bin
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
diff --git a/bin/validate/validate.c b/bin/validate/validate.c
@@ -0,0 +1,125 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <blt/syscall.h>
+#include <blt/namer.h>
+
+int send_port, recv_port;
+
+
+void sender(void)
+{
+ char buffer[32];
+ msg_hdr_t mh;
+
+ os_sleep(20);
+
+ for(;;){
+ mh.src = send_port;
+ mh.dst = recv_port;
+ mh.size = 32;
+ mh.flags = 0;
+ mh.data = buffer;
+
+ old_port_send(&mh);
+ }
+}
+
+void receiver(void)
+{
+ char buffer[32];
+ msg_hdr_t mh;
+
+ recv_port = port_create(0,"recv port");
+ os_sleep(20);
+
+ for(;;){
+ mh.src = 0;
+ mh.dst = recv_port;
+ mh.size = 32;
+ mh.flags = 0;
+ mh.data = buffer;
+
+ old_port_recv(&mh);
+ }
+}
+
+int port_test(void)
+{
+ int s,c;
+ printf("port_test: starting\n");
+ for(c=0;c<1000000;c++){
+ if(!(c % 100000)) printf("port_test: %dth port\n",c);
+ if((s = port_create(0,"port test")) < 1) {
+ printf("port_test: failed (in create) - iteration %d\n",c);
+ return 1;
+ }
+ if(port_destroy(s)){
+ printf("port_test: failed (in destroy) - iteration %d\n",c);
+ return 1;
+ }
+ }
+ printf("port_test: passed\n");
+ return 0;
+}
+
+int semid;
+
+void tt_thread(void *data)
+{
+ sem_release(semid);
+ os_terminate(0);
+}
+
+int thread_test(void)
+{
+ int n;
+ semid = sem_create(0, "thread_test_step");
+
+ for(n=0;n<100000;n++){
+ if(!(n % 1000)) printf("thread_test: %dth thread\n",n);
+ thr_create(tt_thread, NULL, "thread test");
+ sem_acquire(semid);
+ }
+
+}
+
+int sem_test(void)
+{
+ int s,c;
+ printf("sem_test: starting\n");
+ for(c=0;c<1000000;c++){
+ if(!(c % 100000)) printf("sem_test: %dth semaphore\n",c);
+ if((s = sem_create(1,"sem test")) < 1) {
+ printf("sem_test: failed (in create) - iteration %d\n",c);
+ return 1;
+ }
+ if(sem_destroy(s)){
+ printf("sem_test: failed (in destroy) - iteration %d\n",c);
+ return 1;
+ }
+ }
+ printf("sem_test: passed\n");
+ return 0;
+}
+
+int main (int argc, char **argv)
+{
+ int s,c;
+
+#if 0
+ send_port = port_create(0,"xmit port");
+ os_thread(sender);
+ receiver();
+#endif
+
+#if 0
+ if(sem_test()) return 0;
+ if(port_test()) return 0;
+#endif
+
+ if(thread_test()) return 0;
+
+ return 0;
+}
+
diff --git a/bin/vfs_test/Makefile b/bin/vfs_test/Makefile
@@ -0,0 +1,14 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := vfs_test.c
+BINARY := vfs_test.bin
+LIBS := -lposix -lblt -ldl -lc
+
+TARGETS := foo.so
+
+foo.so: foo.o
+ $(LD) -Bshareable -o foo.so foo.o
+
+include $(BLTHOME)make.actions
+
diff --git a/bin/vfs_test/foo.c b/bin/vfs_test/foo.c
@@ -0,0 +1,50 @@
+/* $Id: //depot/blt/bin/vfs_test/foo.c#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+
+extern void jim (void);
+
+static void _init (void)
+{
+ printf ("foo: hello\n");
+#ifdef MAKE_DLOPEN_ERROR
+ jim ();
+#endif
+}
+
+static void _fini (void)
+{
+ printf ("foo: goodbye\n");
+}
+
+void bar (void)
+{
+ printf ("foo: bar\n");
+}
+
diff --git a/bin/vfs_test/vfs_test.c b/bin/vfs_test/vfs_test.c
@@ -0,0 +1,107 @@
+/* Copyright 1999, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <sys/stat.h>
+#include <blt/syscall.h>
+#include <blt/namer.h>
+#include <blt/qsem.h>
+#include <blt/fdl.h>
+
+
+int main (void)
+{
+#if 0
+ int i, j, k;
+ msg_hdr_t mh;
+ qsem_t *sem;
+ DIR *dir1, *dir2;
+ struct dirent *dirent;
+ struct stat buf;
+ char c;
+ void *ptr;
+ int (*fn1)(char *), (*fn2)(void);
+
+/*
+ dir1 = opendir ("/");
+ while ((dirent = readdir (dir1)) != NULL)
+ printf ("readdir says %d %s\n", dirent->d_fileno, dirent->d_name);
+ closedir (dir1);
+ dir2 = opendir ("/");
+ while ((dirent = readdir (dir2)) != NULL)
+ printf ("readdir says %d %s\n", dirent->d_fileno, dirent->d_name);
+ closedir (dir2);
+ dir1 = opendir ("/boot");
+ while ((dirent = readdir (dir1)) != NULL)
+ printf ("readdir says %d %s\n", dirent->d_fileno, dirent->d_name);
+ closedir (dir1);
+*/
+ i = open ("/boot/rc.boot", O_RDONLY, 0);
+ printf ("got fd %d\n", i);
+/*
+ if (i >= 0)
+ while (read (i, &c, 1))
+ printf ("%c", c);
+*/
+ close (i);
+ i = open ("/boot/rc.boot", O_RDONLY, 0);
+ printf ("got fd %d\n", i);
+/*
+ if (i >= 0)
+ while (read (i, &c, 1))
+ printf ("%c", c);
+*/
+ close (i);
+/*
+ dir1 = opendir ("/portal");
+ if (dir1 != NULL)
+ while ((dirent = readdir (dir1)) != NULL)
+ printf ("readdir says %d %s\n", dirent->d_fileno, dirent->d_name);
+ closedir (dir1);
+*/
+ //i = stat ("/boot/rc.boot", &buf);
+/*
+ if (i)
+ printf ("stat failed\n");
+ else
+ {
+ printf ("stat is good\n");
+ printf ("size is %d\n", buf.st_size);
+ }
+*/
+/*
+ printf ("going for input...\n");
+ for (;;)
+ {
+ c = getchar ();
+ printf ("we got %d\n", c);
+ }
+*/
+/*
+ printf ("opening /boot/foo.so\n");
+ ptr = dlopen ("/boot/foo.so", 0);
+ if (ptr != NULL)
+ {
+ fn2 = dlsym (ptr, "bar");
+ (*fn2) ();
+ printf ("closing\n");
+ dlclose (ptr);
+ }
+ else
+ printf ("error: %s\n", dlerror ());
+*/
+#endif
+
+ int *ptr;
+
+ ptr = 1;
+ printf ("hello %d\n", *ptr);
+
+ return 0;
+}
+
diff --git a/bin/winapp/Connection.o b/bin/winapp/Connection.o
Binary files differ.
diff --git a/bin/winapp/Makefile b/bin/winapp/Makefile
@@ -0,0 +1,10 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := main.cpp
+CFLAGS += -fno-rtti -fno-exceptions
+LIBS := -lwin -lblt -lposix -lc
+BINARY := winapp.bin
+
+include $(BLTHOME)make.actions
+
diff --git a/bin/winapp/Window.o b/bin/winapp/Window.o
Binary files differ.
diff --git a/bin/winapp/main.cpp b/bin/winapp/main.cpp
@@ -0,0 +1,123 @@
+#include <blt/os.h>
+#include <blt/syscall.h>
+#include <blt/qsem.h>
+#include <win/Window.h>
+#include <win/Canvas.h>
+#include <win/Event.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+const int kCellWidth = 10;
+
+class DrawingArea : public Canvas {
+public:
+ DrawingArea();
+ virtual void EventReceived(const Event*);
+private:
+ int fLastX;
+ int fLastY;
+ bool fButtonDown;
+};
+
+class PaletteArea : public Canvas {
+public:
+ PaletteArea(DrawingArea *draw);
+ virtual void EventReceived(const Event*);
+ virtual void Repaint(long left, long top, long right, long bottom);
+private:
+ DrawingArea *fDrawingArea;
+ int fCurrentColor;
+};
+
+DrawingArea::DrawingArea()
+ : fButtonDown(false)
+{
+}
+
+void DrawingArea::EventReceived(const Event *event)
+{
+ switch (event->what) {
+ case EVT_MOUSE_DOWN:
+ LockMouseFocus();
+ fButtonDown = true;
+ fLastX = event->x;
+ fLastY = event->y;
+ break;
+
+ case EVT_MOUSE_UP:
+ fButtonDown = false;
+ break;
+
+ case EVT_MOUSE_MOVED:
+ if (fButtonDown) {
+ printf("DrawLine(%d, %d, %d, %d)\n", fLastX, fLastY, event->x, event->y);
+ DrawLine(fLastX, fLastY, event->x, event->y);
+ fLastX = event->x;
+ fLastY = event->y;
+ GetWindow()->Flush();
+ }
+
+ break;
+
+ default:
+ Canvas::EventReceived(event);
+
+ }
+}
+
+PaletteArea::PaletteArea(DrawingArea *draw)
+ : fDrawingArea(draw)
+{
+}
+
+void PaletteArea::EventReceived(const Event *event)
+{
+ switch (event->what) {
+ case EVT_MOUSE_DOWN:
+ printf("PaletteArea: EventReceived\n");
+ fDrawingArea->SetPenColor(event->x / kCellWidth * 2);
+ Invalidate(fCurrentColor * kCellWidth, 0, fCurrentColor * kCellWidth + kCellWidth, 10);
+ fCurrentColor = event->x / kCellWidth;
+ Invalidate(fCurrentColor * kCellWidth, 0, fCurrentColor * kCellWidth + kCellWidth, 10);
+ break;
+
+ default:
+ Canvas::EventReceived(event);
+ }
+}
+
+void PaletteArea::Repaint(long left, long top, long right, long bottom)
+{
+ int x = (left / kCellWidth) * kCellWidth;
+ while (x < right) {
+ SetPenColor(x / kCellWidth * 2);
+ FillRect(x, top, x + kCellWidth, bottom);
+ if (x / kCellWidth == fCurrentColor) {
+ SetPenColor(0);
+ DrawLine(x, top, x + kCellWidth, top);
+ DrawLine(x, bottom, x + kCellWidth, bottom);
+ DrawLine(x, top, x, bottom);
+ DrawLine(x + kCellWidth, top, x + kCellWidth, bottom);
+ }
+
+ x += kCellWidth;
+ }
+}
+
+int main()
+{
+ Window *win = new Window(50, 30, 270, 180);
+ win->Lock();
+ win->Show();
+ Canvas *border = new Canvas;
+ win->AddChild(border, 0, 0, 250, 150);
+ border->SetBackgroundColor(10);
+ DrawingArea *draw = new DrawingArea;
+ PaletteArea *palette = new PaletteArea(draw);
+ border->AddChild(draw, 2, 2, 218, 139);
+ border->AddChild(palette, 2, 140, 218, 148);
+ draw->SetBackgroundColor(250);
+ win->Unlock();
+ return 0;
+}
diff --git a/boot/Makefile b/boot/Makefile
@@ -0,0 +1,12 @@
+BLTHOME := ../
+
+include $(BLTHOME)make.conf
+
+CFLAGS += -I../kernel
+BINARY := boot.bin
+OBJS := bootstub.o boot.o
+LIBS := -lconsole
+ENTRY := $(ENTRY_BOOTSTRAP)
+CRT0 :=
+
+include $(BLTHOME)make.actions
diff --git a/boot/boot.c b/boot/boot.c
@@ -0,0 +1,156 @@
+/* $Id: //depot/blt/boot/boot.c#3 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Stage Two Bootloader -- init paged memory, map the kernel, and
+ * relocate to k_start()
+ */
+#define noDIAG
+
+#include "types.h"
+#include "boot.h"
+#include <multiboot.h>
+
+#ifdef DIAG
+#include "../include/blt/conio.h"
+#endif
+
+void (*k_start)(void);
+
+struct _kinfo
+{
+ uint32 memsize;
+ uint32 entry_ebp;
+ boot_dir *bd;
+ unsigned char *param;
+} *kinfo = (struct _kinfo *) 0x00102000;
+
+static unsigned int multiboot[] __attribute__ ((__section__ (".text"))) =
+{
+ 0x1badb002,
+ 0x00010002,
+ (unsigned int) 0 - 0x1badb002 - 0x00010002,
+ (unsigned int) multiboot,
+ 0x100000,
+ 0x14a000,
+ 0x14a000,
+ 0x101074
+};
+
+static void enable_paging (void)
+{
+ __asm__ ("movl $0x80000001, %eax ; mov %eax, %cr0");
+}
+
+void bootstrap(boot_dir *bd, uint32 memsize, uint32 entry_ebp, char *p)
+{
+ uint32 *flat;
+ uint32 _cr3;
+ int i;
+
+ kinfo->memsize = memsize;
+ kinfo->entry_ebp = entry_ebp;
+ kinfo->bd = bd;
+ kinfo->param = p;
+
+#ifdef DIAG
+ con_init();
+ cprintf("memsize = %x, bdir @ %x, ebp = %x\n",memsize,(int)bd,entry_ebp);
+ cprintf("name[0] = %s\n",bd->bd_entry[0].be_name);
+ cprintf("name[1] = %s\n",bd->bd_entry[1].be_name);
+ cprintf("name[2] = %s\n",bd->bd_entry[2].be_name);
+#endif
+
+ flat = (void*) ((4096*(memsize/4096)) - 4096*3);
+
+ for(i=0;i<1024;i++){
+ flat[i] = 0;
+ flat[1024+i] = 4096*i | 3;
+ flat[2048+i] = i > bd->bd_entry[2].be_size ? 0 : /* XXX! EEK! */
+ ( (bd->bd_entry[2].be_offset*4096+0x100000) + 4096*i) | 3;
+
+#ifdef DIAG
+ if(flat[2048+i]){
+ cprintf("%x -> %x\n",
+ bd->bd_entry[2].be_offset*4096+0x100000 + 4096*i,
+ 0x8000000+4096*i);
+ }
+#endif
+ }
+
+ k_start = (void (*)(void)) 0x80000000 + (bd->bd_entry[2].be_code_ventr);
+
+ /* point the pdir at ptab1 and ptab2 */
+ flat[0] = (uint32) &flat[1024] | 3;
+ flat[512] = (uint32) &flat[2048] | 3;
+
+ /* map the pdir, ptab1, ptab2 starting at 0x803FD000 */
+ flat[2048+1023] = ((uint32) flat + 2*4096) | 3;
+ flat[2048+1022] = ((uint32) flat + 1*4096) | 3;
+ flat[2048+1021] = ((uint32) flat) | 3;
+
+ _cr3 = (uint32) flat;
+ __asm__ ("mov %0, %%cr3"::"r" (_cr3));
+ enable_paging ();
+
+#ifdef DIAG
+ flat = 0x803fd000;
+
+ for(i=0;i<3000000;i++);
+ for(i=0;i<3000000;i++);
+ if(flat[0] & 0xffffff00 != 0x007fe000) cprintf("danger will robinson! (a)\n");
+ if(flat[512] & 0xffffff00 != 0x007ff000) cprintf("danger will robinson! (b)\n");
+ cprintf("a = %x b = %x\n",flat[0],flat[512]);
+ for(i=0;i<3000000;i++);
+ cprintf("go! go! go!\n\n");
+ for(i=0;i<3000000;i++);
+
+
+/* for(i=0;i<80*4;i++){
+ cprintf(".");
+ *((char *) 0x100000+i) = 'X';
+ }
+ asm("hlt"); */
+#endif
+
+ k_start();
+}
+
+void grub_bootstrap (multiboot_info *minfo)
+{
+ const static unsigned int temp_gdt[] = { 0x00000000, 0x00000000,
+ 0x0000ffff, 0x00cf9a00, 0x0000ffff, 0x00cf9200 };
+ unsigned int i[2];
+
+ i[0] = 24 << 16;
+ i[1] = (unsigned int) temp_gdt;
+ asm ("lgdt (%0)" : : "p" (((char *) i) + 2));
+ adjust_seg_regs ();
+ bootstrap ((boot_dir *) 0x100000, (minfo->mem_lower + minfo->mem_upper +
+ 384) * 1024, 0, minfo->cmdline);
+}
+
diff --git a/boot/bootstub.S b/boot/bootstub.S
@@ -0,0 +1,72 @@
+/* $Id: //depot/blt/boot/bootstub.S#1 $
+**
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+.globl _start
+.globl adjust_seg_regs
+
+_start:
+ cmpl $0x2badb002, %eax
+ je grub
+ jmp netboot
+
+netboot:
+ pushl %ebp
+ movl %esp, %ebp
+ subl $0x18, %esp
+ movl %ebp, -4(%ebp)
+ movl 0xc(%ebp), %eax
+ pushl %eax
+ movl -4(%ebp), %eax
+ pushl %eax
+ movl 0x8(%ebp), %eax
+ pushl %eax
+ movl 0x10(%ebp), %eax
+ pushl %eax
+ call bootstrap
+ hlt
+
+grub:
+ movl $0x90ffc, %esp
+ pushl %ebx
+ call grub_bootstrap
+ hlt
+
+adjust_seg_regs:
+ ljmp $0x8, $new_cs
+new_cs:
+ mov $0x10, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+ ret
+
diff --git a/boot/fs.ini b/boot/fs.ini
@@ -0,0 +1,33 @@
+# ---------------------------------------------------------------
+# Stuff that works with vfs
+#
+
+[vfs_test]
+type=data
+file=bin/vfs_test/vfs_test.bin
+ventry=116
+
+[foo.so]
+type=data
+file=bin/vfs_test/foo.so
+ventry=0
+
+#[ide]
+#type=data
+#file=srv/ide/ide.bin
+#ventry=0
+
+#[fdisk]
+#type=data
+#file=bin/fdisk/fdisk.bin
+#ventry=0
+
+#[ffs.so]
+#type=data
+#file=srv/vfs/drivers/ffs/ffs.so
+#ventry=0
+
+#[mkdir]
+#type=data
+#file=bin/mkdir/mkdir.bin
+#ventry=0
diff --git a/boot/grub b/boot/grub
Binary files differ.
diff --git a/boot/grub_e2fs b/boot/grub_e2fs
Binary files differ.
diff --git a/boot/grub_fat b/boot/grub_fat
Binary files differ.
diff --git a/boot/grub_ffs b/boot/grub_ffs
Binary files differ.
diff --git a/boot/grubxx b/boot/grubxx
Binary files differ.
diff --git a/boot/misc.ini b/boot/misc.ini
@@ -0,0 +1,43 @@
+
+# ---------------------------------------------------------------
+# The PCI server provides access to PCI enumeration info,
+# read/write access to PCI configuration space, etc.
+#
+[pci]
+type=data
+file=srv/pci/pci.bin
+ventry=0
+
+[sysinfo]
+type=data
+file=bin/sysinfo/sysinfo.bin
+ventry=0
+
+
+# ---------------------------------------------------------------
+# The "old" klunky network stuff. Due for replacement
+#
+[ne2000]
+type=data
+file=srv/ne2000/ne2000.bin
+ventry=116
+
+# The fish client demo. Works with or without networking
+#
+[fish]
+type=data
+file=srv/fish/fish.bin
+ventry=116
+
+# ---------------------------------------------------------------
+# Programs to exercise BLT and find or reproduce bugs
+#
+[tests]
+type=data
+file=bin/tests/tests.bin
+ventry=0
+
+[validate]
+type=data
+file=bin/validate/validate.bin
+ventry=0
diff --git a/boot/net2.ini b/boot/net2.ini
@@ -0,0 +1,30 @@
+# ---------------------------------------------------------------
+# The "new" modular network stack
+# A work in progress (but on hold)
+#
+
+[network]
+type=data
+file=srv/network/network.bin
+ventry=0
+
+[eth.so]
+type=data
+file=srv/network/protocol/eth/eth.so
+ventry=0
+
+[arp.so]
+type=data
+file=srv/network/protocol/arp/arp.so
+ventry=0
+
+[ne.so]
+type=data
+file=srv/network/device/ne/ne.so
+ventry=0
+
+[ipv4.so]
+type=data
+file=srv/network/protocol/ipv4/ipv4.so
+ventry=0
+
diff --git a/boot/openblt.ini b/boot/openblt.ini
@@ -0,0 +1,84 @@
+# ---------------------------------------------------------------
+# The bootstrap code is where control starts once netboot, boot.com,
+# etc loads the image. It creates a page table to map the kernel in
+# at 0x80000000 and then jumps to the kernel entrypoint where things
+# really start happening. This MUST be the first entry in the .ini
+#
+[bootstrap]
+type=boot
+file=boot/boot.bin
+ventry=116
+
+# ---------------------------------------------------------------
+# The OpenBLT kernel must be the second entry here
+# (the bootstrap isn't very bright).
+#
+[kernel]
+type=boot
+file=kernel/kernel.bin
+ventry=116
+
+# ---------------------------------------------------------------
+# The kernel will start any entries of type "code"
+# immediately on boot. Right now only the naming service
+# and init do this. init brings up the rest of the system
+#
+[init]
+type=code
+file=srv/init/init.bin
+ventry=116
+
+[namer]
+type=code
+file=srv/namer/namer.bin
+ventry=116
+
+# ---------------------------------------------------------------
+# These rc files are read by init to determine what to start
+# (thus init needs the vfs)
+#
+[rc.boot]
+type=data
+file=etc/rc.boot
+ventry=0
+
+[rc]
+type=data
+file=etc/rc
+ventry=0
+
+# ---------------------------------------------------------------
+# The vfs and console servers provide core services
+#
+[vfs]
+type=data
+file=srv/vfs/vfs.bin
+ventry=116
+
+[console]
+type=data
+file=srv/console2/console.bin
+ventry=116
+
+# ---------------------------------------------------------------
+# The shell and some shell tools
+#
+[bltsh]
+type=data
+file=bin/bltsh/bltsh.bin
+ventry=0
+
+[ls]
+type=data
+file=bin/ls/ls.bin
+ventry=0
+
+[cat]
+type=data
+file=bin/cat/cat.bin
+ventry=0
+
+[tell]
+type=data
+file=bin/tell/tell.bin
+ventry=0
diff --git a/boot/window.ini b/boot/window.ini
@@ -0,0 +1,13 @@
+# ---------------------------------------------------------------
+# The Window Server and related apps
+#
+
+[window_server]
+type=data
+file=srv/window/window_server.bin
+ventry=0
+
+[winapp]
+type=data
+file=bin/winapp/winapp.bin
+ventry=0
diff --git a/build/GENERIC/Makefile b/build/GENERIC/Makefile
@@ -0,0 +1,19 @@
+BLTHOME := ../../
+
+all: version build image
+
+version:
+ echo "0" > version
+
+build:
+ $(BLTHOME)/lib/newvers
+ mv -f version.c $(BLTHOME)lib
+ @cd $(BLTHOME) ; make subdirs
+
+image:
+ @( DIR=`pwd` ; cd $(BLTHOME) ; util/bootmaker $$DIR/openblt.ini $$DIR/openblt )
+
+clean:
+ rm -f openblt
+ @cd $(BLTHOME) ; make clean
+
diff --git a/build/GENERIC/openblt.ini b/build/GENERIC/openblt.ini
@@ -0,0 +1,135 @@
+[bootstrap]
+type=boot
+file=boot/boot.bin
+ventry=116
+
+[kernel]
+type=boot
+file=kernel/kernel.bin
+ventry=116
+
+[init]
+type=code
+file=srv/init/init.bin
+ventry=116
+
+[namer]
+type=code
+file=srv/namer/namer.bin
+ventry=116
+
+[console]
+type=data
+file=srv/console2/console.bin
+ventry=116
+
+#[ne2000]
+#type=data
+#file=srv/ne2000/ne2000.bin
+#ventry=116
+
+[vfs]
+type=data
+file=srv/vfs/vfs.bin
+ventry=116
+
+#[fish]
+#type=data
+#file=srv/fish/fish.bin
+#ventry=116
+
+#[vfs_test]
+#type=data
+#file=bin/vfs_test/vfs_test.bin
+#ventry=116
+
+#[foo.so]
+#type=data
+#file=bin/vfs_test/foo.so
+#ventry=0
+
+[rc.boot]
+type=data
+file=etc/rc.boot
+ventry=0
+
+[rc]
+type=data
+file=etc/rc
+ventry=0
+
+[bltsh]
+type=data
+file=bin/bltsh/bltsh.bin
+ventry=0
+
+[ls]
+type=data
+file=bin/ls/ls.bin
+ventry=0
+
+[cat]
+type=data
+file=bin/cat/cat.bin
+ventry=0
+
+[tell]
+type=data
+file=bin/tell/tell.bin
+ventry=0
+
+#[network]
+#type=data
+#file=srv/network/network.bin
+#ventry=0
+
+#[eth.so]
+#type=data
+#file=srv/network/protocol/eth/eth.so
+#ventry=0
+
+#[arp.so]
+#type=data
+#file=srv/network/protocol/arp/arp.so
+#ventry=0
+
+#[ne.so]
+#type=data
+#file=srv/network/device/ne/ne.so
+#ventry=0
+
+#[ipv4.so]
+#type=data
+#file=srv/network/protocol/ipv4/ipv4.so
+#ventry=0
+
+#[validate]
+#type=data
+#file=bin/validate/validate.bin
+#ventry=0
+
+[ide]
+type=data
+file=srv/ide/ide.bin
+ventry=0
+
+#[fdisk]
+#type=data
+#file=bin/fdisk/fdisk.bin
+#ventry=0
+
+[ffs.so]
+type=data
+file=srv/vfs/drivers/ffs/ffs.so
+ventry=0
+
+[mkdir]
+type=data
+file=bin/mkdir/mkdir.bin
+ventry=0
+
+[uname]
+type=data
+file=bin/uname/uname.bin
+ventry=0
+
diff --git a/build/VULCAN/Makefile b/build/VULCAN/Makefile
@@ -0,0 +1,22 @@
+BLTHOME := ../../
+
+all: version build image
+
+version:
+ echo "0" > version
+
+build:
+ $(BLTHOME)lib/newvers
+ mv -f version.c $(BLTHOME)lib
+ @cd $(BLTHOME) ; make subdirs
+
+image:
+ @( DIR=`pwd` ; cd $(BLTHOME) ; util/bootmaker $$DIR/openblt.ini $$DIR/openblt )
+
+floppy:
+ @( DIR=`pwd` ; cd ../.. ; util/bootmaker $$DIR/openblt.ini $$DIR/openblt -floppy )
+
+clean:
+ rm -f openblt
+ @cd $(BLTHOME) ; make clean
+
diff --git a/build/VULCAN/openblt.ini b/build/VULCAN/openblt.ini
@@ -0,0 +1,135 @@
+[bootstrap]
+type=boot
+file=boot/boot.bin
+ventry=116
+
+[kernel]
+type=boot
+file=kernel/kernel.bin
+ventry=116
+
+[init]
+type=code
+file=srv/init/init.bin
+ventry=116
+
+[namer]
+type=code
+file=srv/namer/namer.bin
+ventry=116
+
+[console]
+type=data
+file=srv/console2/console.bin
+ventry=116
+
+#[ne2000]
+#type=data
+#file=srv/ne2000/ne2000.bin
+#ventry=116
+
+[vfs]
+type=data
+file=srv/vfs/vfs.bin
+ventry=116
+
+#[fish]
+#type=data
+#file=srv/fish/fish.bin
+#ventry=116
+
+#[vfs_test]
+#type=data
+#file=bin/vfs_test/vfs_test.bin
+#ventry=116
+
+#[foo.so]
+#type=data
+#file=bin/vfs_test/foo.so
+#ventry=0
+
+[rc.boot]
+type=data
+file=etc/rc.boot
+ventry=0
+
+[rc]
+type=data
+file=build/VULCAN/rc
+ventry=0
+
+[bltsh]
+type=data
+file=bin/bltsh/bltsh.bin
+ventry=0
+
+[ls]
+type=data
+file=bin/ls/ls.bin
+ventry=0
+
+[cat]
+type=data
+file=bin/cat/cat.bin
+ventry=0
+
+[tell]
+type=data
+file=bin/tell/tell.bin
+ventry=0
+
+#[network]
+#type=data
+#file=srv/network/network.bin
+#ventry=0
+
+#[eth.so]
+#type=data
+#file=srv/network/protocol/eth/eth.so
+#ventry=0
+
+#[arp.so]
+#type=data
+#file=srv/network/protocol/arp/arp.so
+#ventry=0
+
+#[ne.so]
+#type=data
+#file=srv/network/device/ne/ne.so
+#ventry=0
+
+#[ipv4.so]
+#type=data
+#file=srv/network/protocol/ipv4/ipv4.so
+#ventry=0
+
+#[validate]
+#type=data
+#file=bin/validate/validate.bin
+#ventry=0
+
+[ide]
+type=data
+file=srv/ide/ide.bin
+ventry=0
+
+#[fdisk]
+#type=data
+#file=bin/fdisk/fdisk.bin
+#ventry=0
+
+[ffs.so]
+type=data
+file=srv/vfs/drivers/ffs/ffs.so
+ventry=0
+
+[mkdir]
+type=data
+file=bin/mkdir/mkdir.bin
+ventry=0
+
+[uname]
+type=data
+file=bin/uname/uname.bin
+ventry=0
+
diff --git a/build/VULCAN/rc b/build/VULCAN/rc
@@ -0,0 +1,17 @@
+# $Id: //depot/blt/build/VULCAN/rc#1 $
+#
+# System initialisation script. This is run by init after running
+# rc.boot to get enough services going to proceed normally. We can
+# run any program here, so we must use full pathnames.
+
+# /boot/network
+# /boot/tell network load eth ipv4 arp ne
+# /boot/tell network probe ne
+# /boot/tell network config ne0 ipv4 up 10.0.1.5 255.255.255.0
+
+/boot/ide
+/boot/tell vfs load ffs
+/boot/mkdir /freebsd
+/boot/tell vfs mount ffs /freebsd ide/0/0/1a
+/boot/bltsh
+
diff --git a/doc/TODO b/doc/TODO
@@ -0,0 +1,42 @@
+
+* area_destroy()
+* perm checking (area, sem, etc)
+* right_*()
+* stacks should be area_create()'d
+* thread_kill() / teardown
+* paging? copy-on-write?
+* console
+* if a non-owner sleeps on a readport it won't be awakened
+* ports; multiple readers?
+
+os_sleep() syscall -- timed sleep? or maybe have a sleeper driver?
+port_option() -- allow for OPT_NOWAIT
+resource reclaimation when a thread dies
+kernel memory pooling for getpages and kgetpages should actually exist
+overhaul aspaces to use spans and pspans
+modify system timer for faster preemption
+perms handoff by namer to other threads/tasks
+port groups
+
+standard support objects:
+namer.bin
+keyboard.bin
+console.bin
+idler.bin
+
+
+libc todos:
+malloc/free, using os_brk()
+
+
+struct msg_hdr {
+ int from;
+ int to;
+ int size;
+ char *buf;
+}
+
+port_create(int restrict);
+port_delete(int port);
+port_send(struct msg_hdr *m);
+port_recv(struct msg_hdr *m);
diff --git a/doc/add-syscall b/doc/add-syscall
@@ -0,0 +1,44 @@
+$Id: //depot/blt/doc/add-syscall#1 $
+
+Copyright 1999 Sidney Cammeresi. All rights reserved.
+
+
+How to add a system call to the kernel
+--------------------------------------
+
+Suppose we want to add a new system call named `port_fry' that will find
+all threads listening on a given port and cause the DRAM cells in which
+their code is stored to explode in a given number of microseconds.
+
+1. Reserve a number for the system call in include/blt/syscall_id.h. At
+ the end of the list add a line like
+
+ #define BLT_SYS_port_fry 666
+
+ This name must begin with BLT_SYS_ because all of the actual system
+ call functions are generated by preprocessor macros.
+
+2. Add a function prototype to include/blt/syscall.h.
+
+ int port_fry (int port, int when);
+
+3. Add an entry for port_fry in lib/libblt/syscalls.S. At the bottom
+ of the file and add a line like
+
+ SYSCALL(port_fry)
+
+ This will generate code that traps into the kernel when you call the
+ C symbol port_fry().
+
+4. Implement the system call in the kernel. In the function syscall()
+ in kernel/syscall.c, add a clause to the case statement:
+
+ case BLT_SYS_port_fry :
+ kprintf ("kernel: will fry on %d in %d usecs", p_uint32 (1),
+ p_uint32 (2));
+ /* ... */
+ break;
+
+ Note that to retrieve the arguments to your system call, you need to
+ use the macros p_uint32() and friends. Argument numbers start at 1.
+
diff --git a/doc/boot.html b/doc/boot.html
@@ -0,0 +1,190 @@
+<HTML>
+<HEAD>
+<TITLE>Booting 'n Stuff</TITLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff">
+
+<CENTER>
+<TABLE WIDTH=600>
+
+
+<TR BGCOLOR="#a0a0a0"><TD><B>About uBoot</B></TD></TR>
+<TR><TD><BR>
+The uBoot system is intended to provide a simple mechanism for booting
+microkernel OS's from one self-contained file in various environments.
+<UL>
+<LI>From a remote network host
+<LI>From the boot sector of a floppy disk
+<LI>From a file on a DOS partition
+</UL>
+The boot image is not simply an executable file, but a 'filesystem' of sorts,
+containing a 2nd stage bootstrap, and whatever other images are needed by
+the target system. A utility (bootmaker) is used to create this boot
+image from a description file and various components.
+<BR><BR><BR></TD></TR>
+
+<TR BGCOLOR="#a0a0a0"><TD><B>Boot Environment</B></TD></TR>
+<TR><TD><BR>
+
+<TABLE BORDER=1>
+<TR><TH>member</TH><TH>type</TH><TH>description</TH></TR>
+<TR><TD>be_name</TD><TD>char[32]</TD><TD>
+Name of the object. Zero terminated ASCII. Entry 0 is always named
+"SBBB/Directory".
+</TD></TR>
+<TR><TD>be_offset</TD><TD>uint32</TD><TD>
+Offset (in 4K pages) from the start of the image to the start of this
+entry.
+</TD></TR>
+<TR><TD>be_type</TD><TD>uint32</TD><TD>
+The object type of the entry. One of the defined types listed below,
+or a system-specific type. Entry 0 must be BE_TYPE_DIRECTORY and entry 1
+must be BE_TYPE_BOOTSTRAP.
+</TD></TR>
+<TR><TD>be_size</TD><TD>uint32</TD><TD>
+The size (in 4K pages) of this entry in the image.
+</TD></TR>
+<TR><TD>be_vsize</TD><TD>uint32</TD><TD>
+The size (in 4K pages) that this entry would like when mapped into memory.
+</TD></TR>
+<TR><TD>be_extra0</TD><TD>uint32</TD><TD>
+extra field
+</TD></TR>
+<TR><TD>be_extra1</TD><TD>uint32</TD><TD>
+extra field
+</TD></TR>
+<TR><TD>be_extra2</TD><TD>uint32</TD><TD>
+extra field
+</TD></TR>
+<TR><TD>be_extra3</TD><TD>uint32</TD><TD>
+extra field
+</TD></TR>
+</TABLE>
+
+<UL>
+<LI>The boot image will be located starting at 0x100000.
+<LI>The boot directory (64 entries) will be located at offset 0 of the
+boot image (also 0x100000.
+<LI>Entry 0 in the directory must be the directory itself (be_offset = 0,
+be_type = BE_TYPE_DIRECTORY, be_size = 1, be_vsize = 1)
+<LI>Entry 1 in the directory must be the 2nd stage loader (or kernel if
+the kernel is sufficiently simple). be_offset = 1, be_type = BE_TYPE_BOOTSTRAP
+<LI>Once the Image is loaded, control is transferred to
+boot_dir->bd_entry[1].be_extra1 + 0x101000;
+<LI>The bootstrap entry point looks like:<BR>
+<TT>void _start(uint32 mem, char *params, boot_dir *bd);</TT><BR>
+mem = system memory size (in bytes), params = zero terminate parameter
+string, bd = 0x100000
+<LI>The last entry will be of type BE_TYPE_NONE to indicate the end of
+the directory
+</UL>
+<PRE>
+
+typedef struct {
+ char be_name[32]; /* asciiZ */
+ unsigned int be_offset; /* 4K pages */
+ unsigned int be_type; /* BE_* */
+ unsigned int be_size; /* 4K pages */
+ unsigned int be_vsize; /* 4K pages */
+ unsigned int be_extra0;
+ unsigned int be_extra1;
+ unsigned int be_extra2;
+ unsigned int be_extra3;
+} boot_entry;
+
+typedef struct {
+ boot_entry bd_entry[64];
+} boot_dir;
+
+#define BE_TYPE_NONE 0 /* empty entry */
+#define BE_TYPE_DIRECTORY 1 /* directory (entry 0) */
+#define BE_TYPE_BOOTSTRAP 2 /* bootstrap code object */
+#define BE_TYPE_CODE 3 /* executable code object */
+#define BE_TYPE_DATA 4 /* raw data object */
+#define BE_TYPE_ELF32 5 /* 32bit ELF object */
+
+/* for BE_TYPE_CODE / BE_TYPE_BOOTSTRAP */
+#define be_code_vaddr be_extra0 /* virtual address (rel offset 0) */
+#define be_code_ventr be_extra1 /* virtual entry point (rel offset 0) */
+</PRE>
+<BR></TD></TR>
+
+<TR BGCOLOR="#a0a0a0"><TD><B>BootMaker (building the image)</B></TD></TR>
+<TR><TD><BR>
+
+The bootmaker util reads description file that looks like:
+
+<PRE>
+# Boot Image for stock OpenBLT
+#
+
+[bootstrap]
+type=boot
+file=boot/boot.bin
+ventry=128
+
+[kernel]
+type=code
+file=kernel/kernel.bin
+
+[namer]
+type=code
+file=srv/namer/namer.bin
+
+[console]
+type=code
+file=srv/console/console.bin
+</PRE>
+
+Each section (headed by a name in []'s) is an entry in the boot directory,
+starting with entry 1 (entry 0 being the directory itself). Each entry
+must have a valid type and a valid file to load. Some entry types will
+allow extra params (eg ventry in a type=boot entry). Valid types are
+boot -> BE_TYPE_BOOTSTRAP, code -> BE_TYPE_CODE, elf32 -> BE_TYPE_ELF32,
+data -> BE_TYPE_DATA.
+<P> A mechanism for defining your own types and meanings
+for the extra[0123] fields will be available soon. The name in the []'s
+starting the section will be placed in be_name. The first entry should
+be a bootstrap entry (as the bootloader will transfer control into it
+whether it is or no.
+<P>
+<P>
+<TT>bootmaker <descr_file> <bootimage_file> [ -floppy ]</TT><P>
+The bootmaker util reads the descr_file, writes the bootimage_file, and
+if the optional -floppy flag is specified, the bootimage_file will be
+a disk image suitable for rawriting or copying with dd.
+
+<BR><BR><BR></TD></TR>
+
+<TR BGCOLOR="#a0a0a0"><TD><B>boot.com (loading the image)</B></TD></TR>
+<TR><TD><BR>
+The DOS bootloader (boot.com) can be invoked in two ways:
+<P>
+<TT>boot.com bootfile</TT><BR>
+Will load the boot image in bootfile to 0x100000 and transfer control
+to it as described above.
+<P>
+<TT>boot.com net=ip=x.y.z.w</TT><BR>
+Will load the netboot bootstrap out of netboot.bin (this will be bundled
+in boot.com in the next revision) and start a netboot server, waiting for
+a unix netboot client to send it a boot image file (see below).
+
+<BR><BR><BR></TD></TR>
+
+<TR BGCOLOR="#a0a0a0"><TD><B>NetBoot Client</B></TD></TR>
+<TR><TD><BR>
+<TT>netboot <bootfile> <ip_address></TT><BR>
+netboot will send the specified bootfile to the netboot server at the
+specified ip address.
+
+<BR><BR><BR></TD></TR>
+
+<TR BGCOLOR="#a0a0a0"><TD><B>BootMaker (building the image)</B></TD></TR>
+<TR><TD><BR>
+<BR></TD></TR>
+
+
+</TABLE>
+</CENTER>
+</BODY>
+</HTML>
diff --git a/doc/ipcdocs b/doc/ipcdocs
@@ -0,0 +1,57 @@
+
+typedef struct {
+ int flags;
+ uint32 src;
+ uint32 dst;
+ uint32 size;
+ void *data;
+} msg_hdr_t;
+
+int port_create(int restrict);
+/* Create a new port owned by the running thread. Only allow messages from
+ * port 'restrict' to be received. If 'restrict' is 0, messages from any
+ * source will be received. Will return ERR_MEMORY if the system lacks the
+ * resources to create the port, otherwise the port number will be returned.
+*/
+
+int port_destroy(uint32 port);
+/* Destroy an existing port.
+ * Returns ERR_RESOURCE if port is not a valid port or if there are other
+ * ports slaved to this port. Returns ERR_PERMISSION if the running thread
+ * is not the owner of this port. Returns ERR_NONE upon success/
+*/
+
+int port_send(msg_hdr_t *mh);
+/* Send the message in mh->data, of length mh->size from port mh->src to port
+ * mh->dst. Returns mh->size upon success, ERR_MEMORY if there is a bounds
+ * error, ERR_RESOURCE if either the source or destination ports do not exist,
+ * ERR_PERMISSION if the source is not owned by the running thread or the
+ * destination is not sendable from the source port.
+*/
+
+int port_recv(msg_hdr_t *mh);
+/* Receive a message (in buffer mh->data, maxlen mh->size) from port mh->dst.
+ * Upon success, mh->src will be set to the sender, mh->dst will be set to
+ * the destination if it was a slaved port, and the number of received bytes
+ * will be returned. If the data or header are out of bounds, ERR_MEMORY is
+ * returned. If the destination port does not exist ERR_RESOURCE is returned.
+ * If the running thread does not own the destination port, ERR_PERMISSION is
+ * returned. This call will block if no messages are available, unless the
+ * port is set to NOWAIT, in which case ERR_WOULDBLOCK is returned.
+*/
+
+int port_slave(uint32 master, uint32 slave);
+/* Cause the master port to receive all messages sent to the slave port.
+ * If master is 0, the slave is released from bondage. Returns ERR_NONE
+ * upon success, ERR_PERMISSION if the master and slave are not both owned
+ * by the running thread, or ERR_RESOURCE if the master or slave are not
+ * valid ports.
+*/
+
+int port_set_restrict(uint32 port, uint32 restrict);
+/* Change the restriction on a port. Returns ERR_NONE on success, ERR_RESOURCE
+ * if the port does not exits, or ERR_PERMISSION if the running thread does not
+ * own the port. A restriction of 0 allows any port to send to this port.
+*/
+
+#endif
diff --git a/doc/notes b/doc/notes
@@ -0,0 +1,9 @@
+
+
+803e1ffc: 00000000 tss->esp0 contains this address (top of kernel stack)
+803e1ff8: 0000002b SS ?
+803e1ff4: 003fff6c ESP
+803e1ff0: 00014293 EFLAGS
+803e1fec: 00000023 CS
+803e1fe8: 0000052a EIP
+803e1fe3: 00010004 error (ESP points here on entry to trap)
diff --git a/doc/openblt.html b/doc/openblt.html
@@ -0,0 +1,206 @@
+<HTML>
+<HEAD>
+<TITLE>OpenBLT Overview</TITLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff">
+
+<CENTER>
+<TABLE WIDTH=600>
+<TR><TD>
+
+<H1>OpenBLT: An Overview</H1>
+<I>by Brian J. Swetland</I>
+
+<P>
+OpenBLT is a microkernel operating system for PC's based on the Intel
+80386 or later CPUs. Some aspects of OpenBLT were inspired by Andy
+Valencia's VSTa OS, Mach, assorted UNIX variants, and the author's
+deranged imagination. The acronym BLT expands to "Brian's Lightweight
+Tasker" or "Bacon, Lettuce, and Threads". The word Open was tacked on
+for no particular reason.
+<P>
+The OpenBLT kernel is responsible for managing system memory, providing
+IPC facilities, and creation, destruction, and scheduling threads of control.
+<P>
+Below, we'll examine Tasks, Aspaces, and Ports (the basic objects managed
+by the OpenBLT kernel) in terms of their use in and appearance to userland
+programs.
+
+<P><B>Tasks</B><BR>
+Tasks in OpenBLT are single threads of control. Each task is associated
+with an address space, within which it runs. Tasks may terminate themselves
+using the
+<PRE>void os_terminate(int status);</PRE>
+system call. A task may start another task (sharing the same address space)
+using the
+
+<PRE>int os_thread(void *addr);</PRE>
+system call. The new task begins execution at the specified address and
+a 4K stack is created for it. <I>[ os_thread() will probably take a stack
+pointer address in the next revision ]</I>
+
+<P><B>Address Spaces</B><BR>
+Address spaces are currently not readily manipulated from userland.
+In the near future, shared memory system calls should allow the creation
+of new address spaces and sharing memory between address spaces. A
+thread may request that its address space be expanded using the <TT>os_brk()</TT> system call:
+<PRE>
+int os_brk(int addr);
+</PRE>
+
+<P><B>Ports</B><BR>
+IPC (interprocess communication) in OpenBLT occurs when one task sends a
+message to another task via a port. Ports are 'owned' by one task (the
+task that created them). Messages are send from one port to another port
+(thus a port must exist for the sending task to send from). A port may
+be restricted so that it can only receive messages from one specified
+other port <I>[ future versions will likely allow a list of allowed senders ]</I>.
+
+
+<P>
+All messages sent or received via an OpenBLT port are described with
+a message header. The header indicates the source port, destination port,
+size of message, pointer to message data (or receive data buffer), and
+flags (to allow for future expansion -- non-blocking IO, scatter/gather
+IO, etc)
+<PRE>
+typedef struct {
+ int flags;
+ int src;
+ int dst;
+ int size;
+ void *data;
+} msg_hdr_t;
+</PRE>
+
+
+<P><TT>int <B>port_create</B>(uint32 restrict);</TT><BR>
+Create a new port owned by the running thread. Only allow messages
+from port 'restrict' to be received. If <TT>restrict</TT> is 0, messages
+from any source will be received. Will return <TT>ERR_MEMORY</TT> if
+the system lacks the resources to create the port, otherwise the port
+number will be returned.
+
+<P><TT>int <B>port_destroy</B>(uint32 port);</TT><BR>
+Destroy an existing port. Returns <TT>ERR_RESOURCE</TT> if <TT>port</TT> is
+not a valid port or if there are other ports slaved to this port.
+Returns <TT>ERR_PERMISSION</TT> if the running thread is not the owner
+of this port. Returns <TT>ERR_NONE</TT> upon success/
+
+<P><TT>int <B>port_send</B>(msg_hdr_t *mh);</TT></BR>
+Send the message in <TT>mh->data</TT>, of length <TT>mh->size</TT>
+from port <T>mh->src</TT> to port <TT>mh->dst</TT>. Returns
+<TT>mh->size</TT> upon success, <TT>ERR_MEMORY</TT> if there is a
+bounds error, <TT>ERR_RESOURCE</TT> if either the source or
+destination ports do not exist, <TT>ERR_PERMISSION</TT> if the source
+is not owned by the running thread or the destination is not sendable
+from the source port.
+
+<P><TT>int <B>port_recv</B>(msg_hdr_t *mh);</TT></BR>
+Receive a message (in buffer <TT>mh->data</TT>, max length
+<TT>mh->size</TT>) from port <TT>mh->dst</TT>. Upon success,
+<TT>mh->src</TT> will be set to the sender, <TT>mh->dst</TT> will be
+set to the destination if it was a slaved port, and the number of
+received bytes will be returned. If the data or header are out of
+bounds, <TT>ERR_MEMORY</TT> is returned. If the destination port does
+not exist <TT>ERR_RESOURCE</TT> is returned. If the running thread
+does not own the destination port, <TT>ERR_PERMISSION</TT> is
+returned. This call will block if no messages are available, unless
+the port is set to NOWAIT, in which case <TT>ERR_WOULDBLOCK</TT> is
+returned.
+
+<P><TT>int <B>port_option</B>(uint32 port, int opt, int arg);</TT></BR>
+Modify port options. The two functions below are wrappers around
+<TT>port_option()</TT>
+
+<P><TT>int <B>port_slave</B>(uint32 master, uint32 slave);</TT><BR>
+Cause the master port to receive all messages sent to the slave port.
+If master is 0, the slave is released from bondage. Returns ERR_NONE
+upon success, <TT>ERR_PERMISSION</TT> if the master and slave are not
+both owned by the running thread, or <TT>ERR_RESOURCE</TT> if the
+master or slave are not valid ports.
+
+<P><TT>int <B>port_set_restrict</B>(uint32 port, uint32 restrict);</TT><BR>
+Change the restriction on a port. Returns <TT>ERR_NONE</TT> on
+success, <TT>ERR_RESOURCE</TT> if the port does not exits, or
+<TT>ERR_PERMISSION</TT> if the running thread does not own the port.
+A restriction of 0 allows any port to send to this port.
+
+<P><B>Finding other tasks to talk to</B><BR>
+Since port numbers are generated dynamically by the kernel and tend to
+be different depending on the order tasks are started, etc, there needs
+to be a mechanism for locating device drivers or just other tasks to
+talk to. The kernel automatically creates port 1 (the uberport) and gives
+ownership of this port to the first task created. This task is the namer,
+a service that allows drivers to register ports under specific names and
+allows tasks that wish to find these drivers to look up the port that is
+associated with a specific name.
+<P>
+The utility functions listed below are part of the OpenBLT libc and provide
+convenient ways to access the namer.
+<PRE>
+int namer_newhandle(void);
+int namer_delhandle(int nh);
+int namer_register(int nh, int port, char *name);
+int namer_find(int nh, char *name);
+</PRE>
+
+<P><B>Connections between Connectionless ports</B><BR>
+Ports in OpenBLT are connectionless. Each <TT>port_send()</TT> specifies
+a source and destination port. Tasks may send from any port they own to
+any port they are allowed to write to. Ports may be writable to be any
+other port or restricted to just one other port. <I>[ multiple port restrict
+lists will be in a later version ]</I>
+<P>
+The general procedure for providing a service in OpenBLT is
+<UL>
+<LI>Create an unrestricted port
+<LI>Register this port with the namer under a descriptive name (eg ne2000, console, etc)
+</UL>
+When one task (a client) wishes to connect to a service (the server),
+the following occurs:
+<UL>
+<LI>The client looks up the servers unrestricted port using the namer
+<LI>The client creates a port that is restricted to the server's
+unrestricted port
+<LI>The client sends a message to the servers unrestricted port
+requesting a connection
+<LI>If the server accepts the connection, it will send a response back
+to the client's port notifying it that the connection is accepted and
+ possibly providing a different port than the unrestricted port that the
+client should send future messages too.
+</UL>
+<I>[ a toolkit in libc will streamline this process ]</I>
+
+<P><B>Handling Devices</B><BR>
+The security model in OpenBLT is still being designed. Most likely
+there will be a task that is a "security manager" which will be able
+to give permissions (for accession IO devices, etc) to tasks that need them.
+The two syscalls described below are sufficient for simple device drivers
+in the initial (overly trusting) version of OpenBLT:
+
+<P><TT>void <B>os_handle_irq</B>(int irq);</TT><BR>
+Ask the kernel to make this task eligible to process the specified IRQ.
+The kernel will also allow the task IO access.
+
+
+<P><TT>void <B>os_sleep_irq</B>(void);</TT><BR>
+Suspend this task until the IRQ it is registered to handle is triggered.
+When that IRQ is triggered, the task will be scheduled (preempting the
+currently running task). The IRQ will be ignored by the kernel when the
+task is no sleeping in <TT>os_sleep_irq()</TT>.
+
+<P><B>Startup</B><BR>
+On startup, OpenBLT creates initializes its internal memory and resource
+management, sets up kernel space at the 2gb line (0x8000000), creates
+an address space and task for each userland program that it can find.
+An idle task is created (to give the scheduler something to schedule,
+should all other tasks be sleeping on something). The kernel schedules
+the first task in the run queue to execute and the fun starts.
+
+
+</TD></TR>
+</TABLE>
+</CENTER>
+
+</BODY>
diff --git a/doc/vfs.txt b/doc/vfs.txt
@@ -0,0 +1,98 @@
+$Id: //depot/blt/doc/vfs.txt#4 $
+
+Documentation for the OpenBLT Virtual Filesystem
+------------------------------------------------
+
+This documentation is Copyright 1999 Sidney Cammeresi. All rights reserved.
+
+
+
+Contents
+--------
+ 1. Overview
+ 2. File descriptor layer
+ 3. Vnode layer
+ 4. Filesystem layer
+
+ 5. VFS server message protocol
+
+
+1. Overview
+-----------
+
+
+
+2. File descriptor layer
+------------------------
+
+This layer is not written yet.
+
+
+
+3. Vnode layer
+--------------
+
+
+
+4. Filesystem layer
+-------------------
+
+
+
+5. VFS server message protocol
+------------------------------
+
+vfs command and return parameters (a.k.a. data[] contents)
+
+
+static symbols are for use by libc only!
+
+
+static void __vfs_openconn (int src_port, int dest_port, int filename_area);
+============================================================================
+0 filename area
+
+0 private port for talking to vfs
+
+static void __vfs_scroll_area (int fd, int offset)
+==================================================
+0 vfs file descriptor
+1 new offset (in bytes for file, dirents for directory)
+
+0 number of bytes copied
+1 more?
+
+DIR *opendir (const char *dir)
+==============================
+0 filename offset
+1 payload area id
+2 payload offset
+3 payload length
+
+0 vfs file descriptor
+1 number of dirents in shmem
+2 more?
+
+int closedir (DIR *dirp)
+========================
+0 vfs file descriptor
+
+no output data
+
+int open (const char *path, int flags, mode_t mode)
+===================================================
+0 filename offset
+1 payload area id
+2 payload offset
+3 payload length
+
+0 vfs file descriptor
+1 length of data in shmem
+2 more?
+
+int stat (const char *path, struct stat *buf)
+=============================================
+0 filename offset
+
+no output data, but a (struct stat) follows the vfs_res_t
+
diff --git a/etc/rc b/etc/rc
@@ -0,0 +1,24 @@
+# $Id: //depot/blt/etc/rc#5 $
+#
+# System initialisation script. This is run by init after running
+# rc.boot to get enough services going to proceed normally. We can
+# run any program here, so we must use full pathnames.
+
+# /boot/network
+# /boot/tell network load eth ipv4 arp ne
+# /boot/tell network probe ne
+# /boot/tell network config ne0 ipv4 up 10.0.1.5 255.255.255.0
+
+# /boot/ide
+# /boot/tell vfs load ffs
+# /boot/mkdir /freebsd
+# /boot/tell vfs mount ffs /freebsd ide/0/0/1aZ
+
+# PCI device services
+#
+/boot/pci
+
+# Start the shell
+#
+/boot/bltsh
+
diff --git a/etc/rc.boot b/etc/rc.boot
@@ -0,0 +1,15 @@
+# $Id: //depot/blt/etc/rc.boot#2 $
+#
+# List of servers to run in order to bootstrap the system. Each
+# server must be in the boot filesystem and statically linked since
+# the VFS isn't running yet.
+#
+# Order is important! These programs don't get run concurrently like
+# they do when you run them from the kernel. If you get the order
+# wrong, or if a bug causes one of these servers to crash or not detach
+# correctly, your system is probably wedged.
+
+# namer
+console
+vfs
+
diff --git a/include/ansi.h b/include/ansi.h
@@ -0,0 +1,78 @@
+/* $OpenBSD: ansi.h,v 1.6 1997/07/07 05:56:37 millert Exp $ */
+/* $NetBSD: ansi.h,v 1.7 1996/11/15 22:38:50 jtc Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ansi.h 8.2 (Berkeley) 1/4/94
+ */
+
+#ifndef _ANSI_H_
+#define _ANSI_H_
+
+/*
+ * Types which are fundamental to the implementation and may appear in
+ * more than one standard header are defined here. Standard headers
+ * then use:
+ * #ifdef _BSD_SIZE_T_
+ * typedef _BSD_SIZE_T_ size_t;
+ * #undef _BSD_SIZE_T_
+ * #endif
+ */
+#define _BSD_CLOCK_T_ unsigned long /* clock() */
+#define _BSD_PTRDIFF_T_ int /* ptr1 - ptr2 */
+#define _BSD_SIZE_T_ unsigned int /* sizeof() */
+#define _BSD_SSIZE_T_ int /* byte count or error */
+#define _BSD_TIME_T_ int /* time() */
+#define _BSD_VA_LIST_ char * /* va_list */
+#define _BSD_CLOCKID_T_ int
+#define _BSD_TIMER_T_ int
+
+/*
+ * Runes (wchar_t) is declared to be an ``int'' instead of the more natural
+ * ``unsigned long'' or ``long''. Two things are happening here. It is not
+ * unsigned so that EOF (-1) can be naturally assigned to it and used. Also,
+ * it looks like 10646 will be a 31 bit standard. This means that if your
+ * ints cannot hold 32 bits, you will be in trouble. The reason an int was
+ * chosen over a long is that the is*() and to*() routines take ints (says
+ * ANSI C), but they use _RUNE_T_ instead of int. By changing it here, you
+ * lose a bit of ANSI conformance, but your programs will still work.
+ *
+ * Note that _WCHAR_T_ and _RUNE_T_ must be of the same type. When wchar_t
+ * and rune_t are typedef'd, _WCHAR_T_ will be undef'd, but _RUNE_T remains
+ * defined for ctype.h.
+ */
+#define _BSD_WCHAR_T_ int /* wchar_t */
+#define _BSD_WINT_T_ int /* wint_t */
+#define _BSD_RUNE_T_ int /* rune_t */
+
+#endif /* _ANSI_H_ */
diff --git a/include/blt/Connection.h b/include/blt/Connection.h
@@ -0,0 +1,35 @@
+// Copyright 1999, Brian J. Swetland. All Rights Reserved.
+// This file is provided under the terms of the OpenBLT License
+
+#ifndef __BLT_CONNECTION_H
+#define __BLT_CONNECTION_H
+
+#include <blt/types.h>
+
+namespace BLT {
+
+class Message;
+
+class Connection
+{
+public:
+ ~Connection();
+
+ int Send(const Message *msg);
+ int Recv(Message *msg);
+
+ int Call(const Message *send, Message *recv);
+
+ static Connection *FindService(const char *name);
+ static Connection *CreateService(const char *name);
+
+private:
+ Connection();
+
+ int _local_port;
+ int _remote_port;
+};
+
+}
+
+#endif
diff --git a/include/blt/Message.h b/include/blt/Message.h
@@ -0,0 +1,60 @@
+// Copyright 1999, Brian J. Swetland. All Rights Reserved.
+// This file is provided under the terms of the OpenBLT License
+
+#ifndef __BLT_MESSAGE_H
+#define __BLT_MESSAGE_H
+
+#include <blt/types.h>
+
+#define BLT_TYPE_INT32 'bI32'
+#define BLT_TYPE_STRING 'bSTR'
+#define BLT_TYPE_POINTER 'bPTR'
+#define BLT_TYPE_MESSAGE 'bMSG'
+
+namespace BLT {
+
+class Message
+{
+public:
+ Message();
+ ~Message();
+
+ /* -------------------------------------------------------- */
+ int PutData(uint32 type, uint32 id, const void *data, uint32 len);
+ int GetData(uint32 type, uint32 id, void *data, uint32 len) const;
+ int GetData(uint32 type, uint32 id, const void **data, uint32 *len) const;
+ int GetEntry(uint32 n, uint32 *type, uint32 *id, const void **data, uint32 *len) const;
+
+ /* -------------------------------------------------------- */
+ int PutInt32(uint32 id, int32 data);
+ int PutString(uint32 id, const char *data);
+ int PutPointer(uint32 id, void *data);
+ int PutMessage(uint32 id, Message *msg);
+
+ /* -------------------------------------------------------- */
+ int GetInt32(uint32 id, int32 *data) const;
+ int GetString(uint32 id, const char **data) const;
+ int GetPointer(uint32 id, void **ptr) const;
+ int GetMessage(uint32 id, Message *msg) const;
+
+ /* -------------------------------------------------------- */
+ int GetPackedData(const void **data, uint32 *length) const;
+ int PutPackedData(const void *data, uint32 length, int reply_port = -1);
+
+ int Reply(const Message *msg) const;
+
+ void Empty();
+
+ void dump();
+
+private:
+ void *_data;
+ uint32 _length;
+ uint32 _available;
+
+ int _reply_port;
+};
+
+}
+#endif
+
diff --git a/include/blt/atomic.h b/include/blt/atomic.h
@@ -0,0 +1,44 @@
+/* $Id: //depot/blt/include/blt/atomic.h#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BLT_ATOMIC_H__
+#define __BLT_ATOMIC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ long atomic_add (long *var, long amount);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/blt/blkdev.h b/include/blt/blkdev.h
@@ -0,0 +1,78 @@
+/* $Id: //depot/blt/include/blt/blkdev.h#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BLT_BLKDEV_H_
+#define _BLT_BLKDEV_H_
+
+#include <blt/types.h>
+
+#define BLK_CMD_OPEN 1
+#define BLK_CMD_READ 2
+#define BLK_CMD_WRITE 3
+
+typedef struct
+{
+ int blksize;
+ int local_port, remote_port;
+ dev_t devno;
+} blkdev_t;
+
+typedef struct
+{
+ dev_t device;
+ unsigned int cmd, block, count;
+} blktxn_t;
+
+typedef struct
+{
+ dev_t device;
+ int status;
+ int data[2];
+} blkres_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int _blk_open (const char *name, int flags, blkdev_t **dev);
+ int blk_open (const char *name, int flags, blkdev_t **dev);
+ int _blk_close (blkdev_t *dev);
+ int blk_close (blkdev_t *dev);
+
+ int _blk_read (blkdev_t *dev, void *buf, int block, int count);
+ int blk_read (blkdev_t *dev, void *buf, int block, int count);
+ int _blk_write (blkdev_t *dev, const void *buf, int block, int count);
+ int blk_write (blkdev_t *dev, const void *buf, int block, int count);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/blt/conio.h b/include/blt/conio.h
@@ -0,0 +1,74 @@
+/* $Id: //depot/blt/include/blt/conio.h#6 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _CONIO_H
+#define _CONIO_H
+
+#include <stdarg.h>
+
+#ifdef MONO
+#define CON_SCREEN 0x000B0000
+#else
+#define CON_SCREEN 0x000B8000
+#endif
+
+#define CON_BLACK 0
+#define CON_BLUE 1
+#define CON_GREEN 2
+#define CON_CYAN 3
+#define CON_RED 4
+#define CON_MAGENTA 5
+#define CON_YELLOW 6
+#define CON_WHITE 7
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void con_attr(int a);
+ void con_clear(void);
+ void con_putc(char ch);
+ void con_puts(char *s);
+ void con_putp(unsigned int p);
+ void con_putx(unsigned char x);
+ void con_goto(int x, int y);
+
+ #define con_fgbg(fg,bg) con_attr((bg) << 4 | (fg));
+
+ #define con_init() { con_attr(CON_WHITE); con_clear(); }
+
+ void con_start(unsigned int video);
+
+ void cprintf(char *fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _CONIO_H */
diff --git a/include/blt/disk.h b/include/blt/disk.h
@@ -0,0 +1,252 @@
+/* $Id: //depot/blt/include/blt/disk.h#4 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BLT_DISK_H_
+#define _BLT_DISK_H_
+
+#include <blt/blkdev.h>
+
+#define FDISK_TYPE_EMPTY 0x00
+#define FDISK_TYPE_FAT12 0x01
+#define FDISK_TYPE_FAT16_SMALL 0x04
+#define FDISK_TYPE_EXTENDED 0x05
+#define FDISK_TYPE_FAT16_BIG 0x06
+#define FDISK_TYPE_NTFS 0x07
+#define FDISK_TYPE_LINUX_SWAP 0x82
+#define FDISK_TYPE_EXT2 0x83
+#define FDISK_TYPE_FREEBSD 0xa5
+#define FDISK_TYPE_OPENBSD 0xa6
+#define FDISK_TYPE_BFS 0xeb
+
+#define FREEBSD_FFS 0x100
+#define FREEBSD_SWAP 0x101
+#define OPENBSD_FFS 0x102
+#define OPENBSD_SWAP 0x103
+
+typedef struct
+{
+ unsigned char bootflag;
+ unsigned char start0;
+ unsigned char start1;
+ unsigned char start2;
+ unsigned char type;
+ unsigned char end0;
+ unsigned char end1;
+ unsigned char end2;
+ unsigned int start_sect_num;
+ unsigned int num_sects;
+} fdisk_partition;
+
+typedef struct
+{
+ char name[3]; /* 0, 0a, etc. */
+ int type;
+ unsigned long long start, size;
+} partition_t;
+
+typedef struct
+{
+ blkdev_t *dev;
+ int numparts;
+ partition_t *partition;
+} disk_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ disk_t *disk_alloc (blkdev_t *dev);
+ void disk_free (disk_t *disk);
+ const char *disk_partition_name (disk_t *disk, int partition);
+ unsigned long long disk_partition_start (disk_t *disk, int partition);
+ unsigned long long disk_partition_size (disk_t *disk, int partition);
+ unsigned int disk_partition_type (disk_t *disk, int partition);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/*
+ * Copyright (c) 1987, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)disklabel.h 8.2 (Berkeley) 7/10/94
+ */
+
+#define NDDATA 5
+#define NSPARE 5
+#define BSD_MAXSLICES 16
+#define BSD_DISKLABEL_MAGIC 0x82564557
+
+typedef struct
+{
+ unsigned int d_magic; /* the magic number */
+ unsigned short d_type; /* drive type */
+ unsigned short d_subtype; /* controller/d_type specific */
+ char d_typename[16]; /* type name, e.g. "eagle" */
+
+ /*
+ * d_packname contains the pack identifier and is returned when
+ * the disklabel is read off the disk or in-core copy.
+ * d_boot0 and d_boot1 are the (optional) names of the
+ * primary (block 0) and secondary (block 1-15) bootstraps
+ * as found in /usr/mdec. These are returned when using
+ * getdiskbyname(3) to retrieve the values from /etc/disktab.
+ */
+ union
+ {
+ char un_d_packname[16]; /* pack identifier */
+ struct
+ {
+ char *un_d_boot0; /* primary bootstrap name */
+ char *un_d_boot1; /* secondary bootstrap name */
+ } un_b;
+ } d_un;
+
+ /* disk geometry: */
+ unsigned int d_secsize; /* # of bytes per sector */
+ unsigned int d_nsectors; /* # of data sectors per track */
+ unsigned int d_ntracks; /* # of tracks per cylinder */
+ unsigned int d_ncylinders; /* # of data cylinders per unit */
+ unsigned int d_secpercyl; /* # of data sectors per cylinder */
+ unsigned int d_secperunit; /* # of data sectors per unit */
+
+ /*
+ * Spares (bad sector replacements) below are not counted in
+ * d_nsectors or d_secpercyl. Spare sectors are assumed to
+ * be physical sectors which occupy space at the end of each
+ * track and/or cylinder.
+ */
+ unsigned short d_sparespertrack; /* # of spare sectors per track */
+ unsigned short d_sparespercyl; /* # of spare sectors per cylinder */
+
+ /*
+ * Alternate cylinders include maintenance, replacement, configuration
+ * description areas, etc.
+ */
+ unsigned int d_acylinders; /* # of alt. cylinders per unit */
+
+ /*
+ * d_interleave, d_trackskew and d_cylskew describe perturbations
+ * in the media format used to compensate for a slow controller.
+ * Interleave is physical sector interleave, set up by the
+ * formatter or controller when formatting. When interleaving is
+ * in use, logically adjacent sectors are not physically
+ * contiguous, but instead are separated by some number of
+ * sectors. It is specified as the ratio of physical sectors
+ * traversed per logical sector. Thus an interleave of 1:1
+ * implies contiguous layout, while 2:1 implies that logical
+ * sector 0 is separated by one sector from logical sector 1.
+ * d_trackskew is the offset of sector 0 on track N relative to
+ * sector 0 on track N-1 on the same cylinder. Finally, d_cylskew
+ * is the offset of sector 0 on cylinder N relative to sector 0
+ * on cylinder N-1.
+ */
+ unsigned short d_rpm; /* rotational speed */
+ unsigned short d_interleave; /* hardware sector interleave */
+ unsigned short d_trackskew; /* sector 0 skew, per track */
+ unsigned short d_cylskew; /* sector 0 skew, per cylinder */
+ unsigned int d_headswitch; /* head switch time, usec */
+ unsigned int d_trkseek; /* track-to-track seek, usec */
+ unsigned int d_flags; /* generic flags */
+ unsigned int d_drivedata[NDDATA]; /* drive-type specific information */
+ unsigned int d_spare[NSPARE]; /* reserved for future use */
+ unsigned int d_magic2; /* the magic number (again) */
+ unsigned short d_checksum; /* xor of data incl. partitions */
+
+ /* filesystem and partition information: */
+ unsigned short d_npartitions; /* number of partitions in following */
+ unsigned int d_bbsize; /* size of boot area at sn0, bytes */
+ unsigned int d_sbsize; /* max size of fs superblock, bytes */
+
+ struct partition /* the partition table */
+ {
+ unsigned int p_size; /* number of sectors in partition */
+ unsigned int p_offset; /* starting sector */
+ unsigned int p_fsize; /* filesystem basic fragment size */
+ unsigned char p_fstype; /* filesystem type, see below */
+ unsigned char p_frag; /* filesystem fragments per block */
+ union
+ {
+ unsigned short cpg; /* UFS: FS cylinders per group */
+ unsigned short sgs; /* LFS: FS segment shift */
+ } p_u1;
+ } d_partitions[BSD_MAXSLICES]; /* actually may be more */
+} bsd_disklabel;
+
+#define BSD_FS_UNUSED 0 /* unused */
+#define BSD_FS_SWAP 1 /* swap */
+#define BSD_FS_V6 2 /* Sixth Edition */
+#define BSD_FS_V7 3 /* Seventh Edition */
+#define BSD_FS_SYSV 4 /* System V */
+#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
+#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
+#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
+#define BSD_FS_MSDOS 8 /* MSDOS file system */
+#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
+#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
+#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
+#define BSD_FS_ISO9660 12 /* ISO 9660, normally CD-ROM */
+#define BSD_FS_BOOT 13 /* partition contains bootstrap */
+#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
+#define BSD_FS_HFS 15 /* Macintosh HFS */
+#define BSD_FS_ADFS 16 /* Acorn Disk Filing System */
+#define BSD_FS_EXT2FS 17 /* ext2fs */
+#define BSD_FS_CCD 18 /* ccd component */
+
+#endif
+
diff --git a/include/blt/error.h b/include/blt/error.h
@@ -0,0 +1,44 @@
+/* $Id: //depot/blt/include/blt/error.h#4 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BLT_ERROR_H
+#define _BLT_ERROR_H
+
+/* these match the E_ constants in kernel.h */
+
+#define ERR_NONE 0
+#define ERR_PERMISSION -1
+#define ERR_RESOURCE -2
+#define ERR_MEMORY -3
+
+#define ERR_SENDPORT -4
+#define ERR_RECVPORT -5
+#define ERR_WOULD_BLOCK -6
+
+#define ERR_SEGV -7
+#endif
diff --git a/include/blt/fdl.h b/include/blt/fdl.h
@@ -0,0 +1,66 @@
+/* $Id: //depot/blt/include/blt/fdl.h#3 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BLT_FDL_H_
+#define _BLT_FDL_H_
+
+#include <blt/types.h>
+
+#define MAX_FD_HANDLERS 64
+#define MAX_FDS 256
+
+typedef struct
+{
+ const char *name;
+
+ int (*read) (void *cookie, void *buf, size_t count);
+ int (*write) (void *cookie, const void *buf, size_t count);
+ int (*ioctl) (void *cookie, unsigned long request, char *argp);
+ int (*close) (void *cookie);
+} fdl_type;
+
+typedef struct
+{
+ fdl_type *imp;
+ void *cookie;
+} __filedesc;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void __libc_init_fdl (void);
+ void __libc_fini_fdl (void);
+ int _fdl_alloc_descriptor (fdl_type *handler, void *cookie);
+ void _fdl_free_descriptor (int desc);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/include/blt/hash.h b/include/blt/hash.h
@@ -0,0 +1,65 @@
+/* $Id: //depot/blt/include/blt/hash.h#3 $
+**
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BLT_HASH_H_
+#define _BLT_HASH_H_
+
+typedef struct
+{
+ int valid, dirty, key, dsize;
+ void *data;
+} hashnode_t;
+
+typedef struct
+{
+ hashnode_t *table;
+ int size_index, used, dirty;
+ float max_load;
+} hashtable_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ hashtable_t *hashtable_new (float max_load);
+ void hashtable_del (hashtable_t *t);
+ void hashtable_insert (hashtable_t *t, int key, void *data, int dsize);
+ void *hashtable_lookup (hashtable_t *t, int key, int *dsize);
+ void *hashtable_remove (hashtable_t *t, int key, int *dsize);
+ void hashtable_print (hashtable_t *t);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/blt/libsyms.h b/include/blt/libsyms.h
@@ -0,0 +1,60 @@
+/* $Id: //depot/blt/include/blt/libsyms.h#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BLT_LIBSYMS_H__
+#define __BLT_LIBSYMS_H__
+
+/*
+ * this creates a weak alias from the symbol original to the symbol alias.
+ * functions like printf should actually be defined as _printf in libc,
+ * with weak aliases linking printf to _printf. by doing this, a user can
+ * put a wrapper around the actual libc functions without rebuilding
+ * libc (for profiling, say). i.e.,
+ *
+ * weak_alias (_printf, printf)
+ * int _printf (char *fmt, ...);
+ *
+ * printf ("foo");
+ *
+ * results in a call to _printf.
+ */
+#define weak_alias(original, alias) \
+ asm (".weak " #alias " ; " #alias " = " #original);
+
+/*
+ * this causes the GNU linker to emit a warning when this symbol is
+ * referenced during a linking stage.
+ *
+ * only the name of the section matters. this must be char[], not char *
+ */
+#define link_warning(symbol, text) \
+ static const char ___link_warning_##symbol[] \
+ __attribute__ ((section (".gnu.warning." #symbol))) = text;
+
+#endif
+
diff --git a/include/blt/namer.h b/include/blt/namer.h
@@ -0,0 +1,27 @@
+/* Copyright 1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _NAMER_H_
+#define _NAMER_H_
+
+#include <blt/types.h>
+
+#define NAMER_PORT 1
+
+#define NAMER_FIND 1
+#define NAMER_REGISTER 2
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int namer_register(int port, const char *name);
+int namer_find(const char *name, int blocking);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/include/blt/network/eth.h b/include/blt/network/eth.h
@@ -0,0 +1,116 @@
+/* $Id: //depot/blt/include/blt/network/eth.h#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * XXX all multibyte quanities are in network byte order
+ */
+
+#ifndef _BLT_NETWORK_ETH_H_
+#define _BLT_NETWORK_ETH_H_
+
+#include <blt/types.h>
+
+#pragma pack(2)
+
+#define ETH_PROT_IP 0x0800
+#define ETH_PROT_ARP 0x0806
+#define ETH_PROT_RARP 0x8035
+
+#define ETH_ARP_OP_REQUEST 1
+#define ETH_ARP_OP_REPLY 2
+#define ETH_RARP_OP_REQUEST 3
+#define ETH_RARP_OP_REPLY 4
+
+struct mbuf;
+
+typedef struct __eth_drv_t
+{
+ const char *name;
+ void (*output) (int num, struct mbuf *);
+ struct __eth_drv_t *next;
+} eth_drv_t;
+
+typedef struct __eth_dev_t
+{
+ eth_drv_t *dev_driver;
+ int dev_num;
+ char dev_addr[6];
+ void *dev_data;
+ struct __eth_dev_t *next;
+} eth_dev_t;
+
+typedef struct
+{
+ uint8 dst[6];
+ uint8 src[6];
+ uint16 frame_type;
+} ether_header;
+
+typedef struct
+{
+ ether_header header;
+ uint16 hard_type;
+ uint16 prot_type;
+ uint8 hard_size;
+ uint8 prot_size;
+ uint16 op;
+ uint8 send_eth_addr[6];
+ uint8 send_ip_addr[4];
+ uint8 targ_eth_addr[6];
+ uint8 targ_ip_addr[4];
+ uint8 __pad__[18];
+} arp_packet;
+
+typedef struct __eth_prot_t
+{
+ const char *name;
+ int num;
+ void (*input) (struct mbuf *);
+ struct __eth_prot_t *next;
+} eth_prot_t;
+
+char eth_broadcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+#ifdef _NETWORK
+
+extern eth_drv_t *drvlist;
+extern eth_dev_t *devlist;
+extern eth_prot_t *protlist;
+
+void register_eth_driver (eth_drv_t *drv);
+void unregister_eth_driver (eth_drv_t *drv);
+void register_eth_device (eth_dev_t *dev);
+void unregister_eth_device (eth_dev_t *dev);
+void register_eth_protocol (eth_prot_t *prot);
+void unregister_eth_protocol (eth_prot_t *prot);
+void eth_input (struct mbuf *mbuf);
+
+#endif
+
+#endif
+
diff --git a/include/blt/network/ipv4.h b/include/blt/network/ipv4.h
@@ -0,0 +1,50 @@
+/* $Id: //depot/blt/include/blt/network/ipv4.h#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BLT_NETWORK_IPV4_H_
+#define _BLT_NETWORK_IPV4_H_
+
+#include <blt/types.h>
+
+struct mbuf;
+
+typedef struct __ipv4_iface_t
+{
+ const char *name;
+ uint8 addr[4];
+ uint8 netmask[4];
+ void (*output) (struct mbuf *);
+ struct __ipv4_iface_t *next;
+} ipv4_iface_t;
+
+#ifdef _NETWORK
+extern ipv4_iface_t *iflist;
+#endif
+
+#endif
+
diff --git a/include/blt/network/mbuf.h b/include/blt/network/mbuf.h
@@ -0,0 +1,140 @@
+/* $Id: //depot/blt/include/blt/network/mbuf.h#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Copyright (c) 1982, 1986, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mbuf.h 8.5 (Berkeley) 2/19/95
+ */
+
+#ifndef _BLT_NETWORK_MBUF_H_
+#define _BLT_NETWORK_MBUF_H_
+
+#define MSIZE 128
+#define MCLBYTES 2048
+
+#define MLEN (MSIZE - sizeof(struct m_hdr)) /* normal data len */
+#define MHLEN (MLEN - sizeof(struct m_pkthdr)) /* data len w/pkthdr */
+#define MINCLSIZE (MHLEN+MLEN+1) /* smallest amount to put in cluster */
+#define M_MAXCOMPRESS (MHLEN / 2) /* max amount to copy for compression */
+
+struct m_hdr
+{
+ struct mbuf *mh_next, *mh_nextpkt;
+ int mh_len;
+ char *mh_data;
+ short mh_type, mh_flags;
+};
+
+struct m_pkthdr
+{
+ void *rcvif;
+ int len;
+};
+
+struct m_ext
+{
+ char *ext_buf;
+ void (*ext_free) (char *, int);
+ int ext_size;
+ volatile int ext_refcnt;
+};
+
+struct mbuf
+{
+ struct m_hdr m_hdr;
+ union
+ {
+ struct
+ {
+ struct m_pkthdr mh_pkthdr;
+ union
+ {
+ struct m_ext *mh_ext;
+ char mh_ext_databuf[MHLEN];
+ } mh_dat;
+ } mh;
+ char mh_databuf[MLEN];
+ } m_dat;
+};
+
+#define m_next m_hdr.mh_next
+#define m_nextpkt m_hdr.mh_nextpkt
+#define m_len m_hdr.mh_len
+#define m_data m_hdr.mh_data
+#define m_type m_hdr.mh_type
+#define m_flags m_hdr.mh_flags
+#define m_databuf m_dat.mh_databuf
+#define m_ext_databuf m_dat.mh.mh_dat.mh_ext_databuf
+
+#define MT_FREE 1
+#define MT_DATA 2
+#define MT_HEADER 3
+#define MT_IFADDR 4
+
+#ifdef _NETWORK
+
+void mbinit (void);
+struct mbuf *mget (void);
+char *mgetcl (struct mbuf *mbuf);
+void mput (struct mbuf *mbuf);
+void mputcl (struct mbuf *mbuf);
+
+#endif
+
+#endif
+
diff --git a/include/blt/network/module.h b/include/blt/network/module.h
@@ -0,0 +1,44 @@
+/* $Id: //depot/blt/include/blt/network/module.h#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BLT_NETWORK_MODULE_H_
+#define _BLT_NETWORK_MODULE_H_
+
+typedef struct __module_t
+{
+ char *name;
+ void *handle;
+ struct __module_t *next;
+} module_t;
+
+#ifdef _NETWORK
+extern module_t *modlist;
+#endif
+
+#endif
+
diff --git a/include/blt/os.h b/include/blt/os.h
@@ -0,0 +1,107 @@
+/* Copyright 1999 Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License.
+*/
+
+#ifndef __BLT_OS_H__
+#define __BLT_OS_H__
+
+/*
+ * this is generic stuff that is used both in userspace and in the kernel
+ * that doesn't really fit elsewhere.
+ *
+ * this file is included in both apps and the kernel, so don't include
+ * silly userland files here!
+ */
+
+#define BLT_MAX_NAME_LENGTH 32
+#define BLT_MAX_CPUS 8
+
+#define PORT_OPT_NOWAIT 1
+#define PORT_OPT_SETRESTRICT 2
+#define PORT_OPT_SETDEFAULT 3
+#define PORT_OPT_SLAVE 4
+
+#define RIGHT_PERM_READ 0x0001 /* allow 'read' access to something */
+#define RIGHT_PERM_WRITE 0x0002 /* allow 'write' access to something */
+#define RIGHT_PERM_DESTROY 0x0004 /* allow the something to be destroyed */
+#define RIGHT_PERM_ATTACH 0x0008 /* allows other rights to be attached */
+#define RIGHT_PERM_GRANT 0x0010 /* this right may be granted to another */
+ /* thread by a thread that is not the */
+ /* owner */
+#define RIGHT_MODE_INHERIT 0x0020 /* automatically granted to child */
+#define RIGHT_MODE_DISSOLVE 0x0040 /* When the owner thread terminates, */
+ /* the right is destroyed */
+
+#define AREA_PHYSMAP 0x00000001
+#define AREA_UNMAPPED 0x00000002
+#define AREA_COPY_ON_WRITE 0x00000004
+#define PAGE_PRESENT 0x00000001
+#define PAGE_WRITABLE 0x00000002
+#define PAGE_USER 0x00000004
+#define PAGE_NORMAL_KERNEL 0x00000003
+#define PAGE_NORMAL_USER 0x00000007
+
+#define JOIN_NO_HANG 0x00000001
+
+#ifndef __ASM__
+
+typedef enum
+{
+ CPU_INTEL_386,
+ CPU_INTEL_486,
+ CPU_INTEL_PENTIUM,
+ CPU_INTEL_PENTIUM_PRO,
+ CPU_INTEL_PENTIUM_II,
+ CPU_INTEL_PENTIUM_III,
+ CPU_MOT_PPC_601,
+ CPU_MOT_PPC_603,
+ CPU_MOT_PPC_603e,
+ CPU_MOT_PPC_604,
+ CPU_MOT_PPC_604e
+} cpu_type;
+
+typedef struct
+{
+ cpu_type c_type;
+ char c_revision, c_active;
+} cpu_info;
+
+typedef struct
+{
+ char *name;
+} thread_info;
+
+typedef struct
+{
+ int num_cpus;
+ cpu_info c_info[BLT_MAX_CPUS];
+ char kernel_name[BLT_MAX_NAME_LENGTH];
+ char kernel_version[BLT_MAX_NAME_LENGTH];
+ char kernel_build_date[BLT_MAX_NAME_LENGTH];
+ char kernel_build_time[BLT_MAX_NAME_LENGTH];
+} sys_info;
+
+typedef struct
+{
+ int rid;
+ union
+ {
+ thread_info t_info;
+ sys_info s_info;
+ } r_un;
+} rsrc_info;
+
+typedef struct
+{
+ void (*func)(void);
+ int priority;
+} init_info;
+
+#define META_NULL_REQUEST 0
+#define META_MIN_RESERVED 0xf0000000
+#define META_MAX_RESERVED 0xffffffff
+
+#endif
+
+#endif
+
diff --git a/include/blt/qsem.h b/include/blt/qsem.h
@@ -0,0 +1,56 @@
+/* $Id: //depot/blt/include/blt/qsem.h#3 $
+**
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BLT_QSEM_H__
+#define __BLT_QSEM_H__
+
+typedef struct
+{
+ volatile int count;
+ volatile int mutex;
+} qsem_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ qsem_t *qsem_create (int count);
+ void qsem_destroy (qsem_t *s);
+ void qsem_acquire (qsem_t *s);
+ void qsem_release (qsem_t *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/blt/syscall.h b/include/blt/syscall.h
@@ -0,0 +1,104 @@
+/* Copyright 1998-2000 Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License.
+*/
+
+#ifndef _SYSCALL_H_
+#define _SYSCALL_H_
+
+#include <blt/types.h>
+#include <blt/os.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void os_terminate(int status);
+ void os_console(char *string);
+ int os_brk(int addr);
+ void os_handle_irq(int irq);
+ void os_sleep_irq(void);
+ void os_debug(void);
+ void os_sleep(int ticks);
+ int os_identify(int rsrc); /* returns the team_id of the owner of a resource */
+
+ sem_id sem_create(int value, const char *name);
+ int sem_destroy(sem_id sem);
+ int sem_acquire(sem_id sem);
+ int sem_release(sem_id sem);
+
+ port_id port_create(int restrict, const char *name);
+ int port_destroy(port_id port);
+ int port_option(port_id port, uint32 opt, uint32 arg);
+ ssize_t port_send(port_id src, port_id dst, const void *data, size_t len, uint32 code);
+ ssize_t port_recv(port_id dst, port_id *src, void *data, size_t max, uint32 *code);
+ ssize_t port_peek(port_id *src, port_id *dst, int *code);
+
+ #define port_set_restrict(port, restrict) port_option(port,PORT_OPT_SETRESTRICT,restrict);
+ #define port_slave(master, slave) port_option(slave,PORT_OPT_SLAVE,master)
+ #define port_set_nonblocking(port) port_option(port, PORT_OPT_NOWAIT, 1);
+ #define port_set_blocking(port) port_option(port, PORT_OPT_NOWAIT, 0);
+ #define port_set_timeout(port, useconds)
+
+ thread_id thr_create(void *addr, void *data, const char *name);
+ int thr_resume(thread_id thr_id);
+ int thr_suspend(thread_id thr_id);
+ int thr_kill(thread_id thr_id);
+ int thr_detach(thread_id (*addr)(void));
+ int thr_wait(thread_id thr_id);
+
+ thread_id thr_spawn(uint32 eip, uint32 esp,
+ area_id area0, uint32 vaddr0,
+ area_id area1, uint32 vaddr1,
+ const char *name);
+
+ area_id area_create(off_t size, off_t virt, void **addr, uint32 flags);
+ area_id area_clone(area_id aid, off_t virt, void **addr, uint32 flags);
+ int area_destroy(area_id aid);
+ int area_resize(area_id aid, off_t size);
+
+ int right_create(int rsrc_id, uint32 flags);
+ int right_destroy(int right_id);
+ int right_revoke(int right_id, int thread_id);
+ int right_grant(int right_id, int thread_id);
+
+ /* look up a resource by name or id number and fill in information about it */
+ int rsrc_find_id (rsrc_info *info, int rsrc_id, int rsrc_type);
+ int rsrc_find_name (rsrc_info *info, const char *name, int rsrc_type);
+
+ /*
+ * the metacall is for random things that are not compiled into the kernel
+ * by default, but might be useful for debugging, etc. if you think you
+ * need to add a syscall temporarily in order to debug something, using
+ * this will save you some time, since you only have to edit two files
+ * instead of four.
+ *
+ * the request parameter is used to multiplex the call among many different
+ * purposes. the range META_MIN_RESERVED to META_MAX_RESERVED is for
+ * temporary purposes that are not submitted to the repository. request
+ * defines are in include/blt/os.h.
+ */
+
+ int os_meta(unsigned int request, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* compatability defines */
+#define os_thread(addr) thr_create(addr,NULL,NULL);
+#define thr_join(thr_id,opt) thr_wait(thr_id);
+#define thr_detach(addr) (0)
+
+/* deprecated messaging system */
+typedef struct {
+ int flags;
+ int src;
+ int dst;
+ int size;
+ void *data;
+} msg_hdr_t;
+
+#define old_port_send(mh) port_send((mh)->src, (mh)->dst, (mh)->data, (mh)->size, 0)
+#define old_port_recv(mh) port_recv((mh)->dst, &((mh)->src), (mh)->data, (mh)->size, 0)
+
+#endif
diff --git a/include/blt/syscall_id.h b/include/blt/syscall_id.h
@@ -0,0 +1,72 @@
+/* $Id: //depot/blt/include/blt/syscall_id.h#11 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef _SYSCALL_ID_H
+#define _SYSCALL_ID_H
+
+/* syscall id #'s */
+#define BLT_SYS_os_meta 0
+#define BLT_SYS_os_terminate 1
+#define BLT_SYS_os_console 2
+#define BLT_SYS_os_brk 3
+#define BLT_SYS_os_handle_irq 4
+#define BLT_SYS_os_sleep_irq 5
+#define BLT_SYS_os_debug 6
+#define BLT_SYS_os_sleep 7
+
+#define BLT_SYS_sem_create 8
+#define BLT_SYS_sem_destroy 9
+#define BLT_SYS_sem_acquire 10
+#define BLT_SYS_sem_release 11
+
+#define BLT_SYS_port_create 12
+#define BLT_SYS_port_destroy 13
+#define BLT_SYS_port_option 14
+#define BLT_SYS_port_send 15
+#define BLT_SYS_port_recv 16
+
+#define BLT_SYS_os_identify 17
+
+#define BLT_SYS_right_create 18
+#define BLT_SYS_right_destroy 19
+#define BLT_SYS_right_revoke 20
+#define BLT_SYS_right_attach 21
+#define BLT_SYS_right_grant 22
+
+#define BLT_SYS_thr_create 24
+#define BLT_SYS_thr_spawn 25
+#define BLT_SYS_thr_resume 26
+#define BLT_SYS_thr_suspend 27
+#define BLT_SYS_thr_kill 28
+#define BLT_SYS_thr_wait 29
+
+#define BLT_SYS_area_create 30
+#define BLT_SYS_area_clone 31
+#define BLT_SYS_area_destroy 32
+#define BLT_SYS_area_resize 33
+
+#endif
diff --git a/include/blt/tell.h b/include/blt/tell.h
@@ -0,0 +1,47 @@
+/* $Id: //depot/blt/include/blt/tell.h#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BLT_TELL_H_
+#define _BLT_TELL_H_
+
+#define TELL_MAX_LEN 256
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int _tell_init (char *name, void (*func)(const char *));
+ int tell_init (char *name, void (*func)(const char *));
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/blt/types.h b/include/blt/types.h
@@ -0,0 +1,43 @@
+/* Copyright 1998-2000 Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License.
+*/
+
+#ifndef _BLT_TYPES_H
+#define _BLT_TYPES_H
+
+#define CHAR_BIT 8
+#define NULL ((void *) 0)
+
+#define ntohs(n) ( (((n) & 0xFF00) >> 8) | (((n) & 0x00FF) << 8) )
+#define htons(n) ( (((n) & 0xFF00) >> 8) | (((n) & 0x00FF) << 8) )
+
+typedef unsigned long long uint64;
+typedef unsigned int uint32;
+typedef unsigned short uint16;
+typedef unsigned char uint8;
+typedef long long int64;
+typedef int int32;
+typedef short int16;
+typedef char int8;
+typedef unsigned char uchar;
+
+typedef int ssize_t;
+typedef unsigned long int size_t;
+
+typedef unsigned int time_t;
+
+typedef unsigned int off_t;
+typedef unsigned int mode_t;
+typedef unsigned int dev_t;
+typedef unsigned int ino_t;
+typedef unsigned int nlink_t;
+typedef unsigned int uid_t;
+typedef unsigned int gid_t;
+
+/* system resources */
+typedef int port_id;
+typedef int area_id;
+typedef int sem_id;
+typedef int thread_id;
+
+#endif
diff --git a/include/blt/vfs.h b/include/blt/vfs.h
@@ -0,0 +1,118 @@
+/* $Id: //depot/blt/include/blt/vfs.h#7 $
+**
+** Copyright 1998-1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BLT_VFS_H_
+#define _BLT_VFS_H_
+
+#include <blt/types.h>
+#include <blt/fdl.h>
+
+/* operations */
+#define VFS_OPENCONN 1
+#define VFS_CLOSECONN 2
+#define VFS_SCROLL_AREA 19
+
+#define VFS_MOUNT 3
+#define VFS_UNMOUNT 4
+#define VFS_INITIALISE 5
+#define VFS_SYNC 6
+#define VFS_RFSTAT 7
+#define VFS_WFSTAT 8
+
+#define VFS_CREATE 9
+#define VFS_MKDIR 10
+#define VFS_SYMLINK 11
+#define VFS_LINK 12
+#define VFS_RENAME 13
+#define VFS_UNLINK 14
+#define VFS_RMDIR 15
+#define VFS_READLINK 16
+
+#define VFS_OPENDIR 17
+#define VFS_CLOSEDIR 18
+
+#define VFS_OPEN 21
+#define VFS_CLOSE 22
+#define VFS_READ 23
+#define VFS_WRITE 24
+#define VFS_IOCTL 25
+#define VFS_SETFLAGS 26
+#define VFS_RSTAT 27
+#define VFS_WSTAT 28
+#define VFS_FSYNC 29
+
+#define VFS_OPEN_ATTRDIR 30
+#define VFS_CLOSE_ATTRDIR 31
+#define VFS_REWIND_ATTRDIR 32
+#define VFS_READ_ATTRDIR 33
+#define VFS_READ_ATTR 34
+#define VFS_WRITE_ATTR 35
+#define VFS_REMOVE_ATTR 36
+#define VFS_RENAME_ATTR 37
+#define VFS_STAT_ATTR 38
+
+#define VFS_OPEN_INDEXDIR 39
+#define VFS_CLOSE_INDEXDIR 40
+#define VFS_REWIND_INDEXDIR 41
+#define VFS_READ_INDEXDIR 42
+#define VFS_READ_INDEX 43
+#define VFS_WRITE_INDEX 44
+#define VFS_REMOVE_INDEX 45
+#define VFS_RENAME_INDEX 46
+#define VFS_STAT_INDEX 47
+
+#define VFS_OPEN_QUERY 48
+#define VFS_CLOSE_QUERY 49
+#define VFS_READ_QUERY 50
+
+/* vfs result codes */
+#define VFS_OK 1
+#define VFS_ERROR 2
+#define VFS_MORE_DATA 4
+
+typedef struct
+{
+ unsigned int cmd;
+ unsigned int data[6];
+} vfs_cmd_t;
+
+typedef struct
+{
+ unsigned int status, errno;
+ unsigned int data[6];
+} vfs_res_t;
+
+typedef struct
+{
+ char *buf;
+ int srv_fd, area_offset;
+ int offset, length, more;
+} vfs_fd;
+
+#endif
+
diff --git a/include/boot.h b/include/boot.h
@@ -0,0 +1,66 @@
+/* $Id: //depot/blt/include/boot.h#3 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BOOT_H_
+#define _BOOT_H_
+
+#define BOOTDIR_NAMELEN 32
+#define BOOTDIR_MAX_ENTRIES 64
+#define BOOTDIR_DIRECTORY "SBBB/Directory"
+
+typedef struct {
+ char be_name[BOOTDIR_NAMELEN]; /* name of loaded object, zero terminated */
+ int be_offset; /* offset of object relative to the start of boot_dir */
+ int be_type; /* object type designator */
+ int be_size; /* size of loaded object (pages) */
+ int be_vsize; /* size loaded object should occupy when mapped in */
+ int be_extra0;
+ int be_extra1;
+ int be_extra2;
+ int be_extra3;
+} boot_entry;
+
+typedef struct {
+ boot_entry bd_entry[BOOTDIR_MAX_ENTRIES];
+} boot_dir;
+
+/* void _start(uint32 mem, char *params, boot_dir *bd); */
+
+#define BE_TYPE_NONE 0 /* empty entry */
+#define BE_TYPE_DIRECTORY 1 /* directory (entry 0) */
+#define BE_TYPE_BOOTSTRAP 2 /* bootstrap code object (entry 1) */
+#define BE_TYPE_CODE 3 /* executable code object */
+#define BE_TYPE_DATA 4 /* raw data object */
+#define BE_TYPE_ELF32 5 /* 32bit ELF object */
+
+/* for BE_TYPE_CODE */
+#define be_code_vaddr be_extra0 /* virtual address (rel offset 0) */
+#define be_code_ventr be_extra1 /* virtual entry point (rel offset 0) */
+
+#endif
+
diff --git a/include/ctype.h b/include/ctype.h
@@ -0,0 +1,45 @@
+/* $Id: //depot/blt/include/ctype.h#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _CTYPE_H_
+#define _CTYPE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int _isdigit (int c);
+ int isdigit (int c);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/dirent.h b/include/dirent.h
@@ -0,0 +1,66 @@
+/* $Id: //depot/blt/include/dirent.h#3 $
+**
+** Copyright 1999 Sidney Cammersi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __DIRENT_H__
+#define __DIRENT_H__
+
+#include <blt/types.h>
+#include <blt/os.h>
+
+typedef struct
+{
+ int fd, hoffset, more, len, left;
+ struct dirent *head, *current;
+} DIR;
+
+struct dirent
+{
+ uint32 d_fileno;
+ uint16 d_reclen;
+ char d_name[BLT_MAX_NAME_LENGTH + 1];
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ DIR *_opendir (const char *path);
+ DIR *opendir (const char *path);
+ int _closedir (DIR *dirp);
+ int closedir (DIR *dirp);
+ struct dirent *_readdir (DIR *dirp);
+ struct dirent *readdir (DIR *dirp);
+ void _rewinddir (DIR *dirp);
+ void rewinddir (DIR *dirp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/include/dlfcn.h b/include/dlfcn.h
@@ -0,0 +1,55 @@
+/* $Id: //depot/blt/include/dlfcn.h#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _DLFCN_H_
+#define _DLFCN_H_
+
+#define RTLD_GLOBAL 1
+#define RTLD_LAZY 2
+#define RTLD_NOW 4
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void *_dlopen (const char *filename, int flag);
+ void *dlopen (const char *filename, int flag);
+ const char *_dlerror (void);
+ const char *dlerror (void);
+ void *_dlsym (void *handle, const char *symbol);
+ void *dlsym (void *handle, const char *symbol);
+ int _dlclose (void *handle);
+ int dlclose (void *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/elf.h b/include/elf.h
@@ -0,0 +1,236 @@
+/* $Id: //depot/blt/include/elf.h#4 $
+**
+** Copyright 1998 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __ELF_H__
+#define __ELF_H__
+
+#define EI_NIDENT 16
+
+/* ELF header */
+typedef struct
+{
+ unsigned char e_ident [EI_NIDENT];
+ unsigned short e_type, e_machine;
+ unsigned int e_version, e_entry, e_phoff, e_shoff, e_flags;
+ unsigned short e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum,
+ e_shstrndx;
+} elf32_hdr_t;
+
+#define ELF_MAGIC 0x464c457f
+
+/* e_ident indices */
+#define EI_MAG0 0 /* 0x7F */
+#define EI_MAG1 1 /* 'E' */
+#define EI_MAG2 2 /* 'L' */
+#define EI_MAG3 3 /* 'F' */
+#define EI_CLASS 4 /* file class */
+#define EI_DATA 5 /* data encoding */
+#define EI_VERSION 6 /* file version */
+#define EI_PAD 7 /* start of padding bytes */
+
+/* e_ident data */
+#define ELFCLASSNONE 0 /* invalid class */
+#define ELFCLASS32 1 /* 32-bit objects */
+#define ELFCLASS64 2 /* 64-bit objects */
+#define ELFDATANONE 0 /* invalid data encoding */
+#define ELFDATA2LSB 1 /* little-endian */
+#define ELFDATA2MSB 2 /* big-endian */
+
+/* e_type */
+#define ET_NONE 0 /* no file type */
+#define ET_REL 1 /* relocatable file */
+#define ET_EXEC 2 /* executable file */
+#define ET_DYN 3 /* shared object file */
+#define ET_CORE 4 /* core file */
+#define ET_LOPROC 0xFF00 /* beginning processor specific range */
+#define ET_HIPROC 0xFFFF /* end of processor specific range */
+
+/* e_machine */
+#define EM_NONE 0 /* no machine */
+#define EM_M32 1 /* AT&T WE 32100 */
+#define EM_SPARC 2 /* SPARC */
+#define EM_386 3 /* Intel 386 */
+#define EM_68K 4 /* Motorola 68000 */
+#define EM_88K 5 /* Motorola 88000 */
+#define EM_486 6 /* Intel 486 - unused */
+#define EM_860 7 /* Intel 80860 */
+#define EM_MIPS 8 /* MIPS R3000 big-endian */
+#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
+#define EM_SPARC64 11 /* SPARC V9 64-bit */
+#define EM_HPPA 15 /* HP PA-RISC */
+#define EM_PPC 20 /* PowerPC */
+
+/* e_version */
+#define EV_NONE 0 /* invalid version */
+#define EV_CURRENT 1 /* current version */
+
+/* section header */
+typedef struct
+{
+ unsigned int sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size,
+ sh_link, sh_info, sh_addralign, sh_entsize;
+} elf32_sec_hdr_t;
+
+/* sh_type */
+#define SHT_NULL 0 /* section header is inactive */
+#define SHT_PROGBITS 1 /* program specific information */
+#define SHT_SYMTAB 2 /* symbol table, only one of these */
+#define SHT_STRTAB 3 /* string table */
+#define SHT_RELA 4 /* relocation entries with addends - ? */
+#define SHT_HASH 5 /* symbol hash table, only one of these */
+#define SHT_DYNAMIC 6 /* dynamic linking information, only one of these */
+#define SHT_NOTE 7 /* file marking information */
+#define SHT_NOBITS 8 /* occupies no space, but similar to SHT_PROGBITS */
+#define SHT_REL 9 /* relocation entries without addends - ? */
+#define SHT_SHLIB 10 /* reserved and unspecified */
+#define SHT_DYNSYM 11 /* symbol table for dynamic linking, only one */
+
+#define SHF_WRITE 1 /* section should be writable */
+#define SHF_ALLOC 2 /* section occupies memory during execution */
+#define SHF_EXECINSTR 4 /* section contains executable text */
+#define SHF_MASKPROC 0xF0000000 /* reserved for machine specific data */
+
+/* program header */
+typedef struct
+{
+ unsigned int p_type, p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, p_flags,
+ p_align;
+} elf32_pgm_hdr_t;
+
+/* p_type */
+#define PT_NULL 0 /* array element unused */
+#define PT_LOAD 1 /* loadable segment */
+#define PT_DYNAMIC 2 /* contains dynamic linking information */
+#define PT_INTERP 3 /* location and size of path to interpreter */
+#define PT_NOTE 4 /* location and size of auxillary information */
+#define PT_SHLIB 5 /* reserved and unspecified */
+#define PT_PHDR 6 /* location and size of program header table */
+#define PT_LOPROC 0x70000000 /* reserved for processor specific use */
+#define PT_HIPROC 0x7FFFFFFF /* end of range */
+
+typedef struct
+{
+ int d_tag;
+ union
+ {
+ unsigned int d_val, d_ptr;
+ } d_un;
+} elf32_dyn_t;
+
+/* d_tag */
+#define DT_NULL 0 /* ignored, but mandatory */
+#define DT_NEEDED 1 /* name of needed library */
+#define DT_PLTRELSZ 2 /* size of plt */
+#define DT_PLTGOT 3
+#define DT_HASH 4
+#define DT_STRTAB 5 /* string table with symbol and library names */
+#define DT_SYMTAB 6
+#define DT_RELA 7
+#define DT_REL 17 /* reloc entries for data */
+#define DT_RELSZ 18
+#define DT_RELENT 19
+#define DT_PLTREL 20
+#define DT_JMPREL 23 /* reloc entries associated with plt */
+
+/* relocation entry without addend */
+typedef struct
+{
+ unsigned int r_offset, r_info;
+} elf32_rel_t;
+
+/* relocation entry with addend */
+typedef struct
+{
+ unsigned int r_offset, r_info, r_addend;
+} elf32_rela_t;
+
+#define ELF32_R_SYM(i) ((i) >> 8)
+#define ELF32_R_TYPE(i) ((unsigned char) (i))
+#define ELF32_R_INFO(i,j) (((i) << 8) + (unsigned char) (j))
+
+#define R_386_NONE 0 /* none */
+#define R_386_32 1
+#define R_386_PC32 2
+#define R_386_GOT32 3
+#define R_386_PLT32 4
+#define R_386_COPY 5
+#define R_386_GLOB_DAT 6
+#define R_386_JMP_SLOT 7 /* location of procedure linkage table entry */
+#define R_386_RELATIVE 8
+#define R_386_GOTOFF 9
+#define R_386_GOTPC 10
+
+typedef struct
+{
+ unsigned int st_name, st_value, st_size;
+ unsigned char st_info, st_other;
+ unsigned short st_shndx;
+} elf32_sym_t;
+
+#define ELF32_ST_BIND(i) ((i) >> 4)
+#define ELF32_ST_TYPE(i) ((i) & 0xF)
+#define ELF32_ST_INFO(i,j) (((i) << 4) + ((j) & 0xF))
+
+#define STT_NOTYPE 0 /* type not specified */
+#define STT_OBJECT 1 /* symbol references data */
+#define STT_FUNC 2 /* symbol represents text */
+#define STT_SECTION 3 /* symbol is a section */
+#define STT_FILE 4 /* object file */
+#define STT_LOPROC 13 /* reserved for processor */
+#define STT_MEDPROC 14 /* reserved for processor */
+#define STT_HIPROC 15 /* reserved for processor */
+
+#define SHN_UNDEF 0
+#define SHN_LORESERVE 0xff00
+#define SHN_LOPROC 0xff00
+#define SHN_HIPROC 0xff1f
+#define SHN_ABS 0xfff1
+#define SHN_COMMON 0xfff2
+#define SHN_HIRESERVE 0xffff
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ elf32_sec_hdr_t *_elf_find_section_hdr (elf32_hdr_t *hdr, char *name);
+ elf32_sec_hdr_t *elf_find_section_hdr (elf32_hdr_t *hdr, char *name);
+ void *_elf_lookup_sym (int filenum, const char *name);
+ void *elf_lookup_sym (int filenum, const char *name);
+ void *_elf_find_section_data (elf32_hdr_t *hdr, char *name);
+ void *elf_find_section_data (elf32_hdr_t *hdr, char *name);
+ int _elf_section_size (elf32_hdr_t *hdr, char *name);
+ int elf_section_size (elf32_hdr_t *hdr, char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/errno.h b/include/errno.h
@@ -0,0 +1,156 @@
+/* $Id: //depot/blt/include/errno.h#1 $ */
+/* $OpenBSD: errno.h,v 1.8 1999/01/07 05:34:29 deraadt Exp $ */
+/* $NetBSD: errno.h,v 1.10 1996/01/20 01:33:53 jtc Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)errno.h 8.5 (Berkeley) 1/21/94
+ */
+
+#ifndef __ERRNO_H__
+#define __ERRNO_H__
+
+extern int errno; /* global error number */
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* Input/output error */
+#define ENXIO 6 /* Device not configured */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file descriptor */
+#define ECHILD 10 /* No child processes */
+#define EDEADLK 11 /* Resource deadlock avoided */
+#define ENOMEM 12 /* Cannot allocate memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* Operation not supported by device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* Too many open files in system */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Inappropriate ioctl for device */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+
+/* math software */
+#define EDOM 33 /* Numerical argument out of domain */
+#define ERANGE 34 /* Result too large */
+
+/* non-blocking and interrupt i/o */
+#define EAGAIN 35 /* Resource temporarily unavailable */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define EINPROGRESS 36 /* Operation now in progress */
+#define EALREADY 37 /* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define ENOTSOCK 38 /* Socket operation on non-socket */
+#define EDESTADDRREQ 39 /* Destination address required */
+#define EMSGSIZE 40 /* Message too long */
+#define EPROTOTYPE 41 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 42 /* Protocol not available */
+#define EPROTONOSUPPORT 43 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
+#define EOPNOTSUPP 45 /* Operation not supported */
+#define EPFNOSUPPORT 46 /* Protocol family not supported */
+#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */
+#define EADDRINUSE 48 /* Address already in use */
+#define EADDRNOTAVAIL 49 /* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define ENETDOWN 50 /* Network is down */
+#define ENETUNREACH 51 /* Network is unreachable */
+#define ENETRESET 52 /* Network dropped connection on reset */
+#define ECONNABORTED 53 /* Software caused connection abort */
+#define ECONNRESET 54 /* Connection reset by peer */
+#define ENOBUFS 55 /* No buffer space available */
+#define EISCONN 56 /* Socket is already connected */
+#define ENOTCONN 57 /* Socket is not connected */
+#define ESHUTDOWN 58 /* Can't send after socket shutdown */
+#define ETOOMANYREFS 59 /* Too many references: can't splice */
+#define ETIMEDOUT 60 /* Operation timed out */
+#define ECONNREFUSED 61 /* Connection refused */
+
+#define ELOOP 62 /* Too many levels of symbolic links */
+#define ENAMETOOLONG 63 /* File name too long */
+
+/* should be rearranged */
+#define EHOSTDOWN 64 /* Host is down */
+#define EHOSTUNREACH 65 /* No route to host */
+#define ENOTEMPTY 66 /* Directory not empty */
+
+/* quotas & mush */
+#define EPROCLIM 67 /* Too many processes */
+#define EUSERS 68 /* Too many users */
+#define EDQUOT 69 /* Disc quota exceeded */
+
+/* Network File System */
+#define ESTALE 70 /* Stale NFS file handle */
+#define EREMOTE 71 /* Too many levels of remote in path */
+#define EBADRPC 72 /* RPC struct is bad */
+#define ERPCMISMATCH 73 /* RPC version wrong */
+#define EPROGUNAVAIL 74 /* RPC prog. not avail */
+#define EPROGMISMATCH 75 /* Program version wrong */
+#define EPROCUNAVAIL 76 /* Bad procedure for program */
+
+#define ENOLCK 77 /* No locks available */
+#define ENOSYS 78 /* Function not implemented */
+
+#define EFTYPE 79 /* Inappropriate file type or format */
+#define EAUTH 80 /* Authentication error */
+#define ENEEDAUTH 81 /* Need authenticator */
+#define EIPSEC 82 /* IPsec processing failure */
+#define ELAST 82 /* Must be equal largest errno */
+
+#endif
+
diff --git a/include/fcntl.h b/include/fcntl.h
@@ -0,0 +1,61 @@
+/* $Id: //depot/blt/include/fcntl.h#4 $
+**
+** Copyright 1998 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _FCNTL_H_
+#define _FCNTL_H_
+
+#include <blt/types.h>
+
+#define O_RDONLY 0x00000001
+#define O_WRONLY 0x00000002
+#define O_RDWR 0x00000003
+#define O_NONBLOCK 0x00000004
+#define O_APPEND 0x00000008
+#define O_CREAT 0x00000010
+#define O_TRUNC 0x00000020
+#define O_EXCL 0x00000040
+#define O_SHLOCK 0x00000080
+#define O_EXLOCK 0x00000100
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int _open (const char *path, int flags, mode_t mode);
+ int open (const char *path, int flags, mode_t mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/i386/asm.h b/include/i386/asm.h
@@ -0,0 +1,40 @@
+/* $Id: //depot/blt/include/i386/asm.h#1 $
+**
+** Copyright 1998 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __I386_ASM_H__
+#define __I386_ASM_H__
+
+#define FUNCTION(name) \
+ .text; \
+ .globl name; \
+ .type name, @function; \
+ .align 4; \
+ name:
+
+#endif
+
diff --git a/include/i386/io.h b/include/i386/io.h
@@ -0,0 +1,165 @@
+#ifndef _ASM_IO_H
+#define _ASM_IO_H
+
+#define SLOW_IO_BY_JUMPING
+
+/*
+ * This file contains the definitions for the x86 IO instructions
+ * inb/inw/inl/outb/outw/outl and the "string versions" of the same
+ * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
+ * versions of the single-IO instructions (inb_p/inw_p/..).
+ *
+ * This file is not meant to be obfuscating: it's just complicated
+ * to (a) handle it all in a way that makes gcc able to optimize it
+ * as well as possible and (b) trying to avoid writing the same thing
+ * over and over again with slight variations and possibly making a
+ * mistake somewhere.
+ */
+
+/*
+ * Thanks to James van Artsdalen for a better timing-fix than
+ * the two short jumps: using outb's to a nonexistent port seems
+ * to guarantee better timings even on fast machines.
+ *
+ * On the other hand, I'd like to be sure of a non-existent port:
+ * I feel a bit unsafe about using 0x80 (should be safe, though)
+ *
+ * Linus
+ */
+
+#ifdef SLOW_IO_BY_JUMPING
+#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:")
+#else
+#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80")
+#endif
+
+#define SLOW_DOWN_IO __SLOW_DOWN_IO
+
+/*
+ * Talk about misusing macros..
+ */
+
+#define __OUT1(s,x) \
+extern inline void __out##s(unsigned x value, unsigned short port) {
+
+#define __OUT2(s,s1,s2) \
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+
+#define __OUT(s,s1,x) \
+__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \
+__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \
+__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; }
+
+#define __IN1(s) \
+extern inline RETURN_TYPE __in##s(unsigned short port) { RETURN_TYPE _v;
+
+#define __IN2(s,s1,s2) \
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+
+#define __IN(s,s1,i...) \
+__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \
+__IN1(s##c) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \
+__IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; }
+
+#define __INS(s) \
+extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("cld ; rep ; ins" #s \
+: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define __OUTS(s) \
+extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("cld ; rep ; outs" #s \
+: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define RETURN_TYPE unsigned char
+/* __IN(b,"b","0" (0)) */
+__IN(b,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned short
+/* __IN(w,"w","0" (0)) */
+__IN(w,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned int
+__IN(l,"")
+#undef RETURN_TYPE
+
+__OUT(b,"b",char)
+__OUT(w,"w",short)
+__OUT(l,,int)
+
+__INS(b)
+__INS(w)
+__INS(l)
+
+__OUTS(b)
+__OUTS(w)
+__OUTS(l)
+
+/*
+ * Note that due to the way __builtin_constant_p() works, you
+ * - can't use it inside a inline function (it will never be true)
+ * - you don't have to worry about side effects within the __builtin..
+ */
+#define outb(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outbc((val),(port)) : \
+ __outb((val),(port)))
+
+#define inb(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inbc(port) : \
+ __inb(port))
+
+#define outb_p(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outbc_p((val),(port)) : \
+ __outb_p((val),(port)))
+
+#define inb_p(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inbc_p(port) : \
+ __inb_p(port))
+
+#define outw(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outwc((val),(port)) : \
+ __outw((val),(port)))
+
+#define inw(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inwc(port) : \
+ __inw(port))
+
+#define outw_p(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outwc_p((val),(port)) : \
+ __outw_p((val),(port)))
+
+#define inw_p(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inwc_p(port) : \
+ __inw_p(port))
+
+#define outl(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outlc((val),(port)) : \
+ __outl((val),(port)))
+
+#define inl(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inlc(port) : \
+ __inl(port))
+
+#define outl_p(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outlc_p((val),(port)) : \
+ __outl_p((val),(port)))
+
+#define inl_p(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inlc_p(port) : \
+ __inl_p(port))
+
+#endif
diff --git a/include/i386/io.h.new b/include/i386/io.h.new
@@ -0,0 +1,222 @@
+/* $OpenBSD: pio.h,v 1.5 1997/11/10 23:40:45 niklas Exp $ */
+/* $NetBSD: pio.h,v 1.13 1996/03/08 20:15:23 cgd Exp $ */
+
+/*
+ * Copyright (c) 1993, 1995 Charles M. Hannum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Charles M. Hannum.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _I386_PIO_H_
+#define _I386_PIO_H_
+
+/*
+ * Functions to provide access to i386 programmed I/O instructions.
+ *
+ * The in[bwl]() and out[bwl]() functions are split into two varieties: one to
+ * use a small, constant, 8-bit port number, and another to use a large or
+ * variable port number. The former can be compiled as a smaller instruction.
+ */
+
+#include "blt/types.h"
+
+#define __SLOW_DOWN_IO asm volatile ("jmp 1f \n 1: jmp 1f \n 1:")
+#define SLOW_DOWN_IO __SLOW_DOWN_IO
+
+#define outb_p(a,b) { outb(a,b) ; SLOW_DOWN_IO; }
+#define inb_p(a,b) { inb(a,b) ; SLOW_DOWN_IO; }
+#define outw_p(a,b) { outw(a,b) ; SLOW_DOWN_IO; }
+#define inw_p(a,b) { inw(a,b) ; SLOW_DOWN_IO; }
+
+#ifdef __OPTIMIZE__
+
+#define __use_immediate_port(port) \
+ (__builtin_constant_p((port)) && (port) < 0x100)
+
+#else
+
+#define __use_immediate_port(port) 0
+
+#endif
+
+
+#define inb(port) \
+ (__use_immediate_port(port) ? __inbc(port) : __inb(port))
+
+static inline uint8
+__inbc(int port)
+{
+ uint8 data;
+ __asm __volatile("inb %1,%0" : "=a" (data) : "id" (port));
+ return data;
+}
+
+static inline uint8
+__inb(int port)
+{
+ uint8 data;
+ __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port));
+ return data;
+}
+
+static inline void
+insb(int port, void *addr, int cnt)
+{
+ __asm __volatile("cld\n\trepne\n\tinsb" :
+ :
+ "d" (port), "D" (addr), "c" (cnt) :
+ "%edi", "%ecx", "memory");
+}
+
+#define inw(port) \
+ (__use_immediate_port(port) ? __inwc(port) : __inw(port))
+
+static inline uint16
+__inwc(int port)
+{
+ uint16 data;
+ __asm __volatile("inw %1,%0" : "=a" (data) : "id" (port));
+ return data;
+}
+
+static inline uint16
+__inw(int port)
+{
+ uint16 data;
+ __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port));
+ return data;
+}
+
+static inline void
+insw(int port, void *addr, int cnt)
+{
+ __asm __volatile("cld\n\trepne\n\tinsw" :
+ :
+ "d" (port), "D" (addr), "c" (cnt) :
+ "%edi", "%ecx", "memory");
+}
+
+#define inl(port) \
+ (__use_immediate_port(port) ? __inlc(port) : __inl(port))
+
+static inline uint32
+__inlc(int port)
+{
+ uint32 data;
+ __asm __volatile("inl %1,%0" : "=a" (data) : "id" (port));
+ return data;
+}
+
+static inline uint32
+__inl(int port)
+{
+ uint32 data;
+ __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port));
+ return data;
+}
+
+static inline void
+insl(int port, void *addr, int cnt)
+{
+ __asm __volatile("cld\n\trepne\n\tinsl" :
+ :
+ "d" (port), "D" (addr), "c" (cnt) :
+ "%edi", "%ecx", "memory");
+}
+
+#define outb(port, data) \
+ (__use_immediate_port(port) ? __outbc(port, data) : __outb(port, data))
+
+static inline void
+__outbc(int port, uint8 data)
+{
+ __asm __volatile("outb %0,%1" : : "a" (data), "id" (port));
+}
+
+static inline void
+__outb(int port, uint8 data)
+{
+ __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port));
+}
+
+static inline void
+outsb(int port, const void *addr, int cnt)
+{
+ __asm __volatile("cld\n\trepne\n\toutsb" :
+ :
+ "d" (port), "S" (addr), "c" (cnt) :
+ "%esi", "%ecx");
+}
+
+#define outw(port, data) \
+ (__use_immediate_port(port) ? __outwc(port, data) : __outw(port, data))
+
+static inline void
+__outwc(int port, uint16 data)
+{
+ __asm __volatile("outw %0,%1" : : "a" (data), "id" (port));
+}
+
+static inline void
+__outw(int port, uint16 data)
+{
+ __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port));
+}
+
+static inline void
+outsw(int port, const void *addr, int cnt)
+{
+ __asm __volatile("cld\n\trepne\n\toutsw" :
+ :
+ "d" (port), "S" (addr), "c" (cnt) :
+ "%esi", "%ecx");
+}
+
+#define outl(port, data) \
+ (__use_immediate_port(port) ? __outlc(port, data) : __outl(port, data))
+
+static inline void
+__outlc(int port, uint32 data)
+{
+ __asm __volatile("outl %0,%1" : : "a" (data), "id" (port));
+}
+
+static inline void
+__outl(int port, uint32 data)
+{
+ __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port));
+}
+
+static inline void
+outsl(int port, const void *addr, int cnt)
+{
+ __asm __volatile("cld\n\trepne\n\toutsl" :
+ :
+ "d" (port), "S" (addr), "c" (cnt) :
+ "%esi", "%ecx");
+}
+
+#endif /* _I386_PIO_H_ */
diff --git a/include/multiboot.h b/include/multiboot.h
@@ -0,0 +1,64 @@
+/* $Id$
+**
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _MULTIBOOT_H_
+#define _MULTIBOOT_H_
+
+#define MBI_MEM 0x00000001
+#define MBI_BOOTDEV 0x00000002
+#define MBI_CMDLINE 0x00000004
+#define MBI_MODS 0x00000008
+#define MBI_SYMS_AOUT 0x00000010
+#define MBI_SYMS_ELF 0x00000020
+#define MBI_MMAP 0x00000040
+
+typedef struct
+{
+ unsigned int flags, mem_lower, mem_upper, boot_device;
+ char *cmdline;
+ unsigned int mods_count, mods_addr;
+ union
+ {
+ struct
+ {
+ unsigned int tabsize, strsize, addr, _pad_;
+ } sym_aout;
+ struct
+ {
+ unsigned int num, size, addr, shndx;
+ } sym_elf;
+ } mb_sym_un;
+ unsigned int mmap_length, mmap_addr;
+} multiboot_info;
+
+
+#endif
+
diff --git a/include/stdarg.h b/include/stdarg.h
@@ -0,0 +1,56 @@
+/* $NetBSD: stdarg.h,v 1.12 1995/12/25 23:15:31 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)stdarg.h 8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _I386_STDARG_H_
+#define _I386_STDARG_H_
+
+#include <ansi.h>
+
+typedef _BSD_VA_LIST_ va_list;
+
+#define __va_size(type) \
+ (((sizeof(type) + sizeof(long) - 1) / sizeof(long)) * sizeof(long))
+
+#define va_start(ap, last) \
+ ((ap) = (va_list)&(last) + __va_size(last))
+
+#define va_arg(ap, type) \
+ (*(type *)((ap) += __va_size(type), (ap) - __va_size(type)))
+
+#define va_end(ap) ((void)0)
+
+#endif /* !_I386_STDARG_H_ */
diff --git a/include/stddef.h b/include/stddef.h
@@ -0,0 +1,35 @@
+/* $Id: //depot/blt/include/stddef.h#2 $
+**
+** Copyright 1998 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _STDDEF_H_
+#define _STDDEF_H_
+
+#define NULL ((void *) 0)
+
+#endif
+
diff --git a/include/stdio.h b/include/stdio.h
@@ -0,0 +1,64 @@
+/* $Id: //depot/blt/include/stdio.h#7 $
+**
+** Copyright 1998 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _STDIO_H_
+#define _STDIO_H_
+
+#include <blt/types.h>
+
+typedef struct
+{
+ int fd;
+} FILE;
+
+extern FILE *stdin, *stdout, *stderr;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int _console_read (void *cookie, void *buf, size_t count);
+
+ int _getc (FILE *stream);
+ int getc (FILE *stream);
+ int _getchar (void);
+ int getchar (void);
+
+ int _printf (const char *format, ...);
+ int printf (const char *format, ...);
+
+ int _snprintf (char *str, size_t size, const char *format, ...);
+ int snprintf (char *str, size_t size, const char *format, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/stdlib.h b/include/stdlib.h
@@ -0,0 +1,61 @@
+/* $Id: //depot/blt/include/stdlib.h#7 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef _stdlib_h
+#define _stdlib_h
+
+#include <blt/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void *_malloc(size_t size);
+ void *malloc(size_t size);
+ void _free(void *ptr);
+ void free(void *ptr);
+ void *_realloc(void *ptr, size_t size);
+ void *realloc(void *ptr, size_t size);
+
+ void _exit (int status);
+ void exit (int status);
+
+ void _qsort (void *base, size_t nmembers, size_t membsize,
+ int (*compar)(const void *, const void *));
+ void qsort (void *base, size_t nmembers, size_t membsize,
+ int (*compar)(const void *, const void *));
+
+ int _atoi (const char *a);
+ int atoi (const char *a);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/string.h b/include/string.h
@@ -0,0 +1,64 @@
+/* $Id: //depot/blt/include/string.h#9 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _STRING_H_
+#define _STRING_H_
+
+#include <blt/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ char *strcpy(char *dst, const char *src);
+ char *strcat(char *dst, const char *src);
+ char *strncpy(char *dst, const char *src, size_t size);
+ int strncmp(const char *s1, const char *s2, size_t n);
+ int strcmp(const char *s1, const char *s2);
+ size_t strlen(const char *str);
+ char *strchr (const char *cs, int c);
+ size_t strlcpy (char *dst, const char *src, size_t size);
+ size_t strlcat (char *dst, const char *src, size_t size);
+
+ void *memset(void *s, int c, size_t n);
+ int memcmp(const void *dst, const void *src, size_t size);
+ void *memcpy(void *dst, const void *src, size_t size);
+ void *memmove(void *dest, const void *src, size_t n);
+
+ int bcmp (const void *s, const void *t, size_t len);
+ void bzero (void *b, size_t len);
+
+ char *_strerror (int errnum);
+ char *strerror (int errnum);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/include/sys/ioctl.h b/include/sys/ioctl.h
@@ -0,0 +1,45 @@
+/* $Id: //depot/blt/include/sys/ioctl.h#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _SYS_IOCTL_H_
+#define _SYS_IOCTL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int _ioctl (int fd, unsigned long request, char *argp);
+ int ioctl (int fd, unsigned long request, char *argp);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/sys/stat.h b/include/sys/stat.h
@@ -0,0 +1,69 @@
+/* $Id: //depot/blt/include/sys/stat.h#4 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _SYS_STAT_H_
+#define _SYS_STAT_H_
+
+#include <sys/types.h>
+
+struct stat
+{
+ dev_t st_dev; /* device on which filesystem resides */
+ ino_t st_ino; /* inode number */
+ mode_t st_mode; /* inode protection mode */
+ nlink_t st_nlink; /* number of hard links to file */
+ uid_t st_uid; /* user id of owner */
+ gid_t st_gid; /* group id of owner */
+ dev_t st_rdev; /* device type for device inodes */
+ off_t st_size; /* file size in bytes */
+ uint32 st_blocks; /* file size in blocks */
+ uint32 st_blksize; /* size of block */
+ struct timespec st_atimespec; /* time of last access */
+ struct timespec st_mtimespec; /* time of last modification */
+ struct timespec st_ctimespec; /* time of last status change */
+ uint32 st_flags; /* user-defined flags */
+ uint32 st_gen; /* file generation number */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int _stat (const char *path, struct stat *buf);
+int stat (const char *path, struct stat *buf);
+
+int _mkdir (const char *path, mode_t mode);
+int mkdir (const char *path, mode_t mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/sys/types.h b/include/sys/types.h
@@ -0,0 +1,44 @@
+/* $Id: //depot/blt/include/sys/types.h#1 $
+**
+** Copyright 1998 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _SYS_TYPES_H_
+#define _SYS_TYPES_H_
+
+#include <blt/types.h>
+
+struct timespec
+{
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+
+#endif
+
diff --git a/include/unistd.h b/include/unistd.h
@@ -0,0 +1,62 @@
+/* $Id: //depot/blt/include/unistd.h#11 $
+**
+** Copyright 1998 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _UNISTD_H_
+#define _UNISTD_H_
+
+#include <blt/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ ssize_t _read (int fd, void *buf, size_t count);
+ ssize_t read (int fd, void *buf, size_t count);
+ ssize_t _write (int fd, const void *buf, size_t count);
+ ssize_t write (int fd, const void *buf, size_t count);
+ int _close (int fd);
+ int close (int fd);
+
+ int _execve (const char *path, char * const *argv, char * const *envp);
+ int execve (const char *path, char * const *argv, char * const *envp);
+
+ void *_sbrk (int diff);
+ void *sbrk (int diff);
+
+ extern char *optarg;
+ extern int optind, optopt, opterr, optreset;
+ int _getopt (int argc, char * const *argv, const char *optstring);
+ int getopt (int argc, char * const *argv, const char *optstring);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/include/win/Button.h b/include/win/Button.h
@@ -0,0 +1,21 @@
+#ifndef _BUTTON_H
+#define _BUTTON_H
+
+#include "Canvas.h"
+
+class Button : public Canvas {
+public:
+ Button(const char *text);
+ virtual ~Button();
+ virtual void Invoke();
+
+private:
+ virtual void Repaint(long, long, long, long);
+ virtual void EventReceived(const Event*);
+
+ char *fText;
+ bool fMouseDown;
+ bool fOverButton;
+};
+
+#endif
diff --git a/include/win/Canvas.h b/include/win/Canvas.h
@@ -0,0 +1,51 @@
+#ifndef _CANVAS_H
+#define _CANVAS_H
+
+class Window;
+class Event;
+
+class Canvas {
+public:
+
+ Canvas();
+ virtual ~Canvas();
+
+ void AddChild(Canvas *child, long left, long top, long right, long bottom);
+ void RemoveChild(Canvas *child);
+ void DrawLine(long, long, long, long);
+ void FillRect(long, long, long, long);
+ void SetBackgroundColor(char);
+ void SetPenColor(char);
+ void DrawString(long, long, const char*);
+ void Hide();
+ void Show();
+ void CopyRect(long left, long top, long right, long bottom, long newLeft,
+ long newTop);
+ Window* GetWindow() const;
+ void GetBounds(long *left, long *top, long *right, long *bottom);
+ void Invalidate(long left = 0, long top = 0, long right = 100000, long bottom
+ = 100000);
+ void LockMouseFocus();
+
+ virtual void Repaint(long left, long top, long right, long bottom);
+ virtual void EventReceived(const Event*);
+
+
+private:
+
+ void HandleEvent(Event*);
+ void BeginPaint(long *out_left, long *out_top, long *out_right, long *out_bottom);
+ void EndPaint();
+
+ int fID;
+ Window *fWindow;
+ bool fInPaint;
+ int fShowLevel;
+ Canvas *fWinListNext, **fWinListPrev;
+ long fLeft, fTop, fRight, fBottom;
+
+ friend class Window;
+};
+
+
+#endif
diff --git a/include/win/Event.h b/include/win/Event.h
@@ -0,0 +1,20 @@
+#ifndef _EVENT_H
+#define _EVENT_H
+
+const int EVT_PAINT = 1;
+const int EVT_QUIT = 2;
+const int EVT_MOUSE_DOWN = 3;
+const int EVT_MOUSE_UP = 4;
+const int EVT_MOUSE_MOVED = 5;
+const int EVT_MOUSE_ENTER = 6;
+const int EVT_MOUSE_LEAVE = 7;
+
+struct Event {
+ int what;
+ int target;
+
+ int x, y;
+};
+
+#endif
+
diff --git a/include/win/Window.h b/include/win/Window.h
@@ -0,0 +1,44 @@
+#ifndef _WINDOW_H
+#define _WINDOW_H
+
+#include <blt/qsem.h>
+
+class Canvas;
+class Connection;
+struct Event;
+
+class Window {
+public:
+
+ Window(long, long, long, long);
+ void Quit();
+ void AddChild(Canvas *child, long left, long top, long right, long bottom);
+ void RemoveChild(Canvas *child);
+ void Flush();
+ void MakeFocus();
+ void Lock();
+ void Unlock();
+ void Show();
+ void Hide();
+
+private:
+
+ ~Window();
+ static int EventLoop(void*);
+ Canvas* FindChild(int id);
+ void DispatchEvent(Event*);
+ void WaitEvent(Event*);
+
+ Connection *fConnection;
+ int fID;
+ int fShowLevel;
+ int fEventPort;
+ qsem_t *fLock;
+
+ Canvas *fCanvasList;
+
+ friend class Canvas;
+};
+
+
+#endif
+\ No newline at end of file
diff --git a/kernel/Makefile b/kernel/Makefile
@@ -0,0 +1,18 @@
+BLTHOME := ../
+include $(BLTHOME)make.conf
+
+CFLAGS += -DASSERT $(SMP) $(SERIAL) $(SERIALDEBUG)
+BINARY := kernel.bin
+LIBS := -lkern -lconsole
+ENTRY := $(ENTRY_KERNEL)
+CRT0 :=
+
+OBJS := stub.o kernel.o i386.o jump.o ktrace.o \
+ memory.o resource.o port.o sem.o aspace.o task.o rights.o \
+ list.o team.o fault.o syscall.o debug.o pager.o
+
+ifeq ($(SMP),-D__SMP__)
+OBJS += smp.o cpuid.o trampoline.o
+endif
+
+include $(BLTHOME)make.actions
diff --git a/kernel/aspace.c b/kernel/aspace.c
@@ -0,0 +1,453 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <blt/os.h>
+#include "kernel.h"
+#include "memory.h"
+#include "aspace.h"
+
+extern uint32 _cr3;
+extern aspace_t *flat;
+
+int snprintf (char *s, int len, const char *fmt, ...);
+
+void aspace_pprint(uint32 *page, uint32 vbase)
+{
+ int i,j;
+
+ char buf[80];
+
+ for(i=0;i<1024;i++){
+ if(page[i]){
+ j = page[i];
+ snprintf(buf,80,"%s %s %s ",
+ (j & 4) ? "USR" : "SYS",
+ (j & 2) ? "RW" : "RO",
+ (j & 1) ? "P" : "X");
+
+ snprintf(buf+9,80-9,"%xv %xp", i*4096+vbase, j&0xFFFFFF00);
+
+ for(j=1;(i+j < 1024) &&
+ ( (0xFFFFFF00 & page[i+j]) ==
+ (0xFFFFFF00 & page[i+j-1])+0x1000 );j++);
+
+ if(j>1) {
+ i += j-1;
+ snprintf(buf+29,80-29," - %xp (%x)",
+ 0x0FFF + (page[i]&0xFFFFFF00), j);
+ }
+ kprintf(buf);
+ }
+ }
+}
+
+void aspace_kprint(aspace_t *a)
+{
+ aspace_pprint(a->high,0x80000000);
+}
+
+void aspace_print(aspace_t *a)
+{
+ aspace_pprint(a->ptab,0);
+}
+
+aspace_t *aspace_create(void)
+{
+ int i;
+ uint32 phys0,phys1;
+ uint32 *raw0,*raw1;
+
+ aspace_t *a = kmalloc(aspace_t);
+ raw0 = kgetpage(&phys0);
+ raw1 = kgetpage(&phys1);
+ a->pdir = raw0;
+ a->ptab = raw1;
+ a->high = flat->high;
+ a->pdirphys = phys0;
+ list_init(&a->areas);
+
+ for(i=0;i<1024;i++){
+ a->pdir[i] = 0;
+ a->ptab[i] = 0;
+ }
+ a->pdir[0] = phys1 | 7;
+ a->pdir[512] = (_cr3 + 2*4096) | 3;
+ rsrc_bind(&a->rsrc, RSRC_ASPACE, kernel_team);
+ return a;
+}
+
+void aspace_protect(aspace_t *a, uint32 virt, uint32 flags)
+{
+ a->ptab[virt] = ((a->ptab[virt] & 0xFFFFF000) | (flags & 0x00000FFF));
+}
+
+void aspace_map(aspace_t *a, uint32 phys, uint32 virt, uint32 len, uint32 flags)
+{
+ int i;
+ for(i=0;i<len;i++){
+ a->ptab[virt+i] = (((phys+i)*4096) & 0xFFFFF000) |
+ (flags & 0x00000FFF);
+ local_flush_pte(0x1000*((virt)+i));
+ }
+}
+
+void aspace_maphi(aspace_t *a, uint32 phys, uint32 virt, uint32 len, uint32 flags)
+{
+ int i;
+ for(i=0;i<len;i++){
+ a->high[(virt&0x3FF)+i] = (phys+i)*4096 | flags;
+ local_flush_pte(0x1000*((virt)+i));
+ }
+
+}
+
+void aspace_clr(aspace_t *a, uint32 virt, uint32 len)
+{
+ int i;
+ for(i=0;i<len;i++){
+ a->ptab[virt+i] = 0;
+ }
+}
+
+void aspace_destroy(aspace_t *a)
+{
+ area_t *area;
+
+ /* tear down all attached areas */
+ while((area = (area_t*) list_peek_head(&a->areas))){
+ area_destroy(a, area->rsrc.id);
+ }
+
+ rsrc_release(&a->rsrc);
+ /* release page directory and table(s) */
+ kfreepage(a->pdir);
+ kfreepage(a->ptab);
+ kfree(aspace_t, a);
+}
+
+/* find a span of contig virtual pages */
+static int locate_span(aspace_t *a, uint32 start, uint32 len)
+{
+ uint32 *map = a->ptab;
+ uint32 found = 0;
+ uint32 foundat = 0;
+
+ /* default to 2mb line if unspec or invalid */
+ if((start < 1) || (start > 1023)) start = 512;
+
+ while((found < len) && (start < 1024)){
+ if(map[start]){
+ found = 0;
+ foundat = 0;
+ } else {
+ if(found == 0) foundat = start;
+ found++;
+ }
+ start++;
+ }
+ return foundat;
+}
+
+/* userland calls */
+int area_create(aspace_t *aspace, off_t size, off_t virt, void **addr, uint32 flags)
+{
+ int ppo,i,p=0,at;
+ area_t *area;
+ pagegroup_t *pg;
+ phys_page_t *pp;
+ size = (size & 0x0FFF) ? (size / 0x1000 + 1) : (size / 0x1000);
+
+ if(size < 1) size = 1;
+
+ if(flags & AREA_PHYSMAP) {
+ p = ((uint32) *addr) / 0x1000;
+ }
+
+ /* find a virtaddr */
+ if(!(at = locate_span(aspace, virt/0x1000, size))){
+ return ERR_MEMORY;
+ }
+
+ /* create a fresh pagegroup and enough phys_page_t's */
+ pg = (pagegroup_t *) kmalloc(pagegroup_t);
+ pg->flags = flags;
+ pg->refcount = 1;
+ pg->size = size;
+ pg->pages = NULL;
+ list_init(&pg->areas);
+ for(i=0;i<size;i+=6){
+ pp = (phys_page_t *) kmalloc(phys_page_t);
+ pp->refcount = 0;
+ pp->next = pg->pages;
+ pg->pages = pp;
+ };
+
+ /* create an area to ref the pagegroup */
+ area = (area_t *) kmalloc(area_t);
+ area->pgroup = pg;
+ area->virt_addr = at;
+ area->length = size;
+ area->maxlength = size;
+
+ /* link this area into the new pagegroup */
+ list_add_tail(&pg->areas, area);
+
+ /* link this area into the aspace's arealist */
+ list_add_tail(&aspace->areas, area);
+
+ /* check for valid ptr */
+ *addr = (void *) (at * 0x1000);
+
+ /* allocate pages, fill phys_page_t's, and map 'em */
+ for(ppo=0,pp=pg->pages,i=0;i<size;i++){
+ if(!(flags & AREA_PHYSMAP)) {
+ p = getpage();
+ }
+ aspace_map(aspace, p, at, 1, 7);
+ pp->addr[ppo] = p;
+ ppo++;
+ if(ppo == 6) {
+ ppo = 0;
+ pp = pp->next;
+ }
+ if(flags & AREA_PHYSMAP) p++;
+ at++;
+ }
+
+ /*
+ * zero extra space in last phys_page_t.
+ * careful, ppo == 0 and pp == NULL if size == 6.
+ */
+ while((ppo < 6) && (pp != NULL)){
+ pp->addr[ppo] = 0;
+ ppo++;
+ }
+
+ /* bind the resource and return the id */
+ rsrc_bind(&(area->rsrc), RSRC_AREA, current->rsrc.owner);
+ return area->rsrc.id;
+}
+
+int area_create_uber(off_t size, void *addr)
+{
+ int ppo,i,p,at=0;
+ area_t *area;
+ pagegroup_t *pg;
+ phys_page_t *pp;
+
+ size = (size & 0x0FFF) ? (size / 0x1000 + 1) : (size / 0x1000);
+ if(size < 1) size = 1;
+
+ p = ((uint32) addr) / 0x1000;
+
+ /* create a fresh pagegroup and enough phys_page_t's */
+ pg = (pagegroup_t *) kmalloc(pagegroup_t);
+ pg->flags = AREA_PHYSMAP;
+ pg->refcount = 1;
+ pg->size = size;
+ pg->pages = NULL;
+ list_init(&pg->areas);
+ for(i=0;i<size;i+=6){
+ pp = (phys_page_t *) kmalloc(phys_page_t);
+ pp->refcount = 0;
+ pp->next = pg->pages;
+ pg->pages = pp;
+ };
+
+ /* create an area to ref the pagegroup */
+ area = (area_t *) kmalloc(area_t);
+ area->pgroup = pg;
+ area->virt_addr = at;
+ area->length = size;
+ area->maxlength = size;
+
+ /* link this area into the new pagegroup */
+ list_add_tail(&pg->areas, area);
+
+ /* allocate pages, fill phys_page_t's, and map 'em */
+ for(ppo=0,pp=pg->pages,i=0;i<size;i++){
+ pp->addr[ppo] = p;
+ ppo++;
+ if(ppo == 6) {
+ ppo = 0;
+ pp = pp->next;
+ }
+ p++;
+ at++;
+ }
+
+ /*
+ * zero extra space in last phys_page_t.
+ * careful, ppo == 0 and pp == NULL if size == 6.
+ */
+ while((ppo < 6) && (pp != NULL)){
+ pp->addr[ppo] = 0;
+ ppo++;
+ }
+
+ /* bind the resource and return the id */
+ rsrc_bind(&(area->rsrc), RSRC_AREA, kernel_team);
+ return area->rsrc.id;
+}
+
+int area_clone(aspace_t *aspace, int area_id, off_t virt, void **addr, uint32 flags)
+{
+ area_t *area0, *area1;
+ uint32 at, size;
+ phys_page_t *pp;
+ int i,ppo;
+
+ /* make sure the area exists */
+ /* xxx : check perm */
+ if(!(area0 = rsrc_find_area(area_id))) return ERR_RESOURCE;
+
+ /* find virt space for it */
+ if(!(at = locate_span(aspace, virt/0x1000, area0->length))){
+ return ERR_MEMORY;
+ }
+
+
+/* xxx lock area1 and area1->pgroup */
+
+ /* allocate the clone area and init it from the orig */
+ area1 = (area_t *) kmalloc(area_t);
+ area0->pgroup->refcount++;
+ area1->pgroup = area0->pgroup;
+ size = area1->length = area0->length;
+ area1->maxlength = area0->maxlength;
+ area1->virt_addr = at;
+
+ /* link this area into the new pagegroup */
+ list_add_tail(&area0->pgroup->areas, area1);
+
+ /* link this area into the aspace's arealist */
+ list_add_tail(&aspace->areas, area1);
+
+ /* check for valid ptr */
+ *addr = (void *) (at * 0x1000);
+
+ /* map the phys_page_t's into the clone area */
+ for(ppo=0,i=0,pp=area1->pgroup->pages;i<size;i++){
+ aspace_map(aspace, pp->addr[ppo], at, 1, 7);
+ at++;
+ ppo++;
+ if(ppo == 6){
+ ppo = 0;
+ pp = pp->next;
+ }
+ }
+ /*
+ kprintf("area0 pgroup %x",area1->pgroup);
+ kprintf("area1 pgroup %x",area1->pgroup);
+ */
+ /* bind and return an id */
+ rsrc_bind(&(area1->rsrc), RSRC_AREA, current->rsrc.owner);
+// kprintf("area_clone(%d) -> %d",area_id,area1->rsrc.id);
+ return area1->rsrc.id;
+}
+
+int area_destroy(aspace_t *aspace, int area_id)
+{
+ area_t *area;
+ pagegroup_t *pg;
+
+ if(!(area = rsrc_find_area(area_id))) return ERR_RESOURCE;
+
+ /* find and unchain the area from its aspace -- complain if it is foreign */
+ if(list_remove(&aspace->areas, area)) return ERR_RESOURCE;
+
+ /* unmap the memory */
+ aspace_clr(aspace, area->virt_addr, area->length);
+
+ pg = area->pgroup;
+
+ /* remove this area from the pgroup's area list */
+ list_remove(&pg->areas, area);
+
+ /* decr the pagegroup refcount and tear it down if zero */
+ pg->refcount--;
+
+ if(pg->refcount == 0){
+ int release = !(pg->flags & AREA_PHYSMAP);
+ int count = 0;
+ phys_page_t *pp;
+
+ while((pp = pg->pages)){
+ pg->pages = pp->next;
+ if(release){
+ for(count=0;pg->size && (count < 6);count++){
+ putpage(pp->addr[count]);
+ pg->size--;
+ }
+ }
+ kfree(phys_page_t, pp);
+ }
+ kfree(pagegroup_t, pg);
+ }
+
+ rsrc_release(&area->rsrc);
+
+ kfree(area_t, area);
+ return ERR_NONE;
+}
+
+int area_resize(aspace_t *aspace, int area_id, off_t size)
+{
+ area_t *area;
+ pagegroup_t *pg;
+ int ppo;
+ phys_page_t *pp,*pp0;
+ uint32 at,p;
+
+ if(!(area = rsrc_find_area(area_id))) return ERR_RESOURCE;
+
+ pg = area->pgroup;
+ pp = area->pgroup->pages;
+
+// kprintf("area_resize(%x,%d,%d)",aspace,area_id,size);
+
+ if(size <= pg->size*0x1000) return 0;
+
+ size = size/0x1000 - pg->size; /* pages to add */
+
+// kprintf("area_resize: %x %x %x + %x",area,pg,pp,size);
+
+ at = locate_span(aspace, area->virt_addr + pg->size, size);
+ if(at != (area->virt_addr + pg->size)) {
+ kprintf("oops: cannot grow area (%x != %x)",at,area->virt_addr+pg->size);
+ return ERR_MEMORY;
+ }
+
+ while(pp->next) pp = pp->next;
+ ppo = pg->size % 6;
+
+ pg->size += size;
+ area->length += size;
+ area->maxlength += size;
+
+ while(size){
+ if(!ppo){
+ pp0 = (phys_page_t *) kmalloc(phys_page_t);
+ pp0->next = NULL;
+ pp->next = pp0;
+ pp0->refcount = 0;
+ pp = pp0;
+ }
+ p = getpage();
+ aspace_map(aspace, p, at, 1, 7);
+ pp->addr[ppo] = p;
+ at++;
+ ppo++;
+ if(ppo == 6) ppo = 0;
+ size--;
+ }
+
+ return 0;
+}
+
+
+
+
+
+
diff --git a/kernel/aspace.h b/kernel/aspace.h
@@ -0,0 +1,72 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _ASPACE_H_
+#define _ASPACE_H_
+
+#include "resource.h"
+#include "list.h"
+
+#define SEL_KCODE (1*8)
+#define SEL_KDATA (2*8)
+#define SEL_KDATA2 (3*8)
+#define SEL_UCODE (4*8)
+#define SEL_UDATA (5*8)
+#define SEL_KTSS (6*8)
+#define SEL_UTSS (7*8)
+
+typedef struct __phys_page_t {
+ struct __phys_page_t *next;
+ uint32 refcount;
+ uint32 addr[6];
+} phys_page_t; /* 32 bytes */
+
+typedef struct __pagegroup_t {
+ uint32 size; /* number of pages */
+ uint32 refcount; /* number of areamaps */
+ uint32 flags; /* page info */
+ list_t areas; /* areas sharing this pagegroup */
+ phys_page_t *pages; /* physical pages that compose this pagegroup */
+} pagegroup_t;
+
+struct __area_t {
+ resource_t rsrc;
+ pagegroup_t *pgroup;
+ uint32 virt_addr; /* virtual PAGE address */
+ uint32 length; /* length in pages */
+ uint32 maxlength; /* maxlength in pages */
+};
+
+struct __aspace_t {
+ resource_t rsrc;
+ list_t areas; /* list of mapped areas */
+ uint32 maxvirt; /* highest virt addr pagetabs maps */
+ /* platform specific */
+ uint32 *pdir; /* page directory -- 4k */
+ uint32 *ptab; /* page table -- 4k */
+ uint32 *high; /* high page table -- 4k (0x8000000 -> ) */
+ uint32 pdirphys; /* physical address of page directory */
+};
+
+
+aspace_t *aspace_create(void);
+void aspace_destroy(aspace_t *a);
+void aspace_map(aspace_t *a, uint32 phys, uint32 virt,
+ uint32 len, uint32 flags);
+void aspace_maphi(aspace_t *a, uint32 phys, uint32 virt,
+ uint32 len, uint32 flags);
+void aspace_clr(aspace_t *a, uint32 virt, uint32 len);
+void aspace_print(aspace_t *a);
+void aspace_protect(aspace_t *a, uint32 virt, uint32 flags);
+
+/* userland stuff */
+int area_create(aspace_t *aspace, off_t size, off_t virt, void **addr, uint32 flags);
+int area_create_uber(off_t size, void *addr);
+int area_destroy(aspace_t *aspace, int area_id);
+int area_clone(aspace_t *aspace, int area_id, off_t virt, void **addr, uint32 flags);
+int area_destroy(aspace_t *aspace, int area_id);
+int area_resize(aspace_t *aspace, int area_id, off_t size);
+
+
+#endif
diff --git a/kernel/cpuid.S b/kernel/cpuid.S
@@ -0,0 +1,43 @@
+/* $Id: //depot/blt/kernel/cpuid.S#3 $
+**
+** Copyright 1998 Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License.
+*/
+
+#include "smp.h"
+
+.section ".text.init"
+
+.globl smp_check_cpu
+
+smp_check_cpu:
+ #.byte 0x66
+ pushfl
+ #.byte 0x66
+ popl %eax
+ movl %eax, %ebx
+ andl $0x00200000, %eax
+ jz not_pentium_or_newer
+
+ xor %eax, %eax
+ cpuid
+ mov %eax, cpuid_max_level
+
+ cmp %ebx, CPUID_GEN_EBX
+ jne not_genuine_intel
+ cmp %ecx, CPUID_GEN_ECX
+ jne not_genuine_intel
+ cmp %edx, CPUID_GEN_EDX
+ jne not_genuine_intel
+
+ mov %eax, cpuid_eax
+ mov %edx, cpuid_edx
+ mov $1, %eax
+ ret
+
+not_pentium_or_newer:
+not_genuine_intel:
+ xor %eax, %eax
+ mov %ebx, %eax
+ ret
+
diff --git a/kernel/debug.c b/kernel/debug.c
@@ -0,0 +1,440 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef KDEBUG
+
+#include <i386/io.h>
+#include <blt/conio.h>
+
+#include <string.h>
+#include "kernel.h"
+#include "port.h"
+#include "rights.h"
+#include "resource.h"
+#include "list.h"
+#include "i386.h"
+
+extern list_t resource_list;
+
+#define RMAX 1024
+
+static char *tstate[] =
+{ "KERNL", "RUNNG", "READY", "DEAD ", "WAIT ", "S/IRQ", "S/TMR", "S/PAG" };
+
+uint32 readnum(const char *s);
+
+char *taskstate(task_t *task)
+{
+ static char ts[60];
+ if(task->waiting_on){
+ snprintf(ts,60,"Waiting on %s #%d \"%s\"",
+ rsrc_typename(task->waiting_on), task->waiting_on->id,
+ task->waiting_on->name);
+ return ts;
+ } else {
+ return "Running";
+ }
+}
+
+void printres(resource_t *r)
+{
+ switch(r->type){
+ case RSRC_PORT:
+ kprintf(" PORT %U: (slave=%d) (size=%d) \"%s\"",r->id,
+ ((port_t*)r)->slaved, ((port_t*)r)->msgcount,r->name);
+ break;
+ case RSRC_TASK:
+ kprintf(" TASK %U: \"%s\"",r->id,r->name);
+ kprintf(" : %s",taskstate((task_t*)r));
+ break;
+ case RSRC_ASPACE:
+ kprintf(" ASPACE %U: @ %x",r->id,((aspace_t*)r)->pdir[0]&0xFFFFF000);
+ break;
+ case RSRC_RIGHT:
+ kprintf(" RIGHT %U: %x",r->id,((right_t*)r)->flags);
+ break;
+ case RSRC_SEM:
+ kprintf(" SEM %U: (count=%d) \"%s\"",
+ r->id,((sem_t*)r)->count,r->name);
+ break;
+ case RSRC_AREA:
+ kprintf(" AREA %U: virt %x size %x pgroup %x (refcnt=%d)",r->id,
+ ((area_t*)r)->virt_addr * 0x1000, ((area_t*)r)->length * 0x1000,
+ ((area_t*)r)->pgroup, ((area_t*)r)->pgroup->refcount);
+ break;
+ case RSRC_QUEUE:
+ kprintf(" QUEUE %U: (count=%d) \"%s\"",r->id,r->queue.count,r->name);
+ break;
+ case RSRC_TEAM:
+ kprintf(" TEAM %U: \"%s\"",r->id,r->name);
+ break;
+ }
+}
+
+void dumprsrc(list_t *rl)
+{
+ node_t *rn = rl->next;
+ while(rn != (node_t*) rl) {
+ printres((resource_t*)rn->data);
+ rn = rn->next;
+ }
+}
+
+void dumponersrc(const char *num)
+{
+ int n;
+ node_t *rn;
+
+ n = readnum (num);
+ rn = resource_list.next;
+ while(rn != (node_t*) &resource_list) {
+ if (((resource_t*)rn->data)->id == n) {
+ printres((resource_t*) rn->data);
+ break;
+ } else {
+ rn = rn->next;
+ }
+ }
+}
+
+void dumptasks(void)
+{
+ int i,j,n;
+ task_t *t;
+ aspace_t *a;
+ team_t *team;
+
+ kprintf("Task Team Aspc State Wait esp scount Name");
+ kprintf("---- ---- ---- ----- ---- -------- -------- --------------------------------");
+
+ for(i=1;i<RMAX;i++){
+ if((t = rsrc_find_task(i))){
+ team = t->rsrc.owner;
+ a = team->aspace;
+ {
+ area_t *area = rsrc_find_area(t->rsrc.owner->heap_id);
+ if(area) j = area->virt_addr + area->length;
+ else j =0;
+ }
+
+ kprintf("%U %U %U %s %U %x %x %s",
+ i,team->rsrc.id,a->rsrc.id,tstate[t->flags],
+ (t->waiting_on ? t->waiting_on->id : 0),t->esp /*j*4096*/,t->scount,
+ t->rsrc.name);
+
+ }
+ }
+}
+
+
+void dumpports()
+{
+ int i;
+ port_t *p;
+
+ kprintf("Port Task Rstr Slav Size Owner Name");
+ kprintf("---- ---- ---- ---- ---- --------------------------------");
+
+ for(i=1;i<RMAX;i++){
+ if((p = rsrc_find_port(i))){
+ kprintf("%U %U %U %U %U %s",
+ i, p->rsrc.owner->rsrc.id, p->restrict, p->slaved,
+ p->msgcount, p->rsrc.owner->rsrc.name);
+ }
+ }
+
+}
+
+
+static void trace(uint32 ebp,uint32 eip)
+{
+ int f = 1;
+
+ kprintf("f# EBP EIP");
+ kprintf("00 xxxxxxxx %x",eip);
+ do {
+/* kprintf("%X %x %x",f,ebp, *((uint32*)ebp));*/
+ kprintf("%X %x %x",f,ebp+4, *((uint32*)(ebp+4)));
+ ebp = *((uint32*)ebp);
+ f++;
+ } while(ebp < 0x00400000 && ebp > 0x00200000);
+}
+
+
+static void dump(uint32 addr, int sections)
+{
+ int i;
+ unsigned char *x;
+
+ for(i=0;i<sections;i++){
+ x = (unsigned char *) (addr + 16*i);
+ kprintf("%x: %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X",
+ addr+16*i,x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],
+ x[8],x[9],x[10],x[11],x[12],x[13],x[14],x[15]);
+ }
+}
+
+static char *hex = "0123456789abcdef";
+
+#define atoi readhex
+uint32 readhex(const char *s)
+{
+ uint32 n=0;
+ char *x;
+ while(*s) {
+ x = hex;
+ while(*x) {
+ if(*x == *s){
+ n = n*16 + (x - hex);
+ break;
+ }
+ x++;
+ }
+ s++;
+ }
+ return n;
+}
+
+uint32 readnum(const char *s)
+{
+ uint32 n=0;
+ if((*s == '0') && (*(s+1) == 'x')) return readhex(s+2);
+ //while(isdigit(*s)) {
+ while(*s) {
+ n = n*10 + (*s - '0');
+ s++;
+ }
+ return n;
+}
+
+void reboot(void)
+{
+ i386lidt(0,0);
+ asm("int $0");
+}
+
+extern aspace_t *flat;
+
+void dumpaddr(int id)
+{
+ node_t *an;
+ area_t *area;
+ aspace_t *a = rsrc_find_aspace(id);
+
+ if(id == 0){
+ aspace_kprint(flat);
+ return;
+ }
+
+ if(!a) {
+ kprintf("no such aspace %d",id);
+ return;
+ }
+
+ aspace_print(a);
+ for(an = a->areas.next; an != (node_t *) &a->areas; an = an->next){
+ area = (area_t*) an->data;
+
+ kprintf("area %U virtaddr %x size %x pgroup %x (refcnt=%d)",
+ area->rsrc.id,
+ area->virt_addr * 0x1000,
+ area->length * 0x1000,
+ area->pgroup, area->pgroup->refcount);
+ }
+
+}
+
+void memory_status(void);
+void print_regs(regs *r, uint32 eip, uint32 cs, uint32 eflags);
+
+void dumpteams(void)
+{
+ node_t *rn = resource_list.next;
+ resource_t *rsrc;
+
+ while(rn != (node_t*) &resource_list) {
+ rsrc = (resource_t*)rn->data;
+ if(rsrc->type == RSRC_TEAM){
+ kprintf("Team %d (%s)",rsrc->id,rsrc->name);
+ }
+ rn = rn->next;
+ }
+}
+
+void dumpteam(int id)
+{
+ node_t *rn;
+
+ team_t *team = rsrc_find_team(id);
+ if(team){
+ kprintf("team %d (%s)...",team->rsrc.id,team->rsrc.name);
+ rn = team->resources.next;
+ while(rn != (node_t*) &team->resources) {
+ printres((resource_t*) rn->data);
+ rn = rn->next;
+ }
+ } else {
+ kprintf("no such team %d",id);
+ }
+
+}
+
+void dumpqueue(int num)
+{
+ resource_t *rsrc;
+ node_t *n;
+
+ int i;
+
+ for(i=1;i<RSRC_MAX;i++){
+ if(rsrc = rsrc_find(i,num)){
+ task_t *task;
+ kprintf("resource: %d \"%s\"",rsrc->id,rsrc->name);
+ kprintf("type : %s",rsrc_typename(rsrc));
+ if(rsrc->owner){
+ kprintf("owner : %d \"%s\"",
+ rsrc->owner->rsrc.id,rsrc->owner->rsrc.name);
+ }
+ kprintf("count : %d",rsrc->queue.count);
+
+ for(n = rsrc->queue.next; n != (node_t*) &rsrc->queue; n = n->next){
+ kprintf("queue : task %d \"%s\"",((task_t*)n->data)->rsrc.id,
+ ((task_t*)n->data)->rsrc.name);
+ }
+ return;
+ }
+ }
+ kprintf("no such resource %d",n);
+}
+
+static int ipchksum(unsigned short *ip, int len)
+{
+ unsigned long sum = 0;
+
+ len >>= 1;
+ while (len--) {
+ sum += *(ip++);
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ }
+ return((~sum) & 0x0000FFFF);
+}
+
+void checksum (char *range)
+{
+ char *s;
+ unsigned int i, good, begin, end;
+
+ if (!*range)
+ return;
+ for (i = good = 0; (i < strlen (range)) && !good; i++)
+ {
+ if (range[i] == ' ')
+ {
+ *(s = range + i) = 0;
+ s++;
+ good = 1;
+ }
+ }
+ if ((!good) || !*s)
+ return;
+ begin = atoi (range);
+ end = atoi (s);
+ kprintf ("%x", ipchksum ((unsigned short *) begin, end - begin));
+}
+
+static void dumppgroup(uint32 addr)
+{
+ pagegroup_t *pg = (pagegroup_t*) addr;
+ phys_page_t *pp = pg->pages;
+ node_t *an = pg->areas.next;
+ int size = pg->size;
+
+ kprintf("pgroup @ 0x%x rc=%d sz=%d",addr,pg->refcount,pg->size);
+ while(an != (node_t*) &pg->areas){
+ kprintf(" area @ 0x%x (id %d) (owner #%d \"%s\")",
+ an->data,((area_t*)an->data)->rsrc.id,
+ ((area_t*)an->data)->rsrc.owner->rsrc.id,
+ ((area_t*)an->data)->rsrc.owner->rsrc.name);
+ an = an->next;
+ }
+ while(size > 0){
+ kprintf(" pages %U %U %U %U %U %U",
+ pp->addr[0],pp->addr[1],pp->addr[2],
+ pp->addr[3],pp->addr[4],pp->addr[5]);
+ size -= 6;
+ pp = pp->next;
+ }
+}
+
+int findpage(uint32 n)
+{
+ node_t *rn = resource_list.next;
+ resource_t *rsrc;
+ int count = 0;
+ int size,i;
+
+ while(rn != (node_t*) &resource_list) {
+ rsrc = (resource_t*)rn->data;
+ if(rsrc->type == RSRC_AREA){
+ area_t *area = (area_t*) rsrc;
+ phys_page_t *pp = area->pgroup->pages;
+ size = area->pgroup->size;
+ while(size > 0){
+ for(i=0;i<6;i++,size--){
+ if(pp->addr[i] == n){
+ kprintf("area %U pgroup %x slot %d",rsrc->id,area->pgroup,i);
+ count ++;
+ }
+ }
+ pp = pp->next;
+ }
+ }
+ rn = rn->next;
+ }
+ return count;
+}
+
+static char linebuf[80];
+void k_debugger(regs *r,uint32 eip, uint32 cs, uint32 eflags)
+{
+ char *line;
+ uint32 n;
+
+ kprintf("OpenBLT Kernel Debugger");
+
+ for(;;){
+ krefresh();
+ line = kgetline(linebuf,80);
+
+ if(!strncmp(line,"pgroup ",7)) { dumppgroup(readnum(line+7)); continue; }
+ if(!strncmp(line,"resource ", 9)) { dumponersrc(line+9); continue; }
+ if(!strcmp(line,"resources")) { dumprsrc(&resource_list); continue; }
+ if(!strncmp(line,"queue ",6)) { dumpqueue(readnum(line+6)); continue; }
+ if(!strcmp(line,"tasks")) { dumptasks(); continue; }
+ if(!strcmp(line,"ports")) { dumpports(); continue; }
+ if(!strcmp(line,"memory")) { memory_status(); continue; }
+ if(!strcmp(line,"trace")) { trace(r->ebp,eip); continue; }
+ if(!strcmp(line,"regs")) { print_regs(r,eip,cs,eflags); continue; }
+ if(!strncmp(line,"dump ",5)) { dump(readnum(line+5),16); continue; }
+ if(!strncmp(line,"aspace ",7)) { dumpaddr(readnum(line+7)); continue; }
+ if(!strcmp(line,"reboot")) { reboot(); }
+ if(!strncmp(line,"checksum ",9)) { checksum(line+9); continue; }
+ if(!strncmp(line,"team ",5)) { dumpteam(readnum(line+5)); continue; }
+ if(!strncmp(line,"find ",5)) { findpage(readnum(line+5)); continue; }
+ if(!strcmp(line,"teams")) { dumpteams(); continue; }
+
+ if(!strcmp(line,"exit")) break;
+ if(!strcmp(line,"x")) break;
+ if(!strcmp(line,"c")) break;
+ }
+}
+
+void DEBUGGER(void)
+{
+ regs r;
+ k_debugger(&r, 0, 0, 0);
+}
+
+#endif
diff --git a/kernel/fault.c b/kernel/fault.c
@@ -0,0 +1,329 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <i386/io.h>
+#include "kernel.h"
+#include "memory.h"
+#include "smp.h"
+#include "init.h"
+#include "port.h"
+#include "task.h"
+#include "aspace.h"
+#include "resource.h"
+#include "pager.h"
+#include "i386.h"
+
+#define noHALT_ON_FAULT
+#define DEBUG_ON_FAULT
+#define noCRASH_ON_FAULT
+
+static char *etable[] = {
+ "Divide-by-zero",
+ "Debug Exception",
+ "NMI",
+ "Breakpoint",
+ "INTO",
+ "BOUNDS",
+ "Invalid Opcode",
+ "Device Not Available",
+ "Double-fault",
+ "Coprocessor segment overrun",
+ "Invalid TSS fault",
+ "Segment Not Present",
+ "Stack Exception",
+ "General Protection",
+ "Page Fault",
+ "*reserved*",
+ "Floating-point error",
+ "Alignment Check",
+ "Machine Check"
+};
+
+typedef void (*ehfunc)();
+
+static void __fault(uint32 number, regs r, uint32 eip, uint32 cs,
+ uint32 eflags);
+static void __faultE(uint32 number, regs r, uint32 error, uint32 eip, uint32 cs,
+ uint32 eflags);
+
+ehfunc ehfunctab[] =
+ { __fault, __fault, __fault, __fault,
+ __fault, __fault, __fault, __fault,
+ __faultE, __fault, __faultE, __faultE,
+ __faultE, __faultE, __faultE /*page_fault*/, __fault,
+ __fault, __fault, __fault };
+
+extern unsigned char *screen;
+
+task_t *irq_task_map[16];
+
+void k_debugger(regs *r, uint32 eip, uint32 cs, uint32 eflags);
+void terminate(void);
+
+void print_regs(regs *r, uint32 eip, uint32 cs, uint32 eflags)
+{
+ kprintf(" EAX = %x EBX = %x ECX = %x EDX = %x",
+ r->eax, r->ebx, r->ecx, r->edx);
+ kprintf(" EBP = %x ESP = %x ESI = %x EDI = %x",
+ r->ebp, r->esp, r->esi, r->edi);
+ kprintf("EFLAGS = %x CS = %x EIP = %x",
+ eflags, cs, eip);
+}
+
+void user_debug(regs *r, uint32 *eip, uint32 *eflags)
+{
+#if 1
+ return;
+#else
+ int src,p,sz;
+ task_t *t0;
+ uchar buf[16];
+ uint32 code;
+
+ p = port_create(0, "debug control");
+
+ /* wake all blocking objects */
+ while((t0 = list_detach_head(¤t->rsrc.queue))) task_wake(t0,ERR_RESOURCE);
+
+ kprintf("Waiting on debug control port (%d)... ",p);
+ current->team = kernel_team; // XXX hack
+
+ while((sz = port_recv(p, &src, buf, 16, &code)) >= 0){
+ }
+ kprintf("debug control error %d\n",sz);
+
+#endif
+}
+
+
+static void __faultE(uint32 number,
+ regs r, uint32 error,
+ uint32 eip, uint32 cs, uint32 eflags)
+{
+ uint32 _cr2, _cr3;
+
+ kprintf("");
+ kprintf("*** Exception 0x%X* (%s)",number,etable[number]);
+#ifdef __SMP__
+ if (smp_configured)
+ kprintf (" on cpu#%d", smp_my_cpu ());
+#endif
+ print_regs(&r, eip, cs, eflags);
+
+ asm("mov %%cr2, %0":"=r" (_cr2));
+ asm("mov %%cr3, %0":"=r" (_cr3));
+ kprintf(" cr2 = %x cr3 = %x error = %x",_cr2,_cr3,error);
+ kprintf("");
+ kprintf("Task %d (%s) crashed.",current->rsrc.id,current->rsrc.name);
+
+ if((cs & 0xFFF8) == SEL_UCODE) user_debug(&r, &eip, &eflags);
+
+#ifdef DEBUG_ON_FAULT
+ current->flags = tDEAD;
+ k_debugger(&r, eip, cs, eflags);
+#endif
+
+#ifdef HALT_ON_FAULT
+ asm("hlt");
+#endif
+
+ terminate();
+}
+
+static void __fault(uint32 number,
+ regs r,
+ uint32 eip, uint32 cs, uint32 eflags)
+{
+
+ kprintf("");
+ kprintf("*** Exception 0x%X (%s)",number,etable[number]);
+ print_regs(&r, eip, cs, eflags);
+
+ kprintf("");
+ kprintf("Task %d (%s) crashed.",current->rsrc.id,current->rsrc.name);
+
+ if((cs & 0xFFF8) == SEL_UCODE) user_debug(&r, &eip, &eflags);
+
+#ifdef DEBUG_ON_FAULT
+ if(number != 2){
+ current->flags = tDEAD;
+ }
+ k_debugger(&r, eip, cs, eflags);
+#endif
+#ifdef HALT_ON_FAULT
+ asm("hlt");
+#endif
+ if(number != 2){
+ terminate();
+ }
+}
+
+void irq_dispatch(regs r, uint32 number)
+{
+ mask_irq(number);
+ if(irq_task_map[number]){
+ if(irq_task_map[number]->flags == tSLEEP_IRQ){
+ preempt(irq_task_map[number],ERR_NONE);
+ }
+ }
+}
+
+int kernel_timer = 0;
+
+unsigned char x[] = { '-', '-', '\\', '\\', '|', '|', '/', '/' };
+
+void pulse (void)
+{
+#ifndef __SMP__
+ screen[0] = x[kernel_timer%8];
+ screen[1] = 7;
+#else
+ screen[smp_my_cpu () * 2] = x[kernel_timer%8];
+ screen[smp_my_cpu () * 2 + 1] = 7;
+#endif
+}
+
+void timer_irq(regs r, uint32 eip, uint32 cs, uint32 eflags)
+{
+ task_t *task;
+ kernel_timer++;
+
+ while((task = rsrc_queue_peek(timer_queue))){
+ if(task->wait_time <= kernel_timer){
+ task = rsrc_dequeue(timer_queue);
+ rsrc_enqueue(run_queue, task);
+ } else {
+ break;
+ }
+ }
+#ifdef PULSE
+ pulse ();
+#endif
+ swtch();
+}
+
+extern void __null_irq(void);
+extern void __timer_irq(void);
+extern void __kbd_irq(void);
+extern void __syscall(void);
+
+#define EX(n) extern void __ex##n(void);
+EX(0); EX(1); EX(2); EX(3); EX(4); EX(5); EX(6); EX(7); EX(8); EX(9);
+EX(10); EX(11); EX(12); EX(13); EX(14); EX(15); EX(16); EX(17); EX(18);
+
+#define IQ(n) extern void __irq##n(void);
+IQ(1); IQ(2); IQ(3); IQ(4); IQ(5); IQ(6); IQ(7); IQ(8); IQ(9);
+IQ(10); IQ(11); IQ(12); IQ(13); IQ(14); IQ(15);
+
+extern void __ipi_cf (void), __ipi_tlb (void), __ipi_pte (void),
+ __ipi_resched (void), __ipi_stop (void);
+
+static void set_irq(uint32 *IDT, int n, void *func)
+{
+ IDT[2*n+1] = (((uint32) func) & 0xFFFF0000) | 0x00008E00;
+ IDT[2*n] = (((uint32) func) & 0x0000FFFF) | (SEL_KCODE << 16);
+}
+
+static void set_irqU(uint32 *IDT, int n, void *func)
+{
+ IDT[2*n+1] = (((uint32) func) & 0xFFFF0000) | 0x00008E00 | 0x00006000;
+ IDT[2*n] = (((uint32) func) & 0x0000FFFF) | (SEL_KCODE << 16);
+}
+
+void __init__ init_idt(uint32 *IDT)
+{
+ int i;
+ for(i=0;i<16;i++) irq_task_map[i] = NULL;
+
+ set_irq(IDT,0x00,__ex0);
+ set_irq(IDT,0x01,__ex1);
+ set_irq(IDT,0x02,__ex2);
+ set_irq(IDT,0x03,__ex3);
+ set_irq(IDT,0x04,__ex4);
+ set_irq(IDT,0x05,__ex5);
+ set_irq(IDT,0x06,__ex6);
+ set_irq(IDT,0x07,__ex7);
+ set_irq(IDT,0x08,__ex8);
+ set_irq(IDT,0x09,__ex9);
+ set_irq(IDT,0x0A,__ex10);
+ set_irq(IDT,0x0B,__ex11);
+ set_irq(IDT,0x0C,__ex12);
+ set_irq(IDT,0x0D,__ex13);
+ set_irq(IDT,0x0E,__ex14);
+ set_irq(IDT,0x0F,__ex15);
+ set_irq(IDT,0x10,__ex16);
+ set_irq(IDT,0x11,__ex17);
+ set_irq(IDT,0x12,__ex18);
+
+ set_irqU(IDT,0x20,__syscall);
+
+ set_irq(IDT,0x30,__timer_irq);
+ set_irq(IDT,0x31,__irq1);
+ set_irq(IDT,0x32,__irq2);
+ set_irq(IDT,0x33,__irq3);
+ set_irq(IDT,0x34,__irq4);
+ set_irq(IDT,0x35,__irq5);
+ set_irq(IDT,0x36,__irq6);
+ set_irq(IDT,0x37,__irq7);
+ set_irq(IDT,0x38,__irq8);
+ set_irq(IDT,0x39,__irq9);
+ set_irq(IDT,0x3A,__irq10);
+ set_irq(IDT,0x3B,__irq11);
+ set_irq(IDT,0x3C,__irq12);
+ set_irq(IDT,0x3D,__irq13);
+ set_irq(IDT,0x3E,__irq14);
+ set_irq(IDT,0x3F,__irq15);
+
+#ifdef __SMP__
+ set_irq(IDT,0x40,__ipi_cf);
+ set_irq(IDT,0x41,__ipi_tlb);
+ set_irq(IDT,0x42,__ipi_pte);
+ set_irq(IDT,0x43,__ipi_resched);
+ set_irq(IDT,0x44,__ipi_stop);
+#endif
+
+ i386lidt((uint32) IDT, 0x3FF);
+
+ remap_irqs();
+ unmask_irq(0);
+ unmask_irq(2);
+}
+
+void restore_idt(void)
+{
+ unmap_irqs();
+ i386lidt(0,0x3FF);
+}
+
+
+#ifdef __SMP__
+void ipi_dispatch (regs r, uint32 number)
+{
+ unsigned int config;
+
+ kprintf ("cpu#%d got ipi %x", smp_my_cpu (), number);
+ apic_write (APIC_EOI, 0);
+ switch (number)
+ {
+ case IPI_CACHE_FLUSH:
+ asm ("wbinvd");
+ break;
+ case IPI_INV_TLB:
+ local_flush_tlb ();
+ break;
+ case IPI_INV_PTE:
+ local_flush_tlb (); /* FIXME */
+ break;
+ case IPI_INV_RESCHED:
+ break;
+ case IPI_STOP:
+ config = apic_read (APIC_LVTT);
+ apic_write (APIC_LVTT, config | 0x10000);
+ while (!smp_begun) ;
+ apic_write (APIC_LVTT, config);
+ break;
+ }
+}
+#endif
+
diff --git a/kernel/i386.c b/kernel/i386.c
@@ -0,0 +1,205 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Copyright 1998-1999, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include "types.h"
+#include "i386.h"
+#include <i386/io.h>
+
+void i386SetSegment(void *entry,
+ uint32 base, uint32 limit,
+ uint8 rights, uint8 gran)
+{
+ *((uint32 *) entry) = (limit & 0xFFFF) | ((base & 0xFFFF) << 16);
+
+ *((uint32 *) ( ((char *) entry) + 4 ) ) =
+ ((base & 0x00FF0000) >> 16) | (base & 0xFF000000) |
+ (rights << 8) | ((gran & 0xF0) << 16) |
+ ((limit & 0x000F000) << 4);
+}
+
+void i386SetTaskGate(void *entry, uint16 selector, uint8 rights)
+{
+ *((uint32 *) entry) = selector << 16;
+ *((uint32 *) ( ((char *) entry) + 4 ) ) = (0x05 | (rights & 0xF0)) << 8;
+}
+
+/* thanks to paul swanson for these... */
+
+void i386ltr(uint32 selector)
+{
+ __asm__ __volatile__ ("ltr %%ax": :"eax" (selector));
+}
+
+void i386lidt(uint32 base, uint32 limit)
+{
+ uint32 i[2];
+
+ i[0] = limit << 16;
+ i[1] = (uint32) base;
+ __asm__ __volatile__ ("lidt (%0)": :"p" (((char *) i)+2));
+}
+
+void i386lgdt(uint32 base, uint32 limit)
+{
+ uint32 i[2];
+
+ i[0] = limit << 16;
+ i[1] = base;
+ __asm__ __volatile__ ("lgdt (%0)": :"p" (((char *) i)+2));
+}
+
+uint32 *i386sgdt(uint32 *limit)
+{
+ uint32 gdtptr[2];
+ __asm__ __volatile__ ("sgdt (%0)": :"p" (((char *) gdtptr)+2));
+ *limit = gdtptr[0] >> 16;
+ return (uint32 *) gdtptr[1];
+}
+
+#if 0
+//#ifdef __SMP__
+
+void remap_irqs (void)
+{
+ unsigned int i, config;
+
+ for (i = 0; i < 16; i++)
+ {
+ config =
+ ioapic_write (IOAPIC_REDIR_TABLE + 2 * i, config);
+ config = 0xff << 24; /* logical destination address */
+ ioapic_write (IOAPIC_REDIR_TABLE + 2 * i + 1, config);
+ }
+}
+
+void unmap_irqs (void)
+{
+}
+
+void unmask_irq (int irq)
+{
+}
+
+void mask_irq (int irq)
+{
+}
+
+#else /* __SMP__ */
+
+#define PORTA0 0x20
+#define PORTB0 0x21
+#define PORTA1 0xA0
+#define PORTB1 0xA1
+
+void remap_irqs(void)
+{
+ outb_p(0x11, PORTA0);
+ outb_p(0x30, PORTB0);
+ outb_p(0x04, PORTB0);
+ outb_p(0x01, PORTB0);
+ outb_p(0xff, PORTB0);
+
+ outb_p(0x11, PORTA1);
+ outb_p(0x38, PORTB1);
+ outb_p(0x02, PORTB1);
+ outb_p(0x01, PORTB1);
+ outb_p(0xff, PORTB1);
+}
+
+void unmap_irqs(void)
+{
+ outb_p(0x11, PORTA0);
+ outb_p(0x08, PORTB0);
+ outb_p(0x04, PORTB0);
+ outb_p(0x01, PORTB0);
+ outb_p(0x00, PORTB0);
+
+ outb_p(0x11, PORTA1);
+ outb_p(0x70, PORTB1);
+ outb_p(0x02, PORTB1);
+ outb_p(0x01, PORTB1);
+ outb_p(0x00, PORTB1);
+}
+
+void unmask_irq(int irq)
+{
+ if(irq < 8)
+ outb((inb(PORTB0) & ~(1 << irq)), PORTB0);
+ else
+ outb((inb(PORTB1) & ~(1 << (irq-8))), PORTB1);
+}
+
+void mask_irq(int irq)
+{
+ if(irq < 8)
+ outb((inb(PORTB0) | (1 << irq)), PORTB0);
+ else
+ outb((inb(PORTB1) | (1 << (irq-8))), PORTB1);
+}
+
+#endif /* __SMP__ */
+
+static int PIT_COUNTER[2][3]={ { 0x40, 0x41, 0x42 },
+ { 0x48, 0x49, 0x4a } };
+static int PIT_CONTROL[2] = { 0x43, 0x4b };
+
+#define PIT_DOSRESET 1 // resert PIT to DOS condition
+#define PIT_IKU 2 // start preemptivlly multitasking
+
+void init_timer(void)
+{
+ outb(0x24,PIT_CONTROL[0]);
+ /* write to counter 0, binary, high byte, mode 2 */
+#if 0
+ outb(0x2f,PIT_COUNTER[0][0]);
+ /*0x2f00=12032 * .8380965us ~= 10.083ms*/
+#else
+ outb(0x0e,PIT_COUNTER[0][0]);
+ /*0x0e00=3584 * .8380965us ~= 3.004ms*/
+#endif
+}
+
+void cli (void)
+{
+ asm ("cli");
+}
+
+void sti (void)
+{
+ asm ("sti");
+}
+
+void local_flush_tlb (void)
+{
+ int junk;
+
+ asm ("mov %%cr3, %0 ; mov %0, %%cr3" : : "r" (junk));
+}
+
+void local_flush_pte (unsigned int addr)
+{
+#ifdef I386
+ local_flush_tlb ();
+#else
+ asm ("invlpg (%0)" : : "r" (addr));
+#endif
+}
+
+void p (unsigned char *lock)
+{
+ int res;
+
+ res = 1;
+ asm ("lock ; xchgb %1, %0" : "=m" (*lock), "=r" (res) : "1" (res) : "memory");
+ while (res)
+ asm ("lock ; xchgb %1, %0" : "=m" (*lock), "=r" (res) : "1" (res) :
+ "memory");
+}
+
+void v (unsigned char *lock)
+{
+ asm ("lock ; btrl $0, %0" : "=m" (*lock));
+}
+
diff --git a/kernel/i386.h b/kernel/i386.h
@@ -0,0 +1,76 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _I386_H
+#define _I386_H
+
+typedef struct
+{
+ uint16 link, __unused0;
+ uint32 esp0;
+ uint16 ss0, __unused1;
+ uint32 esp1;
+ uint16 ss1, __unused2;
+ uint32 esp2;
+ uint16 ss2, __unused3;
+ uint32 cr3,eip,eflags,eax,ecx,edx,ebx,esp,ebp,esi,edi;
+ uint16 es, __unused4;
+ uint16 cs, __unused5;
+ uint16 ss, __unused6;
+ uint16 ds, __unused7;
+ uint16 fs, __unused8;
+ uint16 gs, __unused9;
+ uint16 ldts, __unused10;
+ uint16 debugtrap, iomapbase;
+} TSS;
+
+typedef struct { uint32 edi, esi, ebp, esp, ebx, edx, ecx, eax; } regs;
+
+/* rights bits options */
+#define i386rPRESENT 0x80 /* segment is present */
+
+#define i386rDPL0 0x00
+#define i386rDPL1 0x20
+#define i386rDPL2 0x40
+#define i386rDPL3 0x60
+
+/* for Data/Code/TSS segments */
+#define i386rDATA 0x12 /* segment is data, read/write */
+#define i386rDATAro 0x10 /* segment is data, read only */
+#define i386rCODE 0x1A /* segment is code, read/exec */
+#define i386rCODExo 0x18 /* segment is code, read only */
+
+#define i386rTSS 0x09 /* segment is an i386 TSS */
+
+/* gran bits options */
+#define i386g4K 0x80 /* segment gran is 4K (else 1B) */
+#define i386g32BIT 0x40 /* segment default is 32bit (else 16bit) */
+#define i386gAVL 0x10 /* segment AVL is set */
+
+void i386SetSegment(void *entry,
+ uint32 base, uint32 limit,
+ uint8 rights, uint8 gran);
+void i386SetTaskGate(void *entry, uint16 selector, uint8 rights);
+
+void i386ltr(uint32 selector);
+void i386lidt(uint32 base, uint32 limit);
+void i386lgdt(uint32 base, uint32 limit);
+uint32 *i386sgdt(uint32 *limit);
+
+#define I386_PAGING_ON() asm("push %eax; mov %cr0, %eax; orl $0x80000000,%eax ; mov %eax, %cr0 ; pop %eax");
+#define I386_PAGING_OFF() asm("push %eax; mov %cr0, %eax; andl $0x7FFFFFFF,%eax ; mov %eax, %cr0 ; pop %eax");
+
+void unmap_irqs(void);
+void remap_irqs(void);
+void unmask_irq(int irq);
+void mask_irq(int irq);
+void init_timer(void);
+
+void cli (void);
+void sti (void);
+void local_flush_tlb (void);
+void local_flush_pte (unsigned int addr);
+
+#endif /* _I386_H */
+
diff --git a/kernel/init.h b/kernel/init.h
@@ -0,0 +1,33 @@
+/* Copyright 1998-1999, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _INIT_H_
+#define _INIT_H_
+
+/*
+ * Behold macros to place functions or variables in special elf sections. To
+ * use these jewels, write your functions like this
+ *
+ * void __init__ foo_init (int a, int b)
+ * {
+ * }
+ *
+ * and your function prototypes like this
+ *
+ * extern void foo_init (int a, int b) __init__;
+ *
+ * and your data like this
+ *
+ * static char *foo_stuff __initdata__ = "Foo rules the world.";
+ *
+ * At some point in the future, the .text.init and .data.init sections of the
+ * kernel may be discarded at the end of the kernel's initialisation to free
+ * up a bit of memory.
+ */
+
+#define __init__ __attribute__ ((__section__ (".text.init")))
+#define __initdata__ __attribute__ ((__section__ (".data.init")))
+
+#endif
+
diff --git a/kernel/jump.S b/kernel/jump.S
@@ -0,0 +1,208 @@
+/* $Id: //depot/blt/kernel/jump.S#8 $
+**
+** Copyright 1998 Brian Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License.
+*/
+
+#include "smp.h"
+
+.text
+.globl __syscall
+.globl __null_irq
+.globl __timer_irq
+.globl __kbd_irq
+.globl __ipi_cf
+.globl __ipi_tlb
+.globl __ipi_pte
+.globl __ipi_resched
+.globl __ipi_stop
+.globl ehfunctab
+
+__null_irq:
+ movb $32, %al
+ outb %al, $32
+ iret
+
+__syscall:
+ pusha
+ call syscall
+ popa
+ iret
+
+__timer_irq:
+ pusha
+#ifdef __SMP__
+ movb smp_configured, %al
+ cmpb $1, %al
+ je 1f
+#endif
+ movb $32, %al
+ outb %al, $32
+#ifdef __SMP__
+ jmp 2f
+1:
+ call apic_eoi
+#endif
+2:
+ call timer_irq
+ popa
+ iret
+
+#define FAULT(n) \
+.globl __ex##n ;\
+__ex##n: ;\
+ pusha ;\
+ push $n ;\
+ mov $(n * 4 + ehfunctab), %ebx ;\
+ mov (%ebx), %ebx ;\
+ call *%ebx ;\
+ add $4,%esp ;\
+ popa ;\
+ iret
+
+#define FAULTE(n) \
+.globl __ex##n ;\
+__ex##n: ;\
+ pusha ;\
+ push $n ;\
+ mov $(n * 4 + ehfunctab), %ebx ;\
+ mov (%ebx), %ebx ;\
+ call *%ebx ;\
+ add $4,%esp ;\
+ popa ;\
+ add $4,%esp ;\
+ iret
+
+FAULT(0)
+FAULT(1)
+FAULT(2)
+FAULT(3)
+FAULT(4)
+FAULT(5)
+FAULT(6)
+FAULT(7)
+FAULTE(8)
+FAULT(9)
+FAULTE(10)
+FAULTE(11)
+FAULTE(12)
+FAULTE(13)
+FAULTE(14)
+FAULT(15)
+FAULT(16)
+FAULT(17)
+FAULT(18)
+
+#define IRQ(n) \
+.globl __irq##n ;\
+__irq##n: ;\
+ push $n ;\
+ pusha ;\
+ call irq_dispatch ;\
+ movb $0x20, %al ;\
+ outb %al, $0x20 ;\
+ popa ;\
+ add $4,%esp ;\
+ iret
+
+#define IRQHI(n) \
+.globl __irq##n ;\
+__irq##n: ;\
+ push $n ;\
+ pusha ;\
+ call irq_dispatch ;\
+ movb $0x20, %al ;\
+ outb %al, $0xA0 ;\
+ movb $0x20, %al ;\
+ outb %al, $0x20 ;\
+ popa ;\
+ add $4,%esp ;\
+ iret
+
+IRQ(1)
+IRQ(2)
+IRQ(3)
+IRQ(4)
+IRQ(5)
+IRQ(6)
+IRQ(7)
+IRQHI(8)
+IRQHI(9)
+IRQHI(10)
+IRQHI(11)
+IRQHI(12)
+IRQHI(13)
+IRQHI(14)
+IRQHI(15)
+
+# From: Jeff Bush <jeff@be.com>
+
+;# 1. Stores necessary registers on old stack
+;# 2. Changes old stack pointer to reflect new offset
+;# 3. Change address space if necessary
+;# 4. Pops state off old stack
+;# 5. returns to address on old stack, resuming thread
+
+
+.globl _context_switch
+.globl thread_bootstrap
+.globl kthread_bootstrap
+
+_context_switch:
+ pushf
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ movl 24(%esp), %eax # Where to save stack pointer
+ movl %esp, (%eax) # Save old stack
+ movl 32(%esp), %eax # Get new PDBR
+ movl 28(%esp), %ebx # Get new stack loc
+
+ cmpl $0, %eax # Need to change addr. space?
+ je changed_pdbr # If parameter was zero, no
+ movl %eax, %cr3 # Change address space
+
+changed_pdbr: movl %ebx, %esp # switch to new stack
+ popl %ebx
+ popl %edi
+ popl %esi
+ popl %ebp
+ popf
+ ret
+
+thread_bootstrap:
+ iret
+
+kthread_bootstrap:
+ lret
+
+
+#ifdef __SMP__
+
+__ipi_cf:
+ pushl $0x40
+ jmp __ipi
+__ipi_tlb:
+ pushl $0x41
+ jmp __ipi
+__ipi_pte:
+ pushl $0x42
+ jmp __ipi
+__ipi_resched:
+ pushl $0x43
+ jmp __ipi
+__ipi_stop:
+ pushl $0x44
+ jmp __ipi
+
+__ipi:
+ pusha
+ call ipi_dispatch
+ call apic_eoi
+ popa
+ add $4, %esp
+ iret
+
+#endif
+
diff --git a/kernel/kernel.c b/kernel/kernel.c
@@ -0,0 +1,448 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <blt/os.h>
+#include "kernel.h"
+#include "memory.h"
+#include "boot.h"
+#include "port.h"
+
+#include <i386/io.h>
+#include <string.h>
+#include "resource.h"
+#include "aspace.h"
+#include "task.h"
+#include "smp.h"
+#include "team.h"
+#include "pager.h"
+
+void DEBUGGER(void);
+
+void restore_idt(void);
+void init_idt(char *idt);
+
+void _context_switch(uint32 *old_stack, uint32 new_stack, uint32 pdbr);
+
+aspace_t *flat = NULL;
+boot_dir *bdir = NULL;
+
+char *idt;
+char *gdt;
+char *gdt2;
+char *toppage;
+task_t *current;
+task_t *kernel;
+uint32 gdt2len;
+uint32 entry_ebp;
+uint32 _cr3;
+task_t *idle_task;
+int live_tasks = 0;
+
+resource_t *run_queue, *timer_queue, *reaper_queue;
+team_t *kernel_team = NULL;
+int reaper_sem;
+
+uint32 memsize; /* pages */
+uint32 memtotal;
+
+static int uberportnum = 0, uberareanum = 0;
+
+void destroy_kspace(void)
+{
+/* memory_status();*/
+
+ asm("mov %0, %%cr3"::"r" (_cr3)); /* insure we're in kernel map */
+ restore_idt();
+
+ i386lgdt((uint32)gdt2,gdt2len);
+ asm ("mov %0, %%esp; ret": :"r" (entry_ebp + 4));
+}
+
+void panic(char *reason)
+{
+ kprintf("");
+ kprintf("PANIC: %s",reason);
+ DEBUGGER();
+ asm("hlt");
+}
+
+void idler(void)
+{
+ for(;;){
+ asm("hlt");
+ }
+}
+
+void reaper(void)
+{
+ task_t *task;
+
+ asm("cli"); /* XXX race condition? */
+ for(;;){
+ sem_acquire(reaper_sem);
+ task = rsrc_dequeue(reaper_queue);
+// kprintf("reaper reclaiming thread #%d (%s)",task->rsrc.id,task->rsrc.name);
+ task_destroy(task);
+ }
+
+}
+
+static aspace_t _flat;
+static TSS *ktss;
+
+void init_kspace(int membottom)
+{
+ uint32 *raw;
+
+ /* there's an existing aspace at vaddr 0x803FD000 that was initialized
+ by the 2nd stage loader */
+ raw = (uint32 *) 0x803FD000;
+ flat = &_flat;
+ flat->pdir = raw;
+ flat->ptab = &raw[1024];
+ flat->high = &raw[2048];
+ memtotal = memsize;
+
+ memsize -= 3; /* three pages already in use */
+
+ memory_init(membottom, memsize);
+
+
+ toppage = (char *) kgetpages(3); /* kernel startup stack */
+ gdt = (char *) kgetpages(1);
+ rsrc_init(kgetpages(6),4096*6);
+
+
+ kernel = (task_t *) kmalloc(task_t);
+ ktss = (TSS *) kgetpages(1);
+ kernel->flags = tKERNEL;
+ kernel->rsrc.id = 0;
+ kernel->rsrc.owner = NULL;
+ list_init(&kernel->rsrc.rights);
+ list_init(&kernel->rsrc.queue);
+ current = kernel;
+
+ init_idt(idt = kgetpages(1)); /* init the new idt, save the old */
+ gdt2 = (void *) i386sgdt(&gdt2len); /* save the old gdt */
+
+ i386SetSegment(gdt + SEL_KCODE, /* #01 - 32bit DPL0 CODE */
+ 0, 0xFFFFF,
+ i386rPRESENT | i386rDPL0 | i386rCODE,
+ i386g4K | i386g32BIT);
+
+ i386SetSegment(gdt + SEL_KDATA, /* #02 - 32bit DPL0 DATA */
+ 0, 0xFFFFF,
+ i386rPRESENT | i386rDPL0 | i386rDATA,
+ i386g4K | i386g32BIT);
+
+ i386SetSegment(gdt + SEL_KDATA2, /* #02 - 32bit DPL0 DATA */
+ 0, 0xFFFFF,
+ i386rPRESENT | i386rDPL0 | i386rDATA,
+ i386g4K | i386g32BIT);
+
+ i386SetSegment(gdt + SEL_UCODE, /* #03 - 32bit DPL3 CODE */
+ 0, 0xFFFFF,
+ i386rPRESENT | i386rDPL3 | i386rCODE,
+ i386g4K | i386g32BIT);
+
+ i386SetSegment(gdt + SEL_UDATA, /* #04 - 32bit DPL3 DATA */
+ 0, 0xFFFFF,
+ i386rPRESENT | i386rDPL3 | i386rDATA,
+ i386g4K | i386g32BIT);
+
+ i386SetSegment(gdt + SEL_KTSS, /* #05 - DPL0 TSS (Kernel) */
+ (uint32) ktss, 104,
+ i386rPRESENT | i386rDPL0 | i386rTSS,
+ 0);
+
+ i386lgdt((uint32) gdt, 1024/8);
+
+ asm("mov %%cr3, %0":"=r" (_cr3));
+
+ /* setup the kernel TSS to insure that it's happy */
+ ktss->cs = SEL_KCODE;
+ ktss->ds = ktss->es = ktss->ss = ktss->fs = ktss->gs = SEL_KDATA;
+ ktss->ldts = ktss->debugtrap = ktss->iomapbase = 0;
+ ktss->cr3 = _cr3;
+ ktss->ss0 = SEL_KDATA;
+ ktss->esp1 = ktss->esp2 = ktss->ss1 = ktss->ss2 = 0;
+ i386ltr(SEL_KTSS);
+}
+
+/* current is running -- we want to throw it on the run queue and
+ transfer control to the preemptee */
+void preempt(task_t *task, int status)
+{
+ uint32 *savestack = &(current->esp);
+
+ /* current thread MUST be running, requeue it */
+ if(current != idle_task) rsrc_enqueue(run_queue, current);
+
+ TCHKMAGIC(task);
+ if(task == (task_t *)tDEAD) panic("The dead have returned!");
+
+ /* transfer control to the preemtee -- it had better not be on any queues */
+ current = task;
+ current->status = status;
+ current->flags = tRUNNING;
+ current->scount++;
+ ktss->esp0 = current->esp0;
+ if(*savestack != current->esp){
+ _context_switch(savestack, current->esp, current->cr3);
+ }
+}
+
+void swtch(void)
+{
+ /* current == running thread */
+ uint32 *savestack = &(current->esp);
+
+ /* fast path for the case of only one running thread */
+ if(!run_queue->queue.count && (current->flags == tRUNNING)) return;
+
+ if(current->flags == tRUNNING) {
+ if(current != idle_task) rsrc_enqueue(run_queue, current);
+ }
+
+ /* get the next candidate */
+ current = rsrc_dequeue(run_queue);
+
+ if(!current) {
+ if(live_tasks){
+ current = idle_task;
+ } else {
+ kprintf("");
+ kprintf("No runnable tasks. Exiting.");
+ destroy_kspace();
+ }
+ }
+
+ if(current->flags == tDEAD) panic("The dead have returned!");
+ TCHKMAGIC(current);
+
+ current->flags = tRUNNING;
+ current->scount++;
+ ktss->esp0 = current->esp0;
+ if(*savestack != current->esp){
+ _context_switch(savestack, current->esp, current->cr3);
+ }
+}
+
+task_t *new_thread(team_t *team, uint32 ip, int kernelspace)
+{
+ task_t *t;
+ int stack;
+ void *addr;
+ int i;
+
+ /* xxx this should be cleaner -- have a flag to area_create perhaps */
+ for(i=1023;i>0;i--){
+ if(!team->aspace->ptab[i]) break;
+ }
+ stack = area_create(team->aspace, 4096, i*4096, &addr, 0);
+ if(!stack) panic("cannot create a stack area. eek");
+
+ t = task_create(team, ip, i*4096+4092, kernelspace);
+ t->ustack = (void *) (i << 12);
+ t->stack_area = rsrc_find(RSRC_AREA,stack);
+ rsrc_bind(&t->rsrc, RSRC_TASK, team);
+ t->flags = tREADY;
+ if(!kernelspace) {
+ rsrc_enqueue(run_queue, t);
+ live_tasks++;
+ }
+
+ return t;
+}
+
+int brk(uint32 addr)
+{
+ aspace_t *a = current->rsrc.owner->aspace;
+ area_t *area = rsrc_find_area(current->rsrc.owner->heap_id);
+
+ if(area){
+// kprintf("brk addr %x thid %d",addr,current->rsrc.id);
+ return area_resize(a,current->rsrc.owner->heap_id,
+ 0x1000 + ((addr - area->virt_addr) & 0xFFFFF000));
+ }
+ return ERR_MEMORY;
+}
+
+/*
+ 0 = directory
+ 1 = bootstrap
+ 2 = kernel
+*/
+
+
+void go_kernel(void)
+{
+ task_t *t;
+ int i,len;
+ void *ptr,*phys;
+ port_t *uberport;
+ area_t *uberarea;
+ team_t *team;
+
+ for (i = 0, len = 1; (bdir->bd_entry[i].be_type != BE_TYPE_NONE); i++){
+ len += bdir->bd_entry[i].be_size;
+ }
+ len *= 0x1000;
+
+ uberport = rsrc_find_port(uberportnum = port_create(0,"uberport"));
+ uberarea = rsrc_find_area(uberareanum = area_create_uber(len,
+ (void *) 0x100000));
+ kprintf("uberport allocated with rid = %d",uberportnum);
+ kprintf("uberarea allocated with rid = %d",uberareanum);
+
+ kernel_team = team_create();
+ rsrc_set_name(&kernel_team->rsrc, "kernel team");
+
+ run_queue = rsrc_find_queue(queue_create("run queue",kernel_team));
+ reaper_queue = rsrc_find_queue(queue_create("reaper queue",kernel_team));
+ timer_queue = rsrc_find_queue(queue_create("timer queue",kernel_team));
+ rsrc_set_owner(&uberarea->rsrc,kernel_team);
+ rsrc_set_owner(&uberport->rsrc,kernel_team);
+
+ for(i=3;bdir->bd_entry[i].be_type;i++){
+ if(bdir->bd_entry[i].be_type != BE_TYPE_CODE) continue;
+
+ team = team_create();
+ t = new_thread(team, 0x1074 /*bdir->bd_entry[i].be_code_ventr*/, 0);
+ current = t;
+
+ phys = (void *) (bdir->bd_entry[i].be_offset*0x1000 + 0x100000);
+ team->text_area = area_create(team->aspace,bdir->bd_entry[i].be_size*0x1000,
+ 0x1000, &phys, AREA_PHYSMAP);
+ team->heap_id = area_create(team->aspace,0x2000,0x1000 + bdir->bd_entry[i].be_size*
+ 0x1000, &ptr, 0);
+
+ /* make the thread own it's address space */
+ /* rsrc_set_owner(&a->rsrc, t); */
+
+ if (!strcmp (bdir->bd_entry[i].be_name, "namer")) {
+ rsrc_set_owner(&uberport->rsrc, team);
+ }
+
+ rsrc_set_name(&t->rsrc,bdir->bd_entry[i].be_name);
+ rsrc_set_name(&team->rsrc,bdir->bd_entry[i].be_name);
+
+ kprintf("task %X @ 0x%x, size = 0x%x (%s)",t->rsrc.id,
+ bdir->bd_entry[i].be_offset*4096+0x100000,
+ bdir->bd_entry[i].be_size*4096,
+ t->rsrc.name);
+ }
+
+ kprintf("creating idler...");
+ idle_task = new_thread(kernel_team, (int) idler, 1);
+ rsrc_set_name((resource_t*)idle_task,"idler");
+
+ kprintf("creating grim reaper...");
+ current = new_thread(kernel_team, (int) reaper, 1);
+ rsrc_set_name((resource_t*)current,"grim reaper");
+ reaper_sem = sem_create(0,"death toll");
+ rsrc_enqueue(run_queue, current);
+ live_tasks++;
+
+ kprintf("creating pager...");
+ current = pager_task = new_thread(kernel_team, (int) pager, 1);
+ rsrc_set_name((resource_t*)current,"pager");
+ pager_port_no = port_create(0,"pager port");
+ pager_sem_no = sem_create(0, "pager sem");
+ rsrc_enqueue(run_queue, current);
+ live_tasks++;
+
+ rsrc_set_name((resource_t*)kernel,"kernel");
+
+#ifdef __SMP__
+ smp_init ();
+#endif
+
+// DEBUGGER();
+ kprintf("starting scheduler...");
+
+#ifdef __SMP__
+ if (smp_configured)
+ {
+ smp_final_setup ();
+ kprintf ("smp: signaling other processors");
+ smp_begin ();
+ }
+#endif
+
+ /*
+ * when the new vm stuffas are done, we can at this point discard any
+ * complete pages in the .text.init and .data.init sections of the kernel
+ * by zeroing them and adding them to the free physical page pool.
+ */
+
+ current = kernel;
+ current->flags = tDEAD;
+ current->waiting_on = NULL;
+ swtch();
+
+ kprintf("panic: returned from scheduler?");
+ asm("hlt");
+}
+
+struct _kinfo
+{
+ uint32 memsize;
+ uint32 entry_ebp;
+ boot_dir *bd;
+ unsigned char *params;
+} *kinfo = (struct _kinfo *) 0x80000000;
+
+const static char *copyright1 =
+ "OpenBLT Release I (built "__DATE__ ", " __TIME__ ")";
+const static char *copyright2 =
+ " Copyright (c) 1998-2000 The OpenBLT Dev. Team. All rights reserved.";
+
+void kmain(void)
+{
+ int n,len;
+ memsize = ((kinfo->memsize) / 4096) & ~0xff;
+ entry_ebp = kinfo->entry_ebp;
+ bdir = kinfo->bd;
+
+ for (n = 0, len = 1; (bdir->bd_entry[n].be_type != BE_TYPE_NONE); n++)
+ len += bdir->bd_entry[n].be_size;
+
+ init_timer();
+ init_kspace(256 + len + 16); /* bottom of kernel memory */
+
+ kprintf_init();
+#ifdef SERIAL
+ dprintf_init();
+#endif
+
+ kprintf("");
+ kprintf (copyright1);
+ kprintf (copyright2);
+ kprintf("");
+#ifdef DPRINTF
+ dprintf ("");
+ dprintf (copyright1);
+ dprintf (copyright2);
+ dprintf ("");
+ kprintf ("serial port is in dprintf mode");
+ dprintf ("serial port is in dprintf mode");
+ dprintf ("");
+#endif
+
+ kprintf("system memory 0x%x",memsize*4096);
+
+ n = ((uint32) toppage) + 4080;
+ asm("mov %0, %%esp"::"r" (n) );
+
+ n = SEL_UDATA | 3;
+ asm("pushl %0; popl %%ds"::"r" (n));
+ asm("pushl %0; popl %%es"::"r" (n));
+ asm("pushl %0; popl %%fs"::"r" (n));
+ asm("pushl %0; popl %%gs"::"r" (n));
+
+ kprintf("kernel space initialized");
+ go_kernel();
+}
+
diff --git a/kernel/kernel.h b/kernel/kernel.h
@@ -0,0 +1,53 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _KERNEL_H_
+#define _KERNEL_H_
+
+#include "types.h"
+#include "i386.h"
+#include "aspace.h"
+#include "task.h"
+#include "port.h"
+#include "sem.h"
+#include "team.h"
+
+#include <blt/types.h>
+#include <blt/error.h>
+
+void panic(char *reason);
+
+task_t *new_thread(team_t *team, uint32 ip, int kernel);
+
+int brk(uint32 addr);
+
+void destroy_kspace(void);
+
+/* debugger functions */
+void kprintf_init(void);
+void kprintf(const char *fmt, ...);
+char *kgetline(char *line, int maxlen);
+void krefresh(void);
+
+#ifdef SERIAL
+void dprintf_init(void);
+void dprintf(const char *fmt, ...);
+#endif
+
+void preempt(task_t *t, int status);
+void swtch(void);
+extern char *idt, *gdt;
+extern uint32 _cr3;
+
+extern int kernel_timer;
+
+extern task_t *current;
+extern resource_t *run_queue;
+extern resource_t *reaper_queue;
+extern resource_t *timer_queue;
+extern team_t *kernel_team;
+
+void user_debug(regs *r, uint32 *eip, uint32 *eflags);
+
+#endif
diff --git a/kernel/ktrace.c b/kernel/ktrace.c
@@ -0,0 +1,332 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+/* serial tracing */
+
+#include <stdarg.h>
+#include "memory.h"
+#include <i386/io.h>
+#include <blt/conio.h>
+#include "kernel.h"
+
+#define NULL ((void *) 0)
+
+#define com1 0x3f8
+#define com2 0x2f8
+
+#define combase com1
+
+char *kprintf_lock = 0;
+
+void va_snprintf(char *b, int l, const char *fmt, va_list pvar);
+
+/* catch bad configurations */
+#if defined (SERIAL_DEBUG) && defined (DPRINTF)
+#error cannot use both serial debugging and dprintf
+#endif
+
+#if (defined (SERIAL_DEBUG) || defined (DPRINTF)) && !defined (SERIAL) && !defined (PORT_E9)
+#error cannot use serial debugging or dprintf without serial port code
+#endif
+
+#ifdef PORT_E9
+/* Bochs has this special direct to console thing */
+
+void dprintf_init(void)
+{
+}
+
+static int ser_getc(void)
+{
+ for(;;) ;
+}
+
+static void ser_putc(int ch)
+{
+ while (!(inb(combase + 5) & 0x20));
+ outb((unsigned char) ch, 0xe9);
+}
+
+static void ser_puts(char *s)
+{
+ int t;
+ while(*s){
+ ser_putc(*s);
+ s++;
+ }
+}
+
+#endif
+
+#ifdef SERIAL
+
+void dprintf_init(void)
+{
+ outb(0, combase + 4);
+ outb(0, combase + 0);
+ outb(0x83, combase + 3);
+ outb(6, combase); /* 9600 bps, 8-N-1 */
+ outb(0, combase+1);
+ outb(0x03, combase + 3);
+}
+
+static int ser_getc(void)
+{
+ while (!(inb(combase + 5) & 0x01));
+ return inb(combase);
+}
+
+static void ser_putc(int ch)
+{
+ while (!(inb(combase + 5) & 0x20));
+ outb((unsigned char) ch, combase);
+}
+
+static void ser_puts(char *s)
+{
+ int t;
+ while(*s){
+ ser_putc(*s);
+ s++;
+ }
+}
+
+#endif
+
+#ifdef SERIAL_DEBUG
+void krefresh(void)
+{
+}
+
+unsigned char *screen = NULL;
+
+void kprintf_init(void)
+{
+ screen = (unsigned char *) kmappages(
+#ifdef MONO
+ 0xB0,
+#else
+ 0xB8,
+#endif
+ 2, 3);
+}
+
+char *kgetline(char *line, int len)
+{
+ char c;
+ int pos = 0;
+
+ ser_puts(": ");
+
+ for(;;){
+ switch(c = ser_getc()){
+ case 10:
+ case 13:
+ line[pos]=0;
+ ser_puts("\r\n");
+ return line;
+
+ case 8:
+ if(pos) {
+ pos--;
+ ser_puts("\b \b");
+ }
+ break;
+
+ case 27:
+ while(pos) {
+ pos--;
+ ser_puts("\b \b");
+ }
+ break;
+
+ default:
+ if((c >= ' ') && (c < 0x7f) && (pos < len-1)){
+ line[pos] = c;
+ pos++;
+ ser_putc(c);
+ }
+ }
+ }
+}
+
+static char Line[128];
+void kprintf(const char *fmt, ...)
+{
+ va_list pvar;
+ va_start(pvar,fmt);
+#ifdef __SMP__
+ p (&kprintf_lock);
+#endif
+ va_snprintf(Line,128,fmt,pvar);
+ Line[127]=0;
+ va_end(pvar);
+ ser_puts(Line);
+ ser_puts("\r\n");
+#ifdef __SMP__
+ v (&kprintf_lock);
+#endif
+}
+
+#else
+
+#define ESC 27
+#define BS 8
+#define TAB 9
+#define CR 13
+char ScanTable [] = {' ', ESC, '1', '2', '3', '4', '5', '6', '7', '8',
+ '9', '0', '-', '=', BS, TAB, 'q', 'w', 'e', 'r',
+ 't', 'y', 'u', 'i', 'o', 'p', '[', ']', CR, ' ',
+ 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ '\'', '~', ' ', '\\', 'z', 'x', 'c', 'v', 'b', 'n',
+ 'm', ',', '.', '/', ' ', ' ', ' ', ' ', ' '};
+char ShiftTable [] = {' ', ESC, '!', '@', '#', '$', '%', '^', '&', '*',
+ '(', ')', '_', '+', ' ', ' ', 'Q', 'W', 'E', 'R',
+ 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', CR, ' ',
+ 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+ '\"', '~', ' ', '|', 'Z', 'X', 'C', 'V', 'B', 'N',
+ 'M', '<', '>', '?', ' ', ' ', ' ', ' ', ' '};
+#define LSHIFT 42
+#define RSHIFT 54
+
+unsigned char *screen = NULL;
+static unsigned char vscreen[80*25*2];
+
+void *kmappages(int phys, int count, int flags);
+
+void kprintf_init()
+{
+ screen = (unsigned char *) kmappages(
+#ifdef MONO
+ 0xB0,
+#else
+ 0xB8,
+#endif
+ 2, 3);
+
+ con_start((uint32) vscreen);
+ con_attr(CON_YELLOW|0x08);
+ con_clear();
+}
+
+void krefresh(void)
+{
+ memcpy(screen,vscreen,80*25*2);
+}
+
+static char line[80];
+void kprintf(const char *fmt, ...)
+{
+ va_list pvar;
+ va_start(pvar,fmt);
+#ifdef __SMP__
+ p (&kprintf_lock);
+#endif
+ va_snprintf(line,80,fmt,pvar);
+ line[79] = 0;
+ va_end(pvar);
+ con_goto(0,24);
+ con_puts(line);
+ con_puts("\n");
+ memcpy(screen,vscreen,80*25*2);
+#ifdef __SMP__
+ v (&kprintf_lock);
+#endif
+}
+
+#ifdef DPRINTF
+
+void dprintf(const char *fmt, ...)
+{
+ va_list pvar;
+ va_start(pvar,fmt);
+#ifdef __SMP__
+ p (&kprintf_lock);
+#endif
+ va_snprintf(line,80,fmt,pvar);
+ line[79]=0;
+ va_end(pvar);
+ ser_puts(line);
+ ser_puts("\r\n");
+#ifdef __SMP__
+ v (&kprintf_lock);
+#endif
+}
+
+#endif
+
+void movecursor (int x, int y)
+{
+ int offset;
+
+ offset = 80 * y + x;
+ outb (0xe, 0x3d4);
+ outb (offset / 256, 0x3d5);
+ outb (0xf, 0x3d4);
+ outb (offset % 256, 0x3d5);
+}
+
+char *kgetline(char *line, int len)
+{
+ int i,lp,key;
+ int shift = 0;
+ if(len > 80) len = 80;
+
+ restart:
+ for(i=1;i<len-1;i++) line[i] = ' ';
+ line[0] = ':';
+ line[1] = ' ';
+ line[len-1] = 0;
+ lp = 2;
+
+ for(;;){
+ con_goto(0,24);
+ con_puts(line);
+ movecursor(lp,24);
+
+ memcpy(screen + (80*24*2), vscreen + (80*24*2), 160);
+ while(!(inb(0x64) & 0x01));
+ key = inb(0x60);
+ switch(key){
+ case LSHIFT:
+ case RSHIFT:
+ shift = 1;
+ break;
+ case LSHIFT | 0x80:
+ case RSHIFT | 0x80:
+ shift = 0;
+ break;
+ default:
+ if(key & 0x80){
+ /* break */
+ } else {
+ if(key < 59){
+ key = shift ? ShiftTable[key] : ScanTable[key];
+
+ switch(key){
+ case CR:
+ line[lp] = 0;
+ kprintf(line);
+ return line + 2;
+ case ESC:
+ goto restart;
+ case BS:
+ if(lp > 2){
+ lp--;
+ line[lp]=' ';
+ }
+ break;
+ default:
+ if(lp < len-1);
+ line[lp] = key;
+ lp++;
+ }
+
+ }
+ }
+ }
+ }
+}
+
+#endif
diff --git a/kernel/list.c b/kernel/list.c
@@ -0,0 +1,165 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include "list.h"
+#include "memory.h"
+
+#include <blt/error.h>
+
+void list_init(list_t *list)
+{
+ list->next = (node_t *) list;
+ list->prev = (node_t *) list;
+ list->count = 0;
+}
+
+void list_add_head(list_t *list, void *data)
+{
+ node_t *node = kmalloc(node_t);
+ node->data = data;
+ node->next = list->next;
+ node->next->prev = node;
+ node->prev = (node_t*) list;
+ list->next = node;
+ list->count++;
+}
+
+void list_add_tail(list_t *list, void *data)
+{
+ node_t *node = kmalloc(node_t);
+ node->data = data;
+ node->prev = list->prev;
+ node->prev->next = node;
+ node->next = (node_t*) list;
+ list->prev = node;
+ list->count++;
+}
+
+void *list_peek_head(list_t *list)
+{
+ if(list->next == (node_t*) list) {
+ return NULL;
+ } else {
+ return list->next->data;
+ }
+}
+
+void *list_peek_tail(list_t *list)
+{
+ if(list->prev == (node_t*) list) {
+ return NULL;
+ } else {
+ return list->prev->data;
+ }
+}
+
+void *list_remove_head(list_t *list)
+{
+ node_t *node = list->next;
+ void *data;
+
+ if(node == (node_t*) list){
+ return NULL;
+ } else {
+ data = node->data;
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ kfree(node_t, node);
+ list->count--;
+ return data;
+ }
+}
+
+void *list_remove_tail(list_t *list)
+{
+ node_t *node = list->prev;
+ void *data;
+
+ if(node == (node_t*) list){
+ return NULL;
+ } else {
+ data = node->data;
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ kfree(node_t, node);
+ list->count--;
+ return data;
+ }
+}
+
+int list_remove(list_t *list, void *data)
+{
+ node_t *node = list->next;
+ while(node != (node_t *) list){
+ if(node->data == data){
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+ kfree(node_t, node);
+ list->count--;
+ return ERR_NONE;
+ }
+ node = node->next;
+ }
+ return -1;
+}
+
+
+void list_attach_head(list_t *list, node_t *node)
+{
+ node->next = list->next;
+ node->next->prev = node;
+ node->prev = (node_t*) list;
+ list->next = node;
+ list->count++;
+}
+
+void list_attach_tail(list_t *list, node_t *node)
+{
+ node->prev = list->prev;
+ node->prev->next = node;
+ node->next = (node_t*) list;
+ list->prev = node;
+ list->count++;
+}
+
+void *list_detach_head(list_t *list)
+{
+ node_t *node = list->next;
+ if(node == (node_t*) list){
+ return NULL;
+ } else {
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ list->count--;
+ return node->data;
+ }
+}
+
+void *list_detach_tail(list_t *list)
+{
+ node_t *node = list->prev;
+ if(node == (node_t*) list){
+ return NULL;
+ } else {
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ list->count--;
+ return node->data;
+ }
+}
+
+int list_detach(list_t *list, void *data)
+{
+ node_t *node = list->next;
+ while(node != (node_t *) list){
+ if(node->data == data){
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+ list->count--;
+ return ERR_NONE;
+ }
+ node = node->next;
+ }
+ return -1;
+}
diff --git a/kernel/list.h b/kernel/list.h
@@ -0,0 +1,43 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _LIST_H
+#define _LIST_H
+
+#include "types.h"
+
+struct __list_t
+{
+ node_t *next; /* aka head */
+ node_t *prev; /* aka tail */
+ uint32 count;
+};
+
+/* generic or template dlinklist node */
+struct __node_t
+{
+ node_t *next;
+ node_t *prev;
+ void *data;
+};
+
+void list_init(list_t *list);
+
+/* these functions allocate and destroy node_t's to store the items */
+void list_add_head(list_t *list, void *data);
+void list_add_tail(list_t *list, void *data);
+void *list_peek_head(list_t *list);
+void *list_peek_tail(list_t *list);
+void *list_remove_head(list_t *list);
+void *list_remove_tail(list_t *list);
+int list_remove(list_t *list, void *data);
+
+/* these functions are for items that "own" the node_t */
+void list_attach_head(list_t *list, node_t *node);
+void list_attach_tail(list_t *list, node_t *node);
+void *list_detach_head(list_t *list);
+void *list_detach_tail(list_t *list);
+int list_detach(list_t *list, void *data);
+
+#endif
+\ No newline at end of file
diff --git a/kernel/memory.c b/kernel/memory.c
@@ -0,0 +1,302 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include "kernel.h"
+#include "memory.h"
+
+static unsigned char size_map[513] = {
+ KM16,
+
+ KM16, KM16, KM16, KM16, KM16, KM16, KM16, KM16,
+ KM16, KM16, KM16, KM16, KM16, KM16, KM16, KM16,
+
+ KM32, KM32, KM32, KM32, KM32, KM32, KM32, KM32,
+ KM32, KM32, KM32, KM32, KM32, KM32, KM32, KM32,
+
+ KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64,
+ KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64,
+ KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64,
+ KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64,
+
+ KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96,
+ KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96,
+ KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96,
+ KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96,
+
+ KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
+ KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
+ KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
+ KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
+
+ KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
+ KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
+ KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
+ KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
+ KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
+ KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
+ KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
+ KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192,
+
+ KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
+ KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
+ KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
+ KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
+ KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
+ KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
+ KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
+ KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
+};
+
+
+void *kmallocB(int size)
+{
+ if(size < 256) return kmallocP(size_map[size]);
+ panic("invalid kmallocB");
+}
+
+void kfreeB(int size, void *block)
+{
+ if(size < 256) return kfreeP(size_map[size],block);
+ panic("invalid kmallocB");
+}
+
+
+
+struct km_mnode
+{
+ struct km_mnode *next;
+};
+
+static struct _km_map
+{
+ int size;
+ int used_count;
+ int fresh_count;
+ int free_count;
+ struct km_mnode *free_chain;
+ void *fresh_chain;
+} km_map[KMMAX] = {
+ { 16, 0, 256, 0, NULL, NULL },
+ { 32, 0, 128, 0, NULL, NULL },
+ { 64, 0, 64, 0, NULL, NULL },
+ { 96, 0, 42, 0, NULL, NULL },
+ { 128, 0, 32, 0, NULL, NULL },
+ { 192, 0, 21, 0, NULL, NULL },
+ { 256, 0, 16, 0, NULL, NULL }
+};
+
+extern uint32 memsize;
+extern uint32 memtotal;
+
+static uint32 total_pages;
+static uint32 used_pages;
+
+void memory_status(void)
+{
+ int i;
+ int inuse = 0, allocated = 0;
+
+ kprintf("");
+ kprintf("size used free fresh");
+ for(i=0;i<KMMAX;i++){
+ kprintf("%U %U %U %U", km_map[i].size, km_map[i].used_count,
+ km_map[i].free_count, km_map[i].fresh_count);
+ inuse += km_map[i].size * km_map[i].used_count;
+ allocated += km_map[i].size *
+ (km_map[i].free_count+km_map[i].used_count+km_map[i].fresh_count);
+
+ }
+ inuse /= 1024;
+ allocated /= 1024;
+ kprintf("");
+ kprintf("%dkb allocated, %dkb in use",allocated,inuse);
+ kprintf("%d (of %d) pages in use",used_pages, total_pages);
+
+}
+
+
+/* kernel 'heap' is allocated top down ... top three pages used by the bootstrap */
+static uint32 nextmem = 0x80400000 - 4*4096;
+static node_t *freevpagelist = NULL;
+
+static uint32 *pagelist = NULL;
+static uint32 freepage = 0;
+
+extern aspace_t *flat;
+
+void putpage(uint32 number)
+{
+// kprintf("- %d",number);
+
+ pagelist[number] = freepage;
+ freepage = number;
+ used_pages--;
+}
+
+uint32 getpage(void)
+{
+ uint32 n = freepage;
+
+// kprintf("+ %d",n);
+
+ if(n){
+ freepage = pagelist[n];
+ } else {
+ panic("Out of physical memory");
+ }
+ used_pages++;
+ return n;
+}
+
+void kfreepage(void *vaddr)
+{
+ node_t *n;
+ int pageno;
+ int vpage = (((uint32)vaddr)/0x1000) & 0x3ff;
+
+ if(!flat->high[vpage]){
+ kprintf("vpage %d / %x unmapped already?!",vpage,vaddr);
+ DEBUGGER();
+ }
+
+ /* release the underlying page */
+ pageno = flat->high[vpage] / 0x1000;
+// kprintf("kfreepage(%x) high[%d] = %d",vaddr,vpage,pageno);
+ putpage( pageno );
+
+ flat->high[vpage] = 0;
+ local_flush_pte(vaddr);
+
+ /* stick it on the virtual page freelist */
+ n = kmalloc(node_t);
+ n->next = freevpagelist;
+ n->data = vaddr;
+ freevpagelist = n;
+}
+
+void *kgetpage(uint32 *phys)
+{
+ uint32 pg = getpage();
+ *phys = pg * 0x1000;
+
+ if(nextmem < 0x80050000) panic("kernel vspace exhausted");
+
+ if(freevpagelist){
+ node_t *n = freevpagelist;
+ void *page = n->data;
+ freevpagelist = n->next;
+ kfree(node_t, n);
+ if(flat->high[(((uint32)page)/0x1000) & 0x3ff]){
+ kprintf("page collision @ %x",page);
+ DEBUGGER();
+ }
+ aspace_maphi(flat, pg, (((uint32)page)/0x1000) , 1, 3);
+ return page;
+ } else {
+ nextmem -= 4096;
+ aspace_maphi(flat, pg, nextmem/0x1000, 1, 3);
+ return (void *) nextmem;
+ }
+}
+
+void *kgetpages(int count)
+{
+ if(count == 1){
+ uint32 phys;
+ return kgetpage(&phys);
+ } else {
+ int i,n;
+ nextmem -= 4096*count;
+ for(n=nextmem/0x1000,i=0;i<count;n++,i++){
+ aspace_maphi(flat, getpage(), n, 1, 3);
+ }
+ return (void *) nextmem;
+ }
+}
+
+/* map specific physical pages into kernel space, return virtaddr */
+void *kmappages(int phys, int count, int flags)
+{
+ nextmem -= 4096*count;
+ aspace_maphi(flat, phys, nextmem/0x1000, count, flags);
+ return (void *) nextmem;
+}
+
+void memory_init(uint32 bottom_page, uint32 top_page)
+{
+ int i,count;
+
+ /* we can track 1024 pages for every 4K of pagelist */
+ count = ((top_page - bottom_page) / 1024) + 1;
+
+ /* allocate the pagelist */
+ top_page -= count;
+ total_pages = 0;
+ used_pages = 0;
+
+ nextmem -= 4096*count;
+ pagelist = (uint32 *) nextmem;
+ aspace_maphi(flat, top_page, nextmem/0x1000, count, 3);
+
+ /* setup the pagelist */
+ freepage = 0;
+ for(i=top_page;i>=bottom_page;i--){
+ total_pages++;
+ pagelist[i] = freepage;
+ freepage = i;
+ }
+
+ /* setup the memory pools */
+ for(i=0;i<KMMAX;i++){
+ km_map[i].fresh_chain = kgetpages(1);
+ }
+}
+
+
+void *kmallocP(int size)
+{
+ struct _km_map *km;
+ void *block;
+ if(size >= KMMAX) panic("illegal size in kmalloc()");
+ km = &km_map[size];
+
+ km->used_count++;
+
+ if(km->free_chain) {
+ /* recycle free'd blocks if available */
+ km->free_count--;
+ block = (void *) km->free_chain;
+ km->free_chain = km->free_chain->next;
+ } else {
+ /* shave a new block off of the fresh page if
+ we can't recycle */
+ km->fresh_count--;
+ block = km->fresh_chain;
+
+ if(km->fresh_count){
+ /* still some left, just bump us to the next chunk */
+ km->fresh_chain = (void *)
+ (((char *) km->fresh_chain) + km->size);
+ } else {
+ /* gotta grab a new page */
+ km->fresh_count = 4096 / km->size;
+ km->fresh_chain = kgetpages(1);
+ }
+ }
+
+ return block;
+}
+
+void kfreeP(int size, void *block)
+{
+ struct _km_map *km;
+ if(size > KMMAX) panic("illegal size in kmalloc()");
+ km = &km_map[size];
+
+ km->free_count++;
+ km->used_count--;
+ ((struct km_mnode *) block)->next = km->free_chain;
+ km->free_chain = (struct km_mnode *) block;
+}
+
diff --git a/kernel/memory.h b/kernel/memory.h
@@ -0,0 +1,37 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _MEMORY_H_
+#define _MEMORY_H_
+
+#include "types.h"
+
+#define KM16 0
+#define KM32 1
+#define KM64 2
+#define KM96 3
+#define KM128 4
+#define KM192 5
+#define KM256 6
+#define KMMAX 7
+
+uint32 getpage(void); /* allocate a single physical page */
+void putpage(uint32); /* release a single physical page */
+
+void *kgetpage(uint32 *phys); /* allocate one page (and return phys addr) */
+void *kgetpages(int count); /* allocate count pages */
+void kfreepage(void *vaddr);
+void *kmallocP(int pool); /* allocate from pool (eg KM16, KM128, ...)*/
+void kfreeP(int pool, void *block); /* release back to pool */
+
+void *kmallocB(int size); /* allocate from appropriate pool for size */
+void kfreeB(int size, void *block); /* release back to appropriate pool */
+#define kmalloc(type) kmallocB(sizeof(type))
+#define kfree(type,ptr) kfreeB(sizeof(type),ptr)
+
+void memory_init(uint32 bottom, uint32 top); /* only call once - on kernel launch */
+void memory_status(void); /* dump memory usage information */
+
+#endif
+
diff --git a/kernel/pager.c b/kernel/pager.c
@@ -0,0 +1,93 @@
+/* $Id: //depot/blt/kernel/pager.c#3 $
+**
+** Copyright 2000, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include "kernel.h"
+#include "memory.h"
+#include "types.h"
+#include "sem.h"
+#include "list.h"
+#include "pager.h"
+
+int pager_port_no, pager_sem_no;
+task_t *pager_task;
+sem_t *pager_sem;
+list_t pager_queue;
+
+void terminate (void);
+void k_debugger (regs *r, uint32 eip, uint32 cs, uint32 eflags);
+
+void pager (void)
+{
+ pager_fault_t *fault;
+ list_t *list;
+ node_t *node;
+ area_t *area;
+
+ pager_sem = rsrc_find_sem (pager_sem_no);
+ list_init (&pager_queue);
+
+ for (;;)
+ {
+ sem_acquire (pager_sem_no);
+ fault = list_remove_head (&pager_queue);
+
+ kprintf ("pager: got paging request %d for vaddr %x", fault->op,
+ fault->vaddr);
+ list = &fault->task->team->aspace->areas;
+ node = list->next;
+ while (node->next != (node_t *) list)
+ {
+ area = node->data;
+ kprintf ("pager: checking %x+%x", area->virt_addr, area->length);
+ if (((fault->vaddr >> 12) >= area->virt_addr) &&
+ (fault->vaddr >> 12) < (area->virt_addr + area->length))
+ {
+ /* shouldn't happen yet */
+ kprintf ("pager: found it");
+ continue;
+ }
+ node = node->next;
+ }
+ kprintf ("pager: task %d (%s) SEGV: eip = %x, addr = %x",
+ fault->task->rsrc.id, fault->task->rsrc.name, fault->eip,
+ fault->vaddr);
+ task_wake (fault->task, ERR_SEGV);
+ }
+}
+
+void page_fault (uint32 number, regs r, uint32 error, uint32 eip, uint32 cs,
+ uint32 eflags)
+{
+ pager_fault_t *fault;
+
+ /* queue the paging request */
+ fault = kmalloc (pager_fault_t);
+ fault->op = 666;
+ asm ("mov %%cr2, %0" : "=r" (fault->vaddr));
+ fault->eip = eip;
+ fault->task = current;
+ list_add_tail (&pager_queue, fault);
+
+ /* wake up the kernel pager */
+ current->flags = tSLEEP_PAGING;
+ pager_sem->count++;
+ task_wake (pager_task, ERR_NONE); /* XXX: sem_release requeues us */
+ swtch ();
+
+ /* paging is done; check result */
+ if (current->status == ERR_SEGV) {
+ if((cs & 0xFFF8) == SEL_UCODE) {
+ user_debug(&r, &eip, &eflags);
+ } else {
+ kprintf("pf: cs = %x\n",cs& 0xfff8);
+ }
+
+ current->flags = tDEAD;
+ k_debugger (&r, eip, cs, eflags);
+ terminate ();
+ }
+}
+
diff --git a/kernel/pager.h b/kernel/pager.h
@@ -0,0 +1,27 @@
+/* $Id: //depot/blt/kernel/pager.h#2 $
+**
+** Copyright 1998-2000, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _PAGER_H_
+#define _PAGER_H_
+
+#include "i386.h"
+
+struct __pager_fault_t
+{
+ unsigned int op, vaddr, eip;
+ task_t *task;
+};
+
+extern int pager_port_no, pager_sem_no;
+extern task_t *pager_task;
+extern sem_t *pager_sem;
+
+void pager (void);
+void page_fault (uint32 number, regs r, uint32 error, uint32 eip, uint32 cs,
+ uint32 eflags);
+
+#endif
+
diff --git a/kernel/port.c b/kernel/port.c
@@ -0,0 +1,244 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include "kernel.h"
+#include "memory.h"
+#include "port.h"
+#include "resource.h"
+
+#define MAX_MSGCOUNT 16
+
+int snprintf (char *s, int len, char *fmt, ...);
+
+int port_create(int restrict, const char *name)
+{
+ port_t *p;
+ char qname[16];
+
+ /* create new port */
+ p = kmalloc(port_t);
+ p->sendqueue = kmalloc(resource_t);
+
+ p->msgcount = 0;
+ p->first = p->last = NULL;
+ p->slaved = 0;
+ p->refcount = 1;
+ p->nowait = 0;
+ p->restrict = restrict;
+
+ rsrc_bind(&p->rsrc, RSRC_PORT, current->rsrc.owner);
+ rsrc_bind(p->sendqueue, RSRC_QUEUE, current->rsrc.owner);
+ rsrc_set_name(&p->rsrc, name);
+ snprintf(qname,16,"port:%d",p->rsrc.id);
+ rsrc_set_name(p->sendqueue, name);
+ return p->rsrc.id;
+}
+
+int port_destroy(int port)
+{
+ port_t *p;
+ if(!(p = rsrc_find_port(port))) return ERR_RESOURCE;
+// if(p->rsrc.owner != current) return ERR_PERMISSION;
+
+ if(p->refcount == 1) {
+ /* destroy port */
+ rsrc_release(&p->rsrc);
+ rsrc_release(p->sendqueue);
+ kfree(resource_t,p->sendqueue);
+ kfree(port_t,p);
+ return ERR_NONE;
+ }
+
+ /* port is the master of one or more slaves */
+ return ERR_RESOURCE;
+}
+
+uint32 port_option(uint32 port, uint32 opt, uint32 arg)
+{
+ port_t *p;
+
+ if(!(p = rsrc_find_port(port))) return ERR_RESOURCE;
+ if(p->rsrc.owner != current->rsrc.owner) return ERR_PERMISSION;
+
+ if(opt == PORT_OPT_SETRESTRICT){
+ p->restrict = arg;
+ return ERR_NONE;
+ }
+
+ if(opt == PORT_OPT_SLAVE){
+ port_t *master;
+
+ if(arg){
+ /* arg == 0 will simply release the old master */
+
+ if(!(master = rsrc_find_port(arg))) return ERR_RESOURCE;
+ if(master->rsrc.owner != current->rsrc.owner) return ERR_PERMISSION;
+
+ /* indicate that our master has one more slave */
+ master->refcount++;
+ }
+
+ if(p->slaved){
+ /* change in slave status, deref our old master */
+ if(!(master = rsrc_find_port(p->slaved)))
+ panic("port_option(): master port not found?");
+
+ master->refcount--;
+ }
+ p->slaved = arg;
+ return ERR_NONE;
+ }
+
+ if (opt == PORT_OPT_NOWAIT) {
+ p->nowait = arg;
+ return ERR_NONE;
+ }
+
+ return ERR_PERMISSION;
+}
+
+static chain_t *msg_pool = NULL;
+
+
+int port_send(int src, int dst, void *msg, size_t size, uint32 code)
+{
+ int i;
+ message_t *m;
+ port_t *f,*p;
+
+ if(!(f = rsrc_find_port(src))) return ERR_SENDPORT;
+#if 0
+ if(f->rsrc.owner != current) {
+ task_t *t = current->rsrc.owner; /* XXX */
+ while(t){
+ if(t == f->rsrc.owner) break;
+ t = t->rsrc.owner;
+
+ }
+ if(!t) return ERR_PERMISSION;
+ }
+#endif
+ /* insure the port exists and we may send to it */
+ if(!(p = rsrc_find_port(dst))) return ERR_RECVPORT;
+/* if((p->restrict) &&
+ (p->restrict != src)) return ERR_PERMISSION; XXX */
+
+ /* are we slaved to a different port? */
+ if(p->slaved){
+ if(!(p = rsrc_find_port(p->slaved))) return ERR_RESOURCE;
+ if(p->slaved) return ERR_RESOURCE;
+/* if((p->restrict) &&
+ (p->restrict != src)) return ERR_PERMISSION; XXX */
+ }
+
+ while(p->msgcount >= MAX_MSGCOUNT){
+ int status;
+ if(p->nowait) return ERR_WOULD_BLOCK;
+ if((status = wait_on(p->sendqueue))) return status;
+ }
+
+ /* ignore invalid sizes/locations */
+ if( (((uint32) msg) > 0x400000) ||
+ (size > 4096)) return ERR_MEMORY;
+
+ m = kmalloc(message_t);
+
+ /* allocate a 4k page to carry the message. klunky... */
+ if(size < 256){
+ m->data = size ? kmallocB(size) : NULL;
+ } else {
+ if(msg_pool){
+ m->data = (void *) msg_pool;
+ msg_pool = (chain_t *) msg_pool->next;
+ } else {
+ m->data = kgetpages(1);
+ }
+ }
+
+ for(i=0;i<size;i++){
+ ((unsigned char *) m->data)[i] = *((unsigned char *) msg++);
+ }
+
+ m->from_port = src;
+ m->to_port = dst;
+ m->code = code;
+ m->size = size;
+ m->next = NULL;
+ if(p->last){
+ p->last->next = m;
+ } else {
+ p->first = m;
+ }
+ p->last = m;
+ p->msgcount++;
+
+
+ /* If a thread is sleeping on the destination, wake it up
+ */
+ if(p->slaved){
+ port_t *p0 = rsrc_find_port(p->slaved);
+ if(p0){
+ task_t *task = rsrc_dequeue(&p0->rsrc);
+ if(task) task_wake(task,ERR_NONE);
+ }
+ } else {
+ task_t *task = rsrc_dequeue(&p->rsrc);
+ if(task) task_wake(task,ERR_NONE);
+ }
+
+ return size;
+}
+
+/*int old_port_recv(int port, void *msg, int size, int *from)*/
+int port_recv(int dst, int *src, void *msg, size_t size, uint32 *code)
+{
+ int i;
+ message_t *m;
+ port_t *p;
+
+ /* insure the port exists and we may receive on it */
+ if(!(p = rsrc_find_port(dst))) return ERR_RECVPORT;
+#if 0
+ if(p->rsrc.owner != current) return ERR_PERMISSION;
+#endif
+
+ /* bounds check the message... should be more careful */
+ if((current->team != kernel_team) && (((uint32) msg) > 0x400000))
+ return ERR_MEMORY;
+
+ /* no messages -- sleep */
+ while(!p->msgcount) {
+ int status;
+ if (p->nowait) return ERR_WOULD_BLOCK;
+ if((status = wait_on(&p->rsrc))) return status;
+ }
+
+ m = p->first;
+ for(i=0;i<m->size && (i <size);i++){
+ *((unsigned char *) msg++) = ((unsigned char *) m->data)[i];
+ }
+ if(src) *src = m->from_port;
+ if(code) *code = m->code;
+ dst = m->to_port; // XXX
+
+ /* unchain from the head of the queue */
+ if(!(p->first = p->first->next)) p->last = NULL;
+
+ if(p->sendqueue->queue.count && (p->msgcount <= MAX_MSGCOUNT)) {
+ task_t *task = rsrc_dequeue (p->sendqueue);
+ if(task) task_wake(task, ERR_NONE);
+ }
+ p->msgcount--;
+
+ /* add to the freepool */
+ if(m->size < 256){
+ if(m->size) kfreeB(m->size,m->data);
+ } else {
+ ((chain_t *) m->data)->next = msg_pool;
+ msg_pool = ((chain_t *) m->data);
+ }
+ kfree(message_t,m);
+ return size < m->size ? size : m->size;
+}
+
diff --git a/kernel/port.h b/kernel/port.h
@@ -0,0 +1,50 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _PORT_H_
+#define _PORT_H_
+
+#include "resource.h"
+#include "types.h"
+
+#define PORT_OPT_NOWAIT 1
+#define PORT_OPT_SETRESTRICT 2
+#define PORT_OPT_SETDEFAULT 3
+#define PORT_OPT_SLAVE 4
+
+typedef struct __chain_t
+{
+ struct __chain_t *next;
+} chain_t;
+
+typedef struct __message_t {
+ struct __message_t *next;
+ uint32 size;
+ uint32 code;
+ int from_port;
+ int to_port;
+ void *data;
+} message_t;
+
+struct __port_t
+{
+ resource_t rsrc;
+
+ int msgcount; /* number of messages waiting in the queue */
+ int slaved; /* deliver my messages to a master port */
+ message_t *first; /* head of the queue */
+ message_t *last; /* tail of the queue */
+ int refcount; /* counts owner and any slaved ports */
+ int nowait; /* do we block on an empty queue? */
+ int restrict; /* is port public or private? */
+ resource_t *sendqueue;
+};
+
+int port_create(int restrict, const char *name);
+int port_destroy(int port);
+uint32 port_option(uint32 port, uint32 opt, uint32 arg);
+ssize_t port_send(int src, int dst, void *data, size_t len, uint32 code);
+ssize_t port_recv(int dst, int *src, void *data, size_t max, uint32 *code);
+
+#endif
diff --git a/kernel/resource.c b/kernel/resource.c
@@ -0,0 +1,183 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include "kernel.h"
+#include "memory.h"
+#include "resource.h"
+#include "team.h"
+
+typedef struct _rtab {
+ resource_t *resource;
+ int next;
+} rtab;
+
+static resource_t null_resource;
+
+static rtab *rmap;
+static uint32 rmax = 0;
+static uint32 rfree = 0;
+
+list_t resource_list;
+
+void rsrc_init(void *map, int size)
+{
+ int i;
+
+ list_init(&resource_list);
+
+ null_resource.id = 0;
+ null_resource.type = RSRC_NONE;
+ null_resource.owner = NULL;
+ list_init(&null_resource.rights);
+
+ rfree = 1;
+ rmax = size / sizeof(rtab);
+ rmap = (rtab *) map;
+ for(i = 0; i < rmax; i++) {
+ rmap[i].resource = &null_resource;
+ rmap[i].next = i+1;
+ }
+ rmap[rmax-1].next = 0;
+}
+
+void *rsrc_find(int type, int id)
+{
+ if((id < rmax) && (rmap[id].resource->type == type)) {
+ return rmap[id].resource;
+ } else {
+ return NULL;
+ }
+}
+
+void rsrc_set_owner(resource_t *r, team_t *owner)
+{
+ if(r->owner) list_remove(&r->owner->resources, r);
+ if(r->owner = owner) list_add_tail(&owner->resources, r);
+}
+
+int rsrc_identify(uint32 id)
+{
+ if((id >= rmax) || (rmap[id].resource->type == RSRC_NONE)) return 0;
+ return rmap[id].resource->owner->rsrc.id;
+}
+
+int queue_create(const char *name, team_t *team)
+{
+ resource_t *rsrc = (resource_t*) kmalloc(resource_t);
+ rsrc_bind(rsrc,RSRC_QUEUE,team);
+ rsrc_set_name(rsrc,name);
+ return rsrc->id;
+}
+
+void rsrc_bind(resource_t *rsrc, rsrc_type type, team_t *owner)
+{
+ uint32 id;
+
+ if(rfree){
+ id = rfree;
+ rfree = rmap[rfree].next;
+ } else {
+ panic("resource exhaustion");
+ }
+
+ rmap[id].resource = rsrc;
+ rsrc->id = id;
+ rsrc->type = type;
+ rsrc->owner = owner;
+ rsrc->name[0] = 0;
+
+ list_init(&rsrc->queue);
+ list_init(&rsrc->rights);
+
+ if(owner) list_add_tail(&owner->resources, rsrc);
+
+ list_add_tail(&resource_list, rsrc);
+}
+
+void rsrc_release(resource_t *r)
+{
+ uint32 id = r->id;
+ task_t *t;
+
+ /* unchain it from the owner */
+ if(r->owner) list_remove(&r->owner->resources, r);
+
+ /* unchain it from the global pool */
+ list_remove(&resource_list, r);
+
+ /* wake all blocking objects */
+ while((t = list_detach_head(&r->queue))) {
+ task_wake(t,ERR_RESOURCE);
+ }
+
+ r->type = RSRC_NONE;
+ r->id = 0;
+ rmap[id].resource = &null_resource;
+ rmap[id].next = rfree;
+ rfree = id;
+}
+
+void rsrc_set_name(resource_t *r, const char *name)
+{
+ if(name){
+ int i;
+ for(i=0;*name && (i<31);i++){
+ r->name[i] = *name;
+ name++;
+ }
+ r->name[i] = 0;
+ } else {
+ r->name[0] = 0;
+ }
+}
+
+void rsrc_enqueue_ordered(resource_t *rsrc, task_t *task, uint32 wake_time)
+{
+/* XXX fixme*/
+ list_attach_tail(&rsrc->queue, &task->node);
+ task->wait_time = wake_time;
+ task->flags = tWAITING;
+ task->waiting_on = rsrc;
+}
+
+void rsrc_enqueue(resource_t *rsrc, task_t *task)
+{
+ task->wait_time = 0;
+ task->flags = tWAITING;
+ task->waiting_on = rsrc;
+ list_attach_tail(&rsrc->queue,&task->node);
+}
+
+task_t *rsrc_dequeue(resource_t *rsrc)
+{
+ task_t *task = (task_t *) list_detach_head(&rsrc->queue);
+ if(task){
+ task->waiting_on = NULL;
+ task->flags = tREADY;
+ }
+ return task;
+}
+
+task_t *rsrc_queue_peek(resource_t *rsrc)
+{
+ if(rsrc->queue.next != (node_t*) &rsrc->queue) {
+ return (task_t*) rsrc->queue.next->data;
+ }
+}
+
+const char *rsrc_typename(resource_t *rsrc)
+{
+ switch(rsrc->type){
+ case RSRC_NONE: return "none";
+ case RSRC_TASK: return "task";
+ case RSRC_ASPACE: return "aspace";
+ case RSRC_PORT: return "port";
+ case RSRC_SEM: return "sem";
+ case RSRC_RIGHT: return "right";
+ case RSRC_AREA: return "area";
+ case RSRC_QUEUE: return "queue";
+ case RSRC_TEAM: return "team";
+ default: return "????";
+ }
+}
+\ No newline at end of file
diff --git a/kernel/resource.h b/kernel/resource.h
@@ -0,0 +1,66 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _RESOURCE_H_
+#define _RESOURCE_H_
+
+#include "types.h"
+#include "list.h"
+
+typedef enum
+{
+ RSRC_NONE, RSRC_TASK, RSRC_ASPACE, RSRC_PORT, RSRC_SEM, RSRC_RIGHT,
+ RSRC_AREA, RSRC_QUEUE, RSRC_TEAM, RSRC_MAX
+} rsrc_type;
+
+struct __resource_t
+{
+ uint32 id;
+ rsrc_type type;
+ team_t *owner;
+
+ list_t rights;
+ list_t queue;
+
+ char name[32];
+};
+
+
+/* initialize the resource map */
+void rsrc_init(void *map, int size);
+
+/* locate a specifically typed resource */
+void *rsrc_find(int type, int id);
+
+/* remove the resource from the table */
+void rsrc_release(resource_t *r);
+
+/* assign a portnumber and put it in the resource table */
+void rsrc_bind(resource_t *r, rsrc_type type, team_t *owner);
+
+void rsrc_set_owner(resource_t *r, team_t *owner);
+void rsrc_set_name(resource_t *r, const char *name);
+
+/* usercall - return the rsrc_id of the owner of the resource */
+int rsrc_identify(uint32 id);
+
+void rsrc_enqueue(resource_t *rsrc, task_t *task);
+void rsrc_enqueue_ordered(resource_t *rsrc, task_t *task, uint32 wake_time);
+task_t *rsrc_dequeue(resource_t *rsrc);
+const char *rsrc_typename(resource_t *rsrc);
+
+task_t *rsrc_queue_peek(resource_t *rsrc);
+
+#define rsrc_find_task(id) ((task_t *) rsrc_find(RSRC_TASK, id))
+#define rsrc_find_port(id) ((port_t *) rsrc_find(RSRC_PORT, id))
+#define rsrc_find_aspace(id) ((aspace_t *) rsrc_find(RSRC_ASPACE, id))
+#define rsrc_find_sem(id) ((sem_t *) rsrc_find(RSRC_SEM, id))
+#define rsrc_find_area(id) ((area_t *) rsrc_find(RSRC_AREA, id))
+#define rsrc_find_right(id) ((right_t *) rsrc_find(RSRC_RIGHT, id))
+#define rsrc_find_queue(id) ((resource_t *) rsrc_find(RSRC_QUEUE, id))
+#define rsrc_find_team(id) ((team_t *) rsrc_find(RSRC_TEAM, id))
+
+int queue_create(const char *name, team_t *team);
+
+#endif
diff --git a/kernel/rights.c b/kernel/rights.c
@@ -0,0 +1,29 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include "blt/error.h"
+#include "kernel.h"
+#include "resource.h"
+#include "rights.h"
+
+int right_create(uint32 rsrc_id, uint32 flags)
+{
+ return ERR_NONE;
+}
+
+int right_destroy(uint32 right_id)
+{
+ return ERR_NONE;
+}
+
+int right_revoke(uint32 right_id, uint32 thread_id)
+{
+ return ERR_NONE;
+}
+
+int right_grant(uint32 right_id, uint32 thread_id)
+{
+ return ERR_NONE;
+}
+
diff --git a/kernel/rights.h b/kernel/rights.h
@@ -0,0 +1,37 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _RIGHTS_H_
+#define _RIGHTS_H_
+
+#include "resource.h"
+
+#define RIGHT_PERM_READ 0x0001 /* allow 'read' access to something */
+#define RIGHT_PERM_WRITE 0x0002 /* allow 'write' access to something */
+#define RIGHT_PERM_DESTROY 0x0004 /* allow the something to be destroyed */
+#define RIGHT_PERM_ATTACH 0x0008 /* allows other rights to be attached */
+#define RIGHT_PERM_GRANT 0x0010 /* this right may be granted to another */
+ /* thread by a thread that is not the owner */
+#define RIGHT_MODE_INHERIT 0x0020 /* automatically granted to child */
+#define RIGHT_MODE_DISSOLVE 0x0040 /* When the owner thread terminates, */
+ /* the right is destroyed */
+
+int right_create(uint32 rsrc_id, uint32 flags);
+int right_destroy(uint32 right_id);
+int right_revoke(uint32 right_id, uint32 thread_id);
+int right_grant(uint32 right_id, uint32 thread_id);
+
+struct __right_t
+{
+ resource_t rsrc;
+
+ resource_t *attached;
+ uint32 flags;
+ uint32 refcount;
+ struct __tnode_t *holders;
+};
+
+
+
+#endif
+\ No newline at end of file
diff --git a/kernel/sem.c b/kernel/sem.c
@@ -0,0 +1,64 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include "kernel.h"
+#include "resource.h"
+#include "memory.h"
+
+int sem_create(int count, const char *name)
+{
+ sem_t *s = (sem_t *) kmalloc(sem_t);
+ s->count = count;
+ rsrc_bind(&s->rsrc, RSRC_SEM, current->rsrc.owner);
+ rsrc_set_name(&s->rsrc, name);
+ return s->rsrc.id;
+}
+
+int sem_destroy(int id)
+{
+ sem_t *s;
+ if(!(s = rsrc_find_sem(id))) {
+ return ERR_RESOURCE;
+ }
+ rsrc_release(&s->rsrc);
+ kfree(sem_t,s);
+ return ERR_NONE;
+}
+
+int sem_acquire(int id)
+{
+ int status;
+ sem_t *s;
+
+ if(!(s = rsrc_find_sem(id))) {
+ return ERR_RESOURCE;
+ }
+
+ if(s->count > 0 ){
+ s->count--;
+ } else {
+ s->count--;
+ if(status = wait_on(&s->rsrc)) return status;
+ }
+ return ERR_NONE;
+}
+
+int sem_release(int id)
+{
+ int x;
+ sem_t *s;
+ task_t *t;
+
+ if(!(s = rsrc_find_sem(id))) {
+ return ERR_RESOURCE;
+ }
+
+ s->count++;
+
+ if(t = rsrc_dequeue(&s->rsrc)){
+ preempt(t,ERR_NONE);
+ }
+
+ return ERR_NONE;
+}
diff --git a/kernel/sem.h b/kernel/sem.h
@@ -0,0 +1,22 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _SEM_H
+#define _SEM_H
+
+#include "resource.h"
+
+struct __sem_t
+{
+ resource_t rsrc;
+
+ int count;
+};
+
+int sem_create(int count, const char *name);
+int sem_destroy(int sem);
+int sem_acquire(int id);
+int sem_release(int id);
+
+#endif
diff --git a/kernel/smp.c b/kernel/smp.c
@@ -0,0 +1,583 @@
+/* $Id: //depot/blt/kernel/smp.c#6 $
+**
+** Copyright 1998 Sidney Cammeresi
+** All rights reserved.
+** Copyright (c) 1996, by Steve Passe
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "kernel.h"
+#include "i386/io.h"
+#include "init.h"
+#include "smp.h"
+
+#undef SMP_DEBUG
+
+#ifdef SMP_DEBUG
+#define SMP_PRINTF(f,a...) kprintf (f, ## a)
+#else
+#define SMP_PRINTF(f,a...)
+#endif
+
+const char *cpu_family[] __initdata__ = { "", "", "", "", "Intel 486",
+ "Intel Pentium", "Intel Pentium Pro", "Intel Pentium II" };
+const unsigned int temp_gdt[] = {0x00000000, 0x00000000, /* null descriptor */
+ 0x0000ffff, 0x00cf9a00, /* kernel text */
+ 0x0000ffff, 0x00cf9200 };/* kernel data */
+
+char mp_num_def_config, smp_num_cpus = 1, smp_num_running_cpus;
+volatile char smp_cpus_ready[BLT_MAX_CPUS], smp_configured = 0, smp_begun = 0;
+unsigned int cpuid_max_level, cpuid_eax, cpuid_edx, apic_addr,
+ cpu_apic_id[BLT_MAX_CPUS], cpu_os_id[BLT_MAX_CPUS],
+ cpu_apic_version[BLT_MAX_CPUS], *apic, *apic_virt, *ioapic;
+
+mp_flt_ptr *mp_config;
+
+extern aspace_t *flat;
+extern void (*flush) (void);
+
+volatile char ipi_lock = 0;
+
+volatile unsigned int apic_read (unsigned int *addr)
+{
+ return *addr;
+}
+
+void apic_write (unsigned int *addr, unsigned int data)
+{
+ *addr = data;
+}
+
+/* XXX - hack until we can figure this out */
+int bus_clock (void)
+{
+ return 66000000;
+}
+
+/********** adapted from FreeBSD's i386/i386/mpapic.c **********/
+
+void __init__ apic_set_timer (int value)
+{
+ unsigned long lvtt;
+ long ticks_per_us;
+
+ /* calculate divisor and count from value */
+ apic_write (APIC_TDCR, APIC_TDCR_1);
+ ticks_per_us = bus_clock () / 1000000;
+
+ /* configure timer as one-shot */
+ lvtt = apic_read (APIC_LVTT) & ~(APIC_LVTT_VECTOR | APIC_LVTT_DS |
+ APIC_LVTT_M | APIC_LVTT_TM) | APIC_LVTT_M | 0xff;
+ apic_write (APIC_LVTT, lvtt);
+ apic_write (APIC_ICRT, value * ticks_per_us);
+}
+
+/************************* end FreeBSD *************************/
+
+int apic_read_timer (void)
+{
+ return apic_read (APIC_CCRT);
+}
+
+void __init__ u_sleep (int count)
+{
+ int i;
+
+ apic_set_timer (count);
+ while (i = apic_read (APIC_CCRT)) ;
+}
+
+void __init__ mp_probe (int base, int limit)
+{
+ unsigned int i, *ptr;
+
+ for (ptr = (unsigned int *) base; (unsigned int) ptr < limit; ptr++)
+ if (*ptr == MP_FLT_SIGNATURE)
+ {
+ SMP_PRINTF ("smp: found floating pointer structure at %x", ptr);
+ mp_config = (mp_flt_ptr *) ptr;
+ return;
+ }
+}
+
+int __init__ mp_verify_data (void)
+{
+ char *ptr, total;
+ int i;
+
+ /* check signature */
+ if (mp_config->signature != MP_FLT_SIGNATURE)
+ return 0;
+
+ /* compute floating pointer structure checksum */
+ ptr = (unsigned char *) mp_config;
+ for (i = total = 0; i < (mp_config->mpc_len * 16); i++)
+ total += ptr[i];
+ if (total)
+ return 0;
+ kprintf ("smp: CHECKSUMMED");
+
+ /* compute mp configuration table checksum if we have one*/
+ if ((ptr = (unsigned char *) mp_config->mpc) != NULL)
+ {
+ for (i = total = 0; i < sizeof (mp_config_table); i++)
+ total += ptr[i];
+ if (total)
+ return 0;
+ }
+ else
+ kprintf ("smp: no configuration table\n");
+
+ return 1;
+}
+
+void __init__ mp_do_config (void)
+{
+ char *ptr;
+ int i;
+ mp_ext_pe *pe;
+ mp_ext_ioapic *io;
+
+ /*
+ * we are not running in standard configuration, so we have to look through
+ * all of the mp configuration table crap to figure out how many processors
+ * we have, where our apics are, etc.
+ */
+ smp_num_cpus = 0;
+
+ /* print out our new found configuration. */
+ ptr = (char *) &(mp_config->mpc->oem[0]);
+ kprintf ("smp: oem id: %c%c%c%c%c%c%c%c product id: "
+ "%c%c%c%c%c%c%c%c%c%c%c%c", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4],
+ ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12],
+ ptr[13], ptr[14], ptr[15], ptr[16], ptr[17], ptr[18], ptr[19],
+ ptr[20]);
+ SMP_PRINTF ("smp: base table has %d entries, extended section %d bytes",
+ mp_config->mpc->num_entries, mp_config->mpc->ext_len);
+ apic = (unsigned int *) mp_config->mpc->apic;
+
+ ptr = (char *) ((unsigned int) mp_config->mpc + sizeof (mp_config_table));
+ for (i = 0; i < mp_config->mpc->num_entries; i++)
+ switch (*ptr)
+ {
+ case MP_EXT_PE:
+ pe = (mp_ext_pe *) ptr;
+ cpu_apic_id[smp_num_cpus] = pe->apic_id;
+ cpu_os_id[pe->apic_id] = smp_num_cpus;
+ cpu_apic_version [smp_num_cpus] = pe->apic_version;
+ kprintf ("smp: cpu#%d: %s, apic id %d, version %d%s",
+ smp_num_cpus++, cpu_family[(pe->signature & 0xf00) >> 8],
+ pe->apic_id, pe->apic_version, (pe->cpu_flags & 0x2) ?
+ ", BSP" : "");
+ ptr += 20;
+ break;
+ case MP_EXT_BUS:
+ ptr += 8;
+ break;
+ case MP_EXT_IO_APIC:
+ io = (mp_ext_ioapic *) ptr;
+ ioapic = io->addr;
+ SMP_PRINTF ("smp: found io apic with apic id %d, version %d",
+ io->ioapic_id, io->ioapic_version);
+ ptr += 8;
+ break;
+ case MP_EXT_IO_INT:
+ ptr += 8;
+ break;
+ case MP_EXT_LOCAL_INT:
+ ptr += 8;
+ break;
+ }
+
+ kprintf ("smp: apic @ 0x%x, i/o apic @ 0x%x, total %d processors detected",
+ (unsigned int) apic, (unsigned int) ioapic, smp_num_cpus);
+}
+
+/* FIXME - this is a very long stretch that needs to be broken up. */
+void __init__ smp_init (void)
+{
+ unsigned char *ptr, init_val;
+ unsigned int i, j, config, num_startups, *new_stack, *dir, *table, *page,
+ *common;
+
+ SMP_PRINTF ("smp: initialising");
+ /*
+ * first let's check the kind of processor this is since only intel chips
+ * support the MP specification.
+ */
+#if 0
+ /* FIXME - this check doesn't work */
+ if (!smp_check_cpu ())
+ SMP_ERROR ("smp: processor is not Genuine Intel or is a 386 or 486\n");
+#else
+ j = smp_check_cpu ();
+ SMP_PRINTF ("smp: cpu is %x", j);
+#endif
+
+ /*
+ * scan the three spec-defined regions for the floating pointer
+ * structure. if we find one, copy its address into mp_config,
+ * otherwise, abort smp initialisation. after that, check the
+ * integrity of the structures.
+ */
+ mp_config = (mp_flt_ptr *) 0x1000; /* small hack */
+ /* mp_probe (0, 0x400); */
+ mp_probe (0x9fc00, 0xa0000);
+ mp_probe (0xf0000, 0x100000);
+ if (mp_config == (mp_flt_ptr *) 0x1000) /* if unchanged */
+ SMP_ERROR ("smp: no floating pointer structure detected\n");
+
+#if 0
+ /* FIXME - this check doesn't work */
+ if (!smp_verify_data ())
+ SMP_ERROR ("smp: bad configuration information\n");
+ kprintf ("smp: it's all good\n");
+#endif
+
+ /*
+ * whee, we're running on an smp machine with valid configuration
+ * information. print out some of this new intelligence.
+ */
+ kprintf ("smp: intel mp version %s, %s", (mp_config->mp_rev == 1) ? "1.1" :
+ "1.4", (mp_config->mp_feature_2 & 0x80) ?
+ "imcr and pic compatibility mode." : "virtual wire compatibility mode.");
+
+ if (!mp_config->mpc)
+ {
+ /* this system conforms to one of the default configurations */
+ mp_num_def_config = mp_config->mp_feature_1;
+ kprintf ("smp: standard configuration %d", mp_num_def_config);
+ smp_num_cpus = 2;
+ cpu_apic_id[0] = 0;
+ cpu_apic_id[1] = 1;
+ apic = (unsigned int *) 0xfee00000;
+ ioapic = (unsigned int *) 0xfec00000;
+ kprintf ("smp: WARNING: standard configuration code is untested");
+ else
+ {
+ /*
+ * we don't have a default configuration, so now we have to locate all
+ * of our hardware. boy, do we have a lot of work to do.
+ */
+ SMP_PRINTF ("smp: not a standard configuration");
+ mp_num_def_config = 0;
+ mp_do_config ();
+ }
+ smp_configured = 1;
+
+ /* set up the apic */
+ aspace_maphi (flat, 0xfee00, 0x3fc, 1, 0x13);
+ apic_virt = (unsigned int *) 0x803fc000;
+ asm ("mov %0, %%cr3" : : "r" (_cr3));
+
+ config = apic_read ((unsigned int *) APIC_SIVR) & APIC_FOCUS | APIC_ENABLE |
+ 0xff; /* set spurious interrupt vector to 0xff */
+ apic_write (APIC_SIVR, config);
+ config = apic_read (APIC_TPRI) & 0xffffff00; /* accept all interrupts */
+ apic_write (APIC_TPRI, config);
+
+ apic_read (APIC_SIVR);
+ apic_write (APIC_EOI, 0);
+
+ config = apic_read (APIC_LVT3) & 0xffffff00 | 0xfe; /* XXX - set vector */
+ apic_write (APIC_LVT3, config);
+
+ /* grab a page at 0x9000 for communicating with the aps */
+ aspace_map (flat, 0x9, 0x9, 1, 3);
+ common = (unsigned int *) 0x9000;
+ for (i = 0; i < 6; i++)
+ common [i + 1] = temp_gdt [i];
+ *((unsigned int *) 0x9024) = _cr3;
+ aspace_map (flat, 0xa, 0xa, 1, 3);
+ ptr = (unsigned char *) 0xa000;
+ for (j = 0; j < ((unsigned int) &trampoline_end - (unsigned int)
+ &trampoline + 1); j++)
+ ptr[j] = ((unsigned char *) &trampoline)[j];
+
+ /*
+ * okay, we're ready to go. boot all of the ap's now. we loop through
+ * using the kernel pe id numbers which were set up in smp_do_config ()
+ *
+ * XXX - we assume the bsp is the first detected. trying to boot it here
+ * would be, ahem, bad.
+ */
+ for (i = 1; i < smp_num_cpus; i++)
+ {
+ kprintf ("smp: booting cpu#%d with stack 0x%x", i, i * 0x1000);
+
+ /* map stacks and copy bootstrap code onto them */
+ aspace_map (flat, i, i, 1, 3);
+ ptr = (unsigned char *) (0x1000 * i);
+ for (j = 0; j < ((unsigned int) &trampoline_end - (unsigned int)
+ &trampoline + 1); j++)
+ ptr[j] = ((unsigned char *) &trampoline)[j];
+
+ /*
+ * modify the bootstrap code, specifically, the third highest order
+ * byte of the ljmp. we need to do this if we have more than two
+ * processors, i.e. more than one ap.
+ */
+ ptr = (char *) flush;
+ *(ptr - 5) = i << 4;
+
+ /* write the location of the stack into a fixed spot in memory */
+ *common = 0x1000 * i;
+
+ /* set shutdown code and warm reset vector */
+ ptr = (unsigned char *) 0xf;
+ *ptr = 0xa;
+ ptr = (unsigned char *) 0x467;
+ *ptr = 0x1000 * i;
+ ptr = (unsigned char *) 0x469;
+ *ptr = 0;
+
+ /* reset cpu ready bit */
+ smp_cpus_ready[i] = 0;
+
+ /* clear apic errors */
+ if (cpu_apic_version[i] & 0xf0)
+ {
+ apic_write (APIC_ESR, 0);
+ apic_read (APIC_ESR);
+ }
+
+ /* send (aka assert) INIT IPI */
+ SMP_PRINTF ("smp: asserting INIT");
+ config = apic_read (APIC_ICR2) & 0xf0ffffff | (cpu_apic_id[i] << 24);
+ apic_write (APIC_ICR2, config); /* set target pe */
+ config = apic_read (APIC_ICR1) & 0xfff0f800 | APIC_DM_INIT |
+ APIC_LEVEL_TRIG | APIC_ASSERT;
+ apic_write (APIC_ICR1, config);
+
+ /* deassert INIT */
+ SMP_PRINTF ("smp: deasserting INIT");
+ config = apic_read (APIC_ICR2) & 0xffffff | (cpu_apic_id[i] << 24);
+ apic_write (APIC_ICR2, config);
+ config = apic_read (APIC_ICR1) & ~0xcdfff | APIC_LEVEL_TRIG |
+ APIC_DM_INIT;
+
+ /* wait 10ms */
+ u_sleep (10000);
+
+ /* is this a local apic or an 82489dx ? */
+ num_startups = (cpu_apic_version[i] & 0xf0) ? 2 : 0;
+ for (j = 0; j < num_startups; j++)
+ {
+ /* it's a local apic, so send STARTUP IPIs */
+ SMP_PRINTF ("smp: sending STARTUP");
+ apic_write (APIC_ESR, 0);
+
+ /* set target pe */
+ config = apic_read (APIC_ICR2) & 0xf0ffffff | (cpu_apic_id[i] <<
+ 24);
+ apic_write (APIC_ICR2, config);
+
+ /* send the IPI */
+ config = apic_read (APIC_ICR1) & 0xfff0f800 | APIC_DM_STARTUP |
+ ((0x1000 * i) >> 12);
+ apic_write (APIC_ICR1, config);
+
+ /* wait */
+ u_sleep (200);
+ while (apic_read (APIC_ICR1) & 0x1000) ;
+ }
+
+ /* wait for processor to boot */
+ SMP_PRINTF ("smp: waiting for cpu#%d to come online", i);
+ apic_set_timer (5000000); /* 5 seconds */
+ while (apic_read_timer ())
+ if (smp_cpus_ready[i])
+ break;
+ if (!smp_cpus_ready[i])
+ kprintf ("smp: initialisation of cpu#%d failed", i);
+ }
+
+ /* this processor is already booted */
+ smp_cpus_ready[smp_my_cpu ()] = 1;
+
+ //ioapic_init ();
+ //apic_write (APIC_LVTT, 0x100fe);
+ //ipi_all_but_self (0x40);
+}
+
+void __init__ smp_cpu_setup (void)
+{
+ unsigned int config;
+
+ /* load the correct values into the idtr and gdtr */
+ i386lidt ((uint32) idt, 0x3ff);
+ i386lgdt ((uint32) gdt, 0x400 / 8);
+
+ /* set up the local apic */
+ config = apic_read ((unsigned int *) APIC_SIVR) & APIC_FOCUS | APIC_ENABLE |
+ 0xff; /* set spurious interrupt vector to 0xff */
+ apic_write (APIC_SIVR, config);
+ config = apic_read (APIC_TPRI) & 0xffffff00; /* accept all interrupts */
+ apic_write (APIC_TPRI, config);
+
+ apic_read (APIC_SIVR);
+ apic_write (APIC_EOI, 0);
+
+ config = apic_read (APIC_LVT3) & 0xffffff00; /* XXX - set vector */
+ apic_write (APIC_LVT3, config);
+}
+
+void __init__ smp_final_setup (void)
+{
+ unsigned int config, ticks_per_us;
+
+ ticks_per_us = bus_clock () / 1000000;
+ apic_write (APIC_ICRT, ticks_per_us * 10000); /* 10 ms */
+ config = 0x20030;
+ apic_write (APIC_LVTT, config);
+
+ if (smp_my_cpu ())
+ sti ();
+ else
+ mask_irq (0);
+}
+
+void __init__ smp_cpu_ready (void)
+{
+ /*
+ * C code entry point for aps. we finish initialisation and wait for the
+ * signal from the bsp before heading off into the wild blue yonder.
+ */
+
+ /* finish processor initialisation. */
+ smp_cpu_setup ();
+
+ /* inform the world of our presence. */
+ kprintf ("smp: cpu#%d is online", smp_my_cpu ());
+ smp_cpus_ready[smp_my_cpu ()] = 1;
+
+ /* wait for signal from bsp. */
+ while (!smp_begun) ;
+ kprintf ("smp: cpu#%d running", smp_my_cpu ());
+
+ /* set up local apic to generate timer interrupts. */
+ smp_final_setup ();
+
+ /* bon voyage. */
+ //swtch ();
+ while (1) ;
+}
+
+void __init__ smp_begin (void)
+{
+ /*
+ * begin smp. we set the begun bit to release the application processors
+ * out of their cages. they storm out, fly into the scheduler, and off
+ * we go.
+ */
+ smp_begun = 1;
+}
+
+int smp_my_cpu (void)
+{
+ if (!smp_configured)
+ return 0;
+ else
+ return cpu_os_id [(apic_read (APIC_ID) & 0xffffffff) >> 24];
+}
+
+void ipi_dest (int num, int pe)
+{
+ int config;
+
+ p (&ipi_lock);
+ cli ();
+ config = apic_read (APIC_ICR2) & 0xffffff | (pe << 24);
+ apic_write (APIC_ICR2, config);
+ config = apic_read (APIC_ICR1) & 0xfff0f800 | APIC_DEST_FIELD | num |
+ 0x4000;
+ apic_write (APIC_ICR1, config);
+ sti ();
+ v (&ipi_lock);
+}
+
+void ipi_self (int num)
+{
+ int config;
+
+ p (&ipi_lock);
+ cli ();
+ config = apic_read (APIC_ICR2) & 0xffffff;
+ apic_write (APIC_ICR2, config);
+ config = apic_read (APIC_ICR1) & ~0xfdfff | APIC_DEST_SELF | num;
+ apic_write (APIC_ICR1, config);
+ sti ();
+ v (&ipi_lock);
+}
+
+void ipi_all (int num)
+{
+ int config;
+
+ p (&ipi_lock);
+ cli ();
+ config = apic_read (APIC_ICR2) & 0xffffff;
+ apic_write (APIC_ICR2, config);
+ config = apic_read (APIC_ICR1) & ~0xfdfff | APIC_DEST_ALL | num;
+ apic_write (APIC_ICR1, config);
+ sti ();
+ v (&ipi_lock);
+}
+
+void ipi_all_but_self (int num)
+{
+ int config;
+
+ p (&ipi_lock);
+ cli ();
+ config = apic_read (APIC_ICR2) & 0xffffff;
+ apic_write (APIC_ICR2, config);
+ config = apic_read (APIC_ICR1) & ~0xfdfff | APIC_DEST_ALL_BUT_SELF | num;
+ apic_write (APIC_ICR1, config);
+ sti ();
+ v (&ipi_lock);
+}
+
+volatile unsigned int ioapic_read (unsigned int offset)
+{
+ *ioapic = offset;
+ return *(ioapic + 4); /* ioapic + 16 bytes */
+}
+
+void ioapic_write (unsigned int offset, unsigned int data)
+{
+ *ioapic = offset;
+ *(ioapic + 4) = data; /* ioapic + 16 bytes */
+}
+
+void ioapic_init (void)
+{
+}
+
+void apic_eoi (void)
+{
+ apic_write (APIC_EOI, 0);
+}
+
diff --git a/kernel/smp.h b/kernel/smp.h
@@ -0,0 +1,200 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _SMP_H_
+#define _SMP_H_
+
+#include <blt/os.h>
+
+#ifndef __SMP__
+# ifndef __SMP_ONLY__
+# define UP_OR_SMP(u,s) { u; }
+# else
+# error defined __SMP_ONLY__ without __SMP__
+# endif
+#else
+# if !defined (__SMP_ONLY__)
+# define UP_OR_SMP(u,s) if (!smp_configured) { u; } else { s; }
+# else
+# define UP_OR_SMP(u,s) { s; }
+# endif
+#endif
+
+#define CPUID_GEN_EBX 0x756e6547 /* Genu */
+#define CPUID_GEN_ECX 0x49656369 /* ineI */
+#define CPUID_GEN_EDX 0x6c65746e /* ntel */
+
+#define MP_FLT_SIGNATURE (('_' << 24) | ('P' << 16) | ('M' << 8) | ('_'))
+#define MP_CTH_SIGNATURE (('P' << 24) | ('C' << 16) | ('M' << 8) | ('P'))
+
+#define MP_DEF_LOCAL_APIC 0xfee00000 /* default local apic address */
+#define MP_DEF_IO_APIC 0xfec00000 /* default i/o apic address */
+
+#define APIC_DM_INIT (5 << 8)
+#define APIC_DM_STARTUP (6 << 8)
+#define APIC_LEVEL_TRIG (1 << 14)
+#define APIC_ASSERT (1 << 13)
+
+#define APIC_ENABLE 0x100
+#define APIC_FOCUS (~(1 << 9))
+#define APIC_SIV (0xff)
+
+#define MP_EXT_PE 0
+#define MP_EXT_BUS 1
+#define MP_EXT_IO_APIC 2
+#define MP_EXT_IO_INT 3
+#define MP_EXT_LOCAL_INT 4
+
+#define MP_EXT_PE_LEN 20
+#define MP_EXT_BUS_LEN 8
+#define MP_EXT_IO_APIC_LEN 8
+#define MP_EXT_IO_INT_LEN 8
+#define MP_EXT_LOCAL_INT_LEN 8
+
+#define SET_APIC_DEST(x) (x << 24)
+
+#ifndef __ASM__
+
+#include "kernel.h"
+
+extern unsigned int *apic, *apic_virt;
+
+#define SMP_ERROR(x) { kprintf (x); return; }
+
+#define APIC_ID ((unsigned int *) ((unsigned int) apic_virt + 0x020))
+#define APIC_VERSION ((unsigned int *) ((unsigned int) apic_virt + 0x030))
+#define APIC_TPRI ((unsigned int *) ((unsigned int) apic_virt + 0x080))
+#define APIC_EOI ((unsigned int *) ((unsigned int) apic_virt + 0x0b0))
+#define APIC_SIVR ((unsigned int *) ((unsigned int) apic_virt + 0x0f0))
+#define APIC_ESR ((unsigned int *) ((unsigned int) apic_virt + 0x280))
+#define APIC_ICR1 ((unsigned int *) ((unsigned int) apic_virt + 0x300))
+#define APIC_ICR2 ((unsigned int *) ((unsigned int) apic_virt + 0x310))
+#define APIC_LVTT ((unsigned int *) ((unsigned int) apic_virt + 0x320))
+#define APIC_LINT0 ((unsigned int *) ((unsigned int) apic_virt + 0x350))
+#define APIC_LVT3 ((unsigned int *) ((unsigned int) apic_virt + 0x370))
+#define APIC_ICRT ((unsigned int *) ((unsigned int) apic_virt + 0x380))
+#define APIC_CCRT ((unsigned int *) ((unsigned int) apic_virt + 0x390))
+#define APIC_TDCR ((unsigned int *) ((unsigned int) apic_virt + 0x3e0))
+
+#define APIC_TDCR_2 0x00
+#define APIC_TDCR_4 0x01
+#define APIC_TDCR_8 0x02
+#define APIC_TDCR_16 0x03
+#define APIC_TDCR_32 0x08
+#define APIC_TDCR_64 0x09
+#define APIC_TDCR_128 0x0a
+#define APIC_TDCR_1 0x0b
+
+#define APIC_LVTT_VECTOR 0x000000ff
+#define APIC_LVTT_DS 0x00001000
+#define APIC_LVTT_M 0x00010000
+#define APIC_LVTT_TM 0x00020000
+
+#define APIC_LVT_DM 0x00000700
+#define APIC_LVT_IIPP 0x00002000
+#define APIC_LVT_TM 0x00008000
+#define APIC_LVT_M 0x00010000
+#define APIC_LVT_OS 0x00020000
+
+#define APIC_TPR_PRIO 0x000000ff
+#define APIC_TPR_INT 0x000000f0
+#define APIC_TPR_SUB 0x0000000f
+
+#define APIC_SVR_SWEN 0x00000100
+#define APIC_SVR_FOCUS 0x00000200
+
+#define APIC_DEST_STARTUP 0x00600
+
+#define LOPRIO_LEVEL 0x00000010
+
+#define APIC_DEST_FIELD (0)
+#define APIC_DEST_SELF (1 << 18)
+#define APIC_DEST_ALL (2 << 18)
+#define APIC_DEST_ALL_BUT_SELF (3 << 18)
+
+#define IOAPIC_ID 0x0
+#define IOAPIC_VERSION 0x1
+#define IOAPIC_ARB 0x2
+#define IOAPIC_REDIR_TABLE 0x10
+
+#define IPI_CACHE_FLUSH 0x40
+#define IPI_INV_TLB 0x41
+#define IPI_INV_PTE 0x42
+#define IPI_INV_RESCHED 0x43
+#define IPI_STOP 0x44
+
+typedef struct
+{
+ unsigned int signature; /* "PCMP" */
+ unsigned short table_len; /* length of this structure */
+ unsigned char mp_rev; /* spec supported, 1 for 1.1 or 4 for 1.4 */
+ unsigned char checksum; /* checksum, all bytes add up to zero */
+ char oem[8]; /* oem identification, not null-terminated */
+ char product[12]; /* product name, not null-terminated */
+ void *oem_table_ptr; /* addr of oem-defined table, zero if none */
+ unsigned short oem_len; /* length of oem table */
+ unsigned short num_entries; /* number of entries in base table */
+ unsigned int apic; /* address of apic */
+ unsigned short ext_len; /* length of extended section */
+ unsigned char ext_checksum; /* checksum of extended table entries */
+} mp_config_table;
+
+typedef struct
+{
+ unsigned int signature; /* "_MP_" */
+ mp_config_table *mpc; /* address of mp configuration table */
+ unsigned char mpc_len; /* length of this structure in 16-byte units */
+ unsigned char mp_rev; /* spec supported, 1 for 1.1 or 4 for 1.4 */
+ unsigned char checksum; /* checksum, all bytes add up to zero */
+ unsigned char mp_feature_1; /* mp system configuration type if no mpc */
+ unsigned char mp_feature_2; /* imcrp */
+ unsigned char mp_feature_3, mp_feature_4, mp_feature_5; /* reserved */
+} mp_flt_ptr;
+
+typedef struct
+{
+ unsigned char type;
+ unsigned char apic_id;
+ unsigned char apic_version;
+ unsigned char cpu_flags;
+ unsigned int signature; /* stepping, model, family, each four bits */
+ unsigned int feature_flags;
+ unsigned int res1, res2;
+} mp_ext_pe;
+
+typedef struct
+{
+ unsigned char type;
+ unsigned char ioapic_id;
+ unsigned char ioapic_version;
+ unsigned char ioapic_flags;
+ unsigned int *addr;
+} mp_ext_ioapic;
+
+extern char smp_num_cpus, *trampoline, *trampoline_end;
+extern volatile char smp_configured, smp_begun;
+
+int smp_check_cpu (void);
+void smp_init (void);
+void smp_cpu_setup (void);
+void smp_cpu_ready (void);
+void smp_begin (void);
+void ioapic_init (void);
+
+/* these are more interesting functions for use by the rest of the kernel */
+
+int smp_my_cpu (void);
+
+void ipi_dest (int num, int pe);
+void ipi_self (int num);
+void ipi_all (int num);
+void ipi_all_but_self (int num);
+
+volatile unsigned int ioapic_read (unsigned int offset);
+void ioapic_write (unsigned int offset, unsigned int data);
+
+#endif /* __ASM__ */
+
+#endif /* __SMP__ */
+
diff --git a/kernel/stub.c b/kernel/stub.c
@@ -0,0 +1,30 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifdef __SMP__
+#include "smp.h"
+#endif
+
+void kmain(void);
+
+/*
+ * Our state here depends on how we got here. If we are called from the
+ * first stage bootstrap, we go into the kernel setup code. We can also
+ * arrive here executing on an application processor that has just completed
+ * its move into the wonderful world of protected mode. If this is the case,
+ * we jump into smp code to finish our setup and wait for word from the
+ * bootstrap processor.
+ */
+void _start(void)
+{
+#ifdef __SMP__
+ /* have we detected more processors yet? */
+ if (smp_num_cpus > 1)
+ smp_cpu_ready ();
+ else
+#endif
+ kmain();
+ /* not reached */
+}
+
diff --git a/kernel/syscall.c b/kernel/syscall.c
@@ -0,0 +1,279 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <i386/io.h>
+#include "kernel.h"
+#include "memory.h"
+#include "resource.h"
+#include "boot.h"
+#include "aspace.h"
+#include "task.h"
+#include "smp.h"
+#include "rights.h"
+
+#include <blt/syscall_id.h>
+
+extern task_t *irq_task_map[16];
+
+void k_debugger(regs *r, uint32 eip, uint32 cs, uint32 eflags);
+
+extern int live_tasks;
+extern int reaper_sem;
+
+extern boot_dir *bdir;
+
+/* HACK: sem_release will cause a reschedule which would not be good */
+void wake_the_reaper(void)
+{
+ task_t *task;
+ sem_t *sem = rsrc_find_sem(reaper_sem);
+ sem->count++;
+ if((task = rsrc_dequeue(&sem->rsrc)) != NULL) task_wake(task,ERR_NONE);
+}
+
+void terminate(void)
+{
+ task_t *t = current, *t0;
+
+ //kprintf("Task %X terminated.",current->rsrc.id);
+ live_tasks--;
+ rsrc_enqueue(reaper_queue,current);
+ current->flags = tDEAD;
+
+ /* wake all blocking objects */
+ while((t0 = list_detach_head(&t->rsrc.queue)) != NULL)
+ task_wake(t0,ERR_RESOURCE);
+
+ wake_the_reaper();
+
+ swtch();
+ kprintf("panic: HUH? Back from the dead? %x / %x",t,current);
+ asm("hlt");
+}
+
+void sleep(int ticks)
+{
+ /* convert from microseconds to 3ms ticks - round up slightly */
+ ticks = ((ticks + 2000) / 3000);
+
+ if(ticks) {
+ rsrc_enqueue_ordered(timer_queue, current, kernel_timer + ticks);
+ }
+ swtch();
+}
+
+#define p_uint32(n) (esp[n])
+#define p_int(n) ((int) esp[n])
+#define p_voidptr(n) ((void *) esp[n])
+#define p_charptr(n) ((char *) esp[n])
+#define p_sizet(n) ((size_t) esp[n])
+#define p_pint(n) ((int*) esp[n])
+#define p_puint32(n) ((uint32*) esp[n])
+
+#define res r.eax
+int metacall (volatile uint32 *esp);
+
+void syscall(regs r, volatile uint32 eip, uint32 cs, uint32 eflags,
+ volatile uint32 *esp)
+{
+#if 0
+ kprintf("* %d %x #%d@%x",current->rsrc.id,eip,r.eax,(uint32)esp);
+#endif
+
+ switch(r.eax){
+ case BLT_SYS_os_terminate :
+ terminate();
+ break;
+
+ case BLT_SYS_os_console :
+ kprintf("task %X> %s",current->rsrc.id,p_charptr(1));
+ break;
+
+ case BLT_SYS_os_brk :
+ res = brk(p_uint32(1));
+ break;
+
+ case BLT_SYS_os_handle_irq :
+ /* thread wants to listen to irq in eax */
+ if(p_uint32(1) > 0 && p_uint32(1) < 16) {
+ current->irq = p_uint32(1);
+ irq_task_map[p_uint32(1)] = current;
+ };
+
+ eflags |= 2<<12 | 2<<13;
+ break;
+
+ case BLT_SYS_os_sleep_irq :
+ if(current->irq){
+ /* sleep */
+ current->flags = tSLEEP_IRQ;
+ unmask_irq(current->irq);
+ }
+ swtch();
+ break;
+
+ case BLT_SYS_os_debug :
+#ifdef __SMP__
+ if (smp_configured)
+ {
+ config = apic_read (APIC_LVTT);
+ apic_write (APIC_LVTT, config | 0x10000);
+ smp_begun = 0;
+ ipi_all_but_self (IPI_STOP);
+ }
+#endif
+ k_debugger(&r, eip, cs, eflags);
+ kprintf("bye bye debugger");
+
+#ifdef __SMP__
+ if (smp_configured)
+ {
+ smp_begin ();
+ apic_write (APIC_LVTT, config);
+ }
+#endif
+ break;
+
+ case BLT_SYS_os_sleep :
+ sleep(p_uint32(1));
+ break;
+
+ case BLT_SYS_os_identify :
+ res = rsrc_identify(p_uint32(1));
+ break;
+
+ case BLT_SYS_os_meta :
+ res = metacall(esp);
+ break;
+
+ case BLT_SYS_sem_create :
+ res = sem_create(p_uint32(1),p_charptr(2));
+ break;
+
+ case BLT_SYS_sem_destroy :
+ res = sem_destroy(p_uint32(1));
+ break;
+
+ case BLT_SYS_sem_acquire :
+ res = sem_acquire(p_uint32(1));
+ break;
+
+ case BLT_SYS_sem_release :
+ res = sem_release(p_uint32(1));
+ break;
+
+ case BLT_SYS_port_create :
+ res = port_create(p_uint32(1),p_charptr(2));
+ break;
+
+ case BLT_SYS_port_destroy :
+ res = port_destroy(p_uint32(1));
+ break;
+
+ case BLT_SYS_port_option :
+ res = port_option(p_uint32(1), p_uint32(2), p_uint32(3));
+ break;
+
+ case BLT_SYS_port_send :
+ res = port_send(p_int(1), p_int(2), p_voidptr(3), p_sizet(4), p_uint32(5));
+ break;
+
+ case BLT_SYS_port_recv :
+ res = port_recv(p_int(1), p_pint(2), p_voidptr(3), p_sizet(4), p_puint32(5));
+ break;
+
+ case BLT_SYS_right_create :
+ res = right_create(p_uint32(1), p_uint32(1));
+ break;
+
+ case BLT_SYS_right_destroy :
+ res = right_destroy(p_uint32(1));
+ break;
+
+ case BLT_SYS_right_revoke :
+ res = right_revoke(p_uint32(1), p_uint32(2));
+ break;
+
+ case BLT_SYS_right_grant :
+ res = right_grant(p_uint32(1), p_uint32(2));
+ break;
+
+ case BLT_SYS_area_create :
+ res = area_create(current->rsrc.owner->aspace, p_uint32(1), p_uint32(2), (void **)p_voidptr(3), p_uint32(4));
+ break;
+
+ case BLT_SYS_area_clone :
+ res = area_clone(current->rsrc.owner->aspace, p_uint32(1), p_uint32(2), (void **)p_voidptr(3), p_uint32(4));
+ break;
+
+ case BLT_SYS_area_destroy :
+ res = area_destroy(current->rsrc.owner->aspace, p_uint32(1));
+ break;
+
+ case BLT_SYS_area_resize :
+ res = area_resize(current->rsrc.owner->aspace, p_uint32(1), p_uint32(2));
+ break;
+
+ case BLT_SYS_thr_create : {
+ char *name;
+ int i;
+ task_t *t;
+ t = new_thread(current->rsrc.owner, p_uint32(1), 0);
+ if(t) {
+ *((unsigned int *) (t->ustack + 0xfec)) = p_uint32(2);
+ name = p_charptr(3);
+ if (name == NULL)
+ {
+ for(i=0;current->rsrc.name[i] && i<31;i++) {
+ t->rsrc.name[i] = current->rsrc.name[i];
+ }
+ if(i<30) t->rsrc.name[i++] = '+';
+ t->rsrc.name[i] = 0;
+ } else {
+ rsrc_set_name((resource_t *)t, name);
+ }
+ res = t->rsrc.id;
+ } else {
+ res = -1;
+ }
+ }
+ break;
+
+ case BLT_SYS_thr_resume :
+ break;
+
+ case BLT_SYS_thr_suspend :
+ break;
+
+ case BLT_SYS_thr_spawn :
+ res = thr_spawn(p_uint32(1), p_uint32(2),
+ p_uint32(3), p_uint32(4),
+ p_uint32(5), p_uint32(6),
+ p_charptr(7));
+ break;
+
+ case BLT_SYS_thr_kill :
+ break;
+
+ case BLT_SYS_thr_wait :
+ res = thr_wait(p_uint32(1));
+ break;
+
+ default:
+ res = -1;
+ }
+}
+
+int metacall (volatile uint32 *esp)
+{
+ switch (p_uint32 (0))
+ {
+ case META_NULL_REQUEST :
+ return 0;
+
+ default:
+ return -1;
+ }
+}
+
diff --git a/kernel/task.c b/kernel/task.c
@@ -0,0 +1,167 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include "kernel.h"
+#include "memory.h"
+#include "task.h"
+
+extern char *gdt;
+extern int live_tasks;
+
+void thread_bootstrap(void);
+void kthread_bootstrap(void);
+
+void task_wake(task_t *task, int status)
+{
+ task->status = status;
+ rsrc_enqueue(run_queue, task);
+}
+
+int wait_on(resource_t *rsrc)
+{
+ task_t *task = current;
+ task->status = 0;
+ rsrc_enqueue(rsrc, task);
+ swtch();
+ return current->status;
+}
+
+void task_destroy(task_t *task)
+{
+ team_t *team = task->rsrc.owner;
+
+ if(task == current) panic("cannot destroy the running task");
+
+ TCLRMAGIC(task);
+
+ if(task->stack_area) {
+ area_destroy(team->aspace, task->stack_area->rsrc.id);
+ }
+
+ kfreepage(task->kstack);
+ rsrc_release(&task->rsrc);
+ kfree(task_t, task);
+
+ team->refcount--;
+ if(team->refcount == 0) team_destroy(team);
+}
+
+/* create a new task, complete with int stack */
+task_t *task_create(team_t *team, uint32 ip, uint32 sp, int kernel)
+{
+ task_t *t = kmalloc(task_t);
+ uint32 *SP;
+
+ t->kstack = kgetpages(1);
+ t->cr3 = team->aspace->pdirphys;
+
+ t->esp = (uint32) ( ((char *) t->kstack) + 4092 );
+ t->esp0 = t->esp;
+ t->scount = 0;
+ t->stack_area = NULL;
+ t->team = team;
+
+ t->node.data = t;
+
+ /* prep the kernel stack for first switch
+ ** SS
+ ** ESP
+ ** EFLAGS
+ ** CS
+ ** EIP -- thread_bootstrap will iret into the thread
+ **
+ ** <thread_bootstrap>
+ ** EFLAGS
+ ** EBP (0)
+ ** ESI (0)
+ ** EDI (0) -- stuff for _context_switch to pop off / return to
+ ** EBX (0)
+ */
+
+ SP = (uint32*) t->esp;
+
+ if(kernel) {
+ SP--; *SP = SEL_KDATA;
+ SP--; *SP = sp - 4*5;
+ SP--; *SP = 0x3202;
+ SP--; *SP = SEL_KCODE;
+ SP--; *SP = ip;
+ SP--; *SP = (uint32) thread_bootstrap;
+ } else {
+ SP--; *SP = SEL_UDATA | 3;
+ SP--; *SP = sp - 4*5;
+ SP--; *SP = 0x3202;
+ SP--; *SP = SEL_UCODE | 3;
+ SP--; *SP = ip;
+ SP--; *SP = (uint32) thread_bootstrap;
+ }
+ SP--; *SP = 0x3002;
+ SP--; *SP = 0;
+ SP--; *SP = 0;
+ SP--; *SP = 0;
+ SP--; *SP = 0;
+
+ t->esp = (uint32) SP;
+
+// kprintf("thr:%x/%x:%d",sp,ip,(kernel ? SEL_KCODE : (SEL_UCODE | 3)));
+
+ t->irq = 0;
+ t->flags = tREADY;
+ t->waiting_on = NULL;
+ team->refcount++;
+
+ TSETMAGIC(t);
+ return t;
+}
+
+
+int thr_wait(int thr_id)
+{
+ task_t *task = rsrc_find_task(thr_id);
+
+ if(task) {
+ wait_on((resource_t *)task);
+ return ERR_NONE;
+ } else {
+ return ERR_RESOURCE;
+ }
+}
+
+int thr_spawn(uint32 ip, uint32 sp,
+ uint32 area0, uint32 vaddr0,
+ uint32 area1, uint32 vaddr1,
+ const char *name)
+{
+ aspace_t *aspace;
+ task_t *task;
+ team_t *team;
+ area_t *area;
+ int id;
+ void *addr;
+
+ team = team_create();
+ aspace = team->aspace;
+ task = task_create(team, ip, sp, 0);
+ task->ustack = 0;
+ rsrc_bind(&task->rsrc, RSRC_TASK, team);
+
+ id = area_clone(aspace, area0, vaddr0, &addr, 0);
+ team->heap_id = id;
+
+ if(area = rsrc_find_area(id)) {
+ rsrc_set_owner(&area->rsrc, team);
+ }
+
+ id = area_clone(aspace, area1, vaddr1, &addr, 0);
+ if(area = rsrc_find_area(id)) rsrc_set_owner(&area->rsrc, team);
+
+ rsrc_set_name(&task->rsrc, name);
+ rsrc_set_name(&team->rsrc, name);
+ rsrc_enqueue(run_queue, task);
+ live_tasks++;
+
+ return task->rsrc.id;
+}
+
+
diff --git a/kernel/task.h b/kernel/task.h
@@ -0,0 +1,84 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _TASK_H_
+#define _TASK_H_
+
+#include "resource.h"
+#include "list.h"
+#include "team.h"
+
+#define tKERNEL 0
+#define tRUNNING 1
+#define tREADY 2
+#define tDEAD 3
+#define tWAITING 4
+#define tSLEEP_IRQ 5
+#define tSLEEP_TIMER 6
+#define tSLEEP_PAGING 7
+
+#define PARANOID 0
+
+#if PARANOID
+#define TMAGIC1 0x327610ae
+#define TMAGIC2 0x55716621
+#endif
+
+struct __task_t {
+ resource_t rsrc;
+
+#if PARANOID
+ uint32 magic1;
+#endif
+
+ /* wait_queue support */
+ resource_t *waiting_on;
+ node_t node;
+ int status; /* status code for the task that has just been awakened */
+ uint32 wait_time; /* for timer queues */
+
+ uint32 flags;
+ uint32 irq;
+ uint32 esp; /* saved stack */
+ uint32 esp0; /* kernel entry stack -- to stuff in the TSS */
+#if PARANOID
+ uint32 magic2;
+#endif
+ uint32 cr3;
+ uint32 scount;
+ void *kstack, *ustack;
+ area_t *stack_area;
+ team_t *team; /* team to which this task belongs */
+
+#ifdef __SMP__
+ int has_cpu, processor, last_processor;
+#endif
+};
+
+#if PARANOID
+#define TSETMAGIC(t) { t->magic1 = TMAGIC1; t->magic2 = TMAGIC2; }
+#define TCLRMAGIC(t) { t->magic1 = 0; t->magic2 = 0; }
+#define TCHKMAGIC(t) { if((t->magic1 != TMAGIC1) || (t->magic2 != TMAGIC2)) panic("bad thread magic");}
+#else
+#define TSETMAGIC(t) ((void)0)
+#define TCLRMAGIC(t) ((void)0)
+#define TCHKMAGIC(t) ((void)0)
+#endif
+
+task_t *task_create(team_t *team, uint32 ip, uint32 sp, int kernel);
+void task_destroy(task_t *task);
+void task_wait_on(task_t *task, resource_t *rsrc);
+void task_wake(task_t *task, int status);
+int wait_on(resource_t *rsrc);
+
+void task_call(task_t *t);
+
+int thr_kill(int task_id);
+int thr_wait(int task_id);
+int thr_spawn(uint32 ip, uint32 sp,
+ uint32 area0, uint32 vaddr0,
+ uint32 area1, uint32 vaddr1,
+ const char *name);
+#endif
+
diff --git a/kernel/team.c b/kernel/team.c
@@ -0,0 +1,66 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include "kernel.h"
+#include "memory.h"
+#include "list.h"
+
+team_t *team_create(void)
+{
+ team_t *team = kmalloc(team_t);
+
+ if(!(team->aspace = aspace_create())) return NULL;
+
+ list_init(&team->resources);
+ team->refcount = 0;
+ team->text_area = 0;
+ team->heap_id = 0;
+
+ rsrc_bind(&team->rsrc, RSRC_TEAM, kernel_team);
+ rsrc_set_owner(&team->aspace->rsrc, team);
+
+ return team;
+}
+
+void team_destroy(team_t *team)
+{
+ resource_t *rsrc;
+
+// kprintf("death to team #%d (%s)",team->rsrc.id,team->rsrc.name);
+// DEBUGGER();
+
+ while(rsrc = list_remove_head(&team->resources)){
+ rsrc->owner = NULL;
+// kprintf("- %x %s %d",rsrc,rsrc_typename(rsrc),rsrc->id);
+
+ switch(rsrc->type){
+ case RSRC_TASK:
+ kprintf("oops... cannot destroy team %d because of task %d!?",
+ team->rsrc.id,rsrc->id);
+ DEBUGGER();
+ case RSRC_PORT:
+ port_destroy(rsrc->id);
+ break;
+ case RSRC_SEM:
+ sem_destroy(rsrc->id);
+ break;
+ case RSRC_ASPACE:
+ aspace_destroy((aspace_t*) rsrc);
+ break;
+ case RSRC_AREA:
+ case RSRC_QUEUE:
+ case RSRC_TEAM:
+ /* skip for now - teams don't get destroyed, areas and queues get
+ destroyed with their relatives */
+ break;
+
+ default:
+ kprintf("what the hell is %d (type %d)?",rsrc->id,rsrc->type);
+ }
+ }
+
+ rsrc_release(team);
+ kfree(team_t, team);
+}
+
diff --git a/kernel/team.h b/kernel/team.h
@@ -0,0 +1,25 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _TEAM_H
+#define _TEAM_H
+
+#include "resource.h"
+
+struct __team_t {
+ resource_t rsrc;
+
+ list_t resources; /* all resources owned by the team */
+ int refcount; /* number of attached tasks */
+
+ aspace_t *aspace; /* address space which it all exists in */
+
+ int heap_id;
+ int text_area;
+};
+
+team_t *team_create(void);
+void team_destroy(team_t *team);
+
+#endif
diff --git a/kernel/trampoline.S b/kernel/trampoline.S
@@ -0,0 +1,92 @@
+/* $Id: //depot/blt/kernel/trampoline.S#2 $
+**
+** Copyright 1998 Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License.
+*/
+
+/*
+ * This is the initial bootstrap code for the application processors. When
+ * we get here, we are running on the AP in 16-bit real mode with a stack
+ * allocated at 0x1000 * my_cpu_num by the kernel which we are not set up
+ * to use yet. Our text is at the bottom of this stack. We have to be
+ * careful until things are fixed up.
+ *
+ * Basically, we just set protected mode with a temporary GDT, and call
+ * C code. The IDT and paging are set up later since we can't reference
+ * any global variable here declared outside this file.
+ *
+ * Memory map at this stage is
+ *
+ * 0x9000 location of our stack
+ * 0x9004 null descriptor
+ * 0x9008
+ * 0x900c kernel text descriptor
+ * 0x9010
+ * 0x9014 kernel data descriptor
+ * 0x9018
+ * 0x901c gdt limit << 16
+ * 0x9020 gdt base
+ * 0x9024 address of page directory
+ */
+
+.globl trampoline
+.globl trampoline_end
+.globl flush
+
+.code16
+trampoline:
+ cli # paranoia
+ xor %ax, %ax
+ mov %ax, %ds
+ mov %ax, %ss
+
+ movl $0x9000, %eax # find the location of our stack
+ mov (%eax), %ebx
+
+ xor %eax, %eax
+ mov %ax, %ss
+ add $0x1000, %ebx
+ mov %bx, %sp
+
+ movl $0x18, %eax # i[0] = limit << 16; (limit is 24 dec.)
+ movl $0x10, %ecx
+ shl %cl, %eax
+ mov $0x901c, %ebx
+ mov %eax, (%ebx)
+ mov $0x9004, %eax # i[1] = base; (base = 0x9004)
+ mov %eax, 4(%ebx)
+ mov $0x901e, %eax
+ lgdt (%eax)
+
+ movl $0x9024, %eax
+ mov (%eax), %eax
+ mov %eax, %cr3
+
+ movl $0x80000001, %eax # turn on paging and protected mode
+ mov %eax, %cr0
+
+ /*
+ * Do a long jump to the kernel text segment to serialise the processor.
+ * A jump to flush won't work since we are being linked to run at a
+ * different address, so we calculate the offset in the segment ourselves.
+ */
+ ljmp $0x8, $(0x1000 + flush - trampoline)
+
+.code32
+flush:
+ mov $0x10, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+
+ mov $0x66, %ax
+ mov $0x1000, %dx
+ mov %eax, (%edx)
+ cld # supposedly good for gcc > 2
+ movl $0x80000074, %eax # jmp _start does not work for some reason
+ jmp *%eax
+
+trampoline_end:
+
diff --git a/kernel/types.h b/kernel/types.h
@@ -0,0 +1,24 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+#include <blt/types.h>
+
+typedef struct __resource_t resource_t;
+typedef struct __right_t right_t;
+typedef struct __port_t port_t;
+typedef struct __sem_t sem_t;
+typedef struct __task_t task_t;
+typedef struct __aspace_t aspace_t;
+typedef struct __area_t area_t;
+typedef struct __team_t team_t;
+
+typedef struct __list_t list_t;
+typedef struct __node_t node_t;
+
+typedef struct __pager_fault_t pager_fault_t;
+
+#endif
diff --git a/lib/Makefile b/lib/Makefile
@@ -0,0 +1,28 @@
+BLTHOME := ../
+include $(BLTHOME)make.conf
+
+PRETARGETS := obj crt0.o crtb.o c++rt0.o version.o
+TARGETS := subdirs
+
+SUBDIRS := libc libblt libposix libconsole libdl libwin
+
+obj:
+ mkdir obj
+ ln -fs ../libblt/libblt.a obj
+ ln -fs ../libblt/libblt.so obj
+ ln -fs ../libc/libc.a obj
+ ln -fs ../libc/libc.so obj
+ ln -fs ../libc/libkern.a obj
+ ln -fs ../libconsole/libconsole.a obj
+ ln -fs ../libconsole/libconsole.so obj
+ ln -fs ../libposix/libposix.a obj
+ ln -fs ../libposix/libposix.so obj
+ ln -fs ../libdl/libdl.a obj
+ ln -fs ../libdl/libdl.so obj
+ ln -fs ../libwin/libwin.a obj
+ ln -fs ../libwin/libwin.so obj
+
+clean::
+ @rm -rf obj
+
+include $(BLTHOME)make.actions
diff --git a/lib/c++rt0.c b/lib/c++rt0.c
@@ -0,0 +1,141 @@
+/* $Id: //depot/blt/lib/c++rt0.c#5 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+** Copyright 1998-1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include <elf.h>
+#include <blt/syscall.h>
+#include <blt/libsyms.h>
+
+int main(int argc, char **argv);
+static void _init(void);
+
+char *__progname;
+
+void _start(int argc, char **argv)
+{
+ _init();
+ __progname = *argv;
+ os_terminate (main (argc, argv));
+}
+
+#define MAXINIT 8
+
+void __libc_init_memory(unsigned int top_of_binary,
+ unsigned int start_bss, unsigned int bss_length);
+
+static void _init(void)
+{
+ char *strtab;
+ int symtablen, top, i, j, p;
+ elf32_hdr_t *hdr;
+ elf32_sym_t *symtab;
+ elf32_sec_hdr_t *last;
+ init_info *inits[MAXINIT];
+
+ hdr = (elf32_hdr_t *) 0x1000;
+ symtab = _elf_find_section_data (hdr, ".symtab");
+ strtab = _elf_find_section_data (hdr, ".strtab");
+ symtablen = _elf_section_size (hdr, ".symtab") / sizeof (elf32_sym_t);
+ last = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff +
+ hdr->e_shentsize * (hdr->e_shnum - 1));
+ top = (unsigned int) hdr + last->sh_offset + last->sh_size;
+
+ /* Find any __init_... symbols and build a list of 'em
+ ** These will all be called before main(), but after
+ ** the .bss is zero'd
+ */
+ for (j = 0, i = 0; i < symtablen; i++){
+ if (!strncmp(strtab + symtab[i].st_name, "__init_", 7) &&
+ (symtab[i].st_shndx != SHN_UNDEF)){
+ inits[j++] = (init_info *) symtab[i].st_value;
+ if(j == MAXINIT) break;
+ }
+ }
+
+ __libc_init_memory((unsigned int) top, (unsigned int)
+ _elf_find_section_data (hdr, ".bss"), _elf_section_size (hdr, ".bss"));
+
+ for(p=0;p<5;p++){
+ for(i = 0; i < j; i++){
+ if(inits[i]->priority == p) inits[i]->func();
+ }
+ }
+}
+
+elf32_sec_hdr_t *_elf_find_section_hdr (elf32_hdr_t *hdr, char *name)
+{
+ char *section_name;
+ int i;
+ elf32_sec_hdr_t *sec_hdr;
+
+ sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff +
+ hdr->e_shstrndx * hdr->e_shentsize);
+ section_name = (char *) ((unsigned int) hdr + sec_hdr->sh_offset);
+ sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff);
+ for (i = 0; i < hdr->e_shnum; i++, sec_hdr = (elf32_sec_hdr_t *)
+ ((unsigned int) sec_hdr + hdr->e_shentsize))
+ if (!strcmp (section_name + sec_hdr->sh_name, name))
+ return sec_hdr;
+ return NULL;
+}
+
+void *_elf_find_section_data (elf32_hdr_t *hdr, char *name)
+{
+ elf32_sec_hdr_t *sec_hdr;
+
+ sec_hdr = _elf_find_section_hdr (hdr, name);
+ return (sec_hdr == NULL) ? NULL : (void *) ((unsigned int) hdr +
+ sec_hdr->sh_offset);
+}
+
+int _elf_section_size (elf32_hdr_t *hdr, char *name)
+{
+ elf32_sec_hdr_t *sec_hdr;
+
+ sec_hdr = _elf_find_section_hdr (hdr, name);
+ return (sec_hdr == NULL) ? 0 : sec_hdr->sh_size;
+}
+
+/****** this crap is to make ld happy when we build shared executables ******/
+
+int ___brk_addr;
+int __environ;
+
+void __attribute__ ((noreturn)) abort ()
+{
+ for (;;) ;
+}
+
+void atexit ()
+{
+}
+
+/********************************* end crap *********************************/
+
diff --git a/lib/crt0.c b/lib/crt0.c
@@ -0,0 +1,142 @@
+/* $Id: //depot/blt/lib/crt0.c#20 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+** Copyright 1998-1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include <elf.h>
+#include <blt/syscall.h>
+#include <blt/libsyms.h>
+#include <blt/os.h>
+
+int main(int argc, char **argv);
+static void _init(void);
+
+char *__progname;
+
+void _start(int argc, char **argv)
+{
+ _init();
+ __progname = *argv;
+ os_terminate (main (argc, argv));
+}
+
+#define MAXINIT 8
+
+void __libc_init_memory(unsigned int top_of_binary,
+ unsigned int start_bss, unsigned int bss_length);
+
+static void _init(void)
+{
+ char *strtab;
+ int symtablen, top, i, j, p;
+ elf32_hdr_t *hdr;
+ elf32_sym_t *symtab;
+ elf32_sec_hdr_t *last;
+ init_info *inits[MAXINIT];
+
+ hdr = (elf32_hdr_t *) 0x1000;
+ symtab = _elf_find_section_data (hdr, ".symtab");
+ strtab = _elf_find_section_data (hdr, ".strtab");
+ symtablen = _elf_section_size (hdr, ".symtab") / sizeof (elf32_sym_t);
+ last = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff +
+ hdr->e_shentsize * (hdr->e_shnum - 1));
+ top = (unsigned int) hdr + last->sh_offset + last->sh_size;
+
+ /* Find any __init_... symbols and build a list of 'em
+ ** These will all be called before main(), but after
+ ** the .bss is zero'd
+ */
+ for (j = 0, i = 0; i < symtablen; i++){
+ if (!strncmp(strtab + symtab[i].st_name, "__init_", 7) &&
+ (symtab[i].st_shndx != SHN_UNDEF)){
+ inits[j++] = (init_info *) symtab[i].st_value;
+ if(j == MAXINIT) break;
+ }
+ }
+
+ __libc_init_memory((unsigned int) top, (unsigned int)
+ _elf_find_section_data (hdr, ".bss"), _elf_section_size (hdr, ".bss"));
+
+ for(p=0;p<5;p++){
+ for(i = 0; i < j; i++){
+ if(inits[i]->priority == p) inits[i]->func();
+ }
+ }
+}
+
+elf32_sec_hdr_t *_elf_find_section_hdr (elf32_hdr_t *hdr, char *name)
+{
+ char *section_name;
+ int i;
+ elf32_sec_hdr_t *sec_hdr;
+
+ sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff +
+ hdr->e_shstrndx * hdr->e_shentsize);
+ section_name = (char *) ((unsigned int) hdr + sec_hdr->sh_offset);
+ sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff);
+ for (i = 0; i < hdr->e_shnum; i++, sec_hdr = (elf32_sec_hdr_t *)
+ ((unsigned int) sec_hdr + hdr->e_shentsize))
+ if (!strcmp (section_name + sec_hdr->sh_name, name))
+ return sec_hdr;
+ return NULL;
+}
+
+void *_elf_find_section_data (elf32_hdr_t *hdr, char *name)
+{
+ elf32_sec_hdr_t *sec_hdr;
+
+ sec_hdr = _elf_find_section_hdr (hdr, name);
+ return (sec_hdr == NULL) ? NULL : (void *) ((unsigned int) hdr +
+ sec_hdr->sh_offset);
+}
+
+int _elf_section_size (elf32_hdr_t *hdr, char *name)
+{
+ elf32_sec_hdr_t *sec_hdr;
+
+ sec_hdr = _elf_find_section_hdr (hdr, name);
+ return (sec_hdr == NULL) ? 0 : sec_hdr->sh_size;
+}
+
+/****** this crap is to make ld happy when we build shared executables ******/
+
+int ___brk_addr;
+int __environ;
+
+void __attribute__ ((noreturn)) abort ()
+{
+ for (;;) ;
+}
+
+void atexit ()
+{
+}
+
+/********************************* end crap *********************************/
+
diff --git a/lib/crtb.c b/lib/crtb.c
@@ -0,0 +1,124 @@
+/* $Id: //depot/blt/lib/crtb.c#3 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+** Copyright 1998-1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include <elf.h>
+#include <blt/syscall.h>
+#include <blt/libsyms.h>
+
+int main(int argc, char **argv);
+void __libc_init_memory(unsigned int top_of_binary,
+ unsigned int start_bss, unsigned int bss_length);
+
+static char *strtab = NULL;
+static int symtablen = 0, top = 0;
+static elf32_hdr_t *hdr = NULL;
+static elf32_sym_t *symtab = NULL;
+static void run_all (const char *name);
+
+void _start(int argc, char **argv)
+{
+ elf32_sec_hdr_t *last;
+
+ hdr = (elf32_hdr_t *) 0x1000;
+ symtab = _elf_find_section_data (hdr, ".symtab");
+ strtab = _elf_find_section_data (hdr, ".strtab");
+ symtablen = _elf_section_size (hdr, ".symtab") / sizeof (elf32_sym_t);
+ last = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff +
+ hdr->e_shentsize * (hdr->e_shnum - 1));
+ top = (unsigned int) hdr + last->sh_offset + last->sh_size;
+
+ __libc_init_memory((unsigned int) top, (unsigned int)
+ _elf_find_section_data (hdr, ".bss"), _elf_section_size (hdr, ".bss"));
+
+ run_all ("_init");
+ os_terminate (main (argc, argv));
+}
+
+static void run_all (const char *name)
+{
+ int i;
+
+ for (i = 0; i < symtablen; i++)
+ if (!strcmp (strtab + symtab[i].st_name, name) &&
+ (symtab[i].st_shndx != SHN_UNDEF))
+ (*((void (*)(void)) symtab[i].st_value)) ();
+}
+
+elf32_sec_hdr_t *_elf_find_section_hdr (elf32_hdr_t *hdr, char *name)
+{
+ char *section_name;
+ int i;
+ elf32_sec_hdr_t *sec_hdr;
+
+ sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff +
+ hdr->e_shstrndx * hdr->e_shentsize);
+ section_name = (char *) ((unsigned int) hdr + sec_hdr->sh_offset);
+ sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff);
+ for (i = 0; i < hdr->e_shnum; i++, sec_hdr = (elf32_sec_hdr_t *)
+ ((unsigned int) sec_hdr + hdr->e_shentsize))
+ if (!strcmp (section_name + sec_hdr->sh_name, name))
+ return sec_hdr;
+ return NULL;
+}
+
+void *_elf_find_section_data (elf32_hdr_t *hdr, char *name)
+{
+ elf32_sec_hdr_t *sec_hdr;
+
+ sec_hdr = _elf_find_section_hdr (hdr, name);
+ return (sec_hdr == NULL) ? NULL : (void *) ((unsigned int) hdr +
+ sec_hdr->sh_offset);
+}
+
+int _elf_section_size (elf32_hdr_t *hdr, char *name)
+{
+ elf32_sec_hdr_t *sec_hdr;
+
+ sec_hdr = _elf_find_section_hdr (hdr, name);
+ return (sec_hdr == NULL) ? 0 : sec_hdr->sh_size;
+}
+
+/****** this crap is to make ld happy when we build shared executables ******/
+
+int ___brk_addr;
+int __environ;
+
+void __attribute__ ((noreturn)) abort ()
+{
+ for (;;) ;
+}
+
+void atexit ()
+{
+}
+
+/********************************* end crap *********************************/
+
diff --git a/lib/libblt/Connection.cpp b/lib/libblt/Connection.cpp
@@ -0,0 +1,113 @@
+/* Copyright 1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <blt/Connection.h>
+#include <blt/Message.h>
+#include <blt/namer.h>
+#include <blt/syscall.h>
+
+#include <string.h>
+
+using namespace BLT;
+
+Connection::~Connection()
+{
+ port_destroy(_local_port);
+}
+
+int
+Connection::Send(const Message *msg)
+{
+ msg_hdr_t mh;
+ const void *data;
+ uint32 len;
+ int res;
+
+ msg->GetPackedData(&data,&len);
+
+ mh.flags = 0;
+ mh.src = _local_port;
+ mh.dst = _remote_port;
+ mh.data = (void*) data;
+ mh.size = len;
+
+ res = old_port_send(&mh);
+ if(res != len) {
+ return res;
+ } else {
+ return 0;
+ }
+}
+
+int
+Connection::Recv(Message *msg)
+{
+ msg_hdr_t mh;
+ int res;
+ char buf[1024];
+
+ mh.flags = 0;
+ mh.dst = _local_port;
+ mh.size = 1024;
+ mh.data = buf;
+
+ if((res = old_port_recv(&mh)) < 0) return res;
+
+ return msg->PutPackedData(buf,res,mh.src);
+}
+
+int
+Connection::Call(const Message *send, Message *recv)
+{
+ int res;
+ if((res = Send(send))) {
+ return res;
+ } else {
+ return Recv(recv);
+ }
+}
+
+Connection *
+Connection::FindService(const char *name)
+{
+ Connection *cnxn;
+ int port;
+
+ if(!strcmp(name,"namer")){
+ port = NAMER_PORT;
+ } else {
+ port = namer_find(name, 0);
+ }
+ if(port < 1) return 0;
+
+ cnxn = new Connection();
+ cnxn->_remote_port = port;
+
+ return cnxn;
+}
+
+Connection *
+Connection::CreateService(const char *name)
+{
+ Connection *cnxn = new Connection();
+
+ if(!strcmp(name,"namer")){
+ port_destroy(cnxn->_local_port);
+ cnxn->_local_port = NAMER_PORT;
+ } else {
+ if(namer_register(cnxn->_local_port, (char*) name)){
+ delete cnxn;
+ cnxn = 0;
+ }
+ }
+
+ return cnxn;
+}
+
+
+Connection::Connection()
+{
+ _local_port = port_create(0,"cnxn:local_port");
+ _remote_port = 0;
+}
diff --git a/lib/libblt/Makefile b/lib/libblt/Makefile
@@ -0,0 +1,11 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+LIBRARY := libblt.a
+SHLIB := libblt.so
+SHLIB_MAJOR := 1
+SHLIB_MINOR := 0
+OBJS := hash.o tell.o blkdev.o disk.o \
+ namer.o Message.o Connection.o
+
+include $(BLTHOME)make.actions
diff --git a/lib/libblt/Message.cpp b/lib/libblt/Message.cpp
@@ -0,0 +1,312 @@
+// Copyright 1999, Brian J. Swetland. All Rights Reserved.
+// This file is provided under the terms of the OpenBLT License
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <blt/Message.h>
+#include <blt/syscall.h>
+
+#define GROW_BY 128
+#define BLT_ID_MESSAGE 0x42023017
+
+using namespace BLT;
+
+struct chunk
+{
+ uint32 type;
+ uint32 id;
+ uint32 len;
+ uchar data[4];
+};
+
+Message::Message()
+{
+ chunk *c;
+
+ _data = malloc(GROW_BY);
+ _length = 12;
+ _available = GROW_BY - 12;
+
+ c = (chunk*) _data;
+
+ c->type = BLT_TYPE_MESSAGE;
+ c->id = BLT_ID_MESSAGE;
+ c->len = 0;
+
+ _reply_port = 0;
+}
+
+
+Message::~Message()
+{
+ if(_data) free(_data);
+}
+
+int
+Message::PutData(uint32 type, uint32 id, const void *data, uint32 len)
+{
+ chunk *c;
+ uint32 size = 12 + ((len + 3) & ~3);
+
+ if(_available < size) {
+ while(_available < size) {
+ _available += GROW_BY;
+ }
+ _data = realloc(_data, (_length + _available));
+ }
+
+ c = (chunk*) ((char*) _data + _length);
+ c->type = type;
+ c->id = id;
+ c->len = len;
+ memcpy(c->data, data, len);
+
+ _length += size;
+ ((chunk*)_data)->len = _length - 12;
+}
+
+int
+Message::GetData(uint32 type, uint32 id, void *data, uint32 len) const
+{
+ chunk *c;
+ char *x = (char *) _data + 12;
+ uint32 count = _length - 12;
+ uint32 size;
+
+ while(count > 12){
+ c = (chunk*) x;
+ size = (12 + ((c->len + 3) & ~3));
+ if((type == c->type) && (id == c->id) && (len == c->len)){
+ memcpy(data, c->data, c->len);
+ return 0;
+ }
+
+ x += size;
+ count -= size;
+ }
+
+ return -1;
+}
+
+int
+Message::GetData(uint32 type, uint32 id, const void **data, uint32 *len) const
+{
+ chunk *c;
+ char *x = (char *) _data + 12;
+ uint32 count = _length - 12;
+ uint32 size;
+
+ while(count > 12){
+ c = (chunk*) x;
+ size = (12 + ((c->len + 3) & ~3));
+ if((type == c->type) && (id == c->id)){
+ *data = (void*) c->data;
+ *len = c->len;
+ return 0;
+ }
+
+ x += size;
+ count -= size;
+ }
+
+ *data = NULL;
+ return -1;
+}
+
+int
+Message::GetEntry(uint32 n, uint32 *type, uint32 *id, const void **data, uint32 *len) const
+{
+ chunk *c;
+ char *x = (char *) _data + 12;
+ uint32 count = _length - 12;
+ uint32 size;
+ uint32 _n = 0;
+
+ while(count > 12){
+ c = (chunk*) x;
+ if(_n == n){
+ *type = c->type;
+ *id = c->id;
+ *len = c->len;
+ *data = (void*) c->data;
+ }
+
+ size = (12 + ((c->len + 3) & 3));
+ x += size;
+ count -= size;
+ }
+
+ *data = NULL;
+ return -1;
+}
+
+int
+Message::GetPackedData(const void **data, uint32 *length) const
+{
+ *data = _data;
+ *length = _length;
+
+ return 0;
+}
+
+int
+Message::PutPackedData(const void *data, uint32 length, int reply_port)
+{
+ chunk *c = (chunk*) data;
+
+ if(length < 12) return -1;
+
+ if(c->type != BLT_TYPE_MESSAGE) return -1;
+ if(c->id != BLT_ID_MESSAGE) return -1;
+ if(c->len != (length - 12)) return -1;
+
+ if(_data) free(_data);
+ _data = malloc(length);
+
+ memcpy(_data, data, length);
+ _available = 0;
+ _length = length;
+
+ _reply_port = reply_port;
+
+ return 0;
+}
+
+int
+Message::PutInt32(uint32 id, int32 data)
+{
+ return PutData(BLT_TYPE_INT32, id, &data, sizeof(int32));
+}
+
+int
+Message::PutString(uint32 id, const char *data)
+{
+ return PutData(BLT_TYPE_STRING, id, data, strlen(data)+1);
+}
+
+int
+Message::PutPointer(uint32 id, void *data)
+{
+ return PutData(BLT_TYPE_POINTER, id, data, sizeof(void*));
+}
+
+int
+Message::PutMessage(uint32 id, Message *msg)
+{
+ return PutData(BLT_TYPE_MESSAGE, id, msg->_data, msg->_length);
+}
+
+int
+Message::GetInt32(uint32 id, int32 *data) const
+{
+ return GetData(BLT_TYPE_INT32, id, (void*) data, sizeof(int32));
+}
+
+int
+Message::GetString(uint32 id, const char **data) const
+{
+ uint32 discard;
+ return GetData(BLT_TYPE_STRING, id, (const void**) data, &discard);
+}
+
+int
+Message::GetPointer(uint32 id, void **ptr) const
+{
+ return GetData(BLT_TYPE_POINTER, id, (void*) ptr, sizeof(void *));
+}
+
+int
+Message::GetMessage(uint32 id, Message *msg) const
+{
+ const void *data;
+ uint32 len;
+
+ GetData(BLT_TYPE_MESSAGE, id, &data, &len);
+ return msg->PutPackedData(data,len);
+}
+
+void
+Message::Empty()
+{
+ _available += _length - 12;
+ _length = 12;
+ _reply_port = 0;
+ ((chunk*)_data)->len = 0;
+}
+
+int
+Message::Reply(const Message *msg) const
+{
+ msg_hdr_t mh;
+ int res;
+
+ if(_reply_port > 0){
+ if((res = port_create(0,"reply_port")) < 0) return res;
+ mh.flags = 0;
+ mh.src = res;
+ mh.dst = _reply_port;
+ mh.size = msg->_length;
+ mh.data = msg->_data;
+ res = old_port_send(&mh);
+ port_destroy(mh.src);
+ if(res == msg->_length) {
+ return 0;
+ } else {
+ return res;
+ }
+ } else {
+ return -1;
+ }
+}
+
+#if 0
+
+void Message::dump()
+{
+ int i,j;
+ fprintf(stderr,"bMessage - %d of %d\n",_length,_length+_available);
+
+ for(i=0;i<_length;i+=16){
+ fprintf(stderr,"%04x: ",i);
+ for(j=0;j<16;j++){
+ if((i+j) < _length){
+ fprintf(stderr,"%02x ",((uchar*)_data)[i+j]);
+ } else {
+ fprintf(stderr," ");
+ }
+ }
+ fprintf(stderr," ");
+ for(j=0;j<16;j++){
+ if((i+j) < _length){
+ uchar c = ((uchar*)_data)[i+j];
+ if((c<' ')||(c>126)) c = '.';
+ fprintf(stderr,"%c",c);
+ } else {
+ fprintf(stderr," ");
+ }
+ }
+ fprintf(stderr,"\n");
+ }
+
+}
+
+int main(int argc, char *argv[])
+{
+ int32 n;
+ const char *s;
+
+ Message msg;
+ msg.PutInt32('foob',42);
+ msg.PutString('blah',"Hello, Message");
+
+ if(msg.GetInt32('foob',&n)) exit(1);
+ fprintf(stderr,"foob = %d\n",n);
+
+ if(msg.GetString('blah',&s)) exit(1);
+ fprintf(stderr,"blah = %s\n",s);
+
+ msg.dump();
+ return 0;
+}
+#endif
diff --git a/lib/libblt/blkdev.c b/lib/libblt/blkdev.c
@@ -0,0 +1,117 @@
+/* Copyright 1999, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <blt/libsyms.h>
+#include <blt/blkdev.h>
+#include <blt/namer.h>
+#include <blt/syscall.h>
+
+weak_alias (_blk_open, blk_open)
+weak_alias (_blk_close, blk_close)
+weak_alias (_blk_read, blk_read)
+weak_alias (_blk_write, blk_write)
+
+int __blk_ref;
+
+int _blk_open (const char *name, int flags, blkdev_t **retdev)
+{
+ char *server;
+ int i, len;
+ msg_hdr_t mh;
+ blkdev_t *dev;
+ blktxn_t *txn;
+ blkres_t res;
+
+ for (i = 0; name[i] && (name[i] != '/') && i < BLT_MAX_NAME_LENGTH; i++) ;
+ server = malloc (i);
+ strncpy (server, name, i);
+ server[i] = 0;
+
+ dev = malloc (sizeof (blkdev_t));
+ dev->remote_port = namer_find (server, 1);
+
+ txn = malloc (len = sizeof (blktxn_t) + strlen (name) - i + 1);
+ txn->cmd = BLK_CMD_OPEN;
+ strcpy ((char *) (txn + 1), name + i + 1);
+
+ mh.src = dev->local_port = port_create (dev->remote_port, "blkdev");
+ mh.dst = dev->remote_port;
+ mh.data = txn;
+ mh.size = len;
+ old_port_send (&mh);
+
+ mh.src = dev->remote_port;
+ mh.dst = dev->local_port;
+ mh.data = &res;
+ mh.size = sizeof (blkres_t);
+ old_port_recv (&mh);
+
+ if (res.status)
+ {
+ free (dev);
+ *retdev = NULL;
+ return res.status;
+ }
+
+ dev->blksize = res.data[0];
+ dev->devno = res.data[1];
+ *retdev = dev;
+ return 0;
+}
+
+int _blk_close (blkdev_t *dev)
+{
+ free (dev);
+ return 0;
+}
+
+int _blk_read (blkdev_t *dev, void *buf, int block, int count)
+{
+ int len, ret;
+ msg_hdr_t mh;
+ blktxn_t txn;
+ blkres_t *res;
+
+ res = malloc (len = sizeof (blkres_t) + dev->blksize);
+
+ while (count)
+ {
+ txn.device = dev->devno;
+ txn.cmd = BLK_CMD_READ;
+ txn.block = block;
+ txn.count = count;
+ mh.src = dev->local_port;
+ mh.dst = dev->remote_port;
+ mh.data = &txn;
+ mh.size = sizeof (blktxn_t);
+ old_port_send (&mh);
+
+ mh.src = dev->remote_port;
+ mh.dst = dev->local_port;
+ mh.data = res;
+ mh.size = len;
+ old_port_recv (&mh);
+
+ if (res->status)
+ goto done;
+ memcpy (buf, res + 1, dev->blksize);
+ buf = (char *) buf + dev->blksize;
+ block++;
+ count--;
+ }
+
+done:
+ ret = res->status;
+ free (res);
+ return ret;
+}
+
+int _blk_write (blkdev_t *dev, const void *buf, int block, int count)
+{
+ return 0;
+}
+
diff --git a/lib/libblt/disk.c b/lib/libblt/disk.c
@@ -0,0 +1,167 @@
+/* $Id: //depot/blt/lib/libblt/disk.c#4 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <blt/disk.h>
+
+static int blt_internal_code (int fdisk, int fstype)
+{
+ if (fdisk == FDISK_TYPE_FREEBSD)
+ if (fstype == BSD_FS_BSDFFS)
+ return FREEBSD_FFS;
+ else if (fstype == BSD_FS_SWAP)
+ return FREEBSD_SWAP;
+ else
+ return 0;
+ else if (fdisk == FDISK_TYPE_OPENBSD)
+ if (fstype == BSD_FS_BSDFFS)
+ return OPENBSD_FFS;
+ else if (fstype == BSD_FS_SWAP)
+ return OPENBSD_SWAP;
+ else
+ return 0;
+ else
+ return 0;
+}
+
+disk_t *disk_alloc (blkdev_t *dev)
+{
+ unsigned char *mbr, *label;
+ int i, j, x;
+ disk_t *disk;
+ fdisk_partition *fp;
+ bsd_disklabel *slice;
+
+ disk = malloc (sizeof (disk_t));
+ disk->dev = dev;
+ disk->numparts = 0;
+ mbr = malloc (dev->blksize);
+ label = malloc (dev->blksize);
+ slice = (bsd_disklabel *) label;
+
+ /* count fdisk partitions */
+ blk_read (dev, mbr, 0, 1);
+ for (i = 0; i < 4; i++)
+ {
+ fp = (fdisk_partition *) (mbr + 0x1be) + i;
+ if (fp->type)
+ switch (fp->type)
+ {
+ case FDISK_TYPE_EMPTY:
+ break;
+
+ case FDISK_TYPE_FREEBSD:
+ case FDISK_TYPE_OPENBSD:
+ disk->numparts++;
+ blk_read (dev, label, fp->start_sect_num + 1, 1);
+ for (j = 0; j < BSD_MAXSLICES; j++)
+ if (slice->d_partitions[j].p_fstype != BSD_FS_UNUSED)
+ disk->numparts++;
+ break;
+
+ default:
+ disk->numparts++;
+ break;
+ }
+ }
+ disk->partition = malloc (sizeof (partition_t) * disk->numparts);
+
+ /* create partition data, fdisk partitions first */
+ for (i = x = 0; i < 4; i++)
+ {
+ fp = (fdisk_partition *) (mbr + 0x1be) + i;
+ if (fp->type)
+ {
+ disk->partition[x].name[0] = '0' + i;
+ disk->partition[x].name[1] = 0;
+ disk->partition[x].start = fp->start_sect_num;
+ disk->partition[x].size = fp->num_sects;
+ disk->partition[x].type = fp->type;
+ x++;
+ }
+ }
+
+ /* create data for bsd slices */
+ for (i = 0; i < 4; i++)
+ {
+ fp = (fdisk_partition *) (mbr + 0x1be) + i;
+ switch (fp->type)
+ {
+ case FDISK_TYPE_FREEBSD:
+ case FDISK_TYPE_OPENBSD:
+ blk_read (dev, label, fp->start_sect_num + 1, 1);
+ for (j = 0; j < BSD_MAXSLICES; j++)
+ if (slice->d_partitions[j].p_fstype != BSD_FS_UNUSED)
+ {
+ disk->partition[x].name[0] = '0' + i;
+ disk->partition[x].name[1] = 'a' + j;
+ disk->partition[x].name[2] = 0;
+ disk->partition[x].start =
+ slice->d_partitions[j].p_offset;
+ disk->partition[x].size =
+ slice->d_partitions[j].p_size;
+ disk->partition[x].type = blt_internal_code (fp->type,
+ slice->d_partitions[j].p_fstype);
+ x++;
+ }
+ break;
+ }
+ }
+
+ free (mbr);
+ free (label);
+ return disk;
+}
+
+void disk_free (disk_t *disk)
+{
+ free (disk->partition);
+ free (disk);
+}
+
+const char *disk_partition_name (disk_t *disk, int partition)
+{
+ return disk->partition[partition].name;
+}
+
+unsigned long long disk_partition_start (disk_t *disk, int partition)
+{
+ return disk->partition[partition].start;
+}
+
+unsigned long long disk_partition_size (disk_t *disk, int partition)
+{
+ return disk->partition[partition].size;
+}
+
+unsigned int disk_partition_type (disk_t *disk, int partition)
+{
+ return disk->partition[partition].type;
+}
+
diff --git a/lib/libblt/hash.c b/lib/libblt/hash.c
@@ -0,0 +1,234 @@
+/* $Id: //depot/blt/lib/libblt/hash.c#3 $
+**
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * these algorithms are based on knuth's algorithm 6.4d, as described in
+ * vol. 3, p. 529 of taocp.
+ *
+ * XXX - keys must be unique!
+ */
+
+/*
+
+the primes were computed by using the following program:
+
+int main (void)
+{
+ unsigned int i, j, good, last;
+
+ for (i = 17, last = 0; i < 65536 * 16384 - 1; i++)
+ {
+ for (j = 2, good = 1; (j <= floor (sqrt ((double) i))) && good; j++)
+ if (!(i % j))
+ good = 0;
+ if (good)
+ {
+ if (last == i - 2)
+ {
+ printf ("%d %d\n", last, i);
+ i *= 2;
+ }
+ last = i;
+ }
+ }
+
+ return 0;
+}
+
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <blt/hash.h>
+
+static unsigned int table_size[] = { 7, 19, 43, 103, 229, 463, 1021, 2083, 4219,
+ 8539, 17191, 34471, 69031, 138079, 276373, 552751, 1105549, 2211259,
+ 4422619, 8845453, 17691043, 35382091, 70764259, 141528559, 283057213,
+ 566115259 };
+
+static int hash (int key, int size);
+static int rehash (int key, int size);
+static void hashtable_rebuild (hashtable_t *t, int dir);
+
+static int hash (int key, int size)
+{
+ return key % table_size[size];
+}
+
+static int rehash (int key, int size)
+{
+ return 1 + (key % (table_size[size] - 2));
+}
+
+hashtable_t *hashtable_new (float max_load)
+{
+ int i;
+ hashtable_t *t;
+
+ t = (hashtable_t *) malloc (sizeof (hashtable_t));
+ t->size_index = 0;
+ t->used = t->dirty = 0;
+ t->max_load = max_load;
+ t->table = (hashnode_t *) malloc (sizeof (hashnode_t) * *table_size);
+ for (i = 0; i < table_size[t->size_index]; i++)
+ t->table[i].valid = t->table[i].dirty = 0;
+ return t;
+}
+
+void hashtable_del (hashtable_t *t)
+{
+ free (t->table);
+}
+
+void hashtable_insert (hashtable_t *t, int key, void *data, int dsize)
+{
+ int i, c;
+
+ if (t->used > (t->max_load * table_size[t->size_index]))
+ hashtable_rebuild (t, 1);
+
+ i = hash (key, t->size_index);
+ if (t->table[i].valid)
+ do
+ {
+ c = rehash (key, t->size_index);
+ i -= c;
+ if (i < 0)
+ i += table_size[t->size_index];
+ }
+ while (t->table[i].valid && !t->table[i].dirty);
+ if (!t->table[i].dirty)
+ t->used++;
+ t->table[i].valid = 1;
+ t->table[i].dirty = 0;
+ t->table[i].key = key;
+ t->table[i].dsize = dsize;
+ t->table[i].data = data;
+}
+
+static void hashtable_rebuild (hashtable_t *t, int dir)
+{
+ int i, old_index;
+ hashnode_t *old;
+
+ old = t->table;
+ old_index = t->size_index;
+ switch (dir)
+ {
+ case -1:
+ t->size_index = t->size_index ? t->size_index - 1 : 0;
+ break;
+ case 0:
+ break;
+ case 1:
+ t->size_index++;
+ break;
+ default:
+ return;
+ }
+
+ t->used = t->dirty = 0;
+ t->table = (hashnode_t *) malloc (sizeof (hashnode_t) *
+ table_size[t->size_index]);
+ for (i = 0; i < table_size[t->size_index]; i++)
+ t->table[i].valid = t->table[i].dirty = 0;
+ for (i = 0; i < table_size[old_index]; i++)
+ if (old[i].valid && !old[i].dirty)
+ hashtable_insert (t, old[i].key, old[i].data, old[i].dsize);
+ free (old);
+}
+
+void *hashtable_lookup (hashtable_t *t, int key, int *dsize)
+{
+ int i, c;
+
+ i = hash (key, t->size_index);
+ while (t->table[i].valid)
+ {
+ if ((t->table[i].key == key) && !t->table[i].dirty)
+ {
+ if (dsize != NULL)
+ *dsize = t->table[i].dsize;
+ return t->table[i].data;
+ }
+ c = rehash (key, t->size_index);
+ i -= c;
+ if (i < 0)
+ i += table_size[t->size_index];
+ }
+ if (dsize != NULL)
+ *dsize = 0;
+ return NULL;
+}
+
+void *hashtable_remove (hashtable_t *t, int key, int *dsize)
+{
+ int i, c;
+ void *temp;
+
+ i = hash (key, t->size_index);
+ while (t->table[i].valid)
+ {
+ if ((t->table[i].key == key) && !t->table[i].dirty)
+ {
+ if (dsize != NULL)
+ *dsize = t->table[i].dsize;
+ temp = t->table[i].data;
+ t->table[i].dirty = 1;
+ t->dirty++;
+ if ((t->dirty > ((1 - t->max_load) *
+ table_size[t->size_index])) && t->size_index)
+ hashtable_rebuild (t, -1);
+ return temp;
+ }
+ c = rehash (key, t->size_index);
+ i -= c;
+ if (i < 0)
+ i += table_size[t->size_index];
+ }
+ if (dsize != NULL)
+ *dsize = 0;
+ return NULL;
+}
+
+/*
+void hashtable_print (hashtable_t *t)
+{
+ int i;
+
+ printf ("used: %d\ndirty: %d\n\n", t->used, t->dirty);
+ for (i = 0; i < table_size[t->size_index]; i++)
+ printf ("%3d: %d %d %3d %3d %3d\n", i, t->table[i].valid,
+ t->table[i].dirty, t->table[i].key,
+ t->table[i].data, t->table[i].dsize);
+}
+*/
+
diff --git a/lib/libblt/namer.cpp b/lib/libblt/namer.cpp
@@ -0,0 +1,52 @@
+/* Copyright 1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <blt/Connection.h>
+#include <blt/Message.h>
+#include <blt/namer.h>
+#include <blt/syscall.h>
+
+#include <string.h>
+
+using namespace BLT;
+
+int namer_register(int port, const char *name)
+{
+ int32 res = -1;
+ Connection *cnxn = Connection::FindService("namer");
+
+ if(cnxn){
+ Message msg;
+ msg.PutInt32('code',NAMER_REGISTER);
+ msg.PutInt32('port',port);
+ msg.PutString('name',name);
+ cnxn->Call(&msg,&msg);
+ msg.GetInt32('resp',&res);
+ delete cnxn;
+ }
+
+ return res;
+}
+
+int namer_find(const char *name, int blocking)
+{
+ int32 res = -1;
+ Connection *cnxn;
+
+ cnxn = Connection::FindService("namer");
+
+ if(cnxn){
+ Message msg;
+ msg.PutInt32('code',NAMER_FIND);
+ msg.PutString('name',name);
+ cnxn->Call(&msg,&msg);
+ msg.GetInt32('resp',&res);
+ delete cnxn;
+ }
+
+ return res;
+}
+
+
+
diff --git a/lib/libblt/tell.c b/lib/libblt/tell.c
@@ -0,0 +1,56 @@
+/* Copyright 1999, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <blt/syscall.h>
+#include <blt/libsyms.h>
+#include <blt/namer.h>
+#include <blt/tell.h>
+
+static char *name;
+static volatile int ready = 0;
+static void (*callback)(const char *);
+
+weak_alias (_tell_init, tell_init)
+
+void __tell_impl (void)
+{
+ char *buf, junk;
+ int port, len;
+ msg_hdr_t mh;
+
+ port = port_create (0, "tell_listen_port");
+ buf = malloc (len = TELL_MAX_LEN);
+ strlcpy (buf, name, len);
+ strlcat (buf, ":tell", len);
+ namer_register (port, buf);
+ ready = 1;
+
+ for (;;)
+ {
+ mh.src = 0;
+ mh.dst = port;
+ mh.data = buf;
+ mh.size = len;
+ old_port_recv (&mh);
+ (*callback) (buf);
+ mh.dst = mh.src;
+ mh.src = port;
+ mh.data = &junk;
+ mh.size = 1;
+ old_port_send (&mh);
+ }
+}
+
+int _tell_init (char *n, void (*c)(const char *))
+{
+ name = n;
+ callback = c;
+ os_thread (__tell_impl);
+ while (!ready) ;
+ return ready;
+}
+
diff --git a/lib/libc/Makefile b/lib/libc/Makefile
@@ -0,0 +1,19 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+MINIMAL = string.o snprintf.o strcmp.o strcpy.o strlen.o strlcat.o strlcpy.o
+EXTRA = malloc.o memory.o errno.o qsort.o stdlib.o ctype.o \
+ qsem.o atomic.o syscalls.o cppglue.o
+
+TARGETS := libkern.a
+LIBRARY := libc.a
+SHLIB := libc.so
+SHLIB_MAJOR := 1
+SHLIB_MINOR := 0
+OBJS := $(MINIMAL) $(EXTRA)
+
+libkern.a: $(MINIMAL)
+ @rm -f libkern.a
+ $(AR) r libkern.a $(MINIMAL)
+
+include $(BLTHOME)make.actions
diff --git a/lib/libc/atomic.S b/lib/libc/atomic.S
@@ -0,0 +1,45 @@
+/* $Id: //depot/blt/lib/libc/atomic.S#1 $
+**
+** Copyright 1999 Jeff Bush
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+.globl atomic_add
+
+# long atomic_add(long *var, long amount)
+
+atomic_add:
+ pushl %ebx
+ movl 8(%esp), %ecx # pointer to variable
+try_add:
+ movl (%ecx), %eax # get original value
+ movl 12(%esp), %ebx # get amount to add
+ addl %eax, %ebx # what result should be
+ lock
+ cmpxchg %ebx, (%ecx)
+ jne try_add # failed, try again
+ popl %ebx
+ ret
+
diff --git a/lib/libc/cppglue.cpp b/lib/libc/cppglue.cpp
@@ -0,0 +1,33 @@
+#include <stdlib.h>
+
+void* operator new(size_t size)
+{
+ return malloc(size);
+}
+
+void operator delete(void *ptr)
+{
+ free(ptr);
+}
+
+void* operator new[](size_t size)
+{
+ return malloc(size);
+}
+
+void operator delete[](void *ptr)
+{
+ free(ptr);
+}
+
+extern "C" {
+void __pure_virtual();
+}
+
+/*
+ * This needs to do something a little more useful!
+ */
+void __pure_virtual()
+{
+ *((char*) 0) = 0;
+}
diff --git a/lib/libc/ctype.c b/lib/libc/ctype.c
@@ -0,0 +1,38 @@
+/* $Id: //depot/blt/lib/libc/ctype.c#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <ctype.h>
+#include <blt/libsyms.h>
+
+weak_alias (_isdigit, isdigit)
+
+int _isdigit (int c)
+{
+ return ((c >= '0') && (c <= '9')) ? 1 : 0;
+}
+
diff --git a/lib/libc/errno.c b/lib/libc/errno.c
@@ -0,0 +1,56 @@
+/* $Id: //depot/blt/lib/libc/errno.c#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include <stddef.h>
+#include <errno.h>
+#include <blt/libsyms.h>
+
+int errno;
+
+static char *msgs[] =
+{
+ NULL,
+ "permission denied",
+ "no such file or directory",
+ "no such process",
+ "interrupted system call",
+ "i/o error",
+ "device not configured",
+ "argument list too long",
+ "exec format error"
+};
+
+weak_alias (_strerror, strerror)
+
+char *_strerror (int errnum)
+{
+ return (errnum < (sizeof (msgs) / sizeof (char *))) ? msgs[errnum] :
+ NULL;
+}
+
diff --git a/lib/libc/malloc.c b/lib/libc/malloc.c
@@ -0,0 +1,2878 @@
+/* $Id: //depot/blt/lib/malloc.c#2 $ */
+
+/* ---------- To make a malloc.h, start cutting here ------------ */
+
+/*
+ A version of malloc/free/realloc written by Doug Lea and released to the
+ public domain. Send questions/comments/complaints/performance data
+ to dl@cs.oswego.edu
+
+* VERSION 2.6.5 Wed Jun 17 15:55:16 1998 Doug Lea (dl at gee)
+
+ Note: There may be an updated version of this malloc obtainable at
+ ftp://g.oswego.edu/pub/misc/malloc.c
+ Check before installing!
+
+ Note: This version differs from 2.6.4 only by correcting a
+ statement ordering error that could cause failures only
+ when calls to this malloc are interposed with calls to
+ other memory allocators.
+
+* Why use this malloc?
+
+ This is not the fastest, most space-conserving, most portable, or
+ most tunable malloc ever written. However it is among the fastest
+ while also being among the most space-conserving, portable and tunable.
+ Consistent balance across these factors results in a good general-purpose
+ allocator. For a high-level description, see
+ http://g.oswego.edu/dl/html/malloc.html
+
+* Synopsis of public routines
+
+ (Much fuller descriptions are contained in the program documentation below.)
+
+ malloc(size_t n);
+ Return a pointer to a newly allocated chunk of at least n bytes, or null
+ if no space is available.
+ free(Void_t* p);
+ Release the chunk of memory pointed to by p, or no effect if p is null.
+ realloc(Void_t* p, size_t n);
+ Return a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available. The returned pointer may or may not be
+ the same as p. If p is null, equivalent to malloc. Unless the
+ #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+ memalign(size_t alignment, size_t n);
+ Return a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument, which must be a power of
+ two.
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system (or as near to this as can be figured out from
+ all the includes/defines below.)
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ calloc(size_t unit, size_t quantity);
+ Returns a pointer to quantity * unit bytes, with all locations
+ set to zero.
+ cfree(Void_t* p);
+ Equivalent to free(p).
+ malloc_trim(size_t pad);
+ Release all but pad bytes of freed top-most memory back
+ to the system. Return 1 if successful, else 0.
+ malloc_usable_size(Void_t* p);
+ Report the number usable allocated bytes associated with allocated
+ chunk p. This may or may not report more bytes than were requested,
+ due to alignment and minimum size constraints.
+ malloc_stats();
+ Prints brief summary statistics on stderr.
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics.
+ mallopt(int parameter_number, int parameter_value)
+ Changes one of the tunable parameters described below. Returns
+ 1 if successful in changing the parameter, else 0.
+
+* Vital statistics:
+
+ Alignment: 8-byte
+ 8 byte alignment is currently hardwired into the design. This
+ seems to suffice for all current machines and C compilers.
+
+ Assumed pointer representation: 4 or 8 bytes
+ Code for 8-byte pointers is untested by me but has worked
+ reliably by Wolfram Gloger, who contributed most of the
+ changes supporting this.
+
+ Assumed size_t representation: 4 or 8 bytes
+ Note that size_t is allowed to be 4 bytes even if pointers are 8.
+
+ Minimum overhead per allocated chunk: 4 or 8 bytes
+ Each malloced chunk has a hidden overhead of 4 bytes holding size
+ and status information.
+
+ Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead)
+ 8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
+
+ When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+ ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+ needed; 4 (8) for a trailing size field
+ and 8 (16) bytes for free list pointers. Thus, the minimum
+ allocatable size is 16/24/32 bytes.
+
+ Even a request for zero bytes (i.e., malloc(0)) returns a
+ pointer to something of the minimum allocatable size.
+
+ Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes
+ 8-byte size_t: 2^63 - 16 bytes
+
+ It is assumed that (possibly signed) size_t bit values suffice to
+ represent chunk sizes. `Possibly signed' is due to the fact
+ that `size_t' may be defined on a system as either a signed or
+ an unsigned type. To be conservative, values that would appear
+ as negative numbers are avoided.
+ Requests for sizes with a negative sign bit will return a
+ minimum-sized chunk.
+
+ Maximum overhead wastage per allocated chunk: normally 15 bytes
+
+ Alignnment demands, plus the minimum allocatable size restriction
+ make the normal worst-case wastage 15 bytes (i.e., up to 15
+ more bytes will be allocated than were requested in malloc), with
+ two exceptions:
+ 1. Because requests for zero bytes allocate non-zero space,
+ the worst case wastage for a request of zero bytes is 24 bytes.
+ 2. For requests >= mmap_threshold that are serviced via
+ mmap(), the worst case wastage is 8 bytes plus the remainder
+ from a system page (the minimal mmap unit); typically 4096 bytes.
+
+* Limitations
+
+ Here are some features that are NOT currently supported
+
+ * No user-definable hooks for callbacks and the like.
+ * No automated mechanism for fully checking that all accesses
+ to malloced memory stay within their bounds.
+ * No support for compaction.
+
+* Synopsis of compile-time options:
+
+ People have reported using previous versions of this malloc on all
+ versions of Unix, sometimes by tweaking some of the defines
+ below. It has been tested most extensively on Solaris and
+ Linux. It is also reported to work on WIN32 platforms.
+ People have also reported adapting this malloc for use in
+ stand-alone embedded systems.
+
+ The implementation is in straight, hand-tuned ANSI C. Among other
+ consequences, it uses a lot of macros. Because of this, to be at
+ all usable, this code should be compiled using an optimizing compiler
+ (for example gcc -O2) that can simplify expressions and control
+ paths.
+
+ __STD_C (default: derived from C compiler defines)
+ Nonzero if using ANSI-standard C compiler, a C++ compiler, or
+ a C compiler sufficiently close to ANSI to get away with it.
+ DEBUG (default: NOT defined)
+ Define to enable debugging. Adds fairly extensive assertion-based
+ checking to help track down memory errors, but noticeably slows down
+ execution.
+ REALLOC_ZERO_BYTES_FREES (default: NOT defined)
+ Define this if you think that realloc(p, 0) should be equivalent
+ to free(p). Otherwise, since malloc returns a unique pointer for
+ malloc(0), so does realloc(p, 0).
+ HAVE_MEMCPY (default: defined)
+ Define if you are not otherwise using ANSI STD C, but still
+ have memcpy and memset in your C library and want to use them.
+ Otherwise, simple internal versions are supplied.
+ USE_MEMCPY (default: 1 if HAVE_MEMCPY is defined, 0 otherwise)
+ Define as 1 if you want the C library versions of memset and
+ memcpy called in realloc and calloc (otherwise macro versions are used).
+ At least on some platforms, the simple macro versions usually
+ outperform libc versions.
+ HAVE_MMAP (default: defined as 1)
+ Define to non-zero to optionally make malloc() use mmap() to
+ allocate very large blocks.
+ HAVE_MREMAP (default: defined as 0 unless Linux libc set)
+ Define to non-zero to optionally make realloc() use mremap() to
+ reallocate very large blocks.
+ malloc_getpagesize (default: derived from system #includes)
+ Either a constant or routine call returning the system page size.
+ HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined)
+ Optionally define if you are on a system with a /usr/include/malloc.h
+ that declares struct mallinfo. It is not at all necessary to
+ define this even if you do, but will ensure consistency.
+ INTERNAL_SIZE_T (default: size_t)
+ Define to a 32-bit type (probably `unsigned int') if you are on a
+ 64-bit machine, yet do not want or need to allow malloc requests of
+ greater than 2^31 to be handled. This saves space, especially for
+ very small chunks.
+ INTERNAL_LINUX_C_LIB (default: NOT defined)
+ Defined only when compiled as part of Linux libc.
+ Also note that there is some odd internal name-mangling via defines
+ (for example, internally, `malloc' is named `mALLOc') needed
+ when compiling in this case. These look funny but don't otherwise
+ affect anything.
+ WIN32 (default: undefined)
+ Define this on MS win (95, nt) platforms to compile in sbrk emulation.
+ LACKS_UNISTD_H (default: undefined)
+ Define this if your system does not have a <unistd.h>.
+ MORECORE (default: sbrk)
+ The name of the routine to call to obtain more memory from the system.
+ MORECORE_FAILURE (default: -1)
+ The value returned upon failure of MORECORE.
+ MORECORE_CLEARS (default 1)
+ True (1) if the routine mapped to MORECORE zeroes out memory (which
+ holds for sbrk).
+ DEFAULT_TRIM_THRESHOLD
+ DEFAULT_TOP_PAD
+ DEFAULT_MMAP_THRESHOLD
+ DEFAULT_MMAP_MAX
+ Default values of tunable parameters (described in detail below)
+ controlling interaction with host system routines (sbrk, mmap, etc).
+ These values may also be changed dynamically via mallopt(). The
+ preset defaults are those that give best performance for typical
+ programs/systems.
+
+
+*/
+
+/* Preliminaries */
+
+#ifndef __STD_C
+#ifdef __STDC__
+#define __STD_C 1
+#else
+#if __cplusplus
+#define __STD_C 1
+#else
+#define __STD_C 0
+#endif /*__cplusplus*/
+#endif /*__STDC__*/
+#endif /*__STD_C*/
+
+#ifndef Void_t
+#if __STD_C
+#define Void_t void
+#else
+#define Void_t char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h> /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h> /* needed for malloc_stats */
+
+/*
+ Compile-time options
+*/
+
+/*
+ Debugging:
+
+ Because freed chunks may be overwritten with link fields, this
+ malloc will often die when freed memory is overwritten by user
+ programs. This can be very effective (albeit in an annoying way)
+ in helping track down dangling pointers.
+
+ If you compile with -DDEBUG, a number of assertion checks are
+ enabled that will catch more memory errors. You probably won't be
+ able to make much sense of the actual assertion errors, but they
+ should help you locate incorrectly overwritten memory. The
+ checking is fairly extensive, and will slow down execution
+ noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+ attempt to check every non-mmapped allocated and free chunk in the
+ course of computing the summmaries. (By nature, mmapped regions
+ cannot be checked very much automatically.)
+
+ Setting DEBUG may also be helpful if you are trying to modify
+ this code. The assertions in the check routines spell out in more
+ detail the assumptions and invariants underlying the algorithms.
+
+*/
+
+#if DEBUG
+#include <assert.h>
+#else
+#define assert(x) ((void)0)
+#endif
+
+/*
+ INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+ of chunk sizes. On a 64-bit machine, you can reduce malloc
+ overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
+ at the expense of not being able to handle requests greater than
+ 2^31. This limitation is hardly ever a concern; you are encouraged
+ to set this. However, the default version is the same as size_t.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/*
+ REALLOC_ZERO_BYTES_FREES should be set if a call to
+ realloc with zero bytes should be the same as a call to free.
+ Some people think it should. Otherwise, since this malloc
+ returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+
+/* #define REALLOC_ZERO_BYTES_FREES */
+
+/*
+ HAVE_MEMCPY should be defined if you are not otherwise using
+ ANSI STD C, but still have memcpy and memset in your C library
+ and want to use them in calloc and realloc. Otherwise simple
+ macro versions are defined here.
+
+ USE_MEMCPY should be defined as 1 if you actually want to
+ have memset and memcpy called. People report that the macro
+ versions are often enough faster than libc versions on many
+ systems that it is better to use them.
+
+*/
+
+#define HAVE_MEMCPY
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+
+#if USE_MEMCPY
+
+/* The following macros are only invoked with (2n+1)-multiples of
+ INTERNAL_SIZE_T units, with a positive integer n. This is exploited
+ for fast inline execution when n is small. */
+
+#define MALLOC_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T mzsz = (nbytes); \
+ if(mzsz <= 9*sizeof(mzsz)) { \
+ INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \
+ if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; \
+ if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; \
+ if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; }}} \
+ *mz++ = 0; \
+ *mz++ = 0; \
+ *mz = 0; \
+ } else memset((charp), 0, mzsz); \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T mcsz = (nbytes); \
+ if(mcsz <= 9*sizeof(mcsz)) { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \
+ if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; }}} \
+ *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ *mcdst = *mcsrc ; \
+ } else memcpy(dest, src, mcsz); \
+} while(0)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \
+ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mzp++ = 0; \
+ case 7: *mzp++ = 0; \
+ case 6: *mzp++ = 0; \
+ case 5: *mzp++ = 0; \
+ case 4: *mzp++ = 0; \
+ case 3: *mzp++ = 0; \
+ case 2: *mzp++ = 0; \
+ case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \
+ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mcdst++ = *mcsrc++; \
+ case 7: *mcdst++ = *mcsrc++; \
+ case 6: *mcdst++ = *mcsrc++; \
+ case 5: *mcdst++ = *mcsrc++; \
+ case 4: *mcdst++ = *mcsrc++; \
+ case 3: *mcdst++ = *mcsrc++; \
+ case 2: *mcdst++ = *mcsrc++; \
+ case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#endif
+
+/*
+ Define HAVE_MMAP to optionally make malloc() use mmap() to
+ allocate very large blocks. These will be returned to the
+ operating system immediately after a free().
+*/
+
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 0
+#endif
+
+/*
+ Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+ large blocks. This is currently only possible on Linux with
+ kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#ifdef INTERNAL_LINUX_C_LIB
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+#endif
+
+#if HAVE_MMAP
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#endif /* HAVE_MMAP */
+
+/*
+ Access to system page size. To the extent possible, this malloc
+ manages memory from the system in page-size units.
+
+ The following mechanics for getpagesize were adapted from
+ bsd/gnu getpagesize.h
+*/
+
+#ifndef LACKS_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if 0
+#ifndef malloc_getpagesize
+# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
+# ifndef _SC_PAGE_SIZE
+# define _SC_PAGE_SIZE _SC_PAGESIZE
+# endif
+# endif
+# ifdef _SC_PAGE_SIZE
+# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+# else
+# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+ extern size_t getpagesize();
+# define malloc_getpagesize getpagesize()
+# else
+# include <sys/param.h>
+# ifdef EXEC_PAGESIZE
+# define malloc_getpagesize EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# ifndef CLSIZE
+# define malloc_getpagesize NBPG
+# else
+# define malloc_getpagesize (NBPG * CLSIZE)
+# endif
+# else
+# ifdef NBPC
+# define malloc_getpagesize NBPC
+# else
+# ifdef PAGESIZE
+# define malloc_getpagesize PAGESIZE
+# else
+# define malloc_getpagesize (4096) /* just guess */
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+#endif
+
+#define malloc_getpagesize (0x1000)
+
+/*
+
+ This version of malloc supports the standard SVID/XPG mallinfo
+ routine that returns a struct containing the same kind of
+ information you can get from malloc_stats. It should work on
+ any SVID/XPG compliant system that has a /usr/include/malloc.h
+ defining struct mallinfo. (If you'd like to install such a thing
+ yourself, cut out the preliminary declarations as described above
+ and below and save them in a malloc.h file. But there's no
+ compelling reason to bother to do this.)
+
+ The main declaration needed is the mallinfo struct that is returned
+ (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a
+ bunch of fields, most of which are not even meaningful in this
+ version of malloc. Some of these fields are are instead filled by
+ mallinfo() with other numbers that might possibly be of interest.
+
+ HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+ /usr/include/malloc.h file that includes a declaration of struct
+ mallinfo. If so, it is included; else an SVID2/XPG2 compliant
+ version is declared below. These must be precisely the same for
+ mallinfo() to work.
+
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#if HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+ int arena; /* total space allocated from system */
+ int ordblks; /* number of non-inuse chunks */
+ int smblks; /* unused -- always zero */
+ int hblks; /* number of mmapped regions */
+ int hblkhd; /* total space in mmapped regions */
+ int usmblks; /* unused -- always zero */
+ int fsmblks; /* unused -- always zero */
+ int uordblks; /* total allocated space */
+ int fordblks; /* total non-inuse space */
+ int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/* SVID2/XPG mallopt options */
+
+#define M_MXFAST 1 /* UNUSED in this malloc */
+#define M_NLBLKS 2 /* UNUSED in this malloc */
+#define M_GRAIN 3 /* UNUSED in this malloc */
+#define M_KEEP 4 /* UNUSED in this malloc */
+
+#endif
+
+/* mallopt options that actually do something */
+
+#define M_TRIM_THRESHOLD -1
+#define M_TOP_PAD -2
+#define M_MMAP_THRESHOLD -3
+#define M_MMAP_MAX -4
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+ M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+ to keep before releasing via malloc_trim in free().
+
+ Automatic trimming is mainly useful in long-lived programs.
+ Because trimming via sbrk can be slow on some systems, and can
+ sometimes be wasteful (in cases where programs immediately
+ afterward allocate more large chunks) the value should be high
+ enough so that your overall system performance would improve by
+ releasing.
+
+ The trim threshold and the mmap control parameters (see below)
+ can be traded off with one another. Trimming and mmapping are
+ two different ways of releasing unused memory back to the
+ system. Between these two, it is often possible to keep
+ system-level demands of a long-lived program down to a bare
+ minimum. For example, in one test suite of sessions measuring
+ the XF86 X server on Linux, using a trim threshold of 128K and a
+ mmap threshold of 192K led to near-minimal long term resource
+ consumption.
+
+ If you are using this malloc in a long-lived program, it should
+ pay to experiment with these values. As a rough guide, you
+ might set to a value close to the average size of a process
+ (program) running on your system. Releasing this much memory
+ would allow such a process to run in memory. Generally, it's
+ worth it to tune for trimming rather tham memory mapping when a
+ program undergoes phases where several large chunks are
+ allocated and released in ways that can reuse each other's
+ storage, perhaps mixed with phases where there are no such
+ chunks at all. And in well-behaved long-lived programs,
+ controlling release of large blocks via trimming versus mapping
+ is usually faster.
+
+ However, in most programs, these parameters serve mainly as
+ protection against the system-level effects of carrying around
+ massive amounts of unneeded memory. Since frequent calls to
+ sbrk, mmap, and munmap otherwise degrade performance, the default
+ parameters are set to relatively high values that serve only as
+ safeguards.
+
+ The default trim value is high enough to cause trimming only in
+ fairly extreme (by current memory consumption standards) cases.
+ It must be greater than page size to have any useful effect. To
+ disable trimming completely, you can set to (unsigned long)(-1);
+*/
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD (0)
+#endif
+
+/*
+ M_TOP_PAD is the amount of extra `padding' space to allocate or
+ retain whenever sbrk is called. It is used in two ways internally:
+
+ * When sbrk is called to extend the top of the arena to satisfy
+ a new malloc request, this much padding is added to the sbrk
+ request.
+
+ * When malloc_trim is called automatically from free(),
+ it is used as the `pad' argument.
+
+ In both cases, the actual amount of padding is rounded
+ so that the end of the arena is always a system page boundary.
+
+ The main reason for using padding is to avoid calling sbrk so
+ often. Having even a small pad greatly reduces the likelihood
+ that nearly every malloc request during program start-up (or
+ after trimming) will invoke sbrk, which needlessly wastes
+ time.
+
+ Automatic rounding-up to page-size units is normally sufficient
+ to avoid measurable overhead, so the default is 0. However, in
+ systems where sbrk is relatively slow, it can pay to increase
+ this value, at the expense of carrying around more memory than
+ the program needs.
+
+*/
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+ M_MMAP_THRESHOLD is the request size threshold for using mmap()
+ to service a request. Requests of at least this size that cannot
+ be allocated using already-existing space will be serviced via mmap.
+ (If enough normal freed space already exists it is used instead.)
+
+ Using mmap segregates relatively large chunks of memory so that
+ they can be individually obtained and released from the host
+ system. A request serviced through mmap is never reused by any
+ other request (at least not directly; the system may just so
+ happen to remap successive requests to the same locations).
+
+ Segregating space in this way has the benefit that mmapped space
+ can ALWAYS be individually released back to the system, which
+ helps keep the system level memory demands of a long-lived
+ program low. Mapped memory can never become `locked' between
+ other chunks, as can happen with normally allocated chunks, which
+ menas that even trimming via malloc_trim would not release them.
+
+ However, it has the disadvantages that:
+
+ 1. The space cannot be reclaimed, consolidated, and then
+ used to service later requests, as happens with normal chunks.
+ 2. It can lead to more wastage because of mmap page alignment
+ requirements
+ 3. It causes malloc performance to be more dependent on host
+ system memory management support routines which may vary in
+ implementation quality and may impose arbitrary
+ limitations. Generally, servicing a request via normal
+ malloc steps is faster than going through a system's mmap.
+
+ All together, these considerations should lead you to use mmap
+ only for relatively large requests.
+*/
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+#define DEFAULT_MMAP_MAX (64)
+#else
+#define DEFAULT_MMAP_MAX (0)
+#endif
+#endif
+
+/*
+ M_MMAP_MAX is the maximum number of requests to simultaneously
+ service using mmap. This parameter exists because:
+
+ 1. Some systems have a limited number of internal tables for
+ use by mmap.
+ 2. In most systems, overreliance on mmap can degrade overall
+ performance.
+ 3. If a program allocates many large regions, it is probably
+ better off using normal sbrk-based allocation routines that
+ can reclaim and reallocate normal heap memory. Using a
+ small value allows transition into this mode after the
+ first few allocations.
+
+ Setting to 0 disables all use of mmap. If HAVE_MMAP is not set,
+ the default value is 0, and attempts to set it to non-zero values
+ in mallopt will fail.
+*/
+
+/*
+
+ Special defines for linux libc
+
+ Except when compiled using these special defines for Linux libc
+ using weak aliases, this malloc is NOT designed to work in
+ multithreaded applications. No semaphores or other concurrency
+ control are provided to ensure that multiple malloc or free calls
+ don't run at the same time, which could be disasterous. A single
+ semaphore could be used across malloc, realloc, and free (which is
+ essentially the effect of the linux weak alias approach). It would
+ be hard to obtain finer granularity.
+*/
+
+#ifdef INTERNAL_LINUX_C_LIB
+
+#if __STD_C
+
+Void_t * __default_morecore_init (ptrdiff_t);
+Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
+
+#else
+
+Void_t * __default_morecore_init ();
+Void_t *(*__morecore)() = __default_morecore_init;
+
+#endif
+
+#define MORECORE (*__morecore)
+#define MORECORE_FAILURE 0
+#define MORECORE_CLEARS 1
+
+#else /* INTERNAL_LINUX_C_LIB */
+
+#if __STD_C
+extern Void_t* sbrk(int ptrdiff_t);
+#else
+extern Void_t* sbrk();
+#endif
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE -1
+#endif
+
+#ifndef MORECORE_CLEARS
+#define MORECORE_CLEARS 1
+#endif
+
+#endif /* INTERNAL_LINUX_C_LIB */
+
+#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
+
+#define cALLOc __libc_calloc
+#define fREe __libc_free
+#define mALLOc __libc_malloc
+#define mEMALIGn __libc_memalign
+#define rEALLOc __libc_realloc
+#define vALLOc __libc_valloc
+#define pvALLOc __libc_pvalloc
+#define mALLINFo __libc_mallinfo
+#define mALLOPt __libc_mallopt
+
+#pragma weak calloc = __libc_calloc
+#pragma weak free = __libc_free
+#pragma weak cfree = __libc_free
+#pragma weak malloc = __libc_malloc
+#pragma weak memalign = __libc_memalign
+#pragma weak realloc = __libc_realloc
+#pragma weak valloc = __libc_valloc
+#pragma weak pvalloc = __libc_pvalloc
+#pragma weak mallinfo = __libc_mallinfo
+#pragma weak mallopt = __libc_mallopt
+
+#else
+
+
+#define cALLOc __calloc
+#define fREe __free
+#define mALLOc __malloc
+#define mEMALIGn __memalign
+#define rEALLOc __realloc
+#define vALLOc __valloc
+#define pvALLOc __pvalloc
+#define mALLINFo __mallinfo
+#define mALLOPt __mallopt
+
+#endif
+
+/* Public routines */
+
+#if __STD_C
+
+Void_t* mALLOc(size_t);
+void fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+Void_t* cALLOc(size_t, size_t);
+void cfree(Void_t*);
+int malloc_trim(size_t);
+size_t malloc_usable_size(Void_t*);
+void malloc_stats();
+int mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void fREe();
+Void_t* rEALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+Void_t* cALLOc();
+void cfree();
+int malloc_trim();
+size_t malloc_usable_size();
+void malloc_stats();
+int mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+/* ---------- To make a malloc.h, end cutting here ------------ */
+
+/*
+ Type declarations
+*/
+
+struct malloc_chunk
+{
+ INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk* mchunkptr;
+
+/*
+ malloc_chunk details:
+
+ (The following includes lightly edited explanations by Colin Plumb.)
+
+ Chunks of memory are maintained using a `boundary tag' method as
+ described in e.g., Knuth or Standish. (See the paper by Paul
+ Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+ survey of such techniques.) Sizes of free chunks are stored both
+ in the front of each chunk and at the end. This makes
+ consolidating fragmented chunks into bigger chunks very fast. The
+ size fields also hold bits representing whether chunks are free or
+ in use.
+
+ An allocated chunk looks like this:
+
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk, if allocated | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | User data starts here... .
+ . .
+ . (malloc_usable_space() bytes) .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+ Where "chunk" is the front of the chunk for the purpose of most of
+ the malloc code, but "mem" is the pointer that is returned to the
+ user. "Nextchunk" is the beginning of the next contiguous chunk.
+
+ Chunks always begin on even word boundries, so the mem portion
+ (which is returned to the user) is also on an even word boundary, and
+ thus double-word aligned.
+
+ Free chunks are stored in circular doubly-linked lists, and look like this:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space (may be 0 bytes long) .
+ . .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+ chunk size (which is always a multiple of two words), is an in-use
+ bit for the *previous* chunk. If that bit is *clear*, then the
+ word before the current chunk size contains the previous chunk
+ size, and can be used to find the front of the previous chunk.
+ (The very first chunk allocated always has this bit set,
+ preventing access to non-existent (or non-owned) memory.)
+
+ Note that the `foot' of the current chunk is actually represented
+ as the prev_size of the NEXT chunk. (This makes it easier to
+ deal with alignments etc).
+
+ The two exceptions to all this are
+
+ 1. The special chunk `top', which doesn't bother using the
+ trailing size field since there is no
+ next contiguous chunk that would have to index off it. (After
+ initialization, `top' is forced to always exist. If it would
+ become less than MINSIZE bytes long, it is replenished via
+ malloc_extend_top.)
+
+ 2. Chunks allocated via mmap, which have the second-lowest-order
+ bit (IS_MMAPPED) set in their size fields. Because they are
+ never merged or traversed from any other chunk, they have no
+ foot size or inuse information.
+
+ Available chunks are kept in any of several places (all declared below):
+
+ * `av': An array of chunks serving as bin headers for consolidated
+ chunks. Each bin is doubly linked. The bins are approximately
+ proportionally (log) spaced. There are a lot of these bins
+ (128). This may look excessive, but works very well in
+ practice. All procedures maintain the invariant that no
+ consolidated chunk physically borders another one. Chunks in
+ bins are kept in size order, with ties going to the
+ approximately least recently used chunk.
+
+ The chunks in each bin are maintained in decreasing sorted order by
+ size. This is irrelevant for the small bins, which all contain
+ the same-sized chunks, but facilitates best-fit allocation for
+ larger chunks. (These lists are just sequential. Keeping them in
+ order almost never requires enough traversal to warrant using
+ fancier ordered data structures.) Chunks of the same size are
+ linked with the most recently freed at the front, and allocations
+ are taken from the back. This results in LRU or FIFO allocation
+ order, which tends to give each chunk an equal opportunity to be
+ consolidated with adjacent freed chunks, resulting in larger free
+ chunks and less fragmentation.
+
+ * `top': The top-most available chunk (i.e., the one bordering the
+ end of available memory) is treated specially. It is never
+ included in any bin, is used only if no other chunk is
+ available, and is released back to the system if it is very
+ large (see M_TRIM_THRESHOLD).
+
+ * `last_remainder': A bin holding only the remainder of the
+ most recently split (non-top) chunk. This bin is checked
+ before other non-fitting chunks, so as to provide better
+ locality for runs of sequentially allocated chunks.
+
+ * Implicitly, through the host system's memory mapping tables.
+ If supported, requests greater than a threshold are usually
+ serviced via calls to mmap, and then later released via munmap.
+
+*/
+
+/* sizes, alignments */
+
+#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
+#define MALLOC_ALIGNMENT (SIZE_SZ + SIZE_SZ)
+#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
+#define MINSIZE (sizeof(struct malloc_chunk))
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+/* pad request bytes into a usable size */
+
+#define request2size(req) \
+ (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \
+ (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \
+ (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+/*
+ Physical chunk operations
+*/
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+
+#define PREV_INUSE 0x1
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+
+#define IS_MMAPPED 0x2
+
+/* Bits to mask off when extracting size */
+
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+/* Ptr to next physical malloc_chunk. */
+
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+
+#define prev_chunk(p)\
+ ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+/* Treat space at ptr + offset as a chunk */
+
+#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+
+/*
+ Dealing with use bits
+*/
+
+/* extract p's inuse bit */
+
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* extract inuse bit of previous chunk */
+
+#define prev_inuse(p) ((p)->size & PREV_INUSE)
+
+/* check for mmap()'ed chunk */
+
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+/* set/clear chunk as in use without otherwise disturbing */
+
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+/* check/set/clear inuse bits in known places */
+
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+/*
+ Dealing with size fields
+*/
+
+/* Get size, ignoring use bits */
+
+#define chunksize(p) ((p)->size & ~(SIZE_BITS))
+
+/* Set size at head, without disturbing its use bit */
+
+#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use ignoring previous bits in header */
+
+#define set_head(p, s) ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+
+#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+/*
+ Bins
+
+ The bins, `av_' are an array of pairs of pointers serving as the
+ heads of (initially empty) doubly-linked lists of chunks, laid out
+ in a way so that each pair can be treated as if it were in a
+ malloc_chunk. (This way, the fd/bk offsets for linking bin heads
+ and chunks are the same).
+
+ Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+ 8 bytes apart. Larger bins are approximately logarithmically
+ spaced. (See the table below.) The `av_' array is never mentioned
+ directly in the code, but instead via bin access macros.
+
+ Bin layout:
+
+ 64 bins of size 8
+ 32 bins of size 64
+ 16 bins of size 512
+ 8 bins of size 4096
+ 4 bins of size 32768
+ 2 bins of size 262144
+ 1 bin of size what's left
+
+ There is actually a little bit of slop in the numbers in bin_index
+ for the sake of speed. This makes no difference elsewhere.
+
+ The special chunks `top' and `last_remainder' get their own bins,
+ (this is implemented via yet more trickery with the av_ array),
+ although `top' is never properly linked to its bin since it is
+ always handled specially.
+
+*/
+
+#define NAV 128 /* number of bins */
+
+typedef struct malloc_chunk* mbinptr;
+
+/* access macros */
+
+#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
+#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
+#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
+
+/*
+ The first 2 bins are never indexed. The corresponding av_ cells are instead
+ used for bookkeeping. This is not to save space, but to simplify
+ indexing, maintain locality, and avoid some initialization tests.
+*/
+
+#define top (bin_at(0)->fd) /* The topmost chunk */
+#define last_remainder (bin_at(1)) /* remainder from last split */
+
+/*
+ Because top initially points to its own bin with initial
+ zero size, thus forcing extension on the first malloc request,
+ we avoid having any special code in malloc to check whether
+ it even exists yet. But we still need to in malloc_extend_top.
+*/
+
+#define initial_top ((mchunkptr)(bin_at(0)))
+
+/* Helper macro to initialize bins */
+
+#define IAV(i) bin_at(i), bin_at(i)
+
+static mbinptr av_[NAV * 2 + 2] = {
+ 0, 0,
+ IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7),
+ IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15),
+ IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23),
+ IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31),
+ IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39),
+ IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47),
+ IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55),
+ IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63),
+ IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71),
+ IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79),
+ IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87),
+ IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95),
+ IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103),
+ IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
+ IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
+ IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
+};
+
+/* field-extraction macros */
+
+#define first(b) ((b)->fd)
+#define last(b) ((b)->bk)
+
+/*
+ Indexing into bins
+*/
+
+#define bin_index(sz) \
+(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \
+ ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \
+ ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \
+ ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \
+ ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \
+ ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \
+ 126)
+/*
+ bins for chunks < 512 are all spaced 8 bytes apart, and hold
+ identically sized chunks. This is exploited in malloc.
+*/
+
+#define MAX_SMALLBIN 63
+#define MAX_SMALLBIN_SIZE 512
+#define SMALLBIN_WIDTH 8
+
+#define smallbin_index(sz) (((unsigned long)(sz)) >> 3)
+
+/*
+ Requests are `small' if both the corresponding and the next bin are small
+*/
+
+#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
+
+/*
+ To help compensate for the large number of bins, a one-level index
+ structure is used for bin-by-bin searching. `binblocks' is a
+ one-word bitvector recording whether groups of BINBLOCKWIDTH bins
+ have any (possibly) non-empty bins, so they can be skipped over
+ all at once during during traversals. The bits are NOT always
+ cleared as soon as all bins in a block are empty, but instead only
+ when all are noticed to be empty during traversal in malloc.
+*/
+
+#define BINBLOCKWIDTH 4 /* bins per block */
+
+#define binblocks (bin_at(0)->size) /* bitvector of nonempty blocks */
+
+/* bin<->block macros */
+
+#define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH))
+#define mark_binblock(ii) (binblocks |= idx2binblock(ii))
+#define clear_binblock(ii) (binblocks &= ~(idx2binblock(ii)))
+
+/* Other static bookkeeping data */
+
+/* variables holding tunable values */
+
+static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD;
+static unsigned long top_pad = DEFAULT_TOP_PAD;
+static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX;
+static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+
+/* The first value returned from sbrk */
+static char* sbrk_base = (char*)(-1);
+
+/* The maximum memory obtained from system via sbrk */
+static unsigned long max_sbrked_mem = 0;
+
+/* The maximum via either sbrk or mmap */
+static unsigned long max_total_mem = 0;
+
+/* internal working copy of mallinfo */
+static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* The total memory obtained from system via sbrk */
+#define sbrked_mem (current_mallinfo.arena)
+
+/* Tracking mmaps */
+
+static unsigned int n_mmaps = 0;
+static unsigned long mmapped_mem = 0;
+
+/*
+ Debugging support
+*/
+
+#if DEBUG
+
+/*
+ These routines make a number of assertions about the states
+ of data structures that should be true at all times. If any
+ are not true, it's very likely that a user program has somehow
+ trashed memory. (It's also possible that there is a coding error
+ in malloc. In which case, please report it!)
+*/
+
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+
+ /* No checkable chunk is mmapped */
+ assert(!chunk_is_mmapped(p));
+
+ /* Check for legal address ... */
+ assert((char*)p >= sbrk_base);
+ if (p != top)
+ assert((char*)p + sz <= (char*)top);
+ else
+ assert((char*)p + sz <= sbrk_base + sbrked_mem);
+}
+
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+ mchunkptr next = chunk_at_offset(p, sz);
+
+ do_check_chunk(p);
+
+ /* Check whether it claims to be free ... */
+ assert(!inuse(p));
+
+ /* Unless a special marker, must have OK fields */
+ if ((long)sz >= (long)MINSIZE)
+ {
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert(aligned_OK(chunk2mem(p)));
+ /* ... matching footer field */
+ assert(next->prev_size == sz);
+ /* ... and is fully consolidated */
+ assert(prev_inuse(p));
+ assert (next == top || inuse(next));
+
+ /* ... and has minimally sane links */
+ assert(p->fd->bk == p);
+ assert(p->bk->fd == p);
+ }
+ else /* markers are always of size SIZE_SZ */
+ assert(sz == SIZE_SZ);
+}
+
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+ mchunkptr next = next_chunk(p);
+ do_check_chunk(p);
+
+ /* Check whether it claims to be in use ... */
+ assert(inuse(p));
+
+ /* ... and is surrounded by OK chunks.
+ Since more things can be checked with free chunks than inuse ones,
+ if an inuse chunk borders them and debug is on, it's worth doing them.
+ */
+ if (!prev_inuse(p))
+ {
+ mchunkptr prv = prev_chunk(p);
+ assert(next_chunk(prv) == p);
+ do_check_free_chunk(prv);
+ }
+ if (next == top)
+ {
+ assert(prev_inuse(next));
+ assert(chunksize(next) >= MINSIZE);
+ }
+ else if (!inuse(next))
+ do_check_free_chunk(next);
+}
+
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+ long room = sz - s;
+
+ do_check_inuse_chunk(p);
+
+ /* Legal size ... */
+ assert((long)sz >= (long)MINSIZE);
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert(room >= 0);
+ assert(room < (long)MINSIZE);
+
+ /* ... and alignment */
+ assert(aligned_OK(chunk2mem(p)));
+
+ /* ... and was allocated at front of an available chunk */
+ assert(prev_inuse(p));
+}
+
+#define check_free_chunk(P) do_check_free_chunk(P)
+#define check_inuse_chunk(P) do_check_inuse_chunk(P)
+#define check_chunk(P) do_check_chunk(P)
+#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
+#else
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_chunk(P)
+#define check_malloced_chunk(P,N)
+#endif
+
+/*
+ Macro-based internal utilities
+*/
+
+/*
+ Linking chunks in bin lists.
+ Call these only with variables, not arbitrary expressions, as arguments.
+*/
+
+/*
+ Place chunk p of size s in its bin, in size order,
+ putting it ahead of others of same size.
+*/
+
+#define frontlink(P, S, IDX, BK, FD) \
+{ \
+ if (S < MAX_SMALLBIN_SIZE) \
+ { \
+ IDX = smallbin_index(S); \
+ mark_binblock(IDX); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+ else \
+ { \
+ IDX = bin_index(S); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ if (FD == BK) mark_binblock(IDX); \
+ else \
+ { \
+ while (FD != BK && S < chunksize(FD)) FD = FD->fd; \
+ BK = FD->bk; \
+ } \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+}
+
+/* take a chunk off a list */
+
+#define unlink(P, BK, FD) \
+{ \
+ BK = P->bk; \
+ FD = P->fd; \
+ FD->bk = BK; \
+ BK->fd = FD; \
+} \
+
+/* Place p as the last remainder */
+
+#define link_last_remainder(P) \
+{ \
+ last_remainder->fd = last_remainder->bk = P; \
+ P->fd = P->bk = last_remainder; \
+}
+
+/* Clear the last_remainder bin */
+
+#define clear_last_remainder \
+ (last_remainder->fd = last_remainder->bk = last_remainder)
+
+/* Routines dealing with mmap(). */
+
+#if HAVE_MMAP
+
+#if __STD_C
+static mchunkptr mmap_chunk(size_t size)
+#else
+static mchunkptr mmap_chunk(size) size_t size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ mchunkptr p;
+
+#ifndef MAP_ANONYMOUS
+ static int fd = -1;
+#endif
+
+ if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */
+
+ /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because
+ * there is no following chunk whose prev_size field could be used.
+ */
+ size = (size + SIZE_SZ + page_mask) & ~page_mask;
+
+#ifdef MAP_ANONYMOUS
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+#else /* !MAP_ANONYMOUS */
+ if (fd < 0)
+ {
+ fd = open("/dev/zero", O_RDWR);
+ if(fd < 0) return 0;
+ }
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+#endif
+
+ if(p == (mchunkptr)-1) return 0;
+
+ n_mmaps++;
+ if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps;
+
+ /* We demand that eight bytes into a page must be 8-byte aligned. */
+ assert(aligned_OK(chunk2mem(p)));
+
+ /* The offset to the start of the mmapped region is stored
+ * in the prev_size field of the chunk; normally it is zero,
+ * but that can be changed in memalign().
+ */
+ p->prev_size = 0;
+ set_head(p, size|IS_MMAPPED);
+
+ mmapped_mem += size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#if __STD_C
+static void munmap_chunk(mchunkptr p)
+#else
+static void munmap_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T size = chunksize(p);
+ int ret;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0);
+
+ n_mmaps--;
+ mmapped_mem -= (size + p->prev_size);
+
+ ret = munmap((char *)p - p->prev_size, size + p->prev_size);
+
+ /* munmap returns non-zero on failure */
+ assert(ret == 0);
+}
+
+#if HAVE_MREMAP
+
+#if __STD_C
+static mchunkptr mremap_chunk(mchunkptr p, size_t new_size)
+#else
+static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ INTERNAL_SIZE_T offset = p->prev_size;
+ INTERNAL_SIZE_T size = chunksize(p);
+ char *cp;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((size + offset) & (malloc_getpagesize-1)) == 0);
+
+ /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */
+ new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask;
+
+ cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1);
+
+ if (cp == (char *)-1) return 0;
+
+ p = (mchunkptr)(cp + offset);
+
+ assert(aligned_OK(chunk2mem(p)));
+
+ assert((p->prev_size == offset));
+ set_head(p, (new_size - offset)|IS_MMAPPED);
+
+ mmapped_mem -= size + offset;
+ mmapped_mem += new_size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#endif /* HAVE_MREMAP */
+
+#endif /* HAVE_MMAP */
+
+/*
+ Extend the top-most chunk by obtaining memory from system.
+ Main interface to sbrk (but see also malloc_trim).
+*/
+
+#if __STD_C
+static void malloc_extend_top(INTERNAL_SIZE_T nb)
+#else
+static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
+#endif
+{
+ char* brk; /* return value from sbrk */
+ INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */
+ INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */
+ char* new_brk; /* return of 2nd sbrk call */
+ INTERNAL_SIZE_T top_size; /* new size of top chunk */
+
+ mchunkptr old_top = top; /* Record state of old top */
+ INTERNAL_SIZE_T old_top_size = chunksize(old_top);
+ char* old_end = (char*)(chunk_at_offset(old_top, old_top_size));
+
+ /* Pad request with top_pad plus minimal overhead */
+
+ INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE;
+ unsigned long pagesz = malloc_getpagesize;
+
+ /* If not the first time through, round to preserve page boundary */
+ /* Otherwise, we need to correct to a page size below anyway. */
+ /* (We also correct below if an intervening foreign sbrk call.) */
+
+ if (sbrk_base != (char*)(-1))
+ sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1);
+
+ brk = (char*)(MORECORE (sbrk_size));
+
+ /* Fail if sbrk failed or if a foreign sbrk call killed our space */
+ if (brk == (char*)(MORECORE_FAILURE) ||
+ (brk < old_end && old_top != initial_top))
+ return;
+
+ sbrked_mem += sbrk_size;
+
+ if (brk == old_end) /* can just add bytes to current top */
+ {
+ top_size = sbrk_size + old_top_size;
+ set_head(top, top_size | PREV_INUSE);
+ }
+ else
+ {
+ if (sbrk_base == (char*)(-1)) /* First time through. Record base */
+ sbrk_base = brk;
+ else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */
+ sbrked_mem += brk - (char*)old_end;
+
+ /* Guarantee alignment of first new chunk made from this space */
+ front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK;
+ if (front_misalign > 0)
+ {
+ correction = (MALLOC_ALIGNMENT) - front_misalign;
+ brk += correction;
+ }
+ else
+ correction = 0;
+
+ /* Guarantee the next brk will be at a page boundary */
+ correction += pagesz - ((unsigned long)(brk + sbrk_size) & (pagesz - 1));
+
+ /* Allocate correction */
+ new_brk = (char*)(MORECORE (correction));
+ if (new_brk == (char*)(MORECORE_FAILURE)) return;
+
+ sbrked_mem += correction;
+
+ top = (mchunkptr)brk;
+ top_size = new_brk - brk + correction;
+ set_head(top, top_size | PREV_INUSE);
+
+ if (old_top != initial_top)
+ {
+ /* There must have been an intervening foreign sbrk call. */
+ /* A double fencepost is necessary to prevent consolidation */
+
+ /* If not enough space to do this, then user did something very wrong */
+ if (old_top_size < MINSIZE)
+ {
+ set_head(top, PREV_INUSE); /* will force null return from malloc */
+ return;
+ }
+
+ /* Also keep size a multiple of MALLOC_ALIGNMENT */
+ old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+ set_head_size(old_top, old_top_size);
+ chunk_at_offset(old_top, old_top_size )->size =
+ SIZE_SZ|PREV_INUSE;
+ chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size =
+ SIZE_SZ|PREV_INUSE;
+ /* If possible, release the rest. */
+ if (old_top_size >= MINSIZE)
+ fREe(chunk2mem(old_top));
+ }
+ }
+
+ if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem)
+ max_sbrked_mem = sbrked_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+
+ /* We always land on a page boundary */
+ assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0);
+}
+
+/* Main public routines */
+
+/*
+ Malloc Algorthim:
+
+ The requested size is first converted into a usable form, `nb'.
+ This currently means to add 4 bytes overhead plus possibly more to
+ obtain 8-byte alignment and/or to obtain a size of at least
+ MINSIZE (currently 16 bytes), the smallest allocatable size.
+ (All fits are considered `exact' if they are within MINSIZE bytes.)
+
+ From there, the first successful of the following steps is taken:
+
+ 1. The bin corresponding to the request size is scanned, and if
+ a chunk of exactly the right size is found, it is taken.
+
+ 2. The most recently remaindered chunk is used if it is big
+ enough. This is a form of (roving) first fit, used only in
+ the absence of exact fits. Runs of consecutive requests use
+ the remainder of the chunk used for the previous such request
+ whenever possible. This limited use of a first-fit style
+ allocation strategy tends to give contiguous chunks
+ coextensive lifetimes, which improves locality and can reduce
+ fragmentation in the long run.
+
+ 3. Other bins are scanned in increasing size order, using a
+ chunk big enough to fulfill the request, and splitting off
+ any remainder. This search is strictly by best-fit; i.e.,
+ the smallest (with ties going to approximately the least
+ recently used) chunk that fits is selected.
+
+ 4. If large enough, the chunk bordering the end of memory
+ (`top') is split off. (This use of `top' is in accord with
+ the best-fit search rule. In effect, `top' is treated as
+ larger (and thus less well fitting) than any other available
+ chunk since it can be extended to be as large as necessary
+ (up to system limitations).
+
+ 5. If the request size meets the mmap threshold and the
+ system supports mmap, and there are few enough currently
+ allocated mmapped regions, and a call to mmap succeeds,
+ the request is allocated via direct memory mapping.
+
+ 6. Otherwise, the top of memory is extended by
+ obtaining more space from the system (normally using sbrk,
+ but definable to anything else via the MORECORE macro).
+ Memory is gathered from the system (in system page-sized
+ units) in a way that allows chunks obtained across different
+ sbrk calls to be consolidated, but does not require
+ contiguous memory. Thus, it should be safe to intersperse
+ mallocs with other sbrk calls.
+
+
+ All allocations are made from the the `lowest' part of any found
+ chunk. (The implementation invariant is that prev_inuse is
+ always true of any allocated chunk; i.e., that each allocated
+ chunk borders either a previously allocated and still in-use chunk,
+ or the base of its memory arena.)
+*/
+
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+ mchunkptr victim; /* inspected/selected chunk */
+ INTERNAL_SIZE_T victim_size; /* its size */
+ int idx; /* index for bin traversal */
+ mbinptr bin; /* associated bin */
+ mchunkptr remainder; /* remainder from a split */
+ long remainder_size; /* its size */
+ int remainder_index; /* its bin index */
+ unsigned long block; /* block traverser bit */
+ int startidx; /* first bin of a traversed block */
+ mchunkptr fwd; /* misc temp for linking */
+ mchunkptr bck; /* misc temp for linking */
+ mbinptr q; /* misc temp */
+
+ INTERNAL_SIZE_T nb = request2size(bytes); /* padded request size; */
+
+ /* Check for exact match in a bin */
+
+ if (is_small_request(nb)) /* Faster version for small requests */
+ {
+ idx = smallbin_index(nb);
+
+ /* No traversal or size check necessary for small bins. */
+
+ q = bin_at(idx);
+ victim = last(q);
+
+ /* Also scan the next one, since it would have a remainder < MINSIZE */
+ if (victim == q)
+ {
+ q = next_bin(q);
+ victim = last(q);
+ }
+ if (victim != q)
+ {
+ victim_size = chunksize(victim);
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */
+
+ }
+ else
+ {
+ idx = bin_index(nb);
+ bin = bin_at(idx);
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* too big */
+ {
+ --idx; /* adjust to rescan below after checking last remainder */
+ break;
+ }
+
+ else if (remainder_size >= 0) /* exact fit */
+ {
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+ ++idx;
+ }
+
+ /* Try to use the last split-off remainder */
+
+ if ( (victim = last_remainder->fd) != last_remainder)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* re-split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ clear_last_remainder;
+
+ if (remainder_size >= 0) /* exhaust */
+ {
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* Else place in bin */
+
+ frontlink(victim, victim_size, remainder_index, bck, fwd);
+ }
+
+ /*
+ If there are any possibly nonempty big-enough blocks,
+ search for best fitting chunk by scanning bins in blockwidth units.
+ */
+
+ if ( (block = idx2binblock(idx)) <= binblocks)
+ {
+
+ /* Get to the first marked block */
+
+ if ( (block & binblocks) == 0)
+ {
+ /* force to an even block boundary */
+ idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
+ block <<= 1;
+ while ((block & binblocks) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+
+ /* For each possibly nonempty block ... */
+ for (;;)
+ {
+ startidx = idx; /* (track incomplete blocks) */
+ q = bin = bin_at(idx);
+
+ /* For each bin in this block ... */
+ do
+ {
+ /* Find and use first big enough chunk ... */
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ unlink(victim, bck, fwd);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ else if (remainder_size >= 0) /* take */
+ {
+ set_inuse_bit_at_offset(victim, victim_size);
+ unlink(victim, bck, fwd);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ }
+
+ bin = next_bin(bin);
+
+ } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
+
+ /* Clear out the block bit. */
+
+ do /* Possibly backtrack to try to clear a partial block */
+ {
+ if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
+ {
+ binblocks &= ~block;
+ break;
+ }
+ --startidx;
+ q = prev_bin(q);
+ } while (first(q) == q);
+
+ /* Get to the next possibly nonempty block */
+
+ if ( (block <<= 1) <= binblocks && (block != 0) )
+ {
+ while ((block & binblocks) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+
+ /* Try to use top chunk */
+
+ /* Require that there be a remainder, ensuring top always exists */
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ {
+
+#if HAVE_MMAP
+ /* If big and would otherwise need to extend, try to use mmap instead */
+ if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
+ (victim = mmap_chunk(nb)) != 0)
+ return chunk2mem(victim);
+#endif
+
+ /* Try to extend */
+ malloc_extend_top(nb);
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ {
+ return 0; /* propagate failure */
+ }
+ }
+
+ victim = top;
+ set_head(victim, nb | PREV_INUSE);
+ top = chunk_at_offset(victim, nb);
+ set_head(top, remainder_size | PREV_INUSE);
+ check_malloced_chunk(victim, nb);
+
+ return chunk2mem(victim);
+}
+
+/*
+
+ free() algorithm :
+
+ cases:
+
+ 1. free(0) has no effect.
+
+ 2. If the chunk was allocated via mmap, it is release via munmap().
+
+ 3. If a returned chunk borders the current high end of memory,
+ it is consolidated into the top, and if the total unused
+ topmost memory exceeds the trim threshold, malloc_trim is
+ called.
+
+ 4. Other chunks are consolidated as they arrive, and
+ placed in corresponding bins. (This includes the case of
+ consolidating with the current `last_remainder').
+
+*/
+
+
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p; /* chunk corresponding to mem */
+ INTERNAL_SIZE_T hd; /* its head field */
+ INTERNAL_SIZE_T sz; /* its size */
+ int idx; /* its bin index */
+ mchunkptr next; /* next contiguous chunk */
+ INTERNAL_SIZE_T nextsz; /* its size */
+ INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+ int islr; /* track whether merging with last_remainder */
+
+ if (mem == 0) /* free(0) has no effect */
+ return;
+
+ p = mem2chunk(mem);
+ hd = p->size;
+
+#if HAVE_MMAP
+ if (hd & IS_MMAPPED) /* release mmapped memory. */
+ {
+ munmap_chunk(p);
+ return;
+ }
+#endif
+
+ check_inuse_chunk(p);
+
+ sz = hd & ~PREV_INUSE;
+ next = chunk_at_offset(p, sz);
+ nextsz = chunksize(next);
+
+ if (next == top) /* merge with top */
+ {
+ sz += nextsz;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -prevsz);
+ sz += prevsz;
+ unlink(p, bck, fwd);
+ }
+
+ set_head(p, sz | PREV_INUSE);
+ top = p;
+ if ((unsigned long)(sz) >= (unsigned long)trim_threshold)
+ malloc_trim(top_pad);
+ return;
+ }
+
+ set_head(next, nextsz); /* clear inuse bit */
+
+ islr = 0;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -prevsz);
+ sz += prevsz;
+
+ if (p->fd == last_remainder) /* keep as last_remainder */
+ islr = 1;
+ else
+ unlink(p, bck, fwd);
+ }
+
+ if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */
+ {
+ sz += nextsz;
+
+ if (!islr && next->fd == last_remainder) /* re-insert last_remainder */
+ {
+ islr = 1;
+ link_last_remainder(p);
+ }
+ else
+ unlink(next, bck, fwd);
+ }
+
+
+ set_head(p, sz | PREV_INUSE);
+ set_foot(p, sz);
+ if (!islr)
+ frontlink(p, sz, idx, bck, fwd);
+}
+
+/*
+
+ Realloc algorithm:
+
+ Chunks that were obtained via mmap cannot be extended or shrunk
+ unless HAVE_MREMAP is defined, in which case mremap is used.
+ Otherwise, if their reallocation is for additional space, they are
+ copied. If for less, they are just left alone.
+
+ Otherwise, if the reallocation is for additional space, and the
+ chunk can be extended, it is, else a malloc-copy-free sequence is
+ taken. There are several different ways that a chunk could be
+ extended. All are tried:
+
+ * Extending forward into following adjacent free chunk.
+ * Shifting backwards, joining preceding adjacent space
+ * Both shifting backwards and extending forward.
+ * Extending into newly sbrked space
+
+ Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+
+ If the reallocation is for less space, and the new request is for
+ a `small' (<512 bytes) size, then the newly unused space is lopped
+ off and freed.
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is no longer supported.
+ I don't know of any programs still relying on this feature,
+ and allowing it would also allow too many other incorrect
+ usages of realloc to be sensible.
+
+
+*/
+
+
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+
+ mchunkptr oldp; /* chunk corresponding to oldmem */
+ INTERNAL_SIZE_T oldsize; /* its size */
+
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ Void_t* newmem; /* corresponding user mem */
+
+ mchunkptr next; /* next contiguous chunk after oldp */
+ INTERNAL_SIZE_T nextsize; /* its size */
+
+ mchunkptr prev; /* previous contiguous chunk before oldp */
+ INTERNAL_SIZE_T prevsize; /* its size */
+
+ mchunkptr remainder; /* holds split off extra space from newp */
+ INTERNAL_SIZE_T remainder_size; /* its size */
+
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (bytes == 0) { fREe(oldmem); return 0; }
+#endif
+
+
+ /* realloc of null is supposed to be same as malloc */
+ if (oldmem == 0) return mALLOc(bytes);
+
+ newp = oldp = mem2chunk(oldmem);
+ newsize = oldsize = chunksize(oldp);
+
+
+ nb = request2size(bytes);
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(oldp))
+ {
+#if HAVE_MREMAP
+ newp = mremap_chunk(oldp, nb);
+ if(newp) return chunk2mem(newp);
+#endif
+ /* Note the extra SIZE_SZ overhead. */
+ if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
+ /* Must alloc, copy, free. */
+ newmem = mALLOc(bytes);
+ if (newmem == 0) return 0; /* propagate failure */
+ MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+ munmap_chunk(oldp);
+ return newmem;
+ }
+#endif
+
+ check_inuse_chunk(oldp);
+
+ if ((long)(oldsize) < (long)(nb))
+ {
+
+ /* Try expanding forward */
+
+ next = chunk_at_offset(oldp, oldsize);
+ if (next == top || !inuse(next))
+ {
+ nextsize = chunksize(next);
+
+ /* Forward into top only if a remainder */
+ if (next == top)
+ {
+ if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ newsize += nextsize;
+ top = chunk_at_offset(oldp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ set_head_size(oldp, nb);
+ return chunk2mem(oldp);
+ }
+ }
+
+ /* Forward into next chunk */
+ else if (((long)(nextsize + newsize) >= (long)(nb)))
+ {
+ unlink(next, bck, fwd);
+ newsize += nextsize;
+ goto split;
+ }
+ }
+ else
+ {
+ next = 0;
+ nextsize = 0;
+ }
+
+ /* Try shifting backwards. */
+
+ if (!prev_inuse(oldp))
+ {
+ prev = prev_chunk(oldp);
+ prevsize = chunksize(prev);
+
+ /* try forward + backward first to save a later consolidation */
+
+ if (next != 0)
+ {
+ /* into top */
+ if (next == top)
+ {
+ if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize + nextsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ top = chunk_at_offset(newp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ set_head_size(newp, nb);
+ return newmem;
+ }
+ }
+
+ /* into next chunk */
+ else if (((long)(nextsize + prevsize + newsize) >= (long)(nb)))
+ {
+ unlink(next, bck, fwd);
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += nextsize + prevsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ goto split;
+ }
+ }
+
+ /* backward only */
+ if (prev != 0 && (long)(prevsize + newsize) >= (long)nb)
+ {
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize;
+ newmem = chunk2mem(newp);
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ goto split;
+ }
+ }
+
+ /* Must allocate */
+
+ newmem = mALLOc (bytes);
+
+ if (newmem == 0) /* propagate failure */
+ return 0;
+
+ /* Avoid copy if newp is next chunk after oldp. */
+ /* (This can only happen when new chunk is sbrk'ed.) */
+
+ if ( (newp = mem2chunk(newmem)) == next_chunk(oldp))
+ {
+ newsize += chunksize(newp);
+ newp = oldp;
+ goto split;
+ }
+
+ /* Otherwise copy, free, and exit */
+ MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+ fREe(oldmem);
+ return newmem;
+ }
+
+
+ split: /* split off extra room in old or expanded chunk */
+
+ if (newsize - nb >= MINSIZE) /* split off remainder */
+ {
+ remainder = chunk_at_offset(newp, nb);
+ remainder_size = newsize - nb;
+ set_head_size(newp, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_inuse_bit_at_offset(remainder, remainder_size);
+ fREe(chunk2mem(remainder)); /* let free() deal with it */
+ }
+ else
+ {
+ set_head_size(newp, newsize);
+ set_inuse_bit_at_offset(newp, newsize);
+ }
+
+ check_inuse_chunk(newp);
+ return chunk2mem(newp);
+}
+
+/*
+ memalign algorithm:
+
+ memalign requests more than enough space from malloc, finds a spot
+ within that chunk that meets the alignment request, and then
+ possibly frees the leading and trailing space.
+
+ The alignment argument must be a power of two. This property is not
+ checked by memalign, so misuse may result in random runtime errors.
+
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+*/
+
+
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+ char* m; /* memory returned by malloc call */
+ mchunkptr p; /* corresponding chunk */
+ char* brk; /* alignment point within p */
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */
+ mchunkptr remainder; /* spare room at end to split off */
+ long remainder_size; /* its size */
+
+ /* If need less alignment than we give anyway, just relay to malloc */
+
+ if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+
+ /* Otherwise, ensure that it is at least a minimum chunk size */
+
+ if (alignment < MINSIZE) alignment = MINSIZE;
+
+ /* Call malloc with worst case padding to hit alignment. */
+
+ nb = request2size(bytes);
+ m = (char*)(mALLOc(nb + alignment + MINSIZE));
+
+ if (m == 0) return 0; /* propagate failure */
+
+ p = mem2chunk(m);
+
+ if ((((unsigned long)(m)) % alignment) == 0) /* aligned */
+ {
+#if HAVE_MMAP
+ if(chunk_is_mmapped(p))
+ return chunk2mem(p); /* nothing more to do */
+#endif
+ }
+ else /* misaligned */
+ {
+ /*
+ Find an aligned spot inside chunk.
+ Since we need to give back leading space in a chunk of at
+ least MINSIZE, if the first calculation places us at
+ a spot with less than MINSIZE leader, we can move to the
+ next aligned spot -- we've allocated enough total room so that
+ this is always possible.
+ */
+
+ brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -alignment);
+ if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment;
+
+ newp = (mchunkptr)brk;
+ leadsize = brk - (char*)(p);
+ newsize = chunksize(p) - leadsize;
+
+#if HAVE_MMAP
+ if(chunk_is_mmapped(p))
+ {
+ newp->prev_size = p->prev_size + leadsize;
+ set_head(newp, newsize|IS_MMAPPED);
+ return chunk2mem(newp);
+ }
+#endif
+
+ /* give back leader, use the rest */
+
+ set_head(newp, newsize | PREV_INUSE);
+ set_inuse_bit_at_offset(newp, newsize);
+ set_head_size(p, leadsize);
+ fREe(chunk2mem(p));
+ p = newp;
+
+ assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
+ }
+
+ /* Also give back spare room at the end */
+
+ remainder_size = chunksize(p) - nb;
+
+ if (remainder_size >= (long)MINSIZE)
+ {
+ remainder = chunk_at_offset(p, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_head_size(p, nb);
+ fREe(chunk2mem(remainder));
+ }
+
+ check_inuse_chunk(p);
+ return chunk2mem(p);
+
+}
+
+/*
+ valloc just invokes memalign with alignment argument equal
+ to the page size of the system (or as near to this as can
+ be figured out from all the includes/defines above.)
+*/
+
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+ return mEMALIGn (malloc_getpagesize, bytes);
+}
+
+/*
+ pvalloc just invokes valloc for the nearest pagesize
+ that will accommodate request
+*/
+
+#if __STD_C
+Void_t* pvALLOc(size_t bytes)
+#else
+Void_t* pvALLOc(bytes) size_t bytes;
+#endif
+{
+ size_t pagesize = malloc_getpagesize;
+ return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
+}
+
+/*
+ calloc calls malloc, then zeroes out the allocated chunk.
+*/
+
+#if __STD_C
+Void_t* cALLOc(size_t n, size_t elem_size)
+#else
+Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
+#endif
+{
+ mchunkptr p;
+ INTERNAL_SIZE_T csz;
+
+ INTERNAL_SIZE_T sz = n * elem_size;
+
+ /* check if expand_top called, in which case don't need to clear */
+#if MORECORE_CLEARS
+ mchunkptr oldtop = top;
+ INTERNAL_SIZE_T oldtopsize = chunksize(top);
+#endif
+ Void_t* mem = mALLOc (sz);
+
+ if (mem == 0)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+
+ /* Two optional cases in which clearing not necessary */
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(p)) return mem;
+#endif
+
+ csz = chunksize(p);
+
+#if MORECORE_CLEARS
+ if (p == oldtop && csz > oldtopsize)
+ {
+ /* clear only the bytes from non-freshly-sbrked memory */
+ csz = oldtopsize;
+ }
+#endif
+
+ MALLOC_ZERO(mem, csz - SIZE_SZ);
+ return mem;
+ }
+}
+
+/*
+ cfree just calls free. It is needed/defined on some systems
+ that pair it with calloc, presumably for odd historical reasons.
+*/
+
+#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__)
+#if __STD_C
+void cfree(Void_t *mem)
+#else
+void cfree(mem) Void_t *mem;
+#endif
+{
+ fREe(mem);
+}
+#endif
+
+/*
+ Malloc_trim gives memory back to the system (via negative
+ arguments to sbrk) if there is unused memory at the `high' end of
+ the malloc pool. You can call this after freeing large blocks of
+ memory to potentially reduce the system-level memory requirements
+ of a program. However, it cannot guarantee to reduce memory. Under
+ some allocation patterns, some large free blocks of memory will be
+ locked between two used chunks, so they cannot be given back to
+ the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero,
+ only the minimum amount of memory to maintain internal data
+ structures will be left (one page or less). Non-zero arguments
+ can be supplied to maintain enough trailing space to service
+ future expected allocations without having to re-obtain memory
+ from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+*/
+
+#if __STD_C
+int malloc_trim(size_t pad)
+#else
+int malloc_trim(pad) size_t pad;
+#endif
+{
+ long top_size; /* Amount of top-most memory */
+ long extra; /* Amount to release */
+ char* current_brk; /* address returned by pre-check sbrk call */
+ char* new_brk; /* address returned by negative sbrk call */
+
+ unsigned long pagesz = malloc_getpagesize;
+
+ top_size = chunksize(top);
+ extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+ if (extra < (long)pagesz) /* Not enough memory to release */
+ return 0;
+
+ else
+ {
+ /* Test to make sure no one else called sbrk */
+ current_brk = (char*)(MORECORE (0));
+ if (current_brk != (char*)(top) + top_size)
+ return 0; /* Apparently we don't own memory; must fail */
+
+ else
+ {
+ new_brk = (char*)(MORECORE (-extra));
+
+ if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */
+ {
+ /* Try to figure out what we have */
+ current_brk = (char*)(MORECORE (0));
+ top_size = current_brk - (char*)top;
+ if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */
+ {
+ sbrked_mem = current_brk - sbrk_base;
+ set_head(top, top_size | PREV_INUSE);
+ }
+ check_chunk(top);
+ return 0;
+ }
+
+ else
+ {
+ /* Success. Adjust top accordingly. */
+ set_head(top, (top_size - extra) | PREV_INUSE);
+ sbrked_mem -= extra;
+ check_chunk(top);
+ return 1;
+ }
+ }
+ }
+}
+
+/*
+ malloc_usable_size:
+
+ This routine tells you how many bytes you can actually use in an
+ allocated chunk, which may be more than you requested (although
+ often not). You can use this many bytes without worrying about
+ overwriting other allocated objects. Not a particularly great
+ programming practice, but still sometimes useful.
+*/
+
+#if __STD_C
+size_t malloc_usable_size(Void_t* mem)
+#else
+size_t malloc_usable_size(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p;
+ if (mem == 0)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+ if(!chunk_is_mmapped(p))
+ {
+ if (!inuse(p)) return 0;
+ check_inuse_chunk(p);
+ return chunksize(p) - SIZE_SZ;
+ }
+ return chunksize(p) - 2*SIZE_SZ;
+ }
+}
+
+/* Utility to update current_mallinfo for malloc_stats and mallinfo() */
+
+static void malloc_update_mallinfo()
+{
+ int i;
+ mbinptr b;
+ mchunkptr p;
+#if DEBUG
+ mchunkptr q;
+#endif
+
+ INTERNAL_SIZE_T avail = chunksize(top);
+ int navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0;
+
+ for (i = 1; i < NAV; ++i)
+ {
+ b = bin_at(i);
+ for (p = last(b); p != b; p = p->bk)
+ {
+#if DEBUG
+ check_free_chunk(p);
+ for (q = next_chunk(p);
+ q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE;
+ q = next_chunk(q))
+ check_inuse_chunk(q);
+#endif
+ avail += chunksize(p);
+ navail++;
+ }
+ }
+
+ current_mallinfo.ordblks = navail;
+ current_mallinfo.uordblks = sbrked_mem - avail;
+ current_mallinfo.fordblks = avail;
+ current_mallinfo.hblks = n_mmaps;
+ current_mallinfo.hblkhd = mmapped_mem;
+ current_mallinfo.keepcost = chunksize(top);
+
+}
+
+/*
+
+ malloc_stats:
+
+ Prints on stderr the amount of space obtain from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), the maximum
+ number of simultaneous mmap regions used, and the current number
+ of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. (Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead.)
+
+*/
+
+void malloc_stats()
+{
+ malloc_update_mallinfo();
+/*
+ This commented out since we don't have a printf(1) in userspace yet
+
+ printf("max system bytes = %10u\n",
+ (unsigned int)(max_total_mem));
+ printf("system bytes = %10u\n",
+ (unsigned int)(sbrked_mem + mmapped_mem));
+ printf("in use bytes = %10u\n",
+ (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
+#if HAVE_MMAP
+ printf("max mmap regions = %10u\n",
+ (unsigned int)max_n_mmaps);
+#endif
+*/
+}
+
+/*
+ mallinfo returns a copy of updated current mallinfo.
+*/
+
+struct mallinfo mALLINFo()
+{
+ malloc_update_mallinfo();
+ return current_mallinfo;
+}
+
+/*
+ mallopt:
+
+ mallopt is the general SVID/XPG interface to tunable parameters.
+ The format is to provide a (parameter-number, parameter-value) pair.
+ mallopt then sets the corresponding parameter to the argument
+ value if it can (i.e., so long as the value is meaningful),
+ and returns 1 if successful else 0.
+
+ See descriptions of tunable parameters above.
+
+*/
+
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+ switch(param_number)
+ {
+ case M_TRIM_THRESHOLD:
+ trim_threshold = value; return 1;
+ case M_TOP_PAD:
+ top_pad = value; return 1;
+ case M_MMAP_THRESHOLD:
+ mmap_threshold = value; return 1;
+ case M_MMAP_MAX:
+#if HAVE_MMAP
+ n_mmaps_max = value; return 1;
+#else
+ if (value != 0) return 0; else n_mmaps_max = value; return 1;
+#endif
+
+ default:
+ return 0;
+ }
+}
+
+/*
+
+History:
+
+ V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
+ * Fixed ordering problem with boundary-stamping
+
+ V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
+ * Added pvalloc, as recommended by H.J. Liu
+ * Added 64bit pointer support mainly from Wolfram Gloger
+ * Added anonymously donated WIN32 sbrk emulation
+ * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+ * malloc_extend_top: fix mask error that caused wastage after
+ foreign sbrks
+ * Add linux mremap support code from HJ Liu
+
+ V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
+ * Integrated most documentation with the code.
+ * Add support for mmap, with help from
+ Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Use last_remainder in more cases.
+ * Pack bins using idea from colin@nyx10.cs.du.edu
+ * Use ordered bins instead of best-fit threshhold
+ * Eliminate block-local decls to simplify tracing and debugging.
+ * Support another case of realloc via move into top
+ * Fix error occuring when initial sbrk_base not word-aligned.
+ * Rely on page size for units instead of SBRK_UNIT to
+ avoid surprises about sbrk alignment conventions.
+ * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+ (raymond@es.ele.tue.nl) for the suggestion.
+ * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+ * More precautions for cases where other routines call sbrk,
+ courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Added macros etc., allowing use in linux libc from
+ H.J. Lu (hjl@gnu.ai.mit.edu)
+ * Inverted this history list
+
+ V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
+ * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+ * Removed all preallocation code since under current scheme
+ the work required to undo bad preallocations exceeds
+ the work saved in good cases for most test programs.
+ * No longer use return list or unconsolidated bins since
+ no scheme using them consistently outperforms those that don't
+ given above changes.
+ * Use best fit for very large chunks to prevent some worst-cases.
+ * Added some support for debugging
+
+ V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
+ * Removed footers when chunks are in use. Thanks to
+ Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+ V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
+ * Added malloc_trim, with help from Wolfram Gloger
+ (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+ V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
+
+ V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
+ * realloc: try to expand in both directions
+ * malloc: swap order of clean-bin strategy;
+ * realloc: only conditionally expand backwards
+ * Try not to scavenge used bins
+ * Use bin counts as a guide to preallocation
+ * Occasionally bin return list chunks in first scan
+ * Add a few optimizations from colin@nyx10.cs.du.edu
+
+ V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
+ * faster bin computation & slightly different binning
+ * merged all consolidations to one part of malloc proper
+ (eliminating old malloc_find_space & malloc_clean_bin)
+ * Scan 2 returns chunks (not just 1)
+ * Propagate failure in realloc if malloc returns 0
+ * Add stuff to allow compilation on non-ANSI compilers
+ from kpv@research.att.com
+
+ V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
+ * removed potential for odd address access in prev_chunk
+ * removed dependency on getpagesize.h
+ * misc cosmetics and a bit more internal documentation
+ * anticosmetics: mangled names in macros to evade debugger strangeness
+ * tested on sparc, hp-700, dec-mips, rs6000
+ with gcc & native cc (hp, dec only) allowing
+ Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+ Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
+ * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+ structure of old version, but most details differ.)
+
+*/
+
diff --git a/lib/libc/malloc.h b/lib/libc/malloc.h
@@ -0,0 +1,46 @@
+/* $Id: //depot/blt/lib/malloc.h#2 $
+**
+** Copyright 1998 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _MALLOC_H_
+#define _MALLOC_H_
+
+void *__malloc (size_t);
+void __free (void *);
+void *__realloc (void *, size_t);
+void *__memalign (size_t, size_t);
+void *__valloc (size_t);
+void *__pvalloc (size_t);
+void *__calloc (size_t);
+void __cfree (void *);
+int malloc_trim (size_t);
+size_t malloc_usable_size (void *);
+void malloc_stats (void);
+int __mallopt (int, int);
+
+#endif
+
diff --git a/lib/libc/memory.c b/lib/libc/memory.c
@@ -0,0 +1,113 @@
+/* $Id: //depot/blt/lib/memory.c#4 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <blt/types.h>
+#include <blt/syscall.h>
+#include <blt/libsyms.h>
+#include "malloc.h"
+
+weak_alias (_sbrk, sbrk)
+weak_alias (_malloc, malloc)
+weak_alias (_free, free)
+weak_alias (_realloc, realloc)
+
+static unsigned int __sbrk_max;
+static unsigned int __sbrk_cur;
+static int sem_malloc;
+
+void *_sbrk(int size)
+{
+ if(size < 0 ){
+ __sbrk_cur -= size;
+ return (void *) __sbrk_cur;
+ } else {
+ unsigned int tmp = __sbrk_cur;
+ __sbrk_cur += size;
+ if(__sbrk_cur > __sbrk_max){
+ __sbrk_max = __sbrk_cur;
+ os_brk(__sbrk_max);
+ }
+ return (void *) tmp;
+ }
+
+ return (void *) __sbrk_cur;
+}
+
+void *_malloc(size_t size)
+{
+ void *r;
+ sem_acquire(sem_malloc);
+ r = __malloc(size);
+ sem_release(sem_malloc);
+ return r;
+}
+
+void _free(void *ptr)
+{
+ sem_acquire(sem_malloc);
+ __free(ptr);
+ sem_release(sem_malloc);
+}
+
+void *_realloc(void *ptr, size_t size)
+{
+ void *r;
+ sem_acquire(sem_malloc);
+ r = __realloc(ptr,size);
+ sem_release(sem_malloc);
+ return r;
+}
+
+
+void * _default_morecore(long size)
+{
+ void *result;
+
+ result = sbrk(size);
+ if (result == (void *) -1)
+ return NULL;
+ return result;
+}
+
+void __libc_init_memory(unsigned int top_of_binary,
+ unsigned int start_bss, unsigned int bss_length)
+{
+ int i;
+ unsigned char *x = (unsigned char *) start_bss;
+ unsigned int tob = (top_of_binary/4096+2)*4096;
+ os_brk(tob);
+
+ for (i = 0; i < bss_length; i++)
+ x[i] = 0;
+
+ __sbrk_max = __sbrk_cur = tob;
+
+ sem_malloc = sem_create(1,"libc_malloc_sem");
+}
diff --git a/lib/libc/qsem.c b/lib/libc/qsem.c
@@ -0,0 +1,78 @@
+/* $Id: //depot/blt/lib/libc/qsem.c#1 $
+**
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <blt/syscall.h>
+#include <blt/qsem.h>
+
+qsem_t *qsem_create (int count)
+{
+ qsem_t *s;
+
+ s = (qsem_t *) malloc (sizeof (qsem_t));
+#ifdef I386
+ s->mutex = sem_create (count, "qsem_mutex");
+ s->count = 0;
+#else
+ s->mutex = sem_create (0, "qsem_mutex");
+ s->count = count;
+#endif
+ return s;
+}
+
+void qsem_destroy (qsem_t *s)
+{
+ sem_destroy (s->mutex);
+ free (s);
+}
+
+void qsem_acquire (qsem_t *s)
+{
+#ifdef I386
+ /* no atomic_add() in i386 */
+ sem_acquire(s->mutex);
+#else
+ if (atomic_add (&s->count, -1) <= 0)
+ sem_acquire (s->mutex);
+#endif
+}
+
+void qsem_release (qsem_t *s)
+{
+#ifdef I386
+ /* no atomic_add() in i386 */
+ sem_release(s->mutex);
+#else
+ if (atomic_add (&s->count, 1) < 0)
+ sem_release (s->mutex);
+#endif
+}
+
diff --git a/lib/libc/qsort.c b/lib/libc/qsort.c
@@ -0,0 +1,174 @@
+/* $Id: //depot/blt/lib/libc/qsort.c#1 $ */
+/* $OpenBSD: qsort.c,v 1.5 1997/06/20 11:19:38 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+static __inline char *med3 (char *, char *, char *, int (*)());
+static __inline void swapfunc (char *, char *, int, int);
+
+#define min(a, b) (a) < (b) ? a : b
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) { \
+ long i = (n) / sizeof (TYPE); \
+ register TYPE *pi = (TYPE *) (parmi); \
+ register TYPE *pj = (TYPE *) (parmj); \
+ do { \
+ register TYPE t = *pi; \
+ *pi++ = *pj; \
+ *pj++ = t; \
+ } while (--i > 0); \
+}
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+ es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+static __inline void
+swapfunc(a, b, n, swaptype)
+ char *a, *b;
+ int n, swaptype;
+{
+ if (swaptype <= 1)
+ swapcode(long, a, b, n)
+ else
+ swapcode(char, a, b, n)
+}
+
+#define swap(a, b) \
+ if (swaptype == 0) { \
+ long t = *(long *)(a); \
+ *(long *)(a) = *(long *)(b); \
+ *(long *)(b) = t; \
+ } else \
+ swapfunc(a, b, es, swaptype)
+
+#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+static __inline char *
+med3(a, b, c, cmp)
+ char *a, *b, *c;
+ int (*cmp)();
+{
+ return cmp(a, b) < 0 ?
+ (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
+ :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
+}
+
+void
+qsort(aa, n, es, cmp)
+ void *aa;
+ size_t n, es;
+ int (*cmp)();
+{
+ char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+ int d, r, swaptype, swap_cnt;
+ register char *a = aa;
+
+loop: SWAPINIT(a, es);
+ swap_cnt = 0;
+ if (n < 7) {
+ for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
+ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+ pm = (char *)a + (n / 2) * es;
+ if (n > 7) {
+ pl = (char *)a;
+ pn = (char *)a + (n - 1) * es;
+ if (n > 40) {
+ d = (n / 8) * es;
+ pl = med3(pl, pl + d, pl + 2 * d, cmp);
+ pm = med3(pm - d, pm, pm + d, cmp);
+ pn = med3(pn - 2 * d, pn - d, pn, cmp);
+ }
+ pm = med3(pl, pm, pn, cmp);
+ }
+ swap(a, pm);
+ pa = pb = (char *)a + es;
+
+ pc = pd = (char *)a + (n - 1) * es;
+ for (;;) {
+ while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ swap(pa, pb);
+ pa += es;
+ }
+ pb += es;
+ }
+ while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ swap(pc, pd);
+ pd -= es;
+ }
+ pc -= es;
+ }
+ if (pb > pc)
+ break;
+ swap(pb, pc);
+ swap_cnt = 1;
+ pb += es;
+ pc -= es;
+ }
+ if (swap_cnt == 0) { /* Switch to insertion sort */
+ for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
+ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+
+ pn = (char *)a + n * es;
+ r = min(pa - (char *)a, pb - pa);
+ vecswap(a, pb - r, r);
+ r = min(pd - pc, pn - pd - es);
+ vecswap(pb, pn - r, r);
+ if ((r = pb - pa) > es)
+ qsort(a, r / es, es, cmp);
+ if ((r = pd - pc) > es) {
+ /* Iterate rather than recurse to save stack space */
+ a = pn - r;
+ n = r / es;
+ goto loop;
+ }
+/* qsort(pn - r, r / es, es, cmp);*/
+}
diff --git a/lib/libc/snprintf.c b/lib/libc/snprintf.c
@@ -0,0 +1,186 @@
+/* $Id: //depot/blt/lib/snprintf.c#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Copyright 1997, Brian J. Swetland <swetland@neog.com>
+** Free for non-commercial use. Share and enjoy
+**
+** Minimal snprintf() function.
+** %s - string %d - signed int %x - 32bit hex number (0 padded)
+** %c - character %u - unsigned int %X - 8bit hex number (0 padded)
+*/
+
+#include <stdarg.h>
+
+static char hexmap[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+};
+
+void va_snprintf(char *b, int l, char *fmt, va_list pvar)
+{
+ int n,i;
+ unsigned u;
+ unsigned long long ull;
+ char *t,d[10], mod_l, mod_ll;
+
+ if(!fmt || !b || (l < 1)) return;
+
+ mod_l = mod_ll = 0;
+ while(l && *fmt) {
+ if(*fmt == '%'){
+ if(!(--l)) break;
+ again:
+ fmt++;
+
+ switch(*fmt){
+ case 'l': /* long modifier */
+ if (!mod_l)
+ mod_l = 1;
+ else if (!mod_ll)
+ {
+ mod_l = 0;
+ mod_ll = 1;
+ }
+ goto again;
+
+ case 's': /* string */
+ t = va_arg(pvar,char *);
+ while(l && *t) *b++ = *t++, l--;
+ break;
+
+ case 'c': /* single character */
+ *b++ = va_arg(pvar,char);
+ l--;
+ break;
+
+ case 'S': /* uint32 as a short ... */
+ if(l < 4) { l = 0; break; }
+ u = va_arg(pvar,unsigned int);
+ for(i=3;i>=0;i--){
+ b[i] = hexmap[u & 0x0F];
+ u >>= 4;
+ }
+ b+=4;
+ l-=4;
+ break;
+
+ case 'x':
+ case 'p':
+ if (!mod_ll) { /* 8 digit, unsigned 32-bit hex integer */
+ if(l < 8) { l = 0; break; }
+ u = va_arg(pvar,unsigned int);
+ for(i=7;i>=0;i--){
+ b[i] = hexmap[u & 0x0F];
+ u >>= 4;
+ }
+ b+=8;
+ l-=8;
+ }
+ else if (mod_ll) { /* 16 digit, unsigned 64-bit hex integer */
+ if (l < 16) { l = 0; break; }
+ ull = va_arg (pvar, unsigned long long);
+ for (i = 15; i >= 0; i--) {
+ b[i] = hexmap[ull & 0x0f];
+ ull >>= 4;
+ }
+ b += 16;
+ l -= 16;
+ }
+ mod_l = mod_ll = 0;
+ break;
+
+ case 'd': /* signed integer */
+ n = va_arg(pvar,int);
+ if(n < 0) {
+ u = -n;
+ *b++ = '-';
+ if(!(--l)) break;
+ } else {
+ u = n;
+ }
+ goto u2;
+
+ case 'u': /* unsigned integer */
+ u = va_arg(pvar,unsigned int);
+ u2:
+ i = 9;
+ do {
+ d[i] = (u % 10) + '0';
+ u /= 10;
+ i--;
+ } while(u && i >= 0);
+ while(++i < 10){
+ *b++ = d[i];
+ if(!(--l)) break;
+ }
+ break;
+
+ case 'U':
+ u = va_arg(pvar,unsigned int);
+ i = 9;
+ d[8] = d[7] = d[6] = ' ';
+ do {
+ d[i] = (u % 10) + '0';
+ u /= 10;
+ i--;
+ } while(u && i >= 0);
+ i = 5;
+ while(++i < 10){
+ *b++ = d[i];
+ if(!(--l)) break;
+ }
+ break;
+
+ case 'X': /* 2 digit, unsigned 8bit hex int */
+ if(l < 2) { l = 0; break; }
+ n = va_arg(pvar,int);
+ *b++ = hexmap[(n & 0xF0) >> 4];
+ *b++ = hexmap[n & 0x0F];
+ l-=2;
+ break;
+ default:
+ *b++ = *fmt;
+ }
+ } else {
+ *b++ = *fmt;
+ l--;
+ }
+ fmt++;
+ }
+ *b = 0;
+}
+
+void snprintf(char *str, int len, char *fmt, ...)
+{
+ va_list pvar;
+ va_start(pvar,fmt);
+ va_snprintf(str,len,fmt,pvar);
+ va_end(pvar);
+}
+
+
diff --git a/lib/libc/stdlib.c b/lib/libc/stdlib.c
@@ -0,0 +1,46 @@
+/* $Id: //depot/blt/lib/libc/stdlib.c#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <blt/libsyms.h>
+
+weak_alias (_atoi, atoi)
+
+int _atoi (const char *a)
+{
+ int x, i, power = 1;
+
+ for (x = strlen (a) - 1, i = 0; x >= 0; x--, power *= 10)
+ if (!x && (a[x] == '-'))
+ i *= -1;
+ else
+ i += power * (a[x] - '0');
+ return i;
+}
+
diff --git a/lib/libc/strcmp.S b/lib/libc/strcmp.S
@@ -0,0 +1,84 @@
+/* $Id: //depot/blt/lib/strcmp.S#1 $ */
+
+/* $OpenBSD: strcmp.S,v 1.2 1996/09/27 06:47:49 mickey Exp $ */
+
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+/*
+ * NOTE: I've unrolled the loop eight times: large enough to make a
+ * significant difference, and small enough not to totally trash the
+ * cache.
+ */
+
+#include <i386/asm.h>
+
+FUNCTION (strcmp)
+ movl 0x04(%esp),%eax
+ movl 0x08(%esp),%edx
+ jmp L2 /* Jump into the loop! */
+
+ .align 2,0x90
+L1: incl %eax
+ incl %edx
+L2: movb (%eax),%cl
+ testb %cl,%cl /* null terminator??? */
+ jz L3
+ cmpb %cl,(%edx) /* chars match??? */
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ jz L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ jz L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ jz L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ jz L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ jz L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ jz L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ jz L3
+ cmpb %cl,(%edx)
+ je L1
+ .align 2, 0x90
+L3: movzbl (%eax),%eax /* unsigned comparison */
+ movzbl (%edx),%edx
+ subl %edx,%eax
+ ret
diff --git a/lib/libc/strcpy.S b/lib/libc/strcpy.S
@@ -0,0 +1,59 @@
+/* $Id: //depot/blt/lib/strcpy.S#1 $ */
+
+/* $OpenBSD: strcpy.S,v 1.2 1996/09/27 06:47:50 mickey Exp $ */
+
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+/*
+ * NOTE: I've unrolled the loop eight times: large enough to make a
+ * significant difference, and small enough not to totally trash the
+ * cache.
+ */
+
+#include <i386/asm.h>
+
+FUNCTION (strcpy)
+ movl 4(%esp),%ecx /* dst address */
+ movl 8(%esp),%edx /* src address */
+ pushl %ecx /* push dst address */
+
+ .align 2,0x90
+L1: movb (%edx),%al /* unroll loop, but not too much */
+ movb %al,(%ecx)
+ testb %al,%al
+ jz L2
+ movb 1(%edx),%al
+ movb %al,1(%ecx)
+ testb %al,%al
+ jz L2
+ movb 2(%edx),%al
+ movb %al,2(%ecx)
+ testb %al,%al
+ jz L2
+ movb 3(%edx),%al
+ movb %al,3(%ecx)
+ testb %al,%al
+ jz L2
+ movb 4(%edx),%al
+ movb %al,4(%ecx)
+ testb %al,%al
+ jz L2
+ movb 5(%edx),%al
+ movb %al,5(%ecx)
+ testb %al,%al
+ jz L2
+ movb 6(%edx),%al
+ movb %al,6(%ecx)
+ testb %al,%al
+ jz L2
+ movb 7(%edx),%al
+ movb %al,7(%ecx)
+ addl $8,%edx
+ addl $8,%ecx
+ testb %al,%al
+ jnz L1
+L2: popl %eax /* pop dst address */
+ ret
diff --git a/lib/libc/string.c b/lib/libc/string.c
@@ -0,0 +1,128 @@
+/* $Id: //depot/blt/lib/libc/string.c#4 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+
+char *strncpy(char *dst, const char *src, size_t size)
+{
+ char *d = dst;
+
+ while(size && *src) size--, *dst++ = *src++;
+ if(size) *dst = 0;
+
+ return d;
+}
+
+int strncmp(const char *s1, const char *s2, size_t n)
+{
+ while(n && *s1 && *s2){
+ if(*s1 != *s2) return -1;
+ s1++;
+ s2++;
+ n--;
+
+ }
+ if(n) return -1;
+
+ return 0;
+}
+
+char *strchr (const char *cs, int c)
+{
+ const char *s;
+
+ s = cs;
+ while (*s)
+ {
+ if (*s == c)
+ return (char *) s;
+ s++;
+ }
+ return NULL;
+}
+
+void *memset(void *s, int c, size_t n)
+{
+ unsigned char *u = (unsigned char *) s;
+ while(n) {
+ *u = c;
+ u++;
+ n--;
+ }
+ return s;
+}
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+ unsigned char *d;
+ unsigned char *s;
+
+ if(dest < src){
+ d = (unsigned char *)dest;
+ s = (unsigned char *)src;
+ while(n){
+ *d = *s;
+ d++;
+ s++;
+ n--;
+ }
+ } else {
+ d = ((unsigned char *) dest)+n;
+ s = ((unsigned char *) src)+n;
+ while(n){
+ d--;
+ s--;
+ *d = *s;
+ n--;
+ }
+ }
+ return dest;
+}
+
+int memcmp(const void *dst, const void *src, size_t size)
+{
+ while(size) {
+ if(*((char *)dst) != *((char *)src)) return 1;
+ ((char *) dst)++;
+ ((char *) src)++;
+ size--;
+ }
+ return 0;
+}
+
+void *memcpy(void *dst, const void *src, size_t size)
+{
+ void *r = dst;
+
+ while(size) {
+ *(((unsigned char *) dst)++) = *(((unsigned char *) src)++);
+ size--;
+ }
+ return r;
+}
+
diff --git a/lib/libc/strlcat.c b/lib/libc/strlcat.c
@@ -0,0 +1,68 @@
+/* $Id: //depot/blt/lib/libc/strlcat.c#1 $ */
+/* $OpenBSD: strlcat.c,v 1.1 1998/07/01 01:29:45 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t strlcat(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left */
+ while (*d != '\0' && n != 0)
+ d++;
+ dlen = d - dst;
+ n -= dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+
diff --git a/lib/libc/strlcpy.c b/lib/libc/strlcpy.c
@@ -0,0 +1,65 @@
+/* $Id: //depot/blt/lib/libc/strlcpy.c#1 $ */
+/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t strlcpy(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+
diff --git a/lib/libc/strlen.S b/lib/libc/strlen.S
@@ -0,0 +1,23 @@
+/* $Id: //depot/blt/lib/strlen.S#1 $ */
+
+/* $OpenBSD: strlen.S,v 1.2 1996/09/27 06:47:51 mickey Exp $ */
+
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <i386/asm.h>
+
+FUNCTION (strlen)
+ pushl %edi
+ movl 8(%esp),%edi /* string address */
+ cld /* set search forward */
+ xorl %eax,%eax /* set search for null terminator */
+ movl $-1,%ecx /* set search for lots of characters */
+ repne /* search! */
+ scasb
+ notl %ecx /* get length by taking complement */
+ leal -1(%ecx),%eax /* and subtracting one */
+ popl %edi
+ ret
diff --git a/lib/libc/syscalls.S b/lib/libc/syscalls.S
@@ -0,0 +1,76 @@
+/* $Id: //depot/blt/lib/libc/syscalls.S#3 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <blt/syscall_id.h>
+#include <i386/asm.h>
+
+#define SYSCALL(name) \
+ FUNCTION(name) ; \
+ movl $BLT_SYS_##name, %eax ; \
+ int $0x20 ; \
+ ret
+
+SYSCALL(os_meta)
+SYSCALL(os_terminate)
+SYSCALL(os_console)
+SYSCALL(os_brk)
+SYSCALL(os_handle_irq)
+SYSCALL(os_sleep_irq)
+SYSCALL(os_debug)
+SYSCALL(os_sleep)
+
+SYSCALL(sem_create)
+SYSCALL(sem_destroy)
+SYSCALL(sem_acquire)
+SYSCALL(sem_release)
+
+SYSCALL(port_create)
+SYSCALL(port_destroy)
+SYSCALL(port_option)
+SYSCALL(port_send)
+SYSCALL(port_recv)
+
+SYSCALL(os_identify)
+
+SYSCALL(right_create)
+SYSCALL(right_destroy)
+SYSCALL(right_revoke)
+SYSCALL(right_attach)
+SYSCALL(right_grant)
+
+SYSCALL(thr_create)
+SYSCALL(thr_spawn)
+SYSCALL(thr_resume)
+SYSCALL(thr_suspend)
+SYSCALL(thr_kill)
+SYSCALL(thr_wait)
+
+SYSCALL(area_create)
+SYSCALL(area_clone)
+SYSCALL(area_destroy)
+SYSCALL(area_resize)
diff --git a/lib/libconsole/Makefile b/lib/libconsole/Makefile
@@ -0,0 +1,8 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := conio.c
+LIBRARY := libconsole.a
+SHLIB := libconsole.so
+
+include $(BLTHOME)make.actions
diff --git a/lib/libconsole/conio.c b/lib/libconsole/conio.c
@@ -0,0 +1,162 @@
+/* $Id: //depot/blt/lib/conio.c#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <blt/conio.h>
+
+static int attr = 1, px = 0, py = 24;
+static char *screen = (char *) CON_SCREEN;
+static char *posn = (char *) CON_SCREEN + 80*24*2;
+
+static void scrollup(void)
+{
+ for(posn = screen + 160; posn <= screen + 80*25*2; posn++)
+ *(posn - 160) = *posn;
+ for(posn = screen + 80*24*2; posn <= screen + 80*25*2; posn++){
+ *posn++ = ' ';
+ *posn = attr;
+ }
+}
+
+void con_attr(int a)
+{
+ attr = a;
+}
+
+#define con_init() { con_attr(CON_WHITE); con_clear(); }
+
+void con_start(unsigned int video)
+{
+ screen = (char *) video;
+ con_attr(CON_WHITE);
+ con_clear();
+}
+
+
+void con_clear(void)
+{
+ int i;
+
+ for(posn = screen, i=0;i<80*25;i++){
+ *posn++ = ' ';
+ *posn++ = attr;
+ }
+ px = 0;
+ py = 24;
+ posn = screen + (24*80)*2;
+}
+
+void con_goto(int x, int y)
+{
+ posn = screen + ((y*80)+x)*2;
+ px = x;
+ py = y;
+
+}
+
+/*
+void con_putc(char ch)
+{
+ if(ch == '\n'){
+ goto roll0;
+ }
+ *posn++ = ch;
+ *posn++ = attr;
+ px++;
+ if(px == 80){
+roll0:
+ px = 0;
+ if(py == 24)
+ scrollup();
+ else
+ py++;
+ posn = screen + (py*80+px)*2;
+ }
+}
+*/
+void con_puts(char *s)
+{
+ while(*s){
+ if(*s == '\n'){
+ s++;
+ goto roll1;
+ }
+ *posn++ = *s++;
+ *posn++ = attr;
+ px++;
+ if(px == 80){
+ roll1:
+ px = 0;
+ if(py == 24)
+ scrollup();
+ else
+ py++;
+ posn = screen + (py*80+px)*2;
+ }
+ }
+}
+/*
+static char pbuf[9];
+
+void con_putp(unsigned int p)
+{
+ int i;
+
+ pbuf[8] = 0;
+
+ for(i=7;i>=0;i--){
+ pbuf[i] = (0x0F & p);
+ if(pbuf[i] > 9) pbuf[i] += 'A'-10;
+ else pbuf[i] += '0';
+ p >>= 4;
+ }
+ con_puts(pbuf);
+}
+
+void con_putx(unsigned char x)
+{
+ pbuf[0] = (x & 0xF0) >> 4;
+ if(pbuf[0] > 9) pbuf[0] += 'A'-10;
+ else pbuf[0] += '0';
+ pbuf[1] = (x & 0x0F);
+ if(pbuf[1] > 9) pbuf[1] += 'A'-10;
+ else pbuf[1] += '0';
+ pbuf[2] = 0;
+ con_puts(pbuf);
+}
+*/
+
+void cprintf(char *fmt, ...)
+{
+ char buf[256];
+ va_list pvar;
+ va_start(pvar,fmt);
+ va_snprintf(buf,256,fmt,pvar);
+ va_end(pver);
+ con_puts(buf);
+}
+
diff --git a/lib/libdl/Makefile b/lib/libdl/Makefile
@@ -0,0 +1,16 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+TARGETS := rtld
+SRCS := load.c sym.c elf.c
+LIBRARY := libdl.a
+SHLIB := libdl.so
+SHLIB_MAJOR := 1
+SHLIB_MINOR := 0
+
+RTLD_OBJS = rtld.o sym.o elf.o
+
+rtld: $(RTLD_OBJS)
+ ld -dN -Ttext 0x200074 -o rtld $(RTLD_OBJS) -L../../lib/obj -lc -lblt -lc
+
+include $(BLTHOME)make.actions
diff --git a/lib/libdl/dl-int.h b/lib/libdl/dl-int.h
@@ -0,0 +1,48 @@
+/* $Id: //depot/blt/lib/libdl/dl-int.h#3 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef DL_INT_H
+#define DL_INT_H
+
+#include <elf.h>
+
+typedef struct __lib_t
+{
+ elf32_hdr_t *hdr;
+ elf32_sec_hdr_t *strtab, *symtab, *dynstr, *dynsym;
+ elf32_sym_t *symtab_data, *dynsym_data;
+ char *strtab_data, *dynstr_data;
+ int area, strtab_size, symtab_size, dynsym_size, dynstr_size;
+ struct __lib_t *next;
+} lib_t;
+
+unsigned int __dl_lookup_sym (lib_t *lib, const char *name);
+int __dl_patchup (lib_t *lib);
+
+#endif
+
diff --git a/lib/libdl/elf.c b/lib/libdl/elf.c
@@ -0,0 +1,67 @@
+/* $Id: //depot/blt/lib/libdl/elf.c#3 $
+**
+** Copyright 1998-1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stddef.h>
+#include <string.h>
+#include <elf.h>
+#include <blt/libsyms.h>
+
+elf32_sec_hdr_t *elf_find_section_hdr (elf32_hdr_t *hdr, char *name)
+{
+ char *section_name;
+ int i;
+ elf32_sec_hdr_t *sec_hdr;
+
+ sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff +
+ hdr->e_shstrndx * hdr->e_shentsize);
+ section_name = (char *) ((unsigned int) hdr + sec_hdr->sh_offset);
+ sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff);
+ for (i = 0; i < hdr->e_shnum; i++, sec_hdr = (elf32_sec_hdr_t *)
+ ((unsigned int) sec_hdr + hdr->e_shentsize))
+ if (!strcmp (section_name + sec_hdr->sh_name, name))
+ return sec_hdr;
+ return NULL;
+}
+
+void *elf_find_section_data (elf32_hdr_t *hdr, char *name)
+{
+ elf32_sec_hdr_t *sec_hdr;
+
+ sec_hdr = elf_find_section_hdr (hdr, name);
+ return (sec_hdr == NULL) ? NULL : (void *) ((unsigned int) hdr +
+ sec_hdr->sh_offset);
+}
+
+int elf_section_size (elf32_hdr_t *hdr, char *name)
+{
+ elf32_sec_hdr_t *sec_hdr;
+
+ sec_hdr = elf_find_section_hdr (hdr, name);
+ return (sec_hdr == NULL) ? 0 : sec_hdr->sh_size;
+}
+
diff --git a/lib/libdl/load.c b/lib/libdl/load.c
@@ -0,0 +1,188 @@
+/* $Id: //depot/blt/lib/libdl/load.c#8 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <sys/stat.h>
+#include <blt/libsyms.h>
+#include <blt/syscall.h>
+#include "dl-int.h"
+
+weak_alias (_dlopen, dlopen)
+weak_alias (_dlclose, dlclose)
+weak_alias (_dlerror, dlerror)
+
+const char *__dl_error = NULL;
+static volatile char initialised = 0;
+lib_t *file;
+
+/*
+ * Initialise the list of loaded images with our binary.
+ *
+ * XXX this will break when the executable is at least partially
+ * dynamically linked.
+ */
+void __dlinit (void)
+{
+ initialised = 1;
+ file = malloc (sizeof (lib_t));
+ file->hdr = (elf32_hdr_t *) 0x1000;
+ file->strtab = elf_find_section_hdr (file->hdr, ".strtab");
+ file->strtab_data = elf_find_section_data (file->hdr, ".strtab");
+ file->strtab_size = elf_section_size (file->hdr, ".strtab");
+ file->symtab = elf_find_section_hdr (file->hdr, ".symtab");
+ file->symtab_data = elf_find_section_data (file->hdr, ".symtab");
+ file->symtab_size = elf_section_size (file->hdr, ".symtab");
+/*
+ file->dynstr = elf_find_section_hdr (file->hdr, ".dynstr");
+ file->dynstr_data = elf_find_section_data (file->hdr, ".dynstr");
+ file->dynstr_size = elf_section_size (file->hdr, ".dynstr");
+ file->dynsym = elf_find_section_hdr (file->hdr, ".dynsym");
+ file->dynsym_data = elf_find_section_data (file->hdr, ".dynsym");
+ file->dynsym_size = elf_section_size (file->hdr, ".dynsym");
+*/
+ file->next = NULL;
+}
+
+/*
+ * Loading is not completely straightforward. There is only one hack here,
+ * in that we guess that we will only need one page more memory than the
+ * size of the library. This seems to work on all libraries I can get my
+ * hands on (both OpenBLT and Linux shared libraries).
+ *
+ * The memmove loop may look like a hack because you might think I'm not
+ * completely parsing the program headers. It's not because file offsets
+ * and virtual addresses in an ELF file are equal, modulo 4k or larger
+ * powers of two. Read page 2-7 of the ELF specification for more
+ * information.
+ */
+void *_dlopen (const char *filename, int flag)
+{
+ char *c;
+ int i, size, fd, res, len;
+ struct stat buf;
+ lib_t *lib, *p;
+ elf32_pgm_hdr_t *pgm;
+ int (*fn)(void);
+
+ if (!initialised)
+ __dlinit ();
+
+ __dl_error = NULL;
+ if (_stat (filename, &buf))
+ {
+ errno = ENOENT;
+ return NULL;
+ }
+ size = buf.st_size;
+ size = (size & ~3) ? (size & ~3) + 0x1000 : size;
+ fd = _open (filename, O_RDONLY, 0);
+ if (fd < 0)
+ return NULL;
+ lib = malloc (sizeof (lib_t));
+ lib->area = area_create (size, 0, (void **) &c, 0);
+ len = 0;
+ while ((res = _read (fd, c + len, 0x2000)) > 0)
+ len += res;
+ _close (fd);
+
+ lib->hdr = (elf32_hdr_t *) c;
+ pgm = (elf32_pgm_hdr_t *) ((unsigned int) lib->hdr + lib->hdr->e_phoff);
+ for (i = lib->hdr->e_phnum - 1; i >= 0; i--)
+ memmove ((void *) ((unsigned int) lib->hdr + pgm[i].p_vaddr),
+ (void *) ((unsigned int) lib->hdr + pgm[i].p_offset),
+ pgm[i].p_filesz);
+ lib->strtab = elf_find_section_hdr (lib->hdr, ".strtab");
+ lib->strtab_data = elf_find_section_data (lib->hdr, ".strtab");
+ lib->strtab_size = elf_section_size (lib->hdr, ".strtab");
+ lib->symtab = elf_find_section_hdr (lib->hdr, ".symtab");
+ lib->symtab_data = elf_find_section_data (lib->hdr, ".symtab");
+ lib->symtab_size = elf_section_size (lib->hdr, ".symtab");
+ lib->dynstr = elf_find_section_hdr (lib->hdr, ".dynstr");
+ lib->dynstr_data = elf_find_section_data (lib->hdr, ".dynstr");
+ lib->dynstr_size = elf_section_size (file->hdr, ".dynstr");
+ lib->dynsym = elf_find_section_hdr (lib->hdr, ".dynsym");
+ lib->dynsym_data = elf_find_section_data (lib->hdr, ".dynsym");
+ lib->dynsym_size = elf_section_size (file->hdr, ".dynsym");
+
+ if (__dl_patchup (lib))
+ {
+ area_destroy (lib->area);
+ free (lib);
+ return NULL;
+ }
+ if ((fn = (int (*)(void)) (__dl_lookup_sym (lib, "_init") +
+ (unsigned int) lib->hdr)))
+ res = (*fn) ();
+ if ((flag & ~RTLD_GLOBAL) || res)
+ {
+ p = file;
+ while (p->next != NULL)
+ p = p->next;
+ p->next = lib;
+ lib->next = NULL;
+ }
+ else
+ lib->next = NULL;
+ return lib;
+}
+
+int _dlclose (void *handle)
+{
+ lib_t *lib, *p;
+ void (*fn)(void);
+
+ lib = handle;
+ if (file == lib)
+ file = file->next;
+ else
+ {
+ p = file;
+ while ((p->next != lib) && (p->next != NULL))
+ p = p->next;
+ if (p->next != NULL)
+ p->next = lib->next;
+ }
+ if ((fn = (void (*)(void)) (__dl_lookup_sym (lib, "_fini") +
+ (unsigned int) lib->hdr)))
+ (*fn) ();
+ area_destroy (lib->area);
+ free (handle);
+ return 0;
+}
+
+const char *_dlerror (void)
+{
+ return __dl_error;
+}
+
diff --git a/lib/libdl/rtld.c b/lib/libdl/rtld.c
@@ -0,0 +1,14 @@
+/* $Id: //depot/blt/lib/libdl/rtld.c#1 $
+**
+** Copyright 1999 Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License.
+*/
+
+#include "dl-int.h"
+
+lib_t *file;
+
+void _start (void)
+{
+}
+
diff --git a/lib/libdl/sym.c b/lib/libdl/sym.c
@@ -0,0 +1,139 @@
+/* $Id: //depot/blt/lib/libdl/sym.c#8 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <elf.h>
+#include <dlfcn.h>
+#include <blt/libsyms.h>
+#include "dl-int.h"
+
+weak_alias (_dlsym, dlsym)
+
+extern lib_t *file;
+
+void *_dlsym (void *handle, const char *symbol)
+{
+ int i;
+ lib_t *lib;
+
+ lib = handle;
+ for (i = 0; i < lib->dynsym_size / sizeof (elf32_sym_t); i++)
+ if (!strcmp (lib->dynstr_data + lib->dynsym_data[i].st_name, symbol))
+ return (void *) ((unsigned int) lib->hdr +
+ lib->dynsym_data[i].st_value);
+ for (i = 0; i < lib->symtab_size / sizeof (elf32_sym_t); i++)
+ if (!strcmp (lib->strtab_data + lib->symtab_data[i].st_name, symbol))
+ return (void *) ((unsigned int) lib->hdr +
+ lib->symtab_data[i].st_value);
+ return NULL;
+}
+
+unsigned int __dl_lookup_sym (lib_t *lib, const char *name)
+{
+ int i;
+
+ for (i = 0; i < lib->symtab_size / sizeof (elf32_sym_t); i++)
+ if (!strcmp (lib->strtab_data + lib->symtab_data[i].st_name, name))
+ return lib->symtab_data[i].st_value;
+ return 0;
+}
+
+int __dl_patch_section (lib_t *lib, elf32_rel_t *rel, int size)
+{
+ char *name;
+ int i;
+ unsigned int *word, sym = 0;
+ lib_t *p;
+
+ for (i = 0; i < size; i++)
+ {
+ //_printf ("patching at %x, type %d\n", rel[i].r_offset,
+ // ELF32_R_TYPE (rel[i].r_info));
+ word = (unsigned int *) ((unsigned int) lib->hdr + rel[i].r_offset);
+ if (ELF32_R_SYM (rel[i].r_info))
+ {
+ name = lib->dynstr_data +
+ lib->dynsym_data[ELF32_R_SYM (rel[i].r_info)].st_name;
+ if (!(sym = __dl_lookup_sym (lib, name)))
+ {
+ p = file;
+ while ((p != NULL) && !sym)
+ if (!(sym = __dl_lookup_sym (p, name)))
+ p = p->next;
+ if (!sym)
+ {
+ //_printf ("unresolved symbol %s\n", name);
+ return -1;
+ }
+ if (p != file)
+ sym += (unsigned int) p->hdr;
+ }
+ else
+ sym += (unsigned int) lib->hdr;
+ }
+ switch (ELF32_R_TYPE (rel[i].r_info))
+ {
+ case R_386_32:
+ *word += sym;
+ break;
+
+ case R_386_PC32:
+ *word += sym - (unsigned int) word;
+ break;
+
+ case R_386_RELATIVE:
+ *word += (unsigned int) lib->hdr;
+ break;
+
+ default:
+ //_printf ("unknown relocation type %d; crashing soon...\n",
+ // ELF32_R_TYPE (rel[i].r_info));
+ break;
+ }
+ }
+ return 0;
+}
+
+int __dl_patchup (lib_t *lib)
+{
+ int size;
+ elf32_rel_t *rel;
+
+ rel = (elf32_rel_t *) elf_find_section_data (lib->hdr, ".rel.text");
+ size = elf_section_size (lib->hdr, ".rel.text") / sizeof (elf32_rel_t);
+ if (__dl_patch_section (lib, rel, size))
+ return -1;
+ rel = (elf32_rel_t *) elf_find_section_data (lib->hdr, ".rel.data");
+ size = elf_section_size (lib->hdr, ".rel.data") / sizeof (elf32_rel_t);
+ if (__dl_patch_section (lib, rel, size))
+ return -1;
+ return 0;
+}
+
diff --git a/lib/libposix/Makefile b/lib/libposix/Makefile
@@ -0,0 +1,10 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+LIBRARY := libposix.a
+SHLIB := libposix.so
+SHLIB_MAJOR := 1
+SHLIB_MINOR := 0
+OBJS := exec.o fdl.o vfs.o printf.o stdio.o getopt.o console.o
+
+include $(BLTHOME)make.actions
diff --git a/lib/libposix/console.c b/lib/libposix/console.c
@@ -0,0 +1,74 @@
+/* Copyright 2000, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <string.h>
+#include <blt/namer.h>
+#include <blt/syscall.h>
+#include <blt/libsyms.h>
+
+static int __libc_console_local_port = -1;
+static int __libc_console_out_port = -1;
+
+/* 0 = register, 1 = send, 2 = recv */
+
+int __libc_bind_console (void)
+{
+ if(__libc_console_local_port < 0) {
+ __libc_console_out_port = namer_find("console",1);
+ __libc_console_local_port = port_create(0, "console_io");
+
+ if(port_send(__libc_console_local_port,
+ __libc_console_out_port,
+ NULL, 0, 0) == 0) {
+ return 0;
+ }
+
+ port_destroy(__libc_console_local_port);
+ __libc_console_local_port = -1;
+ }
+ return -1;
+}
+
+size_t __libc_write_console(const void *buf, size_t len)
+{
+ const char *x = (const char *) buf;
+ ssize_t l = len;
+
+ while(len > 0){
+ if(len > 255) {
+ port_send(__libc_console_local_port, __libc_console_out_port,
+ (void*) x, 255, 1);
+ len -= 255;
+ x += 255;
+ } else {
+ port_send(__libc_console_local_port, __libc_console_out_port,
+ (void*) x, len, 1);
+ len = 0;
+ }
+ }
+ return l;
+}
+
+ssize_t __libc_read_console(void *buf, ssize_t len)
+{
+ char *x = (char *) buf;
+ ssize_t r, t;
+
+ t = 0;
+ while(len) {
+ r = port_recv(__libc_console_local_port, NULL, x, 1, NULL);
+ if(r < 0) return 0;
+ x++;
+ t++;
+ len--;
+ }
+
+ return t;
+}
+
+void grab_console(void)
+{
+ port_send(__libc_console_local_port, __libc_console_out_port,
+ NULL, 0, 0);
+}
diff --git a/lib/libposix/exec.c b/lib/libposix/exec.c
@@ -0,0 +1,107 @@
+/* $Id: //depot/blt/lib/libposix/exec.c#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <elf.h>
+#include <sys/stat.h>
+#include <blt/syscall.h>
+#include <blt/libsyms.h>
+
+weak_alias (_execve, execve)
+
+int _execve (const char *path, char * const *argv, char * const *envp)
+{
+ char *ptr, *c;
+ char **n_argv;
+ int i, j, fd, area, sarea, res, size, total;
+ unsigned int *magic;
+ struct stat buf;
+ uint32 *stack, *top;
+
+ res = _stat (path, &buf);
+ if (res)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ size = (buf.st_size & 0xfff) ? (buf.st_size & 0xfffff000) + 0x1000 :
+ buf.st_size;
+ fd = _open (path, O_RDONLY, 0);
+ if (fd < 0)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ area = area_create (size, 0, (void **) &ptr, 0);
+ res = _read (fd, ptr, size);
+ magic = (unsigned int *) ptr;
+ if (*magic != ELF_MAGIC)
+ {
+ errno = ENOEXEC;
+ area_destroy (area);
+ return -1;
+ }
+ // _close(fd);
+
+ /* compute how much stack we need for arguments */
+ for (i = total = 0; argv[i] != NULL; i++)
+ total += strlen (argv[i]) + 1;
+ total = (total & ~3) ? (total & ~3) + 4 : total;
+
+ /* create stack */
+ sarea = area_create (0x1000, 0, (void **) &stack, 0);
+
+ /* copy arguments and set up the argv array */
+ c = (char *) stack + 0xffc - total;
+ n_argv = (char **) (c - i * sizeof (char *));
+ for (j = 0; j < i; j++)
+ {
+ strcpy (c, argv[j]);
+ n_argv[j] = (char *) (0x3ff000 + ((unsigned int) c & 0xfff));
+ c += strlen (argv[j]) + 1;
+ }
+
+ /* drop argc and argv on the top */
+ top = (uint32 *) ((unsigned int) stack + 0x1000 - (total + (i + 3) *
+ sizeof (char *)));
+ top[0] = i;
+ top[1] = 0x3ff000 + (((uint32) top + 8) & 0xfff);
+
+ /* off we go */
+ res = thr_spawn (0x1074, 0x3ff000 + ((unsigned int) top & 0xfff) + 0x10,
+ area, 0x1000, sarea, 0x3ff000, argv[0]);
+
+ /* clean up */
+ area_destroy (area);
+ area_destroy (sarea);
+ return res;
+}
+
diff --git a/lib/libposix/fdl.c b/lib/libposix/fdl.c
@@ -0,0 +1,139 @@
+/* $Id: //depot/blt/lib/libposix/fdl.c#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <blt/qsem.h>
+#include <blt/libsyms.h>
+#include <blt/fdl.h>
+#include <blt/os.h>
+
+static __filedesc **fd_table;
+static qsem_t *fd_table_lock;
+
+weak_alias (_read, read)
+weak_alias (_write, write)
+weak_alias (_ioctl, ioctl)
+weak_alias (_close, close)
+
+void __libc_init_fdl (void)
+{
+ int i;
+
+ fd_table = malloc (sizeof (__filedesc *) * MAX_FDS);
+ for (i = 0; i < MAX_FDS; i++)
+ fd_table[i] = NULL;
+ fd_table_lock = qsem_create (1);
+}
+
+init_info __init_posix_fdl = {
+ &__libc_init_fdl,
+ 1
+};
+
+void __libc_fini_fdl (void)
+{
+ free (fd_table);
+ qsem_destroy (fd_table_lock);
+}
+
+int _fdl_alloc_descriptor (fdl_type *handler, void *cookie)
+{
+ int i;
+
+ qsem_acquire (fd_table_lock);
+ for (i = 0; i < MAX_FDS; i++)
+ if (fd_table[i] == NULL)
+ {
+ fd_table[i] = malloc (sizeof (__filedesc));
+ fd_table[i]->imp = handler;
+ fd_table[i]->cookie = cookie;
+ qsem_release (fd_table_lock);
+ return i;
+ }
+ qsem_release (fd_table_lock);
+ return -1;
+}
+
+void _fdl_free_descriptor (int desc)
+{
+ fd_table[desc] = NULL;
+}
+
+ssize_t _read (int fd, void *buf, size_t count)
+{
+ if (fd_table[fd]->imp->read != NULL)
+ return fd_table[fd]->imp->read (fd_table[fd]->cookie, buf, count);
+ else
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+}
+
+ssize_t _write (int fd, const void *buf, size_t count)
+{
+ if (fd_table[fd]->imp->write != NULL)
+ return fd_table[fd]->imp->write (fd_table[fd]->cookie, buf, count);
+ else
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+}
+
+int _ioctl (int fd, unsigned long request, char *argp)
+{
+ if (fd_table[fd]->imp->ioctl != NULL)
+ return fd_table[fd]->imp->ioctl (fd_table[fd]->cookie, request, argp);
+ else
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+}
+
+int _close (int fd)
+{
+ int res;
+
+ if (fd_table[fd]->imp->close != NULL)
+ {
+ res = fd_table[fd]->imp->close (fd_table[fd]->cookie);
+ fd_table[fd] = NULL;
+ return res;
+ }
+ else
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+}
+
diff --git a/lib/libposix/getopt.c b/lib/libposix/getopt.c
@@ -0,0 +1,122 @@
+/* $Id: //depot/blt/lib/libposix/getopt.c#1 $
+** OpenBSD: getopt.c,v 1.2 1996/08/19 08:33:32 tholo Exp $
+**
+** Copyright (c) 1987, 1993, 1994
+** The Regents of the University of California. All rights reserved.
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. All advertising materials mentioning features or use of this software
+** must display the following acknowledgement:
+** This product includes software developed by the University of
+** California, Berkeley and its contributors.
+** 4. Neither the name of the University nor the names of its contributors
+** may be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <blt/libsyms.h>
+
+weak_alias (_getopt, getopt)
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+extern char *__progname;
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+#define fprintf(file, format, a...) _printf (format, ## a)
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int _getopt (int nargc, char * const *nargv, const char *ostr)
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return (-1);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", __progname, optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ __progname, optopt);
+ return (BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* dump back option letter */
+}
+
diff --git a/lib/libposix/printf.c b/lib/libposix/printf.c
@@ -0,0 +1,44 @@
+/* Copyright 1999, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <stdarg.h>
+#include <string.h>
+#include <blt/namer.h>
+#include <blt/syscall.h>
+#include <blt/libsyms.h>
+
+void va_snprintf (char *s, int len, const char *fmt, ...);
+
+void __libc_bind_console(void);
+ssize_t __libc_write_console(const void *buf, ssize_t len);
+ssize_t __libc_read_console(void *buf, ssize_t);
+
+void __libc_init_console (void)
+{
+ __libc_bind_console ();
+}
+
+weak_alias (_printf, __libc_printf)
+weak_alias (_printf, printf)
+link_warning (__libc_printf, "warning: __libc_printf is deprecated; use printf instead.")
+
+init_info __init_posix_console = {
+ &__libc_init_console,
+ 2
+};
+
+int _printf(char *fmt,...)
+{
+ char buf[256];
+
+ va_list pvar;
+ va_start(pvar,fmt);
+ va_snprintf(buf,256,fmt,pvar);
+ va_end(pvar);
+
+ __libc_write_console(buf, strlen(buf));
+
+ return 0;
+}
+
diff --git a/lib/libposix/stdio.c b/lib/libposix/stdio.c
@@ -0,0 +1,55 @@
+/* Copyright 1999, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <blt/fdl.h>
+#include <blt/syscall.h>
+#include <blt/namer.h>
+#include <blt/libsyms.h>
+
+int __libc_bind_console(void);
+ssize_t __libc_write_console(const void *buf, ssize_t len);
+ssize_t __libc_read_console(void *buf, ssize_t);
+
+static fdl_type console_input_fdl_imp = { "console_input", _console_read,
+ NULL, NULL, NULL };
+
+FILE *stdin, *stdout, *stderr;
+
+weak_alias (_getc, getc)
+weak_alias (_getchar, getchar)
+
+void __libc_init_console_input ()
+{
+ int fd;
+
+ __libc_bind_console();
+
+ fd = _fdl_alloc_descriptor (&console_input_fdl_imp, NULL);
+ if (fd)
+ _printf ("__libc_init_input: console input not on fd 0\n");
+ stdin = malloc (sizeof (FILE));
+ stdin->fd = 0;
+}
+
+int _console_read (void *cookie, void *buf, size_t count)
+{
+ return __libc_read_console(buf, count);
+}
+
+int _getc (FILE *stream)
+{
+ char c;
+
+ _read (stream->fd, &c, 1);
+ return c;
+}
+
+int _getchar (void)
+{
+ return _getc (stdin);
+}
+
diff --git a/lib/libposix/vfs.c b/lib/libposix/vfs.c
@@ -0,0 +1,353 @@
+/* Copyright 1999, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <blt/os.h>
+#include <blt/syscall.h>
+#include <blt/namer.h>
+#include <blt/fdl.h>
+#include <blt/libsyms.h>
+#include <blt/vfs.h>
+
+static int vfs_public_port, vfs_local_port, vfs_remote_port, filename_area;
+static char *nameptr;
+
+static void __vfs_openconn (int src_port, int filename_area);
+ssize_t _vfs_read (void *cookie, void *buf, size_t count);
+int _vfs_close (void *cookie);
+
+static fdl_type vfs_fdl_handler = { "vfs", _vfs_read, NULL, NULL, _vfs_close };
+
+weak_alias (_opendir, opendir)
+weak_alias (_readdir, readdir)
+weak_alias (_closedir, closedir)
+weak_alias (_open, open)
+weak_alias (_stat, stat)
+weak_alias (_mkdir, mkdir)
+
+void __libc_init_vfs (void)
+{
+ vfs_public_port = namer_find ("vfs", 1);
+ vfs_local_port = port_create (vfs_public_port,"vfs_public_port");
+
+ filename_area = area_create (0x1000, 0, (void **) &nameptr, 0);
+ __vfs_openconn (vfs_local_port, filename_area);
+}
+
+init_info __init_posix_vfs = {
+ &__libc_init_vfs,
+ 3
+};
+
+void __libc_fini_vfs (void)
+{
+}
+
+static void __vfs_openconn (int src_port, int filename_area)
+{
+ msg_hdr_t mh;
+ vfs_cmd_t vc;
+ vfs_res_t vr;
+
+ vc.cmd = VFS_OPENCONN;
+ vc.data[0] = filename_area;
+
+ mh.src = vfs_local_port;
+ mh.dst = vfs_public_port;
+ mh.data = &vc;
+ mh.size = sizeof (vc);
+ old_port_send (&mh);
+
+ mh.src = 0; /* XXX */
+ mh.dst = vfs_local_port;
+ mh.data = &vr;
+ mh.size = sizeof (vr);
+ old_port_recv (&mh);
+
+ if (vr.status != VFS_OK)
+ {
+ _printf ("libc: couldn't open connection to vfs\n");
+ vfs_local_port = vfs_remote_port = -1;
+ }
+ vfs_remote_port = vr.data[0];
+}
+
+DIR *_opendir (const char *name)
+{
+ int area;
+ void *ptr;
+ msg_hdr_t msg;
+ vfs_cmd_t vc;
+ vfs_res_t vr;
+ DIR *dirp;
+
+ strlcpy (nameptr, name, BLT_MAX_NAME_LENGTH);
+ area = area_create (0x2000, 0, &ptr, 0);
+
+ vc.cmd = VFS_OPENDIR;
+ vc.data[0] = 0;
+ vc.data[1] = area;
+ vc.data[2] = 0;
+ vc.data[3] = 0x2000;
+ msg.src = vfs_local_port;
+ msg.dst = vfs_remote_port;
+ msg.data = &vc;
+ msg.size = sizeof (vfs_cmd_t);
+ old_port_send (&msg);
+
+ msg.src = vfs_remote_port;
+ msg.dst = vfs_local_port;
+ msg.data = &vr;
+ msg.size = sizeof (vfs_res_t);
+ old_port_recv (&msg);
+
+ if (vr.status != VFS_OK)
+ {
+ errno = vr.errno;
+ return NULL;
+ }
+ //_printf ("libc: opendir got fd %d\n", vr.data[0]);
+ dirp = malloc (sizeof (DIR));
+ dirp->fd = vr.data[0];
+ dirp->hoffset = 0;
+ dirp->head = ptr;
+ dirp->current = ptr;
+ dirp->more = vr.data[2];
+ dirp->len = vr.data[1];
+ dirp->left = dirp->len;
+ return dirp;
+}
+
+struct dirent *_readdir (DIR *dirp)
+{
+ if (dirp == NULL)
+ return NULL;
+ else
+ return (dirp->left-- > 0) ? dirp->current++ : NULL;
+}
+
+int _closedir (DIR *dirp)
+{
+ msg_hdr_t msg;
+ vfs_cmd_t vc;
+ vfs_res_t vr;
+
+ if (dirp == NULL)
+ {
+ errno = EBADF;
+ return -1;
+ }
+ vc.cmd = VFS_CLOSEDIR;
+ vc.data[0] = dirp->fd;
+ msg.src = vfs_local_port;
+ msg.dst = vfs_remote_port;
+ msg.data = &vc;
+ msg.size = sizeof (vfs_cmd_t);
+ old_port_send (&msg);
+
+ msg.src = vfs_remote_port;
+ msg.dst = vfs_local_port;
+ msg.data = &vr;
+ msg.size = sizeof (vfs_res_t);
+ old_port_recv (&msg);
+
+ errno = vr.errno;
+ return (vr.status == VFS_OK) ? 0 : 1;
+}
+
+int _open (const char *path, int flags, mode_t mode)
+{
+ int i, area;
+ void *ptr;
+ msg_hdr_t msg;
+ vfs_cmd_t vc;
+ vfs_res_t vr;
+ vfs_fd *fd;
+
+ strlcpy (nameptr, path, BLT_MAX_NAME_LENGTH);
+ area = area_create (0x2000, 0, &ptr, 0);
+
+ vc.cmd = VFS_OPEN;
+ vc.data[0] = 0;
+ vc.data[1] = area;
+ vc.data[2] = 0;
+ vc.data[3] = 0x2000;
+ msg.src = vfs_local_port;
+ msg.dst = vfs_remote_port;
+ msg.data = &vc;
+ msg.size = sizeof (vfs_cmd_t);
+ old_port_send (&msg);
+
+ msg.src = vfs_remote_port;
+ msg.dst = vfs_local_port;
+ msg.data = &vr;
+ msg.size = sizeof (vfs_res_t);
+ old_port_recv (&msg);
+
+ if (vr.status != VFS_OK)
+ {
+ errno = vr.errno;
+ return -1;
+ }
+ //_printf ("libc: open got %d %d %d\n", vr.data[0], vr.data[1], vr.data[2]);
+ fd = malloc (sizeof (vfs_fd));
+ i = _fdl_alloc_descriptor (&vfs_fdl_handler, fd);
+ fd->buf = ptr;
+ fd->offset = 0;
+ fd->srv_fd = vr.data[0];
+ fd->length = vr.data[1];
+ fd->more = vr.data[2];
+ return i;
+}
+
+int _vfs_close (void *cookie)
+{
+ msg_hdr_t mh;
+ vfs_cmd_t vc;
+ vfs_res_t vr;
+ vfs_fd *vfd;
+
+ vfd = cookie;
+ vc.cmd = VFS_CLOSE;
+ vc.data[0] = vfd->srv_fd;
+ mh.src = vfs_local_port;
+ mh.dst = vfs_remote_port;
+ mh.data = &vc;
+ mh.size = sizeof (vfs_cmd_t);
+ old_port_send (&mh);
+
+ mh.src = vfs_remote_port;
+ mh.dst = vfs_local_port;
+ mh.data = &vr;
+ mh.size = sizeof (vfs_res_t);
+ old_port_recv (&mh);
+
+ if (vr.status != VFS_OK)
+ {
+ errno = vr.errno;
+ return -1;
+ }
+ return 0;
+}
+
+ssize_t _vfs_read (void *cookie, void *buf, size_t count)
+{
+ int i, len;
+ msg_hdr_t mh;
+ vfs_cmd_t vc;
+ vfs_res_t vr;
+ register vfs_fd *vfd;
+
+ vfd = cookie;
+ vc.cmd = VFS_READ;
+ vc.data[0] = vfd->srv_fd;
+ vc.data[1] = count;
+ mh.src = vfs_local_port;
+ mh.dst = vfs_remote_port;
+ mh.data = &vc;
+ mh.size = sizeof (vfs_cmd_t);
+ old_port_send (&mh);
+
+ mh.src = 0;
+ mh.dst = vfs_local_port;
+ mh.data = &vr;
+ mh.size = sizeof (vfs_res_t);
+ old_port_recv (&mh);
+ len = vr.data[0];
+ if (!len)
+ return errno = 0;
+
+ if (len < 0x1000)
+ {
+ mh.data = buf;
+ mh.size = count;
+ old_port_recv (&mh);
+ errno = vr.errno;
+ return len;
+ }
+ else
+ {
+ for (i = 0; len > 0x1000; i += 0x1000, len -= 0x1000)
+ {
+ mh.data = (char *) buf + i;
+ mh.size = 0x1000;
+ old_port_recv (&mh);
+ }
+ mh.data = (char *) buf + i;
+ mh.size = len;
+ old_port_recv (&mh);
+ errno = vr.errno;
+ return i + len;
+ }
+}
+
+int _stat (const char *filename, struct stat *buf)
+{
+ msg_hdr_t msg;
+ vfs_cmd_t vc;
+ vfs_res_t *vr;
+
+ strlcpy (nameptr, filename, BLT_MAX_NAME_LENGTH);
+ vc.cmd = VFS_RSTAT;
+ vc.data[0] = 0;
+ msg.src = vfs_local_port;
+ msg.dst = vfs_remote_port;
+ msg.data = &vc;
+ msg.size = sizeof (vfs_cmd_t);
+ old_port_send (&msg);
+
+ vr = malloc (sizeof (vfs_res_t) + sizeof (struct stat));
+ msg.dst = vfs_local_port;
+ msg.data = vr;
+ msg.size = sizeof (vfs_res_t) + sizeof (struct stat);
+ old_port_recv (&msg);
+
+ if (vr->status == VFS_OK)
+ {
+ memcpy (buf, (void *) vr + sizeof (vfs_res_t), sizeof (struct stat));
+ return 0;
+ }
+ else
+ {
+ errno = vr->errno;
+ return -1;
+ }
+}
+
+int _mkdir (const char *path, mode_t mode)
+{
+ msg_hdr_t mh;
+ vfs_cmd_t vc;
+ vfs_res_t vr;
+
+ strlcpy (nameptr, path, BLT_MAX_NAME_LENGTH);
+ vc.cmd = VFS_MKDIR;
+ vc.data[0] = 0;
+ vc.data[1] = mode;
+ mh.src = vfs_local_port;
+ mh.dst = vfs_remote_port;
+ mh.data = &vc;
+ mh.size = sizeof (vfs_cmd_t);
+ old_port_send (&mh);
+
+ mh.src = vfs_remote_port;
+ mh.dst = vfs_local_port;
+ mh.data = &vr;
+ mh.size = sizeof (vfs_res_t);
+ old_port_recv (&mh);
+
+ if (vr.status != VFS_OK)
+ {
+ errno = vr.errno;
+ return -1;
+ }
+ return 0;
+}
+
diff --git a/lib/libwin/Button.cpp b/lib/libwin/Button.cpp
@@ -0,0 +1,85 @@
+#include <win/Event.h>
+#include <win/Button.h>
+#include <stdlib.h>
+#include <string.h>
+
+Button::Button(const char *text)
+ : fMouseDown(false),
+ fOverButton(false)
+{
+ fText = (char*) malloc(strlen(text) + 1);
+ memcpy(fText, text, strlen(text) + 1);
+}
+
+Button::~Button()
+{
+ free(fText);
+}
+
+void Button::Invoke()
+{
+}
+
+void Button::Repaint(long, long, long, long)
+{
+ long left, top, right, bottom;
+ GetBounds(&left, &top, &right, &bottom);
+
+ if (fMouseDown && fOverButton) {
+ left++;
+ top++;
+ } else {
+ right--;
+ bottom--;
+ }
+
+ SetPenColor(5);
+ DrawLine(left, top, right, top);
+ DrawLine(left, bottom, right, bottom);
+ DrawLine(left, top, left, bottom);
+ DrawLine(right, top, right, bottom);
+ SetPenColor(10);
+ FillRect(left + 1, top + 1, right - 1, bottom - 1);
+ DrawString(left + 1, top + 1, fText);
+}
+
+void Button::EventReceived(const Event *event)
+{
+ switch (event->what) {
+ case EVT_MOUSE_DOWN:
+ LockMouseFocus();
+ fMouseDown = true;
+ fOverButton = true;
+ Invalidate();
+ break;
+
+ case EVT_MOUSE_UP:
+ if (fOverButton)
+ Invoke();
+
+ fMouseDown = false;
+ fOverButton = false;
+ Invalidate();
+ break;
+
+ case EVT_MOUSE_ENTER:
+ if (fMouseDown) {
+ fOverButton = true;
+ Invalidate();
+ }
+
+ break;
+
+ case EVT_MOUSE_LEAVE:
+ if (fMouseDown) {
+ fOverButton = false;
+ Invalidate();
+ }
+
+ break;
+
+ default:
+ Canvas::EventReceived(event);
+ }
+}
+
diff --git a/lib/libwin/Canvas.cpp b/lib/libwin/Canvas.cpp
@@ -0,0 +1,246 @@
+#include <win/Canvas.h>
+#include <win/Window.h>
+#include <win/Event.h>
+#include "Connection.h"
+#include "../../srv/window/protocol.h"
+
+Canvas::Canvas()
+ : fID(-1),
+ fWindow(0),
+ fInPaint(false),
+ fShowLevel(0)
+{
+}
+
+Canvas::~Canvas()
+{
+}
+
+void Canvas::DrawLine(long x1, long y1, long x2, long y2)
+{
+ if (fWindow == 0)
+ return;
+
+ fWindow->fConnection->WriteInt8(OP_DRAW_LINE);
+ fWindow->fConnection->WriteInt32(fID);
+ fWindow->fConnection->WriteInt32(x1);
+ fWindow->fConnection->WriteInt32(y1);
+ fWindow->fConnection->WriteInt32(x2);
+ fWindow->fConnection->WriteInt32(y2);
+ fWindow->fConnection->EndCommand();
+}
+
+void Canvas::FillRect(long x1, long y1, long x2, long y2)
+{
+ if (fWindow == 0)
+ return;
+
+ fWindow->fConnection->WriteInt8(OP_FILL_RECT);
+ fWindow->fConnection->WriteInt32(fID);
+ fWindow->fConnection->WriteInt32(x1);
+ fWindow->fConnection->WriteInt32(y1);
+ fWindow->fConnection->WriteInt32(x2);
+ fWindow->fConnection->WriteInt32(y2);
+ fWindow->fConnection->EndCommand();
+}
+
+void Canvas::SetPenColor(char c)
+{
+ if (fWindow == 0)
+ return;
+
+ fWindow->fConnection->WriteInt8(OP_SET_PEN_COLOR);
+ fWindow->fConnection->WriteInt32(fID);
+ fWindow->fConnection->WriteInt8(c);
+ fWindow->fConnection->EndCommand();
+}
+
+void Canvas::SetBackgroundColor(char c)
+{
+ if (fWindow == 0)
+ return;
+
+ fWindow->fConnection->WriteInt8(OP_SET_BG_COLOR);
+ fWindow->fConnection->WriteInt32(fID);
+ fWindow->fConnection->WriteInt8(c);
+ fWindow->fConnection->EndCommand();
+}
+
+void Canvas::DrawString(long x, long y, const char *str)
+{
+ if (fWindow == 0)
+ return;
+
+ fWindow->fConnection->WriteInt8(OP_DRAW_STRING);
+ fWindow->fConnection->WriteInt32(fID);
+ fWindow->fConnection->WriteInt32(x);
+ fWindow->fConnection->WriteInt32(y);
+ while (*str)
+ fWindow->fConnection->WriteInt8(*str++);
+
+ fWindow->fConnection->WriteInt8(0);
+ fWindow->fConnection->EndCommand();
+}
+
+void Canvas::CopyRect(long left, long top, long right, long bottom,
+ long newLeft, long newTop)
+{
+ if (fWindow == 0)
+ return;
+
+ fWindow->fConnection->WriteInt8(OP_COPY_RECT);
+ fWindow->fConnection->WriteInt32(fID);
+ fWindow->fConnection->WriteInt32(left);
+ fWindow->fConnection->WriteInt32(top);
+ fWindow->fConnection->WriteInt32(right);
+ fWindow->fConnection->WriteInt32(bottom);
+ fWindow->fConnection->WriteInt32(newLeft);
+ fWindow->fConnection->WriteInt32(newTop);
+ fWindow->fConnection->EndCommand();
+}
+
+
+void Canvas::Hide()
+{
+ if (fWindow == 0)
+ return;
+
+ if (--fShowLevel == 0) {
+ fWindow->fConnection->WriteInt8(OP_HIDE_WINDOW);
+ fWindow->fConnection->WriteInt32(fID);
+ fWindow->fConnection->Flush();
+ }
+}
+
+void Canvas::Show()
+{
+ if (fWindow == 0)
+ return;
+
+ if (++fShowLevel == 1) {
+ fWindow->fConnection->WriteInt8(OP_SHOW_WINDOW);
+ fWindow->fConnection->WriteInt32(fID);
+ fWindow->fConnection->Flush();
+ }
+}
+
+void Canvas::BeginPaint(long *out_left, long *out_top, long *out_right, long *out_bottom)
+{
+ if (fInPaint)
+ return;
+
+ fInPaint = true;
+ fWindow->fConnection->WriteInt8(OP_BEGIN_PAINT);
+ fWindow->fConnection->WriteInt32(fID);
+ fWindow->fConnection->Flush();
+
+ *out_left = fWindow->fConnection->ReadInt32();
+ *out_top = fWindow->fConnection->ReadInt32();
+ *out_right = fWindow->fConnection->ReadInt32();
+ *out_bottom = fWindow->fConnection->ReadInt32();
+}
+
+void Canvas::EndPaint()
+{
+ if (!fInPaint)
+ return;
+
+ fInPaint = false;
+ fWindow->fConnection->WriteInt8(OP_END_PAINT);
+ fWindow->fConnection->WriteInt32(fID);
+ fWindow->fConnection->Flush();
+}
+
+void Canvas::AddChild(Canvas *child, long left, long top, long right, long bottom)
+{
+ if (fWindow == 0)
+ return;
+
+ fWindow->fConnection->WriteInt8(OP_CREATE_WINDOW);
+ fWindow->fConnection->WriteInt32(fID); // My child
+ fWindow->fConnection->WriteInt32(left);
+ fWindow->fConnection->WriteInt32(top);
+ fWindow->fConnection->WriteInt32(right);
+ fWindow->fConnection->WriteInt32(bottom);
+ fWindow->fConnection->WriteInt32(fWindow->fEventPort);
+ fWindow->fConnection->Flush();
+ child->fID = fWindow->fConnection->ReadInt32();
+ child->fWindow = fWindow;
+ child->fLeft = 0;
+ child->fTop = 0;
+ child->fRight = right - left;
+ child->fBottom = bottom - top;
+
+ // Stick window in the window's canvas list
+ child->fWinListNext = fWindow->fCanvasList;
+ child->fWinListPrev = &fWindow->fCanvasList;
+ if (fWindow->fCanvasList)
+ fWindow->fCanvasList->fWinListPrev = &child->fWinListNext;
+
+ fWindow->fCanvasList = child;
+
+ child->Show();
+}
+
+void Canvas::RemoveChild(Canvas *child)
+{
+ fWindow->fConnection->WriteInt8(OP_DESTROY_WINDOW);
+ fWindow->fConnection->WriteInt32(child->fID);
+ fWindow->fConnection->Flush();
+ *child->fWinListPrev = child->fWinListNext;
+}
+
+void Canvas::HandleEvent(Event *event)
+{
+ switch (event->what) {
+ case EVT_PAINT: {
+ long left, top, right, bottom;
+ BeginPaint(&left, &top, &right, &bottom);
+ Repaint(left, top, right, bottom);
+ EndPaint();
+ break;
+ }
+
+ default:
+ EventReceived(event);
+ }
+}
+
+Window* Canvas::GetWindow() const
+{
+ return fWindow;
+}
+
+void Canvas::GetBounds(long *left, long *top, long *right, long *bottom)
+{
+ *left = fLeft;
+ *top = fTop;
+ *right = fRight;
+ *bottom = fBottom;
+}
+
+void Canvas::Invalidate(long left, long top, long right, long bottom)
+{
+ fWindow->fConnection->WriteInt8(OP_INVALIDATE);
+ fWindow->fConnection->WriteInt32(fID);
+ fWindow->fConnection->WriteInt32(left);
+ fWindow->fConnection->WriteInt32(top);
+ fWindow->fConnection->WriteInt32(right);
+ fWindow->fConnection->WriteInt32(bottom);
+ fWindow->fConnection->Flush();
+}
+
+void Canvas::Repaint(long left, long top, long right, long bottom)
+{
+}
+
+void Canvas::EventReceived(const Event *)
+{
+}
+
+void Canvas::LockMouseFocus()
+{
+ fWindow->fConnection->WriteInt8(OP_LOCK_MOUSE_FOCUS);
+ fWindow->fConnection->Flush();
+}
+
diff --git a/lib/libwin/Connection.cpp b/lib/libwin/Connection.cpp
@@ -0,0 +1,138 @@
+#include <blt/namer.h>
+#include <blt/syscall.h>
+#include <blt/conio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "Connection.h"
+
+const int kSendBufferSize = 0x1000;
+const int kMaxCommandSize = 270;
+const int kReceiveBufferSize = 1024;
+
+Connection::Connection(int sendPort, int receivePort)
+ : fSendPort(sendPort),
+ fReceivePort(receivePort),
+ fSendBufferSize(0),
+ fReceiveBufferSize(0),
+ fReceiveBufferPos(0)
+{
+ fSendBuffer = (char*) malloc(kSendBufferSize);
+ fReceiveBuffer = (char*) malloc(kReceiveBufferSize);
+}
+
+Connection::~Connection()
+{
+ free(fSendBuffer);
+ free(fReceiveBuffer);
+ port_destroy(fReceivePort);
+}
+
+void Connection::Write(const void *data, int size)
+{
+ int sizeWritten = 0;
+ while (sizeWritten < size) {
+ int sizeToWrite = size - sizeWritten;
+ if (fSendBufferSize + sizeToWrite > kSendBufferSize)
+ sizeToWrite = kSendBufferSize - fSendBufferSize;
+
+ if (sizeToWrite == 0) {
+ Flush();
+ continue;
+ }
+
+ memcpy((void*) (fSendBuffer + fSendBufferSize), (const void*) ((const char*) data
+ + sizeWritten), sizeToWrite);
+ fSendBufferSize += sizeToWrite;
+ sizeWritten += sizeToWrite;
+ }
+}
+
+void Connection::Read(void *data, int size)
+{
+ int sizeRead = 0;
+ while (sizeRead < size) {
+ int sizeToRead = size - sizeRead;
+
+ if (fReceiveBufferSize - fReceiveBufferPos < sizeToRead)
+ sizeToRead = fReceiveBufferSize - fReceiveBufferPos;
+
+ if (sizeToRead == 0) {
+ Receive();
+ continue;
+ }
+
+ memcpy((void*) ((char*) data + sizeRead),
+ (void*) (fReceiveBuffer + fReceiveBufferPos), sizeToRead);
+ fReceiveBufferPos += sizeToRead;
+ sizeRead += sizeToRead;
+ }
+}
+
+void Connection::EndCommand()
+{
+ if (fSendBufferSize > kSendBufferSize - kMaxCommandSize)
+ Flush();
+}
+
+void Connection::Flush()
+{
+ msg_hdr_t header;
+ header.src = fReceivePort;
+ header.dst = fSendPort;
+ header.data = fSendBuffer;
+ header.size = fSendBufferSize;
+
+ old_port_send(&header);
+
+ fSendBufferSize = 0;
+}
+
+void Connection::Receive()
+{
+ msg_hdr_t header;
+ header.src = 0;
+ header.dst = fReceivePort;
+ header.data = fReceiveBuffer;
+ header.size = kReceiveBufferSize;
+
+ fReceiveBufferSize = old_port_recv(&header);
+ fReceiveBufferPos = 0;
+}
+
+int Connection::ReadInt32()
+{
+ int outval;
+ Read(&outval, 4);
+ return outval;
+}
+
+short Connection::ReadInt16()
+{
+ short outval;
+ Read(&outval, 2);
+ return outval;
+}
+
+char Connection::ReadInt8()
+{
+ char outval;
+ Read(&outval, 1);
+ return outval;
+}
+
+void Connection::WriteInt32(int i)
+{
+ Write(&i, 4);
+}
+
+void Connection::WriteInt16(short s)
+{
+ Write(&s, 2);
+}
+
+void Connection::WriteInt8(char c)
+{
+ Write(&c, 1);
+}
+
diff --git a/lib/libwin/Connection.h b/lib/libwin/Connection.h
@@ -0,0 +1,34 @@
+#ifndef _CONNECTION_H
+#define _CONNECTION_H
+
+class Connection {
+public:
+ Connection(int sendPort, int receivePort);
+ ~Connection();
+
+ int ReadInt32();
+ short ReadInt16();
+ char ReadInt8();
+ void WriteInt32(int);
+ void WriteInt16(short);
+ void WriteInt8(char);
+
+ void Write(const void*, int);
+ void Flush();
+ void EndCommand();
+ void Read(void*, int);
+
+private:
+ void Receive();
+
+ int fSendPort;
+ int fReceivePort;
+ char *fSendBuffer;
+ char *fReceiveBuffer;
+ int fSendBufferSize;
+ int fReceiveBufferSize;
+ int fReceiveBufferPos;
+};
+
+
+#endif
+\ No newline at end of file
diff --git a/lib/libwin/Makefile b/lib/libwin/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+CFLAGS += -fno-pic -fno-exceptions -fno-rtti
+SRCS := Connection.cpp Window.cpp Canvas.cpp Button.cpp
+LIBRARY := libwin.a
+SHLIB := libwin.so
+
+include $(BLTHOME)make.actions
diff --git a/lib/libwin/Window.cpp b/lib/libwin/Window.cpp
@@ -0,0 +1,198 @@
+#include <blt/namer.h>
+#include <blt/syscall.h>
+#include <win/Window.h>
+#include <win/Canvas.h>
+#include <win/Event.h>
+#include <stdio.h>
+#include "../../srv/window/protocol.h"
+#include "Connection.h"
+
+Window::Window(long left, long top, long right, long bottom)
+ : fShowLevel(0),
+ fCanvasList(0)
+{
+ int windowServerPort;
+ windowServerPort = namer_find ("window_server", 0);
+ if (windowServerPort <= 0) {
+ printf("couldn't connect to window server\n");
+ return;
+ }
+
+ int localReplyPort = port_create(0, "client_syncport");
+ fEventPort = port_create(0, "client_eventport");
+
+ fConnection = new Connection(windowServerPort, localReplyPort);
+ fConnection->WriteInt8(OP_CREATE_WINDOW);
+ fConnection->WriteInt32(0); // Child of root window
+ fConnection->WriteInt32(left);
+ fConnection->WriteInt32(top);
+ fConnection->WriteInt32(right);
+ fConnection->WriteInt32(bottom);
+ fConnection->WriteInt32(fEventPort);
+ fConnection->Flush();
+ fID = fConnection->ReadInt32();
+
+ fLock = qsem_create(1);
+
+ thr_create((void*) EventLoop, this, "win_thread");
+}
+
+Window::~Window()
+{
+ qsem_acquire(fLock);
+ while (fCanvasList) {
+ Canvas *child = fCanvasList;
+ fCanvasList = fCanvasList->fWinListNext;
+ fConnection->WriteInt8(OP_DESTROY_WINDOW);
+ fConnection->WriteInt32(child->fID);
+ fConnection->Flush();
+ delete child;
+ }
+
+ fConnection->WriteInt8(OP_DESTROY_WINDOW);
+ fConnection->WriteInt32(fID);
+ fConnection->Flush();
+ delete fConnection;
+
+ qsem_destroy(fLock);
+}
+
+
+void Window::MakeFocus()
+{
+ fConnection->WriteInt8(OP_MAKE_FOCUS);
+ fConnection->WriteInt32(fID);
+ fConnection->Flush();
+}
+
+void Window::Flush()
+{
+ fConnection->Flush();
+}
+
+void Window::WaitEvent(Event *event)
+{
+ msg_hdr_t header;
+ header.src = 0;
+ header.dst = fEventPort;
+ header.data = event;
+ header.size = sizeof(Event);
+ old_port_recv(&header);
+}
+
+void Window::AddChild(Canvas *child, long left, long top, long right, long bottom)
+{
+ fConnection->WriteInt8(OP_CREATE_WINDOW);
+ fConnection->WriteInt32(fID); // My child
+ fConnection->WriteInt32(left);
+ fConnection->WriteInt32(top);
+ fConnection->WriteInt32(right);
+ fConnection->WriteInt32(bottom);
+ fConnection->WriteInt32(fEventPort);
+ fConnection->Flush();
+ child->fID = fConnection->ReadInt32();
+ child->fWindow = this;
+ child->fLeft = 0;
+ child->fTop = 0;
+ child->fRight = right - left;
+ child->fBottom = bottom - top;
+ child->Show();
+
+ // Stick window in my canvas list
+ child->fWinListNext = fCanvasList;
+ child->fWinListPrev = &fCanvasList;
+ if (fCanvasList)
+ fCanvasList->fWinListPrev = &child->fWinListNext;
+
+ fCanvasList = child;
+}
+
+void Window::RemoveChild(Canvas *child)
+{
+ Lock();
+ fConnection->WriteInt8(OP_DESTROY_WINDOW);
+ fConnection->WriteInt32(child->fID);
+ fConnection->Flush();
+ *child->fWinListPrev = child->fWinListNext;
+ if (child->fWinListNext)
+ child->fWinListNext->fWinListPrev = child->fWinListPrev;
+
+ Unlock();
+}
+
+void Window::Lock()
+{
+ qsem_acquire(fLock);
+}
+
+void Window::Unlock()
+{
+ qsem_release(fLock);
+}
+
+void Window::Hide()
+{
+ if (--fShowLevel == 0) {
+ fConnection->WriteInt8(OP_HIDE_WINDOW);
+ fConnection->WriteInt32(fID);
+ fConnection->Flush();
+ }
+}
+
+void Window::Show()
+{
+ if (++fShowLevel == 1) {
+ fConnection->WriteInt8(OP_SHOW_WINDOW);
+ fConnection->WriteInt32(fID);
+ fConnection->Flush();
+ }
+}
+
+Canvas* Window::FindChild(int id)
+{
+ for (Canvas *canvas = fCanvasList; canvas; canvas = canvas->fWinListNext)
+ if (canvas->fID == id)
+ return canvas;
+
+ return 0;
+}
+
+void Window::DispatchEvent(Event *event)
+{
+ Canvas *canvas = FindChild(event->target);
+ if (canvas)
+ canvas->HandleEvent(event);
+}
+
+int Window::EventLoop(void *_window)
+{
+ Window *window = (Window*) _window;
+ while (true) {
+ Event event;
+ window->WaitEvent(&event);
+ if (event.what == EVT_QUIT) {
+ delete window;
+ os_terminate(0);
+ }
+
+ window->Lock();
+ window->DispatchEvent(&event);
+ window->Unlock();
+ }
+}
+
+void Window::Quit()
+{
+ Event event;
+ event.what = EVT_QUIT;
+ event.target = fID;
+
+ msg_hdr_t header;
+ header.src = fEventPort; // May break someday
+ header.dst = fEventPort;
+ header.data = &event;
+ header.size = sizeof(Event);
+ old_port_send(&header);
+}
+
+
diff --git a/lib/version.c b/lib/version.c
@@ -0,0 +1,3 @@
+char *ostype = "OpenBLT";
+char *osrelease = "R1";
+char *osversion = "VULCAN#2";
diff --git a/make.actions b/make.actions
@@ -0,0 +1,143 @@
+#
+# For inclusion at the end of a makefile
+#
+
+ifeq ($(QUIET),true)
+SHUSH := @
+endif
+
+# If OBJS unspecified, convert SRCS into OBJS
+#
+ifeq ($(OBJS),)
+OBJS := $(SRCS_TO_OBJS)
+endif
+
+DEPS := $(OBJS:.o=.d)
+include $(DEPS)
+
+ifneq ($(LIBRARY),)
+$(LIBRARY): $(OBJS)
+ifeq ($(QUIET),true)
+ @echo "### Linking: $@"
+endif
+ @rm -f $(LIBRARY)
+ $(SHUSH)$(AR) cr $(LIBRARY) $(OBJS) $(LIBOBJS)
+endif
+
+ifneq ($(SHLIB),)
+ifeq ($(origin SHLIB_MAJOR), undefined)
+SHLIB_NAME := $(SHLIB)
+SHLIB_SONAME :=
+else
+ifeq ($(origin SHLIB_MINOR), undefined)
+SHLIB_NAME := $(SHLIB).$(SHLIB_MAJOR)
+else
+SHLIB_NAME := $(SHLIB).$(SHLIB_MAJOR).$(SHLIB_MINOR)
+endif
+SHLIB_SONAME := -soname $(SHLIB).$(SHLIB_MAJOR)
+endif
+$(SHLIB_NAME): $(OBJS)
+ifeq ($(QUIET),true)
+ @echo "### Linking: $@"
+endif
+ $(SHUSH)$(LD) -Bshareable -o $(SHLIB_NAME) $(SHLIB_SONAME) $(OBJS) $(LIBBASE) $(LIBS)
+ifneq ($(SHLIB), $(SHLIB_NAME))
+ ln -sf $(SHLIB_NAME) $(SHLIB)
+endif
+endif
+
+ifneq ($(BINARY),)
+$(BINARY): $(OBJS)
+ifeq ($(QUIET),true)
+ @echo "### Linking: $@"
+endif
+ $(SHUSH)$(LD) -dN -Ttext $(ENTRY) -o $(BINARY) $(CRT0) $(OBJS) $(LIBBASE) $(LIBS)
+ifeq ($(STRIP),true)
+ $(SHUSH)$(CP) $(BINARY).bin $(BINARY).debug
+ $(SHUSH)$(ST) $(BINARY).bin
+endif
+endif
+
+subdirs::
+ifneq ($(SUBDIRS),)
+ifeq ($(BUILDLOG),)
+ @for i in $(SUBDIRS) ; \
+ do echo "--- Directory: $$i"; \
+ $(MAKE) -C $$i ; \
+ done
+else
+ @for i in $(SUBDIRS) ; \
+ do echo "--- Directory: $$i"; \
+ export BUILDLOG=$(BUILDLOG) ; \
+ if $(MAKE) -C $$i ; then \
+ echo "OKAY `pwd`/$$i" >> $(BUILDLOG); \
+ else \
+ echo "FAIL `pwd`/$$i" >> $(BUILDLOG); \
+ fi ; \
+ done
+endif
+endif
+
+subclean::
+ifneq ($(SUBDIRS),)
+ @for i in $(SUBDIRS) ; \
+ do echo "--- Cleaning: $$i"; \
+ $(MAKE) -C $$i clean ; \
+ done
+endif
+
+all:: check_path $(PRETARGETS) subdirs $(BINARY) $(LIBRARY) $(SHLIB_NAME) $(TARGETS)
+
+clean:: check_path subclean
+ @rm -f $(OBJS) $(LIBOBJS) $(BINARY) $(LIBRARY) $(SHLIB) $(SHLIB_NAME) $(PRETARGETS) $(TARGETS) *.debug *.d
+
+realclean:: clean
+ @rm -f *.d
+
+#############################################
+# rules for compilation of individual files
+#############################################
+DEP_FLAGS := -M -MG $(CFLAGS)
+
+%.o: %.cpp
+ifeq ($(QUIET),true)
+ @echo "### Compiling: $<"
+endif
+ $(SHUSH)$(C++) $(CXXFLAGS) -c $<
+
+%.o: %.c
+ifeq ($(QUIET),true)
+ @echo "### Compiling: $<"
+endif
+ $(SHUSH)$(CC) $(CFLAGS) -c $<
+
+%.o: %.S
+ifeq ($(QUIET),true)
+ @echo "### Assembling: $<"
+endif
+ $(SHUSH)$(CC) $(CFLAGS) -S -o $@ $<
+
+%.o: %.S
+ifeq ($(QUIET),true)
+ @echo "### Assembling: $<"
+endif
+ $(SHUSH)$(CC) $(CFLAGS) -D__ASM__ -c $<
+
+%.d: %.c
+ifeq ($(QUIET),true)
+ @echo "### MakeDeps: $<"
+endif
+ $(SHUSH)$(CC) $(DEP_FLAGS) $< > $@
+
+%.d: %.S
+ifeq ($(QUIET),true)
+ @echo "### MakeDeps: $<"
+endif
+ $(SHUSH)$(CC) -D__ASM__ $(DEP_FLAGS) $< > $@
+
+%.d: %.cpp
+ifeq ($(QUIET),true)
+ @echo "### MakeDeps: $<"
+endif
+ $(SHUSH)$(C++) $(DEP_FLAGS) $< > $@
+
diff --git a/make.conf b/make.conf
@@ -0,0 +1,100 @@
+# Target host for "make run"
+#
+#IP = 10.0.0.5
+#IP = 128.174.252.78
+#IP = 10.113.194.70
+IP = 10.0.0.43
+
+# List of .ini files to pass to bootmaker
+#
+INIFILES := boot/openblt.ini boot/misc.ini boot/window.ini boot/fs.ini
+# LOCALINIFILES :=
+
+##############################################################################
+# KERNEL OPTIONS
+##############################################################################
+# Debug options for monochrome display or serial io
+#
+#VIDMODE = -DMONO
+#SERIAL += -DSERIAL
+#SERIAL += -DSERIAL_DEBUG
+#SERIAL += -DDPRINTF
+#SERIAL += -DPORT_E9
+
+# Uncomment at most one machine type. The default will be equivalent to I386.
+# A sensible choice will get you better performance. Kernels are not
+# guaranteed to run on a lower processor than that which they were built for.
+# Your choice does not affect your ability to do SMP.
+#
+CPU = -DI386
+#CPU = -DI486
+#CPU = -DI586
+#CPU = -DI686
+
+# Uncomment this to build an SMP-capable kernel. SMP kernels will still run
+# on UP machines.
+#
+#SMP = -D__SMP__
+
+##############################################################################
+# END KERNEL OPTIONS
+##############################################################################
+
+# Cross-compilation prefix / postfix stuff
+#
+#PREFIX = i586-beoself-
+#POSTFIX = 386
+
+# Linker arg stuff
+#
+ENTRY_KERNEL = 80000074
+ENTRY_USER = 01074
+ENTRY_BOOTSTRAP = 101074
+ENTRY_ROM = 90074
+
+CC = $(PREFIX)gcc$(POSTFIX)
+C++ = $(PREFIX)g++$(POSTFIX)
+LD = $(PREFIX)ld$(POSTFIX)
+NM = $(PREFIX)nm$(POSTFIX)
+ST = $(PREFIX)strip$(POSTFIX)
+AR = $(PREFIX)ar$(POSTFIX)
+
+OPTIMIZER := -O2
+WARNINGS := -Wall
+
+# Optionally strip all binaries (save some space)
+# .debug versions of binaries will be also made in this case
+#
+STRIP := false
+
+define SRCS_TO_OBJS
+ $(addsuffix .o, $(foreach file, $(SRCS), $(basename $(notdir $(file)))))
+endef
+
+
+# Adjust our paths based on the BLTHOME variable
+#
+#
+ENTRY := $(ENTRY_USER)
+INCLUDES := -I$(BLTHOME)include
+LIBBASE := -L$(BLTHOME)lib/obj
+CRT0 := $(BLTHOME)lib/crt0.o
+
+
+CFLAGS := -nostdinc -fno-builtin $(WARNINGS) -Wno-multichar $(OPTIMIZER) $(INCLUDES) $(VIDMODE) $(CPU)
+
+CXXFLAGS := -nostdinc -fno-rtti -fno-exceptions -fno-builtin $(WARNINGS) -Wno-multichar $(OPTIMIZER) $(INCLUDES) $(VIDMODE) $(CPU)
+
+# Prevent rule confusion...
+#
+
+default: all
+
+# Used to insure BLTHOME is actually set
+#
+check_path:
+ifeq ($(BLTHOME),)
+ @echo error: BLTHOME is not set
+ @/bin/false
+endif
+
diff --git a/netboot/Makefile b/netboot/Makefile
@@ -0,0 +1,37 @@
+BLTHOME := ../
+include $(BLTHOME)make.conf
+
+CFLAGS := -I$(BLTHOME)include -fno-pic -O2
+LIBS := -L$(BLTHOME)lib/obj -lconsole -lkern
+ST := strip
+
+all: netrom.hex
+
+load: netrom.hex
+ ./sersend -b 115200 /dev/ports/serial1 < netrom.hex
+
+makerom: makerom.c
+ gcc -o makerom makerom.c
+
+netrom: netrom.asm
+ nasm netrom.asm
+
+netrom.hex: netrom netboot.raw makerom
+ cat netrom netboot.raw > temp.raw
+ ./makerom temp.raw netrom.hex
+
+OBJS = crt0.o netboot.o pci.o ne2000.o
+
+netboot.raw: $(OBJS)
+ $(LD) -dN -Ttext 0x90000 -o netboot.bin $(OBJS) $(LIBS)
+ $(NM) -nC netboot.bin > netboot.map
+ objcopy -O binary netboot.bin netboot.raw
+
+download: download.c
+ cc -o download download.c
+
+install: download netrom.hex
+ ./download < netrom.hex
+
+clean:
+ rm -f *.o *~ os.* core *.core *.s *.map netboot.bin temp.raw netboot.raw netrom.hex *.boot makerom download
diff --git a/netboot/crt0.c b/netboot/crt0.c
@@ -0,0 +1,33 @@
+/* $Id: //depot/blt/netboot/crt0.c#3 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+void main(int mem);
+
+void _start(int mem)
+{
+ main(mem);
+}
diff --git a/netboot/err.h b/netboot/err.h
@@ -0,0 +1,115 @@
+/* $Id: //depot/blt/netboot/err.h#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __ERR
+#define __ERR
+
+/* NOTE If ret is negative then it is an error otherwise it returns a
+// success code. */
+
+#define NUM_ERR 19
+#define NOERR 0
+#define ERR -1
+#define ERRNOMEM -2
+#define ERRRESOURCE -3
+#define ERRMEMCORRUPT -4
+#define ERRFORMAT -5
+#define ERRNOTFOUND -6
+#define ERRTYPE -7
+#define ERRTIMEOUT -8
+#define ERRNOTSUPPORTED -9
+#define ERROUTOFRANGE -10
+#define ERRPRIV -11
+#define ERRNOTREADY -12
+#define ERRNONEFREE -13
+#define ERRARG -14
+#define ERRINVALID -15
+#define ERRNOTOPEN -16
+#define ERRALREADYDONE -17
+#define ERRVER -18
+
+#define SFOUND 1
+#define SNOTFOUND 2
+#define SALT 3
+
+/* Bits 16-31 are reserved for the facility code. */
+#define OWNOS 0x70
+#define OWNNOMAD 0x70
+
+#define MAX_ERR_MSG 32
+const char err_msg[NUM_ERR][MAX_ERR_MSG] = { "success",
+ "error",
+ "out of memory",
+ "resource allocation",
+ "memory corrupt!!!",
+ "format",
+ "not found",
+ "type",
+ "timeout",
+ "not supported",
+ "out of range",
+ "access denied",
+ "not ready",
+ "none free",
+ "bad argument",
+ "invalid",
+ "not open",
+ "already done",
+ "incorrect version" };
+
+#ifdef __CPP_BINDING
+extern "C" void kprintf(char *, ...);
+class ret {
+ private:
+ int val;
+ public:
+ ret() { val=ERR; }
+ ret(int src) { val=src; }
+ ret operator=(const ret& src) { return val=src.val; }
+ ret operator=(int src) { return val=src; }
+ int operator==(const ret& cmp) { return val==cmp.val; }
+ int operator!() { return val<0; }
+ // returns 1 if error, 0 if success
+ int operator<(int cmp) {
+//kprintf(" %d < %d\n",val,cmp);
+ // TODO implement some severity check
+ return (val<cmp); }
+ int operator<(ret& cmp) {
+//kprintf(" %d < %d\n",val,cmp.val);
+return (val<cmp.val); }
+ operator int() const { return val; }
+// operator bool() { return (val<0); }
+ const char *disp() {
+ if(((val & 0x70) != 0x70) && ((val & 0x70) != 0x00))
+ return "Unknown facility";
+ return err_msg[-val]; }
+};
+#else
+typedef int ret;
+#endif /* __CPP_BINDING */
+
+#endif /* __ERR */
diff --git a/netboot/go b/netboot/go
@@ -0,0 +1,5 @@
+#!/bin/zsh
+cat netrom.bin netboot.bin > test.bin
+./makerom test.bin test.hex
+cp test.hex /dev/cua0
+
diff --git a/netboot/io.h b/netboot/io.h
@@ -0,0 +1,192 @@
+/* $Id: //depot/blt/netboot/io.h#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef _ASM_IO_H
+#define _ASM_IO_H
+
+#define SLOW_IO_BY_JUMPING
+
+/*
+ * This file contains the definitions for the x86 IO instructions
+ * inb/inw/inl/outb/outw/outl and the "string versions" of the same
+ * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
+ * versions of the single-IO instructions (inb_p/inw_p/..).
+ *
+ * This file is not meant to be obfuscating: it's just complicated
+ * to (a) handle it all in a way that makes gcc able to optimize it
+ * as well as possible and (b) trying to avoid writing the same thing
+ * over and over again with slight variations and possibly making a
+ * mistake somewhere.
+ */
+
+/*
+ * Thanks to James van Artsdalen for a better timing-fix than
+ * the two short jumps: using outb's to a nonexistent port seems
+ * to guarantee better timings even on fast machines.
+ *
+ * On the other hand, I'd like to be sure of a non-existent port:
+ * I feel a bit unsafe about using 0x80 (should be safe, though)
+ *
+ * Linus
+ */
+
+#ifdef SLOW_IO_BY_JUMPING
+#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:")
+#else
+#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80")
+#endif
+
+#define SLOW_DOWN_IO __SLOW_DOWN_IO
+
+/*
+ * Talk about misusing macros..
+ */
+
+#define __OUT1(s,x) \
+extern inline void __out##s(unsigned x value, unsigned short port) {
+
+#define __OUT2(s,s1,s2) \
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+
+#define __OUT(s,s1,x) \
+__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \
+__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \
+__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; }
+
+#define __IN1(s) \
+extern inline RETURN_TYPE __in##s(unsigned short port) { RETURN_TYPE _v;
+
+#define __IN2(s,s1,s2) \
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+
+#define __IN(s,s1,i...) \
+__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \
+__IN1(s##c) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \
+__IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; }
+
+#define __INS(s) \
+extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("cld ; rep ; ins" #s \
+: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define __OUTS(s) \
+extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("cld ; rep ; outs" #s \
+: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define RETURN_TYPE unsigned char
+/* __IN(b,"b","0" (0)) */
+__IN(b,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned short
+/* __IN(w,"w","0" (0)) */
+__IN(w,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned int
+__IN(l,"")
+#undef RETURN_TYPE
+
+__OUT(b,"b",char)
+__OUT(w,"w",short)
+__OUT(l,,int)
+
+__INS(b)
+__INS(w)
+__INS(l)
+
+__OUTS(b)
+__OUTS(w)
+__OUTS(l)
+
+/*
+ * Note that due to the way __builtin_constant_p() works, you
+ * - can't use it inside a inline function (it will never be true)
+ * - you don't have to worry about side effects within the __builtin..
+ */
+#define outb(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outbc((val),(port)) : \
+ __outb((val),(port)))
+
+#define inb(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inbc(port) : \
+ __inb(port))
+
+#define outb_p(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outbc_p((val),(port)) : \
+ __outb_p((val),(port)))
+
+#define inb_p(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inbc_p(port) : \
+ __inb_p(port))
+
+#define outw(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outwc((val),(port)) : \
+ __outw((val),(port)))
+
+#define inw(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inwc(port) : \
+ __inw(port))
+
+#define outw_p(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outwc_p((val),(port)) : \
+ __outw_p((val),(port)))
+
+#define inw_p(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inwc_p(port) : \
+ __inw_p(port))
+
+#define outl(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outlc((val),(port)) : \
+ __outl((val),(port)))
+
+#define inl(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inlc(port) : \
+ __inl(port))
+
+#define outl_p(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outlc_p((val),(port)) : \
+ __outl_p((val),(port)))
+
+#define inl_p(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inlc_p(port) : \
+ __inl_p(port))
+
+#endif
diff --git a/netboot/makerom.c b/netboot/makerom.c
@@ -0,0 +1,105 @@
+/* $Id: //depot/blt/netboot/makerom.c#4 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define ROMSIZE 0x4000
+
+unsigned char rom[ROMSIZE];
+unsigned int sum;
+
+void makehex(char *n)
+{
+ FILE *fp;
+ int chk,chk2;
+ int l,i;
+
+ if(fp = fopen(n,"w")){
+ for(l=0;l<ROMSIZE;l+=32) {
+ fprintf(fp,":%02X%04X00",32,l);
+
+ chk = 32;
+
+ chk += ((l & 0xFF00) >> 8);
+ chk += ((l & 0x00FF));
+
+ for(i=0;i<32;i++){
+ fprintf(fp,"%02X",rom[l+i]);
+ chk += rom[l+i];
+ }
+ chk &= 0xFF;
+ chk2 = 0x100 - chk;
+
+ fprintf(fp,"%02X\r\n",(chk2 & 0xFF));
+ }
+ fprintf(fp,":00000001FF\r\n");
+
+ fclose(fp);
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ int i, fd;
+ if (argc < 2) {
+ fprintf(stderr,"usage: %s rom-file hex-file\n",argv[0]);
+ exit(2);
+ }
+ if ((fd = open(argv[1], O_RDWR)) < 0) {
+ perror("unable to open file");
+ return 1;
+ }
+ bzero(rom, ROMSIZE);
+
+ if (read(fd, rom, ROMSIZE) < 0) {
+ perror("read error");
+ return 1;
+ }
+
+ /* store size in ROM header */
+ rom[2] = ROMSIZE / 512;
+
+ /* store size in PCI ROM header */
+ rom[0x18 + 0x10 + 4] = ROMSIZE / 512;
+
+ rom[5] = 0;
+ for (i=0,sum=0; i<ROMSIZE; i++) sum += rom[i];
+ rom[5] = -sum;
+
+ for (i=0,sum=0; i<ROMSIZE; i++) sum += rom[i];
+ if (sum & 0x00FF) printf("checksum fails.\n");
+
+ close(fd);
+
+ makehex(argv[2]);
+
+ return 0;
+}
diff --git a/netboot/ne2000.c b/netboot/ne2000.c
@@ -0,0 +1,627 @@
+/* $Id: //depot/blt/netboot/ne2000.c#3 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/* This file contains the shared code base for the 1997 SigOps NE2000
+// network driver. Use at your own risk! (C) Copyright 1997,
+// Douglas Armstrong site@xnet.com drarmstr@uiuc.edu 10/11/97
+// ...
+// derived from National Semiconductor datasheets and application notes
+// as well as the Linux driver by Donald Becker */
+
+/* Change Log:
+10-25-97 Setup under CVS drarmstr
+10-27-97 Added alloc_buffer() and free_buffer() drarmstr
+*/
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+#include "io.h"
+#include "ne2000.h"
+#include "ne2k.h"
+#include "err.h"
+
+extern void idle();
+extern long ticks; /* replace with a better timeout method, like wait() */
+
+/* we may have to change inb and outb to inb_p and outb_p.
+// Note, none of this code is gauranteed to be reentrant.
+
+// Note, don't create to nics to the same card and then try to use both
+// of them. The results will be unpredictable.
+
+// This violates IO resource manegment if your OS handles that, but it
+// works for now. Make sure that the driver has privlige access to the
+// mapped I/O space and the IRQ.*/
+static unsigned int default_ports[] = { 0x300, 0x280, 0x320, 0x340, 0x360, 0 };
+
+/* internal procedure, don't call this directly.*/
+int nic_probe(int addr) {
+ uint regd;
+ uint state=inb(addr); /* save command state */
+
+ if(inb(addr==0xff)) return ERRNOTFOUND;
+
+ outb(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr);
+ regd=inb(addr + 0x0d);
+ outb(0xff, addr + 0x0d);
+ outb(NIC_DMA_DISABLE | NIC_PAGE0, addr);
+ inb(addr + FAE_TALLY); /* reading CNTR0 resets it.*/
+ if(inb(addr + FAE_TALLY)) { /* counter didn't clear so probe fails*/
+ outb(state,addr); /* restore command state*/
+ outb(regd,addr + 0x0d);
+ return ERRNOTFOUND; }
+
+ return addr; /* network card detected at io addr;*/
+}
+
+/* Detects for presence of NE2000 card. Will check given io addr that
+// is passed to it as well as the default_ports array. Returns ERRNOTFOUND
+// if no card is found, i/o address otherwise. This does conduct an ISA
+// probe, so it's not always a good idea to run it. If you already have
+// the information, then you can just use that with nic_init().*/
+int nic_detect(int given) {
+ int found;
+ if((found=nic_probe(given))!=ERRNOTFOUND) { return found; }
+ return ERRNOTFOUND;
+}
+
+/* This initializes the NE2000 card. If it turns out the card is not
+// really a NE2000 after all then it will return ERRNOTFOUND, else NOERR
+// It also dumps the prom into buffer prom for the upper layers..
+// Pass it a nic with a null iobase and it will initialize the structure for
+// you, otherwise it will just reinitialize it. */
+int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual) {
+ uint f;
+ if(!nic->iobase) {
+ nic->iobase=addr;
+ nic_stat_clear(&nic->stat);
+ nic->pstart=0; nic->pstop=0; nic->wordlength=0;
+ nic->current_page=0;
+ nic->notify=NULL;
+ for(f=0;f<MAX_TX;f++) nic->tx_packet[f].len=0;
+ nic->last_tx=NULL;
+ nic->busy=0;
+ } else {
+ if(!nic->iobase || nic->iobase!=addr) return ERR;
+ }
+
+ outb(inb(addr + NE_RESET), addr + NE_RESET); /* reset the NE2000*/
+ while(!(inb_p(addr+INTERRUPTSTATUS) & ISR_RST)) {
+ /* TODO insert timeout code here.*/
+ }
+
+ outb_p(0xff,addr + INTERRUPTSTATUS); /* clear all pending ints*/
+
+ // Initialize registers
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* enter page 0*/
+ outb_p(DCR_DEFAULT, addr + DATACONFIGURATION);
+ outb_p(0x00, addr + REMOTEBYTECOUNT0);
+ outb_p(0x00, addr + REMOTEBYTECOUNT1);
+ outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/
+ outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/
+ outb_p(RCR_MON, RECEIVECONFIGURATION); /* enter monitor mode*/
+ outb_p(TCR_INTERNAL_LOOPBACK, TRANSMITCONFIGURATION); /* internal loopback*/
+
+ nic->wordlength=nic_dump_prom(nic,prom);
+ if(prom[14]!=0x57 || prom[15]!=0x57) {
+ return ERRNOTFOUND;
+ }
+
+ /* if the wordlength for the NE2000 card is 2 bytes, then
+ // we have to setup the DP8390 chipset to be the same or
+ // else all hell will break loose.*/
+ if(nic->wordlength==2) {
+ outb_p(DCR_DEFAULT_WORD, addr + DATACONFIGURATION);
+ }
+ nic->pstart=(nic->wordlength==2) ? PSTARTW : PSTART;
+ nic->pstop=(nic->wordlength==2) ? PSTOPW : PSTOP;
+
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr);
+ outb_p(nic->pstart, addr + TRANSMITPAGE); /* setup local buffer*/
+ outb_p(nic->pstart + TXPAGES, addr + PAGESTART);
+ outb_p(nic->pstop - 1, addr + BOUNDARY);
+ outb_p(nic->pstop, addr + PAGESTOP);
+ outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/
+ outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/
+ nic->current_page=nic->pstart + TXPAGES;
+
+ /* put physical address in the registers */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); /* switch to page 1 */
+ if(manual) for(f=0;f<6;f++) outb_p(manual[f], addr + PHYSICAL + f);
+ else for(f=0;f<LEN_ADDR;f++) outb_p(prom[f], addr + PHYSICAL + f);
+
+ /* setup multicast filter to accept all packets*/
+ for(f=0;f<8;f++) outb_p(0xFF, addr + MULTICAST + f);
+
+ outb_p(nic->pstart+TXPAGES, addr + CURRENT);
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* switch to page 0 */
+
+ return NOERR;
+}
+
+/* This registers the function that will be called when a new packet
+// comes in. */
+void nic_register_notify(snic *nic, void (*newnotify)(packet_buffer *newpacket)){
+ nic->notify=newnotify;
+}
+
+/* start the NIC so it can actually recieve or transmit packets */
+void nic_start(snic *nic, int promiscuous) {
+ int iobase;
+ if(!nic || !nic->iobase) {
+ return; }
+ iobase=nic->iobase;
+ outb(0xff, iobase + INTERRUPTSTATUS);
+ outb(IMR_DEFAULT, iobase + INTERRUPTMASK);
+ outb(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ outb(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION);
+ if(promiscuous)
+ outb(RCR_PRO | RCR_AM, iobase + RECEIVECONFIGURATION);
+ else
+ outb(RCR_DEFAULT, iobase + RECEIVECONFIGURATION);
+}
+
+/* stops the NIC */
+void nic_stop(snic *nic) {
+ unsigned char tmp_buffer[16];
+ if(!nic || !nic->iobase) return; /* make sure card was initialized */
+ nic_init(nic,nic->iobase,tmp_buffer,NULL);
+}
+
+void nic_isr(snic *nic) {
+ uint isr; /* Illinois Sreet Residence Hall */
+ uint overload;
+ if(!nic || !nic->iobase) return; /* make sure card was initialized */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase);
+ overload=MAX_LOAD+1;
+ while((isr=inb_p(nic->iobase+INTERRUPTSTATUS))) {
+ if((--overload)<=0) break;
+ if(isr & ISR_OVW) nic_overrun(nic);
+ else if(isr & (ISR_PRX | ISR_RXE)) nic_rx(nic);
+ if(isr & ISR_PTX) nic_tx(nic);
+ else if(isr & ISR_TXE) nic_tx_err(nic);
+// if(isr & ISR_CNT) nic_counters(nic);
+ if(isr & ISR_RDC) outb_p(ISR_RDC, nic->iobase+ INTERRUPTSTATUS);
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase);
+ }
+ if(isr) {
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase);
+ if(!overload) {
+
+ outb_p(ISR_ALL, nic->iobase + INTERRUPTSTATUS); // clear
+ } else {
+ outb_p(0xff, nic->iobase + INTERRUPTSTATUS);
+ // Ack it anyway
+ }
+ }
+}
+
+/* You should call this before you just read the stats directlly from the
+// snic struct. This procedure updates the counters */
+nic_stat nic_get_stats(snic *nic) {
+ nic->stat.errors.frame_alignment+=inb_p(nic->iobase + FAE_TALLY);
+ nic->stat.errors.crc+=inb_p(nic->iobase + CRC_TALLY);
+ nic->stat.errors.missed_packets+=inb_p(nic->iobase + MISS_PKT_TALLY);
+ return nic->stat;
+}
+
+void nic_stat_clear(nic_stat *that) {
+ that->rx_packets=0;
+ that->tx_buffered=0; that->tx_packets=0;
+ that->errors.frame_alignment=0; that->errors.crc=0;
+ that->errors.missed_packets=0; that->errors.rx=0;
+ that->errors.rx_size=0; that->errors.rx_dropped=0;
+ that->errors.rx_fifo=0; that->errors.rx_overruns=0;
+ that->errors.tx_collisions=0;
+}
+
+/* Since this could be called by more than one other device, it should
+// be properly protected for reentrancy. We should put in a proper
+// semaphore or something, look into this.
+// NOTE: It is your responsibility to clean up the packet_buffer when you
+// are done calling this. Also note that the buffer.ptr may change if
+// you gave us a packet that was too small and we had to pad the data.
+// UPDATE: we now never change buffer.ptr, but create a whole new
+// packet_buffer instead. We take care of deleting this, so you don't
+// have to worry about it.
+// This is done so we can avoid using dynamic memory allocation ourselves. */
+int nic_send_packet(snic *nic, packet_buffer* buffer) {
+ uint timeout; uint f; int iobase=nic->iobase;
+ packet_buffer *pad=NULL;
+ if(!buffer->len || !buffer->ptr) return ERR;
+ if(!nic || !nic->iobase) return ERR;
+ if(buffer->len>MAX_LENGTH) return ERRFORMAT;
+ /* the following wait for anyother tasks that are calling
+ // nic_send_packet() right now. Note that this doesn't use
+ // an atomic semaphore, so something MAY leak through. */
+ timeout=ticks+10; // wait 10 ticks
+ while(nic->busy && ticks<=timeout) idle();
+ /* Replace this with a proper timeout thing that doesn't use the
+ // ticks method which will be diffrent on each OS. */
+ if(nic->busy) {
+ return ERRTIMEOUT;
+ }
+ nic->busy=1; /* mark as busy, replace with semaphore */
+
+/* XXX should not have to copy the data --- modify nic_block_output to
+ optionally add padding 0's */
+ if(buffer->len<MIN_LENGTH) {
+/* unsigned char *newbuffer=(unsigned char*)kalloc(MIN_LENGTH);
+ if(!newbuffer) return ERRNOMEM; */
+ pad=alloc_buffer(MIN_LENGTH);
+ if(!pad) {
+ nic->busy=0; /* V() */
+ return ERRNOMEM; }
+ for(f=0;f<buffer->len;f++) pad->ptr[f]=buffer->ptr[f];
+ for(;f<MIN_LENGTH;f++) pad->ptr[f]='\0';
+ /* pad the data to the minimum size. */
+ buffer=pad;
+ }
+
+ outb_p(0x00, iobase + INTERRUPTMASK); /* mask ints for now */
+ for(f=0;f<MAX_TX;f++) {
+ if(nic->tx_packet[f].len==0) {
+ nic->tx_packet[f]=*buffer;
+ nic->tx_packet[f].page=nic->pstart + (f * MAX_PAGESPERPACKET);
+ /*output page */
+
+ nic_block_output(nic,nic->tx_packet[f].ptr,
+ nic->tx_packet[f].len,
+ nic->tx_packet[f].page );
+
+ nic->send=f;
+ /* now let's actually trigger the transmitter to send */
+ if(nic_send(nic,f)<0) break;
+ /* note, the nic_tx() interrupt will mark this
+ // tx_packet buffer as free again once it
+ // confirms that the packet was sent. */
+
+ nic->stat.tx_buffered++;
+ outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */
+ nic->busy=0; /* V() */
+ if(pad) free_buffer(pad);
+ return NOERR;
+ }
+ }
+
+ outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */
+ nic->busy=0; /* V() */
+ if(pad) free_buffer(pad);
+ return ERR;
+ /* since we passed with nic->busy not busy then we should
+ // always have at least one buffer free. */
+}
+
+/* dumps the prom into a 16 byte buffer and returns the wordlength of
+// the card.
+// You should be able to make this procedure a wrapper of nic_block_input(). */
+int nic_dump_prom(snic *nic, unsigned char *prom) {
+ uint f;
+ int iobase=nic->iobase;
+ char wordlength=2; /* default wordlength of 2 */
+ unsigned char dump[32];
+ outb_p(32, iobase + REMOTEBYTECOUNT0); /* read 32 bytes from DMA->IO */
+ outb_p(0x00, iobase + REMOTEBYTECOUNT1); /* this is for the PROM dump */
+ outb_p(0x00, iobase + REMOTESTARTADDRESS0); /* configure DMA for 0x0000 */
+ outb_p(0x00, iobase + REMOTESTARTADDRESS1);
+ outb_p(NIC_REM_READ | NIC_START, iobase);
+ for(f=0;f<32;f+=2) {
+ dump[f]=inb_p(iobase + NE_DATA);
+ dump[f+1]=inb_p(iobase + NE_DATA);
+ if(dump[f]!=dump[f+1]) wordlength=1;
+ }
+ /* if wordlength is 2 bytes, then collapse prom to 16 bytes */
+ for(f=0;f<LEN_PROM;f++) prom[f]=dump[f+((wordlength==2)?f:0)];
+
+ return wordlength;
+}
+
+void nic_overrun(snic *nic) {
+ uint tx_status; int iobase=nic->iobase;
+ long starttime; uint resend=0;
+ if(!nic || !nic->iobase) return;
+ tx_status=inb_p(iobase) & NIC_TRANSMIT;
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, iobase);
+ nic->stat.errors.rx_overruns++;
+
+ starttime=ticks;
+/*kprintf("BEFORE\n");*/
+ while(ticks-starttime<=10/*ticks to wait*/) idle();
+ /* Arrgh! TODO: Replace this whole crappy code with a decent
+ // wait method. We need to wait at least 1.6ms as per National
+ // Semiconductor datasheets, but we should probablly wait a
+ // little more to be safe.
+//kprintf("AFTER\n"); */
+
+ outb_p(0x00, iobase + REMOTEBYTECOUNT0);
+ outb_p(0x00, iobase + REMOTEBYTECOUNT1);
+ if(tx_status) {
+ uint tx_completed=inb_p(iobase + INTERRUPTSTATUS) &
+ (ISR_PTX | ISR_TXE);
+ if(!tx_completed) resend=1;
+ }
+
+ outb_p(TCR_INTERNAL_LOOPBACK, iobase + TRANSMITCONFIGURATION);
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ nic_rx(nic); /* cleanup RX ring */
+ outb_p(ISR_OVW, iobase + INTERRUPTSTATUS); /* ACK INT */
+
+ outb_p(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION);
+ if(resend)
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START | NIC_TRANSMIT,
+ iobase);
+}
+
+/* This is the procedure that markst the transmit buffer as available again */
+void nic_tx(snic *nic) {
+ uint f; int iobase=nic->iobase;
+ uint status;
+ if(!nic || !nic->iobase) return;
+ status=inb(iobase + TRANSMITSTATUS);
+
+ if(!nic->tx_packet[nic->send].len) {
+ return;
+ }
+ nic->tx_packet[nic->send].len=0; /* mark buffer as available */
+
+ for(f=0;f<MAX_TX;f++) {
+ if(nic->tx_packet[f].len) {
+ nic->stat.tx_buffered++;
+ nic_send(nic,f); /* send a back-to-back buffer */
+ break;
+ }
+ }
+
+ if(status & TSR_COL) nic->stat.errors.tx_collisions++;
+ if(status & TSR_PTX) nic->stat.tx_packets++;
+ else {
+ if(status & TSR_ABT) {
+ nic->stat.errors.tx_aborts++;
+ nic->stat.errors.tx_collisions+=16; }
+ if(status & TSR_CRS) nic->stat.errors.tx_carrier++;
+ if(status & TSR_FU) nic->stat.errors.tx_fifo++;
+ if(status & TSR_CDH) nic->stat.errors.tx_heartbeat++;
+ if(status & TSR_OWC) nic->stat.errors.tx_window++;
+ }
+
+ outb_p(ISR_PTX, iobase + INTERRUPTSTATUS); /* ack int */
+}
+
+void nic_tx_err(snic *nic) {
+ unsigned char tsr; int iobase=nic->iobase;
+ if(!nic || !nic->iobase) return;
+ tsr=inb_p(nic->iobase);
+/* kprintf("NE2000: ERROR: TX error: ");
+ if(tsr & TSR_ABT) kprintf("Too many collisions.\n");
+ if(tsr & TSR_ND) kprintf("Not deffered.\n");
+ if(tsr & TSR_CRS) kprintf("Carrier lost.\n");
+ if(tsr & TSR_FU) kprintf("FIFO underrun.\n");
+ if(tsr & TSR_CDH) kprintf("Heart attack!\n");
+ */
+ outb_p(ISR_TXE, iobase + INTERRUPTSTATUS);
+ if(tsr & (TSR_ABT | TSR_FU)) {
+ nic_tx(nic);
+ }
+}
+
+void nic_rx(snic *nic) {
+ uint packets=0; uint frame; uint rx_page; uint rx_offset;
+ uint len; uint next_pkt; uint numpages;
+ int iobase=nic->iobase;
+ buffer_header header;
+ if(!nic || !nic->iobase) return;
+ while(packets<MAX_RX) {
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE1, iobase); /*curr is on page 1 */
+ rx_page=inb_p(iobase + CURRENT); /* get current page */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0, iobase);
+ frame=inb(iobase + BOUNDARY)+1;
+ /* we add one becuase boundary is a page behind
+ // as pre NS notes to help in overflow problems */
+ if(frame>=nic->pstop) frame=nic->pstart+TXPAGES;
+ /* circual buffer */
+
+ if(frame==rx_page) break; /* all frames read */
+
+ rx_offset=frame << 8; /* current ptr in bytes(not pages) */
+
+ nic_get_header(nic,frame,&header);
+ len=header.count - sizeof(buffer_header);
+ /* length of packet */
+ next_pkt=frame + 1 + ((len+4)>>8); /* next packet frame */
+
+ numpages=nic->pstop-(nic->pstart+TXPAGES);
+ if( (header.next!=next_pkt)
+ && (header.next!=next_pkt + 1)
+ && (header.next!=next_pkt - numpages)
+ && (header.next != next_pkt +1 - numpages)){
+/* kprintf("NE2000: ERROR: Index mismatch. header.next:%X next_pkt:%X frame:%X\n",
+ header.next,next_pkt,frame);*/
+ nic->current_page=frame;
+ outb(nic->current_page-1, iobase + BOUNDARY);
+ nic->stat.errors.rx++;
+ continue;
+ }
+
+ if(len<60 || len>1518) {
+/* kprintf("NE2000: invalid packet size:%d\n",len);*/
+ nic->stat.errors.rx_size++;
+ } else if((header.status & 0x0f) == RSR_PRX) {
+ /* We have a good packet, so let's recieve it! */
+
+ packet_buffer *newpacket=alloc_buffer(len);
+ if(!newpacket) {
+/* kprintf("NE2000: ERROR: out of memory!\n");*/
+ nic->stat.errors.rx_dropped++;
+ break;
+ }
+
+ nic_block_input(nic,newpacket->ptr,newpacket->len,
+ rx_offset+sizeof(buffer_header));
+ /* read it */
+
+ if(nic->notify) nic->notify(newpacket);
+ /* NOTE: you are responsible for deleting this buffer. */
+
+ nic->stat.rx_packets++;
+
+ } else {
+/* kprintf("NE2000: ERROR: bad packet. header-> status:%X next:%X len:%x.\n",
+ header.status,header.next,header.count); */
+ if(header.status & RSR_FO) nic->stat.errors.rx_fifo++;
+ }
+/* kprintf("frame:%x header.next:%x next_pkt:%x\n",
+// frame,header.next,next_pkt); */
+ next_pkt=header.next;
+
+ if(next_pkt >= nic->pstop) {
+/* kprintf("NE2000: ERROR: next frame beyond local buffer! next:%x.\n",
+ next_pkt);*/
+ next_pkt=nic->pstart+TXPAGES;
+ }
+
+ nic->current_page=next_pkt;
+ outb_p(next_pkt-1, iobase + BOUNDARY);
+ }
+ outb_p(ISR_PRX | ISR_RXE, iobase + INTERRUPTSTATUS); /* ack int */
+}
+
+/* You should be able to make this procedure a wrapper of nic_block_input */
+void nic_get_header(snic *nic, uint page, buffer_header *header) {
+ int iobase=nic->iobase; uint f;
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ outb_p(sizeof(buffer_header), iobase + REMOTEBYTECOUNT0);
+ outb_p(0, iobase + REMOTEBYTECOUNT1); /* read the header */
+ outb_p(0, iobase + REMOTESTARTADDRESS0); /* page boundary */
+ outb_p(page, iobase + REMOTESTARTADDRESS1); /* from this page */
+ outb_p(NIC_REM_READ | NIC_START, iobase); /* start reading */
+
+ if(nic->wordlength==2) for(f=0;f<(sizeof(buffer_header)>>1);f++)
+ ((unsigned short *)header)[f]=inw(iobase+NE_DATA);
+ else for(f=0;f<sizeof(buffer_header);f++)
+ ((unsigned char *)header)[f]=inb(iobase+NE_DATA);
+ /* Do these need to be *_p variants??? */
+ outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */
+}
+
+int nic_send(snic *nic, uint buf) {
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase);
+ if(inb_p(nic->iobase + STATUS) & NIC_TRANSMIT) {
+/* kprintf("NE2000: ERROR: Transmitor busy.\n");*/
+ nic->tx_packet[buf].len=0; /* mark as free again */
+ return ERRTIMEOUT; }
+ outb_p(nic->tx_packet[buf].len & 0xff,nic->iobase+TRANSMITBYTECOUNT0);
+ outb_p(nic->tx_packet[buf].len >> 8,nic->iobase+TRANSMITBYTECOUNT1);
+ outb_p(nic->tx_packet[buf].page,nic->iobase+TRANSMITPAGE);
+ outb_p(NIC_DMA_DISABLE | NIC_TRANSMIT | NIC_START,nic->iobase);
+ return NOERR;
+}
+
+void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset) {
+ int iobase=nic->iobase; uint f;
+ uint xfers=len;
+ uint timeout=TIMEOUT_DMAMATCH; uint addr;
+/* kprintf("NE2000: RX: Length:%x Offset:%x ",len,offset);*/
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ outb_p(len & 0xff, iobase + REMOTEBYTECOUNT0);
+ outb_p(len >> 8, iobase + REMOTEBYTECOUNT1);
+ outb_p(offset & 0xff, iobase + REMOTESTARTADDRESS0);
+ outb_p(offset >> 8, iobase + REMOTESTARTADDRESS1);
+ outb_p(NIC_REM_READ | NIC_START, iobase);
+
+ if(nic->wordlength==2) {
+ for(f=0;f<(len>>1);f++)
+ ((unsigned short *)buf)[f]=inw(iobase+NE_DATA);
+ if(len&0x01) {
+ ((unsigned char *)buf)[len-1]=inb(iobase+NE_DATA);
+ xfers++;
+ }
+ } else for(f=0;f<len;f++)
+ ((unsigned char *)buf)[f]=inb(iobase+NE_DATA);
+ /* Do these need to be *_p variants??? */
+
+/* for(f=0;f<15;f++) kprintf("%X",buf[f]); kprintf("\n");*/
+ /* TODO: make this timeout a constant */
+ for(f=0;f<timeout;f++) {
+ uint high=inb_p(iobase + REMOTESTARTADDRESS1);
+ uint low=inb_p(iobase + REMOTESTARTADDRESS0);
+ addr=(high<<8)+low;
+ if(((offset+xfers)&0xff)==low) break;
+ }
+/* if(f>=timeout)
+ kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n",
+ offset+xfers, addr);*/
+
+ outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */
+}
+
+void nic_block_output(snic *nic, unsigned char *buf, uint len, uint page) {
+ int iobase=nic->iobase;
+ int timeout=TIMEOUT_DMAMATCH; int f; uint addr; int w;
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+
+ /* this next part is to supposedly fix a "read-before-write" bug... */
+ outb_p(0x42, iobase + REMOTEBYTECOUNT0);
+ outb_p(0x00, iobase + REMOTEBYTECOUNT1);
+ outb_p(0x42, iobase + REMOTESTARTADDRESS0);
+ outb_p(0x00, iobase + REMOTESTARTADDRESS1);
+ outb_p(NIC_REM_READ | NIC_START, iobase);
+ SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO;
+
+ outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* ack remote DMA int */
+
+ outb_p(len & 0xff, iobase + REMOTEBYTECOUNT0);
+ outb_p(len >> 8, iobase + REMOTEBYTECOUNT1);
+ outb_p(0x00, iobase + REMOTESTARTADDRESS0);
+ outb_p(page, iobase + REMOTESTARTADDRESS1);
+ outb_p(NIC_REM_WRITE | NIC_START, iobase);
+
+ if(nic->wordlength==2) {
+ for(w=0;w<(len>>1);w++)
+ outw(((unsigned short *)buf)[w],iobase+NE_DATA);
+ if(len & 0x01) {
+ short tmp=buf[len-1]; //so we can output a whole 16-bits
+ // if buf were on the end of something, we would die.
+ outw(tmp,iobase+NE_DATA);
+ }
+ } else for(f=0;f<len;f++)
+ outb(((unsigned char *)buf)[f],iobase+NE_DATA);
+
+ for(f=0;f<timeout;f++) {
+ uint high=inb_p(iobase + REMOTESTARTADDRESS1);
+ uint low=inb_p(iobase + REMOTESTARTADDRESS0);
+ addr=(high<<8)+low;
+ if(( (((page<<8)+(nic->wordlength==2 && (len&0x01))?len:len+1))
+ &0xff)==low)
+ break;
+ }
+/* if(f>=timeout)
+ kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n",
+ page<<8, addr);*/
+
+ outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */
+}
diff --git a/netboot/ne2000.h b/netboot/ne2000.h
@@ -0,0 +1,186 @@
+/* $Id: //depot/blt/netboot/ne2000.h#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __NE2000_SHARED_CODE_BASE
+#define __NE2000_SHARED_CODE_BASE
+typedef unsigned int uint;
+typedef struct snic snic;
+typedef struct nic_stat nic_stat;
+typedef struct buffer_header buffer_header;
+typedef struct packet_buffer packet_buffer;
+typedef struct nic_error_stat nic_error_stat;
+
+/* internal implementation procedures */
+int nic_probe(int addr);
+int nic_dump_prom(snic *nic, unsigned char *prom);
+void nic_overrun(snic *nic);
+void nic_tx(snic *nic);
+void nic_tx_err(snic *nic);
+void nic_rx(snic *nic);
+void nic_counters(snic *nic);
+void nic_get_header(snic *nic, uint page, buffer_header *header);
+int nic_send(snic *nic, uint buf);
+void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset);
+void nic_block_output(snic *nic, unsigned char *buf, uint len, uint page);
+
+#define PSTART 0x20 /* if NE2000 is byte length */
+#define PSTOP 0x40
+#define PSTARTW 0x40 /* if NE2000 is wordlength */
+#define PSTOPW 0x80
+#define MAX_LOAD 12 /* maximum services per IRQ request*/
+#define MAX_RX 10 /* maximum packets recieve per call*/
+#define MIN_LENGTH 60 /* minimum length for packet data */
+#define MAX_LENGTH 1500 /* maximum length for packet data area */
+#define TIMEOUT_DMAMATCH 40 /* for nic_block_input() */
+#define TIMEOUT_TX 40
+
+/* DP8390 NIC Registers*/
+#define COMMAND 0x00
+#define STATUS COMMAND+0
+#define PHYSICAL COMMAND+1 /* page 1 */
+#define MULTICAST COMMAND+8 /* page 1 */
+#define PAGESTART COMMAND+1 /* page 0 */
+#define PAGESTOP COMMAND+2
+#define BOUNDARY COMMAND+3
+#define TRANSMITSTATUS COMMAND+4
+#define TRANSMITPAGE COMMAND+4
+#define TRANSMITBYTECOUNT0 COMMAND+5
+#define NCR COMMAND+5
+#define TRANSMITBYTECOUNT1 COMMAND+6
+#define INTERRUPTSTATUS COMMAND+7
+#define CURRENT COMMAND+7 /* page 1 */
+#define REMOTESTARTADDRESS0 COMMAND+8
+#define CRDMA0 COMMAND+8
+#define REMOTESTARTADDRESS1 COMMAND+9
+#define CRDMA1 COMMAND+9
+#define REMOTEBYTECOUNT0 COMMAND+10 /* how many bytes we will */
+#define REMOTEBYTECOUNT1 COMMAND+11 /* read through remote DMA->IO */
+#define RECEIVESTATUS COMMAND+12
+#define RECEIVECONFIGURATION COMMAND+12
+#define TRANSMITCONFIGURATION COMMAND+13
+#define FAE_TALLY COMMAND+13 /* page 0 */
+#define DATACONFIGURATION COMMAND+14
+#define CRC_TALLY COMMAND+14
+#define INTERRUPTMASK COMMAND+15
+#define MISS_PKT_TALLY COMMAND+15
+
+/* NE2000 specific implementation registers */
+#define NE_RESET 0x1f /* Reset */
+#define NE_DATA 0x10 /* Data port (use for PROM) */
+
+#define PAR0 COMMAND+1
+#define PAR1 COMMAND+2
+#define PAR2 COMMAND+3
+#define PAR3 COMMAND+4
+#define PAR4 COMMAND+5
+#define PAR5 COMMAND+6
+
+/* NIC Commands */
+#define NIC_STOP 0x01 /* STOP */
+#define NIC_START 0x02 /* START */
+#define NIC_PAGE0 0x00
+#define NIC_PAGE1 0x40
+#define NIC_PAGE2 0x80
+#define NIC_TRANSMIT 0x04 /* Transmit a frame */
+#define NIC_REM_READ 0x08 /* Remote Read */
+#define NIC_REM_WRITE 0x10 /* Remote Write */
+#define NIC_DMA_DISABLE 0x20 /* Disable DMA */
+
+/* Data Configuration Register */
+#define DCR_WTS 0x01 /* Word Transfer Select (0=byte, 1=word) */
+#define DCR_BOS 0x02 /* Byte Order Select (0=big-endian) */
+#define DCR_LAS 0x04 /* Long Address Select (0=dual 16-bit DMA) */
+#define DCR_LS 0x08 /* Loopback Select (0=loopback) */
+#define DCR_AR 0x10 /* Auto Initialize Remote */
+#define DCR_FT 0x60 /* (FT0 & FT1) FIFO Threshhold (see datasheet) */
+/*#define DCR_DEFAULT 0x58 /* Standard value for the DCR register */
+#define DCR_DEFAULT 0x48 /* don't use Automatic send packet */
+#define DCR_DEFAULT_WORD 0x49 /* defuault with wold length transfer */
+
+/* Recieve Configure Register */
+#define RCR_SEP 0x01 /* Save Errored Packets */
+#define RCR_AR 0x02 /* Accept Runt Packets */
+#define RCR_AB 0x04 /* Accept Broadcast */
+#define RCR_AM 0x08 /* Accept Multicast */
+#define RCR_PRO 0x10 /* Promiscuous Physical */
+#define RCR_MON 0x20 /* Monitor Mode */
+/*#define RCR_DEFAULT 0x00 /* Standard value for the RCR register */
+#define RCR_DEFAULT 0x0c /* Accept Broadcast/Multicast Packets */
+
+/* Recieve Status Register */
+/* note, this is also stored in the status byte in the buffer header. */
+/* That's the 4 byte entry in the local buffer, not the packet header. */
+#define RSR_PRX 0x01 /* Pakcet Received Intact */
+#define RSR_CRC 0x02 /* CRC Error */
+#define RSR_FAE 0x04 /* Frame Alignment Error */
+#define RSR_FO 0x08 /* FIFO Overrun */
+#define RSR_MPA 0x10 /* Missed Packet */
+#define RSR_PHY 0x20 /* Physical/Multicast Address (0=physical) */
+#define RSR_DIS 0x40 /* Receiver Disabled */
+#define RSR_DFR 0x80 /* Deferring */
+
+/* Transmit Configure Register */
+#define TCR_CRC 0x01 /* Inhibit CRC (0=CRC active) */
+#define TCR_LB 0x06 /* (LB0 & LB1) Encoded Loopback Control */
+#define TCR_ATD 0x08 /* Auto Transmit Disable (0=normal) */
+#define TCR_OFST 0x10 /* Collision Offset Enable (1=low priority) */
+#define TCR_DEFAULT 0x00 /* Standard value for the TCR register */
+#define TCR_INTERNAL_LOOPBACK 0x02 /* Internal loopback configuration */
+
+/* Transmit Status Register */
+#define TSR_PTX 0x01 /* Packet Transmitted */
+#define TSR_ND 0x02 /* Non-Deferral (Documented???) */
+#define TSR_COL 0x04 /* Transmit Collided */
+#define TSR_ABT 0x08 /* Transmit Aborted */
+#define TSR_CRS 0x10 /* Carrier Sense Lost */
+#define TSR_FU 0x20 /* FIFO Underrun */
+#define TSR_CDH 0x40 /* CD Heartbeat */
+#define TSR_OWC 0x80 /* Oout of Window Collision */
+
+/* Interrupt Status Register */
+#define ISR_PRX 0x01 /* Packet Received */
+#define ISR_PTX 0x02 /* Packet Transmitted */
+#define ISR_RXE 0x04 /* Receive Error */
+#define ISR_TXE 0x08 /* Transmit Error */
+#define ISR_OVW 0x10 /* Overwrite Warning */
+#define ISR_CNT 0x20 /* Counter Overflow */
+#define ISR_RDC 0x40 /* Remote DMA Complete */
+#define ISR_RST 0x80 /* Reset Status */
+#define ISR_DEFAULT 0x00 /* Standard value for the ISR register */
+#define ISR_ALL 0x3f /* The services that we handle in the isr */
+
+/* Interrupt Mask Register */
+#define IMR_PRXE 0x01 /* Packet Received Interrupt Enable */
+#define IMR_PTXE 0x02 /* Packet Transmitted Interrupt Enable */
+#define IMR_RXEE 0x04 /* Receive Error Interrupt Enable */
+#define IMR_TXEE 0x08 /* Transmit Error Interrupt Enable */
+#define IMR_OVWE 0x10 /* Overwrite Warning Interrupt Enable */
+#define IMR_CNTE 0x20 /* Counter Overflow Interrupt Enable */
+#define IMR_RDCE 0x40 /* DMA Complete Interrupt Enable */
+#define IMR_DEFAULT 0x3f /* CNTE | OVWE | TXEE | RXEE | PTXE | PRXE */
+
+#endif
diff --git a/netboot/ne2k.h b/netboot/ne2k.h
@@ -0,0 +1,103 @@
+/* $Id: //depot/blt/netboot/ne2k.h#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __NE2000_INTERFACE
+#define __NE2000_INTERFACE
+#ifndef __NE2000_SHARED_CODE_BASE
+typedef unsigned int uint;
+typedef struct snic snic;
+typedef struct nic_stat nic_stat;
+typedef struct buffer_header buffer_header;
+typedef struct packet_buffer packet_buffer;
+typedef struct nic_error_stat nic_error_stat;
+#endif /* NE2000_SHARED_CODE_BASE */
+
+#define LEN_ADDR 6
+#define MAX_TX 2 /* be careful with this (dual buffers) */
+#define MAX_PAGESPERPACKET 6
+#define TXPAGES (MAX_TX*MAX_PAGESPERPACKET)
+#define LEN_PROM 16
+#define LEN_HEADER 14
+
+#ifdef __CPP_BINDING
+extern "C" {
+#endif
+
+/* external interface */
+int nic_detect(int given);
+int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual);
+void nic_register_notify(snic *nic, void (*newnotify)(packet_buffer *newpacket));
+void nic_start(snic *nic, int promiscuous);
+void nic_stop(snic *nic);
+void nic_isr(snic *nic);
+nic_stat nic_get_stats(snic *nic);
+void nic_stat_clear(nic_stat *that);
+int nic_send_packet(snic *nic, packet_buffer*);
+
+/* Your implementation */
+packet_buffer *alloc_buffer(uint size);
+void free_buffer(packet_buffer *ptr);
+
+#ifdef __CPP_BINDING
+};
+#endif
+
+struct buffer_header {
+ unsigned char status;
+ unsigned char next;
+ unsigned short count; /* length of header and packet */
+};
+
+struct nic_error_stat {
+ long frame_alignment, crc, missed_packets;
+ long rx, rx_size, rx_dropped, rx_fifo, rx_overruns;
+ long tx_collisions;
+ long tx_aborts, tx_carrier, tx_fifo, tx_heartbeat, tx_window;
+};
+
+struct nic_stat {
+ long rx_packets;
+ long tx_buffered, tx_packets;
+ nic_error_stat errors;
+};
+
+struct packet_buffer {
+ uint len;
+ uint page;
+ unsigned char *ptr;
+};
+
+struct snic {
+ int iobase; /* NULL if uninitialized */
+ int pstart, pstop, wordlength, current_page;
+ nic_stat stat;
+ void (*notify)(packet_buffer *newpacket);
+ packet_buffer tx_packet[MAX_TX], *last_tx;
+ char busy, send;
+};
+
+#endif /* __NE2000_INTERFACE */
diff --git a/netboot/net.h b/netboot/net.h
@@ -0,0 +1,173 @@
+/* $Id: //depot/blt/netboot/net.h#3 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#pragma pack(2)
+
+/*
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+*/
+
+typedef struct
+{
+ uint8 dst[6];
+ uint8 src[6];
+ uint16 type;
+} net_ether;
+
+typedef struct
+{
+ uint8 ip_hdr_len:4;
+ uint8 ip_version:4;
+ uint8 ip_tos;
+ uint16 ip_len;
+
+ uint16 ip_id;
+ uint16 ip_off;
+
+ uint8 ip_ttl;
+ uint8 ip_proto;
+ uint16 ip_chk;
+
+ uint32 ip_src;
+ uint32 ip_dst;
+} net_ip;
+
+#define IP_PROTO_ICMP 1
+#define IP_PROTO_IGMP 2
+#define IP_PROTO_TCP 6
+#define IP_PROTO_UDP 17
+
+#define IP_TOS_MIN_DELAY 0x10
+#define IP_TOS_MAX_THRU 0x08
+#define IP_TOS_MAX_RELY 0x04
+#define IP_TOS_MIN_COST 0x02
+
+#define IP_FLAG_CE 0x8000
+#define IP_FLAG_DF 0x4000
+#define IP_FLAG_MF 0x2000
+#define IP_FLAG_MASK 0x1FFF
+
+typedef struct
+{
+ uint16 udp_src;
+ uint16 udp_dst;
+
+ uint16 udp_len;
+ uint16 udp_chk;
+} net_udp;
+
+typedef struct
+{
+ uint8 icmp_type;
+ uint8 icmp_code;
+ uint16 icmp_chk;
+} net_icmp;
+
+typedef struct
+{
+ net_icmp ping_icmp;
+ uint16 ping_id;
+ uint16 ping_seq;
+} net_icmp_ping;
+
+typedef struct
+{
+ uint16 arp_hard_type;
+ uint16 arp_prot_type;
+ uint8 arp_hard_size;
+ uint8 arp_prot_size;
+ uint16 arp_op;
+ uint8 arp_enet_sender[6];
+ uint32 arp_ip_sender;
+ uint8 arp_enet_target[6];
+ uint32 arp_ip_target;
+} net_arp;
+
+#define ARP_OP_REQUEST 1
+#define ARP_OP_REPLY 2
+#define RARP_OP_REQUEST 3
+#define RARP_OP_REPLY 4
+
+/* yeah, ugly as shit */
+#define ntohs(n) ( (((n) & 0xFF00) >> 8) | (((n) & 0x00FF) << 8) )
+#define htons(n) ( (((n) & 0xFF00) >> 8) | (((n) & 0x00FF) << 8) )
+#define ntohl(n) ( (((n) & 0xFF000000) >> 24) | (((n) & 0x00FF0000) >> 8) | (((n) & 0x0000FF00) << 8) | (((n) & 0x000000FF) << 24) )
+#define htonl(n) ( (((n) & 0xFF000000) >> 24) | (((n) & 0x00FF0000) >> 8) | (((n) & 0x0000FF00) << 8) | (((n) & 0x000000FF) << 24) )
+
+/*
+typedef struct
+{
+ uint32 ip;
+ uint16 flags;
+ uint8 hw[6];
+} net_arp_table;
+
+typedef struct
+{
+ uint32 dest;
+ uint32 gw;
+ uint32 mask;
+ uint16 flags;
+ net_iface *iface;
+} net_route_table;
+
+
+typedef struct
+{
+ char name[8];
+ uint32 addr;
+ uint32 bcast;
+ uint32 mask;
+ uint16 flags;
+ uint16 mtu;
+ uint32 metric;
+
+ uint32 stat_rx_packets;
+ uint32 stat_rx_errors;
+ uint32 stat_rx_dropped;
+ uint32 stat_rx_overruns;
+
+ uint32 stat_tx_packets;
+ uint32 stat_tx_errors;
+ uint32 stat_tx_dropped;
+ uint32 stat_tx_overruns;
+
+ void (*send)(void);
+ void (*init)(void);
+ void (*add_proto)(net_proto *proto, uint16 id);
+
+} net_iface;
+
+#define IF_UP 0x0001
+#define IF_BROADCAST 0x0002
+#define IF_PROMISC 0x0004
+#define IF_LOOPBACK 0x0008
+#define IF_MULTICAST 0x0010
+#define IF_RUNNING 0x0020
+*/
diff --git a/netboot/netboot.c b/netboot/netboot.c
@@ -0,0 +1,701 @@
+/* $Id: //depot/blt/netboot/netboot.c#8 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "string.h"
+
+#include <blt/conio.h>
+
+#include "net.h"
+#include "boot.h"
+
+#define NULL ((void *) 0)
+
+#include "ne2k.h"
+#include "io.h"
+
+snic TheSNIC;
+
+int nic_addr = 0x300;
+
+char blah[1500]; /* inbound packet buffer */
+
+char defaults[] = "ip=0.0.0.0";
+
+char zz[] = "128.174.38.207";
+
+char param[80];
+
+extern char end[];
+
+#define printf cprintf
+
+int got_server = 0;
+
+int id = 1;
+
+int memsize = 0;
+
+int reset = 0;
+
+int got_ip = 0;
+char *ipmsg = "";
+
+unsigned char prom[32];
+
+unsigned char ip0[8] = { 'i', 'p', '=', 0, 0, 0, 0, 0 };
+unsigned char *ip = ip0 + 3;
+
+unsigned char server_ip[4] = { 0, 0, 0, 0 };
+unsigned char server_mac[6] = { 0, 0, 0, 0, 0, 0 };
+unsigned short port = 0;
+
+#define SKIP 0
+#define LHS 1
+#define RHS 2
+
+void read_ip(char *s, unsigned char *ip)
+{
+ int i=4;
+ int v;
+
+ for(i=4;i>0;i--,ip++){
+ v = 0;
+ while(*s && *s != '.') {
+ v = v*10 + *s-'0';
+ s++;
+ }
+ *ip = v;
+ if(!*s) break;
+ s++;
+ }
+}
+
+void option(char *lhs, char *rhs)
+{
+ if(!strcmp(lhs,"ip")){
+ read_ip(rhs,ip);
+ ipmsg = "(manual)";
+ return;
+ }
+/* if(!strcmp(lhs,"server")){
+ read_ip(rhs,server_ip);
+ return;
+ }
+ if(!strcmp(lhs,"gateway")){
+ read_ip(rhs,gateway_ip);
+ return;
+ }
+ if(!strcmp(lhs,"port")){
+ port = 0;
+ while(*rhs){
+ port = port*10 + *rhs - '0';
+ rhs++;
+ }
+ } */
+ printf("netboot: option %s=\"%s\" unknown\n",lhs,rhs);
+}
+
+void parse(char *p)
+{
+ int state = SKIP;
+ char *lhs;
+ char *rhs;
+
+ while(*p){
+ switch(state){
+ case SKIP :
+ if(*p > ' '){
+ lhs = p;
+ state = LHS;
+ } else {
+ p++;
+ break;
+ }
+ case LHS :
+ if(*p == '='){
+ *p = 0;
+ rhs = ++p;
+ state = RHS;
+ } else {
+ p++;
+ }
+ break;
+ case RHS :
+ if(*p <= ' '){
+ *p = 0;
+ option(lhs,rhs);
+ state = SKIP;
+ }
+ p++;
+ break;
+ }
+ }
+ if(state == RHS){
+ option(lhs,rhs);
+ }
+}
+
+#define ESC 27
+#define BS 8
+#define TAB 9
+#define CR 13
+
+char ScanTable [] = {' ', ESC, '1', '2', '3', '4', '5', '6', '7', '8',
+ '9', '0', '-', '=', BS, TAB, 'q', 'w', 'e', 'r',
+ 't', 'y', 'u', 'i', 'o', 'p', '[', ']', CR, ' ',
+ 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ '\'', '~', ' ', '\\', 'z', 'x', 'c', 'v', 'b', 'n',
+ 'm', ',', '.', '/', ' ', ' ', ' ', ' ', ' '};
+char ShiftTable [] = {' ', ESC, '!', '@', '#', '$', '%', '^', '&', '*',
+ '(', ')', '_', '+', ' ', ' ', 'Q', 'W', 'E', 'R',
+ 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', CR, ' ',
+ 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+ '\"', '~', ' ', '|', 'Z', 'X', 'C', 'V', 'B', 'N',
+ 'M', '<', '>', '?', ' ', ' ', ' ', ' ', ' '};
+#define LSHIFT 42
+#define RSHIFT 54
+
+char linebuf[80];
+int lp;
+
+
+void newline(void)
+{
+ memcpy(linebuf,"netboot> ",9);
+
+ for(lp=9;lp<79;lp++) linebuf[lp]=' ';
+ linebuf[79]=0;
+ lp = 9;
+ con_goto(0,24);
+ con_puts(linebuf);
+
+}
+
+int command(char *cmd)
+{
+ if(cmd[0] == 'g' && cmd[1] == 'o' && cmd[2] == 0) return 1;
+
+ if(cmd[0] == 'b' && cmd[1] == 'o' && cmd[2] == 'o' &&
+ cmd[3] == 't' && cmd[4] == '='){
+ char *p = param;
+ cmd+=5;
+ while(*cmd) {
+ *p = *cmd;
+ cmd++;
+ p++;
+ }
+ *p = 0;
+ return 0;
+
+ }
+
+ parse(cmd);
+
+ return 0;
+}
+
+int keypress(int key)
+{
+ switch(key){
+ case ESC:
+ for(lp=9;lp<79;lp++) linebuf[lp]=' ';
+ lp = 9;
+ break;
+ case CR:
+ printf("\n");
+ linebuf[lp]=0;
+ if(command(linebuf+9)) return 1;
+ newline();
+ break;
+ case BS:
+ if(lp > 9){
+ linebuf[lp-1]=' ';
+ lp--;
+ }
+ break;
+ default:
+ if(lp < 79){
+ linebuf[lp]=key;
+ lp++;
+ }
+ break;
+ }
+ con_goto(0,24);
+ con_puts(linebuf);
+ return 0;
+}
+
+/* keyboard crap */
+int console(void)
+{
+ int key;
+ int shift = 0;
+ newline();
+
+ for(;;){
+ while(inb(0x64) & 0x01) {
+ key = inb(0x60);
+
+ switch(key){
+ case LSHIFT:
+ case RSHIFT:
+ shift = 1;
+ break;
+ case LSHIFT | 0x80:
+ case RSHIFT | 0x80:
+ shift = 0;
+ break;
+ default:
+ if(key & 0x80){
+ /* break */
+ } else {
+ if(key < 59){
+ key = shift ? ShiftTable[key] : ScanTable[key];
+ if(keypress(key)) return 1;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+/* end keyboard crap */
+packet_buffer *alloc_buffer(uint size)
+{
+ static packet_buffer pb;
+
+ pb.len = size;
+ pb.page = 0;
+ pb.ptr = (unsigned char *) blah;
+ return &pb;
+}
+
+void free_buffer(packet_buffer *ptr)
+{
+ int i;
+ return;
+}
+
+int ticks = 0;
+
+void idle(void)
+{
+ int i;
+ for(i=0;i<10000;i++);
+ ticks++;
+}
+
+int memcmp(const void *dst, const void *src, size_t size)
+{
+ while(size) {
+ if(*(((unsigned char *) dst)++) != *(((unsigned char *) src)++))
+ return 1;
+ size--;
+ }
+ return 0;
+}
+
+void *memcpy(void *dst, const void *src, size_t size)
+{
+ while(size) {
+ *(((unsigned char *) dst)++) = *(((unsigned char *) src)++);
+ size--;
+ }
+ return NULL; /* XXX */
+}
+
+typedef struct
+{
+ net_ether ether;
+ net_arp arp;
+} arp_packet;
+
+typedef struct
+{
+ net_ether ether;
+ net_ip ip;
+} ip_packet;
+
+typedef struct
+{
+ net_ether ether;
+ net_ip ip;
+ net_udp udp;
+} udp_packet;
+
+#include "netboot.h"
+
+typedef struct
+{
+ net_ether ether;
+ net_ip ip;
+ net_udp udp;
+ net_boot boot;
+} netboot_packet;
+
+
+int ipchksum(unsigned short *ip, int len)
+{
+ unsigned long sum = 0;
+ len >>= 1;
+ while (len--) {
+ sum += *(ip++);
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ }
+ return((~sum) & 0x0000FFFF);
+}
+
+static netboot_packet nbr;
+
+void handle_udp(udp_packet *pkt)
+{
+ packet_buffer pbuf;
+
+/* printf("handle_udp: %d -> %d, l=%d, ck=%d\n",
+ ntohs(pkt->udp.udp_src),
+ ntohs(pkt->udp.udp_dst),
+ ntohs(pkt->udp.udp_len),
+ ntohs(pkt->udp.udp_chk));*/
+
+ if(ntohs(pkt->udp.udp_dst) == NETBOOT_PORT){
+ netboot_packet *nb = (netboot_packet *) pkt;
+ unsigned int addr = ntohs(nb->boot.blk) * 1024 + NETBOOT_BASE;
+
+ if(ntohs(nb->boot.cmd) != NETBOOT_CMD_LOAD &&
+ ntohs(nb->boot.cmd) != NETBOOT_CMD_EXEC){
+ printf("netboot: invalid command %d\n",
+ ntohs(nb->boot.cmd));
+ return;
+ }
+
+ if(!got_server){
+ memcpy(&server_mac,&(pkt->ether.src),6);
+ memcpy(&server_ip,&(pkt->ip.ip_src),4);
+ printf("netboot: server %d.%d.%d.%d @ %X:%X:%X:%X:%X:%X\n",
+ server_ip[0],server_ip[1],server_ip[2],server_ip[3],
+ server_mac[0],server_mac[1],server_mac[2],server_mac[3],
+ server_mac[4],server_mac[5]);
+ got_server = 1;
+ }
+ if(ntohs(nb->boot.cmd) == NETBOOT_CMD_LOAD){
+/* printf("netboot: loading 1024 bytes, net -> 0x%x\n",
+ addr);*/
+ if(addr == NETBOOT_BASE) {
+ printf("loading ");
+ } else {
+ printf(".");
+ }
+
+ memcpy(((void *) addr), &(nb->boot.data), 1024);
+ }
+
+ memcpy(&(nbr.ether.src),&(prom),6);
+ memcpy(&(nbr.ether.dst),&(server_mac),6);
+ nbr.ether.type = ntohs(0x0800);
+
+ memcpy(&(nbr.ip.ip_src),&ip,4);
+ memcpy(&(nbr.ip.ip_dst),&(server_ip),4);
+ nbr.ip.ip_hdr_len = 5;
+ nbr.ip.ip_version = 4;
+ nbr.ip.ip_tos = 0;
+ nbr.ip.ip_len = ntohs(20+8+8);
+ nbr.ip.ip_id = ntohs(id++);
+ nbr.ip.ip_off = 0;
+ nbr.ip.ip_ttl = 128;
+ nbr.ip.ip_proto = IP_PROTO_UDP;
+ nbr.ip.ip_chk = 0;
+ nbr.ip.ip_chk = ipchksum(&(nbr.ip),sizeof(net_ip));
+
+ nbr.udp.udp_dst = pkt->udp.udp_src;
+ nbr.udp.udp_src = pkt->udp.udp_dst;
+ nbr.udp.udp_chk = 0;
+ nbr.udp.udp_len = ntohs(8 + 4);
+
+ nbr.boot.cmd = htons(NETBOOT_CMD_ACK);
+ nbr.boot.blk = nb->boot.blk;
+ pbuf.ptr = (unsigned char *) &nbr;
+ pbuf.page = 0;
+ pbuf.len = 14 + 20 + 8 + 4;
+
+ if(ntohs(nb->boot.cmd) == NETBOOT_CMD_EXEC){
+ boot_dir *bd = (boot_dir *) NETBOOT_BASE;
+ volatile void (*start)(int, char *, boot_dir *) =
+ bd->bd_entry[1].be_code_ventr +
+ 0x1000 + NETBOOT_BASE;
+
+ printf("\nnetboot: executing at 0x%x\n", (int) start);
+ start(memsize, param[0] ? param : (char *) ip0, bd);
+ asm("hlt");
+ } else {
+ nic_send_packet(&TheSNIC, &pbuf);
+ }
+
+ }
+}
+
+
+void handle_ip(ip_packet *pkt)
+{
+ unsigned char *src = (unsigned char *) &( pkt->ip.ip_src );
+ unsigned char *dst = (unsigned char *) &( pkt->ip.ip_dst );
+ int i;
+
+/* printf("handle_ip: IP: %d.%d.%d.%d -> %d.%d.%d.%d\n",
+ src[0],src[1],src[2],src[3],
+ dst[0],dst[1],dst[2],dst[3]);*/
+
+ if(!memcmp(dst,ip,4)){
+ if(ipchksum(&(pkt->ip),sizeof(net_ip))) {
+ return;
+ }
+/* printf("handle_ip: for me? whoah!\n");*/
+ if(pkt->ip.ip_proto == IP_PROTO_UDP) handle_udp((udp_packet *) pkt);
+
+ }
+
+}
+
+void print_arp(unsigned char *p);
+
+
+unsigned char bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+unsigned char zilch[6] = { 0, 0, 0, 0, 0, 0 };
+
+void issue_rarp_request(void)
+{
+ arp_packet req;
+ packet_buffer pbuf;
+
+ req.ether.type = htons(0x8035);
+ memcpy(&(req.ether.src),prom,6);
+ memcpy(&(req.ether.dst),bcast,6);
+ req.arp.arp_hard_type = htons(1);
+ req.arp.arp_prot_type = htons(0x0800);
+ req.arp.arp_hard_size = 6;
+ req.arp.arp_prot_size = 4;
+ req.arp.arp_op = htons(RARP_OP_REQUEST);
+ memcpy(&(req.arp.arp_enet_sender),prom,6);
+ memcpy(&(req.arp.arp_ip_sender),bcast,4);
+ memcpy(&(req.arp.arp_enet_target),prom,6);
+ memcpy(&(req.arp.arp_ip_target),bcast,4);
+
+ pbuf.ptr = (unsigned char *) &req;
+ pbuf.page = 0;
+ pbuf.len = sizeof(arp_packet);
+ nic_send_packet(&TheSNIC, &pbuf);
+}
+
+void handle_rarp(arp_packet *req)
+{
+ unsigned char *x;
+
+ if(htons(req->arp.arp_op) == RARP_OP_REPLY){
+ if(!memcmp(&(req->arp.arp_enet_target),prom,6)){
+ if(memcmp(&(req->arp.arp_ip_target),ip,4)){
+ x = &(req->arp.arp_ip_target);
+ ip[0] = x[0];
+ ip[1] = x[1];
+ ip[2] = x[2];
+ ip[3] = x[3];
+ got_ip = 1;
+ ipmsg = "(RARP'd)";
+ reset = 1;
+ }
+ }
+ }
+}
+
+void handle_arp(arp_packet *req)
+{
+ if(htons(req->arp.arp_op) == ARP_OP_REQUEST){
+ if(!memcmp(&(req->arp.arp_ip_target),ip,4)){
+ packet_buffer pbuf;
+ arp_packet resp;
+/* printf("handle_arp: IS the one!\n");*/
+/* printf("handle_arp: replying to arp request\n"); */
+ memcpy(&(resp.ether.src),prom,6);
+ memcpy(&(resp.ether.dst),&(req->ether.src),6);
+ resp.ether.type = htons(0x0806);
+ resp.arp.arp_hard_type = htons(1);
+ resp.arp.arp_prot_type = htons(0x0800);
+ resp.arp.arp_hard_size = 6;
+ resp.arp.arp_prot_size = 4;
+ resp.arp.arp_op = htons(ARP_OP_REPLY);
+ memcpy(&(resp.arp.arp_enet_sender),prom,6);
+ memcpy(&(resp.arp.arp_ip_sender),ip,4);
+ memcpy(&(resp.arp.arp_enet_target),&(req->arp.arp_enet_sender),6);
+ memcpy(&(resp.arp.arp_ip_target),&(req->arp.arp_ip_sender),4);
+/* print_arp((unsigned char *) &(resp.arp));*/
+ pbuf.ptr = (unsigned char *) &resp;
+ pbuf.page = 0;
+ pbuf.len = sizeof(arp_packet);
+ nic_send_packet(&TheSNIC, &pbuf);
+ } else {
+/* printf("handle_arp: NOT the one.\n"); */
+ }
+ return;
+ }
+}
+
+void print_arp(unsigned char *p)
+{
+#ifdef ARP_DEBUG
+ net_arp *arp = (net_arp *) p;
+ unsigned char *b;
+ unsigned short t;
+
+ printf(" ARP: ");
+ t = htons(arp->arp_op);
+ if(t == ARP_OP_REQUEST) printf("req ");
+ else if(t == ARP_OP_REPLY) printf("rep ");
+ else printf("??? ");
+
+ b = (unsigned char *) &(arp->arp_enet_sender);
+ printf("source: %X:%X:%X:%X:%X:%X ",b[0],b[1],b[2],b[3],b[4],b[5]);
+ b = (unsigned char *) &(arp->arp_ip_sender);
+ printf("(%d.%d.%d.%d)\n",b[0],b[1],b[2],b[3]);
+
+ printf(" ARP: target: ");
+
+ b = (unsigned char *) &(arp->arp_enet_target);
+ printf("%X:%X:%X:%X:%X:%X ",b[0],b[1],b[2],b[3],b[4],b[5]);
+ b = (unsigned char *) &(arp->arp_ip_target);
+ printf("(%d.%d.%d.%d)\n",b[0],b[1],b[2],b[3]);
+#endif
+}
+
+
+void receive(packet_buffer *packet)
+{
+ unsigned char *b = packet->ptr;
+ int i;
+
+ if(b[12] == 0x80 && b[13] == 0x35) {
+ handle_rarp((arp_packet *) b);
+ return;
+ }
+ if(b[12] != 0x08) return; /* ignore non IP/ARP packets */
+
+ if(b[12] == 0x08 && b[13] == 0x06) {
+/* print_arp(b+14);*/
+ handle_arp((arp_packet *) b);
+ return;
+ }
+
+ if(b[12] == 0x08 && b[13] == 0x00) {
+ handle_ip((ip_packet *) b);
+ return;
+ }
+}
+
+void find_8390(int *addr);
+
+extern char *blagh;
+
+void main(int mem)
+{
+ int i,mono;
+ int nh;
+ char buf[128];
+ int snic_irq = 3;
+ char *x;
+
+ memsize = mem;
+ param[0] = 0;
+
+ mono = (((*((unsigned char *) 0x410)) & 0x30) == 0x30);
+
+ parse(defaults);
+
+ find_8390(&nic_addr);
+
+ ipmsg = "(default)";
+ ip[0] = ip[1] = ip[2] = ip[3] = 10;
+
+ for(;;){
+ reset = 0;
+
+ TheSNIC.iobase = 0;
+ nic_init(&TheSNIC, nic_addr, prom, NULL);
+
+ con_start( mono ? 0xB0000 : 0xB8000);
+
+ if(!mono){
+ con_fgbg(CON_WHITE, CON_BLUE /*WHITE,CON_BLUE*/);
+ }
+/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
+ printf("\n");
+ printf(" ## ## ###### ###### ###### ##### ##### ######\n");
+ printf(" ### ## ## ## ## ## ## ## ## ## ##\n");
+ printf(" ## # ## ##### ## ###### ## ## ## ## ##\n");
+ printf(" ## ### ## ## ## ## ## ## ## ## ## Version 1.5\n");
+ printf(" ## ## ###### ## ###### ##### ##### ## " __DATE__);
+
+ if(!mono){
+ con_fgbg(CON_WHITE,CON_BLACK);
+ }
+ printf("\n\n\n");
+ printf("0x00090000 - bootloader start\n");
+ printf("0x%x - bootloader end\n", (int) end);
+ printf("0x00100000 - target load address\n");
+ printf("0x%x - top of memory\n",mem);
+ printf("\n");
+
+ printf("NE2000 @ 0x%S (%X:%X:%X:%X:%X:%X)\n", nic_addr,
+ prom[0],prom[1],prom[2],prom[3],prom[4],prom[5]);
+
+ printf("ip = %d.%d.%d.%d %s\n",ip[0],ip[1],ip[2],ip[3],
+ ipmsg);
+ if(param[0]) printf("boot = \"%s\"\n",param);
+
+ nic_register_notify(&TheSNIC,receive);
+
+ nic_start(&TheSNIC,0);
+
+ printf("\nready. (ESC for console)\n");
+
+ if(!got_ip){
+ issue_rarp_request();
+ issue_rarp_request();
+ issue_rarp_request();
+ }
+
+ while(!reset){
+ nic_isr(&TheSNIC);
+ if(inb(0x64) & 0x01) {
+ if(inb(0x60) == 1){
+ con_fgbg(CON_YELLOW,CON_BLACK);
+ if(console()) break;
+ }
+ }
+ }
+ nic_stop(&TheSNIC);
+ }
+}
diff --git a/netboot/netboot.h b/netboot/netboot.h
@@ -0,0 +1,43 @@
+/* $Id: //depot/blt/netboot/netboot.h#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#pragma pack(2)
+
+typedef struct
+{
+ unsigned short cmd;
+ unsigned short blk;
+ unsigned char data[1024];
+} net_boot;
+
+#define NETBOOT_CMD_LOAD 1
+#define NETBOOT_CMD_EXEC 2
+#define NETBOOT_CMD_ACK 3
+
+#define NETBOOT_PORT 4242
+
+#define NETBOOT_BASE 0x00100000
diff --git a/netboot/netrom.asm b/netboot/netrom.asm
@@ -0,0 +1,265 @@
+
+
+; 0x02000 [dword] Memory Size
+; 0x02004 [dword] ptable addr
+; 0x03000 page table
+;
+; 0x80000 reloc addr
+;
+; 0x90000 prot mode targ
+; 0x93FFF
+
+memamt equ 0x2000
+ptaddr equ 0x2004
+entry equ 0x90000
+romsize equ 0x4000
+
+ bits 16
+
+rom_start:
+ dw 0xaa55 ; rom signature
+ db 0x20 ; rom size (512 byte units)
+ jmp short s1 ; entrypoint
+ db 0x42 ; checksum (dummy)
+
+ times 0x18 - ($ - rom_start) db 0
+
+ dw pci_header ; PCI Header Offset
+ dw 0x0000 ; PNP Gunk
+
+pci_header:
+ db 'PCIR'
+ dw 0x10ec ; vendor
+ dw 0x8029 ; device
+ dw 0x0000 ; vital data
+ dw 0x0018 ; length
+ db 0 ; pci_header version (0)
+ db 0 ; protocol
+ db 0 ; subclass (ethernet)
+ db 2 ; class (network)
+ dw 0x0000 ; image length
+ dw 0x0000 ; revision
+ db 0 ; code type (x86)
+ db 0x80 ; indicates this is last image
+ dw 0x0000 ; reserved
+
+s1:
+ push ds ; hook into the boot sequence
+
+ xor ax, ax
+ mov ds, ax
+
+ mov word [0x19 * 4], start
+ mov word [0x19 * 4 + 2], cs
+
+ pop ds
+ retf
+
+start:
+ cli
+ cld
+
+ xor di,di ; relocate to 8000:0000
+ xor si,si
+
+ mov ax,0x8000
+ mov es,ax
+
+ mov cx,romsize/4
+ cs
+ rep
+ movsd
+
+ xor ax,ax
+ mov ss,ax
+ mov sp,0xfffc
+
+ mov ax,0x8000
+ mov ds,ax
+
+ jmp 0x8000:start_reloc
+
+start_reloc:
+
+; mov ax, 0x4f02 ; VESA Gunk
+; mov bx, (0x8000 + 0x4000 + 0x105)
+; int 0x10
+
+ call enableA20
+
+ lgdt [unGDT]
+
+ mov eax,cr0
+ or al, 1
+ mov cr0, eax
+
+; jump dword 0x8:(0x80000 + setsegs)
+ db 0x66, 0xea
+ dw setsegs
+ dw 0x0008
+ dw 0x0008
+
+setsegs:
+ mov bx,0x10
+ mov ds,bx
+ mov es,bx
+ mov ss,bx
+
+ and al,0xfe
+ mov cr0, eax
+
+ jmp 0x8000:newip
+
+newip:
+ xor ax,ax
+ mov es,ax
+ mov ds,ax
+ mov ss,ax
+
+ mov edi,0x90000 ; relocate rom to just below 1MB
+ mov esi, eof + 0x80000
+ mov ecx, romsize/4
+ rep a32 movsd
+
+ call countmemory
+
+ mov dword [memamt], eax
+ mov dword [ptaddr], 0x3000
+
+; make some pages tables
+ mov ecx, eax
+ shr ecx, 12
+ mov edi, [ptaddr]
+ add ecx, 0x1000/4
+
+ xor eax, eax
+ rep a32 stosd
+
+ mov ebx, [ptaddr]
+ mov ecx, [memamt]
+
+ shr ecx, 12
+ mov eax, 0x0003
+ mov edi, 0x1000
+
+l1:
+ mov [ebx+edi],eax
+ add eax, 0x1000
+ add edi, 4
+ loop l1
+
+ mov ecx, [memamt]
+ shr ecx, 22
+ inc ecx
+
+ mov eax, [ptaddr]
+ add eax, 0x1003
+ xor edi, edi
+
+l2:
+ mov [ebx+edi], eax
+ mov [ebx+edi+0xf00], eax
+ add eax, 0x1000
+ add edi, 4
+ loop l2
+
+
+ mov eax, [ptaddr]
+ mov ecx, eax
+ or al, 3
+
+ mov [ebx+0xffc], eax
+
+ mov ebx, 0x90000
+
+goprot:
+ push dword 0x0002
+ popfd
+
+ lgdt [cs:GDT]
+
+ mov cr3, ecx
+ mov eax, 0x80000001
+ mov cr0, eax
+
+; jmp far prot
+ db 0x66, 0xea
+ dw 0x0000 + prot, 0x0008, 0x0008
+
+prot:
+ bits 32
+
+ mov eax, 0x10
+ mov ds, eax
+ mov es, eax
+ mov fs, eax
+ mov gs, eax
+ mov ss, eax
+
+ mov esp, ecx
+ sub esp, 4
+
+ push dword [memamt] ; memory amount
+
+ call ebx
+ jmp $
+
+ align 8
+
+unGDT:
+ dw 0xffff, unGDT + 0x0000, 0x0008, 0x0000 ; offset unGDT
+ db 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0x8f, 0x00 ; kCS (0x08) CPL0
+ db 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x8f, 0x00 ; kDS (0x10)
+
+GDT:
+ dw 0xffff, GDT + 0x0000, 0x0008, 0x0000 ; offset GDT
+ db 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 ; kCS (0x08)
+ db 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 ; kDS (0x10)
+
+ bits 16
+
+enableA20:
+ call enableA20o1
+ jnz short enableA20done
+ mov al,0xd1
+ out 0x64,al
+ call enableA20o1
+ jnz short enableA20done
+ mov al,0xdf
+ out 0x60,al
+enableA20o1:
+ mov ecx,0x20000
+enableA20o1l:
+ jmp short enableA20next
+enableA20next:
+ in al,0x64
+ test al,2
+ loopnz enableA20o1l
+enableA20done:
+ ret
+
+countmemory:
+ mov ax, '12'
+ mov ebx, 0x100ff0
+
+b0:
+ mov dx, [ebx] ; save contents
+ mov [ebx], ax ; write signature
+
+ mov di, [ebx] ; read back
+ mov [ebx], dx ; restore contents
+
+ cmp di, ax ; did it stick?
+ jnz b1 ; nope, no more memory
+
+ add ebx, 0x1000
+ jmp b0
+
+b1:
+ mov eax, ebx
+ sub eax, 0x1000
+ add eax, 0x10
+
+ ret
+
+eof:
diff --git a/netboot/netrom.bin b/netboot/netrom.bin
Binary files differ.
diff --git a/netboot/pci.c b/netboot/pci.c
@@ -0,0 +1,67 @@
+#include <blt/types.h>
+#include <i386/io.h>
+
+
+typedef struct confadd
+{
+ uchar reg:8;
+ uchar func:3;
+ uchar dev:5;
+ uchar bus:8;
+ uchar rsvd:7;
+ uchar enable:1;
+} confadd;
+
+uint32 pci_read(int bus, int dev, int func, int reg, int bytes)
+{
+ uint32 base;
+
+ union {
+ confadd c;
+ uint32 n;
+ } u;
+
+ u.c.enable = 1;
+ u.c.rsvd = 0;
+ u.c.bus = bus;
+ u.c.dev = dev;
+ u.c.func = func;
+ u.c.reg = reg & 0xFC;
+
+ outl(u.n,0xCF8);
+
+ base = 0xCFC + (reg & 0x03);
+
+ switch(bytes){
+ case 1: return inb(base);
+ case 2: return inw(base);
+ case 4: return inl(base);
+ default: return 0;
+ }
+}
+
+void find_8390(int *addr)
+{
+ union {
+ struct {
+ uint16 vendor;
+ uint16 device;
+ } id;
+ uint32 n;
+ } u;
+ uint32 n;
+ int bus;
+ int dev;
+
+ for(bus=0;bus<8;bus++){
+ for(dev=0;dev<32;dev++){
+ u.n = pci_read(bus, dev, 0, 0, 4);
+ if((u.id.vendor == 0x10ec) && (u.id.device == 0x8029)){
+ n = pci_read(bus, dev, 0, 0x10, 4);
+ n &= 0xFFF0;
+ *addr = (int) n;
+ return;
+ }
+ }
+ }
+}
diff --git a/srv/Makefile b/srv/Makefile
@@ -0,0 +1,6 @@
+BLTHOME := ../
+include $(BLTHOME)make.conf
+
+SUBDIRS := namer console2 ne2000 vfs init fish ide window pci
+
+include $(BLTHOME)make.actions
diff --git a/srv/console2/Makefile b/srv/console2/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := console.c vt100.c
+CRT0 := $(BLTHOME)lib/crtb.o
+BINARY := console.bin
+LIBS := -lconsole -lblt -lc
+
+include $(BLTHOME)make.actions
diff --git a/srv/console2/console.c b/srv/console2/console.c
@@ -0,0 +1,368 @@
+/* $Id: //depot/blt/srv/console2/console.c#15 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <blt/syscall.h>
+#include <blt/error.h>
+#include <blt/namer.h>
+#include <blt/conio.h>
+#include <blt/qsem.h>
+#include <i386/io.h>
+#include <string.h>
+
+#include "vt100.h"
+
+int console_port = -1;
+int send_port = -1;
+int remote_port = -1;
+
+volatile int ready = 0;
+
+#define CLEAR "\033[2J"
+#define FG_BLACK "\033[30m"
+#define FG_BLUE "\033[31m"
+#define FG_GREEN "\033[32m"
+#define FG_CYAN "\033[33m"
+#define FG_RED "\033[34m"
+#define FG_PURPLE "\033[35m"
+#define FG_BROWN "\033[36m"
+#define FG_WHITE "\033[37m"
+
+#define BG_BLACK "\033[40m"
+#define BG_BLUE "\033[41m"
+#define BG_GREEN "\033[42m"
+#define BG_CYAN "\033[43m"
+#define BG_RED "\033[44m"
+#define BG_PURPLE "\033[45m"
+#define BG_BROWN "\033[46m"
+#define BG_WHITE "\033[47m"
+
+
+#define MONOx
+
+#ifdef MONO
+#define SCREEN 0xB0000
+#else
+#define SCREEN 0xB8000
+#endif
+void *screen = (void *) SCREEN;
+
+void movecursor (int x, int y)
+{
+ int offset;
+
+ offset = 80 * y + x;
+ outb (0xe, 0x3d4);
+ outb (offset / 256, 0x3d5);
+ outb (0xf, 0x3d4);
+ outb (offset % 256, 0x3d5);
+}
+
+struct virtscreen con[10];
+struct virtscreen statbar;
+struct virtscreen *active;
+
+void move_cursor(struct virtscreen *cur)
+{
+ if(cur == active) movecursor(cur->xpos,cur->ypos);
+}
+
+void vprintf(struct virtscreen *vscr, char *fmt, ...);
+void printf(char *fmt, ...);
+
+void keypress(int key)
+{
+ char c;
+
+ sem_acquire(active->lock);
+ char_to_virtscreen(active, key);
+ sem_release(active->lock);
+ if(remote_port > 0) {
+ c = key;
+ port_send(send_port, remote_port, &c, 1, 0);
+ }
+}
+
+void vputs(struct virtscreen *vscr, char *s)
+{
+ sem_acquire(vscr->lock);
+ while(*s) {
+ char_to_virtscreen(vscr, *s);
+ if(*s == '\n') char_to_virtscreen(vscr, '\r');
+ s++;
+ }
+ sem_release(vscr->lock);
+}
+
+
+void printf(char *fmt, ...)
+{
+ static char line[128];
+ va_list pvar;
+ va_start(pvar,fmt);
+ va_snprintf(line,128,fmt,pvar);
+ line[127]=0;
+ va_end(pvar);
+ vputs(active,line);
+}
+
+void vprintf(struct virtscreen *vscr, char *fmt, ...)
+{
+ static char line[128];
+ va_list pvar;
+ va_start(pvar,fmt);
+ va_snprintf(line,128,fmt,pvar);
+ line[127]=0;
+ va_end(pvar);
+ vputs(vscr,line);
+}
+
+void status(int n)
+{
+ vprintf(&statbar,FG_WHITE BG_BLUE CLEAR "### OpenBLT Console mkII ### VC %d",n);
+}
+
+#define ESC 27
+#define BS 8
+#define TAB 9
+#define CR 13
+#define LF 10
+
+char ScanTable [] = {' ', ESC, '1', '2', '3', '4', '5', '6', '7', '8',
+ '9', '0', '-', '=', BS, TAB, 'q', 'w', 'e', 'r',
+ 't', 'y', 'u', 'i', 'o', 'p', '[', ']', LF, ' ',
+ 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ '\'', '`', ' ', '\\', 'z', 'x', 'c', 'v', 'b', 'n',
+ 'm', ',', '.', '/', ' ', ' ', ' ', ' ', ' '};
+char ShiftTable [] = {' ', ESC, '!', '@', '#', '$', '%', '^', '&', '*',
+ '(', ')', '_', '+', ' ', ' ', 'Q', 'W', 'E', 'R',
+ 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', LF, ' ',
+ 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+ '\"', '~', ' ', '|', 'Z', 'X', 'C', 'V', 'B', 'N',
+ 'M', '<', '>', '?', ' ', ' ', ' ', ' ', ' '};
+#define LSHIFT 42
+#define RSHIFT 54
+#define CONTROL 0x1d
+#define ALT 0x38
+
+#define F1 0x3b
+#define F2 0x3c
+#define F3 0x3d
+#define F4 0x3e
+#define F5 0x3f
+#define F6 0x40
+#define F7 0x41
+#define F8 0x42
+#define F9 0x43
+#define F10 0x44
+
+void movecursor (int x, int y);
+void keypress(int key);
+
+void save(struct virtscreen *vscr)
+{
+ sem_acquire(vscr->lock);
+ if(vscr->data != vscr->back) {
+ memcpy(vscr->back,vscr->data,vscr->num_bytes);
+ vscr->data = vscr->back;
+ }
+ sem_release(vscr->lock);
+}
+
+void load(struct virtscreen *vscr)
+{
+ sem_acquire(vscr->lock);
+ if(vscr->data == vscr->back) {
+ vscr->data = screen;
+ memcpy(vscr->data,vscr->back,vscr->num_bytes);
+ }
+ active = vscr;
+ movecursor(vscr->xpos,vscr->ypos);
+ sem_release(vscr->lock);
+ status(vscr - con);
+}
+
+void function(int number)
+{
+ save(active);
+ active = &con[number];
+ load(active);
+}
+
+void keyboard_irq_thread(void)
+{
+ int shift = 0;
+ int control = 0;
+ int alt = 0;
+
+ int key;
+
+ os_handle_irq(1);
+
+ for(;;) {
+ os_sleep_irq();
+#ifdef MULTI
+ while(inb(0x64) & 0x01) {
+#endif
+ key = inb(0x60);
+ if(alt && (key == 1)) {
+ save(active);
+ os_debug();
+ load(active);
+ alt = 0;
+ continue;
+ }
+
+ switch(key){
+ case F1:
+ case F2:
+ case F3:
+ case F4:
+ case F5:
+ case F6:
+ case F7:
+ case F8:
+ case F9:
+ case F10:
+ function(key - F1);
+ break;
+
+ case ALT:
+ alt = 1;
+ break;
+ case ALT | 0x80:
+ alt = 0;
+ break;
+ case CONTROL:
+ control = 1;
+ break;
+ case CONTROL | 0x80:
+ control = 0;
+ break;
+ case LSHIFT:
+ case RSHIFT:
+ shift = 1;
+ break;
+ case LSHIFT | 0x80:
+ case RSHIFT | 0x80:
+ shift = 0;
+ break;
+ default:
+ if(key & 0x80){
+ /* break */
+ } else {
+ if(key < 59){
+ if(control){
+ key = ScanTable[key];
+ if(key >= 'a' && key <= 'z'){
+ keypress(key - 'a' + 1);
+ }
+ } else {
+ key = shift ? ShiftTable[key] : ScanTable[key];
+ keypress(key);
+ }
+ }
+ }
+ }
+#ifdef MULTI
+ }
+#endif
+ }
+
+}
+
+void console_thread(void)
+{
+ int l, src;
+ uint32 code;
+ char data[257];
+
+#ifdef CONSOLE_DEBUG
+ vprintf(active, "console: " FG_GREEN "listener ready" FG_WHITE " (port %d)\n",console_port);
+#endif
+
+ while((l = port_recv(console_port, &src, data, 256, &code)) >= 0){
+ if(code == 0) {
+ remote_port = src;
+ } else {
+ data[l] = 0;
+ vputs(active, data);
+ }
+ }
+ vprintf(active, "console: output listener has left the building (%d)\n",l);
+ os_terminate(0);
+}
+
+int console_main(void)
+{
+ int err,i;
+ area_create(0x2000, 0, &screen, AREA_PHYSMAP);
+
+ console_port = port_create(0,"console_listen_port");
+ send_port = port_create(0,"console_send_port");
+ port_option(send_port, PORT_OPT_NOWAIT, 1);
+
+ err = namer_register(console_port,"console");
+
+ init_virtscreen(&statbar, 1, 80);
+ statbar.back = statbar.data;
+ statbar.data = (unsigned short *) (((uint32) screen) + 80*24*2);
+ statbar.lock = sem_create(1,"statbar_lock");
+
+ for(i=0;i<10;i++){
+ init_virtscreen(&con[i], 24, 80);
+ con[i].back = con[i].data;
+ con[i].lock = sem_create(1,"vscr_lock");
+ vputs(&con[i],CLEAR);
+ }
+ load(&con[0]);
+
+ status(0);
+ if(err) vprintf(active,"console: the namer hates us\n");
+ else
+#ifdef CONSOLE_DEBUG
+ vprintf(active,"console: " FG_GREEN "online." FG_WHITE "\n");
+#else
+ ;
+#endif
+
+ thr_create(keyboard_irq_thread, NULL, "console:kbd");
+ ready = 1;
+ console_thread();
+
+ return 0;
+}
+
+int main(void)
+{
+ thr_create(console_main, NULL, "console:main");
+ while(!ready) ;
+ return 0;
+}
+
diff --git a/srv/console2/vt100.c b/srv/console2/vt100.c
@@ -0,0 +1,464 @@
+/* $Id: //depot/blt/srv/console2/vt100.c#1 $ */
+/* VT100 Engine Copyright 1997 Daniel Marks <dmarks@uiuc.edu> */
+
+#include "vt100.h"
+#include <stdlib.h>
+
+#define STRICT_VT100
+
+/* struct virtscreen newscr; */
+
+void std_interpret_char(struct virtscreen *cur, unsigned char ch);
+void std_interpret_ansi(struct virtscreen *cur, unsigned char ch);
+void special_reading_ansi(struct virtscreen *cur, unsigned char ch);
+void special_ansi_charset_0(struct virtscreen *cur, unsigned char ch);
+void special_ansi_charset_1(struct virtscreen *cur, unsigned char ch);
+
+void clear_region(struct virtscreen *cur, int y1, int x1, int y2, int x2, int atrb);
+
+int init_virtscreen(struct virtscreen *cur, int rows, int columns)
+{
+
+ cur->num_bytes = ((sizeof(unsigned short) * rows * columns));
+
+ if (!(cur->data=malloc(cur->num_bytes)))
+ return (-1);
+
+ cur->data_off_scr = cur->data;
+
+ cur->bottom_scroll = cur->rows = rows;
+ cur->columns = columns;
+ cur->cur_ansi_number = cur->top_scroll = 0;
+ cur->ansi_elements = cur->ansi_reading_number = 0;
+ cur->next_char_send = std_interpret_char;
+ cur->old_attrib = cur->attrib = 0x07;
+ cur->next_char_send = std_interpret_char;
+ clear_region(cur,0,0,rows-1,columns-1,cur->attrib);
+ cur->old_xpos = cur->old_ypos = 0;
+
+ return (0);
+}
+
+void clear_region(struct virtscreen *cur, int y1, int x1, int y2, int x2, int atrb)
+{
+ ushort *ch = loc_in_virtscreen(cur,y1,x1);
+ ushort *tr = loc_in_virtscreen(cur,y2,x2);
+ int dt = 0x20 | (atrb << 8);
+
+ while (ch<=tr)
+ *ch++ = dt;
+}
+
+void clear_virtscreen(struct virtscreen *cur, int mode)
+{
+ switch (mode)
+ {
+ case 0: clear_region(cur,cur->ypos,cur->xpos,
+ cur->rows-1,cur->columns-1,cur->attrib);
+ break;
+ case 1: clear_region(cur,0,0,cur->ypos,cur->xpos,cur->attrib);
+ break;
+ default: clear_region(cur,0,0,cur->rows-1,cur->columns-1,cur->attrib);
+ cur->xpos = cur->ypos = 0;
+ break;
+ }
+}
+
+void clear_to_eol(struct virtscreen *cur, int mode)
+{
+ switch(mode)
+ {
+ case 0:
+ clear_region(cur,cur->ypos,cur->xpos,cur->ypos,
+ cur->columns-1,cur->attrib);
+ break;
+ case 1:
+ clear_region(cur,cur->ypos,0,cur->ypos,cur->xpos,
+ cur->attrib);
+ break;
+ default:
+ clear_region(cur,cur->ypos,0,cur->ypos,cur->columns-1,
+ cur->attrib);
+ }
+}
+
+
+void move_cursor(struct virtscreen *cur);
+/*
+{
+}
+*/
+
+void position_console(struct virtscreen *cur, int ypos, int xpos, int rel)
+{
+ if (rel)
+ {
+ cur->xpos += xpos;
+ cur->ypos += ypos;
+ } else
+ {
+ cur->xpos = xpos;
+ cur->ypos = ypos;
+ }
+ if (cur->xpos < 0) cur->xpos = 0;
+ if (cur->xpos >= cur->columns) cur->xpos = cur->columns-1;
+ if (cur->ypos < 0) cur->ypos = 0;
+ if (cur->ypos >= cur->rows) cur->ypos = cur->rows-1;
+ move_cursor(cur);
+}
+
+void delete_chars_in_line(struct virtscreen *cur, int char_move)
+{
+ ushort *next_move;
+ ushort *end_move;
+ ushort *start_move;
+ ushort clr_with;
+
+ clr_with = (cur->attrib << 8) | 0x20;
+ start_move = loc_in_virtscreen(cur,cur->ypos,cur->xpos);
+ end_move = loc_in_virtscreen(cur,cur->ypos,cur->columns);
+ if ((cur->xpos + char_move) < cur->columns)
+ {
+ next_move = loc_in_virtscreen(cur,cur->ypos,cur->xpos+char_move);
+ while (next_move<end_move)
+ *start_move++ = *next_move++;
+ }
+ while (start_move<end_move) *start_move++ = clr_with;
+}
+
+void scroll_virt_up_at_cursor(struct virtscreen *cur, int dir)
+{
+ ushort clr_with;
+ ushort *beginScr;
+ ushort *endofScr;
+ ushort *lastLine;
+ ushort *nextLine;
+ unsigned int real_scroll_length;
+
+ if ((cur->ypos >= cur->top_scroll) &&
+ (cur->ypos < cur->bottom_scroll))
+ {
+ clr_with = (cur->attrib << 8) | 0x20;
+ beginScr = loc_in_virtscreen(cur,cur->ypos,0);
+ endofScr = loc_in_virtscreen(cur,cur->bottom_scroll,0);
+ lastLine = endofScr - cur->columns;
+ nextLine = beginScr + cur->columns;
+ real_scroll_length = ((unsigned int) lastLine) -
+ ((unsigned int) beginScr);
+
+ if (dir)
+ {
+ memmove(beginScr,nextLine,real_scroll_length);
+ while (lastLine < endofScr)
+ *lastLine++ = clr_with;
+ } else
+ {
+ memmove(nextLine,beginScr,real_scroll_length);
+ while (beginScr < nextLine)
+ *beginScr++ = clr_with;
+ }
+ }
+}
+
+void scroll_virtscreen(struct virtscreen *cur)
+ {
+ int clr_with = (cur->attrib << 8) | 0x20;
+ ushort *beginScr = loc_in_virtscreen(cur,cur->top_scroll,0);
+ ushort *endofScr = loc_in_virtscreen(cur,cur->bottom_scroll,0);
+ ushort *lastLine = endofScr - cur->columns;
+ ushort *nextLine = beginScr + cur->columns;
+ unsigned int real_scroll_length = ((unsigned int) lastLine) -
+ ((unsigned int) beginScr);
+
+ memmove(beginScr,nextLine,real_scroll_length);
+ while (lastLine < endofScr)
+ *lastLine++ = clr_with;
+ };
+
+void set_scroll_region(struct virtscreen *cur, int low, int high)
+{
+ low--;
+ high = (high >= cur->rows) ? cur->rows : high;
+ low = (low < 0) ? 0 : low;
+
+ cur->top_scroll = low;
+ cur->bottom_scroll = high;
+}
+
+void change_attribute(struct virtscreen *cur, int attrib)
+{
+ cur->attrib = attrib;
+}
+
+void change_character(struct virtscreen *cur, int ch)
+{
+ *(loc_in_virtscreen(cur,cur->ypos,cur->xpos)) =
+ ch | (cur->attrib << 8);
+}
+
+void special_ansi_charset_0(struct virtscreen *cur, unsigned char ch)
+{
+ cur->next_char_send = std_interpret_char;
+}
+
+void special_ansi_charset_1(struct virtscreen *cur, unsigned char ch)
+{
+ cur->next_char_send = std_interpret_char;
+}
+
+void std_interpret_ansi(struct virtscreen *cur, unsigned char ch)
+{
+ switch (ch)
+ {
+ case '(': cur->next_char_send = special_ansi_charset_0;
+ return;
+ case ')': cur->next_char_send = special_ansi_charset_1;
+ return;
+ case '[': cur->cur_ansi_number = 0;
+ cur->ansi_elements = 0;
+ cur->ansi_reading_number = 0;
+ cur->next_char_send = special_reading_ansi;
+ return;
+ case '7': cur->old_attrib = cur->attrib;
+ cur->old_xpos = cur->xpos;
+ cur->old_ypos = cur->ypos;
+ break;
+ case '8': change_attribute(cur,cur->old_attrib);
+ position_console(cur,cur->ypos,cur->xpos,0);
+ break;
+ case 'E': cur->xpos = 0;
+ case 'D': cur->ypos++;
+ if (cur->ypos >= cur->bottom_scroll)
+ {
+ scroll_virtscreen(cur);
+ cur->ypos--;
+ }
+ move_cursor(cur);
+ break;
+ case 'M': cur->ypos--;
+ if (cur->ypos < cur->top_scroll)
+ {
+ cur->ypos++;
+ scroll_virt_up_at_cursor(cur,0);
+ }
+ move_cursor(cur);
+ break; /* recalculate screen pos */
+ }
+ if (ch != 27)
+ cur->next_char_send = std_interpret_char;
+}
+
+void std_interpret_char(struct virtscreen *cur, unsigned char ch)
+{
+ switch (ch)
+ {
+ case 27: cur->next_char_send = std_interpret_ansi;
+ return;
+ case 12: clear_virtscreen(cur,2);
+ break;
+ case 13: cur->xpos = 0; /* return = back to begin */
+ break;
+ case 10: cur->ypos++;
+ if (cur->ypos >= cur->bottom_scroll)
+ /* if we're at bottom */
+ {
+ if (cur->ypos == cur->bottom_scroll)
+ scroll_virtscreen(cur); /* and scroll it! */
+ cur->ypos--; /* go back up a line */
+ }
+ cur->xpos=0;
+ break;
+ case 9: position_console(cur,cur->ypos,cur->xpos+(8-(cur->xpos % 8)),0);
+ break;
+ case 8: cur->xpos--; /* backspace on screen */
+ if (cur->xpos<0)
+ {
+ cur->xpos = cur->columns - 1;
+ cur->ypos;
+ if (cur->ypos<0)
+ cur->ypos=0;
+ }
+ break;
+ default: if (!ch)
+ break;
+ change_character(cur,ch);
+ cur->xpos++;
+ if (cur->xpos >= cur->columns)
+ {
+#ifdef STRICT_VT100
+ cur->xpos = cur->columns-1;
+#else
+ cur->xpos = 0;
+ cur->ypos++;
+ if (cur->ypos == cur->bottom_scroll)
+ {
+ cur->ypos--;
+ scroll_virtscreen(cur);
+ }
+#endif
+ }
+ break;
+ }
+ move_cursor(cur);
+}
+
+void special_reading_ansi(struct virtscreen *cur, unsigned char ch)
+{
+ if ((ch>='0') && (ch<='9'))
+ {
+ cur->cur_ansi_number = (cur->cur_ansi_number * 10) + (ch - '0');
+ cur->ansi_reading_number = 1;
+ return;
+ }
+
+ if ((cur->ansi_reading_number) || (ch == ';'))
+ {
+ if (cur->ansi_elements<MAX_ANSI_ELEMENTS)
+ cur->ansi_element[cur->ansi_elements++] = cur->cur_ansi_number;
+ cur->ansi_reading_number = 0;
+ }
+ cur->cur_ansi_number = 0;
+ switch (ch)
+ {
+ case '?':
+ case ';': return;
+ case 'D': position_console(cur,0,(cur->ansi_elements) ?
+ -cur->ansi_element[0] : -1,1);
+ break;
+ case 'a':
+ case 'C': position_console(cur,0,(cur->ansi_elements) ?
+ cur->ansi_element[0] : 1,1);
+ break;
+ case 'A': position_console(cur,(cur->ansi_elements) ?
+ -cur->ansi_element[0] : -1,0,1);
+ break;
+ case 'e':
+ case 'B': position_console(cur,(cur->ansi_elements) ?
+ cur->ansi_element[0] : 1,0,1);
+ break;
+ case '`':
+ case 'G':
+ {
+ int temp = cur->ansi_elements ? cur->ansi_element[0] : 1;
+ if (temp)
+ temp--;
+ position_console(cur,cur->ypos,temp,0);
+ }
+ break;
+ case 'E': position_console(cur,cur->ypos +
+ ((cur->ansi_elements) ? cur->ansi_element[0] : 1),
+ 0,0);
+ break;
+ case 'F': position_console(cur,cur->ypos -
+ ((cur->ansi_elements) ? cur->ansi_element[0] : 1),
+ 0,0);
+ break;
+ case 'd':
+ {
+ int temp = cur->ansi_elements ? cur->ansi_element[0] : 1;
+ if (temp)
+ temp--;
+ position_console(cur,temp,cur->xpos,0);
+ }
+ break;
+ case 'f':
+ case 'H':
+ {
+ int row = (cur->ansi_elements > 0) ? cur->ansi_element[0] : 1;
+ int col = (cur->ansi_elements > 1) ? cur->ansi_element[1] : 1;
+ if (row)
+ row--;
+ if (col)
+ col--;
+ position_console(cur,row,col,0);
+ }
+ break;
+ case 'J': clear_virtscreen(cur,(cur->ansi_elements) ?
+ cur->ansi_element[0]: 0);
+ break;
+ case 'L': {
+ int lines = (cur->ansi_elements) ?
+ cur->ansi_element[0] : 1;
+ while (lines>0)
+ {
+ scroll_virt_up_at_cursor(cur,0);
+ lines--;
+ }
+ }
+ break;
+ case 'M': {
+ int lines = (cur->ansi_elements) ?
+ cur->ansi_element[0] : 1;
+ while (lines>0)
+ {
+ scroll_virt_up_at_cursor(cur,1);
+ lines--;
+ }
+ }
+ break;
+ case 'P': delete_chars_in_line(cur,(cur->ansi_elements) ?
+ cur->ansi_element[0] : 1);
+ break;
+ case 'K': clear_to_eol(cur,cur->ansi_elements ?
+ cur->ansi_element[0] : 0);
+ break;
+ case 's': cur->old_xpos = cur->xpos;
+ cur->old_ypos = cur->ypos;
+ break;
+ case 'u': position_console(cur,cur->old_ypos,cur->old_xpos,0);
+ break;
+ case 'r': {
+ int low = (cur->ansi_elements > 0) ?
+ cur->ansi_element[0] : 1;
+ int high = (cur->ansi_elements > 1) ?
+ cur->ansi_element[1] : cur->rows;
+ if (low<=high)
+ set_scroll_region(cur,low,high);
+ }
+ break;
+ case 'm':
+ {
+ int count = 0;
+ int cthing;
+ if (!cur->ansi_elements)
+ change_attribute(cur,0x07);
+ while (count < cur->ansi_elements)
+ {
+ cthing = cur->ansi_element[count];
+ switch (cthing)
+ {
+ case 0:
+ case 27: change_attribute(cur,0x07);
+ break;
+ case 1: change_attribute(cur,cur->attrib | 0x08);
+ break;
+ case 5: change_attribute(cur,cur->attrib | 0x80);
+ break;
+ case 7: change_attribute(cur,0x70);
+ break;
+ case 21:
+ case 22: change_attribute(cur,cur->attrib & 0xF7);
+ break;
+ case 25: change_attribute(cur,cur->attrib & 0x7F);
+ break;
+ default:
+ if ((cthing>=30) && (cthing<=37))
+ {
+ change_attribute(cur,(cur->attrib & 0xF8) | (cthing-30));
+ }
+ if ((cthing>=40) && (cthing<=47))
+ {
+ change_attribute(cur,(cur->attrib & 0x8F) |
+ ((cthing-40) << 4));
+ }
+ break;
+ }
+ count++;
+ }
+ }
+ break;
+
+ }
+ cur->next_char_send = std_interpret_char;
+}
+
diff --git a/srv/console2/vt100.h b/srv/console2/vt100.h
@@ -0,0 +1,45 @@
+/* $Id: //depot/blt/srv/console2/vt100.h#4 $ */
+/* VT100 Engine Copyright 1997 Daniel Marks <dmarks@uiuc.edu> */
+
+#ifndef _VT_100_H
+#define _VT_100_H
+
+#include <blt/qsem.h>
+
+typedef unsigned short ushort;
+
+#define loc_in_virtscreen(cur,y,x) (((cur)->data)+(((y)*((cur)->columns))+(x)))
+#define MAX_ANSI_ELEMENTS 16
+#define char_to_virtscreen(cur,ch) (((cur)->next_char_send)((cur),(ch)))
+
+struct virtscreen
+{
+ int rows;
+ int columns;
+ int num_bytes;
+ ushort *data;
+ ushort *back;
+ ushort *data_off_scr;
+
+ int xpos;
+ int ypos;
+ int top_scroll;
+ int bottom_scroll;
+ int attrib;
+ int old_attrib;
+ int old_xpos;
+ int old_ypos;
+
+ int cur_ansi_number;
+ int ansi_elements;
+ int ansi_reading_number;
+ int ansi_element[MAX_ANSI_ELEMENTS];
+
+ void (*next_char_send)(struct virtscreen *cur, unsigned char ch);
+
+ int lock;
+};
+
+
+int init_virtscreen(struct virtscreen *cur, int rows, int columns);
+#endif /* _VT_100_h */
diff --git a/srv/fb/Makefile b/srv/fb/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := pci.c fb.c mga1x64.c
+CRT0 := $(BLTHOME)lib/crt0.o
+BINARY := fb.bin
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
diff --git a/srv/fb/fb.c b/srv/fb/fb.c
@@ -0,0 +1,46 @@
+/* $Id$
+**
+** Copyright 1999 Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <blt/syscall.h>
+#include "fb.h"
+
+#define SERIAL_DEBUG 0
+
+void va_snprintf(char *b, int l, char *fmt, va_list pvar);
+
+
+void dprintf(const char *fmt, ...)
+{
+ char buf[256];
+ va_list ap;
+ va_start(ap,fmt);
+ va_snprintf(buf,256,fmt,ap);
+ va_end(pvar);
+#if SERIAL_DEBUG
+ os_console(buf);
+#else
+ printf(buf);
+ printf("\n");
+#endif
+}
+
+extern fb_info fb_mga1x64;
+
+int main (int argc, char **argv)
+{
+ void *cookie;
+ fb_info *fb = &fb_mga1x64;
+
+ if(fb->find(&cookie) == 0){
+ printf("Frame Buffer \"%s\" found.\n",fb->name);
+ fb->init(cookie);
+ }
+
+ return 0;
+}
+
diff --git a/srv/fb/fb.h b/srv/fb/fb.h
@@ -0,0 +1,21 @@
+/* $Id$
+**
+** Copyright 1999 Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _FB_H
+#define _FB_H
+
+#include <blt/types.h>
+
+void dprintf(const char *fmt, ...);
+
+typedef struct fb_info
+{
+ const char *name;
+ int32 (*find)(void **cookie);
+ int32 (*init)(void *cookie);
+} fb_info;
+
+#endif
diff --git a/srv/fb/mga1x64.c b/srv/fb/mga1x64.c
@@ -0,0 +1,67 @@
+/* $Id$
+**
+** Copyright 1999 Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include "pci.h"
+#include "fb.h"
+
+#include <stdlib.h>
+#include <blt/syscall.h>
+
+#include "mga1x64.h"
+
+
+static int32 mga_find(void **cookie)
+{
+ pci_cfg cfg;
+ mga1x64 *mga;
+ int i;
+
+ if(pci_find(&cfg,VENDOR,DEVICE)) return -1;
+
+ dprintf("mga_find(): card @ %d/%d/%d",cfg.bus,cfg.dev,cfg.func);
+
+ if(!(mga = (mga1x64*) malloc(sizeof(mga1x64)))) return -1;
+ *cookie = mga;
+
+ mga->regs = (uint32 *) (cfg.base[REGS] & 0xfffffff0);
+ if(area_create(0x4000, 0, (void**) &(mga->regs), AREA_PHYSMAP) < 0){
+ dprintf("mga_find(): CANNOT MAP REGISTERS!?");
+ free(mga);
+ return -1;
+ }
+
+ mga->fb = (uchar *) (cfg.base[FB] & 0xfffffff0);
+ mga->fbsize = 0x100000;
+ if(area_create(mga->fbsize, 0, (void**) &(mga->fb), AREA_PHYSMAP) < 0){
+ dprintf("mga_find(): CANNOT MAP FRAMEBUFFER!?");
+ free(mga);
+ return -1;
+ }
+
+ dprintf("mga_find(): registers @ %xv, %xp",
+ mga->regs,cfg.base[REGS]&0xfffffff0);
+ dprintf("mga_find(): framebuffer @ %xv, %xp (sz %x)",
+ mga->fb,cfg.base[FB]&0xfffffff0,mga->fbsize);
+
+ dprintf("mga_find(): FIFOSTATUS = %x",RD(FIFOSTATUS));
+
+ return 0;
+}
+
+static int32 mga_init(void *cookie)
+{
+ mga1x64 *mga = (mga1x64*) cookie;
+
+ dprintf("mga_init()");
+}
+
+fb_info fb_mga1x64 =
+{
+ "MGA-1x64",
+ &mga_find,
+ &mga_init
+};
+
diff --git a/srv/fb/mga1x64.h b/srv/fb/mga1x64.h
@@ -0,0 +1,30 @@
+/* $Id$
+**
+** Copyright 1999 Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _MGA_1X64_H
+#define _MGA_1X64_H
+
+#define VENDOR 0x102b
+#define DEVICE 0x051a
+
+typedef struct mga1x64
+{
+ volatile uint32 *regs;
+ volatile uchar *fb;
+ int32 fbsize;
+} mga1x64;
+
+/* base registers to use */
+#define REGS 1
+#define FB 2
+
+/* registers */
+#define FIFOSTATUS 0x1e10
+
+#define RD(r) (mga->regs[(r)/4])
+#define WR(r,v) (mga->regs[(r)/4] = v)
+
+#endif
diff --git a/srv/fb/pci.c b/srv/fb/pci.c
@@ -0,0 +1,157 @@
+/* $Id$
+**
+** Copyright 1999 Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <i386/io.h>
+
+#include "pci.h"
+
+typedef struct
+{
+ uchar reg:8;
+ uchar func:3;
+ uchar dev:5;
+ uchar bus:8;
+ uchar rsvd:7;
+ uchar enable:1;
+} confadd;
+
+uint32 pci_read(int bus, int dev, int func, int reg, int bytes)
+{
+ uint32 base;
+
+ union {
+ confadd c;
+ uint32 n;
+ } u;
+
+ u.c.enable = 1;
+ u.c.rsvd = 0;
+ u.c.bus = bus;
+ u.c.dev = dev;
+ u.c.func = func;
+ u.c.reg = reg & 0xFC;
+
+ outl(u.n,0xCF8);
+
+ base = 0xCFC + (reg & 0x03);
+
+ switch(bytes){
+ case 1: return inb(base);
+ case 2: return inw(base);
+ case 4: return inl(base);
+ default: return 0;
+ }
+}
+
+void pci_write(int bus, int dev, int func, int reg, uint32 v, int bytes)
+{
+ uint32 base;
+
+ union {
+ confadd c;
+ uint32 n;
+ } u;
+
+ u.c.enable = 1;
+ u.c.rsvd = 0;
+ u.c.bus = bus;
+ u.c.dev = dev;
+ u.c.func = func;
+ u.c.reg = reg & 0xFC;
+
+ base = 0xCFC + (reg & 0x03);
+ outl(u.n,0xCF8);
+ switch(bytes){
+ case 1: outb(v,base); break;
+ case 2: outw(v,base); break;
+ case 4: outl(v,base); break;
+ }
+
+}
+
+int pci_probe(int bus, int dev, int func, pci_cfg *cfg)
+{
+ uint32 *word = (uint32 *) cfg;
+ uint32 v;
+ int i;
+ for(i=0;i<4;i++){
+ word[i] = pci_read(bus,dev,func,4*i,4);
+ }
+ if(cfg->vendor_id == 0xffff) return 1;
+
+ cfg->bus = bus;
+ cfg->dev = dev;
+ cfg->func = func;
+#if 0
+ printf("Device Info: /bus/pci/%d/%d/%d\n",bus,dev,func);
+ printf(" * Vendor: %S Device: %S Class/SubClass/Interface %X/%X/%X\n",
+ cfg->vendor_id,cfg->device_id,cfg->base_class,cfg->sub_class,cfg->interface);
+ printf(" * Status: %S Command: %S BIST/Type/Lat/CLS: %X/%X/%X/%X\n",
+ cfg->status, cfg->command, cfg->bist, cfg->header_type,
+ cfg->latency_timer, cfg->cache_line_size);
+#endif
+
+ switch(cfg->header_type & 0x7F){
+ case 0: /* normal device */
+ for(i=0;i<6;i++){
+ v = pci_read(bus,dev,func,i*4 + 0x10, 4);
+ if(v) {
+ int v2;
+ pci_write(bus,dev,func,i*4 + 0x10, 0xffffffff, 4);
+ v2 = pci_read(bus,dev,func,i*4+0x10, 4) & 0xfffffff0;
+ pci_write(bus,dev,func,i*4 + 0x10, v, 4);
+ v2 = 1 + ~v2;
+ if(v & 1) {
+// printf(" * Base Register %d IO: %x (%x)\n",i,v&0xfff0,v2&0xffff);
+ cfg->base[i] = v & 0xffff;
+ cfg->size[i] = v2 & 0xffff;
+ } else {
+// printf(" * Base Register %d MM: %x (%x)\n",i,v&0xfffffff0,v2);
+ cfg->base[i] = v;
+ cfg->size[i] = v2;
+ }
+ } else {
+ cfg->base[i] = 0;
+ cfg->size[i] = 0;
+ }
+
+ }
+ v = pci_read(bus,dev,func,0x3c,1);
+// if((v != 0xff) && (v != 0)) printf(" * Interrupt Line: %X\n",v);
+ break;
+ case 1:
+// printf(" * PCI <-> PCI Bridge\n");
+ break;
+ default:
+// printf(" * Unknown Header Type\n");
+ }
+ return 0;
+}
+
+int pci_find(pci_cfg *cfg, uint16 vendor_id, uint16 device_id)
+{
+ int bus,dev,func;
+
+ for(bus=0;bus<255;bus++){
+ for(dev=0;dev<32;dev++) {
+ if(pci_probe(bus,dev,0,cfg)) continue;
+ if((cfg->vendor_id == vendor_id) &&
+ (cfg->device_id == device_id)) return 0;
+ if(cfg->header_type & 0x80){
+ for(func=1;func<8;func++){
+ if(!pci_probe(bus,dev,func,cfg) &&
+ (cfg->vendor_id == vendor_id) &&
+ (cfg->device_id == device_id)) return 0;
+ }
+ }
+ }
+ }
+}
+
diff --git a/srv/fb/pci.h b/srv/fb/pci.h
@@ -0,0 +1,49 @@
+/* $Id$
+**
+** Copyright 1999 Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _PCI_H
+#define _PCI_H
+
+#include <blt/types.h>
+
+typedef struct
+{
+ /* normal header stuff */
+ uint16 vendor_id;
+ uint16 device_id;
+
+ uint16 command;
+ uint16 status;
+
+ uint8 revision_id;
+ uint8 interface;
+ uint8 sub_class;
+ uint8 base_class;
+
+ uint8 cache_line_size;
+ uint8 latency_timer;
+ uint8 header_type;
+ uint8 bist;
+
+ /* device info */
+ uint8 bus;
+ uint8 dev;
+ uint8 func;
+ uint8 _pad;
+
+ /* base registers */
+ uint32 base[6];
+ uint32 size[6];
+
+} pci_cfg;
+
+int pci_find(pci_cfg *cfg, uint16 vendor_id, uint16 device_id);
+
+uint32 pci_read(int bus, int dev, int func, int reg, int bytes);
+void pci_write(int bus, int dev, int func, int reg, uint32 v, int bytes);
+
+
+#endif
diff --git a/srv/fish/Makefile b/srv/fish/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := fish.c vga.c
+BINARY := fish.bin
+LIBS := -lblt -lc
+
+include $(BLTHOME)make.actions
+
diff --git a/srv/fish/dfp.h b/srv/fish/dfp.h
@@ -0,0 +1,127 @@
+/* $Id: //depot/blt/srv/fish/dfp.h#3 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*
+** Distributed Fish Protocol
+** Version 1.0
+**
+** Special Interest Group for Operating Systems
+** Association for Computing Machinery
+** University of Illinios at Urbana-Champaign
+*/
+
+#ifndef _DFP_H
+#define _DFP_H
+
+#ifdef _WIN32
+#include <sys/types.h>
+#include <winsock.h>
+#endif
+
+#ifdef NEED_TYPES
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+#endif
+typedef char sint8;
+
+#define DFP_VERSION 0x0201
+
+#define DEFAULT_DFP_PORT 5049
+
+#define DFP_MIN_SUBTANK_X 0
+#define DFP_MAX_SUBTANK_X 3
+#define DFP_MIN_SUBTANK_Y 0
+#define DFP_MAX_SUBTANK_Y 3
+
+#define DFP_PKT_PING 0
+#define DFP_PKT_PONG 1
+#define DFP_PKT_SEND_FISH 2
+#define DFP_PKT_ACK_FISH 3
+#define DFP_PKT_NACK_FISH 4
+#define DFP_PKT_SYNC_FISH 5
+
+/* pack everything along byte boundaries */
+#pragma pack( 1 )
+
+typedef struct
+{
+ uint16 version;
+ uint8 src_tank_x;
+ uint8 src_tank_y;
+ uint8 dst_tank_x;
+ uint8 dst_tank_y;
+ uint8 type; /* one of DFP_PKT_* */
+ uint8 pad; /* should be 0 */
+ uint16 size; /* size of entire packet */
+} dfp_base;
+
+typedef struct
+{
+ uint8 creator_tank_x;
+ uint8 creator_tank_y;
+ uint8 timestamp[4];
+} dfp_uid;
+
+typedef struct
+{
+ uint8 x;
+ uint8 y;
+ sint8 dx;
+ sint8 dy;
+ uint16 ttl;
+ uint8 name[16];
+} dfp_fish;
+
+
+#define DFP_SIZE_LOCATE 10
+#define DFP_SIZE_CONFIRM 16
+#define DFP_SIZE_TRANSFER 38
+
+
+typedef struct
+{
+ dfp_base base;
+} dfp_pkt_locate;
+
+typedef struct
+{
+ dfp_base base;
+ dfp_uid uid;
+} dfp_pkt_confirm;
+
+typedef struct
+{
+ dfp_base base;
+ dfp_uid uid;
+ dfp_fish fish;
+} dfp_pkt_transfer;
+
+/* restore default packing */
+#pragma pack()
+
+#endif /* __DFP_H */
diff --git a/srv/fish/fish.c b/srv/fish/fish.c
@@ -0,0 +1,1020 @@
+/* Copyright 1998-1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <i386/io.h>
+#include <blt/namer.h>
+#include <blt/syscall.h>
+
+#include "dfp.h"
+#include "vga.h"
+
+static int WITH_NET = 1;
+
+void keythread(void);
+
+int myX = 2;
+int myY = 2;
+
+int st_sent = 0;
+int st_recv = 0;
+int st_rej = 0;
+int st_count = 0;
+int sticky = 0;
+int collision = 0;
+int snooze = 5;
+
+int logsize = 15;
+
+
+int borg = 0;
+int logo = 0;
+int logging = 1;
+int recluse = 0;
+int ticks = 0;
+
+#define LOGGING
+#define TIMEOUT 8
+
+#define MAXKEYS 64
+static char keybuf2[MAXKEYS+4];
+static char *keybuf = keybuf2+2;
+static int keyptr = 0;
+
+int port_fish, port_net, port_console, port_net_xmit;
+
+static char kpbuf[512];
+static char *kp = kpbuf;
+static char *x;
+
+typedef struct _msg
+{
+ struct _msg *next;
+ char buf[65];
+} msg;
+msg *first_msg = NULL, *last_msg = NULL;
+int msgcount = 0;
+
+int sem_fish = 0, sem_msgs = 0;
+
+void lprintf(char *fmt,...)
+{
+#ifdef LOGGING
+ va_list pvar;
+ int n;
+ msg *m = (msg *) malloc(sizeof(msg));
+
+ va_start(pvar,fmt);
+ va_snprintf(m->buf,64,fmt,pvar);
+ va_end(pvar);
+
+ m->buf[60]=0;
+ m->next = NULL;
+ sem_acquire(sem_msgs);
+ msgcount++;
+ if(last_msg){
+ last_msg->next = m;
+ last_msg = m;
+ } else {
+ first_msg = last_msg = m;
+ }
+ sem_release(sem_msgs);
+#endif
+}
+
+#define DEAD 0
+#define LIVE 1
+#define XMIT 2
+typedef struct _fish
+{
+ struct _fish *next, *prev;
+ int x,y;
+ int dx,dy;
+ char name[17];
+ char *bitmap;
+ int state;
+ int xt;
+ dfp_pkt_transfer xfer;
+ int dest;
+} fish;
+
+fish *first = NULL;
+fish *last = NULL;
+
+
+struct
+{
+ int live;
+ int tx, ty;
+} cnxn[4] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} };
+
+#define C_UP 0
+#define C_DN 1
+#define C_LF 2
+#define C_RT 3
+#define NET_CONNECT 1
+#define NET_SEND 2
+#define NET_IP 3
+
+void settank(int tx, int ty, int live)
+{
+ int i;
+ for(i=0;i<4;i++){
+ if(cnxn[i].tx == tx && cnxn[i].ty == ty){
+ cnxn[i].live = live;
+ return;
+ }
+ }
+}
+
+
+typedef struct
+{
+ int cmd;
+ int port;
+} net_cmd;
+
+typedef struct
+{
+ net_cmd cmd;
+ dfp_pkt_transfer dfp;
+} net_fish;
+
+void newfish(int x, int y, int dx, int dy, char *n);
+
+void pingtank(int tx, int ty)
+{
+ if(WITH_NET){
+ net_fish f;
+ msg_hdr_t msg;
+ f.cmd.cmd = NET_SEND;
+ f.cmd.port = 5049;
+ f.dfp.base.src_tank_x = myX;
+ f.dfp.base.src_tank_y = myY;
+ f.dfp.base.dst_tank_x = tx;
+ f.dfp.base.dst_tank_y = ty;
+ f.dfp.base.size = htons(DFP_SIZE_LOCATE);
+ f.dfp.base.type = DFP_PKT_PING;
+ f.dfp.base.pad = 0;
+ f.dfp.base.version = htons(DFP_VERSION);
+ msg.flags = 0;
+ msg.src = port_fish;
+ msg.dst = port_net;
+ msg.size = sizeof(dfp_base)+8;
+ msg.data = &f;
+ old_port_send(&msg);
+ }
+}
+
+void initiate(dfp_pkt_transfer *send, int tx, int ty)
+{
+ if(WITH_NET){
+ net_fish f;
+ msg_hdr_t msg;
+ f.cmd.cmd = NET_SEND;
+ f.cmd.port = 5049;
+ f.dfp.base.src_tank_x = myX;
+ f.dfp.base.src_tank_y = myY;
+ f.dfp.base.dst_tank_x = tx;
+ f.dfp.base.dst_tank_y = ty;
+ f.dfp.base.size = ntohs(DFP_SIZE_TRANSFER);
+ f.dfp.base.type = DFP_PKT_SEND_FISH;
+ f.dfp.base.pad = 0;
+ f.dfp.base.version = htons(DFP_VERSION);
+ memcpy(&(f.dfp.uid), &(send->uid), 6);
+ memcpy(&(f.dfp.fish), &(send->fish), sizeof(dfp_fish));
+ msg.flags = 0;
+ msg.src = port_fish;
+ msg.dst = port_net;
+ msg.size = DFP_SIZE_TRANSFER + 8;
+ msg.data = &f;
+ old_port_send(&msg);
+ }
+
+}
+
+char *types[] = { "PING", "PING", "SEND", "ACK", "NACK", "SYNC" };
+
+void dofish(dfp_pkt_transfer *dfp)
+{
+ int i;
+
+ net_fish f;
+ fish *ff;
+ char n2[17];
+ msg_hdr_t msg;
+ dfp->base.version = ntohs(dfp->base.version);
+ dfp->base.size = ntohs(dfp->base.size);
+
+ if(!(dfp->base.dst_tank_x == myX && dfp->base.dst_tank_y == myY)){
+ return;
+ }
+
+
+ if(dfp->base.type == DFP_PKT_SYNC_FISH) lprintf("fish: s(%d,%d) d(%d,%d) s=%d %s",
+ dfp->base.src_tank_x, dfp->base.src_tank_y,
+ dfp->base.dst_tank_x, dfp->base.dst_tank_y,
+ dfp->base.size,
+ dfp->base.type < 6 ? types[dfp->base.type] : "????"
+ );
+
+ switch(dfp->base.type){
+ case DFP_PKT_PING :
+ f.cmd.cmd = NET_SEND;
+ f.cmd.port = 5049;
+ f.dfp.base.src_tank_x = myX;
+ f.dfp.base.src_tank_y = myY;
+ f.dfp.base.dst_tank_x = dfp->base.src_tank_x;
+ f.dfp.base.dst_tank_y = dfp->base.src_tank_y;
+ f.dfp.base.size = htons(DFP_SIZE_LOCATE);
+ f.dfp.base.type = DFP_PKT_PONG;
+ f.dfp.base.pad = 0;
+ f.dfp.base.version = htons(DFP_VERSION);
+ settank(dfp->base.src_tank_x,dfp->base.src_tank_y,1);
+ msg.flags = 0;
+ msg.src = port_fish;
+ msg.dst = port_net;
+ msg.size = sizeof(dfp_base)+8;
+ msg.data = &f;
+ old_port_send(&msg);
+
+
+ break;
+
+ case DFP_PKT_PONG :
+ lprintf("Pong from %d,%d",dfp->base.src_tank_x,dfp->base.src_tank_y);
+ settank(dfp->base.src_tank_x,dfp->base.src_tank_y,1);
+/* for(i=0;i<4;i++){
+ if((cnxn[i].tx == dfp->base.src_tank_x) &&
+ (cnxn[i].ty == dfp->base.src_tank_y)) {
+ cnxn[i].live = 1;
+ break;
+ }
+ }*/
+ break;
+
+ case DFP_PKT_SEND_FISH :
+ dfp->fish.ttl = ntohs(dfp->fish.ttl);
+ strncpy(n2,dfp->fish.name,16);
+ n2[16]=0;
+ if(recluse){
+ lprintf("Ignoring \"%s\" from (%d,%d)",n2,
+ dfp->base.src_tank_x, dfp->base.src_tank_y);
+ break;
+ }
+ /* lprintf(" : UID %X%X%X%X%X%X @(%d,%d) d(%d,%d) ttl=%d, name=\"%s\"",
+ dfp->uid.creator_tank_x, dfp->uid.creator_tank_y,
+ dfp->uid.timestamp[0], dfp->uid.timestamp[1],
+ dfp->uid.timestamp[2], dfp->uid.timestamp[3],
+ dfp->fish.x, dfp->fish.y, dfp->fish.dx, dfp->fish.dy,
+ dfp->fish.ttl, n2);
+ */
+ f.cmd.cmd = NET_SEND;
+ f.cmd.port = 5049;
+ f.dfp.base.src_tank_x = myX;
+ f.dfp.base.src_tank_y = myY;
+ f.dfp.base.dst_tank_x = dfp->base.src_tank_x;
+ f.dfp.base.dst_tank_y = dfp->base.src_tank_y;
+ f.dfp.base.size = ntohs(DFP_SIZE_CONFIRM);
+ f.dfp.base.type = DFP_PKT_ACK_FISH;
+ f.dfp.base.pad = 0;
+ f.dfp.base.version = htons(DFP_VERSION);
+ memcpy(&(f.dfp.uid), &(dfp->uid), 6);
+
+ msg.flags = 0;
+ msg.src = port_fish;
+ msg.dst = port_net;
+ msg.size = DFP_SIZE_CONFIRM + 8;
+ msg.data = &f;
+ old_port_send(&msg);
+ break;
+
+ case DFP_PKT_ACK_FISH :
+ /* lprintf(" : UID %X%X%X%X%X%X",
+ dfp->uid.creator_tank_x, dfp->uid.creator_tank_y,
+ dfp->uid.timestamp[0], dfp->uid.timestamp[1],
+ dfp->uid.timestamp[2], dfp->uid.timestamp[3]);
+ */
+ sem_acquire(sem_fish);
+ for(ff = first; ff; ff=ff->next){
+ if((ff->state==XMIT) &&
+ (!memcmp(&(ff->xfer.uid),&(dfp->uid),6))){
+ ff->state = DEAD;
+ st_count--;
+ sem_release(sem_fish);
+ lprintf("Goodbye fish \"%s\" (%d,%d)",ff->name,
+ dfp->base.src_tank_x,dfp->base.src_tank_y);
+
+ f.cmd.cmd = NET_SEND;
+ f.cmd.port = 5049;
+ f.dfp.base.src_tank_x = myX;
+ f.dfp.base.src_tank_y = myY;
+ f.dfp.base.dst_tank_x = dfp->base.src_tank_x;
+ f.dfp.base.dst_tank_y = dfp->base.src_tank_y;
+ f.dfp.base.size = ntohs(DFP_SIZE_TRANSFER);
+ f.dfp.base.type = DFP_PKT_SYNC_FISH;
+ f.dfp.base.pad = 0;
+ f.dfp.base.version = htons(DFP_VERSION);
+ memcpy(&(f.dfp.uid), &(ff->xfer.uid), 6);
+ memcpy(&(f.dfp.fish), &(ff->xfer.fish), sizeof(dfp_fish));
+ msg.flags = 0;
+ msg.src = port_fish;
+ msg.dst = port_net;
+ msg.size = DFP_SIZE_TRANSFER + 8;
+ msg.data = &f;
+ old_port_send(&msg);
+ st_sent++;
+ goto donesync;
+ }
+ }
+ sem_release(sem_fish);
+donesync:
+ break;
+
+ case DFP_PKT_NACK_FISH :
+ break;
+
+ case DFP_PKT_SYNC_FISH :
+ dfp->fish.ttl = ntohs(dfp->fish.ttl);
+
+ strncpy(n2,dfp->fish.name,16);
+ n2[16]=0;
+ lprintf(" : UID %X%X%X%X%X%X @(%d,%d) d(%d,%d) ttl=%d, name=\"%s\"\n",
+ dfp->uid.creator_tank_x, dfp->uid.creator_tank_y,
+ dfp->uid.timestamp[0], dfp->uid.timestamp[1],
+ dfp->uid.timestamp[2], dfp->uid.timestamp[3],
+ dfp->fish.x, dfp->fish.y, dfp->fish.dx, dfp->fish.dy,
+ dfp->fish.ttl, n2);
+
+ newfish(dfp->fish.x, dfp->fish.y,
+ dfp->fish.dx, dfp->fish.dy,
+ n2);
+/* lprintf("Welcome, \"%s\" from (%d,%d)",n2,
+ dfp->base.src_tank_x, dfp->base.src_tank_y);*/
+
+ settank(dfp->base.src_tank_x,dfp->base.src_tank_y,1);
+ default:
+ break;
+ }
+}
+
+void test(int x, int y)
+{
+ static dfp_pkt_transfer tran;
+ tran.fish.x = 100;
+ tran.fish.y = 100;
+ tran.fish.dx = 3;
+ tran.fish.dy = 4;
+ tran.fish.ttl = htons(1600);
+ tran.uid.creator_tank_x = myX;
+ tran.uid.creator_tank_y = myY;
+ *((uint32 *) tran.uid.timestamp) = 0x10203040;
+
+ strcpy(tran.fish.name,"Bitchin Fish");
+
+ initiate(&tran,x,y);
+}
+
+unsigned char *fish_bm =
+ ".........XXXXXX.....XXX."
+ ".....XXXXYYYYYYXX..XYYYX"
+ "...XXYY.YYYYYYYYYXXYYYYX"
+ ".XXYYYYYYYYYYYYYYYYYYYX."
+ "...XXYYYYYYYYYYYYYXXYYYX"
+ ".....XXXYYYYYYYXXX..XXYX"
+ "........XXXYYYX.......XX"
+ "...........XXXXX........"
+;
+
+unsigned char *arrow_up[2] ={
+ "....rr...."
+ "...rrrr..."
+ "..rrrrrr.."
+ ".rrrrrrrr."
+ "rrrrrrrrrr"
+,
+ "....gg...."
+ "...gggg..."
+ "..gggggg.."
+ ".gggggggg."
+ "gggggggggg"
+};
+unsigned char *arrow_dn[2] ={
+ "rrrrrrrrrr"
+ ".rrrrrrrr."
+ "..rrrrrr.."
+ "...rrrr..."
+ "....rr...."
+,
+ "gggggggggg"
+ ".gggggggg."
+ "..gggggg.."
+ "...gggg..."
+ "....gg...."
+};
+unsigned char *arrow_lf[2] ={
+ "....r"
+ "...rr"
+ "..rrr"
+ ".rrrr"
+ "rrrrr"
+ "rrrrr"
+ ".rrrr"
+ "..rrr"
+ "...rr"
+ "....r"
+,
+ "....g"
+ "...gg"
+ "..ggg"
+ ".gggg"
+ "ggggg"
+ "ggggg"
+ ".gggg"
+ "..ggg"
+ "...gg"
+ "....g"
+};
+unsigned char *arrow_rt[2] = {
+ "r...."
+ "rr..."
+ "rrr.."
+ "rrrr."
+ "rrrrr"
+ "rrrrr"
+ "rrrr."
+ "rrr.."
+ "rr..."
+ "r...."
+,
+ "g...."
+ "gg..."
+ "ggg.."
+ "gggg."
+ "ggggg"
+ "ggggg"
+ "gggg."
+ "ggg.."
+ "gg..."
+ "g...."
+};
+
+int dist(int x0, int y0, int x1, int y1)
+{
+ return((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1));
+}
+
+void sendfish(fish *f, int tx, int ty)
+{
+ f->xfer.fish.x = f->x;
+ f->xfer.fish.y = f->y;
+ f->xfer.fish.dx = f->dx;
+ f->xfer.fish.dy = f->dy;
+ f->xfer.fish.ttl = htons(1600);
+ f->state = XMIT;
+ f->xt = ticks+TIMEOUT;
+ initiate(&f->xfer,tx,ty);
+}
+
+void prep(void)
+{
+ int i;
+ cnxn[C_LF].tx = myX - 1;
+ cnxn[C_LF].ty = myY;
+ cnxn[C_RT].tx = myX + 1;
+ cnxn[C_RT].ty = myY;
+ cnxn[C_UP].tx = myX;
+ cnxn[C_UP].ty = myY - 1;
+ cnxn[C_DN].tx = myX;
+ cnxn[C_DN].ty = myY + 1;
+ for(i=0;i<4;i++){
+ cnxn[i].live = 0;
+ pingtank(cnxn[i].tx,cnxn[i].ty);
+ }
+}
+
+
+void vloop(void)
+{
+ fish *f,*lf;
+ fish *f2;
+
+ int x,y,i;
+ int xx, xy, xd;
+ msg *m;
+
+ for(i=0;i<4;i++){
+ cnxn[i].live = 0;
+ pingtank(cnxn[i].tx,cnxn[i].ty);
+ }
+
+ for(;;){
+ ticks++;
+ if(!(ticks % 200)){
+ lprintf("pinging now...");
+ for(i=0;i<4;i++){
+ cnxn[i].live = 0;
+ pingtank(cnxn[i].tx,cnxn[i].ty);
+ }
+ }
+ os_sleep(snooze * 9000); /* 9ms increments */
+ vga_fillX();
+#ifdef LOGGING
+ sem_acquire(sem_msgs);
+ if(msgcount > logsize){
+ msgcount--;
+ m = first_msg;
+ first_msg = first_msg->next;
+ free(m);
+ }
+ if(logging){
+ for(y=16,m = first_msg; (y < 161) && m; m=m->next, y +=8){
+ vga_blit_str(m->buf,15,y,'#');
+ }
+ }
+ sem_release(sem_msgs);
+#endif
+ sem_acquire(sem_fish);
+ for(lf=NULL,f=first;f;f=f->next){
+ if(f->state == DEAD && lf){
+ lprintf("Expiring \"%s\"",f->name);
+ lf->next = f->next;
+ free(f);
+ f = lf;
+ continue;
+ }
+ if((f->state == XMIT) && (ticks > f->xt)) {
+ cnxn[f->dest].live = 0;
+ f->state = LIVE;
+ st_rej++;
+ }
+ if(f->state == LIVE){
+ xx = xy = 0;
+ xd = -1;
+ x = f->x;
+ y = f->y;
+ if(f->x < 0){
+ xx = 1;
+ if(cnxn[C_LF].live) {
+ xd = C_LF;
+ f->x = 254;
+ }
+ }
+ if(f->x > 255){
+ xx = 1;
+ if(cnxn[C_RT].live) {
+ xd = C_RT;
+ f->x = 1;
+ }
+ }
+ if(f->y < 0){
+ xy = 1;
+ if(cnxn[C_UP].live) {
+ if(xd == -1) {
+ xd = C_UP;
+ f->y = 254;
+ }
+ }
+ }
+ if(f->y > 255) {
+ xy = 1;
+ if(cnxn[C_DN].live) {
+ if(xd == -1) {
+ xd = C_DN;
+ f->y = 1;
+ }
+ }
+ }
+ if(!sticky && !recluse && (xd != -1)) {
+ f->dest = xd;
+ sendfish(f,cnxn[xd].tx,cnxn[xd].ty);
+ }
+ if(xx){
+ f->dx = - f->dx;
+ f->x = x + f->dx;
+ }
+ if(xy){
+ f->dy = - f->dy;
+ f->y = y + f->dy;
+ }
+ if(xd != -1) continue;
+#ifdef XXX
+ /* collision ? */
+ {
+ int xc,yc;
+ xc = f->x + 12;
+ yc = f->y + 4;
+
+ for(f2 = first; f2; f2 = f2->next){
+ if((f2 == f) || (f2->state != LIVE)) continue;
+ if(dist(xc,yc,f2->x+12,f2->y+4) < 100){
+ if(collision){
+ f->dx = - f->dx;
+ f->dy = - f->dy;
+ }
+ if(!strcmp(f->name,"killer")) {
+ f2->state = DEAD;
+ }
+ if(!strcmp(f2->name,"killer")){
+ f->state = DEAD;
+ }
+ break;
+ }
+ }
+ }
+ /* collision - */
+#endif
+ f->x += f->dx;
+ f->y += f->dy;
+ x = (f->x * (320-24)) / 256;
+ y = (f->y * (200-16)) / 256 + 8;
+
+ if(f->dx < 0){
+ vga_blit_trans(f->bitmap,x,y,24,8);
+ } else {
+ vga_blit_trans_r(f->bitmap,x,y,24,8);
+ }
+ vga_blit_str(f->name,x,y-8,'w');
+ }
+ lf = f;
+ }
+ sem_release(sem_fish);
+
+
+ vga_blit_trans(arrow_up[cnxn[C_UP].live],320/2-5,0,10,5);
+ vga_blit_trans(arrow_dn[cnxn[C_DN].live],320/2-5,200-9,10,5);
+ vga_blit_trans(arrow_lf[cnxn[C_LF].live],0,100-5,5,10);
+ vga_blit_trans(arrow_rt[cnxn[C_RT].live],320-6,100-5,5,10);
+ /* if(logo) vga_blit_trans(blt,319-blt_w,2,blt_w,blt_h); */
+ if(sticky) vga_blit_str("STICKY",0,0,'r');
+ if(recluse) vga_blit_str("RECLUSIVE",8*7,0,'r');
+ if(borg) vga_blit_str("BORG",320-(8*6),0,'r');
+
+ if(keybuf[0]){
+ vga_fill(320,10,0,179,'b');
+ vga_blit_str(keybuf2,1,180,'w');
+ }
+ vga_swap_buffers();
+ }
+}
+
+int bc = 0;
+
+void newfish(int x, int y, int dx, int dy, char *n)
+{
+ fish *f = (fish *) malloc(sizeof(fish));
+
+ char bf[16];
+
+ st_recv++;
+ if(borg) {
+ n = bf;
+ snprintf(n,16,"Borg (%d)",bc++);
+ bf[15]=0;
+ }
+ f->x = x;
+ f->y = y;
+ f->dx = dx;
+ f->dy = dy;
+ strncpy(f->name,n,16);
+ f->name[16]=0;
+ f->bitmap = fish_bm;
+ f->state = LIVE;
+ f->xfer.uid.creator_tank_x = myX;
+ f->xfer.uid.creator_tank_y = myY;
+ *((uint32 *)f->xfer.uid.timestamp) = 0x1000000 + ticks;
+ /*XXX */
+
+ strcpy(f->xfer.fish.name,f->name);
+ sem_acquire(sem_fish);
+ f->next = first;
+ first = f;
+ sem_release(sem_fish);
+ st_count++;
+}
+
+
+
+void vinit(void)
+{
+ int i;
+ void *vmem = 0xA0000;
+ area_create(64*1024, 0, &vmem, AREA_PHYSMAP);
+
+ vga_set_sram(vmem);
+ vga_set_mode(320,200,8);
+
+ vmem = malloc(64*1024);
+ vga_set_vram(vmem);
+
+ vga_set_palette('.',0,0,255);
+ vga_set_palette('w',255,255,255);
+ vga_set_palette('X',255,0,0);
+ vga_set_palette('Y',255,255,0);
+ vga_set_palette('#',0,255,0);
+ vga_set_palette('g',0,255,0);
+ vga_set_palette('r',255,0,0);
+ vga_set_palette('b',0,0,0);
+ vga_set_palette('L',0,255,0);
+ for(i=0;i<50;i++){
+ vga_set_palette(128+i,0,0,12+i);
+ }
+
+ vga_fill_grad(320,200,0,0);
+ vga_swap_buffers();
+
+ lprintf("fish: vinit()");
+
+ newfish(160,160,3,3,"fish");
+ newfish(100,40,-1,2,"not fish");
+}
+
+void command(char *str);
+
+void fishmain(void)
+{
+ int once = 1;
+ unsigned char data[1500];
+ msg_hdr_t msg;
+ int i;
+ int size;
+ net_cmd cmd;
+ unsigned char ip[4];
+
+ sem_fish = sem_create(1, "fish_lock");
+ sem_msgs = sem_create(1, "msgs_lock");
+
+ keybuf2[0] = '>';
+ keybuf2[1] = ' ';
+
+ if((port_net = namer_find("net",0)) < 1) WITH_NET = 0;
+ if((port_net_xmit = namer_find("net_xmit",0)) < 1) WITH_NET = 0;
+
+ port_fish = port_create(0, "fish_tell_port");
+ namer_register(port_fish, "fish:tell");
+
+ vinit();
+
+ os_thread(vloop);
+/* os_thread(restarter); */
+
+ lprintf("fish: port=%d, console=%d, net=%d\n",
+ port_fish, port_console, port_net);
+
+ if(WITH_NET){
+ msg.flags = 0;
+ msg.src = port_fish;
+ msg.dst = port_net;
+ msg.size = 8;
+ msg.data = &cmd;
+
+ cmd.cmd = NET_IP;
+ cmd.port = 0;
+ old_port_send(&msg);
+ msg.src = port_net_xmit;
+ msg.dst = port_fish;
+ msg.size = 4;
+ msg.data = ip;
+ old_port_recv(&msg);
+
+ lprintf("IP = %d.%d.%d.%d\n",ip[0],ip[1],ip[2],ip[3]);
+
+ myX = (ip[3] >> 3) & 0x07;
+ myY = (ip[3]) & 0x07;
+ lprintf("tank @ %d,%d",myX, myY);
+
+ msg.flags = 0;
+ msg.src = port_fish;
+ msg.dst = port_net;
+ msg.size = 8;
+ msg.data = &cmd;
+
+ cmd.cmd = NET_CONNECT;
+ cmd.port = 5049;
+ old_port_send(&msg);
+ } else {
+ lprintf("no network support\n");
+ }
+
+ prep();
+#if 0
+ os_thread(keythread);
+#endif
+ for(;;){
+ msg.flags = 0;
+ msg.src = 0;
+ msg.dst = port_fish;
+ msg.size = 1500;
+ msg.data = data;
+
+ if((size = old_port_recv(&msg)) > 0){
+ if(WITH_NET && (msg.src == port_net_xmit)){
+ dofish((dfp_pkt_transfer *) data);
+ } else {
+ uint32 response = 0;
+ data[size]=0;
+ command(data);
+ msg.dst = msg.src;
+ msg.src = port_fish;
+ msg.size = 4;
+ msg.data = &response;
+ old_port_send(&msg);
+ }
+ }
+ }
+}
+
+int main(void)
+{
+ os_thread(fishmain);
+ return 0;
+}
+
+void command(char *str)
+{
+ if(!strncmp(str,"tank",4)){
+ int x,y;
+ x = str[5]-'0';
+ y = str[6]-'0';
+ if(x <0 || x>9 || y<0 || x>9) return;
+ myX = x;
+ myY = y;
+ prep();
+ lprintf("relocating tank to %d,%d",myX,myY);
+ return;
+ }
+ if(!strncmp(str,"stats",5)){
+ lprintf("count: %d sent: %d recv: %d rej: %d",st_count,st_sent,st_recv,st_rej);
+ return;
+ }
+ if(!strncmp(str,"sticky",6)){
+ sticky = !sticky;
+ lprintf("Sticky mode %s",sticky?"on":"off");
+ return;
+ }
+ if(!strncmp(str,"recluse",7)){
+ recluse = !recluse;
+ lprintf("Recluse mode %s",recluse?"on":"off");
+ return;
+ }
+ if(!strncmp(str,"panic",5)){
+ fish *f;
+ sem_acquire(sem_fish);
+ for(f=first;f;f=f->next) {
+ f->dx *= 2;
+ f->dy *= 2;
+ }
+ sem_release(sem_fish);
+ return;
+ }
+ if(!strncmp(str,"purge",5)){
+ fish *f;
+ sem_acquire(sem_fish);
+ for(f=first;f;f=f->next) {
+ if(f->state == LIVE) f->state = DEAD;
+ }
+ st_count = 0;
+ sem_release(sem_fish);
+ return;
+ }
+ if(!strncmp(str,"logo",4)){
+ logo = !logo;
+ return;
+ }
+ if(!strncmp(str,"collision",9)){
+ collision = !collision;
+ return;
+ }
+ if(!strncmp(str,"snooze ",7)){
+ snooze = str[7]-'0';
+ if(snooze < 3 || snooze > 9) snooze = 5;
+ return;
+ }
+ if(!strncmp(str,"borg",4)){
+ borg = !borg;
+ lprintf("Borg mode %s",borg?"on - prepare to assimilate":"off");
+ return;
+ }
+ if(!strncmp(str,"eject",5)){
+ int i;
+ lprintf("Ejecting all fish now!");
+ for(i=0;i<4;i++){
+ if(cnxn[i].live){
+ fish *f;
+ sem_acquire(sem_fish);
+ for(f = first; f; f=f->next){
+ if(f->state == LIVE){
+ sendfish(f,cnxn[i].tx,cnxn[i].ty);
+ }
+ }
+ sem_release(sem_fish);
+ return;
+ }
+ }
+ return;
+ }
+ if(!strncmp(str,"debug",5)){
+ os_debug();
+ return;
+ }
+ if(!strncmp(str,"log",3)){
+ logging = !logging;
+ return;
+ }
+ if(!strncmp(str,"new ",3)) {
+ str+=4;
+ str[16]=0;
+ if(str[0] == '*'){
+ newfish(100,100,-3,-5,str+1);
+ newfish(130,100, 3,-5,str+1);
+ newfish(160,100,-3, 5,str+1);
+ newfish(190,100, 3, 5,str+1);
+ newfish(100,150,-3,-5,str+1);
+ newfish(130,150, 3,-5,str+1);
+ newfish(160,150,-3, 5,str+1);
+ newfish(190,150, 3, 5,str+1);
+ } else {
+ newfish(160,160,-3,5,str);
+ }
+ }
+
+}
+
+
+/* keyboard handler */
+
+#define ESC 27
+#define BS 8
+#define TAB 9
+#define CR 13
+
+char ScanTable [] = {' ', ESC, '1', '2', '3', '4', '5', '6', '7', '8',
+ '9', '0', '-', '=', BS, TAB, 'q', 'w', 'e', 'r',
+ 't', 'y', 'u', 'i', 'o', 'p', '[', ']', CR, ' ',
+ 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ '\'', '~', ' ', '\\', 'z', 'x', 'c', 'v', 'b', 'n',
+ 'm', ',', '.', '/', ' ', ' ', ' ', ' ', ' '};
+char ShiftTable [] = {' ', ESC, '!', '@', '#', '$', '%', '^', '&', '*',
+ '(', ')', '_', '+', ' ', ' ', 'Q', 'W', 'E', 'R',
+ 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', CR, ' ',
+ 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+ '\"', '~', ' ', '|', 'Z', 'X', 'C', 'V', 'B', 'N',
+ 'M', '<', '>', '?', ' ', ' ', ' ', ' ', ' '};
+#define LSHIFT 42
+#define RSHIFT 54
+
+void keythread(void)
+{
+ int shift = 0;
+ int key;
+
+ os_handle_irq(1);
+
+ for(;;) {
+ os_sleep_irq();
+ key = inb(0x60);
+ switch(key){
+ case LSHIFT:
+ case RSHIFT:
+ shift = 1;
+ break;
+ case LSHIFT | 0x80:
+ case RSHIFT | 0x80:
+ shift = 0;
+ break;
+ default:
+ if(key & 0x80){
+ /* break */
+ } else {
+ if(key < 59){
+ key = shift ? ShiftTable[key] : ScanTable[key];
+ switch(key){
+ case CR:
+ if(keyptr) command(keybuf);
+ case ESC:
+ keybuf[0] = 0;
+ keyptr = 0;
+ break;
+ case BS:
+ if(keyptr){
+ keyptr--;
+ keybuf[keyptr]=0;
+ }
+ break;
+ default:
+ if(keyptr < MAXKEYS){
+ keyptr++;
+ keybuf[keyptr]=0;
+ keybuf[keyptr-1]=key;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/srv/fish/font.h b/srv/fish/font.h
@@ -0,0 +1,157 @@
+/* $Id: //depot/blt/srv/fish/font.h#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+unsigned char *font[128] = {
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ "........................................",
+ ".......#....#....#....#.........#.......",
+ "......#.#..#.#..#.#.....................",
+ ".#.#..#.#.#####.#.#.#####.#.#..#.#......",
+ "..#...###.#.#...###...#.#.###...#.......",
+ "......#....#.#...#...#.#....#...........",
+ "..#...#.#..#.#...#...#.#..#.#...#.#.....",
+ ".......##...#...#.......................",
+ "........#...#....#....#.....#...........",
+ "......#.....#....#....#...#.............",
+ "......#..#..##..####..##..#..#..........",
+ ".......#....#..#####..#....#............",
+ "......................##...#...#........",
+ ".....................####...............",
+ "......................#...###...#.......",
+ ".........#....#...#...#...#....#........",
+ ".......#...#.#..#.#..#.#..#.#...#.......",
+ ".......#...##....#....#....#...###......",
+ ".......##..#..#....#..##..#....####.....",
+ ".......##..#..#...#.....#.#..#..##......",
+ "........#...##..#.#..####...#....#......",
+ "......####.#....###.....#.#..#..##......",
+ ".......##..#....#.#..##.#.#..#..##......",
+ "......####....#...#....#...#....#.......",
+ ".......##..#..#..##..#..#.#..#..##......",
+ ".......##..#..#.#.##..#.#....#..##......",
+ ".......##...##........##...##...........",
+ ".......##...##........##...#...#........",
+ "........#...#...#....#.....#.....#......",
+ "...........###.......###................",
+ "......#.....#.....#....#...#...#........",
+ ".......#...#.#....#...#.........#.......",
+ "..##..#..##..###.#.##.#.##..#..#.....##.",
+ ".......##..#..#.#..#.####.#..#.#..#.....",
+ "......###..#..#.###..#..#.#..#.###......",
+ ".......##..#..#.#....#....#..#..##......",
+ "......###..#..#.#..#.#..#.#..#.###......",
+ "......####.#....###..#....#....####.....",
+ "......####.#....###..#....#....#........",
+ ".......##..#..#.#....#.##.#..#..##......",
+ "......#..#.#..#.####.#..#.#..#.#..#.....",
+ "......###...#....#....#....#...###......",
+ ".......###....#....#....#.#..#..##......",
+ "......#..#.#.#..##...#.#..#.#..#..#.....",
+ "......#....#....#....#....#....###......",
+ "......#..#.####.####.#..#.#..#.#..#.....",
+ "......#..#.##.#.####.#.##.#.##.#..#.....",
+ ".......##..#..#.#..#.#..#.#..#..##......",
+ "......###..#..#.#..#.###..#....#........",
+ ".......##..#..#.#..#.##.#.#.##..##.....#",
+ "......###..#..#.#..#.###..#.##.#..#.....",
+ ".......##..#..#..#.....#..#..#..##......",
+ ".....#####..#....#....#....#....#.......",
+ "......#..#.#..#.#..#.#..#.#..#..##......",
+ "......#..#.#..#.#..#.#..#..##...##......",
+ "......#..#.#..#.#..#.####.####.#..#.....",
+ "......#..#.#..#..##...##..#..#.#..#.....",
+ ".....#...##...#.#.#...#....#....#.......",
+ "......####....#...#...#...#....####.....",
+ "......###..#....#....#....#....###......",
+ "......#....#.....#.....#.....#....#.....",
+ "......###....#....#....#....#..###......",
+ ".......#...#.#..#.#.....................",
+ "....................................####",
+ "......##...#.....#......................",
+ ".................#.#.#.##.#.##..#.#.....",
+ "......#....#....###..#..#.#..#.###......",
+ ".................##..#....#.....##......",
+ ".........#....#..#.#.#.##.#.##..#.#.....",
+ ".................##..####.#.....##......",
+ "........#...#.#..#...###...#....#.......",
+ ".................##..#..#..###....#..##.",
+ "......#....#....###..#..#.#..#.#..#.....",
+ ".......#........##....#....#...###......",
+ "........#.........#....#....#..#.#...#..",
+ "......#....#....#..#.###..#..#.#..#.....",
+ "......##....#....#....#....#...###......",
+ "................#.#.#.#.##.#.##...#.....",
+ "................###..#..#.#..#.#..#.....",
+ ".................##..#..#.#..#..##......",
+ "................###..#..#.###..#....#...",
+ ".................###.#..#..###....#....#",
+ "................#.#..##.#.#....#........",
+ "................###..##.....#..###......",
+ ".......#....#...###...#....#.#...#......",
+ "................#..#.#..#.#..#..###.....",
+ "................#.#..#.#..#.#...#.......",
+ "...............#...##.#.##.#.#.###......",
+ "................#..#..##...##..#..#.....",
+ "................#..#.#..#..###.#..#..##.",
+ "................####...#...#...####.....",
+ "...##..#.....#..##.....#...#.....##.....",
+ ".......#....#....#....#....#....#.......",
+ ".##.....#...#.....##..#.....#..##.......",
+ ".......#.#.#.#..........................",
+ "........................................",
+};
diff --git a/srv/fish/vga.c b/srv/fish/vga.c
@@ -0,0 +1,225 @@
+/* $Id: //depot/blt/srv/fish/vga.c#3 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "vga.h"
+
+#include <i386/io.h>
+
+const int MiscOutputReg = 0x3c2;
+const int DataReg = 0x3c0;
+const int AddressReg = 0x3c0;
+
+const char mode13[][32] = {
+ { 0x03, 0x01, 0x0f, 0x00, 0x0e }, /* 0x3c4, index 0-4*/
+ { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x0e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
+ 0xff }, /* 0x3d4, index 0-0x18*/
+ { 0, 0, 0, 0, 0, 0x40, 0x05, 0x0f, 0xff }, /* 0x3ce, index 0-8*/
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 0x41, 0, 0x0f, 0, 0 } /* 0x3c0, index 0-0x14*/
+};
+
+#define Vga256 0x13 // 320x200x256
+#define TextMode 0x03 // 80x25 text mode
+#define PaletteMask 0x3C6 // bit mask register
+#define PaletteRegisterRead 0x3C7 // read index
+#define PaletteRegisterWrite 0x3C8 // write index
+#define PaletteData 0x3C9 // send/receive data here
+#define RomCharSegment 0xF000
+#define RomCharOffset 0xFA6E
+#define CharWidth 8
+#define CharHeight 8
+
+
+#define pixel(x,y,c) (((unsigned char *)VRAM)[(y)*320+(x)] = c)
+
+
+void vga_set_palette(int color, int red, int green, int blue)
+{
+
+ outb(0xFF, PaletteMask);
+ outb(color, PaletteRegisterWrite);
+ outb(red, PaletteData);
+ outb(green, PaletteData);
+ outb(blue, PaletteData);
+}
+
+int vga_set_mode(int xres, int yres, int bitdepth)
+{
+ int i;
+
+ outb_p(0x63, MiscOutputReg);
+ outb_p(0x00, 0x3da);
+
+ for (i=0; i < 5; i++) {
+ outb_p(i, 0x3c4);
+ outb_p(mode13[0][i], 0x3c4+1);
+ }
+
+ outw_p(0x0e11, 0x3d4);
+
+ for (i=0; i < 0x19; i++) {
+ outb_p(i, 0x3d4);
+ outb_p(mode13[1][i], (0x3d4 + 1));
+ }
+
+ for (i=0; i < 0x9; i++) {
+ outb_p(i, 0x3ce);
+ outb_p(mode13[2][i], (0x3ce + 1));
+ }
+
+ inb_p(0x3da);
+
+ for (i=0; i < 0x15; i++) {
+ inw(DataReg);
+ outb_p(i, AddressReg);
+ outb_p(mode13[3][i], DataReg);
+ }
+
+ outb_p(0x20, 0x3c0);
+
+ return 1;
+}
+
+#include "font.h"
+
+static unsigned int VRAM = 0xA0000;
+static unsigned int SRAM = 0xA0000;
+
+void vga_set_sram(void *addr)
+{
+ SRAM = (unsigned int) addr;
+}
+
+void vga_set_vram(void *addr)
+{
+ VRAM = (unsigned int) addr;
+}
+
+void vga_swap_buffers(void)
+{
+ int i;
+ unsigned int *vram = (unsigned int *) VRAM;
+ unsigned int *disp = (unsigned int *) SRAM;
+
+ i = 16000;
+ while(i--) *disp++ = *vram++;
+}
+
+
+void vga_blit(char *bitmap, int x, int y, int w, int h)
+{
+ int i, j;
+ char *edi = (char *) (VRAM + y*320 + x);
+
+ for (i = 0; i < h; i++, edi += 320 - w) {
+ for (j = 0; j < w; j++, edi++, bitmap++)
+ *edi = *bitmap;
+ }
+}
+
+void vga_blit_trans(char *bitmap, int x, int y, int w, int h)
+{
+ int i, j;
+ char *edi = (char *) (VRAM + y*320 + x);
+
+ for (i = 0; i < h; i++, edi += 320 - w) {
+ for (j = 0; j < w; j++, edi++, bitmap++)
+ if (*bitmap != '.') *edi = *bitmap;
+ }
+}
+
+void vga_blit_trans_r(char *bitmap, int x, int y, int w, int h)
+{
+ int i, j;
+ char *edi = (char *) (VRAM + y*320 + x + w);
+
+ for (i = 0; i < h; i++, edi += 320 + w) {
+ for (j = w; j >0; j--, edi--, bitmap++)
+ if (*bitmap != '.') *edi = *bitmap;
+ }
+}
+
+void vga_blit_str(char *s, int x, int y, int c)
+{
+ int w, h, i, j;
+ char *edi;
+ char *bitmap;
+ w = 5;
+ h = 8;
+ while(*s) {
+ bitmap = font[(*s) & 0x7F];
+ edi = (char *) (VRAM + y*320 + x);
+ for (i = 0; i < h; i++, edi += 320 - w) {
+ for (j = 0; j < w; j++, edi++, bitmap++){
+ if (*bitmap != '.') *edi = c;
+ }
+ }
+ x += 5;
+ s++;
+ }
+}
+
+
+
+void vga_fill(int w, int h, int x, int y, int c)
+{
+ int tx,ty;
+
+ for(ty = y; ty < y+h; ty++){
+ for(tx = x; tx < x+w; tx++){
+ pixel(tx,ty,c);
+ }
+ }
+
+}
+
+void vga_fillX(void)
+{
+ unsigned int f,i,j=50,n=128+49;
+ unsigned int *addr = (unsigned int *) VRAM;
+
+ while(j--){
+ f = (n << 24) | (n << 16) | (n << 8) | n;
+ n--;
+ i = 320;
+ while(i--) *addr++ = f;
+ }
+}
+
+void vga_fill_grad(int w, int h, int x, int y)
+{
+ int tx,ty;
+
+ for(ty = y; ty < y+h; ty++){
+ for(tx = x; tx < x+w; tx++){
+ pixel(tx,ty,128 + ty/4);
+ }
+ }
+
+}
diff --git a/srv/fish/vga.h b/srv/fish/vga.h
@@ -0,0 +1,49 @@
+/* $Id: //depot/blt/srv/fish/vga.h#3 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef _vga_h
+#define _vga_h
+
+void vga_set_palette(int color, int red, int green, int blue);
+int vga_set_mode(int xres, int yres, int bitdepth);
+/* only valid parms are (320, 200, 8); */
+
+void vga_blit(char *bitmap, int x, int y, int w, int h);
+void vga_blit_trans(char *bitmap, int x, int y, int w, int h);
+void vga_blit_trans_r(char *bitmap, int x, int y, int w, int h);
+void vga_blit_str(char *s, int x, int y, int c);
+
+void vga_fill(int w, int h, int x, int y, int c);
+void vga_fill_grad(int w, int h, int x, int y);
+
+void vga_set_vram(void *addr);
+void vga_set_sram(void *addr);
+void vga_swap_buffers(void);
+void vga_fillX(void);
+void vga_modex(unsigned int w);
+
+#endif
diff --git a/srv/ide/Makefile b/srv/ide/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := main.c identify.c disk.c blkdev.c
+BINARY := ide.bin
+CFLAGS += -finline-functions
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
diff --git a/srv/ide/TODO b/srv/ide/TODO
@@ -0,0 +1,16 @@
+- probe for busses
+- support multiple busses
+- distinguish between disks and cdroms and such
+- error checking
+- write support
+- proper initialisation of controller
+
+done
+----
+
+bugs
+----
+- stuff works, turn off machine, go to sleep, wake up, turn on machine,
+ stuff is broken, boot freebsd, turn off, turn on, stuff works. i have
+ no idea what causes this.
+
diff --git a/srv/ide/blkdev.c b/srv/ide/blkdev.c
@@ -0,0 +1,64 @@
+/* $Id: //depot/blt/srv/ide/blkdev.c#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <blt/blkdev.h>
+#include "ide-int.h"
+
+int blk_open (const char *name, int flags, blkdev_t **retdev)
+{
+ blkdev_t *dev;
+
+ dev = malloc (sizeof (blkdev_t));
+ dev->blksize = 512;
+ dev->devno = (name[4] - '0') * 2 + (name[6] - '0');
+ *retdev = dev;
+ return 0;
+}
+
+int blk_close (blkdev_t *dev)
+{
+ free (dev);
+ return 0;
+}
+
+int blk_read (blkdev_t *dev, void *buf, int block, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ ide_dev[dev->devno]->read ((dev->devno & 0xff) / 2, dev->devno % 2,
+ (char *) buf + dev->blksize * i, block + i);
+ return 0;
+}
+
+int blk_write (blkdev_t *dev, const void *buf, int block, int count)
+{
+ return 0;
+}
+
diff --git a/srv/ide/disk.c b/srv/ide/disk.c
@@ -0,0 +1,89 @@
+/* $Id: //depot/blt/srv/ide/disk.c#4 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "ide-int.h"
+#include <stdio.h>
+#include <i386/io.h>
+
+int ide_disk_read (int bus, int device, void *data, int block)
+{
+ unsigned short *buf;
+ int i, base, cyl, head, sect;
+
+ base = ide_base (bus);
+ buf = (unsigned short *) data;
+ ide_btochs (block, ide_dev[bus * 2 + device], &cyl, &head, §);
+ IDE_WAIT_0 (STATUS, 7);
+
+ IDE_SEL_DH (bus, device, head);
+ IDE_WAIT_0 (STATUS, 7);
+ //IDE_WAIT_1 (STATUS, 6);
+
+ outb (cyl / 256, IDE_REG_CYLMSB);
+ outb (cyl % 256, IDE_REG_CYLLSB);
+ outb (sect + 1, IDE_REG_SECNUM);
+ outb (1, IDE_REG_SECCNT);
+ outb (IDE_OP_READ, IDE_REG_COMMAND);
+ IDE_WAIT_0 (STATUS, 7);
+ IDE_WAIT_1 (STATUS, 3);
+
+ for (i = 0; i < 256; i++)
+ buf[i] = inw (IDE_REG_DATA);
+ return 0;
+}
+
+int ide_disk_write (int bus, int device, const void *data, int block)
+{
+#if 0
+ short *buf;
+ int i, base, cyl, head, sect;
+
+ base = ide_base (bus);
+ buf = (short *) data;
+ ide_btochs (block, ide_dev[bus * 2 + device], &cyl, &head, §);
+ IDE_WAIT_0 (STATUS, 7);
+
+ /* select device */
+ IDE_SEL_DH (bus, device, head);
+ IDE_WAIT_0 (STATUS, 7);
+ IDE_WAIT_1 (STATUS, 6);
+
+ outb (cyl / 256, IDE_REG_CYLMSB);
+ outb (cyl % 256, IDE_REG_CYLLSB);
+ outb (sect, IDE_REG_SECNUM);
+ outb (1, IDE_REG_SECCNT);
+ outb (IDE_OP_WRITE, IDE_REG_COMMAND);
+ IDE_WAIT_1 (STATUS, 3);
+
+ for (i = 0; i < 256; i++)
+ outw (buf[i], IDE_REG_DATA);
+#endif
+
+ return 0;
+}
+
diff --git a/srv/ide/ide-int.h b/srv/ide/ide-int.h
@@ -0,0 +1,148 @@
+/* $Id: //depot/blt/srv/ide/ide-int.h#5 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef IDE_INT_H
+#define IDE_INT_H
+
+#include <blt/disk.h>
+
+#define IDE_PRI_BASE 0x1f0
+#define IDE_SEC_BASE 0x170
+#define IDE_DIGITAL_OUTPUT 0x3f6
+#define IDE_DRIVE_ADDR 0x3f7
+
+#define IDE_REG_OFF_DATA 0 /* R/W, 16 bits */
+#define IDE_REG_OFF_ERROR 1 /* R */
+#define IDE_REG_OFF_PRECOMP 1 /* W */
+#define IDE_REG_OFF_SECCNT 2 /* R/W */
+#define IDE_REG_OFF_SECNUM 3 /* R/W */
+#define IDE_REG_OFF_CYLLSB 4 /* R/W */
+#define IDE_REG_OFF_CYLMSB 5 /* R/W */
+#define IDE_REG_OFF_DH 6 /* R/W */
+#define IDE_REG_OFF_STATUS 7 /* R */
+#define IDE_REG_OFF_COMMAND 7 /* W */
+
+#define IDE_REG_DATA (base + IDE_REG_OFF_DATA)
+#define IDE_REG_ERROR (base + IDE_REG_OFF_ERROR)
+#define IDE_REG_PRECOMP (base + IDE_REG_OFF_PRECOMP)
+#define IDE_REG_SECCNT (base + IDE_REG_OFF_SECCNT)
+#define IDE_REG_SECNUM (base + IDE_REG_OFF_SECNUM)
+#define IDE_REG_CYLLSB (base + IDE_REG_OFF_CYLLSB)
+#define IDE_REG_CYLMSB (base + IDE_REG_OFF_CYLMSB)
+#define IDE_REG_DH (base + IDE_REG_OFF_DH)
+#define IDE_REG_STATUS (base + IDE_REG_OFF_STATUS)
+#define IDE_REG_COMMAND (base + IDE_REG_OFF_COMMAND)
+
+#define IDE_SEL_DH(bus, device, head) \
+ outb (0x1010000 | (device << 4) | head, IDE_REG_DH)
+
+#define IDE_WAIT_0(reg, bit) \
+ while (inb (IDE_REG_##reg) & (1 << bit)) ;
+#define IDE_WAIT_1(reg, bit) \
+ while (!(inb (IDE_REG_##reg) & (1 << bit))) ;
+
+/* XXX - hack */
+#define IDE_WAITFAIL_1(reg, bit) \
+ { \
+ int __spin__ = 0; \
+ while (!(inb (IDE_REG_##reg) & (1 << bit)) && (__spin__ < 10000)) \
+ __spin__++; \
+ if (__spin__ == 10000) \
+ fail = 1; \
+ }
+
+#define IDE_OP_RECALIBRATE 0x10
+#define IDE_OP_READ 0x20
+#define IDE_OP_WRITE 0x30
+#define IDE_OP_IDENTIFY_DEVICE 0xec
+
+#define IDE_IDENTIFY_DATA_SIZE 256
+
+typedef struct
+{
+ unsigned short config; /* obsolete stuff */
+ unsigned short cyls; /* logical cylinders */
+ unsigned short _reserved_2;
+ unsigned short heads; /* logical heads */
+ unsigned short _vendor_4;
+ unsigned short _vendor_5;
+ unsigned short sectors; /* logical sectors */
+ unsigned short _vendor_7;
+ unsigned short _vendor_8;
+ unsigned short _vendor_9;
+ char serial[20]; /* serial number */
+ unsigned short _vendor_20;
+ unsigned short _vendor_21;
+ unsigned short vend_bytes_long; /* no. vendor bytes on long cmd */
+ char firmware[8];
+ char model[40];
+ unsigned short mult_support; /* vendor stuff and multiple cmds */
+ unsigned short _reserved_48;
+ unsigned short capabilities;
+ unsigned short _reserved_50;
+ unsigned short pio;
+ unsigned short dma;
+ unsigned short _reserved_53;
+ unsigned short curr_cyls; /* current logical cylinders */
+ unsigned short curr_heads; /* current logical heads */
+ unsigned short curr_sectors; /* current logical sectors */
+ unsigned int capacity; /* capacity in sectors */
+ unsigned short _pad[256-59]; /* don't need this stuff for now */
+} ide_hw_id_t;
+
+typedef struct
+{
+ const ide_hw_id_t *hwdev;
+ int iobase;
+ disk_t *disk;
+ int (*read) (int bus, int device, void *buf, int block);
+ int (*write) (int bus, int device, const void *buf, int block);
+} ide_dev_t;
+
+extern ide_dev_t **ide_dev;
+extern int total_busses;
+
+void ide_btochs (int block, ide_dev_t *dev, int *cyl, int *head, int *sect);
+
+int ide_probe_devices (void);
+
+int ide_disk_read (int bus, int device, void *data, int block);
+int ide_disk_write (int bus, int device, const void *data, int block);
+
+static inline int ide_base (int bus)
+{
+ if (bus == 0)
+ return IDE_PRI_BASE;
+ else if (bus == 1)
+ return IDE_SEC_BASE;
+ else
+ return -1;
+}
+
+#endif
+
diff --git a/srv/ide/identify.c b/srv/ide/identify.c
@@ -0,0 +1,173 @@
+/* $Id: //depot/blt/srv/ide/identify.c#6 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <blt/syscall.h>
+#include <blt/types.h>
+#include <blt/disk.h>
+#include <blt/blkdev.h>
+#include <i386/io.h>
+#include "ide-int.h"
+
+int total_busses = 0;
+ide_dev_t **ide_dev;
+
+static void ide_string_conv (char *str, int len)
+{
+ int i;
+ unsigned short *w;
+
+ w = (unsigned short *) str;
+ for (i = 0; i < len / sizeof (unsigned short); i++)
+ w[i] = ntohs (w[i]);
+
+ str[len - 1] = 0;
+ for (i = len - 1; (i >= 0) && ((str[i] == ' ') || !str[i]); i--)
+ str[i] = 0;
+}
+
+int ide_reset (int bus, int device)
+{
+ int i, base, fail = 0;
+
+ outb (6, IDE_DIGITAL_OUTPUT);
+ for (i = 0; i < 1000000; i++) ; /* XXX */
+ outb (0, IDE_DIGITAL_OUTPUT);
+ //IDE_WAIT_1 (STATUS, 6);
+
+ base = ide_base (bus);
+ IDE_WAIT_0 (STATUS, 7);
+ IDE_SEL_DH (bus, device, 0);
+ IDE_WAIT_0 (STATUS, 7);
+ IDE_WAITFAIL_1 (STATUS, 6);
+ if (fail)
+ return 1;
+
+ outb (0, IDE_REG_CYLLSB);
+ outb (0, IDE_REG_CYLMSB);
+ outb (0, IDE_REG_SECNUM);
+ outb (0, IDE_REG_SECCNT);
+ outb (IDE_OP_RECALIBRATE, IDE_REG_COMMAND);
+ return 0;
+}
+
+const ide_hw_id_t *ide_identify_device (int bus, int device)
+{
+ short *buf;
+ int i, base, fail, mb;
+ ide_hw_id_t *hwdev;
+
+ if ((base = ide_base (bus)) < 0)
+ return NULL;
+ if ((device < 0) || (device > 1))
+ return NULL;
+
+ fail = 0;
+ buf = (short *) hwdev = malloc (sizeof (ide_hw_id_t));
+ IDE_WAIT_0 (STATUS, 7);
+
+ IDE_SEL_DH (bus, device, 0);
+ IDE_WAIT_0 (STATUS, 7);
+ IDE_WAITFAIL_1 (STATUS, 6);
+ if (fail)
+ return NULL;
+
+ outb (IDE_OP_IDENTIFY_DEVICE, IDE_REG_COMMAND);
+ IDE_WAIT_1 (STATUS, 3);
+
+ for (i = 0; i < sizeof (ide_hw_id_t) / sizeof (short); i++)
+ buf[i] = inw (IDE_REG_DATA);
+
+ ide_string_conv (hwdev->serial, sizeof (hwdev->serial));
+ ide_string_conv (hwdev->firmware, sizeof (hwdev->firmware));
+ ide_string_conv (hwdev->model, sizeof (hwdev->model));
+ mb = hwdev->cyls * hwdev->heads * hwdev->sectors * 512 / 1024 / 1024;
+
+ printf ("ide: disk at bus %d, device %d, <%s>\n", bus, device,
+ hwdev->model);
+ printf ("ide/%d/%d: %dMB; %d cyl, %d head, %d sec, 512 bytes/sec\n",
+ bus, device, mb, hwdev->cyls, hwdev->heads, hwdev->sectors);
+ return hwdev;
+}
+
+int ide_attach_bus (int io, int irq)
+{
+ total_busses++;
+ return 0;
+}
+
+int ide_attach_device (int bus, int device)
+{
+ char name[9];
+ int i;
+ blkdev_t *bdev;
+ disk_t *disk;
+ const ide_hw_id_t *hwdev;
+ ide_dev_t *dev;
+
+ if ((hwdev = ide_identify_device (bus, device)) == NULL)
+ return 0;
+
+ dev = ide_dev[bus * 2 + device] = malloc (sizeof (ide_dev_t));
+ dev->hwdev = hwdev;
+ dev->iobase = ide_base (bus);
+ dev->read = ide_disk_read;
+ dev->write = ide_disk_write;
+
+ snprintf (name, sizeof (name), "ide/%d/%d", bus, device);
+ printf ("%s: partitions:", name);
+ blk_open (name, 0, &bdev);
+ dev->disk = disk = disk_alloc (bdev);
+ for (i = 0; i < disk->numparts; i++)
+ printf (" %s", disk_partition_name (disk, i));
+ printf ("\n");
+ blk_close (bdev);
+ return 1;
+}
+
+int ide_probe_devices (void)
+{
+ int i, found;
+
+ found = 0;
+ os_handle_irq (14);
+ ide_attach_bus (0x1f0, 14); /* XXX find this properly */
+ ide_dev = malloc (sizeof (ide_dev_t *) * total_busses * 2);
+
+ for (i = 0; i < total_busses; i++)
+ {
+ //if (!ide_reset (i, 0))
+ found += ide_attach_device (i, 0);
+ //if (!ide_reset (i, 1))
+ found += ide_attach_device (i, 1);
+ }
+ return found;
+}
+
diff --git a/srv/ide/main.c b/srv/ide/main.c
@@ -0,0 +1,140 @@
+/* Copyright 1999, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <blt/syscall.h>
+#include <blt/namer.h>
+#include <blt/os.h>
+#include <blt/blkdev.h>
+#include <blt/disk.h>
+#include "ide-int.h"
+
+void ide_btochs (int block, ide_dev_t *dev, int *cyl, int *head, int *sect)
+{
+ *cyl = block / (dev->hwdev->heads * dev->hwdev->sectors);
+ block %= dev->hwdev->heads * dev->hwdev->sectors;
+ *head = block / dev->hwdev->sectors;
+ block %= dev->hwdev->sectors;
+ *sect = block;
+}
+
+void ide_main (int *ready)
+{
+ char *c, dev[3];
+ int a, b, i, port, txnlen, reslen, bus, device, offset;
+ msg_hdr_t mh;
+ blktxn_t *txn;
+ blkres_t *res;
+ disk_t *disk;
+
+ if (!ide_probe_devices ())
+ {
+ printf ("ide: no devices found; exiting.\n");
+ os_terminate (1);
+ }
+
+ port = port_create (0, "ide");
+ namer_register (port, "ide");
+ txn = malloc (txnlen = sizeof (blktxn_t) + 1024);
+ res = malloc (reslen = sizeof (blkres_t) + 1024);
+ *ready = 1;
+
+ for (;;)
+ {
+ mh.src = 0;
+ mh.dst = port;
+ mh.data = txn;
+ mh.size = txnlen;
+ old_port_recv (&mh);
+
+ switch (txn->cmd)
+ {
+ case BLK_CMD_OPEN:
+ c = (char *) (txn + 1);
+ if (!isdigit (c[0]) || !isdigit (c[2]) || (c[1] != '/') ||
+ (c[3] != '/'))
+ {
+ res->status = ENOENT;
+ break;
+ }
+ bus = c[0] - '0';
+ device = c[2] - '0';
+ if ((bus >= total_busses) || ((device != 0) && (device != 1)))
+ res->status = ENOENT;
+ else if (ide_dev[bus * 2 + device] == NULL)
+ res->status = ENOENT;
+ else if (!strcmp (c + 4, "raw"))
+ {
+ res->status = 0;
+ res->data[0] = 512;
+ res->data[1] = (bus * 2 + device) | (0xff << 8);
+ mh.size = sizeof (blkres_t);
+ }
+ else if (isdigit (c[4]) && !c[5])
+ {
+ res->status = 0;
+ res->data[0] = 512;
+ res->data[1] = (bus * 2 + device) | ((c[4] - '0' + 1) << 8);
+ mh.size = sizeof (blkres_t);
+ }
+ else if (isdigit (c[4]) && c[5])
+ {
+ res->status = 0;
+ res->data[0] = 512;
+ res->data[1] = (bus * 2 + device) | ((c[4] - '0' + 1) <<
+ 8) | ((c[5] - 'a' + 1) << 16);
+ mh.size = sizeof (blkres_t);
+ }
+ else
+ res->status = ENOENT;
+ break;
+
+ case BLK_CMD_READ:
+ if ((txn->device & 0xff) > (total_busses * 2))
+ {
+ res->status = ENOENT;
+ break;
+ }
+ offset = 0;
+ if ((txn->device >> 8))
+ {
+ a = ((txn->device & 0x0000ff00) >> 8);
+ b = ((txn->device & 0x00ff0000) >> 16);
+ dev[0] = a ? a - 1 + '0' : 0;
+ dev[1] = b ? b - 1 + 'a' : 0;
+ dev[2] = 0;
+ disk = ide_dev[txn->device & 0xff]->disk;
+ for (i = 0; i < disk->numparts; i++)
+ if (!strcmp (disk_partition_name (disk, i), dev))
+ offset = disk_partition_start (disk, i);
+ txn->device &= 0xff;
+ }
+ res->status = ide_dev[txn->device]->read (txn->device / 2,
+ txn->device % 2, res + 1, txn->block + offset);
+ mh.size = res->status ? sizeof (blkres_t) : sizeof (blkres_t) +
+ 512;
+ break;
+ }
+
+ mh.dst = mh.src;
+ mh.src = port;
+ mh.data = res;
+ old_port_send (&mh);
+ }
+}
+
+int main (void)
+{
+ volatile int ready;
+
+ ready = 0;
+ thr_create (ide_main, (void *) &ready, "ide");
+ while (!ready) ;
+ return 0;
+}
+
diff --git a/srv/init/Makefile b/srv/init/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := init.c
+CRT0 := $(BLTHOME)lib/crtb.o
+BINARY := init.bin
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
diff --git a/srv/init/init.c b/srv/init/init.c
@@ -0,0 +1,225 @@
+/* $Id: //depot/blt/srv/init/init.c#11 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Since nothing is running yet, we divide the system startup into two
+ * phases: starting bootstrap servers and normal initialisation. The
+ * former requires lots of strange incantations to parse the boot image
+ * to find rc.boot and run everything it says to; basically we have to
+ * reimplement what execve and the vfs do for us. Once that stuff gets
+ * going, we can open rc using the vfs and proceed in a more normal
+ * fashion.
+ *
+ * As rc.boot contains fairly critical stuff, an error from something
+ * in there will probably result in a wedged system.
+ *
+ * Microkernels are fun.
+ *
+ * - sc
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <boot.h>
+#include <blt/syscall.h>
+
+static char *copyright = "\
+OpenBLT Release I (built " __DATE__ ", " __TIME__ ")
+ Copyright (c) 1998-1999 The OpenBLT Dev Team. All rights reserved.
+\n";
+
+void __libc_init_fdl (void), __libc_init_console (void),
+ __libc_init_vfs (void);
+
+int boot_get_num (boot_dir *dir, const char *name)
+{
+ int i;
+
+ for (i = 0; i < BOOTDIR_MAX_ENTRIES; i++)
+ if (!strcmp (dir->bd_entry[i].be_name, name))
+ return i;
+ return -1;
+}
+
+char *boot_get_data (boot_dir *dir, int num)
+{
+ return (char *) dir + dir->bd_entry[num].be_offset * 0x1000;
+}
+
+int main (void)
+{
+ int area, sarea;
+ char *c, *rcboot, *line, *boot_servers, **params;
+ int i, space, p_argc, boot, fd, len, total, prog, filenum;
+ void *ptr;
+ boot_dir *dir;
+
+
+ line = malloc (256);
+ boot_servers = malloc (256);
+
+ if (!(boot = area_clone (3, 0, (void **) &dir, 0)))
+ {
+ os_console ("no uberarea; giving up");
+ os_debug ();
+ for (;;) ; /* fatal */
+ return 0;
+ }
+ else if ((filenum = boot_get_num (dir, "rc.boot")) < 0)
+ {
+ os_console ("no /boot/rc.boot; do you know what you're doing?");
+ os_debug ();
+ }
+ else
+ {
+ *line = *boot_servers = len = total = 0;
+ rcboot = boot_get_data (dir, filenum);
+
+ while (total < dir->bd_entry[filenum].be_vsize)
+ {
+ line[len++] = *rcboot++;
+ total++;
+
+ if (line[len - 1] == '\n')
+ {
+ line[len-- - 1] = 0;
+ for (i = space = 0, p_argc = 2; i < len; i++)
+ if ((line[i] == ' ') && !space)
+ space = 1;
+ else if ((line[i] != ' ') && space)
+ {
+ p_argc++;
+ space = 0;
+ }
+ if ((*line != '#') && *line)
+ {
+ params = malloc (sizeof (char *) * p_argc);
+ c = line;
+ for (i = 0; i < p_argc - 1; i++)
+ {
+ for (len = 0; c[len] && (c[len] != ' '); len++) ;
+ params[i] = malloc (len + 1);
+ strlcpy (params[i], c, len + 1);
+ c += len + 1;
+ }
+ params[i] = NULL;
+ if (!strcmp (params[0], "exit"))
+ os_terminate (1);
+
+ prog = boot_get_num (dir, params[0]);
+ area = area_create (dir->bd_entry[prog].be_vsize, 0,
+ &ptr, 0);
+ memcpy (ptr, boot_get_data (dir, prog),
+ dir->bd_entry[prog].be_vsize);
+ sarea = area_create (0x1000, 0, &ptr, 0);
+ strlcat (boot_servers, " ", 256);
+ strlcat (boot_servers, params[0], 256);
+ thr_wait (thr_spawn (0x1074, 0x3ffffd, area, 0x1000,
+ sarea, 0x3ff000, params[0]));
+ }
+ len = 0;
+ }
+ }
+ }
+
+ /* say hello */
+ __libc_init_fdl ();
+ __libc_init_console ();
+ __libc_init_vfs ();
+ printf (copyright);
+ printf ("init: bootstrap servers started. [ %s ]\n", boot_servers + 1);
+
+ /* if we one day pass arguments to init, we will parse them here. */
+
+ /* do some more normal stuff */
+ printf ("init: beginning automatic boot.\n\n");
+ fd = open ("/boot/rc", O_RDONLY, 0);
+ if (fd < 0)
+ printf ("error opening /boot/rc\n");
+ else
+ {
+ *line = len = 0;
+ while (read (fd, line + len++, 1) > 0)
+ {
+ if (line[len - 1] == '\n')
+ {
+/*
+ line[len - 1] = 0;
+ if ((*line != '#') && *line)
+ {
+ // printf ("execing `%s'\n", line);
+ params = malloc (sizeof (char *) * 2);
+ params[0] = malloc (strlen (line) + 1);
+ strcpy (params[0], line);
+ params[1] = NULL;
+ thr_join (thr_detach (run2), 0);
+ }
+ len = 0;
+*/
+ line[len-- - 1] = 0;
+ for (i = space = 0, p_argc = 2; i < len; i++)
+ if ((line[i] == ' ') && !space)
+ space = 1;
+ else if ((line[i] != ' ') && space)
+ {
+ p_argc++;
+ space = 0;
+ }
+ if ((*line != '#') && *line)
+ {
+ params = malloc (sizeof (char *) * p_argc);
+ c = line;
+ for (i = 0; i < p_argc - 1; i++)
+ {
+ for (len = 0; c[len] && (c[len] != ' '); len++) ;
+ params[i] = malloc (len + 1);
+ strlcpy (params[i], c, len + 1);
+ c += len + 1;
+ }
+ params[i] = NULL;
+ if (!strcmp (params[0], "exit"))
+ os_terminate (1);
+
+ i = execve (params[0], params, NULL);
+ if(i>0) thr_wait(i);
+ else printf("cannot execute \"%s\"\n",params[0]);
+ }
+ len = 0;
+ }
+ }
+ close (fd);
+ }
+
+ printf ("init: nothing left to do\n");
+ return 0;
+}
+
diff --git a/srv/namer/Makefile b/srv/namer/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := namer.cpp
+BINARY := namer.bin
+CRT0 := $(BLTHOME)lib/crtb.o
+LIBS := -lblt -lc
+
+include $(BLTHOME)make.actions
diff --git a/srv/namer/namer.cpp b/srv/namer/namer.cpp
@@ -0,0 +1,97 @@
+/* Copyright 1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <blt/namer.h>
+#include <blt/Message.h>
+#include <blt/Connection.h>
+
+#include <blt/syscall.h>
+#include <string.h>
+#include <stdlib.h>
+
+using namespace BLT;
+
+typedef struct nentry nentry;
+
+struct nentry
+{
+ nentry *next;
+ int32 port;
+ char name[1];
+};
+
+static nentry *first = 0;
+
+static int32
+do_namer_find(const char *name)
+{
+ nentry *e;
+
+ if(!name) return -1;
+
+ for(e = first; e; e = e->next){
+ if(!strcmp(e->name,name)) return e->port;
+ }
+
+ return -1;
+}
+
+static int32
+do_namer_register(int32 port, const char *name)
+{
+ nentry *e;
+
+ if(!name) return -1;
+ if(port < 1) return -1;
+
+ for(e = first; e; e = e->next){
+ if(!strcmp(e->name,name)) return -1;
+ }
+
+ e = (nentry *) malloc(sizeof(nentry) + strlen(name));
+
+ if(!e) return -1;
+
+ e->port = port;
+ strcpy(e->name,name);
+ e->next = first;
+ first = e;
+
+ return 0;
+}
+
+int main(void)
+{
+ Connection *cnxn = Connection::CreateService("namer");
+ Message msg, reply;
+
+ do_namer_register(NAMER_PORT,"namer");
+
+ while(cnxn->Recv(&msg) == 0){
+ int32 op = -1;
+ int32 port = -1;
+ const char *name = 0;
+ int32 res = -1;
+
+ msg.GetInt32('code',&op);
+ msg.GetInt32('port',&port);
+ msg.GetString('name',&name);
+
+ switch(op){
+ case NAMER_FIND:
+ res = do_namer_find(name);
+ break;
+
+ case NAMER_REGISTER:
+ res = do_namer_register(port, name);
+ break;
+ }
+
+ reply.Empty();
+ reply.PutInt32('resp',res);
+ msg.Reply(&reply);
+ }
+
+ return 0;
+}
diff --git a/srv/ne2000/Makefile b/srv/ne2000/Makefile
@@ -0,0 +1,10 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := ne2k.c ne2000.c pciglue.cpp
+BINARY := ne2000.bin
+LIBS := -lposix -lblt -lc
+CFLAGS += -I../pci
+CXXFLAGS += -I../pci
+
+include $(BLTHOME)make.actions
diff --git a/srv/ne2000/err.h b/srv/ne2000/err.h
@@ -0,0 +1,138 @@
+/* $Id: //depot/blt/srv/ne2000/err.h#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __ERR
+#define __ERR
+
+/* NOTE If ret is negative then it is an error otherwise it returns a
+// success code. */
+
+/////
+// Error codes
+/////
+
+#define NUM_ERR 22
+#define NOERR 0
+#define ERR -1
+#define ERRNOMEM -2
+#define ERRRESOURCE -3
+#define ERRMEMCORRUPT -4
+#define ERRFORMAT -5
+#define ERRNOTFOUND -6
+#define ERRTYPE -7
+#define ERRTIMEOUT -8
+#define ERRNOTSUPPORTED -9
+#define ERROUTOFRANGE -10
+#define ERRPRIV -11
+#define ERRNOTREADY -12
+#define ERRNONEFREE -13
+#define ERRARG -14
+#define ERRINVALID -15
+#define ERRNOTOPEN -16
+#define ERRALREADYDONE -17
+#define ERRVER -18
+#define ERROVERFLOW -19
+#define ERRINUSE -20
+#define ERRTOOBIG -21
+
+/////
+// Success codes
+/////
+
+#define SFOUND 1
+#define SNOTFOUND 2
+#define SALT 3
+
+/////
+// Facility codes
+/////
+
+/* Bits 16-31 are reserved for the facility code. */
+#define OWNOS 0x70
+#define OWNNOMAD 0x70
+
+/////
+// Error Messages
+/////
+
+#define MAX_ERR_MSG 32
+static const char err_msg[NUM_ERR][MAX_ERR_MSG] = { "success",
+ "error",
+ "out of memory",
+ "resource allocation",
+ "memory corrupt!!!",
+ "format",
+ "not found",
+ "type",
+ "timeout",
+ "not supported",
+ "out of range",
+ "access denied",
+ "not ready",
+ "none free",
+ "bad argument",
+ "invalid",
+ "not open",
+ "already done",
+ "incorrect version",
+ "overflow",
+ "in use",
+ "too big" };
+
+/////
+// Return code object
+/////
+
+#ifdef __CPP_BINDING
+class ret {
+ private:
+ int val;
+ public:
+ ret() { val=ERR; }
+ ret(int src) { val=src; }
+// ret(const ret& src) { val=src; }
+ ret operator=(const ret& src) { return val=src.val; }
+ ret operator=(int src) { return val=src; }
+ int operator==(const ret& cmp) { return val==cmp.val; }
+ int operator!() { return val<0; }
+ // returns 1 if error, 0 if success
+ int operator<(int cmp) {
+ // TODO implement some severity check
+ return (val<cmp); }
+ int operator<(ret& cmp) { return (val<cmp.val); }
+ operator int() const { return val; } // cast
+// operator bool() { return (val<0); }
+ const char *disp() {
+ if(((val & 0x70) != 0x70) && ((val & 0x70) != 0x00))
+ return "Unknown facility";
+ return err_msg[-val]; }
+};
+#else
+typedef int ret;
+#endif /* __CPP_BINDING */
+
+#endif /* __ERR */
diff --git a/srv/ne2000/ne2000.c b/srv/ne2000/ne2000.c
@@ -0,0 +1,858 @@
+/* $Id: //depot/blt/srv/ne2000/ne2000.c#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/* This file contains a network driver core for the NE2000 card.
+// Use at your own risk! (C) Copyright 1997,
+// Douglas Armstrong site@xnet.com drarmstr@uiuc.edu 10/11/97
+// ...
+// derived from National Semiconductor datasheets and application notes
+// as well as the Linux driver by Donald Becker */
+
+/* History Log:
+10-25-97 Setup under CVS drarmstr
+10-27-97 Added alloc_buffer() and free_buffer() drarmstr
+12-08-97 Finished scatter gather drarmstr
+03-03-98 Minor bug / Output cleanup drarmstr
+03-04-98 snic->tx_buf[] packet_buf -> packet_buf* drarmstr
+03-04-98 added passback pointer to notify and snic drarmstr
+*/
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+#include <i386/io.h>
+#include "ne2000.h"
+#include "ne2k.h"
+#include "err.h"
+extern void kprintf(char *, ...); /* Make sure your OS has these...*/
+extern void idle();
+extern unsigned long ticks;
+ /* replace with a better timeout method, like wait() */
+
+#ifdef XXX
+static char *BLARGH = 0xB8000 + 160*23 + 152;
+#define t(a) { BLARGH[0] = #a[0]; }
+#define T(a) { BLARGH[2] = #a[0]; }
+#else
+#define t(a) {}
+#define T(a) {}
+#endif
+
+/* we may have to change inb and outb to inb_p and outb_p.
+// Note, none of this code is gauranteed to be reentrant.
+
+// Note, don't create two nics to the same card and then try to use both
+// of them. The results will be unpredictable.
+
+// This violates IO resource manegment if your OS handles that, but it
+// works for now. Make sure that the driver has privlige access to the
+// mapped I/O space and the IRQ.*/
+static unsigned int default_ports[] = { 0x300, 0x280, 0x320, 0x340, 0x360, 0 };
+
+/* internal procedure, don't call this directly.*/
+int nic_probe(int addr) {
+ uint regd;
+ uint state=inb(addr); /* save command state */
+
+ if(inb(addr==0xff)) return ERRNOTFOUND;
+
+ outb(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr);
+ regd=inb(addr + 0x0d);
+ outb(0xff, addr + 0x0d);
+ outb(NIC_DMA_DISABLE | NIC_PAGE0, addr);
+ inb(addr + FAE_TALLY); /* reading CNTR0 resets it.*/
+ if(inb(addr + FAE_TALLY)) { /* counter didn't clear so probe fails*/
+ outb(state,addr); /* restore command state*/
+ outb(regd,addr + 0x0d);
+ return ERRNOTFOUND; }
+
+ return addr; /* network card detected at io addr;*/
+}
+
+/* Detects for presence of NE2000 card. Will check given io addr that
+// is passed to it as well as the default_ports array. Returns ERRNOTFOUND
+// if no card is found, i/o address otherwise. This does conduct an ISA
+// probe, so it's not always a good idea to run it. If you already have
+// the information, then you can just use that with nic_init().*/
+int nic_detect(int given) {
+ int found; int f;
+ kprintf("NE2000: detecting card...");
+ if(given) if((found=nic_probe(given))!=ERRNOTFOUND) {
+ kprintf("found at given:0x%x\n",given);
+ return found; }
+
+ /* probe for PCI clones here.... or not...*/
+
+ for(f=0;default_ports[f]!='\0';f++) {
+ // perform resource manegment here
+ if((found=nic_probe(default_ports[f]))!=ERRNOTFOUND) {
+ kprintf("found at default:0x%x\n",default_ports[f]);
+ return found; }
+ }
+ kprintf("none found.\n");
+ return ERRNOTFOUND;
+}
+
+/* This initializes the NE2000 card. If it turns out the card is not
+// really a NE2000 after all then it will return ERRNOTFOUND, else NOERR
+// It also dumps the prom into buffer prom for the upper layers..
+// Pass it a nic with a null iobase and it will initialize the structure for
+// you, otherwise it will just reinitialize it. */
+int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual) {
+ uint f;
+ kprintf("NE2000: reseting NIC card...");
+ if(!nic->iobase) {
+ nic->iobase=addr;
+ nic_stat_clear(&nic->stat);
+ nic->pstart=0; nic->pstop=0; nic->wordlength=0;
+ nic->current_page=0;
+ nic->notify=NULL;
+ for(f=0;f<MAX_TX;f++) {
+ nic->tx_packet[f]= NULL;
+/* nic->tx_packet[f].count=0;
+ nic->tx_packet[f].buf=NULL;
+ nic->tx_packet[f].page=0; */
+ }
+ nic->last_tx=NULL;
+ nic->busy=0;
+ nic->sending=0;
+ } else {
+ if(!nic->iobase || nic->iobase!=addr) return ERR;
+ }
+
+
+ outb(inb(addr + NE_RESET), addr + NE_RESET); /* reset the NE2000*/
+ while(!(inb_p(addr+INTERRUPTSTATUS) & ISR_RST)) {
+ /* TODO insert timeout code here.*/
+ }
+ kprintf("done.\n");
+ outb_p(0xff,addr + INTERRUPTSTATUS); /* clear all pending ints*/
+
+ // Initialize registers
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* enter page 0*/
+ outb_p(DCR_DEFAULT, addr + DATACONFIGURATION);
+ outb_p(0x00, addr + REMOTEBYTECOUNT0);
+ outb_p(0x00, addr + REMOTEBYTECOUNT1);
+ outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/
+ outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/
+ outb_p(RCR_MON, RECEIVECONFIGURATION); /* enter monitor mode*/
+ outb_p(TCR_INTERNAL_LOOPBACK, TRANSMITCONFIGURATION); /* internal loopback*/
+
+ nic->wordlength=nic_dump_prom(nic,prom);
+ if(prom[14]!=0x57 || prom[15]!=0x57) {
+ kprintf("NE2000: PROM signature does not match NE2000 0x57.\n");
+ return ERRNOTFOUND;
+ }
+ kprintf("NE2000: PROM signature matches NE2000 0x57.\n");
+
+ /* if the wordlength for the NE2000 card is 2 bytes, then
+ // we have to setup the DP8390 chipset to be the same or
+ // else all hell will break loose.*/
+ if(nic->wordlength==2) {
+ outb_p(DCR_DEFAULT_WORD, addr + DATACONFIGURATION);
+ }
+ nic->pstart=(nic->wordlength==2) ? PSTARTW : PSTART;
+ nic->pstop=(nic->wordlength==2) ? PSTOPW : PSTOP;
+
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr);
+ outb_p(nic->pstart, addr + TRANSMITPAGE); /* setup local buffer*/
+ outb_p(nic->pstart + TXPAGES, addr + PAGESTART);
+ outb_p(nic->pstop - 1, addr + BOUNDARY);
+ outb_p(nic->pstop, addr + PAGESTOP);
+ outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/
+ outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/
+ nic->current_page=nic->pstart + TXPAGES;
+
+ /* put physical address in the registers */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); /* switch to page 1 */
+ if(manual) for(f=0;f<6;f++) outb_p(manual[f], addr + PHYSICAL + f);
+ else for(f=0;f<LEN_ADDR;f++) outb_p(prom[f], addr + PHYSICAL + f);
+ kprintf("NE2000: Physical Address- ");
+ kprintf("%X:%X:%X:%X:%X:%X\n",
+ inb(addr+PAR0),inb(addr+PAR1),inb(addr+PAR2),
+ inb(addr+PAR3),inb(addr+PAR4),inb(addr+PAR5));
+
+ /* setup multicast filter to accept all packets*/
+ for(f=0;f<8;f++) outb_p(0xFF, addr + MULTICAST + f);
+
+ outb_p(nic->pstart+TXPAGES, addr + CURRENT);
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* switch to page 0 */
+
+ return NOERR;
+}
+
+/* This registers the function that will be called when a new packet
+// comes in. */
+void nic_register_notify(snic *nic,
+ void (*newnotify)(void*,packet_data*), void *passback){
+ nic->kore= passback;
+ nic->notify= newnotify;
+}
+
+/* start the NIC so it can actually recieve or transmit packets */
+void nic_start(snic *nic, int promiscuous) {
+ int iobase;
+ kprintf("NE2000: Starting NIC.\n");
+ if(!nic || !nic->iobase) {
+ kprintf("NE2000: can't start a non-initialized card.\n");
+ return; }
+ iobase=nic->iobase;
+ outb(0xff, iobase + INTERRUPTSTATUS);
+ outb(IMR_DEFAULT, iobase + INTERRUPTMASK);
+ outb(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ outb(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION);
+ if(promiscuous)
+ outb(RCR_PRO | RCR_AM, iobase + RECEIVECONFIGURATION);
+ else
+ outb(RCR_DEFAULT, iobase + RECEIVECONFIGURATION);
+
+ /* The following is debugging code! */
+#ifdef SHIT
+ kprintf("NE2000: Trying to fire off an IRQ.\n");
+ outb_p(0x50,iobase+INTERRUPTMASK);
+ outb_p(0x00,iobase+REMOTEBYTECOUNT0);
+ outb_p(0x00,iobase+REMOTEBYTECOUNT1);
+ outb_p(NIC_REM_READ | NIC_START,iobase); /* this should fire off */
+ outb_p(IMR_DEFAULT,iobase+INTERRUPTMASK); /* an interrupt... */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ outb_p(0xff,iobase+INTERRUPTSTATUS);
+#endif
+ /* End debugging code */
+}
+
+/* stops the NIC */
+void nic_stop(snic *nic) {
+ unsigned char tmp_buffer[16];
+ if(!nic || !nic->iobase) return; /* make sure card was initialized */
+ nic_init(nic,nic->iobase,tmp_buffer,NULL);
+}
+
+void nic_isr(snic *nic) {
+ uint isr; /* Illinois Sreet Residence Hall */
+ uint overload;
+ if(!nic || !nic->iobase) return; /* make sure card was initialized */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase);
+ overload=MAX_LOAD+1;
+ while((isr=inb_p(nic->iobase+INTERRUPTSTATUS))) {
+ if((--overload)<=0) break;
+ if(isr & ISR_OVW) nic_overrun(nic);
+ else if(isr & (ISR_PRX | ISR_RXE)) nic_rx(nic);
+ if(isr & ISR_PTX) nic_tx(nic);
+ else if(isr & ISR_TXE) nic_tx_err(nic);
+ if(isr & ISR_CNT) nic_counters(nic);
+ if(isr & ISR_RDC) outb_p(ISR_RDC, nic->iobase+ INTERRUPTSTATUS);
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase);
+ }
+ if(isr) {
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase);
+ if(!overload) {
+ kprintf("NE2000: Too many requests in ISR. ISR:%X MaxLoad:%X\n",
+ isr, MAX_LOAD);
+ outb_p(ISR_ALL, nic->iobase + INTERRUPTSTATUS); // clear
+ } else {
+ kprintf("NE2000: Unhandeled interrupt, ISR:%X\n",isr);
+ outb_p(0xff, nic->iobase + INTERRUPTSTATUS);
+ // Ack it anyway
+ }
+ }
+}
+
+/* You should call this before you just read the stats directlly from the
+// snic struct. This procedure updates the counters */
+nic_stat nic_get_stats(snic *nic) {
+ nic->stat.errors.frame_alignment+=inb_p(nic->iobase + FAE_TALLY);
+ nic->stat.errors.crc+=inb_p(nic->iobase + CRC_TALLY);
+ nic->stat.errors.missed_packets+=inb_p(nic->iobase + MISS_PKT_TALLY);
+ return nic->stat;
+}
+
+void nic_stat_clear(nic_stat *that) {
+ that->rx_packets=0;
+ that->tx_buffered=0; that->tx_packets=0;
+ that->errors.frame_alignment=0; that->errors.crc=0;
+ that->errors.missed_packets=0; that->errors.rx=0;
+ that->errors.rx_size=0; that->errors.rx_dropped=0;
+ that->errors.rx_fifo=0; that->errors.rx_overruns=0;
+ that->errors.tx_collisions=0;
+}
+
+/* Since this could be called by more than one other device, it should
+// be properly protected for reentrancy. We should put in a proper
+// semaphore or something, look into this.
+// NOTE: It is your responsibility to clean up the packet_buffer when you
+// are done calling this. */
+/* TODO- Have it check how lonk a transmission is taking and attempt to
+ restart the card if it's too long. */
+int nic_send_packet(snic *nic, packet_buffer *buffer) {
+ uint timeout; uint f; int iobase;
+/* kprintf("nic_send_packet()\n"); */
+ if(!buffer) return ERRARG;
+ if(!buffer->count || !buffer->buf) return ERRARG;
+ if(!nic || !nic->iobase) return ERR;
+ iobase=nic->iobase;
+
+ t(A);
+
+ buffer->len=0;
+ for(f=0;f<buffer->count;f++) buffer->len+=buffer->buf[f].len;
+ if(buffer->len>MAX_LENGTH) return ERRTOOBIG;
+
+ t(B);
+
+ /* the following wait for anyother tasks that are calling
+ // nic_send_packet() right now. Note that this doesn't use
+ // an atomic semaphore, so something MAY leak through. */
+/* timeout=ticks+10; wait 10 ticks */
+ timeout=ticks+100;
+ while(nic->busy && ticks<=timeout) idle();
+ /* Replace this with a proper timeout thing that doesn't use the
+ // ticks method which will be diffrent on each OS. */
+ t(C);
+ if(nic->busy) {
+ kprintf("NE2000: ERROR: Card stalled, timeout.\n");
+ return ERRTIMEOUT;
+ }
+ nic->busy=1; /* mark as busy, replace with semaphore */
+
+ t(D);
+
+ outb_p(0x00, iobase + INTERRUPTMASK); /* mask ints for now */
+ t(E);
+
+ timeout=ticks+TIMEOUT_TX;
+ while(idle(), ticks<=timeout) for(f=0;f<MAX_TX;f++) {
+ if(!nic->tx_packet[f]) {
+ t(F);
+
+/* nic->tx_packet[f]=*buffer;*/
+ nic->tx_packet[f]=buffer;
+ nic->tx_packet[f]->page=nic->pstart + (f * MAX_PAGESPERPACKET);
+ /*output page */
+
+/* kprintf("NE2000: sending packet with count:%x on page:%X with buffer:%x\n",
+ buffer->count,buffer->page,buffer->buf); */
+ t(>);
+
+ nic_block_output(nic,nic->tx_packet[f]);
+
+ t(<);
+
+ if(!nic->sending) {
+ nic->send=f; nic->sending=1;
+ /* now let's actually trigger the transmitter */
+ t(I);
+
+ if(nic_send(nic,f)<0) {
+ nic->sending=0;
+ break; }
+
+ /* note, the nic_tx() interrupt will mark this
+ // tx_packet buffer as free again once it
+ // confirms that the packet was sent. */
+ }
+ t(J);
+
+ nic->stat.tx_buffered++;
+ outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */
+ nic->busy=0; /* V() */
+ t(K);
+
+ return NOERR;
+ }
+ }
+
+ t(L);
+
+ outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */
+ nic->busy=0; /* V() */
+ kprintf("NE2000: ERROR: Transmitter stalled, card timeout.\n");
+ if(f==MAX_TX) {
+ kprintf("NE2000: ERROR: There are no transmit buffers available. TX stalled.\n");
+ return ERRTIMEOUT;
+ }
+ return ERR;
+}
+
+/* dumps the prom into a 16 byte buffer and returns the wordlength of
+// the card.
+// You should be able to make this procedure a wrapper of nic_block_input(). */
+int nic_dump_prom(snic *nic, unsigned char *prom) {
+ uint f;
+ int iobase=nic->iobase;
+ char wordlength=2; /* default wordlength of 2 */
+ unsigned char dump[32];
+ outb_p(32, iobase + REMOTEBYTECOUNT0); /* read 32 bytes from DMA->IO */
+ outb_p(0x00, iobase + REMOTEBYTECOUNT1); /* this is for the PROM dump */
+ outb_p(0x00, iobase + REMOTESTARTADDRESS0); /* configure DMA for 0x0000 */
+ outb_p(0x00, iobase + REMOTESTARTADDRESS1);
+ outb_p(NIC_REM_READ | NIC_START, iobase);
+ for(f=0;f<32;f+=2) {
+ dump[f]=inb_p(iobase + NE_DATA);
+ dump[f+1]=inb_p(iobase + NE_DATA);
+ if(dump[f]!=dump[f+1]) wordlength=1;
+ }
+ /* if wordlength is 2 bytes, then collapse prom to 16 bytes */
+ for(f=0;f<LEN_PROM;f++) prom[f]=dump[f+((wordlength==2)?f:0)];
+/* kprintf("NE2000: prom dump - ");
+ for(f=0;f<LEN_PROM;f++) kprintf("%X",prom[f]);
+ kprintf("\n"); */
+
+ return wordlength;
+}
+
+void nic_overrun(snic *nic) {
+ uint tx_status; int iobase=nic->iobase;
+ long starttime; uint resend=0;
+ kprintf("NE2000: Receive packet ring overrun!\n");
+ if(!nic || !nic->iobase) return;
+ tx_status=inb_p(iobase) & NIC_TRANSMIT;
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, iobase);
+ nic->stat.errors.rx_overruns++;
+
+ starttime=ticks;
+kprintf("BEFORE\n");
+ while(ticks-starttime<=10/*ticks to wait*/) idle();
+ /* Arrgh! TODO: Replace this whole crappy code with a decent
+ // wait method. We need to wait at least 1.6ms as per National
+ // Semiconductor datasheets, but we should probablly wait a
+ // little more to be safe. */
+kprintf("AFTER\n");
+
+ outb_p(0x00, iobase + REMOTEBYTECOUNT0);
+ outb_p(0x00, iobase + REMOTEBYTECOUNT1);
+ if(tx_status) {
+ uint tx_completed=inb_p(iobase + INTERRUPTSTATUS) &
+ (ISR_PTX | ISR_TXE);
+ if(!tx_completed) resend=1;
+ }
+
+ outb_p(TCR_INTERNAL_LOOPBACK, iobase + TRANSMITCONFIGURATION);
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ nic_rx(nic); /* cleanup RX ring */
+ outb_p(ISR_OVW, iobase + INTERRUPTSTATUS); /* ACK INT */
+
+ outb_p(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION);
+ if(resend)
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START | NIC_TRANSMIT,
+ iobase);
+}
+
+/* This is the procedure that markst the transmit buffer as available again */
+void nic_tx(snic *nic) {
+ uint f; int iobase=nic->iobase;
+ uint status;
+/* kprintf("nic_tx()\n"); */
+ if(!nic || !nic->iobase) return;
+ status=inb(iobase + TRANSMITSTATUS);
+
+ if(!nic->tx_packet[nic->send]) {
+ kprintf("NE2000: ERROR: Invalid transmison packet buffer.\n");
+ return;
+ }
+ if(!nic->sending) kprintf("NE2000: ERROR: Invalid nic->sending value.\n");
+
+ free_buffer(nic->tx_packet[nic->send]);
+ nic->tx_packet[nic->send]= NULL;
+/* nic->tx_packet[nic->send].count=0; mark buffer as available */
+/* nic->tx_packet[nic->send].len=0;
+ nic->tx_packet[nic->send].page=0; */
+
+ for(f=0;f<MAX_TX;f++) {
+ if(nic->tx_packet[f]) {
+ kprintf("NE2000: DEBUG: transmitting secondary buffer:%X\n",f);
+ nic->stat.tx_buffered++;
+ nic->send=f; nic->sending=1;
+ nic_send(nic,f); /* send a back-to-back buffer */
+ break;
+ }
+ }
+ if(f==MAX_TX) nic->sending=0;
+
+ if(status & TSR_COL) nic->stat.errors.tx_collisions++;
+ if(status & TSR_PTX) nic->stat.tx_packets++;
+ else {
+ if(status & TSR_ABT) {
+ nic->stat.errors.tx_aborts++;
+ nic->stat.errors.tx_collisions+=16; }
+ if(status & TSR_CRS) nic->stat.errors.tx_carrier++;
+ if(status & TSR_FU) nic->stat.errors.tx_fifo++;
+ if(status & TSR_CDH) nic->stat.errors.tx_heartbeat++;
+ if(status & TSR_OWC) nic->stat.errors.tx_window++;
+ }
+
+ outb_p(ISR_PTX, iobase + INTERRUPTSTATUS); /* ack int */
+}
+
+void nic_tx_err(snic *nic) {
+ unsigned char tsr; int iobase=nic->iobase;
+ if(!nic || !nic->iobase) return;
+ tsr=inb_p(nic->iobase);
+ kprintf("NE2000: ERROR: TX error: ");
+ if(tsr & TSR_ABT) kprintf("Too many collisions.\n");
+ if(tsr & TSR_ND) kprintf("Not deffered.\n");
+ if(tsr & TSR_CRS) kprintf("Carrier lost.\n");
+ if(tsr & TSR_FU) kprintf("FIFO underrun.\n");
+ if(tsr & TSR_CDH) kprintf("Heart attack!\n");
+
+ outb_p(ISR_TXE, iobase + INTERRUPTSTATUS);
+ if(tsr & (TSR_ABT | TSR_FU)) {
+ kprintf("NE2000: DEBUG: Attempting to retransmit packet.\n");
+ nic_tx(nic);
+ }
+}
+
+void nic_rx(snic *nic) {
+ uint packets=0; uint frame; uint rx_page; uint rx_offset;
+ uint len; uint next_pkt; uint numpages;
+ int iobase=nic->iobase;
+ buffer_header header;
+ if(!nic || !nic->iobase) return;
+ while(packets<MAX_RX) {
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE1, iobase); /*curr is on page 1 */
+ rx_page=inb_p(iobase + CURRENT); /* get current page */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0, iobase);
+ frame=inb(iobase + BOUNDARY)+1;
+ /* we add one becuase boundary is a page behind
+ // as pre NS notes to help in overflow problems */
+ if(frame>=nic->pstop) frame=nic->pstart+TXPAGES;
+ /* circual buffer */
+
+ if(frame != nic->current_page) {
+ kprintf("NE2000: ERROR: mismatched read page pointers!\n");
+ kprintf("NE2000: NIC-Boundary:%x dev-current_page:%x\n",
+ frame, nic->current_page); }
+
+/* kprintf("Boundary-%x Current-%x\n",frame-1,rx_page); */
+ if(frame==rx_page) break; /* all frames read */
+
+ rx_offset=frame << 8; /* current ptr in bytes(not pages) */
+
+ nic_get_header(nic,frame,&header);
+ len=header.count - sizeof(buffer_header);
+ /* length of packet */
+ next_pkt=frame + 1 + ((len+4)>>8); /* next packet frame */
+
+ numpages=nic->pstop-(nic->pstart+TXPAGES);
+ if( (header.next!=next_pkt)
+ && (header.next!=next_pkt + 1)
+ && (header.next!=next_pkt - numpages)
+ && (header.next != next_pkt +1 - numpages)){
+ kprintf("NE2000: ERROR: Index mismatch. header.next:%X next_pkt:%X frame:%X\n",
+ header.next,next_pkt,frame);
+ nic->current_page=frame;
+ outb(nic->current_page-1, iobase + BOUNDARY);
+ nic->stat.errors.rx++;
+ continue;
+ }
+
+ if(len<60 || len>1518) {
+ kprintf("NE2000: invalid packet size:%d\n",len);
+ nic->stat.errors.rx_size++;
+ } else if((header.status & 0x0f) == RSR_PRX) {
+ /* We have a good packet, so let's recieve it! */
+
+ packet_data *newpacket=alloc_buffer_data(len);
+ if(!newpacket) {
+ kprintf("NE2000: ERROR: out of memory!\n");
+ nic->stat.errors.rx_dropped++;
+ nic_block_input(nic,NULL,len,rx_offset+
+ sizeof(buffer_header));
+ } else {
+ nic_block_input(nic,newpacket->ptr,newpacket->len,
+ rx_offset+sizeof(buffer_header));
+ /* read it */
+
+ if(nic->notify) nic->notify(nic->kore,newpacket);
+ else free_buffer_data(newpacket);
+ /* NOTE: you are responsible for deleting this buffer. */
+
+ nic->stat.rx_packets++;
+ }
+ } else {
+ kprintf("NE2000: ERROR: bad packet. header-> status:%X next:%X len:%x.\n",
+ header.status,header.next,header.count);
+ if(header.status & RSR_FO) nic->stat.errors.rx_fifo++;
+ }
+/* kprintf("frame:%x header.next:%x next_pkt:%x\n",
+ frame,header.next,next_pkt); */
+ next_pkt=header.next;
+
+ if(next_pkt >= nic->pstop) {
+ kprintf("NE2000: ERROR: next frame beyond local buffer! next:%x.\n",
+ next_pkt);
+ next_pkt=nic->pstart+TXPAGES;
+ }
+
+ nic->current_page=next_pkt;
+ outb_p(next_pkt-1, iobase + BOUNDARY);
+ }
+ outb_p(ISR_PRX | ISR_RXE, iobase + INTERRUPTSTATUS); /* ack int */
+}
+
+void nic_counters(snic *nic) {
+ nic->stat.errors.frame_alignment+=inb_p(nic->iobase+FAE_TALLY);
+ nic->stat.errors.crc+=inb_p(nic->iobase+CRC_TALLY);
+ nic->stat.errors.missed_packets+=inb_p(nic->iobase+MISS_PKT_TALLY);
+ /* reading the counters on the DC8390 clears them. */
+ outb_p(ISR_CNT, nic->iobase + INTERRUPTSTATUS); /* ackkowledge int */
+}
+
+/* You should be able to make this procedure a wrapper of nic_block_input */
+void nic_get_header(snic *nic, uint page, buffer_header *header) {
+ int iobase=nic->iobase; uint f;
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ outb_p(sizeof(buffer_header), iobase + REMOTEBYTECOUNT0);
+ outb_p(0, iobase + REMOTEBYTECOUNT1); /* read the header */
+ outb_p(0, iobase + REMOTESTARTADDRESS0); /* page boundary */
+ outb_p(page, iobase + REMOTESTARTADDRESS1); /* from this page */
+ outb_p(NIC_REM_READ | NIC_START, iobase); /* start reading */
+
+ if(nic->wordlength==2) for(f=0;f<(sizeof(buffer_header)>>1);f++)
+ ((unsigned short *)header)[f]=inw(iobase+NE_DATA);
+ else for(f=0;f<sizeof(buffer_header);f++)
+ ((unsigned char *)header)[f]=inb(iobase+NE_DATA);
+ /* Do these need to be *_p variants??? */
+ outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */
+}
+
+int nic_send(snic *nic, uint buf) {
+ uint len= (nic->tx_packet[buf]->len<MIN_LENGTH) ?
+ MIN_LENGTH : nic->tx_packet[buf]->len;
+/* kprintf("nic_send()\n"); */
+ if(!nic->tx_packet[buf]) return ERR; /* this is bad */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase);
+ if(inb_p(nic->iobase + STATUS) & NIC_TRANSMIT) {
+ kprintf("NE2000: ERROR: Transmitor busy.\n");
+ free_buffer(nic->tx_packet[buf]);
+ nic->tx_packet[buf]= NULL;
+/* nic->tx_packet[buf].count=0; mark as free again */
+ return ERRTIMEOUT; }
+ outb_p(len & 0xff,nic->iobase+TRANSMITBYTECOUNT0);
+ outb_p(len >> 8,nic->iobase+TRANSMITBYTECOUNT1);
+ outb_p(nic->tx_packet[buf]->page,nic->iobase+TRANSMITPAGE);
+ outb_p(NIC_DMA_DISABLE | NIC_TRANSMIT | NIC_START,nic->iobase);
+ return NOERR;
+}
+
+void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset) {
+ int iobase=nic->iobase; uint f;
+ uint xfers=len;
+ uint timeout=TIMEOUT_DMAMATCH; uint addr;
+/* kprintf("NE2000: RX: Length:%x Offset:%x ",len,offset); */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ outb_p(len & 0xff, iobase + REMOTEBYTECOUNT0);
+ outb_p(len >> 8, iobase + REMOTEBYTECOUNT1);
+ outb_p(offset & 0xff, iobase + REMOTESTARTADDRESS0);
+ outb_p(offset >> 8, iobase + REMOTESTARTADDRESS1);
+ outb_p(NIC_REM_READ | NIC_START, iobase);
+
+ /* allow for no buffer */
+ if(buf){
+ if(nic->wordlength==2) {
+ for(f=0;f<(len>>1);f++)
+ ((unsigned short *)buf)[f]=inw(iobase+NE_DATA);
+ if(len&0x01) {
+ ((unsigned char *)buf)[len-1]=inb(iobase+NE_DATA);
+ xfers++;
+ }
+ } else {
+ for(f=0;f<len;f++)
+ ((unsigned char *)buf)[f]=inb(iobase+NE_DATA);
+ }
+ } else {
+ if(nic->wordlength==2) {
+ for(f=0;f<(len>>1);f++)
+ inw(iobase+NE_DATA);
+ if(len&0x01) {
+ inb(iobase+NE_DATA);
+ xfers++;
+ }
+ } else {
+ for(f=0;f<len;f++)
+ inb(iobase+NE_DATA);
+ }
+ }
+ /* Do these need to be *_p variants??? */
+
+/* for(f=0;f<15;f++) kprintf("%X",buf[f]); kprintf("\n"); */
+ /* TODO: make this timeout a constant */
+ for(f=0;f<timeout;f++) {
+ uint high=inb_p(iobase + REMOTESTARTADDRESS1);
+ uint low=inb_p(iobase + REMOTESTARTADDRESS0);
+ addr=(high<<8)+low;
+ if(((offset+xfers)&0xff)==low) break;
+ }
+ /*
+ if(f>=timeout)
+ kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n",
+ offset+xfers, addr); HUH WHAT? BJS*/
+
+ outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */
+}
+
+/* Now supports scatter gather */
+void nic_block_output(snic *nic, packet_buffer *pkt) {
+ int iobase=nic->iobase;
+ int timeout=TIMEOUT_DMAMATCH; int f; uint addr; int tmplen;
+ int bufidx, buflen; /* current packet_data in packet_buffer */
+ void *bufptr;
+ char skip=0; /* Ask me about this if you have questions */
+ uint deleteme=0; /* delete when done debugging */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+
+ T(A);
+
+ for(f=0;f<pkt->count;f++) deleteme+=pkt->buf[f].len;
+ T(B);
+
+ if(pkt->len != deleteme) return;
+
+ if(pkt->len > MAX_LENGTH) return;
+ /* we should not have gotten this far... Paranoia check */
+
+ /* this next part is to supposedly fix a "read-before-write" bug... */
+ outb_p(0x42, iobase + REMOTEBYTECOUNT0);
+ outb_p(0x00, iobase + REMOTEBYTECOUNT1);
+ outb_p(0x42, iobase + REMOTESTARTADDRESS0);
+ outb_p(0x00, iobase + REMOTESTARTADDRESS1);
+ outb_p(NIC_REM_READ | NIC_START, iobase);
+ SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO;
+
+ outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* ack remote DMA int */
+ T(C);
+
+ tmplen=(pkt->len < MIN_LENGTH) ? MIN_LENGTH : pkt->len;
+ outb_p(tmplen & 0xff, iobase + REMOTEBYTECOUNT0);
+ outb_p(tmplen >> 8, iobase + REMOTEBYTECOUNT1);
+ outb_p(0x00, iobase + REMOTESTARTADDRESS0);
+ outb_p(pkt->page, iobase + REMOTESTARTADDRESS1);
+ outb_p(NIC_REM_WRITE | NIC_START, iobase);
+
+ T(D);
+
+ /* go through each buffer and transfer it's contents */
+ for(bufidx=pkt->count-1; bufidx >= 0; bufidx--) {
+ char odd;
+ buflen=pkt->buf[bufidx].len; /* only do derefrence once */
+ bufptr=pkt->buf[bufidx].ptr; /* for performance :) */
+
+ if(nic->wordlength==2) {
+
+ odd=(buflen & 0x01);
+ buflen>>=1; /* half the transfers */
+
+ if(skip) ((uint)bufptr)--; /* korewa baka desu */
+
+ for(f=skip;f<buflen;f++) { /* do we skip? */
+ outw(((unsigned short *)bufptr)[f],iobase+NE_DATA);
+ tmplen -= 2;
+ }
+
+ /* output 16-bits of the last odd byte */
+ skip=0; /* assume we don't skip */
+
+ if(odd) {
+ short tmp=((unsigned char *)bufptr)[buflen<<1];
+ /* get the byte from the next segment */
+ if((bufidx-1)>=0) {
+ tmp |= ((unsigned char *) pkt->buf[bufidx-1].ptr)[0] << 8;
+ }
+ outw(tmp,iobase + NE_DATA);
+ tmplen -= 2;
+ skip=1;
+ }
+ } else
+ for(f=0;f<buflen;f++) {
+ outb(((unsigned char *)bufptr)[f],iobase+NE_DATA);
+ tmplen--;
+ }
+ }
+ T(E);
+
+ /* If it's too short, pad with 0s */
+ if(tmplen > 0) {
+ T(F);
+/* kprintf("Padding runt\n"); */
+ if(nic->wordlength==2) {
+ for(f=0;f<tmplen/2;f++){
+ outw(0x00,iobase + NE_DATA);
+ tmplen -= 2;
+ }
+ }
+ }
+ if (tmplen > 0) {
+ for(f=0;f<tmplen;f++) {
+ outb(0x00,iobase + NE_DATA);
+ tmplen--;
+ }
+ }
+
+
+ T(G);
+#ifdef SHIT
+ if(nic->wordlength==2) {
+ for(w=0;w<(len>>1);w++)
+ outw(((unsigned short *)buf)[w],iobase+NE_DATA);
+ if(len & 0x01) {
+ short tmp=buf[len-1]; //so we can output a whole 16-bits
+ // if buf were on the end of something, we would die.
+ outw(tmp,iobase+NE_DATA);
+ }
+ } else for(f=0;f<len;f++)
+ outb(((unsigned char *)buf)[f],iobase+NE_DATA);
+
+#endif
+ for(f=0;f<timeout;f++) {
+ uint high=inb_p(iobase + REMOTESTARTADDRESS1);
+ uint low=inb_p(iobase + REMOTESTARTADDRESS0);
+ addr=(high<<8)+low;
+ if(( (((pkt->page<<8)+(nic->wordlength==2 && (pkt->len&0x01))?
+/* pkt->len+1:pkt->len+2))&0xff)==low)*/
+ pkt->len+0:pkt->len+1))&0xff)==low)
+ break;
+ if( (pkt->len < MIN_LENGTH) && ( (((pkt->page<<8)+MIN_LENGTH)
+ & 0xff) == low) )
+ break;
+ }
+ T(H);
+#ifdef SHIT
+ if(f>=timeout)
+ kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n",
+ ( (pkt->len >= MIN_LENGTH) ?
+ ((pkt->page<<8)+
+ (nic->wordlength==2&&(pkt->len&0x01))?
+ pkt->len+0:pkt->len+1)
+/* pkt->len+1:pkt->len+2)*/
+ : ((pkt->page<<8)+MIN_LENGTH) ),
+ addr);
+#endif
+/* TODO Check ISR_RDC */
+
+ T(I);
+
+ outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */
+}
diff --git a/srv/ne2000/ne2000.h b/srv/ne2000/ne2000.h
@@ -0,0 +1,187 @@
+/* $Id: //depot/blt/srv/ne2000/ne2000.h#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __NE2000_SHARED_CODE_BASE
+#define __NE2000_SHARED_CODE_BASE
+typedef unsigned int uint;
+typedef struct snic snic;
+typedef struct nic_stat nic_stat;
+typedef struct buffer_header buffer_header;
+typedef struct packet_data packet_data;
+typedef struct packet_buffer packet_buffer;
+typedef struct nic_error_stat nic_error_stat;
+
+/* internal implementation procedures */
+int nic_probe(int addr);
+int nic_dump_prom(snic *nic, unsigned char *prom);
+void nic_overrun(snic *nic);
+void nic_tx(snic *nic);
+void nic_tx_err(snic *nic);
+void nic_rx(snic *nic);
+void nic_counters(snic *nic);
+void nic_get_header(snic *nic, uint page, buffer_header *header);
+int nic_send(snic *nic, uint buf);
+void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset);
+void nic_block_output(snic *nic, packet_buffer *pkt);
+
+#define PSTART 0x20 /* if NE2000 is byte length */
+#define PSTOP 0x40
+#define PSTARTW 0x40 /* if NE2000 is wordlength */
+#define PSTOPW 0x80
+#define MAX_LOAD 12 /* maximum services per IRQ request*/
+#define MAX_RX 10 /* maximum packets recieve per call*/
+#define MIN_LENGTH 60 /* minimum length for packet data */
+#define MAX_LENGTH 1500 /* maximum length for packet data area */
+#define TIMEOUT_DMAMATCH 40 /* for nic_block_input() */
+#define TIMEOUT_TX 40
+
+/* DP8390 NIC Registers*/
+#define COMMAND 0x00
+#define STATUS COMMAND+0
+#define PHYSICAL COMMAND+1 /* page 1 */
+#define MULTICAST COMMAND+8 /* page 1 */
+#define PAGESTART COMMAND+1 /* page 0 */
+#define PAGESTOP COMMAND+2
+#define BOUNDARY COMMAND+3
+#define TRANSMITSTATUS COMMAND+4
+#define TRANSMITPAGE COMMAND+4
+#define TRANSMITBYTECOUNT0 COMMAND+5
+#define NCR COMMAND+5
+#define TRANSMITBYTECOUNT1 COMMAND+6
+#define INTERRUPTSTATUS COMMAND+7
+#define CURRENT COMMAND+7 /* page 1 */
+#define REMOTESTARTADDRESS0 COMMAND+8
+#define CRDMA0 COMMAND+8
+#define REMOTESTARTADDRESS1 COMMAND+9
+#define CRDMA1 COMMAND+9
+#define REMOTEBYTECOUNT0 COMMAND+10 /* how many bytes we will */
+#define REMOTEBYTECOUNT1 COMMAND+11 /* read through remote DMA->IO */
+#define RECEIVESTATUS COMMAND+12
+#define RECEIVECONFIGURATION COMMAND+12
+#define TRANSMITCONFIGURATION COMMAND+13
+#define FAE_TALLY COMMAND+13 /* page 0 */
+#define DATACONFIGURATION COMMAND+14
+#define CRC_TALLY COMMAND+14
+#define INTERRUPTMASK COMMAND+15
+#define MISS_PKT_TALLY COMMAND+15
+
+/* NE2000 specific implementation registers */
+#define NE_RESET 0x1f /* Reset */
+#define NE_DATA 0x10 /* Data port (use for PROM) */
+
+#define PAR0 COMMAND+1
+#define PAR1 COMMAND+2
+#define PAR2 COMMAND+3
+#define PAR3 COMMAND+4
+#define PAR4 COMMAND+5
+#define PAR5 COMMAND+6
+
+/* NIC Commands */
+#define NIC_STOP 0x01 /* STOP */
+#define NIC_START 0x02 /* START */
+#define NIC_PAGE0 0x00
+#define NIC_PAGE1 0x40
+#define NIC_PAGE2 0x80
+#define NIC_TRANSMIT 0x04 /* Transmit a frame */
+#define NIC_REM_READ 0x08 /* Remote Read */
+#define NIC_REM_WRITE 0x10 /* Remote Write */
+#define NIC_DMA_DISABLE 0x20 /* Disable DMA */
+
+/* Data Configuration Register */
+#define DCR_WTS 0x01 /* Word Transfer Select (0=byte, 1=word) */
+#define DCR_BOS 0x02 /* Byte Order Select (0=big-endian) */
+#define DCR_LAS 0x04 /* Long Address Select (0=dual 16-bit DMA) */
+#define DCR_LS 0x08 /* Loopback Select (0=loopback) */
+#define DCR_AR 0x10 /* Auto Initialize Remote */
+#define DCR_FT 0x60 /* (FT0 & FT1) FIFO Threshhold (see datasheet) */
+/*#define DCR_DEFAULT 0x58 Standard value for the DCR register */
+#define DCR_DEFAULT 0x48 /* don't use Automatic send packet */
+#define DCR_DEFAULT_WORD 0x49 /* defuault with wold length transfer */
+
+/* Recieve Configure Register */
+#define RCR_SEP 0x01 /* Save Errored Packets */
+#define RCR_AR 0x02 /* Accept Runt Packets */
+#define RCR_AB 0x04 /* Accept Broadcast */
+#define RCR_AM 0x08 /* Accept Multicast */
+#define RCR_PRO 0x10 /* Promiscuous Physical */
+#define RCR_MON 0x20 /* Monitor Mode */
+/*#define RCR_DEFAULT 0x00 Standard value for the RCR register */
+#define RCR_DEFAULT 0x0c /* Accept Broadcast/Multicast Packets */
+
+/* Recieve Status Register */
+/* note, this is also stored in the status byte in the buffer header. */
+/* That's the 4 byte entry in the local buffer, not the packet header. */
+#define RSR_PRX 0x01 /* Pakcet Received Intact */
+#define RSR_CRC 0x02 /* CRC Error */
+#define RSR_FAE 0x04 /* Frame Alignment Error */
+#define RSR_FO 0x08 /* FIFO Overrun */
+#define RSR_MPA 0x10 /* Missed Packet */
+#define RSR_PHY 0x20 /* Physical/Multicast Address (0=physical) */
+#define RSR_DIS 0x40 /* Receiver Disabled */
+#define RSR_DFR 0x80 /* Deferring */
+
+/* Transmit Configure Register */
+#define TCR_CRC 0x01 /* Inhibit CRC (0=CRC active) */
+#define TCR_LB 0x06 /* (LB0 & LB1) Encoded Loopback Control */
+#define TCR_ATD 0x08 /* Auto Transmit Disable (0=normal) */
+#define TCR_OFST 0x10 /* Collision Offset Enable (1=low priority) */
+#define TCR_DEFAULT 0x00 /* Standard value for the TCR register */
+#define TCR_INTERNAL_LOOPBACK 0x02 /* Internal loopback configuration */
+
+/* Transmit Status Register */
+#define TSR_PTX 0x01 /* Packet Transmitted */
+#define TSR_ND 0x02 /* Non-Deferral (Documented???) */
+#define TSR_COL 0x04 /* Transmit Collided */
+#define TSR_ABT 0x08 /* Transmit Aborted */
+#define TSR_CRS 0x10 /* Carrier Sense Lost */
+#define TSR_FU 0x20 /* FIFO Underrun */
+#define TSR_CDH 0x40 /* CD Heartbeat */
+#define TSR_OWC 0x80 /* Oout of Window Collision */
+
+/* Interrupt Status Register */
+#define ISR_PRX 0x01 /* Packet Received */
+#define ISR_PTX 0x02 /* Packet Transmitted */
+#define ISR_RXE 0x04 /* Receive Error */
+#define ISR_TXE 0x08 /* Transmit Error */
+#define ISR_OVW 0x10 /* Overwrite Warning */
+#define ISR_CNT 0x20 /* Counter Overflow */
+#define ISR_RDC 0x40 /* Remote DMA Complete */
+#define ISR_RST 0x80 /* Reset Status */
+#define ISR_DEFAULT 0x00 /* Standard value for the ISR register */
+#define ISR_ALL 0x3f /* The services that we handle in the isr */
+
+/* Interrupt Mask Register */
+#define IMR_PRXE 0x01 /* Packet Received Interrupt Enable */
+#define IMR_PTXE 0x02 /* Packet Transmitted Interrupt Enable */
+#define IMR_RXEE 0x04 /* Receive Error Interrupt Enable */
+#define IMR_TXEE 0x08 /* Transmit Error Interrupt Enable */
+#define IMR_OVWE 0x10 /* Overwrite Warning Interrupt Enable */
+#define IMR_CNTE 0x20 /* Counter Overflow Interrupt Enable */
+#define IMR_RDCE 0x40 /* DMA Complete Interrupt Enable */
+#define IMR_DEFAULT 0x3f /* CNTE | OVWE | TXEE | RXEE | PTXE | PRXE */
+
+#endif
diff --git a/srv/ne2000/ne2k.c b/srv/ne2000/ne2k.c
@@ -0,0 +1,609 @@
+/* Copyright 1999, Brian J. Swetland. All Rights Reserved.
+** This file is provided under the terms of the OpenBLT License
+*/
+
+#include "string.h"
+
+#include <blt/namer.h>
+#include <blt/syscall.h>
+#include <blt/conio.h>
+#include <blt/qsem.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "net.h"
+
+#define NULL ((void *) 0)
+
+#include "ne2k.h"
+
+int find_pci(uint16 vendor, uint16 device, int *iobase, int *irq);
+
+/* hard code these for now */
+#define NIC_IRQ 5
+#define NIC_ADDR 0x300
+
+static snic TheSNIC;
+int snic_irq = NIC_IRQ;
+int snic_addr = NIC_ADDR;
+
+
+static unsigned char prom[32];
+static unsigned char IP[4] = { 10, 113, 216, 6 }; /* we get our ip from the booter */
+
+/* messaging */
+static int port_isr = 0;
+static int port_xmit = 0;
+
+static qsem_t *sem_xmit_done = NULL;
+static int port_net = 0;
+
+qsem_t *mutex = NULL;
+qsem_t *sem_ring = NULL;
+
+#define LOG_LEVEL 9999
+
+/* to keep site's ne2000 code happy */
+void kprintf(char *fmt,...)
+{
+}
+
+#define trace(a, b) if (a >= LOG_LEVEL) printf("ne2000: %s\n", b);
+
+#define RINGSIZE 16
+#define PACKETSIZE 1536
+
+typedef struct _pbuf {
+ struct _pbuf *next; /* 4 */
+ packet_buffer pb; /* 16 */
+ packet_data pd; /* 8 */
+ int n;
+} pbuf;
+
+#define pb_to_ring(x) ((pbuf *) (((char *) (x)) - 4))
+#define pd_to_ring(x) ((pbuf *) (((char *) (x)) - 20))
+
+pbuf *p_next = NULL;
+
+typedef struct pmap pmap;
+
+struct pmap {
+ struct pmap *next;
+ int udp_port;
+ int blt_port;
+};
+
+pmap *pmaps = NULL;
+
+pbuf *p_discard;
+
+void init_ring(void)
+{
+ int i;
+ pbuf *p;
+ p_next = NULL;
+
+ for(i=0;i<RINGSIZE;i++){
+ p = (pbuf *) malloc(sizeof(pbuf));
+ p->next = p_next;
+ p_next = p;
+ p->pb.count = 1;
+ p->pb.buf = &(p->pd);
+ p->pd.ptr = (char *) malloc(PACKETSIZE);
+ p->n = i;
+ }
+
+ p_discard = p_next;
+ p_next = p_next->next;
+}
+
+
+/* called by the ne2k core to get a receive buffer */
+packet_data *alloc_buffer_data(uint size)
+{
+ pbuf *P;
+
+ qsem_acquire(sem_ring);
+ if(!p_next){
+ qsem_release(sem_ring);
+ printf("ne2000: !!! out of packet ringbuffers (recv)\n");
+ return NULL;
+ }
+ P = p_next;
+ p_next = P->next;
+ qsem_release(sem_ring);
+
+ P->pd.len = size;
+ return &(P->pd);
+}
+
+
+/* called by the us to sem_release a received buffer */
+void free_buffer_data(packet_data *pd)
+{
+ pbuf *P = pd_to_ring(pd);
+ qsem_acquire(sem_ring);
+ P->next = p_next;
+ p_next = P;
+ qsem_release(sem_ring);
+}
+
+
+/* called by our send data routines to get a send buffer */
+pbuf *get_pbuf(void)
+{
+ pbuf *P;
+ qsem_acquire(sem_ring);
+ if(!p_next){
+ qsem_release(sem_ring);
+ return p_discard;
+ }
+ P = p_next;
+ p_next = P->next;
+ qsem_release(sem_ring);
+ return P;
+}
+
+/* called after a pbuf is xmit'd */
+void free_buffer(packet_buffer *ptr)
+{
+ pbuf *P = pb_to_ring(ptr);
+
+ trace(1, "free_buffer");
+
+ if(P == p_discard) return;
+
+ qsem_acquire(sem_ring);
+ P->next = p_next;
+ p_next = P;
+ qsem_release(sem_ring);
+
+ qsem_release(sem_xmit_done);
+}
+
+int ticks = 0;
+void idle(void)
+{
+ int i;
+ for(i=0;i<1000;i++);
+ ticks++;
+}
+
+typedef struct
+{
+ net_ether ether;
+ net_arp arp;
+} arp_packet;
+
+void print_arp(unsigned char *p);
+
+
+void
+xmit(pbuf *P)
+{
+ int i;
+ msg_hdr_t mh;
+ /* printf("xmit: P->n = %d\n",P->n);*/
+
+ if(P == p_discard) return;
+
+ mh.flags = 0;
+ mh.src = port_isr;
+ mh.dst = port_xmit;
+ mh.size = 4;
+ mh.data = &P;
+ if((i = old_port_send(&mh)) != 4) printf("xmit: blargh! %d\n",i);
+
+}
+
+void handle_arp(arp_packet *req, pbuf *packet)
+{
+ if(htons(req->arp.arp_op) == ARP_OP_REQUEST){
+ if(!memcmp(&(req->arp.arp_ip_target),IP,4)){
+ pbuf *P;
+ arp_packet *resp;
+ P = get_pbuf();
+ resp = (arp_packet *) P->pd.ptr;
+
+/* printf("handle_arp: IS the one!\n");*/
+ memcpy(&(resp->ether.src),prom,6);
+ memcpy(&(resp->ether.dst),&(req->ether.src),6);
+ resp->ether.type = htons(0x0806);
+ resp->arp.arp_hard_type = htons(1);
+ resp->arp.arp_prot_type = htons(0x0800);
+ resp->arp.arp_hard_size = 6;
+ resp->arp.arp_prot_size = 4;
+ resp->arp.arp_op = htons(ARP_OP_REPLY);
+ memcpy(&(resp->arp.arp_enet_sender),prom,6);
+ memcpy(&(resp->arp.arp_ip_sender),IP,4);
+ memcpy(&(resp->arp.arp_enet_target),&(req->arp.arp_enet_sender),6);
+ memcpy(&(resp->arp.arp_ip_target),&(req->arp.arp_ip_sender),4);
+ print_arp((unsigned char *) &(resp->arp));
+
+ P->pd.len = sizeof(arp_packet);
+ P->pb.len = sizeof(arp_packet);
+
+ xmit(P);
+ } else {
+ /*printf("handle_arp: NOT the one.\n"); */
+ }
+ }
+}
+
+void print_arp(unsigned char *p)
+{
+ net_arp *arp = (net_arp *) p;
+ unsigned char *b;
+ unsigned short t;
+
+ printf(" ARP: ");
+ t = htons(arp->arp_op);
+ if(t == ARP_OP_REQUEST) printf("req ");
+ else if(t == ARP_OP_REPLY) printf("rep ");
+ else printf("??? ");
+
+ b = (unsigned char *) &(arp->arp_enet_sender);
+ printf("source: %X:%X:%X:%X:%X:%X ",b[0],b[1],b[2],b[3],b[4],b[5]);
+ b = (unsigned char *) &(arp->arp_ip_sender);
+ printf("(%d.%d.%d.%d)\n",b[0],b[1],b[2],b[3]);
+
+ printf(" ARP: target: ");
+
+ b = (unsigned char *) &(arp->arp_enet_target);
+ printf("%X:%X:%X:%X:%X:%X ",b[0],b[1],b[2],b[3],b[4],b[5]);
+ b = (unsigned char *) &(arp->arp_ip_target);
+ printf("(%d.%d.%d.%d)\n",b[0],b[1],b[2],b[3]);
+
+}
+
+void print_ip(unsigned char *p)
+{
+}
+
+int ipchksum(void *_ip, int len)
+{
+ register unsigned short *ip = (unsigned short *) _ip;
+ register unsigned long sum = 0;
+ len >>= 1;
+ while (len--) {
+ sum += *(ip++);
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ }
+ return((~sum) & 0x0000FFFF);
+}
+
+
+void
+handle_icmp(icmp_packet *icmp)
+{
+ pbuf *P;
+ icmp_packet *resp;
+
+ if(icmp->icmp.icmp_type == ICMP_PING_REQ){
+ P = get_pbuf();
+ resp = (icmp_packet *) P->pd.ptr;
+
+ memcpy(&(resp->ether.src),prom,6);
+ memcpy(&(resp->ether.dst),&(icmp->ether.src),6);
+ memcpy(&(resp->ether.type),&(icmp->ether.type),2);
+
+ resp->ip.ip_hdr_len = 5;
+ resp->ip.ip_version = 4;
+ resp->ip.ip_tos = 0;
+ resp->ip.ip_len = icmp->ip.ip_len;
+ resp->ip.ip_id = 0;
+ resp->ip.ip_off = 0;
+ resp->ip.ip_ttl = 64;
+ resp->ip.ip_proto = 0x01;
+ resp->ip.ip_chk = 0;
+ (int) resp->ip.ip_src = *(int *) IP;
+ resp->ip.ip_dst = icmp->ip.ip_src;
+ resp->ip.ip_chk = ipchksum(&(resp->ip),sizeof(net_ip));
+
+ resp->icmp.icmp_type = ICMP_PING_REP;
+ resp->icmp.icmp_code = 0;
+ resp->icmp.icmp_chk = 0;
+ resp->icmp.data.ping.id = icmp->icmp.data.ping.id;
+ resp->icmp.data.ping.seq = icmp->icmp.data.ping.seq;
+ memcpy(resp->icmp.data.ping.data,icmp->icmp.data.ping.data,
+ ntohs(icmp->ip.ip_len) - 28);
+
+ resp->icmp.icmp_chk = ipchksum(&(resp->ip),ntohs(resp->ip.ip_len));
+/* printf("ICMP resp l = %d\n",ntohs(resp->ip.ip_len));*/
+
+ P->pb.len = P->pd.len = ntohs(resp->ip.ip_len)+14;
+
+ xmit(P);
+ }
+}
+
+
+void
+handle_udp(udp_packet *udp, pbuf *packet)
+{
+ pmap *m;
+ msg_hdr_t msg;
+ int i;
+
+ for(m = pmaps; m; m = m->next){
+ if(m->udp_port == ntohs(udp->udp.udp_dst)){
+ msg.src = port_isr;
+ msg.dst = m->blt_port;
+ msg.flags = 0;
+ msg.size = ntohs(udp->udp.udp_len) - 8;
+ msg.data = udp->data;
+
+ if((i = old_port_send(&msg)) <0) {
+ /* XXX: if resource is gone, tear down this mapping */
+ /* printf("aieee %d / %d / %x\n",i,msg.size,msg.data); */
+ }
+ }
+ }
+
+
+/* printf("UDP %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\n",
+ src[0],src[1],src[2],src[3],ntohs(udp->udp.udp_src),
+ dst[0],dst[1],dst[2],dst[3],ntohs(udp->udp.udp_dst)
+ );*/
+}
+
+
+void
+handle_tcp(tcp_packet *tcp, pbuf *packet)
+{
+ trace(2, "handle_tcp");
+ /* full of worms */
+}
+
+
+void
+handle_ip(ip_packet *ip, pbuf *packet)
+{
+ unsigned char *dst = (unsigned char *) &(ip->ip.ip_dst);
+
+ trace(2, "handle_ip");
+
+ if(!memcmp(dst,IP,4) || (dst[3] == 0xFF)){ /*!memcmp(dst,bcip,4)){*/
+#ifdef DEBUG
+ printf("IP %d.%d.%d.%d -> %d.%d.%d.%d\n",
+ src[0],src[1],src[2],src[3],
+ dst[0],dst[1],dst[2],dst[3]
+ );
+#endif
+
+ switch(ip->ip.ip_proto){
+ case 0x01:
+ handle_icmp((icmp_packet *) ip);
+ break;
+ case 0x11:
+ handle_udp((udp_packet *) ip, packet);
+ break;
+ case 0x6:
+ handle_tcp((tcp_packet *) ip, packet);
+ break;
+ }
+ }
+}
+
+
+void
+receive(void *cb, packet_data *_packet)
+{
+ pbuf *packet = pd_to_ring(_packet);
+ unsigned char *b = (unsigned char *) packet->pd.ptr;
+
+trace(1, "receive");
+
+ if(b[12] == 0x08){
+ if(b[13] == 0x00) {
+ handle_ip((ip_packet *) b, packet);
+ } else if (b[13] == 0x06) {
+ handle_arp((arp_packet *) b, packet);
+ }
+ }
+ free_buffer_data(&(packet->pd));
+}
+
+#define NET_CONNECT 1
+#define NET_SEND 2
+#define NET_IP 3
+typedef struct
+{
+ int cmd;
+ int port;
+ char data[0];
+} net_cmd;
+
+
+unsigned char bcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+void send_udp(int src_port, int dst_port, unsigned char *ip, void *data, int size)
+{
+ pbuf *P;
+ udp_packet *udp;
+
+ P = get_pbuf();
+ udp = (udp_packet *) P->pd.ptr;
+
+ memcpy(&(udp->ether.src),prom,6);
+ memcpy(&(udp->ether.dst),bcast,6);
+ udp->ether.type = ntohs(0x0800);
+
+ udp->ip.ip_hdr_len = 5;
+ udp->ip.ip_version = 4;
+ udp->ip.ip_tos = 0;
+ udp->ip.ip_len = htons(20 + 8 + size);
+ udp->ip.ip_id = 0;
+ udp->ip.ip_off = 0;
+ udp->ip.ip_ttl = 64;
+ udp->ip.ip_proto = 17;
+ udp->ip.ip_chk = 0;
+ memcpy(&(udp->ip.ip_src),IP,4);
+ memcpy(&(udp->ip.ip_dst),bcast,4);
+ udp->ip.ip_chk = ipchksum(&(udp->ip),sizeof(net_ip));
+
+ udp->udp.udp_src = htons(src_port);
+ udp->udp.udp_dst = htons(dst_port);
+ udp->udp.udp_len = htons(size + 8);
+ udp->udp.udp_chk = 0;
+
+ memcpy(udp->data, data, size);
+
+/* printf("sending UDP to %d / %d\n",port,size);*/
+ P->pb.len = P->pd.len = 14 + 20 + 8 + size;
+
+ xmit(P);
+
+}
+
+void
+control(void)
+{
+ msg_hdr_t msg;
+ char cbuf[1500];
+ net_cmd *cmd = (net_cmd *) cbuf;
+ int size;
+
+ msg.flags=0;
+
+ for(;;){
+ msg.dst = port_net;
+ msg.src = 0;
+ msg.data = cbuf;
+ msg.size = 1500;
+ size = old_port_recv(&msg);
+
+ if(size >= 8){
+ switch(cmd->cmd){
+ case NET_IP:
+ memcpy(cbuf,IP,4);
+ msg.size = 4;
+ msg.data = cbuf;
+ msg.dst = msg.src;
+ msg.src = port_isr;
+ old_port_send(&msg);
+ break;
+
+ case NET_CONNECT: {
+ pmap *m = (pmap *) malloc(sizeof(pmap));
+ if(m) {
+ m->udp_port = cmd->port;
+ m->blt_port = msg.src;
+ m->next = pmaps;
+ pmaps = m;
+ printf("ne2000: routing udp:%d -> blt:%d\n",
+ cmd->port, msg.src);
+ }
+ break;
+ }
+ case NET_SEND: {
+ pmap *m;
+ for(m = pmaps; m; m = m->next){
+ if(msg.src == m->blt_port) {
+ send_udp(m->udp_port, cmd->port, NULL, cmd->data, size-8);
+ }
+ }
+ break;
+ }
+ }
+
+ }
+ }
+
+}
+
+void
+sender(void)
+{
+ msg_hdr_t mh;
+ pbuf *packet;
+
+ mh.flags = 0;
+ mh.src = port_isr;
+ mh.size = 4;
+ mh.data = &packet;
+
+ for(;;){
+ /* wait for a send request */
+ mh.dst = port_xmit;
+ if(old_port_recv(&mh) == 4){
+ trace(2, "sender: sending packet");
+ /* send the packet */
+ qsem_acquire(mutex);
+ nic_send_packet(&TheSNIC, &(packet->pb));
+ qsem_release(mutex);
+
+ qsem_acquire(sem_xmit_done);
+ }
+ }
+}
+
+void ISR(void)
+{
+ os_handle_irq(snic_irq);
+
+ for(;;){
+ os_sleep_irq();
+ qsem_acquire(mutex);
+ nic_isr(&TheSNIC);
+ qsem_release(mutex);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+
+ if(argc == 5){
+ for(i=0;i<4;i++){
+ IP[i] = atoi(argv[i+1]);
+ }
+ }
+
+ if(find_pci(0x10ec, 0x8029, &snic_addr, &snic_irq)){
+ printf("ne2000: found PCI device\n");
+ }
+
+ os_brk(RINGSIZE*PACKETSIZE*2);
+
+ sem_ring = qsem_create(1);
+ mutex = qsem_create(1);
+
+ /* create our send port */
+ port_isr = port_create(0,"net_send_port");
+ port_set_restrict(port_isr, port_isr);
+ port_option(port_isr, PORT_OPT_NOWAIT, 1);
+
+ namer_register(port_isr,"net_xmit");
+
+ init_ring();
+ TheSNIC.iobase = 0;
+ nic_init(&TheSNIC, snic_addr, prom, NULL);
+
+ printf("ne2000: irq %d @ 0x%S mac = %X:%X:%X:%X:%X:%X\n",
+ snic_irq,snic_addr,prom[0],prom[1],prom[2],prom[3],prom[4],prom[5]);
+
+ nic_register_notify(&TheSNIC,receive,NULL);
+ printf("ne2000: IP %d.%d.%d.%d\n",IP[0],IP[1],IP[2],IP[3]);
+
+ printf("ne2000: starting sender, dispatcher, and control\n");
+
+ namer_register(port_net = port_create(0,"net_listen_port"),"net");
+
+ port_xmit = port_create(port_isr,"net_isr_port");
+ sem_xmit_done = qsem_create(0);
+
+ os_thread(sender);
+ os_thread(control);
+
+ printf("ne2000: starting NIC\n");
+ nic_start(&TheSNIC,0);
+ printf("ne2000: \033[32mready.\033[37m\n");
+
+ os_thread(ISR);
+
+ return 0;
+}
diff --git a/srv/ne2000/ne2k.h b/srv/ne2000/ne2k.h
@@ -0,0 +1,116 @@
+/* $Id: //depot/blt/srv/ne2000/ne2k.h#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __NE2000_INTERFACE
+#define __NE2000_INTERFACE
+#ifndef __NE2000_SHARED_CODE_BASE
+typedef unsigned int uint;
+typedef struct snic snic;
+typedef struct nic_stat nic_stat;
+typedef struct buffer_header buffer_header;
+typedef struct packet_data packet_data;
+typedef struct packet_buffer packet_buffer;
+typedef struct nic_error_stat nic_error_stat;
+#endif /* NE2000_SHARED_CODE_BASE */
+
+#define LEN_ADDR 6
+#define MAX_TX 2 /* be careful with this (dual buffers) */
+#define MAX_PAGESPERPACKET 6
+#define TXPAGES (MAX_TX*MAX_PAGESPERPACKET)
+#define LEN_PROM 16
+#define LEN_HEADER 14
+#define MIN_LENGTH 60 /* minimum length for packet data */
+#define MAX_LENGTH 1500 /* maximum length for packet data area */
+
+#ifdef __CPP_BINDING
+extern "C" {
+#endif
+
+/* external interface */
+int nic_detect(int given);
+int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual);
+void nic_register_notify(snic *nic, void(*newnotify)(void*,packet_data*),void*);
+void nic_start(snic *nic, int promiscuous);
+void nic_stop(snic *nic);
+void nic_isr(snic *nic);
+nic_stat nic_get_stats(snic *nic);
+void nic_stat_clear(nic_stat *that);
+int nic_send_packet(snic *nic, packet_buffer *buffer);
+
+/* Your implementation */
+/*packet_buffer *alloc_buffer(uint count); */ /* Optional */
+packet_data *alloc_buffer_data(uint size);
+void free_buffer(packet_buffer *ptr);
+void cleanup_buffer(packet_buffer *ptr);
+void free_buffer_data(packet_data *ptr); /* Optional */
+/* I reserve the right to use the "Option" procedures in the future */
+
+#ifdef __CPP_BINDING
+};
+#endif
+
+struct buffer_header {
+ unsigned char status;
+ unsigned char next;
+ unsigned short count; /* length of header and packet */
+};
+
+struct nic_error_stat {
+ long frame_alignment, crc, missed_packets;
+ long rx, rx_size, rx_dropped, rx_fifo, rx_overruns;
+ long tx_collisions;
+ long tx_aborts, tx_carrier, tx_fifo, tx_heartbeat, tx_window;
+};
+
+struct nic_stat {
+ long rx_packets;
+ long tx_buffered, tx_packets;
+ nic_error_stat errors;
+};
+
+struct packet_buffer {
+ uint page;
+ uint count, len;
+ packet_data *buf; /* An array of data segments */
+};
+
+struct packet_data { /* each protocol layer can add it's own */
+ uint len;
+ char *ptr;
+};
+
+struct snic {
+ int iobase; /* NULL if uninitialized */
+ int pstart, pstop, wordlength, current_page;
+ nic_stat stat;
+ void (*notify)(void *passback, packet_data *newpacket);
+ void *kore; /* Passback pointer */
+ packet_buffer *tx_packet[MAX_TX], *last_tx;
+ int busy, send, sending;
+};
+
+#endif /* __NE2000_INTERFACE */
diff --git a/srv/ne2000/net.h b/srv/ne2000/net.h
@@ -0,0 +1,180 @@
+/* $Id: //depot/blt/srv/ne2000/net.h#4 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#pragma pack(2)
+
+typedef struct
+{
+ uint8 dst[6];
+ uint8 src[6];
+ uint16 type;
+} net_ether;
+
+typedef struct
+{
+ uint8 ip_hdr_len:4;
+ uint8 ip_version:4;
+ uint8 ip_tos;
+ uint16 ip_len;
+
+ uint16 ip_id;
+ uint16 ip_off;
+
+ uint8 ip_ttl;
+ uint8 ip_proto;
+ uint16 ip_chk;
+
+ uint32 ip_src;
+ uint32 ip_dst;
+} net_ip;
+
+typedef struct
+{
+ uint16 udp_src;
+ uint16 udp_dst;
+
+ uint16 udp_len;
+ uint16 udp_chk;
+} net_udp;
+
+typedef struct
+{
+ uint8 icmp_type;
+ uint8 icmp_code;
+ uint16 icmp_chk;
+ union {
+ struct {
+ uint16 id;
+ uint16 seq;
+ uint8 data[128];
+ } ping;
+ } data;
+} net_icmp;
+
+#define ICMP_PING_REQ 8
+#define ICMP_PING_REP 0
+
+typedef struct
+{
+ uint16 arp_hard_type;
+ uint16 arp_prot_type;
+ uint8 arp_hard_size;
+ uint8 arp_prot_size;
+ uint16 arp_op;
+ uint8 arp_enet_sender[6];
+ uint32 arp_ip_sender;
+ uint8 arp_enet_target[6];
+ uint32 arp_ip_target;
+} net_arp;
+
+typedef struct
+{
+ net_ether ether;
+ net_ip ip;
+ unsigned char data[0];
+} ip_packet;
+
+typedef struct {
+ net_ether ether;
+ net_ip ip;
+/* stub for now */
+} tcp_packet;
+
+typedef struct {
+ net_ether ether;
+ net_ip ip;
+ net_udp udp;
+ unsigned char data[0];
+} udp_packet;
+
+typedef struct {
+ net_ether ether;
+ net_ip ip;
+ net_icmp icmp;
+ unsigned char data[0];
+} icmp_packet;
+
+#define ARP_OP_REQUEST 1
+#define ARP_OP_REPLY 2
+
+/* yeah, ugly as shit */
+#define ntohs(n) ( (((n) & 0xFF00) >> 8) | (((n) & 0x00FF) << 8) )
+#define htons(n) ( (((n) & 0xFF00) >> 8) | (((n) & 0x00FF) << 8) )
+#define ntohl(n) ( (((n) & 0xFF000000) >> 24) | (((n) & 0x00FF0000) >> 8) | (((n) & 0x0000FF00) << 8) | (((n) & 0x000000FF) << 24) )
+#define htonl(n) ( (((n) & 0xFF000000) >> 24) | (((n) & 0x00FF0000) >> 8) | (((n) & 0x0000FF00) << 8) | (((n) & 0x000000FF) << 24) )
+
+/*
+typedef struct
+{
+ uint32 ip;
+ uint16 flags;
+ uint8 hw[6];
+} net_arp_table;
+
+typedef struct
+{
+ uint32 dest;
+ uint32 gw;
+ uint32 mask;
+ uint16 flags;
+ net_iface *iface;
+} net_route_table;
+
+
+typedef struct
+{
+ char name[8];
+ uint32 addr;
+ uint32 bcast;
+ uint32 mask;
+ uint16 flags;
+ uint16 mtu;
+ uint32 metric;
+
+ uint32 stat_rx_packets;
+ uint32 stat_rx_errors;
+ uint32 stat_rx_dropped;
+ uint32 stat_rx_overruns;
+
+ uint32 stat_tx_packets;
+ uint32 stat_tx_errors;
+ uint32 stat_tx_dropped;
+ uint32 stat_tx_overruns;
+
+ void (*send)(void);
+ void (*init)(void);
+ void (*add_proto)(net_proto *proto, uint16 id);
+
+} net_iface;
+
+#define IF_UP 0x0001
+#define IF_BROADCAST 0x0002
+#define IF_PROMISC 0x0004
+#define IF_LOOPBACK 0x0008
+#define IF_MULTICAST 0x0010
+#define IF_RUNNING 0x0020
+*/
diff --git a/srv/ne2000/pciglue.cpp b/srv/ne2000/pciglue.cpp
@@ -0,0 +1,35 @@
+#define PCI_STUB
+
+#include <pci.h>
+
+extern "C" {
+ int find_pci(uint16 vendor, uint16 device, int *iobase, int *irq);
+}
+
+using namespace BLT;
+
+int find_pci(uint16 vendor, uint16 device, int *iobase, int *irq)
+{
+ Message msg;
+ pci_cfg cfg;
+ int n;
+ int res = 0;
+
+ PCI *pci = PCI::FindService();
+
+ if(pci){
+ for(n=0;pci->get_nth_cfg(n,&cfg) == 0;n++){
+ if((cfg.device_id == device) &&
+ (cfg.vendor_id == vendor)){
+ *iobase = cfg.base[0] & 0xfff8;
+ *irq = cfg.irq;
+ res = 1;
+ break;
+ }
+ }
+ delete pci;
+ }
+
+ return res;
+}
+
diff --git a/srv/network/Makefile b/srv/network/Makefile
@@ -0,0 +1,10 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := network.c mbuf.c
+LIBS := -lc -lblt -ldl
+BINARY := network.bin
+SUBDIRS := device protocol
+
+include $(BLTHOME)/make.actions
+
diff --git a/srv/network/device/Makefile b/srv/network/device/Makefile
@@ -0,0 +1,6 @@
+BLTHOME := ../../../
+include $(BLTHOME)make.conf
+
+SUBDIRS := ne
+
+include $(BLTHOME)make.actions
diff --git a/srv/network/device/ne/Makefile b/srv/network/device/ne/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../../../
+include $(BLTHOME)make.conf
+
+CFLAGS = $(CF) -I../../../../include -D_NETWORK
+
+OBJS := wrap.o support.o ne2000.o
+SHLIB := ne.so
+
+include $(BLTHOME)make.actions
diff --git a/srv/network/device/ne/defs.h b/srv/network/device/ne/defs.h
@@ -0,0 +1,187 @@
+/* $Id: //depot/blt/srv/network/device/ne/defs.h#1 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __NE2000_SHARED_CODE_BASE
+#define __NE2000_SHARED_CODE_BASE
+typedef unsigned int uint;
+typedef struct snic snic;
+typedef struct nic_stat nic_stat;
+typedef struct buffer_header buffer_header;
+typedef struct packet_data packet_data;
+typedef struct packet_buffer packet_buffer;
+typedef struct nic_error_stat nic_error_stat;
+
+/* internal implementation procedures */
+int nic_probe(int addr);
+int nic_dump_prom(snic *nic, unsigned char *prom);
+void nic_overrun(snic *nic);
+void nic_tx(snic *nic);
+void nic_tx_err(snic *nic);
+void nic_rx(snic *nic);
+void nic_counters(snic *nic);
+void nic_get_header(snic *nic, uint page, buffer_header *header);
+int nic_send(snic *nic, uint buf);
+void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset);
+void nic_block_output(snic *nic, packet_buffer *pkt);
+
+#define PSTART 0x20 /* if NE2000 is byte length */
+#define PSTOP 0x40
+#define PSTARTW 0x40 /* if NE2000 is wordlength */
+#define PSTOPW 0x80
+#define MAX_LOAD 12 /* maximum services per IRQ request*/
+#define MAX_RX 10 /* maximum packets recieve per call*/
+#define MIN_LENGTH 60 /* minimum length for packet data */
+#define MAX_LENGTH 1500 /* maximum length for packet data area */
+#define TIMEOUT_DMAMATCH 40 /* for nic_block_input() */
+#define TIMEOUT_TX 40
+
+/* DP8390 NIC Registers*/
+#define COMMAND 0x00
+#define STATUS COMMAND+0
+#define PHYSICAL COMMAND+1 /* page 1 */
+#define MULTICAST COMMAND+8 /* page 1 */
+#define PAGESTART COMMAND+1 /* page 0 */
+#define PAGESTOP COMMAND+2
+#define BOUNDARY COMMAND+3
+#define TRANSMITSTATUS COMMAND+4
+#define TRANSMITPAGE COMMAND+4
+#define TRANSMITBYTECOUNT0 COMMAND+5
+#define NCR COMMAND+5
+#define TRANSMITBYTECOUNT1 COMMAND+6
+#define INTERRUPTSTATUS COMMAND+7
+#define CURRENT COMMAND+7 /* page 1 */
+#define REMOTESTARTADDRESS0 COMMAND+8
+#define CRDMA0 COMMAND+8
+#define REMOTESTARTADDRESS1 COMMAND+9
+#define CRDMA1 COMMAND+9
+#define REMOTEBYTECOUNT0 COMMAND+10 /* how many bytes we will */
+#define REMOTEBYTECOUNT1 COMMAND+11 /* read through remote DMA->IO */
+#define RECEIVESTATUS COMMAND+12
+#define RECEIVECONFIGURATION COMMAND+12
+#define TRANSMITCONFIGURATION COMMAND+13
+#define FAE_TALLY COMMAND+13 /* page 0 */
+#define DATACONFIGURATION COMMAND+14
+#define CRC_TALLY COMMAND+14
+#define INTERRUPTMASK COMMAND+15
+#define MISS_PKT_TALLY COMMAND+15
+
+/* NE2000 specific implementation registers */
+#define NE_RESET 0x1f /* Reset */
+#define NE_DATA 0x10 /* Data port (use for PROM) */
+
+#define PAR0 COMMAND+1
+#define PAR1 COMMAND+2
+#define PAR2 COMMAND+3
+#define PAR3 COMMAND+4
+#define PAR4 COMMAND+5
+#define PAR5 COMMAND+6
+
+/* NIC Commands */
+#define NIC_STOP 0x01 /* STOP */
+#define NIC_START 0x02 /* START */
+#define NIC_PAGE0 0x00
+#define NIC_PAGE1 0x40
+#define NIC_PAGE2 0x80
+#define NIC_TRANSMIT 0x04 /* Transmit a frame */
+#define NIC_REM_READ 0x08 /* Remote Read */
+#define NIC_REM_WRITE 0x10 /* Remote Write */
+#define NIC_DMA_DISABLE 0x20 /* Disable DMA */
+
+/* Data Configuration Register */
+#define DCR_WTS 0x01 /* Word Transfer Select (0=byte, 1=word) */
+#define DCR_BOS 0x02 /* Byte Order Select (0=big-endian) */
+#define DCR_LAS 0x04 /* Long Address Select (0=dual 16-bit DMA) */
+#define DCR_LS 0x08 /* Loopback Select (0=loopback) */
+#define DCR_AR 0x10 /* Auto Initialize Remote */
+#define DCR_FT 0x60 /* (FT0 & FT1) FIFO Threshhold (see datasheet) */
+/*#define DCR_DEFAULT 0x58 Standard value for the DCR register */
+#define DCR_DEFAULT 0x48 /* don't use Automatic send packet */
+#define DCR_DEFAULT_WORD 0x49 /* defuault with wold length transfer */
+
+/* Recieve Configure Register */
+#define RCR_SEP 0x01 /* Save Errored Packets */
+#define RCR_AR 0x02 /* Accept Runt Packets */
+#define RCR_AB 0x04 /* Accept Broadcast */
+#define RCR_AM 0x08 /* Accept Multicast */
+#define RCR_PRO 0x10 /* Promiscuous Physical */
+#define RCR_MON 0x20 /* Monitor Mode */
+/*#define RCR_DEFAULT 0x00 Standard value for the RCR register */
+#define RCR_DEFAULT 0x0c /* Accept Broadcast/Multicast Packets */
+
+/* Recieve Status Register */
+/* note, this is also stored in the status byte in the buffer header. */
+/* That's the 4 byte entry in the local buffer, not the packet header. */
+#define RSR_PRX 0x01 /* Pakcet Received Intact */
+#define RSR_CRC 0x02 /* CRC Error */
+#define RSR_FAE 0x04 /* Frame Alignment Error */
+#define RSR_FO 0x08 /* FIFO Overrun */
+#define RSR_MPA 0x10 /* Missed Packet */
+#define RSR_PHY 0x20 /* Physical/Multicast Address (0=physical) */
+#define RSR_DIS 0x40 /* Receiver Disabled */
+#define RSR_DFR 0x80 /* Deferring */
+
+/* Transmit Configure Register */
+#define TCR_CRC 0x01 /* Inhibit CRC (0=CRC active) */
+#define TCR_LB 0x06 /* (LB0 & LB1) Encoded Loopback Control */
+#define TCR_ATD 0x08 /* Auto Transmit Disable (0=normal) */
+#define TCR_OFST 0x10 /* Collision Offset Enable (1=low priority) */
+#define TCR_DEFAULT 0x00 /* Standard value for the TCR register */
+#define TCR_INTERNAL_LOOPBACK 0x02 /* Internal loopback configuration */
+
+/* Transmit Status Register */
+#define TSR_PTX 0x01 /* Packet Transmitted */
+#define TSR_ND 0x02 /* Non-Deferral (Documented???) */
+#define TSR_COL 0x04 /* Transmit Collided */
+#define TSR_ABT 0x08 /* Transmit Aborted */
+#define TSR_CRS 0x10 /* Carrier Sense Lost */
+#define TSR_FU 0x20 /* FIFO Underrun */
+#define TSR_CDH 0x40 /* CD Heartbeat */
+#define TSR_OWC 0x80 /* Oout of Window Collision */
+
+/* Interrupt Status Register */
+#define ISR_PRX 0x01 /* Packet Received */
+#define ISR_PTX 0x02 /* Packet Transmitted */
+#define ISR_RXE 0x04 /* Receive Error */
+#define ISR_TXE 0x08 /* Transmit Error */
+#define ISR_OVW 0x10 /* Overwrite Warning */
+#define ISR_CNT 0x20 /* Counter Overflow */
+#define ISR_RDC 0x40 /* Remote DMA Complete */
+#define ISR_RST 0x80 /* Reset Status */
+#define ISR_DEFAULT 0x00 /* Standard value for the ISR register */
+#define ISR_ALL 0x3f /* The services that we handle in the isr */
+
+/* Interrupt Mask Register */
+#define IMR_PRXE 0x01 /* Packet Received Interrupt Enable */
+#define IMR_PTXE 0x02 /* Packet Transmitted Interrupt Enable */
+#define IMR_RXEE 0x04 /* Receive Error Interrupt Enable */
+#define IMR_TXEE 0x08 /* Transmit Error Interrupt Enable */
+#define IMR_OVWE 0x10 /* Overwrite Warning Interrupt Enable */
+#define IMR_CNTE 0x20 /* Counter Overflow Interrupt Enable */
+#define IMR_RDCE 0x40 /* DMA Complete Interrupt Enable */
+#define IMR_DEFAULT 0x3f /* CNTE | OVWE | TXEE | RXEE | PTXE | PRXE */
+
+#endif
diff --git a/srv/network/device/ne/err.h b/srv/network/device/ne/err.h
@@ -0,0 +1,109 @@
+/* $Id: //depot/blt/srv/network/device/ne/err.h#1 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __ERR
+#define __ERR
+
+/* NOTE If ret is negative then it is an error otherwise it returns a
+// success code. */
+
+/////
+// Error codes
+/////
+
+#define NUM_ERR 22
+#define NOERR 0
+#define ERR -1
+#define ERRNOMEM -2
+#define ERRRESOURCE -3
+#define ERRMEMCORRUPT -4
+#define ERRFORMAT -5
+#define ERRNOTFOUND -6
+#define ERRTYPE -7
+#define ERRTIMEOUT -8
+#define ERRNOTSUPPORTED -9
+#define ERROUTOFRANGE -10
+#define ERRPRIV -11
+#define ERRNOTREADY -12
+#define ERRNONEFREE -13
+#define ERRARG -14
+#define ERRINVALID -15
+#define ERRNOTOPEN -16
+#define ERRALREADYDONE -17
+#define ERRVER -18
+#define ERROVERFLOW -19
+#define ERRINUSE -20
+#define ERRTOOBIG -21
+
+/////
+// Success codes
+/////
+
+#define SFOUND 1
+#define SNOTFOUND 2
+#define SALT 3
+
+/////
+// Facility codes
+/////
+
+/* Bits 16-31 are reserved for the facility code. */
+#define OWNOS 0x70
+#define OWNNOMAD 0x70
+
+/////
+// Error Messages
+/////
+
+#define MAX_ERR_MSG 32
+static const char err_msg[NUM_ERR][MAX_ERR_MSG] = { "success",
+ "error",
+ "out of memory",
+ "resource allocation",
+ "memory corrupt!!!",
+ "format",
+ "not found",
+ "type",
+ "timeout",
+ "not supported",
+ "out of range",
+ "access denied",
+ "not ready",
+ "none free",
+ "bad argument",
+ "invalid",
+ "not open",
+ "already done",
+ "incorrect version",
+ "overflow",
+ "in use",
+ "too big" };
+
+typedef int ret;
+
+#endif /* __ERR */
+
diff --git a/srv/network/device/ne/ne2000.c b/srv/network/device/ne/ne2000.c
@@ -0,0 +1,860 @@
+/* $Id: //depot/blt/srv/network/device/ne/ne2000.c#1 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/* This file contains a network driver core for the NE2000 card.
+// Use at your own risk! (C) Copyright 1997,
+// Douglas Armstrong site@xnet.com drarmstr@uiuc.edu 10/11/97
+// ...
+// derived from National Semiconductor datasheets and application notes
+// as well as the Linux driver by Donald Becker */
+
+/* History Log:
+10-25-97 Setup under CVS drarmstr
+10-27-97 Added alloc_buffer() and free_buffer() drarmstr
+12-08-97 Finished scatter gather drarmstr
+03-03-98 Minor bug / Output cleanup drarmstr
+03-04-98 snic->tx_buf[] packet_buf -> packet_buf* drarmstr
+03-04-98 added passback pointer to notify and snic drarmstr
+*/
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+#include <i386/io.h>
+#include "defs.h"
+#include "ne2000.h"
+#include "err.h"
+//extern void kprintf(char *, ...); /* Make sure your OS has these...*/
+#define kprintf(f, a...)
+//#define kprintf printf
+extern void idle();
+extern unsigned long ticks;
+ /* replace with a better timeout method, like wait() */
+
+#ifdef XXX
+static char *BLARGH = 0xB8000 + 160*23 + 152;
+#define t(a) { BLARGH[0] = #a[0]; }
+#define T(a) { BLARGH[2] = #a[0]; }
+#else
+#define t(a) {}
+#define T(a) {}
+#endif
+
+/* we may have to change inb and outb to inb_p and outb_p.
+// Note, none of this code is gauranteed to be reentrant.
+
+// Note, don't create two nics to the same card and then try to use both
+// of them. The results will be unpredictable.
+
+// This violates IO resource manegment if your OS handles that, but it
+// works for now. Make sure that the driver has privlige access to the
+// mapped I/O space and the IRQ.*/
+static unsigned int default_ports[] = { 0x300, 0x280, 0x320, 0x340, 0x360, 0 };
+
+/* internal procedure, don't call this directly.*/
+int nic_probe(int addr) {
+ uint regd;
+ uint state=inb(addr); /* save command state */
+
+ if(inb(addr==0xff)) return ERRNOTFOUND;
+
+ outb(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr);
+ regd=inb(addr + 0x0d);
+ outb(0xff, addr + 0x0d);
+ outb(NIC_DMA_DISABLE | NIC_PAGE0, addr);
+ inb(addr + FAE_TALLY); /* reading CNTR0 resets it.*/
+ if(inb(addr + FAE_TALLY)) { /* counter didn't clear so probe fails*/
+ outb(state,addr); /* restore command state*/
+ outb(regd,addr + 0x0d);
+ return ERRNOTFOUND; }
+
+ return addr; /* network card detected at io addr;*/
+}
+
+/* Detects for presence of NE2000 card. Will check given io addr that
+// is passed to it as well as the default_ports array. Returns ERRNOTFOUND
+// if no card is found, i/o address otherwise. This does conduct an ISA
+// probe, so it's not always a good idea to run it. If you already have
+// the information, then you can just use that with nic_init().*/
+int nic_detect(int given) {
+ int found; int f;
+ kprintf("NE2000: detecting card...");
+ if(given) if((found=nic_probe(given))!=ERRNOTFOUND) {
+ kprintf("found at given:0x%x\n",given);
+ return found; }
+
+ /* probe for PCI clones here.... or not...*/
+
+ for(f=0;default_ports[f]!='\0';f++) {
+ // perform resource manegment here
+ if((found=nic_probe(default_ports[f]))!=ERRNOTFOUND) {
+ kprintf("found at default:0x%x\n",default_ports[f]);
+ return found; }
+ }
+ kprintf("none found.\n");
+ return ERRNOTFOUND;
+}
+
+/* This initializes the NE2000 card. If it turns out the card is not
+// really a NE2000 after all then it will return ERRNOTFOUND, else NOERR
+// It also dumps the prom into buffer prom for the upper layers..
+// Pass it a nic with a null iobase and it will initialize the structure for
+// you, otherwise it will just reinitialize it. */
+int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual) {
+ uint f;
+ kprintf("NE2000: reseting NIC card...");
+ if(!nic->iobase) {
+ nic->iobase=addr;
+ nic_stat_clear(&nic->stat);
+ nic->pstart=0; nic->pstop=0; nic->wordlength=0;
+ nic->current_page=0;
+ nic->notify=NULL;
+ for(f=0;f<MAX_TX;f++) {
+ nic->tx_packet[f]= NULL;
+/* nic->tx_packet[f].count=0;
+ nic->tx_packet[f].buf=NULL;
+ nic->tx_packet[f].page=0; */
+ }
+ nic->last_tx=NULL;
+ nic->busy=0;
+ nic->sending=0;
+ } else {
+ if(!nic->iobase || nic->iobase!=addr) return ERR;
+ }
+
+
+ outb(inb(addr + NE_RESET), addr + NE_RESET); /* reset the NE2000*/
+ while(!(inb_p(addr+INTERRUPTSTATUS) & ISR_RST)) {
+ /* TODO insert timeout code here.*/
+ }
+ kprintf("done.\n");
+ outb_p(0xff,addr + INTERRUPTSTATUS); /* clear all pending ints*/
+
+ // Initialize registers
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* enter page 0*/
+ outb_p(DCR_DEFAULT, addr + DATACONFIGURATION);
+ outb_p(0x00, addr + REMOTEBYTECOUNT0);
+ outb_p(0x00, addr + REMOTEBYTECOUNT1);
+ outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/
+ outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/
+ outb_p(RCR_MON, RECEIVECONFIGURATION); /* enter monitor mode*/
+ outb_p(TCR_INTERNAL_LOOPBACK, TRANSMITCONFIGURATION); /* internal loopback*/
+
+ nic->wordlength=nic_dump_prom(nic,prom);
+ if(prom[14]!=0x57 || prom[15]!=0x57) {
+ kprintf("NE2000: PROM signature does not match NE2000 0x57.\n");
+ return ERRNOTFOUND;
+ }
+ kprintf("NE2000: PROM signature matches NE2000 0x57.\n");
+
+ /* if the wordlength for the NE2000 card is 2 bytes, then
+ // we have to setup the DP8390 chipset to be the same or
+ // else all hell will break loose.*/
+ if(nic->wordlength==2) {
+ outb_p(DCR_DEFAULT_WORD, addr + DATACONFIGURATION);
+ }
+ nic->pstart=(nic->wordlength==2) ? PSTARTW : PSTART;
+ nic->pstop=(nic->wordlength==2) ? PSTOPW : PSTOP;
+
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr);
+ outb_p(nic->pstart, addr + TRANSMITPAGE); /* setup local buffer*/
+ outb_p(nic->pstart + TXPAGES, addr + PAGESTART);
+ outb_p(nic->pstop - 1, addr + BOUNDARY);
+ outb_p(nic->pstop, addr + PAGESTOP);
+ outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/
+ outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/
+ nic->current_page=nic->pstart + TXPAGES;
+
+ /* put physical address in the registers */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); /* switch to page 1 */
+ if(manual) for(f=0;f<6;f++) outb_p(manual[f], addr + PHYSICAL + f);
+ else for(f=0;f<LEN_ADDR;f++) outb_p(prom[f], addr + PHYSICAL + f);
+ kprintf("NE2000: Physical Address- ");
+ kprintf("%X:%X:%X:%X:%X:%X\n",
+ inb(addr+PAR0),inb(addr+PAR1),inb(addr+PAR2),
+ inb(addr+PAR3),inb(addr+PAR4),inb(addr+PAR5));
+
+ /* setup multicast filter to accept all packets*/
+ for(f=0;f<8;f++) outb_p(0xFF, addr + MULTICAST + f);
+
+ outb_p(nic->pstart+TXPAGES, addr + CURRENT);
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* switch to page 0 */
+
+ return NOERR;
+}
+
+/* This registers the function that will be called when a new packet
+// comes in. */
+void nic_register_notify(snic *nic,
+ void (*newnotify)(void*,packet_data*), void *passback){
+ nic->kore= passback;
+ nic->notify= newnotify;
+}
+
+/* start the NIC so it can actually recieve or transmit packets */
+void nic_start(snic *nic, int promiscuous) {
+ int iobase;
+ kprintf("NE2000: Starting NIC.\n");
+ if(!nic || !nic->iobase) {
+ kprintf("NE2000: can't start a non-initialized card.\n");
+ return; }
+ iobase=nic->iobase;
+ outb(0xff, iobase + INTERRUPTSTATUS);
+ outb(IMR_DEFAULT, iobase + INTERRUPTMASK);
+ outb(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ outb(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION);
+ if(promiscuous)
+ outb(RCR_PRO | RCR_AM, iobase + RECEIVECONFIGURATION);
+ else
+ outb(RCR_DEFAULT, iobase + RECEIVECONFIGURATION);
+
+ /* The following is debugging code! */
+#ifdef SHIT
+ kprintf("NE2000: Trying to fire off an IRQ.\n");
+ outb_p(0x50,iobase+INTERRUPTMASK);
+ outb_p(0x00,iobase+REMOTEBYTECOUNT0);
+ outb_p(0x00,iobase+REMOTEBYTECOUNT1);
+ outb_p(NIC_REM_READ | NIC_START,iobase); /* this should fire off */
+ outb_p(IMR_DEFAULT,iobase+INTERRUPTMASK); /* an interrupt... */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ outb_p(0xff,iobase+INTERRUPTSTATUS);
+#endif
+ /* End debugging code */
+}
+
+/* stops the NIC */
+void nic_stop(snic *nic) {
+ unsigned char tmp_buffer[16];
+ if(!nic || !nic->iobase) return; /* make sure card was initialized */
+ nic_init(nic,nic->iobase,tmp_buffer,NULL);
+}
+
+void nic_isr(snic *nic) {
+ uint isr; /* Illinois Sreet Residence Hall */
+ uint overload;
+ if(!nic || !nic->iobase) return; /* make sure card was initialized */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase);
+ overload=MAX_LOAD+1;
+ while((isr=inb_p(nic->iobase+INTERRUPTSTATUS))) {
+ if((--overload)<=0) break;
+ if(isr & ISR_OVW) nic_overrun(nic);
+ else if(isr & (ISR_PRX | ISR_RXE)) nic_rx(nic);
+ if(isr & ISR_PTX) nic_tx(nic);
+ else if(isr & ISR_TXE) nic_tx_err(nic);
+ if(isr & ISR_CNT) nic_counters(nic);
+ if(isr & ISR_RDC) outb_p(ISR_RDC, nic->iobase+ INTERRUPTSTATUS);
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase);
+ }
+ if(isr) {
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase);
+ if(!overload) {
+ kprintf("NE2000: Too many requests in ISR. ISR:%X MaxLoad:%X\n",
+ isr, MAX_LOAD);
+ outb_p(ISR_ALL, nic->iobase + INTERRUPTSTATUS); // clear
+ } else {
+ kprintf("NE2000: Unhandeled interrupt, ISR:%X\n",isr);
+ outb_p(0xff, nic->iobase + INTERRUPTSTATUS);
+ // Ack it anyway
+ }
+ }
+}
+
+/* You should call this before you just read the stats directlly from the
+// snic struct. This procedure updates the counters */
+nic_stat nic_get_stats(snic *nic) {
+ nic->stat.errors.frame_alignment+=inb_p(nic->iobase + FAE_TALLY);
+ nic->stat.errors.crc+=inb_p(nic->iobase + CRC_TALLY);
+ nic->stat.errors.missed_packets+=inb_p(nic->iobase + MISS_PKT_TALLY);
+ return nic->stat;
+}
+
+void nic_stat_clear(nic_stat *that) {
+ that->rx_packets=0;
+ that->tx_buffered=0; that->tx_packets=0;
+ that->errors.frame_alignment=0; that->errors.crc=0;
+ that->errors.missed_packets=0; that->errors.rx=0;
+ that->errors.rx_size=0; that->errors.rx_dropped=0;
+ that->errors.rx_fifo=0; that->errors.rx_overruns=0;
+ that->errors.tx_collisions=0;
+}
+
+/* Since this could be called by more than one other device, it should
+// be properly protected for reentrancy. We should put in a proper
+// semaphore or something, look into this.
+// NOTE: It is your responsibility to clean up the packet_buffer when you
+// are done calling this. */
+/* TODO- Have it check how lonk a transmission is taking and attempt to
+ restart the card if it's too long. */
+int nic_send_packet(snic *nic, packet_buffer *buffer) {
+ uint timeout; uint f; int iobase;
+/* kprintf("nic_send_packet()\n"); */
+ if(!buffer) return ERRARG;
+ if(!buffer->count || !buffer->buf) return ERRARG;
+ if(!nic || !nic->iobase) return ERR;
+ iobase=nic->iobase;
+
+ t(A);
+
+ buffer->len=0;
+ for(f=0;f<buffer->count;f++) buffer->len+=buffer->buf[f].len;
+ if(buffer->len>MAX_LENGTH) return ERRTOOBIG;
+
+ t(B);
+
+ /* the following wait for anyother tasks that are calling
+ // nic_send_packet() right now. Note that this doesn't use
+ // an atomic semaphore, so something MAY leak through. */
+/* timeout=ticks+10; wait 10 ticks */
+ timeout=ticks+100;
+ while(nic->busy && ticks<=timeout) idle();
+ /* Replace this with a proper timeout thing that doesn't use the
+ // ticks method which will be diffrent on each OS. */
+ t(C);
+ if(nic->busy) {
+ kprintf("NE2000: ERROR: Card stalled, timeout.\n");
+ return ERRTIMEOUT;
+ }
+ nic->busy=1; /* mark as busy, replace with semaphore */
+
+ t(D);
+
+ outb_p(0x00, iobase + INTERRUPTMASK); /* mask ints for now */
+ t(E);
+
+ timeout=ticks+TIMEOUT_TX;
+ while(idle(), ticks<=timeout) for(f=0;f<MAX_TX;f++) {
+ if(!nic->tx_packet[f]) {
+ t(F);
+
+/* nic->tx_packet[f]=*buffer;*/
+ nic->tx_packet[f]=buffer;
+ nic->tx_packet[f]->page=nic->pstart + (f * MAX_PAGESPERPACKET);
+ /*output page */
+
+/* kprintf("NE2000: sending packet with count:%x on page:%X with buffer:%x\n",
+ buffer->count,buffer->page,buffer->buf); */
+ t(>);
+
+ nic_block_output(nic,nic->tx_packet[f]);
+
+ t(<);
+
+ if(!nic->sending) {
+ nic->send=f; nic->sending=1;
+ /* now let's actually trigger the transmitter */
+ t(I);
+
+ if(nic_send(nic,f)<0) {
+ nic->sending=0;
+ break; }
+
+ /* note, the nic_tx() interrupt will mark this
+ // tx_packet buffer as free again once it
+ // confirms that the packet was sent. */
+ }
+ t(J);
+
+ nic->stat.tx_buffered++;
+ outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */
+ nic->busy=0; /* V() */
+ t(K);
+
+ return NOERR;
+ }
+ }
+
+ t(L);
+
+ outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */
+ nic->busy=0; /* V() */
+ kprintf("NE2000: ERROR: Transmitter stalled, card timeout.\n");
+ if(f==MAX_TX) {
+ kprintf("NE2000: ERROR: There are no transmit buffers available. TX stalled.\n");
+ return ERRTIMEOUT;
+ }
+ return ERR;
+}
+
+/* dumps the prom into a 16 byte buffer and returns the wordlength of
+// the card.
+// You should be able to make this procedure a wrapper of nic_block_input(). */
+int nic_dump_prom(snic *nic, unsigned char *prom) {
+ uint f;
+ int iobase=nic->iobase;
+ char wordlength=2; /* default wordlength of 2 */
+ unsigned char dump[32];
+ outb_p(32, iobase + REMOTEBYTECOUNT0); /* read 32 bytes from DMA->IO */
+ outb_p(0x00, iobase + REMOTEBYTECOUNT1); /* this is for the PROM dump */
+ outb_p(0x00, iobase + REMOTESTARTADDRESS0); /* configure DMA for 0x0000 */
+ outb_p(0x00, iobase + REMOTESTARTADDRESS1);
+ outb_p(NIC_REM_READ | NIC_START, iobase);
+ for(f=0;f<32;f+=2) {
+ dump[f]=inb_p(iobase + NE_DATA);
+ dump[f+1]=inb_p(iobase + NE_DATA);
+ if(dump[f]!=dump[f+1]) wordlength=1;
+ }
+ /* if wordlength is 2 bytes, then collapse prom to 16 bytes */
+ for(f=0;f<LEN_PROM;f++) prom[f]=dump[f+((wordlength==2)?f:0)];
+/* kprintf("NE2000: prom dump - ");
+ for(f=0;f<LEN_PROM;f++) kprintf("%X",prom[f]);
+ kprintf("\n"); */
+
+ return wordlength;
+}
+
+void nic_overrun(snic *nic) {
+ uint tx_status; int iobase=nic->iobase;
+ long starttime; uint resend=0;
+ kprintf("NE2000: Receive packet ring overrun!\n");
+ if(!nic || !nic->iobase) return;
+ tx_status=inb_p(iobase) & NIC_TRANSMIT;
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, iobase);
+ nic->stat.errors.rx_overruns++;
+
+ starttime=ticks;
+kprintf("BEFORE\n");
+ while(ticks-starttime<=10/*ticks to wait*/) idle();
+ /* Arrgh! TODO: Replace this whole crappy code with a decent
+ // wait method. We need to wait at least 1.6ms as per National
+ // Semiconductor datasheets, but we should probablly wait a
+ // little more to be safe. */
+kprintf("AFTER\n");
+
+ outb_p(0x00, iobase + REMOTEBYTECOUNT0);
+ outb_p(0x00, iobase + REMOTEBYTECOUNT1);
+ if(tx_status) {
+ uint tx_completed=inb_p(iobase + INTERRUPTSTATUS) &
+ (ISR_PTX | ISR_TXE);
+ if(!tx_completed) resend=1;
+ }
+
+ outb_p(TCR_INTERNAL_LOOPBACK, iobase + TRANSMITCONFIGURATION);
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ nic_rx(nic); /* cleanup RX ring */
+ outb_p(ISR_OVW, iobase + INTERRUPTSTATUS); /* ACK INT */
+
+ outb_p(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION);
+ if(resend)
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START | NIC_TRANSMIT,
+ iobase);
+}
+
+/* This is the procedure that markst the transmit buffer as available again */
+void nic_tx(snic *nic) {
+ uint f; int iobase=nic->iobase;
+ uint status;
+/* kprintf("nic_tx()\n"); */
+ if(!nic || !nic->iobase) return;
+ status=inb(iobase + TRANSMITSTATUS);
+
+ if(!nic->tx_packet[nic->send]) {
+ kprintf("NE2000: ERROR: Invalid transmison packet buffer.\n");
+ return;
+ }
+ if(!nic->sending) kprintf("NE2000: ERROR: Invalid nic->sending value.\n");
+
+ free_buffer(nic->tx_packet[nic->send]);
+ nic->tx_packet[nic->send]= NULL;
+/* nic->tx_packet[nic->send].count=0; mark buffer as available */
+/* nic->tx_packet[nic->send].len=0;
+ nic->tx_packet[nic->send].page=0; */
+
+ for(f=0;f<MAX_TX;f++) {
+ if(nic->tx_packet[f]) {
+ kprintf("NE2000: DEBUG: transmitting secondary buffer:%X\n",f);
+ nic->stat.tx_buffered++;
+ nic->send=f; nic->sending=1;
+ nic_send(nic,f); /* send a back-to-back buffer */
+ break;
+ }
+ }
+ if(f==MAX_TX) nic->sending=0;
+
+ if(status & TSR_COL) nic->stat.errors.tx_collisions++;
+ if(status & TSR_PTX) nic->stat.tx_packets++;
+ else {
+ if(status & TSR_ABT) {
+ nic->stat.errors.tx_aborts++;
+ nic->stat.errors.tx_collisions+=16; }
+ if(status & TSR_CRS) nic->stat.errors.tx_carrier++;
+ if(status & TSR_FU) nic->stat.errors.tx_fifo++;
+ if(status & TSR_CDH) nic->stat.errors.tx_heartbeat++;
+ if(status & TSR_OWC) nic->stat.errors.tx_window++;
+ }
+
+ outb_p(ISR_PTX, iobase + INTERRUPTSTATUS); /* ack int */
+}
+
+void nic_tx_err(snic *nic) {
+ unsigned char tsr; int iobase=nic->iobase;
+ if(!nic || !nic->iobase) return;
+ tsr=inb_p(nic->iobase);
+ kprintf("NE2000: ERROR: TX error: ");
+ if(tsr & TSR_ABT) kprintf("Too many collisions.\n");
+ if(tsr & TSR_ND) kprintf("Not deffered.\n");
+ if(tsr & TSR_CRS) kprintf("Carrier lost.\n");
+ if(tsr & TSR_FU) kprintf("FIFO underrun.\n");
+ if(tsr & TSR_CDH) kprintf("Heart attack!\n");
+
+ outb_p(ISR_TXE, iobase + INTERRUPTSTATUS);
+ if(tsr & (TSR_ABT | TSR_FU)) {
+ kprintf("NE2000: DEBUG: Attempting to retransmit packet.\n");
+ nic_tx(nic);
+ }
+}
+
+void nic_rx(snic *nic) {
+ uint packets=0; uint frame; uint rx_page; uint rx_offset;
+ uint len; uint next_pkt; uint numpages;
+ int iobase=nic->iobase;
+ buffer_header header;
+ if(!nic || !nic->iobase) return;
+ while(packets<MAX_RX) {
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE1, iobase); /*curr is on page 1 */
+ rx_page=inb_p(iobase + CURRENT); /* get current page */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0, iobase);
+ frame=inb(iobase + BOUNDARY)+1;
+ /* we add one becuase boundary is a page behind
+ // as pre NS notes to help in overflow problems */
+ if(frame>=nic->pstop) frame=nic->pstart+TXPAGES;
+ /* circual buffer */
+
+ if(frame != nic->current_page) {
+ kprintf("NE2000: ERROR: mismatched read page pointers!\n");
+ kprintf("NE2000: NIC-Boundary:%x dev-current_page:%x\n",
+ frame, nic->current_page); }
+
+/* kprintf("Boundary-%x Current-%x\n",frame-1,rx_page); */
+ if(frame==rx_page) break; /* all frames read */
+
+ rx_offset=frame << 8; /* current ptr in bytes(not pages) */
+
+ nic_get_header(nic,frame,&header);
+ len=header.count - sizeof(buffer_header);
+ /* length of packet */
+ next_pkt=frame + 1 + ((len+4)>>8); /* next packet frame */
+
+ numpages=nic->pstop-(nic->pstart+TXPAGES);
+ if( (header.next!=next_pkt)
+ && (header.next!=next_pkt + 1)
+ && (header.next!=next_pkt - numpages)
+ && (header.next != next_pkt +1 - numpages)){
+ kprintf("NE2000: ERROR: Index mismatch. header.next:%X next_pkt:%X frame:%X\n",
+ header.next,next_pkt,frame);
+ nic->current_page=frame;
+ outb(nic->current_page-1, iobase + BOUNDARY);
+ nic->stat.errors.rx++;
+ continue;
+ }
+
+ if(len<60 || len>1518) {
+ kprintf("NE2000: invalid packet size:%d\n",len);
+ nic->stat.errors.rx_size++;
+ } else if((header.status & 0x0f) == RSR_PRX) {
+ /* We have a good packet, so let's recieve it! */
+
+ packet_data *newpacket=alloc_buffer_data(len);
+ if(!newpacket) {
+ kprintf("NE2000: ERROR: out of memory!\n");
+ nic->stat.errors.rx_dropped++;
+ nic_block_input(nic,NULL,len,rx_offset+
+ sizeof(buffer_header));
+ } else {
+ nic_block_input(nic,newpacket->ptr,newpacket->len,
+ rx_offset+sizeof(buffer_header));
+ /* read it */
+
+ if(nic->notify) nic->notify(nic->kore,newpacket);
+ else free_buffer_data(newpacket);
+ /* NOTE: you are responsible for deleting this buffer. */
+
+ nic->stat.rx_packets++;
+ }
+ } else {
+ kprintf("NE2000: ERROR: bad packet. header-> status:%X next:%X len:%x.\n",
+ header.status,header.next,header.count);
+ if(header.status & RSR_FO) nic->stat.errors.rx_fifo++;
+ }
+/* kprintf("frame:%x header.next:%x next_pkt:%x\n",
+ frame,header.next,next_pkt); */
+ next_pkt=header.next;
+
+ if(next_pkt >= nic->pstop) {
+ kprintf("NE2000: ERROR: next frame beyond local buffer! next:%x.\n",
+ next_pkt);
+ next_pkt=nic->pstart+TXPAGES;
+ }
+
+ nic->current_page=next_pkt;
+ outb_p(next_pkt-1, iobase + BOUNDARY);
+ }
+ outb_p(ISR_PRX | ISR_RXE, iobase + INTERRUPTSTATUS); /* ack int */
+}
+
+void nic_counters(snic *nic) {
+ nic->stat.errors.frame_alignment+=inb_p(nic->iobase+FAE_TALLY);
+ nic->stat.errors.crc+=inb_p(nic->iobase+CRC_TALLY);
+ nic->stat.errors.missed_packets+=inb_p(nic->iobase+MISS_PKT_TALLY);
+ /* reading the counters on the DC8390 clears them. */
+ outb_p(ISR_CNT, nic->iobase + INTERRUPTSTATUS); /* ackkowledge int */
+}
+
+/* You should be able to make this procedure a wrapper of nic_block_input */
+void nic_get_header(snic *nic, uint page, buffer_header *header) {
+ int iobase=nic->iobase; uint f;
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ outb_p(sizeof(buffer_header), iobase + REMOTEBYTECOUNT0);
+ outb_p(0, iobase + REMOTEBYTECOUNT1); /* read the header */
+ outb_p(0, iobase + REMOTESTARTADDRESS0); /* page boundary */
+ outb_p(page, iobase + REMOTESTARTADDRESS1); /* from this page */
+ outb_p(NIC_REM_READ | NIC_START, iobase); /* start reading */
+
+ if(nic->wordlength==2) for(f=0;f<(sizeof(buffer_header)>>1);f++)
+ ((unsigned short *)header)[f]=inw(iobase+NE_DATA);
+ else for(f=0;f<sizeof(buffer_header);f++)
+ ((unsigned char *)header)[f]=inb(iobase+NE_DATA);
+ /* Do these need to be *_p variants??? */
+ outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */
+}
+
+int nic_send(snic *nic, uint buf) {
+ uint len= (nic->tx_packet[buf]->len<MIN_LENGTH) ?
+ MIN_LENGTH : nic->tx_packet[buf]->len;
+/* kprintf("nic_send()\n"); */
+ if(!nic->tx_packet[buf]) return ERR; /* this is bad */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase);
+ if(inb_p(nic->iobase + STATUS) & NIC_TRANSMIT) {
+ kprintf("NE2000: ERROR: Transmitor busy.\n");
+ free_buffer(nic->tx_packet[buf]);
+ nic->tx_packet[buf]= NULL;
+/* nic->tx_packet[buf].count=0; mark as free again */
+ return ERRTIMEOUT; }
+ outb_p(len & 0xff,nic->iobase+TRANSMITBYTECOUNT0);
+ outb_p(len >> 8,nic->iobase+TRANSMITBYTECOUNT1);
+ outb_p(nic->tx_packet[buf]->page,nic->iobase+TRANSMITPAGE);
+ outb_p(NIC_DMA_DISABLE | NIC_TRANSMIT | NIC_START,nic->iobase);
+ return NOERR;
+}
+
+void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset) {
+ int iobase=nic->iobase; uint f;
+ uint xfers=len;
+ uint timeout=TIMEOUT_DMAMATCH; uint addr;
+/* kprintf("NE2000: RX: Length:%x Offset:%x ",len,offset); */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+ outb_p(len & 0xff, iobase + REMOTEBYTECOUNT0);
+ outb_p(len >> 8, iobase + REMOTEBYTECOUNT1);
+ outb_p(offset & 0xff, iobase + REMOTESTARTADDRESS0);
+ outb_p(offset >> 8, iobase + REMOTESTARTADDRESS1);
+ outb_p(NIC_REM_READ | NIC_START, iobase);
+
+ /* allow for no buffer */
+ if(buf){
+ if(nic->wordlength==2) {
+ for(f=0;f<(len>>1);f++)
+ ((unsigned short *)buf)[f]=inw(iobase+NE_DATA);
+ if(len&0x01) {
+ ((unsigned char *)buf)[len-1]=inb(iobase+NE_DATA);
+ xfers++;
+ }
+ } else {
+ for(f=0;f<len;f++)
+ ((unsigned char *)buf)[f]=inb(iobase+NE_DATA);
+ }
+ } else {
+ if(nic->wordlength==2) {
+ for(f=0;f<(len>>1);f++)
+ inw(iobase+NE_DATA);
+ if(len&0x01) {
+ inb(iobase+NE_DATA);
+ xfers++;
+ }
+ } else {
+ for(f=0;f<len;f++)
+ inb(iobase+NE_DATA);
+ }
+ }
+ /* Do these need to be *_p variants??? */
+
+/* for(f=0;f<15;f++) kprintf("%X",buf[f]); kprintf("\n"); */
+ /* TODO: make this timeout a constant */
+ for(f=0;f<timeout;f++) {
+ uint high=inb_p(iobase + REMOTESTARTADDRESS1);
+ uint low=inb_p(iobase + REMOTESTARTADDRESS0);
+ addr=(high<<8)+low;
+ if(((offset+xfers)&0xff)==low) break;
+ }
+ /*
+ if(f>=timeout)
+ kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n",
+ offset+xfers, addr); HUH WHAT? BJS*/
+
+ outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */
+}
+
+/* Now supports scatter gather */
+void nic_block_output(snic *nic, packet_buffer *pkt) {
+ int iobase=nic->iobase;
+ int timeout=TIMEOUT_DMAMATCH; int f; uint addr; int tmplen;
+ int bufidx, buflen; /* current packet_data in packet_buffer */
+ void *bufptr;
+ char skip=0; /* Ask me about this if you have questions */
+ uint deleteme=0; /* delete when done debugging */
+ outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
+
+ T(A);
+
+ for(f=0;f<pkt->count;f++) deleteme+=pkt->buf[f].len;
+ T(B);
+
+ if(pkt->len != deleteme) return;
+
+ if(pkt->len > MAX_LENGTH) return;
+ /* we should not have gotten this far... Paranoia check */
+
+ /* this next part is to supposedly fix a "read-before-write" bug... */
+ outb_p(0x42, iobase + REMOTEBYTECOUNT0);
+ outb_p(0x00, iobase + REMOTEBYTECOUNT1);
+ outb_p(0x42, iobase + REMOTESTARTADDRESS0);
+ outb_p(0x00, iobase + REMOTESTARTADDRESS1);
+ outb_p(NIC_REM_READ | NIC_START, iobase);
+ SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO;
+
+ outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* ack remote DMA int */
+ T(C);
+
+ tmplen=(pkt->len < MIN_LENGTH) ? MIN_LENGTH : pkt->len;
+ outb_p(tmplen & 0xff, iobase + REMOTEBYTECOUNT0);
+ outb_p(tmplen >> 8, iobase + REMOTEBYTECOUNT1);
+ outb_p(0x00, iobase + REMOTESTARTADDRESS0);
+ outb_p(pkt->page, iobase + REMOTESTARTADDRESS1);
+ outb_p(NIC_REM_WRITE | NIC_START, iobase);
+
+ T(D);
+
+ /* go through each buffer and transfer it's contents */
+ for(bufidx=pkt->count-1; bufidx >= 0; bufidx--) {
+ char odd;
+ buflen=pkt->buf[bufidx].len; /* only do derefrence once */
+ bufptr=pkt->buf[bufidx].ptr; /* for performance :) */
+
+ if(nic->wordlength==2) {
+
+ odd=(buflen & 0x01);
+ buflen>>=1; /* half the transfers */
+
+ if(skip) ((uint)bufptr)--; /* korewa baka desu */
+
+ for(f=skip;f<buflen;f++) { /* do we skip? */
+ outw(((unsigned short *)bufptr)[f],iobase+NE_DATA);
+ tmplen -= 2;
+ }
+
+ /* output 16-bits of the last odd byte */
+ skip=0; /* assume we don't skip */
+
+ if(odd) {
+ short tmp=((unsigned char *)bufptr)[buflen<<1];
+ /* get the byte from the next segment */
+ if((bufidx-1)>=0) {
+ tmp |= ((unsigned char *) pkt->buf[bufidx-1].ptr)[0] << 8;
+ }
+ outw(tmp,iobase + NE_DATA);
+ tmplen -= 2;
+ skip=1;
+ }
+ } else
+ for(f=0;f<buflen;f++) {
+ outb(((unsigned char *)bufptr)[f],iobase+NE_DATA);
+ tmplen--;
+ }
+ }
+ T(E);
+
+ /* If it's too short, pad with 0s */
+ if(tmplen > 0) {
+ T(F);
+/* kprintf("Padding runt\n"); */
+ if(nic->wordlength==2) {
+ for(f=0;f<tmplen/2;f++){
+ outw(0x00,iobase + NE_DATA);
+ tmplen -= 2;
+ }
+ }
+ }
+ if (tmplen > 0) {
+ for(f=0;f<tmplen;f++) {
+ outb(0x00,iobase + NE_DATA);
+ tmplen--;
+ }
+ }
+
+
+ T(G);
+#ifdef SHIT
+ if(nic->wordlength==2) {
+ for(w=0;w<(len>>1);w++)
+ outw(((unsigned short *)buf)[w],iobase+NE_DATA);
+ if(len & 0x01) {
+ short tmp=buf[len-1]; //so we can output a whole 16-bits
+ // if buf were on the end of something, we would die.
+ outw(tmp,iobase+NE_DATA);
+ }
+ } else for(f=0;f<len;f++)
+ outb(((unsigned char *)buf)[f],iobase+NE_DATA);
+
+#endif
+ for(f=0;f<timeout;f++) {
+ uint high=inb_p(iobase + REMOTESTARTADDRESS1);
+ uint low=inb_p(iobase + REMOTESTARTADDRESS0);
+ addr=(high<<8)+low;
+ if(( (((pkt->page<<8)+(nic->wordlength==2 && (pkt->len&0x01))?
+/* pkt->len+1:pkt->len+2))&0xff)==low)*/
+ pkt->len+0:pkt->len+1))&0xff)==low)
+ break;
+ if( (pkt->len < MIN_LENGTH) && ( (((pkt->page<<8)+MIN_LENGTH)
+ & 0xff) == low) )
+ break;
+ }
+ T(H);
+#ifdef SHIT
+ if(f>=timeout)
+ kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n",
+ ( (pkt->len >= MIN_LENGTH) ?
+ ((pkt->page<<8)+
+ (nic->wordlength==2&&(pkt->len&0x01))?
+ pkt->len+0:pkt->len+1)
+/* pkt->len+1:pkt->len+2)*/
+ : ((pkt->page<<8)+MIN_LENGTH) ),
+ addr);
+#endif
+/* TODO Check ISR_RDC */
+
+ T(I);
+
+ outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */
+}
diff --git a/srv/network/device/ne/ne2000.h b/srv/network/device/ne/ne2000.h
@@ -0,0 +1,116 @@
+/* $Id: //depot/blt/srv/network/device/ne/ne2000.h#1 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __NE2000_INTERFACE
+#define __NE2000_INTERFACE
+#ifndef __NE2000_SHARED_CODE_BASE
+typedef unsigned int uint;
+typedef struct snic snic;
+typedef struct nic_stat nic_stat;
+typedef struct buffer_header buffer_header;
+typedef struct packet_data packet_data;
+typedef struct packet_buffer packet_buffer;
+typedef struct nic_error_stat nic_error_stat;
+#endif /* NE2000_SHARED_CODE_BASE */
+
+#define LEN_ADDR 6
+#define MAX_TX 2 /* be careful with this (dual buffers) */
+#define MAX_PAGESPERPACKET 6
+#define TXPAGES (MAX_TX*MAX_PAGESPERPACKET)
+#define LEN_PROM 16
+#define LEN_HEADER 14
+#define MIN_LENGTH 60 /* minimum length for packet data */
+#define MAX_LENGTH 1500 /* maximum length for packet data area */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* external interface */
+int nic_detect(int given);
+int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual);
+void nic_register_notify(snic *nic, void(*newnotify)(void*,packet_data*),void*);
+void nic_start(snic *nic, int promiscuous);
+void nic_stop(snic *nic);
+void nic_isr(snic *nic);
+nic_stat nic_get_stats(snic *nic);
+void nic_stat_clear(nic_stat *that);
+int nic_send_packet(snic *nic, packet_buffer *buffer);
+
+/* Your implementation */
+/*packet_buffer *alloc_buffer(uint count); */ /* Optional */
+packet_data *alloc_buffer_data(uint size);
+void free_buffer(packet_buffer *ptr);
+void cleanup_buffer(packet_buffer *ptr);
+void free_buffer_data(packet_data *ptr); /* Optional */
+/* I reserve the right to use the "Option" procedures in the future */
+
+#ifdef __cplusplus
+};
+#endif
+
+struct buffer_header {
+ unsigned char status;
+ unsigned char next;
+ unsigned short count; /* length of header and packet */
+};
+
+struct nic_error_stat {
+ long frame_alignment, crc, missed_packets;
+ long rx, rx_size, rx_dropped, rx_fifo, rx_overruns;
+ long tx_collisions;
+ long tx_aborts, tx_carrier, tx_fifo, tx_heartbeat, tx_window;
+};
+
+struct nic_stat {
+ long rx_packets;
+ long tx_buffered, tx_packets;
+ nic_error_stat errors;
+};
+
+struct packet_buffer {
+ uint page;
+ uint count, len;
+ packet_data *buf; /* An array of data segments */
+};
+
+struct packet_data { /* each protocol layer can add it's own */
+ uint len;
+ char *ptr;
+};
+
+struct snic {
+ int iobase; /* NULL if uninitialized */
+ int pstart, pstop, wordlength, current_page;
+ nic_stat stat;
+ void (*notify)(void *passback, packet_data *newpacket);
+ void *kore; /* Passback pointer */
+ packet_buffer *tx_packet[MAX_TX], *last_tx;
+ int busy, send, sending;
+};
+
+#endif /* __NE2000_INTERFACE */
diff --git a/srv/network/device/ne/support.c b/srv/network/device/ne/support.c
@@ -0,0 +1,62 @@
+/* $Id: //depot/blt/srv/network/device/ne/support.c#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include "ne2000.h"
+
+unsigned int ticks;
+
+void idle (void)
+{
+ int i;
+
+ for (i = 0; i < 1000; i++)
+ ticks++;
+}
+
+packet_data *alloc_buffer_data (uint size)
+{
+ packet_data *data;
+
+ data = malloc (sizeof (packet_data));
+ data->len = size;
+ data->ptr = malloc (size);
+ return data;
+}
+
+void free_buffer (packet_buffer *buf)
+{
+ free (buf);
+}
+
+void free_buffer_data (packet_data *pd)
+{
+ free (pd->ptr);
+ free (pd);
+}
+
diff --git a/srv/network/device/ne/wrap.c b/srv/network/device/ne/wrap.c
@@ -0,0 +1,180 @@
+/* $Id: //depot/blt/srv/network/device/ne/wrap.c#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * limitations: can only support one card for now.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <blt/qsem.h>
+#include <blt/network/eth.h>
+#include <blt/network/mbuf.h>
+#include "ne2000.h"
+#include "wrap.h"
+
+#define NE_IRQ 3
+
+void probe (void);
+static void isr (void);
+static void receive (void *cb, packet_data *data);
+static void send (int num, struct mbuf *data);
+
+static eth_drv_t driver = { "ne", send, NULL };
+
+static int maxdev = 0;
+static int __irq;
+static qsem_t *__mutex;
+static ne_card_t *__card;
+static eth_dev_t *__dev;
+
+int _init (void)
+{
+ register_eth_driver (&driver);
+ return 0;
+}
+
+void _fini (void)
+{
+}
+
+void probe (void)
+{
+ int iobase;
+ ne_card_t *card;
+ eth_dev_t *dev;
+
+ if (iobase = nic_detect (0))
+ {
+ card = malloc (sizeof (ne_card_t));
+ card->nic.iobase = 0;
+ card->irq = NE_IRQ;
+ card->mutex = qsem_create (1);
+ nic_init (&card->nic, iobase, card->prom, NULL);
+ printf ("network: ne0 at port 0x%x, irq %d, mac = %X:%X:%X:%X:%X:%X\n",
+ card->nic.iobase, card->irq, card->prom[0], card->prom[1],
+ card->prom[2], card->prom[3], card->prom[4], card->prom[5]);
+ dev = malloc (sizeof (eth_dev_t));
+ dev->dev_driver = &driver;
+ dev->dev_num = maxdev++;
+ memcpy (dev->dev_addr, card->prom, sizeof (dev->dev_addr));
+ dev->dev_data = card;
+
+ register_eth_device (dev);
+ nic_register_notify (&card->nic, receive, NULL);
+ nic_start (&card->nic, 0);
+
+ __card = card;
+ __irq = card->irq;
+ __mutex = card->mutex;
+ __dev = dev;
+
+ thr_create (isr, 0, "network:ne:isr");
+ }
+ else
+ printf ("network: ne: probe failed.\n");
+}
+
+int config (int num, const char *prot, int state, const char *data)
+{
+ eth_config (__dev, prot, state, data);
+ return 0;
+}
+
+static void isr (void)
+{
+ os_handle_irq (__irq);
+ for (;;)
+ {
+ os_sleep_irq ();
+ qsem_acquire (__mutex);
+ nic_isr (&__card->nic);
+ qsem_release (__mutex);
+ }
+}
+
+static void receive (void *cb, packet_data *data)
+{
+ struct mbuf *mbuf, *header;
+
+ mbuf = mget ();
+ mbuf->m_type = MT_DATA;
+ mbuf->m_len = data->len;
+ if (data->len < MLEN)
+ {
+ mbuf->m_data = mbuf->m_databuf;
+ memcpy (mbuf->m_data, data->ptr, data->len);
+ }
+ free_buffer_data (data);
+
+ header = mget ();
+ header->m_type = MT_IFADDR;
+ header->m_len = 3;
+ *((eth_dev_t **) header->m_data) = __dev;
+ header->m_next = mbuf;
+
+ eth_input (header);
+}
+
+struct _pbuf {
+ packet_buffer pb; /* 16 */
+ packet_data pd; /* 8 */
+ int n;
+} pbuf;
+
+static void send (int num, struct mbuf *data)
+{
+ int res;
+ packet_buffer *pb;
+
+ printf ("send! %d\n", data->m_next->m_len);
+#if 0
+ pb = malloc (sizeof (packet_buffer));
+ pb->count = 1;
+ pb->len = data->m_next->m_len;
+ pb->buf = alloc_buffer_data (pb->len);
+ pb->buf->len = data->m_next->m_len;
+ memcpy (pb->buf->ptr, data->m_next->m_data, pb->len);
+ qsem_acquire (__mutex);
+ res = nic_send_packet (&__card->nic, pb);
+ qsem_release (__mutex);
+#else
+ pbuf.pb.count = 1;
+ pbuf.pb.buf = &pbuf.pd;
+ pbuf.pd.ptr = malloc (1000);
+ memcpy (pbuf.pd.ptr, data->m_next->m_data, data->m_next->m_len);
+ pbuf.pb.len = pbuf.pd.len = data->m_next->m_len + 100;
+ qsem_acquire (__mutex);
+ res = nic_send_packet (&__card->nic, &pbuf.pb);
+ qsem_release (__mutex);
+#endif
+ printf ("sent %d\n", res);
+ mput (data->m_next);
+ mput (data);
+}
+
diff --git a/srv/network/device/ne/wrap.h b/srv/network/device/ne/wrap.h
@@ -0,0 +1,43 @@
+/* $Id: //depot/blt/srv/network/device/ne/wrap.h#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef WRAP_H
+#define WRAP_H
+
+#include <blt/qsem.h>
+
+typedef struct
+{
+ snic nic;
+ char prom[32];
+ int irq;
+ qsem_t *mutex;
+} ne_card_t;
+
+#endif
+
diff --git a/srv/network/mbuf.c b/srv/network/mbuf.c
@@ -0,0 +1,106 @@
+/* $Id: //depot/blt/srv/network/mbuf.c#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <unistd.h>
+#include <blt/qsem.h>
+#include <blt/network/mbuf.h>
+
+#define MBUF_INIT_MEM 0x1000 /* start with one page of mbufs */
+#define MCL_INIT_MEM 0x4000 /* start with eight clusters */
+
+static struct mbuf *free_mbuf = NULL;
+static unsigned int **free_cluster = NULL;
+
+static qsem_t *free_mbuf_sem, *free_cluster_sem;
+
+void mbinit (void)
+{
+ unsigned int i, **cl;
+ struct mbuf *m;
+
+ m = sbrk (MBUF_INIT_MEM);
+ for (i = 0; i < MBUF_INIT_MEM / sizeof (struct mbuf); i++)
+ {
+ m[i].m_next = free_mbuf;
+ m[i].m_nextpkt = NULL;
+ m[i].m_len = MLEN;
+ m[i].m_data = (char *) &m[i] + sizeof (struct mbuf);
+ m[i].m_type = MT_FREE;
+ m[i].m_flags = 0;
+ free_mbuf = &m[i];
+ }
+
+ cl = sbrk (MCL_INIT_MEM);
+ for (i = 0; i < MCL_INIT_MEM / 0x800; i++, cl += 0x800 / sizeof (int))
+ {
+ *cl = (unsigned int *) free_cluster;
+ free_cluster = cl;
+ }
+
+ free_mbuf_sem = qsem_create (1);
+ free_cluster_sem = qsem_create (1);
+}
+
+struct mbuf *mget (void)
+{
+ struct mbuf *mbuf;
+
+ qsem_acquire (free_mbuf_sem);
+ if ((mbuf = free_mbuf) == NULL)
+ {
+ /* allocate more memory */
+ }
+ else
+ free_mbuf = free_mbuf->m_next;
+ qsem_release (free_mbuf_sem);
+ mbuf->m_next = NULL;
+ return mbuf;
+}
+
+char *mgetcl (struct mbuf *mbuf)
+{
+}
+
+void mput (struct mbuf *mbuf)
+{
+ mbuf->m_nextpkt = NULL;
+ mbuf->m_len = MLEN;
+ mbuf->m_data = (char *) mbuf + sizeof (struct mbuf);
+ mbuf->m_type = MT_FREE;
+ mbuf->m_flags = 0;
+ mputcl (mbuf);
+ qsem_acquire (free_mbuf_sem);
+ mbuf->m_next = free_mbuf;
+ free_mbuf = mbuf->m_next;
+ qsem_release (free_mbuf_sem);
+}
+
+void mputcl (struct mbuf *mbuf)
+{
+}
+
diff --git a/srv/network/network.c b/srv/network/network.c
@@ -0,0 +1,257 @@
+/* $Id: //depot/blt/srv/network/network.c#5 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <blt/syscall.h>
+#include <blt/namer.h>
+#include <blt/tell.h>
+#include <blt/os.h>
+#include <blt/network/module.h>
+#include <blt/network/mbuf.h>
+
+static int ctl_port, tell_port;
+module_t *modlist = NULL;
+
+void network_cmd (const char *cmd, const char *arg)
+{
+ char c[] = { 0, 0 }, *name, *num, *prot;
+ int i, len, ifnum, state;
+ void *handle;
+ void (*probe)(void);
+ void (*config)(int, const char *, int, const char *);
+ module_t *m;
+
+ if (!strcmp (cmd, "load"))
+ {
+ printf (" %s", arg);
+ name = malloc (len = BLT_MAX_NAME_LENGTH);
+ strlcpy (name, "/boot/", len);
+ strlcat (name, arg, len);
+ strlcat (name, ".so", len);
+ handle = dlopen (name, 0);
+ if (handle == NULL)
+ {
+ printf ("(error)", arg);
+ return;
+ }
+ free (name);
+ m = malloc (sizeof (module_t));
+ m->name = malloc (strlen (arg) + 1);
+ strcpy (m->name, arg);
+ m->handle = handle;
+ m->next = modlist;
+ modlist = m;
+ }
+ else if (!strcmp (cmd, "probe"))
+ {
+ m = modlist;
+ while (m != NULL)
+ {
+ if (!strcmp (m->name, arg))
+ {
+ probe = dlsym (m->handle, "probe");
+ if (probe != NULL)
+ {
+ (*probe) ();
+ return;
+ }
+ }
+ else
+ m = m->next;
+ }
+ }
+ else if (!strcmp (cmd, "config"))
+ {
+ name = malloc (len = BLT_MAX_NAME_LENGTH);
+ for (i = 0; (i < len) && arg[i]; i++)
+ if ((arg[i] >= '0') && (arg[i] <= '9'))
+ {
+ name[i] = 0;
+ break;
+ }
+ else
+ name[i] = arg[i];
+
+ num = malloc (BLT_MAX_NAME_LENGTH);
+ *num = 0;
+ i++;
+ while ((arg[i] != ' ') && arg[i])
+ {
+ *c = arg[i];
+ strlcat (num, c, len);
+ }
+ ifnum = atoi (num);
+
+ prot = malloc (BLT_MAX_NAME_LENGTH);
+ *prot = 0;
+ i++;
+ while ((arg[i] != ' ') && arg[i])
+ {
+ *c = arg[i++];
+ strlcat (prot, c, len);
+ }
+
+ *num = 0;
+ i++;
+ while ((arg[i] != ' ') && arg[i])
+ {
+ *c = arg[i++];
+ strlcat (num, c, len);
+ }
+ if (!strcmp (num, "up"))
+ state = 1;
+ else if (!strcmp (num, "down"))
+ state = 0;
+ else
+ ;
+
+ m = modlist;
+ while (m != NULL)
+ {
+ if (!strcmp (m->name, name))
+ {
+ config = dlsym (m->handle, "config");
+ if (config != NULL)
+ {
+ (*config) (ifnum, prot, state, arg + i + 1);
+ return;
+ }
+ }
+ else
+ m = m->next;
+ }
+ free (name);
+ free (num);
+ free (prot);
+ }
+}
+
+void network_tell (const char *msg)
+{
+ const char *c, *cmd;
+ char *full;
+ char *d;
+ int i, whole, len;
+
+ c = msg;
+ cmd = NULL;
+ whole = 0;
+ while (*c)
+ {
+ i = 0;
+ while ((c[i] != ' ') && c[i])
+ i++;
+ d = malloc (i + 1);
+ strlcpy (d, c, i + 1);
+ if (cmd == NULL)
+ {
+ cmd = d;
+ if (!strcmp (cmd, "load"))
+ printf ("network: loading drivers. [");
+ else if (!strcmp (cmd, "config"))
+ {
+ whole = 1;
+ full = malloc (len = strlen (msg + 1));
+ *full = 0;
+ }
+ }
+ else if (!whole)
+ network_cmd (cmd, d);
+ else
+ {
+ strlcat (full, d, len);
+ strlcat (full, " ", len);
+ }
+ if (i != strlen (c))
+ c += i + 1;
+ else
+ break;
+ }
+ if (!strcmp (cmd, "load"))
+ printf (" ]\n");
+ else if (!strcmp (cmd, "config"))
+ {
+ network_cmd (cmd, full);
+ free (full);
+ }
+}
+
+int network_main (volatile int *ready)
+{
+ char *buffer;
+ int len;
+ msg_hdr_t mh;
+
+ ctl_port = port_create (0, "network_ctl_port");
+ tell_port = port_create (0, "network_tell_port");
+ port_slave (ctl_port, tell_port);
+ namer_register (ctl_port, "network");
+ namer_register (tell_port, "network:tell");
+
+ printf ("network: ready.\n");
+ buffer = malloc (len = 256);
+ mbinit ();
+ *ready = 1;
+
+ for (;;)
+ {
+ mh.src = 0;
+ mh.dst = ctl_port;
+ mh.data = buffer;
+ mh.size = len;
+ old_port_recv (&mh);
+
+ if (mh.dst == tell_port)
+ {
+ network_tell (buffer);
+ mh.dst = mh.src;
+ mh.src = tell_port;
+ mh.data = &tell_port;
+ mh.size = 1;
+ old_port_send (&mh);
+ }
+ else if (mh.dst == ctl_port)
+ {
+ }
+ }
+
+ return 0;
+}
+
+int main (int argc, char **argv)
+{
+ volatile int ready = 0;
+
+ thr_create (network_main, (int *) &ready, "network");
+ while (!ready) ;
+ return 0;
+}
+
diff --git a/srv/network/protocol/Makefile b/srv/network/protocol/Makefile
@@ -0,0 +1,6 @@
+BLTHOME := ../../../
+include $(BLTHOME)make.conf
+
+SUBDIRS := eth arp ipv4
+
+include $(BLTHOME)make.actions
diff --git a/srv/network/protocol/arp/Makefile b/srv/network/protocol/arp/Makefile
@@ -0,0 +1,8 @@
+BLTHOME := ../../../../
+include $(BLTHOME)make.conf
+
+CFLAGS += -D_NETWORK
+OBJS := arp.o
+SHLIB := arp.so
+
+include $(BLTHOME)make.actions
diff --git a/srv/network/protocol/arp/arp.c b/srv/network/protocol/arp/arp.c
@@ -0,0 +1,108 @@
+/* $Id: //depot/blt/srv/network/protocol/arp/arp.c#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <blt/network/mbuf.h>
+#include <blt/network/eth.h>
+#include <blt/network/ipv4.h>
+
+void arp_input (struct mbuf *mbuf);
+static eth_prot_t protocol = { "arp", 0, arp_input, NULL };
+
+int _init (void)
+{
+ protocol.num = htons (ETH_PROT_ARP);
+ register_eth_protocol (&protocol);
+ return 0;
+}
+
+void arp_print_addrs (arp_packet *arp)
+{
+ printf ("%X:%X:%X:%X:%X:%X %X:%X:%X:%X:%X:%X\n", arp->header.src[0],
+ arp->header.src[1], arp->header.src[2], arp->header.src[3],
+ arp->header.src[4], arp->header.src[5], arp->header.dst[0],
+ arp->header.dst[1], arp->header.dst[2], arp->header.dst[3],
+ arp->header.dst[4], arp->header.dst[5]);
+}
+
+/*
+ * this doesn't take too long, so we do it synchronously.
+ */
+void arp_input (struct mbuf *mbuf)
+{
+ arp_packet *arp_request, *arp_reply;
+ ipv4_iface_t *iface;
+ eth_dev_t *dev;
+ struct mbuf *reply_header, *reply;
+
+ arp_request = (arp_packet *) mbuf->m_next->m_data;
+ iface = iflist;
+ while (iface != NULL)
+ if (!memcmp (iface->addr, arp_request->targ_ip_addr, 4))
+ {
+ printf ("ARP: who-has %d.%d.%d.%d tell %d.%d.%d.%d\n",
+ arp_request->targ_ip_addr[0], arp_request->targ_ip_addr[1],
+ arp_request->targ_ip_addr[2], arp_request->targ_ip_addr[3],
+ arp_request->send_ip_addr[0], arp_request->send_ip_addr[1],
+ arp_request->send_ip_addr[2], arp_request->send_ip_addr[3]);
+
+ dev = *((eth_dev_t **) mbuf->m_data);
+ reply_header = mget ();
+ reply_header->m_next = reply = mget ();
+ arp_reply = (arp_packet *) (reply->m_data = reply->m_databuf);
+ memcpy (arp_reply->header.dst, arp_request->header.src, 6);
+ memcpy (arp_reply->header.src, dev->dev_addr, 6);
+ arp_reply->header.frame_type = htons (ETH_PROT_ARP);
+ arp_reply->hard_type = htons (1);
+ arp_reply->prot_type = htons (ETH_PROT_IP);
+ arp_reply->hard_size = 6;
+ arp_reply->prot_size = 4;
+ arp_reply->op = htons (ETH_ARP_OP_REPLY);
+ memcpy (arp_reply->send_eth_addr, dev->dev_addr, 6);
+ memcpy (arp_reply->send_ip_addr, iface->addr, 4);
+ memcpy (arp_reply->targ_eth_addr, arp_request->header.src, 6);
+ memcpy (arp_reply->targ_ip_addr, arp_request->send_ip_addr, 4);
+
+ printf ("ARP: reply %d.%d.%d.%d is-at %X:%X:%X:%X:%X:%X\n",
+ arp_reply->send_ip_addr[0], arp_reply->send_ip_addr[1],
+ arp_reply->send_ip_addr[2], arp_reply->send_ip_addr[3],
+ arp_reply->send_eth_addr[0], arp_reply->send_eth_addr[1],
+ arp_reply->send_eth_addr[2], arp_reply->send_eth_addr[3],
+ arp_reply->send_eth_addr[4], arp_reply->send_eth_addr[5]);
+
+ arp_print_addrs (arp_request);
+ arp_print_addrs (arp_reply);
+ reply->m_len = sizeof (arp_packet);
+ dev->dev_driver->output (dev->dev_num, reply_header);
+ mput (mbuf->m_next);
+ mput (mbuf);
+ return;
+ }
+ else
+ iface = iface->next;
+}
+
diff --git a/srv/network/protocol/eth/Makefile b/srv/network/protocol/eth/Makefile
@@ -0,0 +1,8 @@
+BLTHOME := ../../../../
+include $(BLTHOME)make.conf
+
+CFLAGS += -D_NETWORK
+OBJS := eth.o
+SHLIB := eth.so
+
+include $(BLTHOME)make.actions
diff --git a/srv/network/protocol/eth/eth.c b/srv/network/protocol/eth/eth.c
@@ -0,0 +1,210 @@
+/* $Id: //depot/blt/srv/network/protocol/eth/eth.c#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+e* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <blt/qsem.h>
+#include <blt/network/eth.h>
+#include <blt/network/mbuf.h>
+#include <blt/network/module.h>
+
+eth_drv_t *drvlist = NULL;
+eth_dev_t *devlist = NULL;
+eth_prot_t *protlist = NULL;
+
+static qsem_t *eth_input_lock_sem, *eth_input_length_sem;
+static qsem_t *eth_output_lock_sem, *eth_output_length_sem;
+static struct mbuf *eth_input_queue = NULL, *eth_output_queue = NULL;
+static void eth_input_thread (void);
+static void eth_output_thread (void);
+
+int _init (void)
+{
+ eth_input_lock_sem = qsem_create (1);
+ eth_input_length_sem = qsem_create (0);
+ thr_create (eth_input_thread, 0, "network:eth:input");
+ eth_output_lock_sem = qsem_create (1);
+ eth_output_length_sem = qsem_create (0);
+ thr_create (eth_output_thread, 0, "network:eth:output");
+ return 1;
+}
+
+void _fini (void)
+{
+}
+
+void register_eth_driver (eth_drv_t *drv)
+{
+ drv->next = drvlist;
+ drvlist = drv;
+}
+
+void unregister_eth_driver (eth_drv_t *drv)
+{
+}
+
+void register_eth_device (eth_dev_t *dev)
+{
+ dev->next = devlist;
+ devlist = dev;
+}
+
+void unregister_eth_device (eth_dev_t *dev)
+{
+}
+
+void register_eth_protocol (eth_prot_t *prot)
+{
+ prot->next = protlist;
+ protlist = prot;
+}
+
+void unregister_eth_protocol (eth_prot_t *prot)
+{
+}
+
+void eth_input (struct mbuf *mbuf)
+{
+ struct mbuf *m;
+
+ qsem_acquire (eth_input_lock_sem);
+ if (eth_input_queue == NULL)
+ {
+ eth_input_queue = mbuf;
+ mbuf->m_nextpkt = NULL;
+ }
+ else
+ {
+ m = eth_input_queue;
+ while (m->m_nextpkt != NULL)
+ m = m->m_nextpkt;
+ m->m_nextpkt = mbuf;
+ }
+ qsem_release (eth_input_lock_sem);
+ qsem_release (eth_input_length_sem);
+}
+
+static void eth_input_thread (void)
+{
+ struct mbuf *mbuf, *mbuf_header;
+ eth_prot_t *prot;
+ ether_header *header;
+
+ for (;;)
+ {
+ qsem_acquire (eth_input_length_sem);
+ qsem_acquire (eth_input_lock_sem);
+ mbuf_header = eth_input_queue;
+ eth_input_queue = eth_input_queue->m_nextpkt;
+ qsem_release (eth_input_lock_sem);
+
+ mbuf = mbuf_header->m_next;
+ header = (ether_header *) mbuf->m_data;
+#if 0
+ printf ("eth_input_thread prot: %x src: %X:%X:%X:%X:%X:%X dst: "
+ "%X:%X:%X:%X:%X:%X\n", header->frame_type, header->src[0],
+ header->src[1], header->src[2], header->src[3], header->src[4],
+ header->src[5], header->dst[0], header->dst[1], header->dst[2],
+ header->dst[3], header->dst[4], header->dst[5]);
+#endif
+ prot = protlist;
+ while (prot != NULL)
+ if (prot->num == header->frame_type)
+ {
+ prot->input (mbuf_header);
+ break;
+ }
+ else
+ prot = prot->next;
+ }
+}
+
+void eth_output (struct mbuf *mbuf)
+{
+ struct mbuf *m;
+
+ qsem_acquire (eth_output_lock_sem);
+ if (eth_output_queue == NULL)
+ {
+ eth_output_queue = mbuf;
+ mbuf->m_nextpkt = NULL;
+ }
+ else
+ {
+ m = eth_output_queue;
+ while (m->m_nextpkt != NULL)
+ m = m->m_nextpkt;
+ m->m_nextpkt = mbuf;
+ }
+ qsem_release (eth_output_lock_sem);
+ qsem_release (eth_output_length_sem);
+}
+
+static void eth_output_thread (void)
+{
+ struct mbuf *mbuf;
+
+ for (;;)
+ {
+ qsem_acquire (eth_output_length_sem);
+ qsem_acquire (eth_output_lock_sem);
+ mbuf = eth_output_queue;
+ eth_output_queue = eth_input_queue->m_nextpkt;
+ qsem_release (eth_output_lock_sem);
+ printf ("eth_output_thread\n");
+ }
+}
+
+void eth_config (eth_dev_t *dev, const char *prot, int state, const char *data)
+{
+ char *devname;
+ int len;
+ int (*config_up)(const char *, void (*)(struct mbuf *), const char *);
+ module_t *mod;
+
+ mod = modlist;
+ while (mod != NULL)
+ if (!strcmp (mod->name, prot))
+ {
+ printf ("network: %s%d: interface %s, ", dev->dev_driver->name,
+ dev->dev_num, state ? "up" : "down");
+ devname = malloc (len = 16);
+ snprintf (devname, len, "%s%d", dev->dev_driver->name,
+ dev->dev_num);
+ config_up = dlsym (mod->handle, "ipv4_config_up"); /* XXX */
+ if (config_up != NULL)
+ (*config_up) (devname, eth_output, data);
+ return;
+ }
+ else
+ mod = mod->next;
+ printf ("network: %s%d: unknown protocol %s\n", dev->dev_driver->name,
+ dev->dev_num, prot);
+}
+
diff --git a/srv/network/protocol/ipv4/Makefile b/srv/network/protocol/ipv4/Makefile
@@ -0,0 +1,8 @@
+BLTHOME := ../../../../
+include $(BLTHOME)make.conf
+
+CFLAGS += -D_NETWORK
+OBJS := iface.o
+SHLIB := ipv4.so
+
+include $(BLTHOME)make.actions
diff --git a/srv/network/protocol/ipv4/iface.c b/srv/network/protocol/ipv4/iface.c
@@ -0,0 +1,84 @@
+/* $Id: //depot/blt/srv/network/protocol/ipv4/iface.c#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <blt/network/ipv4.h>
+
+ipv4_iface_t *iflist = NULL;
+
+int _init (void)
+{
+ return 1;
+}
+
+int ipv4_config_up (const char *name, void (*output)(struct mbuf *),
+ const char *data)
+{
+ char c[] = { 0, 0 }, temp[16];
+ unsigned char num[8];
+ int i, j, k, len, space;
+ ipv4_iface_t *iface;
+
+ for (i = j = k = space = *temp = 0; i < strlen (data); i++)
+ if (data[i] == '.')
+ {
+ num[k++] = atoi (temp);
+ j++;
+ *temp = 0;
+ }
+ else if (data[i] == ' ')
+ {
+ num[k++] = atoi (temp);
+ j++;
+ *temp = 0;
+ space = 1;
+ }
+ else
+ {
+ *c = data[j++];
+ strlcat (temp, c, sizeof (temp));
+ }
+ iface = malloc (sizeof (ipv4_iface_t));
+ iface->name = name;
+ iface->addr[0] = num[0]; iface->addr[1] = num[1];
+ iface->addr[2] = num[2]; iface->addr[3] = num[3];
+ iface->netmask[0] = num[4]; iface->netmask[1] = num[5];
+ iface->netmask[2] = num[6]; iface->netmask[3] = num[7];
+ iface->output = output;
+ iface->next = iflist;
+ iflist = iface;
+ printf ("address %d.%d.%d.%d netmask %d.%d.%d.%d\n",
+ iface->addr[0], iface->addr[1], iface->addr[2], iface->addr[3],
+ iface->netmask[0], iface->netmask[1], iface->netmask[2],
+ iface->netmask[3]);
+}
+
+int ipv4_config_down (void)
+{
+}
+
diff --git a/srv/pci/Makefile b/srv/pci/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+SRCS := pci.c server.cpp
+CRT0 := $(BLTHOME)lib/crt0.o
+BINARY := pci.bin
+LIBS := -lposix -lblt -lc
+
+include $(BLTHOME)make.actions
diff --git a/srv/pci/pci.c b/srv/pci/pci.c
@@ -0,0 +1,138 @@
+/* Copyright 1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <i386/io.h>
+
+#include "pci.h"
+
+typedef struct confadd
+{
+ uchar reg:8;
+ uchar func:3;
+ uchar dev:5;
+ uchar bus:8;
+ uchar rsvd:7;
+ uchar enable:1;
+} confadd;
+
+uint32 pci_read(int bus, int dev, int func, int reg, int bytes)
+{
+ uint32 base;
+
+ union {
+ confadd c;
+ uint32 n;
+ } u;
+
+ u.c.enable = 1;
+ u.c.rsvd = 0;
+ u.c.bus = bus;
+ u.c.dev = dev;
+ u.c.func = func;
+ u.c.reg = reg & 0xFC;
+
+ outl(u.n,0xCF8);
+
+ base = 0xCFC + (reg & 0x03);
+
+ switch(bytes){
+ case 1: return inb(base);
+ case 2: return inw(base);
+ case 4: return inl(base);
+ default: return 0;
+ }
+}
+
+void pci_write(int bus, int dev, int func, int reg, uint32 v, int bytes)
+{
+ uint32 base;
+
+ union {
+ confadd c;
+ uint32 n;
+ } u;
+
+ u.c.enable = 1;
+ u.c.rsvd = 0;
+ u.c.bus = bus;
+ u.c.dev = dev;
+ u.c.func = func;
+ u.c.reg = reg & 0xFC;
+
+ base = 0xCFC + (reg & 0x03);
+ outl(u.n,0xCF8);
+ switch(bytes){
+ case 1: outb(v,base); break;
+ case 2: outw(v,base); break;
+ case 4: outl(v,base); break;
+ }
+
+}
+
+int pci_probe(int bus, int dev, int func, pci_cfg *cfg)
+{
+ uint32 *word = (uint32 *) cfg;
+ uint32 v;
+ int i;
+ for(i=0;i<4;i++){
+ word[i] = pci_read(bus,dev,func,4*i,4);
+ }
+ if(cfg->vendor_id == 0xffff) return 1;
+
+ cfg->bus = bus;
+ cfg->dev = dev;
+ cfg->func = func;
+#if 0
+ printf("Device Info: /bus/pci/%d/%d/%d\n",bus,dev,func);
+ printf(" * Vendor: %S Device: %S Class/SubClass/Interface %X/%X/%X\n",
+ cfg->vendor_id,cfg->device_id,cfg->base_class,cfg->sub_class,cfg->interface);
+ printf(" * Status: %S Command: %S BIST/Type/Lat/CLS: %X/%X/%X/%X\n",
+ cfg->status, cfg->command, cfg->bist, cfg->header_type,
+ cfg->latency_timer, cfg->cache_line_size);
+#endif
+
+ switch(cfg->header_type & 0x7F){
+ case 0: /* normal device */
+ for(i=0;i<6;i++){
+ v = pci_read(bus,dev,func,i*4 + 0x10, 4);
+ if(v) {
+ int v2;
+ pci_write(bus,dev,func,i*4 + 0x10, 0xffffffff, 4);
+ v2 = pci_read(bus,dev,func,i*4+0x10, 4) & 0xfffffff0;
+ pci_write(bus,dev,func,i*4 + 0x10, v, 4);
+ v2 = 1 + ~v2;
+ if(v & 1) {
+// printf(" * Base Register %d IO: %x (%x)\n",i,v&0xfff0,v2&0xffff);
+ cfg->base[i] = v & 0xffff;
+ cfg->size[i] = v2 & 0xffff;
+ } else {
+// printf(" * Base Register %d MM: %x (%x)\n",i,v&0xfffffff0,v2);
+ cfg->base[i] = v;
+ cfg->size[i] = v2;
+ }
+ } else {
+ cfg->base[i] = 0;
+ cfg->size[i] = 0;
+ }
+
+ }
+ v = pci_read(bus,dev,func,0x3c,1);
+ cfg->irq = (v == 0xff ? 0 : v);
+
+// printf(" * Interrupt Line: %X\n",cfg->irq);
+ break;
+ case 1:
+// printf(" * PCI <-> PCI Bridge\n");
+ break;
+ default:
+// printf(" * Unknown Header Type\n");
+ }
+ return 0;
+}
+
+
diff --git a/srv/pci/pci.h b/srv/pci/pci.h
@@ -0,0 +1,151 @@
+/* Copyright 1999, Brian J. Swetland. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#ifndef _PCI_H
+#define _PCI_H
+
+#include <blt/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+ /* normal header stuff */
+ uint16 vendor_id;
+ uint16 device_id;
+
+ uint16 command;
+ uint16 status;
+
+ uint8 revision_id;
+ uint8 interface;
+ uint8 sub_class;
+ uint8 base_class;
+
+ uint8 cache_line_size;
+ uint8 latency_timer;
+ uint8 header_type;
+ uint8 bist;
+
+ /* device info */
+ uint8 bus;
+ uint8 dev;
+ uint8 func;
+ uint8 irq;
+
+ /* base registers */
+ uint32 base[6];
+ uint32 size[6];
+
+} pci_cfg;
+
+uint32 pci_read(int bus, int dev, int func, int reg, int bytes);
+void pci_write(int bus, int dev, int func, int reg, uint32 v, int bytes);
+int pci_probe(int bus, int dev, int func, pci_cfg *cfg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef PCI_STUB
+
+#include <blt/Connection.h>
+#include <blt/Message.h>
+
+namespace BLT {
+
+class PCI
+{
+public:
+ int read(int bus, int dev, int func, int reg, uint32 *v, int bytes);
+ int write(int bus, int dev, int func, int reg, uint32 v, int bytes);
+ int get_nth_cfg(int n, pci_cfg *cfg);
+
+ static PCI *FindService();
+ ~PCI();
+
+private:
+ PCI(Connection *pci);
+ Connection *pci;
+};
+
+inline int
+PCI::read(int bus, int dev, int func, int reg, uint32 *v, int bytes)
+{
+ int32 res;
+ Message msg;
+ msg.PutInt32('code',2);
+ msg.PutInt32('arg0',bus);
+ msg.PutInt32('arg1',dev);
+ msg.PutInt32('arg2',func);
+ msg.PutInt32('arg3',reg);
+ msg.PutInt32('arg4',bytes);
+
+ if((res = pci->Call(&msg,&msg))) return res;
+ msg.GetInt32('ret0',(int32*) v);
+ msg.GetInt32('resp',&res);
+
+ return res;
+}
+
+inline int
+PCI::write(int bus, int dev, int func, int reg, uint32 v, int bytes)
+{
+ int32 res;
+ Message msg;
+ msg.PutInt32('code',3);
+ msg.PutInt32('arg0',bus);
+ msg.PutInt32('arg1',dev);
+ msg.PutInt32('arg2',func);
+ msg.PutInt32('arg3',reg);
+ msg.PutInt32('arg4',(int32)v);
+ msg.PutInt32('arg5',bytes);
+
+ if((res = pci->Call(&msg,&msg))) return res;
+ msg.GetInt32('resp',&res);
+
+ return res;
+}
+
+inline int
+PCI::get_nth_cfg(int n, pci_cfg *cfg)
+{
+ int32 res;
+ Message msg;
+ msg.PutInt32('code',1);
+ msg.PutInt32('arg0',n);
+
+ if((res = pci->Call(&msg,&msg))) return res;
+ if((res = msg.GetData('ret0','pcic',cfg,sizeof(pci_cfg)))) return res;
+ msg.GetInt32('resp',&res);
+
+ return res;
+}
+
+inline PCI *
+PCI::FindService()
+{
+ Connection *cnxn = Connection::FindService("pci");
+ if(cnxn) {
+ return new PCI(cnxn);
+ } else {
+ return 0;
+ }
+}
+
+PCI::PCI(Connection *cnxn){
+ pci = cnxn;
+}
+
+PCI::~PCI(){
+ delete pci;
+}
+
+}
+
+#endif
+
+#endif
diff --git a/srv/pci/server.cpp b/srv/pci/server.cpp
@@ -0,0 +1,132 @@
+#include <blt/Message.h>
+#include <blt/Connection.h>
+#include <blt/namer.h>
+#include <blt/syscall.h>
+
+using namespace BLT;
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pci.h"
+
+static pci_cfg *pci_dev[128];
+static int pci_count = 0;
+
+void server(void *data)
+{
+ Connection *cnxn = (Connection *) data;
+ Message msg,reply;
+ int res;
+
+ while(cnxn->Recv(&msg) == 0){
+ int32 op = -1;
+ msg.GetInt32('code',&op);
+
+ reply.Empty();
+
+ switch(op){
+ case 1: { // get_nth_pci_cfg
+ int32 n = -1;
+ msg.GetInt32('arg0', &n);
+ if((n >= 0) && (n < pci_count)){
+ reply.PutData('ret0','pcic',pci_dev[n],sizeof(pci_cfg));
+ res = 0;
+ } else {
+ res = -1;
+ }
+ break;
+ }
+
+ case 2: { // pci_read
+ int32 bus = 0;
+ int32 dev = 0;
+ int32 func = 0;
+ int32 reg = 0;
+ int32 size = 0;
+ msg.GetInt32('arg0',&bus);
+ msg.GetInt32('arg1',&dev);
+ msg.GetInt32('arg2',&func);
+ msg.GetInt32('arg3',®);
+ msg.GetInt32('arg4',&size);
+
+ printf("pci: read(%d,%d,%d,%d,%d)\n",bus,dev,func,reg,size);
+ size = (int32) pci_read(bus,dev,func,reg,size);
+
+ reply.PutInt32('ret0',size);
+ res = 0;
+ break;
+ }
+
+ case 3: { // pci_write
+ int32 bus = 0;
+ int32 dev = 0;
+ int32 func = 0;
+ int32 reg = 0;
+ int32 size = 0;
+ int32 val = 0;
+
+ msg.GetInt32('arg0',&bus);
+ msg.GetInt32('arg1',&dev);
+ msg.GetInt32('arg2',&func);
+ msg.GetInt32('arg3',®);
+ msg.GetInt32('arg4',&val);
+ msg.GetInt32('arg5',&size);
+ pci_write(bus,dev,func,reg,(uint32)val,size);
+ res = 0;
+ break;
+ }
+
+ default:
+ res = -1;
+ }
+
+ reply.PutInt32('resp',res);
+ res = msg.Reply(&reply);
+ }
+}
+
+int pci_scan()
+{
+ pci_cfg cfg;
+ int bus,dev,func;
+
+ for(bus=0;bus<255;bus++){
+ for(dev=0;dev<32;dev++) {
+ if(pci_probe(bus,dev,0,&cfg)) continue;
+ pci_dev[pci_count] = (pci_cfg*) malloc(sizeof(pci_cfg));
+ memcpy(pci_dev[pci_count],&cfg,sizeof(pci_cfg));
+ pci_count++;
+ if(cfg.header_type & 0x80){
+ for(func=1;func<8;func++){
+ if(!pci_probe(bus,dev,func,&cfg)){
+ pci_dev[pci_count] = (pci_cfg*) malloc(sizeof(pci_cfg));
+ memcpy(pci_dev[pci_count],&cfg,sizeof(pci_cfg));
+ pci_count++;
+ }
+ }
+ }
+ }
+ }
+}
+
+int main(int argc, char **argv[])
+{
+ Connection *cnxn;
+
+ if(namer_find("pci",0) > 0) {
+// printf("pci: server is already running\n");
+ return 0;
+ }
+
+ cnxn = Connection::CreateService("pci");
+
+ pci_scan();
+
+ if(cnxn){
+// printf("pci: server started\n",cnxn);
+ thr_resume(thr_create(server,cnxn,"pci server"));
+ }
+ return 0;
+}
diff --git a/srv/vfs/Makefile b/srv/vfs/Makefile
@@ -0,0 +1,14 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+BINARY := vfs.bin
+OBJS := vfs.o fs.o super.o vnode.o shm.o path.o rootfs.o bootfs.o
+CRT0 := $(BLTHOME)lib/crtb.o
+LIBS := -lposix -lblt -ldl -lc
+SUBDIRS := drivers
+
+#CFLAGS += -DVFS_SANDBOX -Isandbox -Wall
+
+sandbox: fs.o super.o vnode.o
+
+include $(BLTHOME)make.actions
diff --git a/srv/vfs/bootfs.c b/srv/vfs/bootfs.c
@@ -0,0 +1,317 @@
+/* $Id: //depot/blt/srv/vfs/bootfs.c#9 $
+**
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <blt/syscall.h>
+#include "vfs-int.h"
+#include "bootfs.h"
+
+static int inode_max = 0;
+
+static struct vnode_ops bootfs_vnode_ops =
+{
+ bootfs_read_vnode, bootfs_drop_vnode, NULL, NULL, bootfs_walk, NULL,
+ bootfs_mount, bootfs_unmount, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ bootfs_opendir, bootfs_closedir, NULL, bootfs_rewinddir, bootfs_readdir,
+ bootfs_open, bootfs_close, bootfs_free_cookie, bootfs_read, NULL,
+ NULL, NULL, bootfs_rstat, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+};
+
+struct fs_type bootfs = { "bootfs", &bootfs_vnode_ops, NULL };
+
+static struct bootfs_inode *bootfs_inew (const char *name, int offset,
+ int size)
+{
+ struct bootfs_inode *inode;
+
+ inode = malloc (sizeof (struct bootfs_inode));
+ inode->i_ino = inode_max++;
+ inode->i_offset = offset;
+ inode->i_size = size;
+ strlcpy (inode->i_name, name, sizeof (inode->i_name));
+ inode->i_next = NULL;
+ return inode;
+}
+
+int bootfs_mount (struct superblock *super, const char *data, int silent)
+{
+ int i;
+ struct bootfs_sb_data *sb_data;
+ struct bootfs_inode *inode;
+ boot_entry *be;
+
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_mount\n");
+#endif
+ sb_data = (struct bootfs_sb_data *) malloc (sizeof (struct bootfs_sb_data));
+ sb_data->d_bootdir_area = area_clone (3, 0, (void **) &sb_data->d_bootdir,
+ 0);
+ sb_data->inode_list = NULL;
+
+ /* create inode list */
+ sb_data->inode_list = bootfs_inew (".", 0, 0);
+ sb_data->inode_list->i_next = bootfs_inew ("..", 0, 0);
+ for (i = 0; i < BOOTDIR_MAX_ENTRIES; i++)
+ if ((sb_data->d_bootdir->bd_entry[i].be_type != BE_TYPE_NONE) &&
+ strcmp (sb_data->d_bootdir->bd_entry[i].be_name,
+ BOOTDIR_DIRECTORY))
+ {
+ be = &sb_data->d_bootdir->bd_entry[i];
+ inode = bootfs_inew (be->be_name, be->be_offset, be->be_vsize);
+ inode->i_next = sb_data->inode_list;
+ sb_data->inode_list = inode;
+ }
+
+ super->sb_data = sb_data;
+ super->sb_root = vget (super, 0);
+ return 0;
+}
+
+void bootfs_unmount (struct superblock *sb)
+{
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_unmount\n");
+#endif
+}
+
+int bootfs_read_vnode (struct vnode *vnode)
+{
+ struct bootfs_sb_data *sb_data;
+ struct bootfs_inode *inode;
+
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_read_vnode %llx\n", vnode->v_vnid);
+#endif
+ sb_data = vnode->v_sb->sb_data;
+ inode = sb_data->inode_list;
+ while (inode != NULL)
+ if (inode->i_ino == vnode->v_vnid)
+ {
+ vnode->v_data = inode;
+ return 0;
+ }
+ else
+ inode = inode->i_next;
+
+ return 0;
+}
+
+void bootfs_drop_vnode (struct vnode *vnode)
+{
+#ifdef BOOTFS_DEBUG
+ vnode->v_data = NULL;
+#endif
+}
+
+struct vnode *bootfs_walk (struct vnode *parent, const char *path)
+{
+ struct bootfs_sb_data *data;
+ struct bootfs_inode *inode;
+
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_walk %s\n", path);
+#endif
+ if (parent->v_vnid)
+ return NULL;
+ else
+ {
+ data = parent->v_sb->sb_data;
+ inode = data->inode_list;
+ while (inode != NULL)
+ //if (!strncmp (inode->i_name, path, BOOTDIR_NAMELEN))
+ if (!strcmp (inode->i_name, path))
+ return vget (parent->v_sb, inode->i_ino);
+ else
+ inode = inode->i_next;
+ return NULL;
+ }
+}
+
+int bootfs_opendir (struct vnode *dir, void **cookie)
+{
+ struct bootfs_sb_data *data;
+ struct vfs_dirent_node *head, *p;
+ struct bootfs_inode *inode;
+ union bootfs_cookie *bc;
+
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_opendir\n");
+#endif
+ if (dir->v_vnid)
+ return ENOTDIR; /* paranoia */
+
+ head = NULL;
+ data = dir->v_sb->sb_data;
+ inode = data->inode_list;
+ while (inode != NULL)
+ {
+ p = malloc (sizeof (struct vfs_dirent_node));
+ p->dirent = malloc (sizeof (struct dirent));
+ p->dirent->d_fileno = inode->i_ino;
+ p->dirent->d_reclen = sizeof (struct dirent);
+ strncpy (p->dirent->d_name, inode->i_name, sizeof (p->dirent->d_name));
+
+ p->next = head;
+ head = p;
+ inode = inode->i_next;
+ }
+
+ bc = malloc (sizeof (union bootfs_cookie));
+ bc->u_dir.head = bc->u_dir.current = head;
+ *cookie = bc;
+ return 0;
+}
+
+void bootfs_closedir (struct vnode *dir, void *cookie)
+{
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_closedir\n");
+#endif
+}
+
+int bootfs_rewinddir (struct vnode *dir, void *cookie)
+{
+ union bootfs_cookie *bc;
+
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_rewinddir\n");
+#endif
+
+ bc = cookie;
+ bc->u_dir.current = bc->u_dir.head;
+ return 0;
+}
+
+int bootfs_readdir (struct vnode *dir, struct dirent *dirent, void *cookie)
+{
+ struct dirent *orig;
+ union bootfs_cookie *bc;
+
+ bc = cookie;
+ if (bc->u_dir.current == NULL)
+ return 1;
+ orig = bc->u_dir.current->dirent;
+ dirent->d_fileno = orig->d_fileno;
+ dirent->d_reclen = orig->d_reclen;
+ strncpy (dirent->d_name, orig->d_name, BLT_MAX_NAME_LENGTH);
+ bc->u_dir.current = bc->u_dir.current->next;
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_readdir %s\n", dirent->d_name);
+#endif
+ return 0;
+}
+
+int bootfs_open (struct vnode *vnode, void **cookie)
+{
+ struct bootfs_sb_data *data;
+ struct bootfs_inode *inode;
+ union bootfs_cookie *bc;
+
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_open %llx\n", vnode->v_vnid);
+#endif
+ data = vnode->v_sb->sb_data;
+ inode = vnode->v_data;
+ bc = malloc (sizeof (union bootfs_cookie));
+ bc->u_file.begin = (char *) data->d_bootdir + inode->i_offset * 0x1000;
+ bc->u_file.pos = 0;
+ *cookie = bc;
+ return 0;
+}
+
+int bootfs_close (struct vnode *vnode, void *cookie)
+{
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_close %llx\n", vnode->v_vnid);
+#endif
+ return 0;
+}
+
+void bootfs_free_cookie (void *cookie)
+{
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_free_cookie\n");
+#endif
+ free (cookie);
+}
+
+int bootfs_read (struct vnode *vnode, char *buf, size_t count, off_t offset,
+ size_t *numread, void *cookie)
+{
+ char *src;
+ struct bootfs_sb_data *data;
+ struct bootfs_inode *inode;
+ union bootfs_cookie *bc;
+
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_read %llx\n", vnode->v_vnid);
+#endif
+ data = vnode->v_sb->sb_data;
+ inode = vnode->v_data;
+ bc = cookie;
+ if (offset >= inode->i_size)
+ {
+ *numread = 0;
+ return 0;
+ }
+ src = (char *) data->d_bootdir + inode->i_offset * 0x1000 + offset;
+ *numread = (count <= inode->i_size - offset) ? count : (inode->i_size -
+ offset);
+ memcpy (buf, src, *numread);
+ return 0;
+}
+
+int bootfs_rstat (struct vnode *vnode, struct stat *buf)
+{
+ struct bootfs_inode *inode;
+
+#ifdef BOOTFS_DEBUG
+ printf ("bootfs_rstat %llx\n", vnode->v_vnid);
+#endif
+ inode = vnode->v_data;
+
+ buf->st_ino = inode->i_ino;
+ buf->st_nlink = 0;
+ buf->st_uid = 0;
+ buf->st_gid = 0;
+ buf->st_blksize = 512;
+ buf->st_size = inode->i_size;
+ buf->st_blocks = (inode->i_size & 0xfff) ? (inode->i_size >> 12) + 1 :
+ inode->i_size >> 12;
+ return 0;
+}
+
diff --git a/srv/vfs/bootfs.h b/srv/vfs/bootfs.h
@@ -0,0 +1,81 @@
+/* $Id: //depot/blt/srv/vfs/bootfs.h#6 $
+**
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BOOTFS_H_
+#define _BOOTFS_H_
+
+#include <boot.h>
+#include "vfs-int.h"
+
+struct bootfs_inode
+{
+ int i_ino, i_offset, i_size;
+ char i_name[BOOTDIR_NAMELEN];
+ struct bootfs_inode *i_next;
+};
+
+struct bootfs_sb_data
+{
+ int d_bootdir_area;
+ boot_dir *d_bootdir;
+ struct bootfs_inode *inode_list;
+};
+
+union bootfs_cookie
+{
+ struct
+ {
+ struct vfs_dirent_node *head, *current;
+ } u_dir;
+ struct
+ {
+ char *begin;
+ int pos;
+ } u_file;
+};
+
+int bootfs_mount (struct superblock *sb, const char *data, int silent);
+void bootfs_unmount (struct superblock *sb);
+int bootfs_read_vnode (struct vnode *vnode);
+void bootfs_drop_vnode (struct vnode *vnode);
+struct vnode *bootfs_walk (struct vnode *parent, const char *path);
+int bootfs_opendir (struct vnode *dir, void **cookie);
+void bootfs_closedir (struct vnode *dir, void *cookie);
+int bootfs_rewinddir (struct vnode *dir, void *cookie);
+int bootfs_readdir (struct vnode *dir, struct dirent *dirent, void *cookie);
+int bootfs_open (struct vnode *dir, void **cookie);
+int bootfs_close (struct vnode *dir, void *cookie);
+void bootfs_free_cookie (void *cookie);
+int bootfs_read (struct vnode *dir, char *buf, size_t count, off_t offset,
+ size_t *res, void *cookie);
+int bootfs_rstat (struct vnode *vnode, struct stat *buf);
+
+#endif
+
diff --git a/srv/vfs/drivers/Makefile b/srv/vfs/drivers/Makefile
@@ -0,0 +1,6 @@
+BLTHOME := ../../../
+include $(BLTHOME)make.conf
+
+SUBDIRS := ffs
+
+include $(BLTHOME)make.actions
diff --git a/srv/vfs/drivers/ffs/Makefile b/srv/vfs/drivers/ffs/Makefile
@@ -0,0 +1,9 @@
+BLTHOME := ../../../../
+include $(BLTHOME)make.conf
+
+SHLIB := ffs.so
+OBJS := super.o inode.o file.o dir.o
+CFLAGS += -I. -I../..
+#CFLAGS += -DVFS_SANDBOX -I. -I../..
+
+include $(BLTHOME)make.actions
diff --git a/srv/vfs/drivers/ffs/dinode.h b/srv/vfs/drivers/ffs/dinode.h
@@ -0,0 +1,132 @@
+/* $Id: //depot/blt/srv/vfs/drivers/ffs/dinode.h#2 $ */
+/* OpenBSD: dinode.h,v 1.3 1997/02/24 14:27:16 niklas Exp */
+/* NetBSD: dinode.h,v 1.7 1995/06/15 23:22:48 cgd Exp */
+
+/*
+ * Copyright (c) 1982, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dinode.h 8.6 (Berkeley) 9/13/94
+ */
+
+#ifndef DINODE_H
+#define DINODE_H
+
+/*
+ * The root inode is the root of the file system. Inode 0 can't be used for
+ * normal purposes and historically bad blocks were linked to inode 1, thus
+ * the root inode is 2. (Inode 1 is no longer used for this purpose, however
+ * numerous dump tapes make this assumption, so we are stuck with it).
+ */
+#define ROOTINO ((ino_t)2)
+
+/*
+ * The Whiteout inode# is a dummy non-zero inode number which will
+ * never be allocated to a real file. It is used as a place holder
+ * in the directory entry which has been tagged as a DT_W entry.
+ * See the comments about ROOTINO above.
+ */
+#define WINO ((ino_t)1)
+
+/*
+ * A dinode contains all the meta-data associated with a UFS file.
+ * This structure defines the on-disk format of a dinode. Since
+ * this structure describes an on-disk structure, all its fields
+ * are defined by types with precise widths.
+ */
+
+#define NDADDR 12 /* Direct addresses in inode. */
+#define NIADDR 3 /* Indirect addresses in inode. */
+
+struct ffs_dinode {
+ uint16 di_mode; /* 0: IFMT, permissions; see below. */
+ int16 di_nlink; /* 2: File link count. */
+ union {
+ uint16 oldids[2]; /* 4: Ffs: old user and group ids. */
+ ino_t inumber; /* 4: Lfs: inode number. */
+ } di_u;
+ uint64 di_size; /* 8: File byte count. */
+ int32 di_atime; /* 16: Last access time. */
+ int32 di_atimensec; /* 20: Last access time. */
+ int32 di_mtime; /* 24: Last modified time. */
+ int32 di_mtimensec; /* 28: Last modified time. */
+ int32 di_ctime; /* 32: Last inode change time. */
+ int32 di_ctimensec; /* 36: Last inode change time. */
+ int32 di_db[NDADDR]; /* 40: Direct disk blocks. */
+ int32 di_ib[NIADDR]; /* 88: Indirect disk blocks. */
+ uint32 di_flags; /* 100: Status flags (chflags). */
+ int32 di_blocks; /* 104: Blocks actually held. */
+ int32 di_gen; /* 108: Generation number. */
+ uint32 di_uid; /* 112: File owner. */
+ uint32 di_gid; /* 116: File group. */
+ int32 di_spare[2]; /* 120: Reserved; currently unused */
+};
+
+/*
+ * The di_db fields may be overlaid with other information for
+ * file types that do not have associated disk storage. Block
+ * and character devices overlay the first data block with their
+ * dev_t value. Short symbolic links place their path in the
+ * di_db area.
+ */
+#define di_inumber di_u.inumber
+#define di_ogid di_u.oldids[1]
+#define di_ouid di_u.oldids[0]
+#define di_rdev di_db[0]
+#define di_shortlink di_db
+#define MAXSYMLINKLEN ((NDADDR + NIADDR) * sizeof(uint32))
+
+/* File permissions. */
+#define IEXEC 0000100 /* Executable. */
+#define IWRITE 0000200 /* Writeable. */
+#define IREAD 0000400 /* Readable. */
+#define ISVTX 0001000 /* Sticky bit. */
+#define ISGID 0002000 /* Set-gid. */
+#define ISUID 0004000 /* Set-uid. */
+
+/* File types. */
+#define IFMT 0170000 /* Mask of file type. */
+#define IFIFO 0010000 /* Named pipe (fifo). */
+#define IFCHR 0020000 /* Character device. */
+#define IFDIR 0040000 /* Directory file. */
+#define IFBLK 0060000 /* Block device. */
+#define IFREG 0100000 /* Regular file. */
+#define IFLNK 0120000 /* Symbolic link. */
+#define IFSOCK 0140000 /* UNIX domain socket. */
+#define IFWHT 0160000 /* Whiteout. */
+
+#endif
+
diff --git a/srv/vfs/drivers/ffs/dir.c b/srv/vfs/drivers/ffs/dir.c
@@ -0,0 +1,153 @@
+/* $Id: //depot/blt/srv/vfs/drivers/ffs/dir.c#3 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include "vfs-int.h"
+
+#ifndef VFS_SANDBOX
+#include <blt/blkdev.h>
+#else
+#include "../../sandbox/blkdev.h"
+#endif
+
+#include "ffs.h"
+#include "ffs-blt.h"
+#include "dinode.h"
+#include "dir.h"
+
+int ffs_opendir (struct vnode *dir, void **cookie)
+{
+ char *buf;
+ int i, j, offset;
+ struct vfs_dirent_node *head, *p;
+ struct ffs_super *fs;
+ struct ffs_super_data *data;
+ struct ffs_dinode *di;
+ struct ffs_dircookie *fc;
+ struct ffs_direct *direct;
+
+#ifdef FFS_DEBUG
+ printf ("ffs_opendir %lld\n", dir->v_vnid);
+#endif
+
+ head = NULL;
+ data = dir->v_sb->sb_data;
+ fs = data->sbbuf;
+ di = dir->v_data;
+ buf = malloc (BLKSIZE);
+ for (i = 0; i < NDADDR; i++)
+ if (di->di_db[i])
+ {
+ blk_read (data->dev, buf, fsbtodb (fs, di->di_db[i]),
+ BLKSIZE / data->dev->blksize);
+ for (j = offset = 0; offset < BLKSIZE; offset += direct->d_reclen)
+ {
+ direct = (struct ffs_direct *) (buf + offset);
+ if (!direct->d_ino)
+ break;
+ //printf ("opendir %s %d %d\n", direct->d_name, offset, j++);
+ //if (j > 10) for (;;) ;
+ p = malloc (sizeof (struct vfs_dirent_node));
+ p->dirent = malloc (sizeof (struct dirent));
+ p->dirent->d_fileno = direct->d_ino;
+ p->dirent->d_reclen = sizeof (struct dirent);
+ strncpy (p->dirent->d_name, direct->d_name,
+ sizeof (p->dirent->d_name));
+ p->next = head;
+ head = p;
+ }
+ }
+ for (i = 0; i < NIADDR; i++)
+ if (di->di_ib[i])
+ {
+ }
+ free (buf);
+ fc = malloc (sizeof (struct ffs_dircookie));
+ fc->head = fc->current = head;
+ *cookie = fc;
+ return 0;
+}
+
+void ffs_closedir (struct vnode *dir, void *cookie)
+{
+#ifdef FFS_DEBUG
+ printf ("ffs_closedir %lld\n", dir->v_vnid);
+#endif
+}
+
+void ffs_free_dircookie (void *cookie)
+{
+ struct ffs_dircookie *fc;
+
+#ifdef FFS_DEBUG
+ printf ("ffs_freedircookie\n");
+#endif
+ fc = cookie;
+ while (fc->head != NULL)
+ {
+ fc->current = fc->head->next;
+ free (fc->head);
+ fc->head = fc->current;
+ }
+ free (fc);
+}
+
+int ffs_rewinddir (struct vnode *dir, void *cookie)
+{
+ struct ffs_dircookie *fc;
+
+#ifdef FFS_DEBUG
+ printf ("ffs_rewinddir %lld\n", dir->v_vnid);
+#endif
+ fc = cookie;
+ fc->current = fc->head;
+ return 0;
+}
+
+int ffs_readdir (struct vnode *dir, struct dirent *dirent, void *cookie)
+{
+ struct dirent *orig;
+ struct ffs_dircookie *fc;
+
+#ifdef FFS_DEBUG
+ //printf ("ffs_readdir %lld\n", dir->v_vnid);
+#endif
+ fc = cookie;
+ if (fc->current == NULL)
+ return 1;
+ orig = fc->current->dirent;
+ dirent->d_fileno = orig->d_fileno;
+ dirent->d_reclen = orig->d_reclen;
+ strncpy (dirent->d_name, orig->d_name, MAXNAMLEN);
+ fc->current = fc->current->next;
+ return 0;
+}
+
diff --git a/srv/vfs/drivers/ffs/dir.h b/srv/vfs/drivers/ffs/dir.h
@@ -0,0 +1,149 @@
+/* $Id: //depot/blt/srv/vfs/drivers/ffs/dir.h#1 $ */
+/* OpenBSD: dir.h,v 1.6 1997/05/30 08:34:56 downsj Exp */
+/* NetBSD: dir.h,v 1.8 1996/03/09 19:42:41 scottr Exp */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dir.h 8.4 (Berkeley) 8/10/94
+ */
+
+#ifndef DIR_H
+#define DIR_H
+
+/*
+ * Theoretically, directories can be more than 2Gb in length, however, in
+ * practice this seems unlikely. So, we define the type doff_t as a 32-bit
+ * quantity to keep down the cost of doing lookup on a 32-bit machine.
+*/
+#define doff_t int32
+#define MAXDIRSIZE (0x7fffffff)
+
+/*
+ * A directory consists of some number of blocks of DIRBLKSIZE
+ * bytes, where DIRBLKSIZE is chosen such that it can be transferred
+ * to disk in a single atomic operation (e.g. 512 bytes on most machines).
+ *
+ * Each DIRBLKSIZE byte block contains some number of directory entry
+ * structures, which are of variable length. Each directory entry has
+ * a struct direct at the front of it, containing its inode number,
+ * the length of the entry, and the length of the name contained in
+ * the entry. These are followed by the name padded to a 4 byte boundary
+ * with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ *
+ * The macro DIRSIZ(fmt, dp) gives the amount of space required to represent
+ * a directory entry. Free space in a directory is represented by
+ * entries which have dp->d_reclen > DIRSIZ(fmt, dp). All DIRBLKSIZE bytes
+ * in a directory block are claimed by the directory entries. This
+ * usually results in the last entry in a directory having a large
+ * dp->d_reclen. When entries are deleted from a directory, the
+ * space is returned to the previous entry in the same directory
+ * block by increasing its dp->d_reclen. If the first entry of
+ * a directory block is free, then its dp->d_ino is set to 0.
+ * Entries other than the first in a directory do not normally have
+ * dp->d_ino set to 0.
+ */
+#ifndef DIRBLKSIZE
+#define DIRBLKSIZE DEV_BSIZE
+#endif
+#define MAXNAMLEN 255
+
+struct ffs_direct {
+ uint32 d_ino; /* inode number of entry */
+ uint16 d_reclen; /* length of this record */
+ uint8 d_type; /* file type, see below */
+ uint8 d_namlen; /* length of string in d_name */
+ char d_name[MAXNAMLEN + 1];/* name with length <= MAXNAMLEN */
+};
+
+/*
+ * File types
+ */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
+/*
+ * Convert between stat structure types and directory types.
+ */
+#define IFTODT(mode) (((mode) & 0170000) >> 12)
+#define DTTOIF(dirtype) ((dirtype) << 12)
+
+/*
+ * The DIRSIZ macro gives the minimum record length which will hold
+ * the directory entry. This requires the amount of space in struct direct
+ * without the d_name field, plus enough space for the name with a terminating
+ * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+ */
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+#define DIRSIZ(oldfmt, dp) \
+ ((oldfmt) ? \
+ ((sizeof(struct direct) - (MAXNAMLEN+1)) + (((dp)->d_type+1 + 3) &~ 3)) : \
+ ((sizeof(struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)))
+#else
+#define DIRSIZ(oldfmt, dp) \
+ ((sizeof(struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+#endif
+#define OLDDIRFMT 1
+#define NEWDIRFMT 0
+
+/*
+ * Template for manipulating directories. Should use struct direct's,
+ * but the name field is MAXNAMLEN - 1, and this just won't do.
+ */
+struct dirtemplate {
+ uint32 dot_ino;
+ int16 dot_reclen;
+ uint8 dot_type;
+ uint8 dot_namlen;
+ char dot_name[4]; /* must be multiple of 4 */
+ uint32 dotdot_ino;
+ int16 dotdot_reclen;
+ uint8 dotdot_type;
+ uint8 dotdot_namlen;
+ char dotdot_name[4]; /* ditto */
+};
+
+#endif
+
diff --git a/srv/vfs/drivers/ffs/ffs-blt.h b/srv/vfs/drivers/ffs/ffs-blt.h
@@ -0,0 +1,69 @@
+/* $Id: //depot/blt/srv/vfs/drivers/ffs/ffs-blt.h#2 $
+**
+** Copyright 1998 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FFS_BLT_H
+#define FFS_BLT_H
+
+#include <dirent.h>
+
+struct ffs_super_data
+{
+ blkdev_t *dev;
+ struct ffs_super *sbbuf;
+};
+
+struct ffs_cookie
+{
+ char *buf1, *buf2;
+ int block1, block2;
+};
+
+struct ffs_dircookie
+{
+ struct vfs_dirent_node *head, *current;
+};
+
+int ffs_mount (struct superblock *super, const char *data, int silent);
+void ffs_unmount (struct superblock *super);
+int ffs_read_vnode (struct vnode *vnode);
+void ffs_drop_vnode (struct vnode *vnode);
+struct vnode *ffs_walk (struct vnode *parent, const char *path);
+int ffs_opendir (struct vnode *dir, void **cookie);
+void ffs_closedir (struct vnode *dir, void *cookie);
+void ffs_free_dircookie (void *cookie);
+int ffs_rewinddir (struct vnode *dir, void *cookie);
+int ffs_readdir (struct vnode *dir, struct dirent *dirent, void *cookie);
+int ffs_open (struct vnode *dir, void **cookie);
+int ffs_close (struct vnode *dir, void *cookie);
+void ffs_free_cookie (void *cookie);
+int ffs_read (struct vnode *vnode, char *buf, size_t count, off_t offset,
+ size_t *numbytes, void *cookie);
+int ffs_rstat (struct vnode *vnode, struct stat *buf);
+
+#endif
+
diff --git a/srv/vfs/drivers/ffs/ffs.h b/srv/vfs/drivers/ffs/ffs.h
@@ -0,0 +1,520 @@
+/* $Id: //depot/blt/srv/vfs/drivers/ffs/ffs.h#1 $ */
+/* OpenBSD: fs.h,v 1.8 1998/11/29 00:45:30 art Exp */
+/* NetBSD: fs.h,v 1.6 1995/04/12 21:21:02 mycroft Exp */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fs.h 8.10 (Berkeley) 10/27/94
+ */
+
+#ifndef FFS_H
+#define FFS_H
+
+#ifndef VFS_SANDBOX
+#include <blt/types.h>
+#else
+#include "types.h"
+#endif
+
+/*
+ * Each disk drive contains some number of file systems.
+ * A file system consists of a number of cylinder groups.
+ * Each cylinder group has inodes and data.
+ *
+ * A file system is described by its super-block, which in turn
+ * describes the cylinder groups. The super-block is critical
+ * data and is replicated in each cylinder group to protect against
+ * catastrophic loss. This is done at `newfs' time and the critical
+ * super-block data does not change, so the copies need not be
+ * referenced further unless disaster strikes.
+ *
+ * For file system fs, the offsets of the various blocks of interest
+ * are given in the super block as:
+ * [fs->fs_sblkno] Super-block
+ * [fs->fs_cblkno] Cylinder group block
+ * [fs->fs_iblkno] Inode blocks
+ * [fs->fs_dblkno] Data blocks
+ * The beginning of cylinder group cg in fs, is given by
+ * the ``cgbase(fs, cg)'' macro.
+ *
+ * The first boot and super blocks are given in absolute disk addresses.
+ * The byte-offset forms are preferred, as they don't imply a sector size.
+ */
+#define DEV_BSIZE 512
+#define BBSIZE 8192
+#define SBSIZE 8192
+#define BLKSIZE 8192
+#define BBOFF ((off_t)(0))
+#define SBOFF ((off_t)(BBOFF + BBSIZE))
+#define BBLOCK ((uint32)(0))
+#define SBLOCK ((uint32)(BBLOCK + BBSIZE / DEV_BSIZE))
+
+/*
+ * Addresses stored in inodes are capable of addressing fragments
+ * of `blocks'. File system blocks of at most size MAXBSIZE can
+ * be optionally broken into 2, 4, or 8 pieces, each of which is
+ * addressible; these pieces may be DEV_BSIZE, or some multiple of
+ * a DEV_BSIZE unit.
+ *
+ * Large files consist of exclusively large data blocks. To avoid
+ * undue wasted disk space, the last data block of a small file may be
+ * allocated as only as many fragments of a large block as are
+ * necessary. The file system format retains only a single pointer
+ * to such a fragment, which is a piece of a single large block that
+ * has been divided. The size of such a fragment is determinable from
+ * information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
+ *
+ * The file system records space availability at the fragment level;
+ * to determine block availability, aligned fragments are examined.
+ */
+
+/*
+ * MINBSIZE is the smallest allowable block size.
+ * In order to insure that it is possible to create files of size
+ * 2^32 with only two levels of indirection, MINBSIZE is set to 4096.
+ * MINBSIZE must be big enough to hold a cylinder group block,
+ * thus changes to (struct cg) must keep its size within MINBSIZE.
+ * Note that super blocks are always of size SBSIZE,
+ * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
+ */
+#define MINBSIZE 4096
+
+/*
+ * The path name on which the file system is mounted is maintained
+ * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
+ * the super block for this name.
+ */
+#define MAXMNTLEN 512
+
+/*
+ * The limit on the amount of summary information per file system
+ * is defined by MAXCSBUFS. It is currently parameterized for a
+ * size of 128 bytes (2 million cylinder groups on machines with
+ * 32-bit pointers, and 1 million on 64-bit machines). One pointer
+ * is taken away to point to an array of cluster sizes that is
+ * computed as cylinder groups are inspected.
+ */
+#define MAXCSBUFS ((128 / sizeof(void *)) - 1)
+
+/*
+ * A summary of contiguous blocks of various sizes is maintained
+ * in each cylinder group. Normally this is set by the initial
+ * value of fs_maxcontig. To conserve space, a maximum summary size
+ * is set by FS_MAXCONTIG.
+ */
+#define FS_MAXCONTIG 16
+
+/*
+ * MINFREE gives the minimum acceptable percentage of file system
+ * blocks which may be free. If the freelist drops below this level
+ * only the superuser may continue to allocate blocks. This may
+ * be set to 0 if no reserve of free blocks is deemed necessary,
+ * however throughput drops by fifty percent if the file system
+ * is run at between 95% and 100% full; thus the minimum default
+ * value of fs_minfree is 5%. However, to get good clustering
+ * performance, 10% is a better choice. hence we use 10% as our
+ * default value. With 10% free space, fragmentation is not a
+ * problem, so we choose to optimize for time.
+ */
+#define MINFREE 5
+#define DEFAULTOPT FS_OPTTIME
+
+/*
+ * The file system is made out of blocks of at most MAXBSIZE units, with
+ * smaller units (fragments) only in the last direct block. MAXBSIZE
+ * primarily determines the size of buffers in the buffer pool. It may be
+ * made larger without any effect on existing file systems; however making
+ * it smaller makes some file systems unmountable.
+ */
+#define MAXFRAG 8
+
+/*
+ * Per cylinder group information; summarized in blocks allocated
+ * from first cylinder group data blocks. These blocks have to be
+ * read in from fs_csaddr (size fs_cssize) in addition to the
+ * super block.
+ *
+ * N.B. sizeof(struct csum) must be a power of two in order for
+ * the ``fs_cs'' macro to work (see below).
+ */
+struct csum {
+ int32 cs_ndir; /* number of directories */
+ int32 cs_nbfree; /* number of free blocks */
+ int32 cs_nifree; /* number of free inodes */
+ int32 cs_nffree; /* number of free frags */
+};
+
+/*
+ * Super block for an FFS file system.
+ */
+struct ffs_super {
+ int32 fs_firstfield; /* historic file system linked list, */
+ int32 fs_unused_1; /* used for incore super blocks */
+ uint32 fs_sblkno; /* addr of super-block in filesys */
+ uint32 fs_cblkno; /* offset of cyl-block in filesys */
+ uint32 fs_iblkno; /* offset of inode-blocks in filesys */
+ uint32 fs_dblkno; /* offset of first data after cg */
+ int32 fs_cgoffset; /* cylinder group offset in cylinder */
+ int32 fs_cgmask; /* used to calc mod fs_ntrak */
+ time_t fs_time; /* last time written */
+ int32 fs_size; /* number of blocks in fs */
+ int32 fs_dsize; /* number of data blocks in fs */
+ int32 fs_ncg; /* number of cylinder groups */
+ int32 fs_bsize; /* size of basic blocks in fs */
+ int32 fs_fsize; /* size of frag blocks in fs */
+ int32 fs_frag; /* number of frags in a block in fs */
+/* these are configuration parameters */
+ int32 fs_minfree; /* minimum percentage of free blocks */
+ int32 fs_rotdelay; /* num of ms for optimal next block */
+ int32 fs_rps; /* disk revolutions per second */
+/* these fields can be computed from the others */
+ int32 fs_bmask; /* ``blkoff'' calc of blk offsets */
+ int32 fs_fmask; /* ``fragoff'' calc of frag offsets */
+ int32 fs_bshift; /* ``lblkno'' calc of logical blkno */
+ int32 fs_fshift; /* ``numfrags'' calc number of frags */
+/* these are configuration parameters */
+ int32 fs_maxcontig; /* max number of contiguous blks */
+ int32 fs_maxbpg; /* max number of blks per cyl group */
+/* these fields can be computed from the others */
+ int32 fs_fragshift; /* block to frag shift */
+ int32 fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
+ int32 fs_sbsize; /* actual size of super block */
+ int32 fs_csmask; /* csum block offset */
+ int32 fs_csshift; /* csum block number */
+ int32 fs_nindir; /* value of NINDIR */
+ int32 fs_inopb; /* value of INOPB */
+ int32 fs_nspf; /* value of NSPF */
+/* yet another configuration parameter */
+ int32 fs_optim; /* optimization preference, see below */
+/* these fields are derived from the hardware */
+ int32 fs_npsect; /* # sectors/track including spares */
+ int32 fs_interleave; /* hardware sector interleave */
+ int32 fs_trackskew; /* sector 0 skew, per track */
+/* fs_id takes the space of the unused fs_headswitch and fs_trkseek fields */
+ int32 fs_id[2]; /* unique filesystem id */
+/* sizes determined by number of cylinder groups and their sizes */
+ uint32 fs_csaddr; /* blk addr of cyl grp summary area */
+ int32 fs_cssize; /* size of cyl grp summary area */
+ int32 fs_cgsize; /* cylinder group size */
+/* these fields are derived from the hardware */
+ int32 fs_ntrak; /* tracks per cylinder */
+ int32 fs_nsect; /* sectors per track */
+ int32 fs_spc; /* sectors per cylinder */
+/* this comes from the disk driver partitioning */
+ int32 fs_ncyl; /* cylinders in file system */
+/* these fields can be computed from the others */
+ int32 fs_cpg; /* cylinders per group */
+ int32 fs_ipg; /* inodes per group */
+ int32 fs_fpg; /* blocks per group * fs_frag */
+/* this data must be re-computed after crashes */
+ struct csum fs_cstotal; /* cylinder summary information */
+/* these fields are cleared at mount time */
+ int8 fs_fmod; /* super block modified flag */
+ int8 fs_clean; /* file system is clean flag */
+ int8 fs_ronly; /* mounted read-only flag */
+ int8 fs_flags; /* see FS_ below */
+ uint8 fs_fsmnt[MAXMNTLEN]; /* name mounted on */
+/* these fields retain the current block allocation info */
+ int32 fs_cgrotor; /* last cg searched */
+ struct csum *fs_csp[MAXCSBUFS];/* list of fs_cs info buffers */
+ int32 *fs_maxcluster; /* max cluster in each cyl group */
+ int32 fs_cpc; /* cyl per cycle in postbl */
+ int16 fs_opostbl[16][8]; /* old rotation block list head */
+ int32 fs_sparecon[49]; /* reserved for future constants */
+ time_t fs_fscktime; /* last time fsck(8)ed */
+ int32 fs_contigsumsize; /* size of cluster summary array */
+ int32 fs_maxsymlinklen; /* max length of an internal symlink */
+ int32 fs_inodefmt; /* format of on-disk inodes */
+ uint64 fs_maxfilesize; /* maximum representable file size */
+ int64 fs_qbmask; /* ~fs_bmask - for use with quad size */
+ int64 fs_qfmask; /* ~fs_fmask - for use with quad size */
+ int32 fs_state; /* validate fs_clean field */
+ int32 fs_postblformat; /* format of positional layout tables */
+ int32 fs_nrpos; /* number of rotational positions */
+ int32 fs_postbloff; /* (u_int16) rotation block list head */
+ int32 fs_rotbloff; /* (u_int8) blocks for each rotation */
+ int32 fs_magic; /* magic number */
+ uint8 fs_space[1]; /* list of blocks for each rotation */
+/* actually longer */
+};
+
+/*
+ * Filesystem identification
+ */
+#define FS_MAGIC 0x011954 /* the fast filesystem magic number */
+#define FS_OKAY 0x7c269d38 /* superblock checksum */
+#define FS_42INODEFMT -1 /* 4.2BSD inode format */
+#define FS_44INODEFMT 2 /* 4.4BSD inode format */
+
+/*
+ * Filesystem clean flags
+ */
+#define FS_ISCLEAN 0x01
+#define FS_WASCLEAN 0x02
+
+/*
+ * Preference for optimization.
+ */
+#define FS_OPTTIME 0 /* minimize allocation time */
+#define FS_OPTSPACE 1 /* minimize disk fragmentation */
+
+/*
+ * Filesystem flags.
+ */
+#define FS_UNCLEAN 0x01 /* filesystem not clean at mount */
+#define FS_DOSOFTDEP 0x02 /* filesystem using soft dependencies */
+
+/*
+ * Rotational layout table format types
+ */
+#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */
+#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */
+/*
+ * Macros for access to superblock array structures
+ */
+#define fs_postbl(fs, cylno) \
+ (((fs)->fs_postblformat == FS_42POSTBLFMT) \
+ ? ((fs)->fs_opostbl[cylno]) \
+ : ((int16 *)((uint8 *)(fs) + \
+ (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos))
+#define fs_rotbl(fs) \
+ (((fs)->fs_postblformat == FS_42POSTBLFMT) \
+ ? ((fs)->fs_space) \
+ : ((uint8 *)((uint8 *)(fs) + (fs)->fs_rotbloff)))
+
+/*
+ * The size of a cylinder group is calculated by CGSIZE. The maximum size
+ * is limited by the fact that cylinder groups are at most one block.
+ * Its size is derived from the size of the maps maintained in the
+ * cylinder group and the (struct cg) size.
+ */
+#define CGSIZE(fs) \
+ /* base cg */ (sizeof(struct cg) + sizeof(int32) + \
+ /* blktot size */ (fs)->fs_cpg * sizeof(int32) + \
+ /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(int16) + \
+ /* inode map */ howmany((fs)->fs_ipg, NBBY) + \
+ /* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY) +\
+ /* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \
+ /* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32) + \
+ /* cluster map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPB(fs), NBBY)))
+
+/*
+ * Convert cylinder group to base address of its global summary info.
+ *
+ * N.B. This macro assumes that sizeof(struct csum) is a power of two.
+ */
+#define fs_cs(fs, indx) \
+ fs_csp[(indx) >> (fs)->fs_csshift][(indx) & ~(fs)->fs_csmask]
+
+/*
+ * Cylinder group block for a file system.
+ */
+#define CG_MAGIC 0x090255
+struct cg {
+ int32 cg_firstfield; /* historic cyl groups linked list */
+ int32 cg_magic; /* magic number */
+ time_t cg_time; /* time last written */
+ int32 cg_cgx; /* we are the cgx'th cylinder group */
+ int16 cg_ncyl; /* number of cyl's this cg */
+ int16 cg_niblk; /* number of inode blocks this cg */
+ int32 cg_ndblk; /* number of data blocks this cg */
+ struct csum cg_cs; /* cylinder summary information */
+ int32 cg_rotor; /* position of last used block */
+ int32 cg_frotor; /* position of last used frag */
+ int32 cg_irotor; /* position of last used inode */
+ int32 cg_frsum[MAXFRAG]; /* counts of available frags */
+ int32 cg_btotoff; /* (int32) block totals per cylinder */
+ int32 cg_boff; /* (u_int16) free block positions */
+ int32 cg_iusedoff; /* (u_int8) used inode map */
+ int32 cg_freeoff; /* (u_int8) free block map */
+ int32 cg_nextfreeoff; /* (u_int8) next available space */
+ int32 cg_clustersumoff; /* (u_int32) counts of avail clusters */
+ int32 cg_clusteroff; /* (u_int8) free cluster map */
+ int32 cg_nclusterblks; /* number of clusters this cg */
+ int32 cg_sparecon[13]; /* reserved for future use */
+ uint8 cg_space[1]; /* space for cylinder group maps */
+/* actually longer */
+};
+
+/*
+ * Macros for access to cylinder group array structures
+ */
+#define cg_blktot(cgp) \
+ (((cgp)->cg_magic != CG_MAGIC) \
+ ? (((struct ocg *)(cgp))->cg_btot) \
+ : ((int32 *)((uint8 *)(cgp) + (cgp)->cg_btotoff)))
+#define cg_blks(fs, cgp, cylno) \
+ (((cgp)->cg_magic != CG_MAGIC) \
+ ? (((struct ocg *)(cgp))->cg_b[cylno]) \
+ : ((int16 *)((uint8 *)(cgp) + \
+ (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos))
+#define cg_inosused(cgp) \
+ (((cgp)->cg_magic != CG_MAGIC) \
+ ? (((struct ocg *)(cgp))->cg_iused) \
+ : ((uint8 *)((uint8 *)(cgp) + (cgp)->cg_iusedoff)))
+#define cg_blksfree(cgp) \
+ (((cgp)->cg_magic != CG_MAGIC) \
+ ? (((struct ocg *)(cgp))->cg_free) \
+ : ((uint8 *)((uint8 *)(cgp) + (cgp)->cg_freeoff)))
+#define cg_chkmagic(cgp) \
+ ((cgp)->cg_magic == CG_MAGIC || ((struct ocg *)(cgp))->cg_magic == CG_MAGIC)
+#define cg_clustersfree(cgp) \
+ ((uint8 *)((uint8 *)(cgp) + (cgp)->cg_clusteroff))
+#define cg_clustersum(cgp) \
+ ((int32 *)((uint8 *)(cgp) + (cgp)->cg_clustersumoff))
+
+/*
+ * Turn file system block numbers into disk block addresses.
+ * This maps file system blocks to device size blocks.
+ */
+#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb)
+#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb)
+
+/*
+ * Cylinder group macros to locate things in cylinder groups.
+ * They calc file system addresses of cylinder group data structures.
+ */
+#define cgbase(fs, c) ((uint32)((fs)->fs_fpg * (c)))
+#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */
+#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */
+#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */
+#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */
+#define cgstart(fs, c) \
+ (cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask)))
+
+/*
+ * Macros for handling inode numbers:
+ * inode number to file system block offset.
+ * inode number to cylinder group number.
+ * inode number to file system block address.
+ */
+#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg)
+#define ino_to_fsba(fs, x) \
+ ((uint32)(cgimin((fs), ino_to_cg((fs), x)) + \
+ (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
+#define ino_to_fsbo(fs, x) ((x) % INOPB(fs))
+
+/*
+ * Give cylinder group number for a file system block.
+ * Give cylinder group block number for a file system block.
+ */
+#define dtog(fs, d) ((d) / (fs)->fs_fpg)
+#define dtogd(fs, d) ((d) % (fs)->fs_fpg)
+
+/*
+ * Extract the bits for a block from a map.
+ * Compute the cylinder and rotational position of a cyl block addr.
+ */
+#define blkmap(fs, map, loc) \
+ (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
+#define cbtocylno(fs, bno) \
+ ((bno) * NSPF(fs) / (fs)->fs_spc)
+#define cbtorpos(fs, bno) \
+ (((bno) * NSPF(fs) % (fs)->fs_spc / (fs)->fs_nsect * (fs)->fs_trackskew + \
+ (bno) * NSPF(fs) % (fs)->fs_spc % (fs)->fs_nsect * (fs)->fs_interleave) % \
+ (fs)->fs_nsect * (fs)->fs_nrpos / (fs)->fs_npsect)
+
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
+ ((loc) & (fs)->fs_qbmask)
+#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \
+ ((loc) & (fs)->fs_qfmask)
+#define lblktosize(fs, blk) /* calculates (blk * fs->fs_bsize) */ \
+ ((blk) << (fs)->fs_bshift)
+#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
+ ((loc) >> (fs)->fs_bshift)
+#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
+ ((loc) >> (fs)->fs_fshift)
+#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \
+ (((size) + (fs)->fs_qbmask) & (fs)->fs_bmask)
+#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
+ (((size) + (fs)->fs_qfmask) & (fs)->fs_fmask)
+#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
+ ((frags) >> (fs)->fs_fragshift)
+#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
+ ((blks) << (fs)->fs_fragshift)
+#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \
+ ((fsb) & ((fs)->fs_frag - 1))
+#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \
+ ((fsb) &~ ((fs)->fs_frag - 1))
+
+/*
+ * Determine the number of available frags given a
+ * percentage to hold in reserve.
+ */
+#define freespace(fs, percentreserved) \
+ (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
+ (fs)->fs_cstotal.cs_nffree - ((fs)->fs_dsize * (percentreserved) / 100))
+
+/*
+ * Determining the size of a file block in the file system.
+ */
+#define blksize(fs, ip, lbn) \
+ (((lbn) >= NDADDR || (ip)->i_ffs_size >= ((lbn) + 1) << (fs)->fs_bshift) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (ip)->i_ffs_size))))
+#define dblksize(fs, dip, lbn) \
+ (((lbn) >= NDADDR || (dip)->di_size >= ((lbn) + 1) << (fs)->fs_bshift) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (dip)->di_size))))
+
+#define sblksize(fs, size, lbn) \
+ (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (size)))))
+
+
+/*
+ * Number of disk sectors per block/fragment; assumes DEV_BSIZE byte
+ * sector size.
+ */
+#define NSPB(fs) ((fs)->fs_nspf << (fs)->fs_fragshift)
+#define NSPF(fs) ((fs)->fs_nspf)
+
+/*
+ * Number of inodes in a secondary storage block/fragment.
+ */
+#define INOPB(fs) ((fs)->fs_inopb)
+#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift)
+
+/*
+ * Number of indirects in a file system block.
+ */
+#define NINDIR(fs) ((fs)->fs_nindir)
+
+#endif
+
diff --git a/srv/vfs/drivers/ffs/file.c b/srv/vfs/drivers/ffs/file.c
@@ -0,0 +1,201 @@
+/* $Id: //depot/blt/srv/vfs/drivers/ffs/file.c#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "vfs-int.h"
+
+#ifndef VFS_SANDBOX
+#include <blt/blkdev.h>
+#else
+#include "../../sandbox/blkdev.h"
+#endif
+
+#include "ffs.h"
+#include "ffs-blt.h"
+#include "dinode.h"
+
+int ffs_open (struct vnode *vnode, void **cookie)
+{
+ struct ffs_super_data *data;
+ struct ffs_dinode *inode;
+ struct ffs_cookie *fc;
+
+#ifdef FFS_DEBUG
+ printf ("ffs_open %lld\n", vnode->v_vnid);
+#endif
+ data = vnode->v_sb->sb_data;
+ inode = vnode->v_data;
+ fc = malloc (sizeof (struct ffs_cookie));
+ *cookie = fc;
+ return 0;
+}
+
+int ffs_close (struct vnode *vnode, void *cookie)
+{
+#ifdef FFS_DEBUG
+ printf ("ffs_close %lld\n", vnode->v_vnid);
+#endif
+ return 0;
+}
+
+void ffs_free_cookie (void *cookie)
+{
+#ifdef FFS_DEBUG
+ printf ("ffs_free_cookie\n");
+#endif
+ free (cookie);
+}
+
+static inline int32 ffs_fbtofsb (struct ffs_super *fs, blkdev_t *dev,
+ struct ffs_dinode *di, uint32 fb)
+{
+ int32 *buf, res;
+
+ if (fb < NDADDR)
+ return di->di_db[fb];
+ else if ((fb -= NDADDR) < NINDIR (fs))
+ {
+ buf = malloc (BLKSIZE);
+ blk_read (dev, buf, fsbtodb (fs, di->di_ib[0]), BLKSIZE / dev->blksize);
+ res = buf[fb];
+ free (buf);
+ return res;
+ }
+ else if ((fb -= NINDIR (fs)) < NINDIR (fs) * NINDIR (fs))
+ {
+ printf ("ffs: doubly indirect blocks unsupported.\n");
+ return 0;
+ }
+ else if ((fb -= NINDIR (fs) * NINDIR (fs)) < NINDIR (fs) * NINDIR (fs) *
+ NINDIR (fs))
+ {
+ printf ("ffs: trebly indirect blocks unsupported.\n");
+ return 0;
+ }
+ else
+ return -1;
+}
+
+int ffs_read (struct vnode *vnode, char *buf, size_t count, off_t pos,
+ size_t *numbytes, void *cookie)
+{
+ char *temp;
+ int i, block;
+ off_t offset, len;
+ struct ffs_super *fs;
+ struct ffs_super_data *data;
+ struct ffs_dinode *di;
+
+#ifdef FFS_DEBUG
+ printf ("ffs_read %lld %d\n", pos, count);
+#endif
+ *numbytes = 0;
+ if (!count)
+ return 0;
+ data = vnode->v_sb->sb_data;
+ fs = data->sbbuf;
+ di = vnode->v_data;
+ if (pos >= di->di_size)
+ return 0;
+ if (pos + count > di->di_size)
+ count = di->di_size - pos;
+ temp = malloc (BLKSIZE);
+
+ /*
+ * if we are not starting at a block boundary, first read up to the
+ * next block boundary.
+ */
+ if ((offset = pos % BLKSIZE))
+ {
+ block = ffs_fbtofsb (fs, data->dev, di, pos / BLKSIZE);
+ len = (count < (BLKSIZE - offset)) ? count : (BLKSIZE - offset);
+ blk_read (data->dev, temp, fsbtodb (fs, block), BLKSIZE /
+ data->dev->blksize);
+ memcpy (buf, temp + offset, len);
+ *numbytes += len, pos += len;
+#ifdef FFS_DEBUG
+ printf ("ffs_read: (1) %lld\n", len);
+#endif
+ }
+ if (*numbytes == count)
+ goto done;
+
+ /*
+ * now we are block-aligned; read whole blocks at a time until we have
+ * less than a full block to go.
+ */
+ for (i = 0; i < ((count - *numbytes) / BLKSIZE); i++, *numbytes += BLKSIZE,
+ pos += BLKSIZE)
+ {
+ block = ffs_fbtofsb (fs, data->dev, di, pos / BLKSIZE);
+ blk_read (data->dev, temp, fsbtodb (fs, block), BLKSIZE /
+ data->dev->blksize);
+ memcpy (buf + *numbytes, temp, BLKSIZE);
+#ifdef FFS_DEBUG
+ printf ("ffs_read: (2) #%d\n", i);
+#endif
+ }
+ if (*numbytes == count)
+ goto done;
+
+ /*
+ * read in the next block and copy as much as we need.
+ */
+ block = ffs_fbtofsb (fs, data->dev, di, pos / BLKSIZE);
+ blk_read (data->dev, temp, fsbtodb (fs, block), BLKSIZE /
+ data->dev->blksize);
+ memcpy (buf + *numbytes, temp, len = count - *numbytes);
+ *numbytes += len, pos += len;
+#ifdef FFS_DEBUG
+ printf ("ffs_read: (3) %lld\n", len);
+#endif
+
+done:
+ free (temp);
+ return 0;
+}
+
+int ffs_rstat (struct vnode *vnode, struct stat *buf)
+{
+ struct ffs_dinode *di;
+#ifdef FFS_DEBUG
+ printf ("ffs_rstat %lld\n", vnode->v_vnid);
+#endif
+
+ di = vnode->v_data;
+ buf->st_ino = vnode->v_vnid;
+ buf->st_nlink = di->di_nlink;
+ buf->st_uid = di->di_uid;
+ buf->st_gid = di->di_gid;
+ buf->st_size = di->di_size;
+ buf->st_blocks = di->di_blocks;
+ return 0;
+}
+
diff --git a/srv/vfs/drivers/ffs/inode.c b/srv/vfs/drivers/ffs/inode.c
@@ -0,0 +1,141 @@
+/* $Id: //depot/blt/srv/vfs/drivers/ffs/inode.c#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "vfs-int.h"
+
+#ifndef VFS_SANDBOX
+#include <blt/blkdev.h>
+#else
+#include "../../sandbox/blkdev.h"
+#endif
+
+#include "ffs.h"
+#include "ffs-blt.h"
+#include "dinode.h"
+#include "dir.h"
+
+int ffs_read_vnode (struct vnode *vnode)
+{
+ char *buf;
+ int block, offset;
+ struct ffs_super *fs;
+ struct ffs_super_data *data;
+ struct ffs_dinode *di;
+
+#ifdef FFS_DEBUG
+ printf ("ffs_read_vnode %lld\n", vnode->v_vnid);
+#endif
+ data = vnode->v_sb->sb_data;
+ fs = data->sbbuf;
+ vnode->v_data = di = malloc (sizeof (struct ffs_dinode));
+ buf = malloc (BLKSIZE);
+ block = fsbtodb (fs, ino_to_fsba (fs, (int) vnode->v_vnid));
+ offset = ino_to_fsbo (fs, (int) vnode->v_vnid);
+ blk_read (data->dev, buf, block, BLKSIZE / data->dev->blksize);
+ memcpy (di, (struct ffs_dinode *) buf + offset, sizeof (struct ffs_dinode));
+ free (buf);
+ return 0;
+}
+
+void ffs_drop_vnode (struct vnode *vnode)
+{
+#ifdef FFS_DEBUG
+ printf ("ffs_drop_vnode %lld\n", vnode->v_vnid);
+#endif
+ free (vnode->v_data);
+}
+
+static struct vnode *ffs_walk_one (struct vnode *parent, const char *path)
+{
+ char *buf;
+ int i, offset;
+ struct ffs_super *fs;
+ struct ffs_super_data *data;
+ struct ffs_dinode *di;
+ struct ffs_direct *direct;
+
+#ifdef FFS_DEBUG
+ printf ("ffs_walk_one %s\n", path);
+#endif
+ data = parent->v_sb->sb_data;
+ fs = data->sbbuf;
+ di = parent->v_data;
+ buf = malloc (BLKSIZE);
+
+ for (i = 0; i < NDADDR; i++)
+ if (di->di_db[i])
+ {
+ blk_read (data->dev, buf, fsbtodb (fs, di->di_db[i]),
+ BLKSIZE / data->dev->blksize);
+ for (offset = 0; offset < BLKSIZE; offset += direct->d_reclen)
+ {
+ direct = (struct ffs_direct *) (buf + offset);
+ if (!strcmp (direct->d_name, path))
+ return vget (parent->v_sb, direct->d_ino);
+ }
+ }
+ printf ("ffs_walk_one: failage 1!\n");
+
+ for (i = 0; i < NIADDR; i++)
+ if (di->di_ib[i])
+ {
+ printf ("ffs_walk_one: indirect %d\n", di->di_ib[i]);
+ }
+
+ free (buf);
+ printf ("ffs_walk_one: failage 2!\n");
+ return NULL;
+}
+
+struct vnode *ffs_walk (struct vnode *parent, const char *path)
+{
+ char *name;
+ int i, j, len;
+ struct vnode *vn, *vnnext;
+
+#ifdef FFS_DEBUG
+ printf ("ffs_walk %s\n", path);
+#endif
+ vn = parent;
+ name = malloc ((len = strlen (path)) + 1);
+ strcpy (name, path);
+
+ for (i = 0; i < strlen (path); i = j + 1, vn = vnnext)
+ {
+ for (j = i; (name[j] != '/') && (j < len); j++) ;
+ name[j] = 0;
+ vnnext = ffs_walk_one (vn, name + i);
+ if (vn != parent)
+ vput (vn);
+ }
+ return vn;
+}
+
diff --git a/srv/vfs/drivers/ffs/super.c b/srv/vfs/drivers/ffs/super.c
@@ -0,0 +1,101 @@
+/* $Id: //depot/blt/srv/vfs/drivers/ffs/super.c#4 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "vfs-int.h"
+
+#ifndef VFS_SANDBOX
+#include <blt/blkdev.h>
+#else
+#include "../../sandbox/blkdev.h"
+#endif
+
+#include "ffs.h"
+#include "ffs-blt.h"
+#include "dinode.h"
+
+static struct vnode_ops ffs_vnode_ops =
+{
+ ffs_read_vnode, ffs_drop_vnode, NULL, NULL, ffs_walk, NULL,
+ ffs_mount, ffs_unmount, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ ffs_opendir, ffs_closedir, ffs_free_dircookie, ffs_rewinddir, ffs_readdir,
+ ffs_open, ffs_close, ffs_free_cookie, ffs_read, NULL, NULL, NULL,
+ ffs_rstat, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+};
+
+static struct fs_type ffs = { "ffs", &ffs_vnode_ops, NULL };
+
+int _init (void)
+{
+#ifdef FFS_DEBUG
+ printf ("ffs: registering driver\n");
+#endif
+ fs_register (&ffs);
+ return 0;
+}
+
+int ffs_mount (struct superblock *super, const char *data, int silent)
+{
+ struct ffs_super_data *sbdata;
+ struct ffs_super *ds;
+
+#ifdef FFS_DEBUG
+ printf ("ffs_mount, data `%s'\n", data);
+#endif
+ sbdata = malloc (sizeof (struct ffs_super_data));
+ blk_open (data, 0, &sbdata->dev);
+ super->sb_data = sbdata;
+ sbdata->sbbuf = ds = malloc (SBSIZE);
+ blk_read (sbdata->dev, ds, SBOFF / sbdata->dev->blksize,
+ SBSIZE / sbdata->dev->blksize);
+ super->sb_root = vget (super, ROOTINO);
+ super->sb_dev = malloc (strlen (data) + 1);
+ strcpy (super->sb_dev, data);
+ return 0;
+}
+
+void ffs_unmount (struct superblock *super)
+{
+ struct ffs_super_data *sbdata;
+
+#ifdef FFS_DEBUG
+ printf ("ffs_unmount\n");
+#endif
+ vput (super->sb_root);
+ sbdata = super->sb_data;
+ blk_close (sbdata->dev);
+ free (sbdata->sbbuf);
+ free (sbdata);
+}
+
diff --git a/srv/vfs/fs.c b/srv/vfs/fs.c
@@ -0,0 +1,77 @@
+/* $Id: //depot/blt/srv/vfs/fs.c#1 $
+**
+** Copyright 1998 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include "vfs-int.h"
+
+int fs_register (struct fs_type *driver)
+{
+ struct fs_type *p;
+
+ if (fs_drivers == NULL)
+ {
+ fs_drivers = driver;
+ fs_drivers->next = NULL;
+ return 0;
+ }
+ else
+ {
+ p = fs_drivers;
+ while (p->next != NULL)
+ {
+ if (!strcmp (p->name, driver->name))
+ return 1;
+ p = p->next;
+ }
+ p->next = driver;
+ driver->next = NULL;
+ return 0;
+ }
+}
+
+struct superblock *fs_find (const char *node)
+{
+ int len, bestlen;
+ struct superblock *super, *best;
+
+ super = mount_list;
+ len = bestlen = 0;
+ best = NULL;
+ while (super != NULL)
+ {
+ if (!strncmp (super->sb_dir, node, len = strlen (super->sb_dir)))
+ if (len > bestlen)
+ {
+ best = super;
+ bestlen = len;
+ }
+ super = super->sb_next;
+ }
+ return best;
+}
+
diff --git a/srv/vfs/path.c b/srv/vfs/path.c
@@ -0,0 +1,97 @@
+/* $Id: //depot/blt/srv/vfs/path.c#2 $
+**
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include "path.h"
+
+char *path_concat (char *s, const char *t)
+{
+ char *c;
+
+ c = s;
+ while (*c++) ;
+ c--;
+
+ while (*t) /* for each component */
+ if (*t == '/')
+ *c++ = *t++;
+ else if (*t != '.') /* normal component */
+ while (*t && (*t != '/'))
+ *c++ = *t++;
+ else /* doesn't begin with . or / */
+ {
+ t++;
+ if ((*t == '/') || !*t) /* ./ component */
+ t++;
+ else if (*t == '.') /* ../ component */
+ {
+ if (c != s + 1) /* can't .. from the root dir */
+ {
+ c -= 2;
+ while ((c != s) && (*c != '/'))
+ c--;
+ c++;
+ t++;
+ if (*t == '/')
+ t++;
+ }
+ }
+ else /* component beginning with a period */
+ {
+ *c++ = '.';
+ while (*t && (*t != '/'))
+ *c++ = *t++;
+ }
+ }
+
+ *c = 0;
+ if (((c - 1) != s) && (c[-1] == '/'))
+ c[-1] = 0;
+
+ return s;
+}
+
+char *path_combine (const char *s, const char *t, char *d)
+{
+ const char *c;
+ char *node;
+
+ *d = 0;
+ node = d;
+ if (*t == '/')
+ return path_concat (node, t);
+
+ c = s;
+ while (*c)
+ *d++ = *c++;
+ if (*d != '/')
+ *d++ = '/';
+
+ return path_concat (node, t);
+}
+
diff --git a/srv/vfs/path.h b/srv/vfs/path.h
@@ -0,0 +1,36 @@
+/* $Id: //depot/blt/srv/vfs/path.h#2 $
+**
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _PATH_H_
+#define _PATH_H_
+
+char *path_concat (char *s, const char *t);
+char *path_combine (const char *s, const char *t, char *d);
+
+#endif
+
diff --git a/srv/vfs/rootfs.c b/srv/vfs/rootfs.c
@@ -0,0 +1,218 @@
+/* $Id: //depot/blt/srv/vfs/rootfs.c#3 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "vfs-int.h"
+#include "rootfs.h"
+
+static int inode_max = 0;
+
+static struct vnode_ops rootfs_vnode_ops =
+{
+ rootfs_read_vnode, rootfs_drop_vnode, NULL, NULL, rootfs_walk, NULL,
+ rootfs_mount, rootfs_unmount, NULL, NULL, NULL, NULL,
+ NULL, rootfs_mkdir, NULL, NULL, NULL, NULL, NULL, NULL,
+ rootfs_opendir, rootfs_closedir, NULL, rootfs_rewinddir, rootfs_readdir,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+};
+
+struct fs_type rootfs = { "rootfs", &rootfs_vnode_ops, NULL };
+
+static struct rootfs_inode *rootfs_inew (const char *name)
+{
+ struct rootfs_inode *i;
+
+ i = malloc (sizeof (struct rootfs_inode));
+ i->i_ino = inode_max++;
+ i->i_name = malloc (strlen (name) + 1);
+ strcpy (i->i_name, name);
+ i->i_next = NULL;
+ return i;
+}
+
+int rootfs_mount (struct superblock *super, const char *data, int silent)
+{
+ struct rootfs_inode *ri;
+
+#ifdef ROOTFS_DEBUG
+ printf ("rootfs_mount\n");
+#endif
+ super->sb_data = ri = rootfs_inew (".");
+ ri->i_next = rootfs_inew ("..");
+ super->sb_root = vget (super, 0);
+ return 0;
+}
+
+void rootfs_unmount (struct superblock *super)
+{
+#ifdef ROOTFS_DEBUG
+ printf ("rootfs_unmount\n");
+#endif
+}
+
+int rootfs_read_vnode (struct vnode *vnode)
+{
+ struct rootfs_inode *inode;
+
+#ifdef ROOTFS_DEBUG
+ printf ("rootfs_read_vnode %llx\n", vnode->v_vnid);
+#endif
+ inode = vnode->v_sb->sb_data;
+ while (inode != NULL)
+ if (inode->i_ino == vnode->v_vnid)
+ {
+ vnode->v_data = inode;
+ return 0;
+ }
+ else
+ inode = inode->i_next;
+ return -1;
+}
+
+void rootfs_drop_vnode (struct vnode *vnode)
+{
+ vnode->v_data = NULL;
+}
+
+struct vnode *rootfs_walk (struct vnode *parent, const char *path)
+{
+ struct rootfs_inode *inode;
+
+#ifdef ROOTFS_DEBUG
+ printf ("rootfs_walk %llx %s\n", parent->v_vnid, path);
+#endif
+ inode = parent->v_data;
+ while (inode != NULL)
+ if (strcmp (inode->i_name, path))
+ inode = inode->i_next;
+ else
+ return vget (parent->v_sb, inode->i_ino);
+ return NULL;
+}
+
+int rootfs_mkdir (struct vnode *parent, const char *name, mode_t mode)
+{
+ struct rootfs_inode *inode, *p;
+
+#ifdef ROOTFS_DEBUG
+ printf ("rootfs_mkdir %llx %s\n", parent->v_vnid, name);
+#endif
+ if (parent->v_vnid)
+ return -1; /* paranoia */
+
+ inode = malloc (sizeof (struct rootfs_inode));
+ inode->i_ino = inode_max++;
+ inode->i_name = malloc (strlen (name) + 1);
+ strcpy (inode->i_name, name);
+ inode->i_next = NULL;
+
+ p = parent->v_sb->sb_data;
+ while (p->i_next != NULL)
+ p = p->i_next;
+ p->i_next = inode;
+ return 0;
+}
+
+int rootfs_opendir (struct vnode *dir, void **cookie)
+{
+ struct vfs_dirent_node *head, *p;
+ struct rootfs_inode *inode;
+ union rootfs_cookie *rc;
+
+#ifdef ROOTFS_DEBUG
+ printf ("rootfs_opendir\n");
+#endif
+ if (dir->v_vnid)
+ return ENOTDIR; /* paranoia */
+
+ head = NULL;
+ inode = dir->v_sb->sb_data;
+ while (inode != NULL)
+ {
+ p = malloc (sizeof (struct vfs_dirent_node));
+ p->dirent = malloc (sizeof (struct dirent));
+ p->dirent->d_fileno = inode->i_ino;
+ p->dirent->d_reclen = sizeof (struct dirent);
+ strncpy (p->dirent->d_name, inode->i_name, sizeof (p->dirent->d_name));
+
+ p->next = head;
+ head = p;
+ inode = inode->i_next;
+ }
+
+ rc = malloc (sizeof (union rootfs_cookie));
+ rc->u_dir.head = rc->u_dir.current = head;
+ *cookie = rc;
+ return 0;
+}
+
+void rootfs_closedir (struct vnode *dir, void *cookie)
+{
+#ifdef ROOTFS_DEBUG
+ printf ("rootfs_closedir\n");
+#endif
+}
+
+int rootfs_rewinddir (struct vnode *dir, void *cookie)
+{
+ union rootfs_cookie *rc;
+
+#ifdef ROOTFS_DEBUG
+ printf ("rootfs_rewinddir\n");
+#endif
+
+ rc = cookie;
+ rc->u_dir.current = rc->u_dir.head;
+ return 0;
+}
+
+int rootfs_readdir (struct vnode *dir, struct dirent *dirent, void *cookie)
+{
+ struct dirent *orig;
+ union rootfs_cookie *rc;
+
+ rc = cookie;
+ if (rc->u_dir.current == NULL)
+ return 1;
+ orig = rc->u_dir.current->dirent;
+ dirent->d_fileno = orig->d_fileno;
+ dirent->d_reclen = orig->d_reclen;
+ strncpy (dirent->d_name, orig->d_name, BLT_MAX_NAME_LENGTH);
+ rc->u_dir.current = rc->u_dir.current->next;
+#ifdef ROOTFS_DEBUG
+ printf ("rootfs_readdir %s\n", dirent->d_name);
+#endif
+ return 0;
+}
+
diff --git a/srv/vfs/rootfs.h b/srv/vfs/rootfs.h
@@ -0,0 +1,67 @@
+/* $Id: //depot/blt/srv/vfs/rootfs.h#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _ROOTFS_H_
+#define _ROOTFS_H_
+
+#include "vfs-int.h"
+
+struct rootfs_inode
+{
+ int i_ino;
+ char *i_name;
+ struct rootfs_inode *i_next;
+};
+
+union rootfs_cookie
+{
+ struct
+ {
+ struct vfs_dirent_node *head, *current;
+ } u_dir;
+ struct
+ {
+ int pos;
+ } u_file;
+};
+
+static struct rootfs_inode *rootfs_inew (const char *name);
+
+int rootfs_mount (struct superblock *sb, const char *data, int silent);
+void rootfs_unmount (struct superblock *super);
+int rootfs_read_vnode (struct vnode *vnode);
+void rootfs_drop_vnode (struct vnode *vnode);
+struct vnode *rootfs_walk (struct vnode *vnode, const char *path);
+int rootfs_mkdir (struct vnode *vnode, const char *name, mode_t mode);
+int rootfs_opendir (struct vnode *dir, void **cookie);
+void rootfs_closedir (struct vnode *dir, void *cookie);
+int rootfs_readdir (struct vnode *dir, struct dirent *dirent, void *cookie);
+int rootfs_rewinddir (struct vnode *dir, void *cookie);
+
+#endif
+
diff --git a/srv/vfs/sandbox/Makefile b/srv/vfs/sandbox/Makefile
@@ -0,0 +1,14 @@
+# $Id: //depot/blt/srv/vfs/sandbox/Makefile#2 $
+
+CFLAGS = $(CF) -I. -Wall -g -DVFS_SANDBOX
+LIBS =
+OBJS = vfs.o blkdev.o ../fs.o ../super.o ../vnode.o ../../../lib/libblt/hash.o
+EXEC = vfs
+
+all: $(EXEC)
+
+$(EXEC): $(OBJS)
+ $(CC) -o $(EXEC) $(OBJS) $(LIBS)
+
+clean:
+ rm -f *.o *~ core *.core $(EXEC)
diff --git a/srv/vfs/sandbox/README b/srv/vfs/sandbox/README
@@ -0,0 +1,17 @@
+This is a test harness for developing filesystem drivers under UNIX to
+be used on OpenBLT. Its design was inspired by a similar system written
+by Dominic Giampaolo for designing BFS as described in *Practical
+Filesystem Design with the Be File System*.
+
+This code is guaranteed to build on OpenBSD/sparc, but should build on
+other UNIX systems. It will probably also build on UNIX-like systems
+such as Linux. I will eventually make it work on BeOS. To build, type
+`make' as this is not built during a normal build.
+
+
+Some caveats:
+
+ - add -DVFS_SANDBOX to $(CF) in make.conf
+ - if you're using this on an architecture other than Intel, remember
+ to rebuild the driver you're testing, fs.o, super.o, and hash.o
+
diff --git a/srv/vfs/sandbox/blkdev.c b/srv/vfs/sandbox/blkdev.c
@@ -0,0 +1,78 @@
+/* $Id: //depot/blt/srv/vfs/sandbox/blkdev.c#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "blkdev.h"
+
+int blk_open (const char *name, int flags, blkdev_t **retdev)
+{
+ int fd;
+ struct stat statbuf;
+
+ if (stat (name, &statbuf))
+ {
+ *retdev = NULL;
+ return -1;
+ }
+ if ((fd = open (name, O_RDONLY, 0)) < 0)
+ {
+ *retdev = NULL;
+ return -1;
+ }
+ *retdev = malloc (sizeof (blkdev_t));
+ (*retdev)->blksize = 512;
+ (*retdev)->devno = fd;
+ return 0;
+}
+
+int blk_close (blkdev_t *dev)
+{
+ close (dev->devno);
+ free (dev);
+ return 0;
+}
+
+int blk_read (blkdev_t *dev, void *buf, int block, int count)
+{
+ int i;
+
+ lseek (dev->devno, block * dev->blksize, SEEK_SET);
+ for (i = 0; i < count; i++)
+ read (dev->devno, buf + dev->blksize * i, dev->blksize);
+ return 0;
+}
+
+int blk_write (blkdev_t dev, const void *buf, int block, int count)
+{
+ return 0;
+}
+
diff --git a/srv/vfs/sandbox/blkdev.h b/srv/vfs/sandbox/blkdev.h
@@ -0,0 +1,48 @@
+/* $Id: //depot/blt/srv/vfs/sandbox/blkdev.h#1 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef SANDBOX_BLKDEV_H
+#define SANDBOX_BLKDEV_H
+
+#ifdef _BLT_BLKDEV_H_
+#error using both blt/blkdev.h and sandbox/blkdev.h is bad
+#endif
+
+typedef struct
+{
+ int blksize;
+ dev_t devno;
+} blkdev_t;
+
+int blk_open (const char *name, int flags, blkdev_t **retdev);
+int blk_close (blkdev_t *dev);
+int blk_read (blkdev_t *dev, void *buf, int block, int count);
+int blk_write (blkdev_t dev, const void *buf, int block, int count);
+
+#endif
+
diff --git a/srv/vfs/sandbox/hash.h b/srv/vfs/sandbox/hash.h
@@ -0,0 +1,56 @@
+/* $Id: //depot/blt/srv/vfs/sandbox/hash.h#1 $
+**
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED
+** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef HASH_H
+#define HASH_H
+
+typedef struct
+{
+ int valid, dirty, key, dsize;
+ void *data;
+} hashnode_t;
+
+typedef struct
+{
+ hashnode_t *table;
+ int size_index, used, dirty;
+ float max_load;
+} hashtable_t;
+
+hashtable_t *hashtable_new (float max_load);
+void hashtable_del (hashtable_t *t);
+void hashtable_insert (hashtable_t *t, int key, void *data, int dsize);
+void *hashtable_lookup (hashtable_t *t, int key, int *dsize);
+void *hashtable_remove (hashtable_t *t, int key, int *dsize);
+void hashtable_print (hashtable_t *t);
+
+#endif
+
diff --git a/srv/vfs/sandbox/types.h b/srv/vfs/sandbox/types.h
@@ -0,0 +1,50 @@
+/* $Id: //depot/blt/srv/vfs/sandbox/types.h#1 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef TYPES_H
+#define TYPES_H
+
+typedef unsigned long long uint64;
+typedef unsigned int uint32;
+typedef unsigned short uint16;
+typedef unsigned char uint8;
+typedef long long int64;
+typedef int int32;
+typedef short int16;
+typedef char int8;
+
+/*
+typedef unsigned int off_t;
+typedef unsigned int mode_t;
+typedef unsigned int dev_t;
+typedef unsigned int ino_t;
+typedef unsigned int nlink_t;
+typedef unsigned int uid_t;
+typedef unsigned int gid_t;
+*/
+
+#endif
diff --git a/srv/vfs/sandbox/vfs.c b/srv/vfs/sandbox/vfs.c
@@ -0,0 +1,157 @@
+/* $Id: //depot/blt/srv/vfs/sandbox/vfs.c#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include "../vfs-int.h"
+
+#define NAME_PREFIX "../drivers/"
+#define NAME_SUFFIX ".so"
+
+struct fs_type *fs_drivers;
+struct superblock *mount_list = NULL;
+
+void usage (void)
+{
+ printf ("usage: vfs driver file\n");
+ exit (1);
+}
+
+int main (int argc, char **argv)
+{
+ char *buf, c;
+ int i, len, num, pos, res;
+ void *fs, *cookie;
+ struct stat statbuf;
+ struct dirent dirent;
+ struct vnode *vn;
+
+ if (argc < 3)
+ usage ();
+
+ buf = malloc (strlen (NAME_PREFIX) + strlen (NAME_SUFFIX) +
+ strlen (argv[1]) * 2 + 2);
+ strcpy (buf, NAME_PREFIX);
+ strcat (buf, argv[1]);
+ strcat (buf, "/");
+ strcat (buf, argv[1]);
+ strcat (buf, NAME_SUFFIX);
+
+ if (stat (buf, &statbuf))
+ {
+ printf ("driver `%s' not found\n", argv[1]);
+ exit (1);
+ }
+ if ((fs = dlopen (buf, 0)) == NULL)
+ {
+ printf ("error loading driver `%s'\n", argv[1]);
+ exit (1);
+ }
+
+ vfs_mount ("/", argv[1], 0, argv[2]);
+ free (buf);
+
+/*
+ vn = fs_drivers->t_vops->walk (mount_list->sb_root, "etc/afs/ThisCell");
+ vput (vn);
+ vn = fs_drivers->t_vops->walk (mount_list->sb_root,
+ "etc/kerberosIV/krb.conf");
+ vput (vn);
+ vn = fs_drivers->t_vops->walk (mount_list->sb_root, "bin/df");
+ vput (vn);
+*/
+/*
+ vn = fs_drivers->t_vops->walk (mount_list->sb_root, "etc");
+ fs_drivers->t_vops->opendir (vn, &cookie);
+ vput (vn);
+*/
+/*
+ vn = fs_drivers->t_vops->walk (mount_list->sb_root, "bin");
+ printf ("vnid is %lld\n", vn->v_vnid);
+ fs_drivers->t_vops->opendir (vn, &cookie);
+ while (!fs_drivers->t_vops->readdir (vn, &dirent, cookie))
+ printf ("name %s\n", dirent.d_name);
+ fs_drivers->t_vops->rewinddir (vn, cookie);
+ fs_drivers->t_vops->closedir (vn, cookie);
+ fs_drivers->t_vops->free_dircookie (cookie);
+ vput (vn);
+*/
+/*
+ buf = malloc (len = 13062);
+ vn = fs_drivers->t_vops->walk (mount_list->sb_root, "etc/rc");
+ fs_drivers->t_vops->open (vn, &cookie);
+ res = fs_drivers->t_vops->read (vn, buf, len, pos = 0, &num, cookie);
+ printf ("read %d %d bytes\n", res, num);
+ for (i = 0; i < len; i++)
+ printf ("%c", buf[i]);
+ vput (vn);
+*/
+/*
+ pos = 0;
+ vn = fs_drivers->t_vops->walk (mount_list->sb_root, "etc/rc");
+ fs_drivers->t_vops->open (vn, &cookie);
+ do
+ {
+ res = fs_drivers->t_vops->read (vn, &c, 1, pos++, &num, cookie);
+ printf ("%c", c);
+ }
+ while (!res && num);
+ vput (vn);
+*/
+/*
+ //pos = 12 * 8192;
+ pos = 0;
+ buf = malloc (len = 8192);
+ vn = fs_drivers->t_vops->walk (mount_list->sb_root, "etc/magic");
+ fs_drivers->t_vops->open (vn, &cookie);
+ do
+ {
+ res = fs_drivers->t_vops->read (vn, buf, len, pos, &num, cookie);
+ pos += num;
+ for (i = 0; i < num; i++)
+ printf ("%c", buf[i]);
+ }
+ while (!res && num);
+ vput (vn);
+ free (buf);
+*/
+
+ vn = fs_drivers->t_vops->walk (mount_list->sb_root, "etc/magic");
+ fs_drivers->t_vops->rstat (vn, &statbuf);
+ printf ("inode is %lld, nlink is %d, uid is %d, gid is %d, size is %d\n",
+ statbuf.st_ino, statbuf.st_nlink, statbuf.st_uid, statbuf.st_gid,
+ statbuf.st_size);
+ vput (vn);
+
+ return 0;
+}
+
diff --git a/srv/vfs/shm.c b/srv/vfs/shm.c
@@ -0,0 +1,86 @@
+/* $Id: //depot/blt/srv/vfs/shm.c#6 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include "bootfs.h"
+#include "shm.h"
+
+void shm_write_dir (struct ofile *ofile, int skip, int doff, int len,
+ int *numents, int *more)
+{
+ int i, res;
+ struct dirent dirent;
+ struct vnode *vnode;
+ register struct vnode_ops *ops;
+
+ vnode = ofile->o_vnode;
+ ops = vnode->v_sb->sb_vops;
+ ops->rewinddir (vnode, ofile->o_cookie);
+ for (i = 0; i < skip; i++)
+ ops->readdir (vnode, &dirent, ofile->o_cookie);
+ for (i = res = 0; (i < (len / sizeof (struct dirent))) && !res; i++)
+ {
+ res = ops->readdir (vnode, &dirent, ofile->o_cookie);
+ if (!res)
+ memcpy (ofile->dataptr + doff + i * sizeof (struct dirent),
+ &dirent, sizeof (struct dirent));
+ }
+ *numents = (i == 0) ? 0 : i - 1;
+ *more = 0;
+}
+
+void shm_write (struct ofile *ofile, int skip, int doff, int len,
+ int *numbytes, int *more)
+{
+#if 0
+ char buf[256];
+ int i, res;
+ struct vnode *vnode;
+ register struct vnode_ops *ops;
+
+ vnode = ofile->o_vnode;
+ ops = vnode->v_sb->sb_vops;
+/*
+ FIXME - this works without this code for now, but won't when we get lseek
+ for (i = 0; i < skip; i++)
+ ops->read (vnode, buf, 1, ofile->o_cookie);
+*/
+ for (i = 0, res = 1; (i < len) && res; i += res)
+ if ((res = ops->read (vnode, buf, sizeof (buf), ofile->o_cookie)) > 0)
+ memcpy (ofile->dataptr + doff + i, buf, res);
+ *numbytes = i;
+ *more = (i == len);
+#ifdef SHM_DEBUG
+ printf ("shm_write: %x / %x %x %x %x %x\n", ofile->dataptr + doff,
+ *numbytes, i, *more, len, skip);
+#endif
+#endif
+}
+
diff --git a/srv/vfs/shm.h b/srv/vfs/shm.h
@@ -0,0 +1,40 @@
+/* $Id: //depot/blt/srv/vfs/shm.h#2 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _SHM_H_
+#define _SHM_H_
+
+#include "vfs-int.h"
+
+void shm_write_dir (struct ofile *ofile, int skip, int doff, int len,
+ int *numents, int *more);
+void shm_write (struct ofile *ofile, int skip, int doff, int len,
+ int *numbytes, int *more);
+
+#endif
+
diff --git a/srv/vfs/super.c b/srv/vfs/super.c
@@ -0,0 +1,90 @@
+/* $Id: //depot/blt/srv/vfs/super.c#5 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "vfs-int.h"
+
+int vfs_mount (const char *dir, const char *type, int flags, const void *data)
+{
+ int res;
+ static int rootmounted = 0;
+ struct fs_type *driver;
+ struct superblock *super;
+
+#ifdef VFS_DEBUG
+ printf ("vfs_mount %s %s\n", dir, type);
+#endif
+
+ /* find filesystem driver */
+ driver = fs_drivers;
+ while (driver != NULL)
+ {
+ if (!strcmp (driver->name, type))
+ break;
+ else
+ driver = driver->next;
+ }
+ if (driver == NULL)
+ {
+ printf ("vfs: no driver\n");
+ return 1;
+ }
+ super = malloc (sizeof (struct superblock));
+ super->sb_vops = driver->t_vops;
+
+ super->sb_dir = malloc (strlen (dir) + 1);
+ strcpy (super->sb_dir, dir);
+
+ /* verify mount point existence */
+ if (!rootmounted)
+ {
+ rootmounted = 1;
+ super->sb_dev = "none";
+ }
+ else
+ {
+ super->sb_dev = "none";
+ }
+
+ super->sb_vnode_cache = hashtable_new (0.75);
+ super->sb_next = NULL;
+ res = driver->t_vops->mount (super, data, 1);
+ if (!res)
+ {
+ if (mount_list != NULL)
+ super->sb_next = mount_list;
+ mount_list = super;
+ if (strcmp (type, "rootfs") && strcmp (type, "bootfs"))
+ printf ("vfs: mounted type %s on %s from %s\n", type,
+ super->sb_dir, super->sb_dev);
+ }
+ return res;
+}
+
diff --git a/srv/vfs/vfs-int.h b/srv/vfs/vfs-int.h
@@ -0,0 +1,211 @@
+/* $Id: //depot/blt/srv/vfs/vfs-int.h#11 $
+**
+** Copyright 1999 Sidney Cammeresi.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _VFS_INT_H_
+#define _VFS_INT_H_
+
+
+#include <dirent.h>
+#include <sys/stat.h>
+
+#ifndef VFS_SANDBOX
+#include <blt/types.h>
+#include <blt/hash.h>
+#include <blt/qsem.h>
+#include <blt/vfs.h>
+#include <blt/syscall.h>
+#else
+#include "hash.h"
+#define MAX_FDS 256
+#endif
+
+struct fs_type
+{
+ char *name;
+ struct vnode_ops *t_vops;
+ struct fs_type *next;
+};
+
+struct superblock
+{
+ char *sb_dev, *sb_dir;
+ struct vnode *sb_root;
+ struct vnode_ops *sb_vops;
+ void *sb_data;
+ hashtable_t *sb_vnode_cache;
+ struct superblock *sb_next;
+};
+
+/*
+ * This stuff was mercilessly stolen from *Practical File System Design
+ * With the Be File System* by Dominic Giampaolo. According to rumours,
+ * it is a lot like the way BeOS handles stuff internally.
+ */
+
+/*
+ * don't be alarmed by all of the voids; i've just not yet come to the
+ * semantics of all of these yet. patience, please.
+ */
+struct vnode_ops
+{
+ int (*read_vnode) (struct vnode *vnode);
+ void (*drop_vnode) (struct vnode *vnode);
+ void (*remove_vnode) (void);
+ void (*secure_vnode) (void);
+ struct vnode *(*walk) (struct vnode *parent, const char *path);
+ void (*access) (void);
+
+ int (*mount) (struct superblock *sb, const char *data, int silent);
+ void (*unmount) (struct superblock *sb);
+ void (*initialise) (void);
+ void (*sync) (void);
+ void (*rfstat) (void);
+ void (*wfstat) (void);
+
+ void (*create) (void);
+ int (*mkdir) (struct vnode *parent, const char *name, mode_t mode);
+ void (*symlink) (void);
+ void (*link) (void);
+ void (*rename) (void);
+ void (*unlink) (void);
+ void (*rmdir) (void);
+ void (*readlink) (void);
+
+ int (*opendir) (struct vnode *dir, void **cookie);
+ void (*closedir) (struct vnode *dir, void *cookie);
+ void (*free_dircookie) (void *cookie);
+ int (*rewinddir) (struct vnode *dir, void *cookie);
+ int (*readdir) (struct vnode *vnode, struct dirent *dirent, void *cookie);
+
+ int (*open) (struct vnode *vnode, void **cookie);
+ int (*close) (struct vnode *vnode, void *cookie);
+ void (*free_cookie) (void *cookie);
+ int (*read) (struct vnode *vnode, char *buf, size_t count, off_t offset,
+ size_t *res, void *cookie);
+ void (*write) (struct vnode *vnode, const char *buf, size_t count,
+ void *cookie);
+ void (*ioctl) (void);
+ void (*setflags) (void);
+ int (*rstat) (struct vnode *vnode, struct stat *buf);
+ int (*wstat) (struct vnode *vnode, struct stat *buf);
+ void (*fsync) (void);
+
+ void (*open_attrdir) (void);
+ void (*close_attrdir) (void);
+ void (*free_attrdircookie) (void);
+ void (*rewind_attrdir) (void);
+ void (*read_attrdir) (void);
+ void (*read_attr) (void);
+ void (*write_attr) (void);
+ void (*remove_attr) (void);
+ void (*rename_attr) (void);
+ void (*stat_attr) (void);
+
+ void (*open_indexdir) (void);
+ void (*close_indexdir) (void);
+ void (*free_indexdircookie) (void);
+ void (*rewind_indexdir) (void);
+ void (*read_indexdir) (void);
+ void (*create_index) (void);
+ void (*remove_index) (void);
+ void (*rename_index) (void);
+ void (*stat_index) (void);
+
+ void (*open_query) (void);
+ void (*close_query) (void);
+ void (*free_query_cookie) (void);
+ void (*read_query) (void);
+};
+
+struct vnode
+{
+ unsigned long long v_vnid;
+ unsigned int v_refcount;
+ struct superblock *v_sb;
+ void *v_data;
+#ifndef VFS_SANDBOX
+ qsem_t *v_lock;
+#endif
+};
+
+struct ofile
+{
+ struct vnode *o_vnode;
+ void *o_cookie;
+ int area, offset, length, flags;
+ int o_pos;
+ void *dataptr;
+};
+
+struct fdarray
+{
+ struct ofile *ofile[MAX_FDS];
+};
+
+struct ioctx
+{
+ char *cwd;
+ struct fdarray fdarray;
+};
+
+struct client
+{
+ int in, out, filename_area;
+ struct ioctx ioctx;
+ char *nameptr;
+};
+
+/* functions for use by modules */
+int fs_register (struct fs_type *type);
+void fs_unregister (struct fs_type *type);
+
+/* utility functions */
+struct superblock *fs_find (const char *name);
+struct vnode *vget (struct superblock *super, int num);
+void vput (struct vnode *vnode);
+
+#ifndef VFS_SANDBOX
+vfs_res_t *vfs_openconn (int rport, int area);
+vfs_res_t *vfs_scroll_area (struct client *client, vfs_cmd_t *vc);
+vfs_res_t *vfs_opendir (struct client *client, vfs_cmd_t *vc);
+vfs_res_t *vfs_closedir (struct client *client, vfs_cmd_t *vc);
+#endif
+
+struct vfs_dirent_node
+{
+ struct dirent *dirent;
+ struct vfs_dirent_node *next;
+};
+
+extern struct fs_type *fs_drivers;
+extern struct superblock *mount_list;
+
+int vfs_mount (const char *dir, const char *type, int flags, const void *data);
+
+#endif
+
diff --git a/srv/vfs/vfs.c b/srv/vfs/vfs.c
@@ -0,0 +1,671 @@
+/* Copyright 1998-1999, Sidney Cammeresi. All rights reserved.
+** Distributed under the terms of the OpenBLT License
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <boot.h>
+#include <dlfcn.h>
+#include <sys/stat.h>
+#include <blt/syscall.h>
+#include <blt/namer.h>
+#include <blt/error.h>
+#include <blt/hash.h>
+#include <blt/libsyms.h>
+#include <blt/vfs.h>
+#include "vfs-int.h"
+#include "path.h"
+#include "shm.h"
+
+#define FG_GREEN "\033[32m"
+#define FG_RED "\033[34m"
+#define FG_WHITE "\033[37m"
+
+int vfs_port;
+struct fs_type *fs_drivers;
+struct superblock *mount_list = NULL;
+hashtable_t *conn_table;
+
+void __libc_init_vfs (void), __dlinit (void);
+
+extern struct fs_type rootfs, bootfs;
+extern void __libc_init_console ();
+extern int __blk_ref;
+
+vfs_res_t *vfs_openconn (int rport, int area)
+{
+ int i, private_port;
+ vfs_res_t *res;
+ struct client *client;
+
+ res = malloc (sizeof (vfs_res_t));
+ res->status = VFS_OK;
+ res->errno = 0;
+ private_port = port_create (rport, "vfs_private_port");
+ port_slave (vfs_port, private_port);
+ res->data[0] = private_port;
+
+ client = malloc (sizeof (struct client));
+ client->in = rport;
+ client->out = private_port;
+ client->filename_area = area;
+ area_clone (area, 0, (void **) &client->nameptr, 0);
+ client->ioctx.cwd = malloc (BLT_MAX_NAME_LENGTH);
+ strcpy (client->ioctx.cwd, "/");
+ for (i = 0; i < MAX_FDS; i++)
+ client->ioctx.fdarray.ofile[i] = NULL;
+ hashtable_insert (conn_table, client->in, client, sizeof (struct client));
+
+#ifdef VFS_DEBUG
+ printf ("vfs_openconn: from port %d, assigned port %d, area %d "
+ "mapped to %p\n", rport, private_port, area, client->nameptr);
+#endif
+ return res;
+}
+
+vfs_res_t *vfs_scroll_area (struct client *client, vfs_cmd_t *vc)
+{
+ struct ofile *ofile;
+ vfs_res_t *res;
+
+ res = malloc (sizeof (vfs_res_t));
+ ofile = client->ioctx.fdarray.ofile[vc->data[0]];
+ shm_write (ofile, vc->data[1], 0, ofile->length, &res->data[0],
+ &res->data[1]);
+ res->status = VFS_OK;
+ res->errno = 0;
+ return res;
+}
+
+int vfs_mkdir (const char *dir, mode_t mode)
+{
+ const char *s;
+ int res;
+ struct superblock *super;
+ struct vnode *vnode;
+
+#ifdef VFS_DEBUG
+ printf ("vfs_mkdir %s %d\n", dir, mode);
+#endif
+
+ /* find superblock and check if mkdir supported */
+ super = fs_find (dir);
+ if (super->sb_vops->mkdir == NULL)
+ return ENOSYS;
+
+ /* XXX dispatch to root vnode for now */
+ vnode = super->sb_root;
+ s = dir + strlen (super->sb_dir);
+ res = super->sb_vops->mkdir (vnode, s, mode);
+ return res;
+}
+
+vfs_res_t *vfs_opendir (struct client *client, vfs_cmd_t *vc)
+{
+ char *reldir, *dir;
+ int i;
+ vfs_res_t *res;
+ struct ofile *ofile;
+ struct superblock *super;
+ struct vnode *vnode;
+
+ reldir = client->nameptr + vc->data[0];
+ res = malloc (sizeof (vfs_res_t));
+#ifdef VFS_DEBUG
+ printf ("vfs_opendir %s\n", reldir);
+#endif
+
+ /* get a file descriptor */
+ for (i = 0; i < MAX_FDS; i++)
+ if (client->ioctx.fdarray.ofile[i] == NULL)
+ break;
+ if (i == MAX_FDS)
+ {
+ res->status = VFS_ERROR;
+ res->errno = EMFILE;
+ return res;
+ }
+
+ /* is opendir supported? */
+ dir = malloc (BLT_MAX_NAME_LENGTH);
+ strlcpy (dir, client->ioctx.cwd, BLT_MAX_NAME_LENGTH);
+ path_combine (client->ioctx.cwd, reldir, dir);
+ super = fs_find (dir);
+ if (super == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = ENOENT;
+ free (dir);
+ return res;
+ }
+ if (super->sb_vops->opendir == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = ENOSYS;
+ free (dir);
+ return res;
+ }
+
+ /* find directory's vnode */
+ if (!strcmp (dir, super->sb_dir))
+ vnode = super->sb_root;
+ else
+ vnode = super->sb_vops->walk (super->sb_root, dir +
+ strlen (super->sb_dir) + 1);
+ if (vnode == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = ENOENT;
+ free (dir);
+ return res;
+ }
+
+ /* stat here to check for directory */
+
+ /* call filesystem's opendir and read the directory */
+ ofile = client->ioctx.fdarray.ofile[i] = malloc (sizeof (struct ofile));
+ ofile->o_vnode = vnode;
+ ofile->area = area_clone (vc->data[1], 0, &ofile->dataptr, 0);
+ ofile->offset = vc->data[2];
+ ofile->length = vc->data[3];
+ res->errno = super->sb_vops->opendir (vnode, &ofile->o_cookie);
+ res->status = res->errno ? VFS_ERROR : VFS_OK;
+ res->data[0] = i;
+ free (dir);
+ return res;
+}
+
+vfs_res_t *vfs_closedir (struct client *client, vfs_cmd_t *vc)
+{
+ vfs_res_t *res;
+ struct ofile *ofile;
+ struct vnode *vnode;
+
+#ifdef VFS_DEBUG
+ printf ("vfs_closedir %d\n", vc->data[0]);
+#endif
+ res = malloc (sizeof (vfs_res_t));
+
+ /* is file descriptor valid? */
+ if ((ofile = client->ioctx.fdarray.ofile[vc->data[0]]) == NULL)
+ {
+ res->errno = EBADF;
+ res->status = VFS_ERROR;
+ return res;
+ }
+
+ /* is closedir supported? */
+ vnode = ofile->o_vnode;
+ if (vnode->v_sb->sb_vops->closedir == NULL)
+ {
+ res->errno = ENOSYS;
+ res->status = VFS_ERROR;
+ return res;
+ }
+
+ /* call filesystem */
+ vnode->v_sb->sb_vops->closedir (vnode, ofile->o_cookie);
+ if (!res->errno && (vnode->v_sb->sb_vops->free_dircookie != NULL))
+ vnode->v_sb->sb_vops->free_dircookie (ofile->o_cookie);
+ free (ofile);
+ client->ioctx.fdarray.ofile[vc->data[0]] = NULL;
+
+ res->status = VFS_OK;
+ res->errno = 0;
+ return res;
+}
+
+vfs_res_t *vfs_open (struct client *client, vfs_cmd_t *vc)
+{
+ int i;
+ char *path;
+ vfs_res_t *res;
+ struct ofile *ofile;
+ struct superblock *super;
+ struct vnode *vnode;
+
+ res = malloc (sizeof (vfs_res_t));
+ path = client->nameptr + vc->data[0];
+#ifdef VFS_DEBUG
+ printf ("vfs_open %s\n", path);
+#endif
+
+ /* get a file descriptor */
+ for (i = 0; i < MAX_FDS; i++)
+ if (client->ioctx.fdarray.ofile[i] == NULL)
+ break;
+ if (i == MAX_FDS)
+ {
+ res->status = VFS_ERROR;
+ res->errno = EMFILE;
+ return res;
+ }
+
+ /* is open supported? */
+ super = fs_find (path);
+ if (super == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = ENOENT;
+ return res;
+ }
+ if (super->sb_vops->open == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = ENOSYS;
+ return res;
+ }
+
+ /* find file's vnode */
+ vnode = super->sb_vops->walk (super->sb_root, path +
+ strlen (super->sb_dir) + 1);
+ if (vnode == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = ENOENT;
+ return res;
+ }
+
+ /* call filesystem */
+ ofile = client->ioctx.fdarray.ofile[i] = malloc (sizeof (struct ofile));
+ ofile->o_vnode = vnode;
+ ofile->o_pos = 0;
+ ofile->area = area_clone (vc->data[1], 0, &ofile->dataptr, 0);
+ ofile->offset = vc->data[2];
+ ofile->length = vc->data[3];
+ res->errno = super->sb_vops->open (vnode, &ofile->o_cookie);
+ res->status = res->errno ? VFS_ERROR : VFS_OK;
+ res->data[0] = i;
+ return res;
+}
+
+vfs_res_t *vfs_close (struct client *client, vfs_cmd_t *vc)
+{
+ vfs_res_t *res;
+ struct ofile *ofile;
+ struct superblock *super;
+
+ res = malloc (sizeof (vfs_res_t));
+#ifdef VFS_DEBUG
+ printf ("vfs_close\n");
+#endif
+
+ ofile = client->ioctx.fdarray.ofile[vc->data[0]];
+ if (ofile == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = EBADF;
+ return res;
+ }
+ super = ofile->o_vnode->v_sb;
+ if (super->sb_vops->close == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = ENOSYS;
+ return res;
+ }
+ res->errno = super->sb_vops->close (ofile->o_vnode,
+ ofile->o_cookie);
+
+ if (super->sb_vops->free_cookie != NULL)
+ super->sb_vops->free_cookie (ofile->o_cookie);
+
+ res->status = res->errno ? VFS_ERROR : VFS_OK;
+ return res;
+}
+
+vfs_res_t *vfs_read (struct client *client, vfs_cmd_t *vc, void **data,
+ int *len)
+{
+ size_t numread;
+ void *buf;
+ vfs_res_t *res;
+ struct ofile *ofile;
+ struct superblock *super;
+
+#ifdef VFS_DEBUG
+ printf ("vfs_read\n");
+#endif
+ res = malloc (sizeof (vfs_res_t));
+ buf = malloc (vc->data[1]);
+
+ ofile = client->ioctx.fdarray.ofile[vc->data[0]];
+ if (ofile == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = EBADF;
+ return res;
+ }
+ super = ofile->o_vnode->v_sb;
+ if (super->sb_vops->read == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = ENOSYS;
+ return res;
+ }
+
+ res->errno = super->sb_vops->read (ofile->o_vnode, buf, vc->data[1],
+ ofile->o_pos, &numread, ofile->o_cookie);
+ res->status = res->errno ? VFS_ERROR : VFS_OK;
+ res->data[0] = numread;
+ ofile->o_pos += *len = numread;
+ *data = buf;
+ return res;
+}
+
+vfs_res_t *vfs_rstat (struct client *client, vfs_cmd_t *vc)
+{
+ char *path;
+ vfs_res_t *res;
+ struct superblock *super;
+ struct vnode *vnode;
+ struct stat *buf;
+
+#ifdef VFS_DEBUG
+ printf ("vfs_rstat\n");
+#endif
+ res = malloc (sizeof (vfs_res_t) + sizeof (struct stat));
+ buf = (void *) res + sizeof (vfs_res_t);
+ path = client->nameptr + vc->data[0];
+
+ /* is stat supported? */
+ super = fs_find (path);
+ if (super == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = ENOENT;
+ return res;
+ }
+ if (super->sb_vops->rstat == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = ENOSYS;
+ return res;
+ }
+
+ /* find file's vnode */
+ vnode = super->sb_vops->walk (super->sb_root, path +
+ strlen (super->sb_dir) + 1);
+ if (vnode == NULL)
+ {
+ res->status = VFS_ERROR;
+ res->errno = ENOENT;
+ return res;
+ }
+
+ /* call filesystem */
+ res->errno = super->sb_vops->rstat (vnode, buf);
+ res->status = res->errno ? VFS_ERROR : VFS_OK;
+ return res;
+}
+
+void vfs_tell_cmd (const char *cmd, char *arg)
+{
+ char *name;
+ const char *type, *dir, *data;
+ int i, len;
+ void *handle;
+
+ if (!strcmp (cmd, "load"))
+ {
+ printf (" %s", arg);
+ name = malloc (len = BLT_MAX_NAME_LENGTH);
+ strlcpy (name, "/boot/", len);
+ strlcat (name, arg, len);
+ strlcat (name, ".so", len);
+ handle = dlopen (name, 0);
+ if (handle == NULL)
+ {
+ printf ("(error)");
+ return;
+ }
+ free (name);
+ }
+ else if (!strcmp (cmd, "mount"))
+ {
+ type = arg;
+ for (i = 0; arg[i] != ' '; i++) ;
+ arg[i] = 0;
+ dir = arg + i + 1;
+ for (arg++; arg[i] != ' '; i++) ;
+ arg[i] = 0;
+ data = arg + i + 1;
+ vfs_mount (dir, type, 0, data);
+ }
+}
+
+void vfs_tell_parse (const char *msg)
+{
+ const char *c, *cmd;
+ char *full;
+ char *d;
+ int i, whole, len;
+
+ c = msg;
+ cmd = full = NULL;
+ whole = len = 0;
+ while (*c)
+ {
+ i = 0;
+ while ((c[i] != ' ') && c[i])
+ i++;
+ d = malloc (i + 1);
+ strlcpy (d, c, i + 1);
+ if (cmd == NULL)
+ {
+ cmd = d;
+ if (!strcmp (cmd, "load"))
+ printf ("vfs: loading drivers. [");
+ else if (!strcmp (cmd, "mount"))
+ {
+ whole = 1;
+ full = malloc (len = strlen (msg + 1));
+ *full = 0;
+ }
+ }
+ else if (!whole)
+ vfs_tell_cmd (cmd, d);
+ else
+ {
+ strlcat (full, d, len);
+ strlcat (full, " ", len);
+ }
+ if (i != strlen (c))
+ c += i + 1;
+ else
+ break;
+ }
+ if (whole)
+ full[strlen (full) - 1] = 0;
+ if (!strcmp (cmd, "load"))
+ printf (" ]\n");
+ else if (!strcmp (cmd, "mount"))
+ vfs_tell_cmd (cmd, full);
+}
+
+void vfs_tell (void)
+{
+ char buf[64];
+ int port;
+ msg_hdr_t mh;
+
+ __libc_init_fdl ();
+ __libc_init_vfs ();
+ __dlinit ();
+ __blk_ref++;
+
+ port = port_create (0, "vfs:tell");
+ namer_register (port, "vfs:tell");
+
+ for (;;)
+ {
+ mh.src = 0;
+ mh.dst = port;
+ mh.data = buf;
+ mh.size = sizeof (buf);
+ old_port_recv (&mh);
+ vfs_tell_parse (mh.data);
+
+ mh.dst = mh.src;
+ mh.src = port;
+ mh.data = &port;
+ mh.size = 1;
+ old_port_send (&mh);
+ }
+}
+
+int vfs_main (volatile int *ready)
+{
+ int i, size, len;
+ void *data;
+ msg_hdr_t msg, reply;
+ vfs_cmd_t vc;
+ vfs_res_t *res;
+ struct client *client;
+
+ /* open a connection to the console */
+ __libc_init_console ();
+
+ /* get a public port and register ourself with the namer */
+ vfs_port = port_create (0, "vfs_listen_port");
+ namer_register (vfs_port, "vfs");
+
+ /* say hello */
+#ifdef VFS_DEBUG
+ printf ("vfs: " FG_GREEN "listener ready" FG_WHITE " (port %d)\n",
+ vfs_port);
+#endif
+
+ /* initialise structures */
+ fs_drivers = NULL;
+ conn_table = hashtable_new (0.75);
+ res = NULL;
+ client = NULL;
+
+ /* mount the root and boot filesystems */
+ fs_register (&rootfs);
+ fs_register (&bootfs);
+ vfs_mount ("/", "rootfs", 0, NULL);
+ vfs_mkdir ("/boot", 755);
+ vfs_mount ("/boot", "bootfs", 0, NULL);
+ thr_create (vfs_tell, 0, "vfs:tell");
+ *ready = 1;
+
+ for (;;)
+ {
+ /*
+ * listen for commands. all ports will be slaved to the one
+ * we just created, so we only need to listen on one port.
+ */
+ msg.src = 0;
+ msg.dst = vfs_port;
+ msg.data = &vc;
+ msg.size = sizeof (vc);
+ old_port_recv (&msg);
+
+ if (vc.cmd != VFS_OPENCONN)
+ client = hashtable_lookup (conn_table, msg.src, NULL);
+ size = sizeof (vfs_res_t);
+ data = NULL;
+
+ switch (vc.cmd)
+ {
+ case VFS_OPENCONN:
+ res = vfs_openconn (msg.src, vc.data[0]);
+ break;
+
+ case VFS_SCROLL_AREA:
+ res = vfs_scroll_area (client, &vc);
+ break;
+
+ case VFS_OPENDIR:
+ res = vfs_opendir (client, &vc);
+ if (res->status == VFS_OK)
+ shm_write_dir (client->ioctx.fdarray.ofile[res->data[0]],
+ 0, 0, vc.data[3], &res->data[1], &res->data[2]);
+ break;
+
+ case VFS_CLOSEDIR:
+ res = vfs_closedir (client, &vc);
+ break;
+
+ case VFS_OPEN:
+ res = vfs_open (client, &vc);
+ if (res->status == VFS_OK)
+ shm_write (client->ioctx.fdarray.ofile[res->data[0]],
+ 0, 0, vc.data[3], &res->data[1], &res->data[2]);
+ break;
+
+ case VFS_CLOSE:
+ res = vfs_close (client, &vc);
+ break;
+
+ case VFS_READ:
+ res = vfs_read (client, &vc, &data, &len);
+ break;
+
+ case VFS_RSTAT:
+ res = vfs_rstat (client, &vc);
+ size = sizeof (vfs_res_t) + sizeof (struct stat);
+ break;
+
+ case VFS_MKDIR:
+ res = malloc (sizeof (vfs_res_t));
+ res->status = vfs_mkdir (client->nameptr + vc.data[0],
+ vc.data[1]);
+ res->errno = 0;
+ break;
+ }
+
+ if (res != NULL)
+ {
+ reply.src = (vc.cmd == VFS_OPENCONN) ? vfs_port : client->out;
+ reply.dst = msg.src;
+ reply.data = res;
+ reply.size = size;
+ old_port_send (&reply);
+ free (res);
+
+ if (data != NULL)
+ {
+ reply.src = client->out;
+ reply.dst = msg.src;
+ if (len < 0x1000)
+ {
+ reply.data = data;
+ reply.size = len;
+ old_port_send (&reply);
+ }
+ else
+ {
+ for (i = 0; len > 0x1000; i += 0x1000, len -= 0x1000)
+ {
+ reply.data = (char *) data + i;
+ reply.size = 0x1000;
+ old_port_send (&reply);
+ }
+ reply.data = (char *) data + i;
+ reply.size = len;
+ old_port_send (&reply);
+ }
+ free (data);
+ }
+ }
+ }
+
+ /* not reached */
+ return 0;
+}
+
+int main (void)
+{
+ volatile int ready = 0;
+
+ thr_create (vfs_main, (int *) &ready, "vfs");
+ while (!ready) ;
+ return 0;
+}
+
diff --git a/srv/vfs/vnode.c b/srv/vfs/vnode.c
@@ -0,0 +1,61 @@
+/* $Id: //depot/blt/srv/vfs/vnode.c#4 $
+**
+** Copyright 1999 Sidney Cammeresi
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "vfs-int.h"
+
+struct vnode *vget (struct superblock *super, int vnid)
+{
+ struct vnode *v;
+
+#ifdef VNODE_DEBUG
+ printf ("vfs: vget %d\n", vnid);
+#endif
+ v = malloc (sizeof (struct vnode));
+ v->v_vnid = vnid;
+ v->v_refcount = 1;
+ v->v_sb = super;
+#ifndef VFS_SANDBOX
+ v->v_lock = qsem_create (1);
+#endif
+ super->sb_vops->read_vnode (v);
+ return v;
+}
+
+void vput (struct vnode *vnode)
+{
+ vnode->v_sb->sb_vops->drop_vnode (vnode);
+#ifndef VFS_SANDBOX
+ qsem_destroy (vnode->v_lock);
+#endif
+ vnode->v_refcount--;
+ if (!vnode->v_refcount)
+ free (vnode);
+}
+
diff --git a/srv/window/GraphicsContext.cpp b/srv/window/GraphicsContext.cpp
@@ -0,0 +1,228 @@
+#include "Renderer.h"
+#include "Rect.h"
+#include "Region.h"
+#include "GraphicsContext.h"
+#include "util.h"
+#include "font.h"
+#include "Window.h"
+
+#define swap(a, b) { int temp = a; a = b; b = temp; }
+
+
+GraphicsContext::GraphicsContext()
+ : fRenderer(0)
+{
+}
+
+void GraphicsContext::SetColor(char color)
+{
+ fCurrentColor = color;
+}
+
+const unsigned kBottom = 1;
+const unsigned kTop = 2;
+const unsigned kLeft = 4;
+const unsigned kRight = 8;
+
+inline unsigned clipmask(int x, int y, const Rect &rect)
+{
+ unsigned mask = 0;
+ if (x < rect.left)
+ mask |= kLeft;
+ else if (x > rect.right)
+ mask |= kRight;
+
+ if (y < rect.top)
+ mask |= kTop;
+ else if (y > rect.bottom)
+ mask |= kBottom;
+
+ return mask;
+}
+
+inline int vert_intersection(int x1, int y1, int x2, int y2, int x)
+{
+ return y1 + (y2 - y1) * (x - x1) / (x2 - x1);
+}
+
+inline int horz_intersection(int x1, int y1, int x2, int y2, int y)
+{
+ return x1 + (x2 - x1) * (y - y1) / (y2 - y1);
+}
+
+void GraphicsContext::DrawLine(int x1, int y1, int x2, int y2)
+{
+ x1 += fXOrigin;
+ x2 += fXOrigin;
+ y1 += fYOrigin;
+ y2 += fYOrigin;
+
+ for (int rect = 0; rect < fClipRegion.CountRects(); rect++) {
+ const Rect &clipRect = fClipRegion.RectAt(rect);
+ int clippedX1 = x1;
+ int clippedY1 = y1;
+ int clippedX2 = x2;
+ int clippedY2 = y2;
+ unsigned point1mask = clipmask(clippedX1, clippedY1, clipRect);
+ unsigned point2mask = clipmask(clippedX2, clippedY2, clipRect);
+
+ bool rejected = false;
+ while (point1mask != 0 || point2mask != 0) {
+ if ((point1mask & point2mask) != 0) {
+ rejected = true;
+ break;
+ }
+
+ unsigned mask = point1mask ? point1mask : point2mask;
+ int x = 0;
+ int y = 0;
+ if (mask & kBottom) {
+ y = clipRect.bottom;
+ x = horz_intersection(clippedX1, clippedY1, clippedX2, clippedY2, y);
+ } else if (mask & kTop) {
+ y = clipRect.top;
+ x = horz_intersection(clippedX1, clippedY1, clippedX2, clippedY2, y);
+ } else if (mask & kRight) {
+ x = clipRect.right;
+ y = vert_intersection(clippedX1, clippedY1, clippedX2, clippedY2, x);
+ } else if (mask & kLeft) {
+ x = clipRect.left;
+ y = vert_intersection(clippedX1, clippedY1, clippedX2, clippedY2, x);
+ }
+
+ if (point1mask) {
+ // Clip point 1
+ point1mask = clipmask(x, y, clipRect);
+ clippedX1 = x;
+ clippedY1 = y;
+ } else {
+ // Clip point 2
+ point2mask = clipmask(x, y, clipRect);
+ clippedX2 = x;
+ clippedY2 = y;
+ }
+ }
+
+ if (!rejected)
+ fRenderer->DrawLine(clippedX1, clippedY1, clippedX2, clippedY2, fCurrentColor);
+ }
+}
+
+
+
+void GraphicsContext::FillRect(int x1, int y1, int x2, int y2)
+{
+ x1 += fXOrigin;
+ x2 += fXOrigin;
+ y1 += fYOrigin;
+ y2 += fYOrigin;
+
+ if (x1 > x2) swap(x1, x2);
+ if (y1 > y2) swap(y1, y2);
+
+ for (int rect = 0; rect < fClipRegion.CountRects(); rect++) {
+ const Rect &clipRect = fClipRegion.RectAt(rect);
+ int clipleft = max(x1, clipRect.left);
+ int cliptop = max(y1, clipRect.top);
+ int clipright = min(x2, clipRect.right);
+ int clipbottom = min(y2, clipRect.bottom);
+
+ if (clipright >= clipleft && clipbottom >= cliptop)
+ fRenderer->FillRect(clipleft, cliptop, clipright, clipbottom,
+ fCurrentColor);
+ }
+}
+
+void GraphicsContext::Blit(int x, int y, char image[], int image_width,
+ int image_height, int img_bytes_per_row)
+{
+ x += fXOrigin;
+ y += fYOrigin;
+
+ for (int rect = 0; rect < fClipRegion.CountRects(); rect++) {
+ const Rect &clipRect = fClipRegion.RectAt(rect);
+ int clipleft = max(x, clipRect.left);
+ int cliptop = max(y, clipRect.top);
+ int clipright = min(x + image_width - 1, clipRect.right);
+ int clipbottom = min(y + image_height - 1, clipRect.bottom);
+
+ if (clipright >= clipleft && clipbottom >= cliptop) {
+ fRenderer->Blit(clipleft, cliptop, image + (clipleft - x) +
+ (cliptop - y) * img_bytes_per_row, clipright - clipleft + 1,
+ clipbottom - cliptop + 1, img_bytes_per_row);
+ }
+ }
+}
+
+void GraphicsContext::StretchBlit(Rect imageRect, Rect screenRect, char image[], int img_bytes_per_row)
+{
+ screenRect.left += fXOrigin;
+ screenRect.top += fYOrigin;
+ screenRect.right += fXOrigin;
+ screenRect.bottom += fYOrigin;
+
+ for (int rect = 0; rect < fClipRegion.CountRects(); rect++) {
+ const Rect &clipRect = fClipRegion.RectAt(rect);
+ Rect clippedScreenRect;
+ clippedScreenRect.left = max(screenRect.left, clipRect.left);
+ clippedScreenRect.top = max(screenRect.top, clipRect.top);
+ clippedScreenRect.right = min(screenRect.right, clipRect.right);
+ clippedScreenRect.bottom = min(screenRect.bottom, clipRect.bottom);
+
+ if (clippedScreenRect.Width() > 0 && clippedScreenRect.Height() > 0) {
+ Rect clippedImageRect;
+ clippedImageRect.left = (clippedScreenRect.left - screenRect.left)
+ * imageRect.Width() / screenRect.Width();
+ clippedImageRect.right = (clippedScreenRect.right - screenRect.left)
+ * imageRect.Width() / screenRect.Width();
+ clippedImageRect.top = (clippedScreenRect.top - screenRect.top)
+ * imageRect.Height() / screenRect.Height();
+ clippedImageRect.bottom = (clippedScreenRect.bottom - screenRect.top)
+ * imageRect.Height() / screenRect.Height();
+
+ fRenderer->StretchBlit(clippedImageRect, clippedScreenRect, image, img_bytes_per_row);
+ }
+ }
+}
+
+void GraphicsContext::CopyRect(Rect src, Rect dest, const Region &inCleanRegion,
+ Region &outNotCopied)
+{
+ src.OffsetBy(fXOrigin, fYOrigin);
+ dest.OffsetBy(fXOrigin, fYOrigin);
+
+ int dX = dest.left - src.left;
+ int dY = dest.top - src.top;
+ Region copyRegion = inCleanRegion;
+ copyRegion.ConstrainTo(dest);
+ copyRegion.Translate(-dX, -dY);
+ copyRegion.Intersect(inCleanRegion);
+ for (int rect = 0; rect < copyRegion.CountRects(); rect++) {
+ const Rect &srcRect = copyRegion.RectAt(rect);
+ Rect destRect(srcRect);
+ destRect.OffsetBy(dX, dY);
+ fRenderer->CopyRect(srcRect, destRect);
+ }
+
+ copyRegion.Invert();
+ copyRegion.Intersect(fClipRegion);
+ outNotCopied = copyRegion;
+}
+
+void GraphicsContext::DrawString(int x, int y, const char *string)
+{
+ while (*string) {
+ Blit(x, y, (char*) &font5x8[*string++ * 40], 5, 8, 5);
+ x += 5;
+ }
+}
+
+Rect GraphicsContext::Bounds()
+{
+ Rect rect = fClipRegion.Bounds();
+ rect.OffsetBy(-fXOrigin, -fYOrigin);
+ return rect;
+}
+
+
+
diff --git a/srv/window/GraphicsContext.h b/srv/window/GraphicsContext.h
@@ -0,0 +1,71 @@
+#ifndef _GRAPHICS_CONTEXT_H
+#define _GRAPHICS_CONTEXT_H
+
+#include "Renderer.h"
+#include "Region.h"
+
+class Window;
+
+class GraphicsContext {
+public:
+
+ GraphicsContext();
+ Rect Bounds();
+
+ inline const Region& ClipRegion();
+ inline void SetClipRegion(const Region&);
+ inline void SetRenderer(Renderer*);
+ inline Renderer* GetRenderer();
+ inline void SetOrigin(int x, int y);
+
+ void DrawLine(int, int, int, int);
+ void FillRect(int, int, int, int);
+ void Blit(int x, int y, char image[], int image_width,
+ int image_height, int img_bytes_per_row);
+ void StretchBlit(Rect imageRect, Rect screenRect, char image[],
+ int img_bytes_per_row);
+ void CopyRect(Rect src, Rect dest, const Region &inCleanRegion,
+ Region &outNotCopied);
+
+ void SetColor(char color);
+ void DrawString(int x, int y, const char *string);
+
+private:
+
+ Region fClipRegion;
+ Renderer *fRenderer;
+ char fCurrentColor;
+ int fXOrigin;
+ int fYOrigin;
+};
+
+
+inline const Region& GraphicsContext::ClipRegion()
+{
+ return fClipRegion;
+}
+
+inline void GraphicsContext::SetClipRegion(const Region ®ion)
+{
+ fClipRegion = region;
+ fClipRegion.ConstrainTo(fRenderer->Bounds());
+}
+
+inline void GraphicsContext::SetRenderer(Renderer *renderer)
+{
+ fRenderer = renderer;
+}
+
+inline Renderer* GraphicsContext::GetRenderer()
+{
+ return fRenderer;
+}
+
+inline void GraphicsContext::SetOrigin(int x, int y)
+{
+ fXOrigin = x;
+ fYOrigin = y;
+}
+
+
+#endif
diff --git a/srv/window/Makefile b/srv/window/Makefile
@@ -0,0 +1,13 @@
+BLTHOME := ../../
+include $(BLTHOME)make.conf
+
+CFLAGS += -fno-rtti -fno-exceptions -fno-pic -O2
+LIBS := -lposix -lblt -lc
+BINARY := window_server.bin
+
+OBJS := main.o GraphicsContext.o Region.o \
+ Window.o WindowManager.o Renderer_8bpp.o \
+ vga.o Renderer_vga.o SerialMouse.o
+
+include $(BLTHOME)make.actions
+
diff --git a/srv/window/Rect.h b/srv/window/Rect.h
@@ -0,0 +1,131 @@
+#ifndef RECT_H
+#define RECT_H
+
+#include <stdio.h>
+#include "util.h"
+
+class Rect {
+public:
+ inline Rect();
+ inline Rect(int left, int top, int right, int bottom);
+ inline void SetTo(int l, int t, int r, int b);
+ inline Rect& InsetBy(int, int);
+ inline Rect& OffsetBy(int, int);
+ inline Rect& OffsetTo(int, int);
+ inline bool Contains(int, int) const;
+ inline bool Contains(const Rect&) const;
+ inline bool Intersects(const Rect&) const;
+ inline Rect& Intersect(const Rect&);
+ inline bool Valid() const;
+ inline int Width() const;
+ inline int Height() const;
+ inline void Dump() const;
+
+ int left;
+ int top;
+ int right;
+ int bottom;
+};
+
+inline Rect::Rect()
+ : left(0),
+ top(0),
+ right(0),
+ bottom(0)
+{
+}
+
+inline Rect::Rect(int l, int t, int r, int b)
+ : left(l),
+ top(t),
+ right(r),
+ bottom(b)
+{
+}
+
+inline void Rect::SetTo(int l, int t, int r, int b)
+{
+ left = l;
+ top = t;
+ right = r;
+ bottom = b;
+}
+
+
+
+inline Rect& Rect::InsetBy(int h, int v)
+{
+ left += h;
+ right -= h;
+ top += v;
+ bottom -= v;
+ return *this;
+}
+
+inline Rect& Rect::OffsetBy(int h, int v)
+{
+ left += h;
+ right += h;
+ top += v;
+ bottom += v;
+ return *this;
+}
+
+
+inline Rect& Rect::OffsetTo(int h, int v)
+{
+ right += (h - left);
+ bottom += (v - top);
+ left = h;
+ top = v;
+ return *this;
+}
+
+inline bool Rect::Intersects(const Rect &rect) const
+{
+ return max(left, rect.left) <= min(right, rect.right)
+ && max(top, rect.top) <= min(bottom, rect.bottom);
+}
+
+inline bool Rect::Valid() const
+{
+ return right >= left && bottom >= top;
+}
+
+inline void Rect::Dump() const
+{
+ printf("Rect (%d, %d, %d, %d)\n", left, top, right, bottom);
+}
+
+
+inline int Rect::Width() const
+{
+ return right - left;
+}
+
+inline int Rect::Height() const
+{
+ return bottom - top;
+}
+
+inline bool Rect::Contains(int x, int y) const
+{
+ return (x >= left && x <= right && y >= top && y <= bottom);
+}
+
+inline bool Rect::Contains(const Rect &rect) const
+{
+ return rect.left >= left && rect.right <= right
+ && rect.top >= top && rect.bottom <= bottom;
+}
+
+inline Rect& Rect::Intersect(const Rect &rect)
+{
+ left = max(left, rect.left);
+ right = min(right, rect.right);
+ top = max(top, rect.top);
+ bottom = min(bottom, rect.bottom);
+ return *this;
+}
+
+#endif
diff --git a/srv/window/Region.cpp b/srv/window/Region.cpp
@@ -0,0 +1,341 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "Region.h"
+#include "util.h"
+
+const int kRectAllocSize = 16;
+
+Region::Region()
+ : fRects(0),
+ fNumRects(0),
+ fOpLevel(0)
+{
+}
+
+Region::Region(const Region ©Region)
+ : fRects(0),
+ fNumRects(0),
+ fOpLevel(0)
+{
+ SetTo(copyRegion);
+}
+
+Region::~Region()
+{
+ free(fRects);
+}
+
+Region& Region::SetTo(const Region ©Region)
+{
+ AllocSpace(copyRegion.fNumRects);
+ fNumRects = copyRegion.fNumRects;
+ memcpy(fRects, copyRegion.fRects, fNumRects * sizeof(Rect));
+ return *this;
+}
+
+Region& Region::operator=(const Region ©Region)
+{
+ return SetTo(copyRegion);
+}
+
+Rect Region::Bounds() const
+{
+ Rect bounds(COORD_MAX, COORD_MAX, -COORD_MAX, -COORD_MAX);
+ for (int i = 0; i < fNumRects; i++) {
+ const Rect &rect = RectAt(i);
+ bounds.left = min(bounds.left, rect.left);
+ bounds.right = max(bounds.right, rect.right);
+ bounds.top = min(bounds.top, rect.top);
+ bounds.bottom = max(bounds.bottom, rect.bottom);
+ }
+
+ return bounds;
+}
+
+Region& Region::Include(const Rect &rect)
+{
+ Region temp;
+
+ BeginOperation();
+ // Make sure that there are no overlaps
+ temp.AddRect(rect);
+ for (int i = 0; i < fNumRects; i++)
+ temp.Exclude(RectAt(i));
+
+ AddRegionRects(temp);
+ EndOperation();
+ return *this;
+}
+
+Region& Region::Include(const Region ®ion)
+{
+ BeginOperation();
+ for (int i = 0; i < region.CountRects(); i++)
+ Include(region.RectAt(i));
+ EndOperation();
+
+ return *this;
+}
+
+#define SPLIT_TEST(rect1, rect2) \
+ (max(rect1.left, rect2.left) < min(rect1.right, rect2.right) \
+ && max(rect1.top, rect2.top) < min(rect1.bottom, rect2.bottom))
+
+Region& Region::Exclude(const Rect &excludeRect)
+{
+ BeginOperation();
+ int index = 0;
+ int rectsToCheck = fNumRects;
+ while (index < rectsToCheck) {
+ Rect &clipRect = fRects[index];
+
+ if (!excludeRect.Intersects(clipRect)) {
+ index++;
+ continue;
+ }
+
+ // This clip rect intersects the excluded rect, and could be divided into
+ // as many as eight pieces. Test for each case. Note that none of these
+ // rectangles overlap!!!!
+ Rect quad1(clipRect.left, clipRect.top, excludeRect.left - 1, excludeRect.top - 1);
+ if (SPLIT_TEST(clipRect, quad1)) {
+ quad1.Intersect(clipRect);
+ AddRect(quad1);
+ }
+
+ Rect quad2(excludeRect.left, clipRect.top, excludeRect.right, excludeRect.top - 1);
+ if (SPLIT_TEST(clipRect, quad2)) {
+ quad2.Intersect(clipRect);
+ AddRect(quad2);
+ }
+
+ Rect quad3(excludeRect.right + 1, clipRect.top, clipRect.right, excludeRect.top - 1);
+ if (SPLIT_TEST(clipRect, quad3)) {
+ quad3.Intersect(clipRect);
+ AddRect(quad3);
+ }
+
+ Rect quad4(clipRect.left, excludeRect.top, excludeRect.left - 1, excludeRect.bottom);
+ if (SPLIT_TEST(clipRect, quad4)) {
+ quad4.Intersect(clipRect);
+ AddRect(quad4);
+ }
+
+ Rect quad5(excludeRect.right + 1, excludeRect.top, clipRect.right, excludeRect.bottom);
+ if (SPLIT_TEST(clipRect, quad5)) {
+ quad5.Intersect(clipRect);
+ AddRect(quad5);
+ }
+
+ Rect quad6(clipRect.left, excludeRect.bottom + 1, excludeRect.left - 1, clipRect.bottom);
+ if (SPLIT_TEST(clipRect, quad6)) {
+ quad6.Intersect(clipRect);
+ AddRect(quad6);
+ }
+
+ Rect quad7(excludeRect.left, excludeRect.bottom + 1, excludeRect.right, clipRect.bottom);
+ if (SPLIT_TEST(clipRect, quad7)) {
+ quad7.Intersect(clipRect);
+ AddRect(quad7);
+ }
+
+ Rect quad8(excludeRect.right + 1, excludeRect.bottom + 1, clipRect.right, clipRect.bottom);
+ if (SPLIT_TEST(clipRect, quad8)) {
+ quad8.Intersect(clipRect);
+ AddRect(quad8);
+ }
+
+ // This rect has been split, remove it. Note we don't
+ // change the index
+ RemoveRect(index);
+ rectsToCheck--;
+ }
+ EndOperation();
+ return *this;
+}
+
+Region& Region::Exclude(const Region &ex)
+{
+ BeginOperation();
+ Region temp(ex);
+ temp.Invert();
+ Intersect(temp);
+ EndOperation();
+ return *this;
+}
+
+
+
+Region& Region::Clear()
+{
+ fNumRects = 0;
+ AllocSpace(0);
+ return *this;
+}
+
+Region& Region::ConstrainTo(const Rect &rect)
+{
+ BeginOperation();
+ for (int i = fNumRects - 1; i >= 0; i--) {
+ fRects[i].left = max(rect.left, fRects[i].left);
+ fRects[i].right = min(rect.right, fRects[i].right);
+ fRects[i].top = max(rect.top, fRects[i].top);
+ fRects[i].bottom = min(rect.bottom, fRects[i].bottom);
+ if (!fRects[i].Valid())
+ RemoveRect(i);
+ }
+
+ EndOperation();
+ return *this;
+}
+
+Region& Region::Translate(int x, int y)
+{
+ for (int i = 0; i < fNumRects; i++) {
+ fRects[i].left += x;
+ fRects[i].right += x;
+ fRects[i].top += y;
+ fRects[i].bottom += y;
+ }
+
+ return *this;
+}
+
+Region& Region::Intersect(const Region &intersectRegion)
+{
+ BeginOperation();
+ Region newRegion;
+ for (int i = 0; i < fNumRects; i++) {
+ for (int j = 0; j < intersectRegion.fNumRects; j++) {
+ if (RectAt(i).Intersects(intersectRegion.RectAt(j))) {
+ Rect temp(RectAt(i));
+ temp.Intersect(intersectRegion.RectAt(j));
+ newRegion.AddRect(temp);
+ }
+ }
+ }
+
+ SetTo(newRegion);
+ EndOperation();
+ return *this;
+}
+
+Region& Region::Invert()
+{
+ BeginOperation();
+ Region temp;
+ temp.Include(Rect(-COORD_MAX, -COORD_MAX, COORD_MAX, COORD_MAX));
+ for (int i = 0; i < fNumRects; i++)
+ temp.Exclude(fRects[i]);
+
+ SetTo(temp);
+ EndOperation();
+ return *this;
+}
+
+const bool Region::FindRect(int x, int y, Rect &outRect) const
+{
+ for (int i = 0; i < CountRects(); i++) {
+ if (RectAt(i).Contains(x, y)) {
+ outRect = RectAt(i);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Region::AddRect(const Rect &rect)
+{
+ AllocSpace(fNumRects + 1);
+ fRects[fNumRects++] = rect;
+}
+
+void Region::RemoveRect(int index)
+{
+ fNumRects--;
+ memcpy(fRects + index, fRects + index + 1, (fNumRects - index) * sizeof(Rect));
+ AllocSpace(fNumRects);
+}
+
+void Region::AddRegionRects(const Region ®ion)
+{
+ for (int i = 0; i < region.fNumRects; i++)
+ AddRect(region.RectAt(i));
+}
+
+void Region::Consolidate()
+{
+ // Optimize region by consolidating adjacent rectangles.
+ for (int i = 0; i < fNumRects; i++) {
+ for (int j = fNumRects - 1; j > i; j--) {
+ Rect &rect1 = fRects[i];
+ Rect &rect2 = fRects[j];
+ if (rect1.top == rect2.top && rect1.bottom == rect2.bottom) {
+ if (rect1.right + 1 == rect2.left) {
+ rect1.right = rect2.right;
+ RemoveRect(j);
+ } else if (rect2.right + 1 == rect1.left) {
+ rect1.left = rect2.left;
+ RemoveRect(j);
+ }
+ } else if (rect1.left == rect2.left && rect1.right == rect2.right) {
+ if (rect1.top == rect2.bottom + 1) {
+ rect1.top = rect2.top;
+ RemoveRect(j);
+ } else if (rect1.bottom + 1 == rect2.top) {
+ rect1.bottom = rect2.bottom;
+ RemoveRect(j);
+ }
+ }
+ }
+ }
+}
+
+void Region::AllocSpace(int numRects)
+{
+ int currentAlloc = ((fNumRects + kRectAllocSize - 1) / kRectAllocSize)
+ * kRectAllocSize;
+ int sizeWanted = ((numRects + kRectAllocSize - 1) / kRectAllocSize)
+ * kRectAllocSize;
+
+ if (sizeWanted != currentAlloc) {
+ if (fRects == 0 && sizeWanted > 0)
+ fRects = (Rect*) malloc(sizeWanted * sizeof(Rect));
+ else if (sizeWanted == 0 && fRects != 0) {
+ free(fRects);
+ fRects = 0;
+ } else
+ fRects = (Rect*) realloc(fRects, sizeWanted * sizeof(Rect));
+ }
+}
+
+
+void Region::BeginOperation()
+{
+ fOpLevel++;
+}
+
+void Region::EndOperation()
+{
+ if (--fOpLevel == 0)
+ Consolidate();
+
+ ASSERT(fOpLevel >= 0);
+}
+
+
+
+void Region::Dump() const
+{
+ printf("Region: ");
+ for (int i = 0; i < fNumRects; i++) {
+ if ((i % 6) == 5)
+ printf("\n");
+ printf("(%d %d %d %d) ", fRects[i].left, fRects[i].top, fRects[i].right,
+ fRects[i].bottom);
+ }
+
+ printf("\n");
+}
diff --git a/srv/window/Region.h b/srv/window/Region.h
@@ -0,0 +1,73 @@
+#ifndef _REGION_H
+#define _REGION_H
+
+#include "Rect.h"
+#include "assert.h"
+
+const int COORD_MAX = 0x7ffffff0;
+
+class Region {
+public:
+
+ Region();
+ ~Region();
+ Region(const Region&);
+ Region& Clear();
+ Region& Include(const Rect&);
+ Region& Include(const Region&);
+ Region& Exclude(const Rect&);
+ Region& Exclude(const Region&);
+ Region& Invert();
+ Region& Intersect(const Region&);
+ Region& Translate(int x, int y);
+ Region& ConstrainTo(const Rect&);
+ Region& SetTo(const Region&);
+ Region& operator=(const Region&);
+
+ const bool FindRect(int x, int y, Rect &outRect) const;
+
+ Rect Bounds() const;
+ inline bool Valid() const;
+ inline int CountRects() const;
+ const Rect& RectAt(int index) const;
+
+ void Dump() const;
+
+private:
+
+ void AddRect(const Rect&);
+ void RemoveRect(int index);
+ void Consolidate();
+
+ // Assumes there are no overlaps
+ void AddRegionRects(const Region&);
+
+ void AllocSpace(int numRects);
+
+ void BeginOperation();
+ void EndOperation();
+
+ Rect *fRects;
+ int fNumRects;
+ int fOpLevel;
+};
+
+inline int Region::CountRects() const
+{
+ return fNumRects;
+}
+
+inline const Rect& Region::RectAt(int index) const
+{
+ ASSERT(index < fNumRects);
+ return fRects[index];
+}
+
+
+inline bool Region::Valid() const
+{
+ return fNumRects > 0;
+}
+
+
+#endif
diff --git a/srv/window/Renderer.h b/srv/window/Renderer.h
@@ -0,0 +1,67 @@
+#ifndef _RENDERER_H
+#define _RENDERER_H
+
+#include "Rect.h"
+
+class Renderer {
+public:
+
+ inline Renderer(char *baseAddress, int width, int height, int bytesPerRow);
+ virtual void DrawLine(int x1, int y1, int x2, int y2, char color) = 0;
+ virtual void FillRect(int x1, int y1, int x2, int y2, char color) = 0;
+ virtual void Blit(int x, int y, char image[], int image_width,
+ int image_height, int img_bytes_per_row) = 0;
+ virtual void StretchBlit(const Rect &imageRect, const Rect &displayRect, char image[],
+ int imageBytesPerRow) = 0;
+ virtual void CopyRect(const Rect &source, const Rect &dest) = 0;
+
+ inline Rect Bounds() const;
+
+ inline char *BufferBaseAddress() const;
+ inline int BufferWidth() const;
+ inline int BufferHeight() const;
+ inline int BufferBytesPerRow() const;
+
+private:
+ char *fBufferBaseAddress;
+ int fBufferWidth;
+ int fBufferHeight;
+ int fBufferBytesPerRow;
+};
+
+inline Renderer::Renderer(char *baseAddress, int width, int height, int bytesPerRow)
+ : fBufferBaseAddress(baseAddress),
+ fBufferWidth(width),
+ fBufferHeight(height),
+ fBufferBytesPerRow(bytesPerRow)
+{
+}
+
+inline char* Renderer::BufferBaseAddress() const
+{
+ return fBufferBaseAddress;
+}
+
+inline int Renderer::BufferWidth() const
+{
+ return fBufferWidth;
+}
+
+inline int Renderer::BufferHeight() const
+{
+ return fBufferHeight;
+}
+
+inline int Renderer::BufferBytesPerRow() const
+{
+ return fBufferBytesPerRow;
+}
+
+inline Rect Renderer::Bounds() const
+{
+ return Rect(0, 0, fBufferWidth - 1, fBufferHeight - 1);
+}
+
+
+
+#endif
diff --git a/srv/window/Renderer_8bpp.cpp b/srv/window/Renderer_8bpp.cpp
@@ -0,0 +1,233 @@
+#include "Renderer_8bpp.h"
+#include "assert.h"
+
+Renderer_8bpp::Renderer_8bpp(char *baseAddress, int width, int height, int bytesPerRow)
+ : Renderer(baseAddress, width, height, bytesPerRow)
+{
+}
+
+const unsigned kBottom = 1;
+const unsigned kTop = 2;
+const unsigned kLeft = 4;
+const unsigned kRight = 8;
+
+#define clipmask(x, y, rect) \
+ ({ unsigned mask = 0; \
+ if (x < rect.left) mask |= kLeft; \
+ else if (x > rect.right) mask |= kRight; \
+ if (y < rect.top) mask |= kTop; \
+ else if (y > rect.bottom) mask |= kBottom; \
+ mask;})
+
+void Renderer_8bpp::DrawLine(int x1, int y1, int x2, int y2, char color)
+{
+ ASSERT(x1 >= 0 && x1 < BufferWidth());
+ ASSERT(x2 >= 0 && x2 < BufferWidth());
+ ASSERT(y1 >= 0 && y1 < BufferWidth());
+ ASSERT(y2 >= 0 && y2 < BufferWidth());
+
+ // Swap if necessary so we always draw top to bottom
+ if (y1 > y2) {
+ int temp = y1;
+ y1 = y2;
+ y2 = temp;
+
+ temp = x1;
+ x1 = x2;
+ x2 = temp;
+ }
+
+ int deltaY = y2 - y1;
+ int deltaX = x2 > x1 ? x2 - x1 : x1 - x2;
+ int xDir = x2 > x1 ? 1 : -1;
+ int error = 0;
+ char *ptr = BufferBaseAddress() + x1 + y1 * BufferBytesPerRow();
+
+ if (deltaX == 0) {
+ // Vertical line
+ for (int y = deltaY; y >= 0; y--) {
+ *ptr = color;
+ ptr += BufferBytesPerRow();
+ }
+ } else if (deltaY == 0) {
+ // Horizontal line
+ for (int x = deltaX; x >= 0; x--) {
+ *ptr = color;
+ ptr += xDir;
+ }
+ } else if (deltaX > deltaY) {
+ // Diagonal with horizontal major axis
+ x2 += xDir; // Want to quit on pixel past last. Ugly, I know.
+ for (int x = x1; x != x2; x += xDir) {
+ *ptr = color;
+
+ error += deltaY;
+ if (error > deltaX) {
+ ptr += BufferBytesPerRow();
+ error -= deltaX;
+ }
+
+ ptr += xDir;
+ }
+ } else {
+ // Diagonal with vertical major axis
+ for (int y = y1; y <= y2; y++) {
+ *ptr = color;
+
+ error += deltaX;
+ if (error > deltaY) {
+ ptr += xDir;
+ error -= deltaY;
+ }
+
+ ptr += BufferBytesPerRow();
+ }
+ }
+}
+
+void Renderer_8bpp::FillRect(int x1, int y1, int x2, int y2, char color)
+{
+ ASSERT(x1 >= 0 && x1 <= BufferWidth());
+ ASSERT(x2 >= 0 && x2 <= BufferWidth());
+ ASSERT(y1 >= 0 && y1 <= BufferWidth());
+ ASSERT(y2 >= 0 && y2 <= BufferWidth());
+ ASSERT(x2 >= x1);
+ ASSERT(y2 >= y1);
+
+ char *ptr = BufferBaseAddress() + x1 + y1 * BufferBytesPerRow();
+ unsigned int longcolor = (unsigned int)(unsigned char)color | ((unsigned int)(unsigned char)color << 8) |
+ ((unsigned int)(unsigned char)color << 16) | ((unsigned int)(unsigned char)color << 24);
+
+ int wrap = BufferBytesPerRow() - (x2 - x1) - 1;
+ for (int y = y1; y <= y2; y++) {
+ int x = x1;
+ while (x <= x2 && (x & 3) != 0) {
+ *ptr++ = color;
+ x++;
+ }
+
+ while (x + 4 <= x2) {
+ *((long*) ptr) = longcolor;
+ ptr += 4;
+ x += 4;
+ }
+
+ while (x <= x2) {
+ *ptr++ = color;
+ x++;
+ }
+
+ ptr += wrap;
+ }
+}
+
+void Renderer_8bpp::Blit(int x, int y, char image[], int imageWidth,
+ int imageHeight, int imageBytesPerRow)
+{
+ ASSERT(x >= 0 && x + imageWidth <= BufferWidth());
+ ASSERT(y >= 0 && y + imageHeight <= BufferWidth());
+
+ char *screen_ptr = BufferBaseAddress() + x + y * BufferBytesPerRow();
+ char *image_ptr = image;
+ int imageOffs = imageBytesPerRow - imageWidth;
+ int screenOffs = BufferBytesPerRow() - imageWidth;
+
+ for (int i = 0; i < imageHeight; i++) {
+ for (int j = 0; j < imageWidth; j++) {
+ if ((unsigned char) *image_ptr != 0xff)
+ *screen_ptr = *image_ptr;
+
+ screen_ptr++;
+ image_ptr++;
+ }
+
+ image_ptr += imageOffs;
+ screen_ptr += screenOffs;
+ }
+}
+
+void Renderer_8bpp::StretchBlit(const Rect &imageRect, const Rect &displayRect, char image[],
+ int imageBytesPerRow)
+{
+ ASSERT(imageRect.Valid());
+ ASSERT(displayRect.Valid());
+ ASSERT(imageRect.left >= 0);
+ ASSERT(imageRect.top >= 0);
+ ASSERT(imageRect.right < imageBytesPerRow);
+
+ int verror = 0;
+ char *screen_ptr = BufferBaseAddress() + displayRect.left + displayRect.top
+ * BufferBytesPerRow();
+ char *current_image_line = image + imageRect.left + imageRect.top *
+ imageBytesPerRow;
+ int screenOffs = BufferBytesPerRow() - displayRect.Width() - 1;
+
+ for (int y = displayRect.top; y <= displayRect.bottom; y++) {
+ char *image_ptr = current_image_line;
+ int herror = 0;
+ for (int x = displayRect.left; x <= displayRect.right; x++) {
+ if ((unsigned char) *image_ptr != 0xff)
+ *screen_ptr = *image_ptr;
+
+ herror += imageRect.Width();
+ while (herror >= displayRect.Width()) {
+ herror -= displayRect.Width();
+ image_ptr++;
+ }
+
+ screen_ptr++;
+ }
+
+ verror += imageRect.Height();
+ while (verror > displayRect.Height()) {
+ verror -= displayRect.Height();
+ current_image_line += imageBytesPerRow;
+ }
+
+ screen_ptr += screenOffs;
+ }
+}
+
+void Renderer_8bpp::CopyRect(const Rect &source, const Rect &dest)
+{
+ ASSERT(source.Width() == dest.Width());
+ ASSERT(source.Height() == dest.Height());
+
+ int dX;
+ int dY;
+ int startX;
+ int startY;
+ if (dest.left > source.left && dest.left < source.right) {
+ // overlap left side, copy backward
+ dX = -1;
+ startX = source.right;
+ } else {
+ dX = 1;
+ startX = source.left;
+ }
+
+ if (dest.top > source.top && dest.top < source.bottom) {
+ // overlap bottom, copy top up
+ dY = -(BufferBytesPerRow() + dX * (source.Width() + 1));
+ startY = source.bottom;
+ } else {
+ dY = (BufferBytesPerRow() - dX * (source.Width() - 1));
+ startY = source.top;
+ }
+
+ char *srcptr = BufferBaseAddress() + startX + startY * BufferBytesPerRow();
+ int offset = (dest.left - source.left) + (dest.top - source.top)
+ * BufferBytesPerRow();
+
+ for (int y = source.top; y <= source.bottom; y++) {
+ for (int x = source.left; x <= source.right; x++) {
+ *((char*) srcptr + offset) = *srcptr;
+ srcptr += dX;
+ }
+
+ srcptr += dY;
+ }
+}
+
+
+
diff --git a/srv/window/Renderer_8bpp.h b/srv/window/Renderer_8bpp.h
@@ -0,0 +1,20 @@
+#ifndef _RENDERER_8BPP_H
+#define _RENDERER_8BPP_H
+
+#include "Renderer.h"
+#include "Rect.h"
+
+class Renderer_8bpp : public Renderer {
+public:
+ Renderer_8bpp(char *baseAddress, int width, int height, int bytesPerRow);
+ void DrawLine(int x1, int y1, int x2, int y2, char color);
+ void FillRect(int x1, int y1, int x2, int y2, char color);
+ void Blit(int x, int y, char image[], int image_width,
+ int image_height, int img_bytes_per_row);
+ void StretchBlit(const Rect &imageRect, const Rect &displayRect, char image[],
+ int imageBytesPerRow);
+ void CopyRect(const Rect &source, const Rect &dest);
+};
+
+
+#endif
diff --git a/srv/window/Renderer_vga.cpp b/srv/window/Renderer_vga.cpp
@@ -0,0 +1,230 @@
+#include "Renderer_vga.h"
+#include "assert.h"
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+const unsigned char kCursorBits [] = {
+ 0x3f,0x3f,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0x3f,0x3f,0x3f,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x3f,0x3f,0x3f,0x3f,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x3f,0x3f,0x3f,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0x3f,0x3f,0x3f,0xff,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+};
+
+Renderer_vga::Renderer_vga(char *baseAddress, int width, int height, int bytesPerRow)
+ : Renderer_8bpp(baseAddress, width, height, bytesPerRow)
+{
+ fCursorX = width / 2;
+ fCursorY = height / 2;
+ DrawCursor();
+}
+
+const unsigned kBottom = 1;
+const unsigned kTop = 2;
+const unsigned kLeft = 4;
+const unsigned kRight = 8;
+
+#define clipmask(x, y, rect) \
+ ({ unsigned mask = 0; \
+ if (x < rect.left) mask |= kLeft; \
+ else if (x > rect.right) mask |= kRight; \
+ if (y < rect.top) mask |= kTop; \
+ else if (y > rect.bottom) mask |= kBottom; \
+ mask;})
+
+inline int vert_intersection(int x1, int y1, int x2, int y2, int x)
+{
+ return y1 + (y2 - y1) * (x - x1) / (x2 - x1);
+}
+
+inline int horz_intersection(int x1, int y1, int x2, int y2, int y)
+{
+ return x1 + (x2 - x1) * (y - y1) / (y2 - y1);
+}
+
+void Renderer_vga::DrawLine(int x1, int y1, int x2, int y2, char color)
+{
+ Rect cursorRect(fCursorX, fCursorY, fCursorX + 16, fCursorY + 16);
+ bool invalidateCursor = true;
+
+ int clippedX1 = x1;
+ int clippedY1 = y1;
+ int clippedX2 = x2;
+ int clippedY2 = y2;
+ unsigned point1mask = clipmask(clippedX1, clippedY1, cursorRect);
+ unsigned point2mask = clipmask(clippedX2, clippedY2, cursorRect);
+ while (point1mask != 0 || point2mask != 0) {
+ if ((point1mask & point2mask) != 0) {
+ invalidateCursor = false;
+ break;
+ }
+
+ unsigned mask = point1mask ? point1mask : point2mask;
+ int x = 0;
+ int y = 0;
+ if (mask & kBottom) {
+ y = cursorRect.bottom;
+ x = horz_intersection(clippedX1, clippedY1, clippedX2, clippedY2, y);
+ } else if (mask & kTop) {
+ y = cursorRect.top;
+ x = horz_intersection(clippedX1, clippedY1, clippedX2, clippedY2, y);
+ } else if (mask & kRight) {
+ x = cursorRect.right;
+ y = vert_intersection(clippedX1, clippedY1, clippedX2, clippedY2, x);
+ } else if (mask & kLeft) {
+ x = cursorRect.left;
+ y = vert_intersection(clippedX1, clippedY1, clippedX2, clippedY2, x);
+ }
+
+ if (point1mask) {
+ // Clip point 1
+ point1mask = clipmask(x, y, cursorRect);
+ clippedX1 = x;
+ clippedY1 = y;
+ } else {
+ // Clip point 2
+ point2mask = clipmask(x, y, cursorRect);
+ clippedX2 = x;
+ clippedY2 = y;
+ }
+ }
+
+ if (invalidateCursor)
+ EraseCursor();
+
+ Renderer_8bpp::DrawLine(x1, y1, x2, y2, color);
+
+ if (invalidateCursor)
+ DrawCursor();
+}
+
+void Renderer_vga::FillRect(int x1, int y1, int x2, int y2, char color)
+{
+
+ bool invalidateCursor = false;
+ if (Rect(x1, y1, x2, y2).Intersects(Rect(fCursorX, fCursorY, fCursorX + 16,
+ fCursorY + 16))) {
+ invalidateCursor = true;
+ EraseCursor();
+ }
+
+ Renderer_8bpp::FillRect(x1, y1, x2, y2, color);
+ if (invalidateCursor)
+ DrawCursor();
+}
+
+void Renderer_vga::Blit(int x, int y, char image[], int imageWidth,
+ int imageHeight, int imageBytesPerRow)
+{
+
+ bool invalidateCursor = false;
+ if (Rect(x, y, x + imageWidth, y + imageHeight).Intersects(Rect(fCursorX,
+ fCursorY, fCursorX + 16, fCursorY + 16))) {
+ invalidateCursor = true;
+ EraseCursor();
+ }
+
+ Renderer_8bpp::Blit(x, y, image, imageWidth, imageHeight, imageBytesPerRow);
+ if (invalidateCursor)
+ DrawCursor();
+}
+
+void Renderer_vga::StretchBlit(const Rect &imageRect, const Rect &displayRect, char image[],
+ int imageBytesPerRow)
+{
+
+ bool invalidateCursor = false;
+ if (displayRect.Intersects(Rect(fCursorX, fCursorY, fCursorX + 16,
+ fCursorY + 16))) {
+ invalidateCursor = true;
+ EraseCursor();
+ }
+
+ Renderer_8bpp::StretchBlit(imageRect, displayRect, image, imageBytesPerRow);
+
+ if (invalidateCursor)
+ DrawCursor();
+}
+
+void Renderer_vga::CopyRect(const Rect &source, const Rect &dest)
+{
+ bool invalidateCursor = false;
+ Rect cursorRect(fCursorX, fCursorY, fCursorX + 16, fCursorY + 16);
+ if (cursorRect.Intersects(source) || cursorRect.Intersects(dest)) {
+ invalidateCursor = true;
+ EraseCursor();
+ }
+
+ Renderer_8bpp::CopyRect(source, dest);
+ if (invalidateCursor)
+ DrawCursor();
+}
+
+void Renderer_vga::SetCursorPosition(int x, int y)
+{
+ EraseCursor();
+ fCursorX = x;
+ fCursorY = y;
+ DrawCursor();
+}
+
+void Renderer_vga::EraseCursor()
+{
+ char *screen_ptr = BufferBaseAddress() + fCursorX + fCursorY * BufferBytesPerRow();
+ char *saveBackground = fSavedBackground;
+ int cursorDisplayWidth = MIN(16, BufferBytesPerRow() - fCursorX);
+ int cursorDisplayHeight = MIN(16, BufferHeight() - fCursorY);
+ int stride = BufferBytesPerRow() - cursorDisplayWidth;
+
+ for (int y = 0; y < cursorDisplayHeight; y++) {
+ for (int x = 0; x < cursorDisplayWidth; x++) {
+ if ((unsigned char) *saveBackground != 0xff)
+ *screen_ptr = *saveBackground;
+
+ screen_ptr++;
+ saveBackground++;
+ }
+
+ screen_ptr += stride;
+ saveBackground += 16 - cursorDisplayWidth;
+ }
+}
+
+void Renderer_vga::DrawCursor()
+{
+ char *screen_ptr = BufferBaseAddress() + fCursorX + fCursorY * BufferBytesPerRow();
+ char *cursorImage = (char *) kCursorBits;
+ char *saveBackground = fSavedBackground;
+ int cursorDisplayWidth = MIN(16, BufferBytesPerRow() - fCursorX);
+ int cursorDisplayHeight = MIN(16, BufferHeight() - fCursorY);
+ int stride = BufferBytesPerRow() - cursorDisplayWidth;
+
+ for (int y = 0; y < cursorDisplayHeight; y++) {
+ for (int x = 0; x < cursorDisplayWidth; x++) {
+ if ((unsigned char) *cursorImage != 0xff) {
+ *saveBackground = *screen_ptr;
+ *screen_ptr = *cursorImage;
+ } else
+ *saveBackground = 0xff;
+
+ screen_ptr++;
+ cursorImage++;
+ saveBackground++;
+ }
+
+ screen_ptr += stride;
+ cursorImage += 16 - cursorDisplayWidth;
+ saveBackground += 16 - cursorDisplayWidth;
+ }
+}
diff --git a/srv/window/Renderer_vga.h b/srv/window/Renderer_vga.h
@@ -0,0 +1,30 @@
+#ifndef _RENDERER_VGA_H
+#define _RENDERER_VGA_H
+
+#include <blt/qsem.h>
+#include "Renderer_8bpp.h"
+#include "Rect.h"
+
+class Renderer_vga : public Renderer_8bpp {
+public:
+ Renderer_vga(char *baseAddress, int width, int height, int bytesPerRow);
+ void DrawLine(int x1, int y1, int x2, int y2, char color);
+ void FillRect(int x1, int y1, int x2, int y2, char color);
+ void Blit(int x, int y, char image[], int image_width,
+ int image_height, int img_bytes_per_row);
+ void StretchBlit(const Rect &imageRect, const Rect &displayRect, char image[],
+ int imageBytesPerRow);
+ void CopyRect(const Rect &source, const Rect &dest);
+
+ void SetCursorPosition(int x, int y);
+
+private:
+ void EraseCursor();
+ void DrawCursor();
+
+ char fSavedBackground[256];
+ int fCursorX, fCursorY;
+};
+
+
+#endif
diff --git a/srv/window/SerialMouse.cpp b/srv/window/SerialMouse.cpp
@@ -0,0 +1,86 @@
+#include <i386/io.h>
+#include <blt/syscall.h>
+#include <stdio.h>
+#include "SerialMouse.h"
+#include "util.h"
+
+#define POLL 1
+
+const int kBaudRate = 1200;
+const int kPortBase = 0x3f8;
+
+SerialMouse::SerialMouse(int xmax, int ymax)
+ : fXPos(xmax / 2),
+ fYPos(ymax / 2),
+ fXMax(xmax),
+ fYMax(ymax)
+{
+ unsigned short divisor = 115200 / kBaudRate;
+
+ outb(0, kPortBase + 1); // No interrupts for now
+ outb(0, kPortBase + 4); // clear DTR and RTS
+
+ outb(0x80, kPortBase + 3); // load divisor latch
+ outb((divisor & 0xff), kPortBase); // divisor LSB
+ outb((divisor >> 8), kPortBase + 1); // divisor MSB
+ outb(2, kPortBase + 3); // clear DLAB, set up for 7N1
+
+ outb(3, kPortBase + 4); // Say hello. Raise DTR and RTS
+ if (SerialRead() == 'M')
+ printf("Detected MS serial mouse\n");
+}
+
+
+// The data is sent in 3 byte packets in following format:
+// D7 D6 D5 D4 D3 D2 D1 D0
+// 1. X 1 LB RB Y7 Y6 X7 X6
+// 2. X 0 X5 X4 X3 X2 X1 X0
+// 3. X 0 Y5 Y4 Y3 Y2 Y1 Y0
+void SerialMouse::GetPos(int *out_x, int *out_y, int *out_buttons)
+{
+ char b1;
+
+ // loop until we get to the beginning of a packet
+ while (true) {
+ b1 = SerialRead();
+ if ((b1 & (1 << 6)) != 0)
+ break; // beginning of packet
+ }
+
+ char b2 = SerialRead();
+ char b3 = SerialRead();
+
+ fXPos += (int)(char)((b1 << 6) | (b2 & 0x3f));
+ fYPos += (int)(char)(((b1 << 4) & 0xc0) | (b3 & 0x3f));
+
+ fXPos = min(fXPos, fXMax);
+ fXPos = max(fXPos, 0);
+ fYPos = min(fYPos, fYMax);
+ fYPos = max(fYPos, 0);
+
+ *out_buttons = (b1 >> 4) & 3;
+ *out_x = fXPos;
+ *out_y = fYPos;
+}
+
+unsigned char SerialMouse::SerialRead()
+{
+ while (true) {
+#if POLL
+ while ((inb(kPortBase + 5) & 1) == 0)
+ ;
+#else
+ os_handle_irq(4);
+ outb(1, kPortBase + 1); // Interrupt on recieve ready
+ os_sleep_irq();
+ int id = inb(kPortBase + 2);
+ if ((id & 1) == 0 || (id >> 1) != 2)
+ continue; // Not for me
+#endif
+
+ break;
+ }
+
+ return inb(kPortBase);
+}
+
diff --git a/srv/window/SerialMouse.h b/srv/window/SerialMouse.h
@@ -0,0 +1,24 @@
+#ifndef _SERIAL_MOUSE_H
+#define _SERIAL_MOUSE_H
+
+struct mouse_data_packet;
+
+const int MAIN_BUTTON = 1;
+const int SECONDARY_BUTTON = 2;
+
+class SerialMouse {
+public:
+
+ SerialMouse(int xmax, int ymax);
+ void GetPos(int *out_x, int *out_y, int *out_buttons);
+
+private:
+
+ unsigned char SerialRead();
+
+ int fXPos, fYPos;
+ int fXMax, fYMax;
+};
+
+
+#endif
diff --git a/srv/window/Window.cpp b/srv/window/Window.cpp
@@ -0,0 +1,303 @@
+#include <blt/syscall.h>
+#include <blt/os.h>
+#include <stdio.h>
+#include <win/Event.h>
+#include "assert.h"
+#include "Window.h"
+
+Window::Window(int id, int eventPort, Renderer *renderer)
+ : fID(id),
+ fNextSibling(0),
+ fPreviousSibling(0),
+ fChildList(0),
+ fParent(0),
+ fIsVisible(false),
+ fEventPort(eventPort),
+ fPaintMsgSent(false),
+ fColor(0)
+{
+ if (renderer) {
+ // I am being attached directly to a renderer. My clip
+ // region is the bounds of the renderer.
+ fGC.SetRenderer(renderer);
+ fFrame = renderer->Bounds();
+ fVisibleRegion.Clear();
+ fVisibleRegion.Include(fFrame);
+ fClipRegion = fVisibleRegion;
+ fGC.SetClipRegion(fClipRegion);
+ }
+}
+
+Window::~Window()
+{
+ if (fParent)
+ fParent->RemoveChild(this);
+}
+
+Window* Window::ChildAtPoint(int x, int y)
+{
+ // See what child is covering me at this point
+ for (Window *child = fChildList; child; child = child->fNextSibling) {
+ if (child->Frame().Contains(x, y))
+ return child->ChildAtPoint(x - child->Frame().left, y - child->Frame().top);
+ }
+
+ return this; // I guess that's me!
+}
+
+void Window::UpdateClipRegion()
+{
+ Region newClipRegion = fVisibleRegion;
+ Rect myScreenFrame = LocalToScreen(Bounds());
+
+ // Walk the child list. It is ordered from front to back.
+ for (Window *child = fChildList; child; child = child->fNextSibling) {
+ // Ship hidden children (and effectively all their descendents).
+ if (!child->IsVisible()) {
+ Region empty;
+ child->SetVisibleRegion(empty);
+ continue;
+ }
+
+ // My children are obscured both by my siblings and theirs.
+ // Create a new region. Note that fClipRegion is initialized as
+ // my visible region (that is, parts of me that aren't clipped by
+ // my siblings). With iteration, each child window is excluded
+ // from it, so this clips my children against each other.
+ Region childClipRegion = newClipRegion;
+ Rect childScreenFrame = LocalToScreen(child->Frame());
+ childClipRegion.ConstrainTo(childScreenFrame);
+ child->SetVisibleRegion(childClipRegion);
+
+ // I am obscured by my child windows, remove them from my clip
+ // region.
+ newClipRegion.Exclude(childScreenFrame);
+ }
+
+ // Handle exposures.
+ // 1. Invert the old clipping region to find
+ // which parts of the window were previously hidden.
+ // 2. Intersect that with the new clipping region to find areas
+ // that have become visible.
+ Region exposedRegion = fClipRegion;
+ exposedRegion.Invert();
+ exposedRegion.Intersect(newClipRegion);
+
+ if (exposedRegion.Valid())
+ Invalidate(exposedRegion);
+
+ // Now set the new clip region for this window.
+ fClipRegion = newClipRegion;
+ fGC.SetClipRegion(fClipRegion);
+ fGC.SetOrigin(myScreenFrame.left, myScreenFrame.top);
+}
+
+void Window::AddChild(const Rect &frame, Window *child)
+{
+ child->fFrame = frame;
+ child->fGC.SetRenderer(fGC.GetRenderer());
+
+ child->fNextSibling = fChildList;
+ child->fPreviousSibling = &fChildList;
+ if (fChildList)
+ fChildList->fPreviousSibling = &child->fNextSibling;
+
+ fChildList = child;
+ child->fParent = this;
+ if (child->IsVisible())
+ UpdateClipRegion();
+}
+
+void Window::RemoveChild(Window *window)
+{
+ ASSERT(window->parent == this);
+ ASSERT(window->fPreviousSibling);
+
+ *window->fPreviousSibling = window->fNextSibling;
+ fParent = 0;
+
+ // Should remove all of its children
+
+ UpdateClipRegion();
+}
+
+void Window::MoveToFront()
+{
+ fParent->RemoveChild(this);
+ fParent->AddChild(fFrame, this);
+ UpdateClipRegion();
+}
+
+void Window::SetVisibleRegion(const Region ®ion)
+{
+ fVisibleRegion = region;
+ UpdateClipRegion();
+
+ if (fInRedraw) {
+ Region drawRegion = fCurrentRedrawRegion;
+ drawRegion.Intersect(fClipRegion);
+ fGC.SetClipRegion(drawRegion);
+ } else
+ fGC.SetClipRegion(fClipRegion);
+}
+
+const Region& Window::ClipRegion() const
+{
+ return fClipRegion;
+}
+
+void Window::MoveTo(long x, long y)
+{
+ fFrame.OffsetTo(x, y);
+ UpdateClipRegion();
+}
+
+void Window::ResizeTo(long width, long height)
+{
+ fFrame.right = fFrame.left + width;
+ fFrame.bottom = fFrame.top + height;
+ UpdateClipRegion();
+}
+
+void Window::Invalidate(const Region ®ion)
+{
+ // Erase background
+ for (int rect = 0; rect < region.CountRects(); rect++) {
+ const Rect &clipRect = region.RectAt(rect);
+ fGC.GetRenderer()->FillRect(clipRect.left, clipRect.top, clipRect.right,
+ clipRect.bottom, Color());
+ }
+
+ fInvalidRegion.Include(region);
+ if (!fPaintMsgSent) {
+ Event paintEvent;
+ paintEvent.what = EVT_PAINT;
+ PostEvent(&paintEvent);
+ fPaintMsgSent = true;
+ }
+}
+
+void Window::Invalidate(const Rect &rect)
+{
+ Rect screenRect(LocalToScreen(rect));
+
+ // Erase background
+ Region eraseRegion(fVisibleRegion);
+ Region invalRegion;
+ invalRegion.Include(screenRect);
+ eraseRegion.Intersect(invalRegion);
+ for (int index = 0; index < eraseRegion.CountRects(); index++) {
+ const Rect &clipRect = eraseRegion.RectAt(index);
+ fGC.GetRenderer()->FillRect(clipRect.left, clipRect.top, clipRect.right,
+ clipRect.bottom, Color());
+ }
+
+ // The rect is assumed to be in window coordinates
+ fInvalidRegion.Include(screenRect);
+ if (!fPaintMsgSent) {
+ Event paintEvent;
+ paintEvent.what = EVT_PAINT;
+ PostEvent(&paintEvent);
+ fPaintMsgSent = true;
+ }
+}
+
+GraphicsContext& Window::GC()
+{
+ return fGC;
+}
+
+void Window::BeginPaint(Rect &out_invalidRect)
+{
+ fPaintMsgSent = false;
+ fInRedraw = true;
+ fCurrentRedrawRegion = fInvalidRegion;
+ fInvalidRegion.Clear();
+
+ Region drawRegion = fCurrentRedrawRegion;
+ drawRegion.Intersect(fClipRegion);
+ out_invalidRect = ScreenToLocal(drawRegion.Bounds());
+ fGC.SetClipRegion(drawRegion);
+}
+
+void Window::EndPaint()
+{
+ fInRedraw = false;
+}
+
+bool Window::IsVisible() const
+{
+ return fIsVisible;
+}
+
+char Window::Color() const
+{
+ return fColor;
+}
+
+void Window::SetColor(char c)
+{
+ fColor = c;
+}
+
+void Window::Show()
+{
+ if (!fIsVisible) {
+ fIsVisible = true;
+ if (fParent)
+ fParent->UpdateClipRegion();
+ }
+}
+
+void Window::Hide()
+{
+ if (fIsVisible) {
+ fIsVisible = false;
+ if (fParent)
+ fParent->UpdateClipRegion();
+ }
+}
+
+void Window::PostEvent(Event *event)
+{
+ event->target = fID;
+
+ msg_hdr_t header;
+ header.src = fEventPort; // May break someday
+ header.dst = fEventPort;
+ header.data = event;
+ header.size = sizeof(Event);
+ old_port_send(&header);
+}
+
+Rect Window::LocalToScreen(const Rect &inRect) const
+{
+ Rect outRect = inRect;
+ for (const Window *window = this; window; window = window->fParent)
+ outRect.OffsetBy(window->fFrame.left, window->fFrame.top);
+
+ return outRect;
+}
+
+Rect Window::ScreenToLocal(const Rect &inRect) const
+{
+ Rect outRect = inRect;
+ for (const Window *window = this; window; window = window->fParent)
+ outRect.OffsetBy(-window->fFrame.left, -window->fFrame.top);
+
+ return outRect;
+}
+
+void Window::DumpChildList(int level)
+{
+ for (int i = 0; i < level; i++)
+ printf(" | ");
+
+ Rect frame = Frame();
+ printf(" + %d %d %d %d\n", frame.left, frame.top, frame.right, frame.bottom);
+ for (Window *child = fChildList; child; child = child->fNextSibling)
+ child->DumpChildList(level + 1);
+}
+
+
+
diff --git a/srv/window/Window.h b/srv/window/Window.h
@@ -0,0 +1,103 @@
+#ifndef _WINDOW_H
+#define _WINDOW_H
+
+#include "Region.h"
+#include "GraphicsContext.h"
+
+class Event;
+
+class Window {
+public:
+
+ Window(int id, int eventPort, Renderer *renderer = 0);
+ ~Window();
+ void AddChild(const Rect& frame, Window *window);
+ void RemoveChild(Window *window);
+ void MoveToFront();
+ inline int ID() const;
+
+ Window *ChildAtPoint(int x, int y);
+
+ Rect LocalToScreen(const Rect&) const;
+ Rect ScreenToLocal(const Rect&) const;
+
+ void SetVisibleRegion(const Region&);
+ inline const Rect& Frame() const;
+ inline Rect Bounds() const;
+
+ const Region& InvalidRegion() const;
+ const Region& ClipRegion() const;
+ void Invalidate(const Region&);
+ void Invalidate(const Rect&);
+ void BeginPaint(Rect &out_invalidRect);
+ void EndPaint();
+ GraphicsContext& GC();
+ void ResetGC();
+ bool IsVisible() const;
+ char Color() const;
+ void SetColor(char);
+ void Show();
+ void Hide();
+ void PostEvent(Event*);
+
+ void DumpChildList(int level = 0);
+
+private:
+ void UpdateClipRegion();
+ void MoveTo(long, long);
+ void ResizeTo(long, long);
+
+ int fID;
+ Window *fNextSibling;
+ Window **fPreviousSibling;
+ Window *fChildList;
+ Window *fParent;
+
+ Region fInvalidRegion;
+ Region fCurrentRedrawRegion;
+
+ // The visible region represents what part of this window is not
+ // obscured by siblings of my parent. I maintain this
+ // when recomputing clipping for my children.
+ Region fVisibleRegion;
+
+ // The clip region is the visible region, minus parts of my window
+ // that are obscured by my children.
+ Region fClipRegion;
+
+ Rect fFrame;
+ GraphicsContext fGC;
+ bool fIsVisible;
+ bool fInRedraw;
+ int fEventPort;
+ bool fPaintMsgSent;
+ char fColor;
+};
+
+inline int Window::ID() const
+{
+ return fID;
+}
+
+inline const Rect& Window::Frame() const
+{
+ return fFrame;
+}
+
+inline Rect Window::Bounds() const
+{
+ Rect rect(fFrame);
+ rect.OffsetTo(0, 0);
+ return rect;
+}
+
+inline const Region& Window::InvalidRegion() const
+{
+ return fInvalidRegion;
+}
+
+
+
+
+#endif
+
diff --git a/srv/window/WindowManager.cpp b/srv/window/WindowManager.cpp
@@ -0,0 +1,524 @@
+#include <blt/os.h>
+#include <blt/syscall.h>
+#include <blt/namer.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <win/Event.h>
+
+#include "WindowManager.h"
+#include "Renderer.h"
+#include "Window.h"
+#include "protocol.h"
+#include "SerialMouse.h"
+#include "Renderer_vga.h"
+
+const int kReceiveBufferSize = 16384;
+const int kMaxStrLen = 256;
+
+WindowManager::WindowManager(Renderer *screenRenderer)
+ : fNextWindowID(1),
+ fReceiveBufferSize(0),
+ fReceiveBufferPos(0),
+ fCurrentMouseFocus(0),
+ fMouseFocusLocked(false),
+ fInFocusLockedWindow(false),
+ fScreenRenderer(screenRenderer)
+{
+ fReceiveBuffer = (char*) malloc(kReceiveBufferSize);
+ for (int i = 0; i < kMaxWindows; i++)
+ fWindowArray[i] = 0;
+
+ // Create the root window, which has an id of 0.
+ fWindowArray[0] = new Window(0, -1, screenRenderer);
+ Region screen;
+ screen.Include(screenRenderer->Bounds());
+ fWindowArray[0]->SetVisibleRegion(screen);
+
+ fCursorLock = qsem_create(1);
+
+ thr_create((void*) StartDispatchThread, this, "draw_thread");
+ thr_create((void*) StartMouseThread, this, "mouse_thread");
+}
+
+WindowManager::~WindowManager()
+{
+ qsem_destroy(fCursorLock);
+}
+
+Window* WindowManager::CreateWindow(Window *parent, const Rect &rect, int eventPort)
+{
+ while (fWindowArray[fNextWindowID % kMaxWindows] != 0)
+ fNextWindowID++;
+
+ Window *window = new Window(fNextWindowID, eventPort);
+ fWindowArray[fNextWindowID % kMaxWindows] = window;
+ fNextWindowID++;
+
+ parent->AddChild(rect, window);
+ return window;
+}
+
+void WindowManager::InvalidateMouseBoundries()
+{
+ fMouseBoundries.SetTo(-1, -1, -1, -1);
+}
+
+
+void WindowManager::DestroyWindow(Window *window)
+{
+ fWindowArray[window->ID() % kMaxWindows] = 0;
+ delete window;
+}
+
+Window* WindowManager::LookupWindow(int id)
+{
+ Window *window = fWindowArray[id % kMaxWindows];
+ if (window && window->ID() == id)
+ return window;
+
+ return 0;
+}
+
+Window* WindowManager::WindowAtPoint(int x, int y)
+{
+ Window *root = LookupWindow(0);
+ return root->ChildAtPoint(x, y);
+}
+
+int WindowManager::StartDispatchThread(void *windowManager)
+{
+ ((WindowManager*) windowManager)->DispatchThread();
+ return 0;
+}
+
+void WindowManager::ReadServicePort(void *data, int size)
+{
+ int sizeRead = 0;
+ while (sizeRead < size) {
+ int sizeToRead = size - sizeRead;
+
+ if (fReceiveBufferSize - fReceiveBufferPos < sizeToRead)
+ sizeToRead = fReceiveBufferSize - fReceiveBufferPos;
+
+ if (sizeToRead == 0) {
+ msg_hdr_t header;
+ header.src = 0;
+ header.dst = fServicePort;
+ header.data = fReceiveBuffer;
+ header.size = kReceiveBufferSize;
+
+ fReceiveBufferSize = old_port_recv(&header);
+ fReceiveBufferPos = 0;
+ fRequestorPort = header.src;
+ continue;
+ }
+
+ memcpy((void*) ((char*) data + sizeRead),
+ (void*) (fReceiveBuffer + fReceiveBufferPos), sizeToRead);
+ fReceiveBufferPos += sizeToRead;
+ sizeRead += sizeToRead;
+ }
+}
+
+void WindowManager::Respond(void *data, int size)
+{
+ msg_hdr_t header;
+ header.src = fServicePort;
+ header.dst = RequestorPort();
+ header.data = data;
+ header.size = size;
+ old_port_send(&header);
+}
+
+int WindowManager::ReadInt32()
+{
+ int outval;
+ ReadServicePort(&outval, 4);
+ return outval;
+}
+
+short WindowManager::ReadInt16()
+{
+ short outval;
+ ReadServicePort(&outval, 2);
+ return outval;
+}
+
+char WindowManager::ReadInt8()
+{
+ char outval;
+ ReadServicePort(&outval, 1);
+ return outval;
+}
+
+int WindowManager::RequestorPort() const
+{
+ return fRequestorPort;
+}
+
+void WindowManager::LockCursor()
+{
+ qsem_acquire(fCursorLock);
+}
+
+void WindowManager::UnlockCursor()
+{
+ qsem_release(fCursorLock);
+}
+
+void WindowManager::DispatchThread()
+{
+ fServicePort = port_create(0, "window_server");
+
+ namer_register(fServicePort, "window_server");
+
+ while (true) {
+ int opcode = ReadInt8();
+ switch (opcode) {
+ case OP_DRAW_LINE: {
+ long windowID = ReadInt32();
+ long x1 = ReadInt32();
+ long y1 = ReadInt32();
+ long x2 = ReadInt32();
+ long y2 = ReadInt32();
+
+ Window *targetWindow = LookupWindow(windowID);
+ LockCursor();
+ if (targetWindow)
+ targetWindow->GC().DrawLine(x1, y1, x2, y2);
+ UnlockCursor();
+
+ break;
+ }
+
+ case OP_FILL_RECT: {
+ long windowID = ReadInt32();
+ long x1 = ReadInt32();
+ long y1 = ReadInt32();
+ long x2 = ReadInt32();
+ long y2 = ReadInt32();
+ Window *targetWindow = LookupWindow(windowID);
+ LockCursor();
+ if (targetWindow)
+ targetWindow->GC().FillRect(x1, y1, x2, y2);
+ UnlockCursor();
+
+ break;
+ }
+
+ case OP_SET_PEN_COLOR: {
+ long windowID = ReadInt32();
+ char color = ReadInt8();
+ Window *targetWindow = LookupWindow(windowID);
+ if (targetWindow)
+ targetWindow->GC().SetColor(color);
+
+ break;
+ }
+
+ case OP_SET_BG_COLOR: {
+ long windowID = ReadInt32();
+ char color = ReadInt8();
+ Window *targetWindow = LookupWindow(windowID);
+ if (targetWindow) {
+ targetWindow->SetColor(color);
+ targetWindow->Invalidate(targetWindow->Bounds());
+ }
+
+ break;
+ }
+
+ case OP_DRAW_STRING: {
+ // Draw string
+ long windowID = ReadInt32();
+ long x = ReadInt32();
+ long y = ReadInt32();
+
+ char buf[kMaxStrLen + 1];
+ char c;
+ int index = 0;
+ while (true) {
+ c = ReadInt8();
+ if (c == 0)
+ break;
+
+ if (index < kMaxStrLen)
+ buf[index++] = c;
+ }
+
+ buf[index] = 0;
+ Window *targetWindow = LookupWindow(windowID);
+ LockCursor();
+ if (targetWindow)
+ targetWindow->GC().DrawString(x, y, buf);
+
+ UnlockCursor();
+ }
+
+ case OP_DESTROY_WINDOW: {
+ long windowID = ReadInt32();
+ Window *targetWindow = LookupWindow(windowID);
+ if (targetWindow)
+ DestroyWindow(targetWindow);
+
+ InvalidateMouseBoundries();
+ break;
+ }
+
+ case OP_SHOW_WINDOW: {
+ long windowID = ReadInt32();
+ Window *targetWindow = LookupWindow(windowID);
+ if (targetWindow)
+ targetWindow->Show();
+
+ InvalidateMouseBoundries();
+ break;
+ }
+
+ case OP_HIDE_WINDOW: {
+ long windowID = ReadInt32();
+ Window *targetWindow = LookupWindow(windowID);
+ if (targetWindow)
+ targetWindow->Hide();
+
+ InvalidateMouseBoundries();
+ break;
+ }
+
+ case OP_MAKE_FOCUS: {
+ long windowID = ReadInt32();
+ Window *targetWindow = LookupWindow(windowID);
+ if (targetWindow)
+ targetWindow->MoveToFront();
+
+ InvalidateMouseBoundries();
+ break;
+ }
+
+ case OP_BEGIN_PAINT: {
+ long windowID = ReadInt32();
+ Rect rect;
+ Window *targetWindow = LookupWindow(windowID);
+ if (targetWindow)
+ targetWindow->BeginPaint(rect);
+
+ Respond(&rect, sizeof(rect));
+ break;
+ }
+
+ case OP_END_PAINT: {
+ long windowID = ReadInt32();
+ Window *targetWindow = LookupWindow(windowID);
+ if (targetWindow)
+ targetWindow->EndPaint();
+
+ break;
+ }
+
+ case OP_CREATE_WINDOW: {
+ long parentWindow = ReadInt32();
+ Rect rect;
+ rect.left = ReadInt32();
+ rect.top = ReadInt32();
+ rect.right = ReadInt32();
+ rect.bottom = ReadInt32();
+ long eventPort = ReadInt32();
+
+ Window *parent = LookupWindow(parentWindow);
+ int id = -1;
+ LockCursor();
+ if (parent)
+ id = CreateWindow(parent, rect, eventPort)->ID();
+ UnlockCursor();
+
+ Respond(&id, sizeof(id));
+ InvalidateMouseBoundries();
+ break;
+ }
+
+ case OP_COPY_RECT: {
+ long windowID = ReadInt32();
+ Rect sourceRect;
+ sourceRect.left = ReadInt32();
+ sourceRect.top = ReadInt32();
+ sourceRect.right = ReadInt32();
+ sourceRect.bottom = ReadInt32();
+
+ long destX = ReadInt32();
+ long destY = ReadInt32();
+ Rect destRect(sourceRect);
+ destRect.OffsetTo(destX, destY);
+
+ Window *targetWindow = LookupWindow(windowID);
+ LockCursor();
+ if (targetWindow) {
+ Region invalidateRegion;
+ if (targetWindow->InvalidRegion().Valid()) {
+ // Parts of the window are damaged and can't be copied.
+ Region copyRegion = targetWindow->ClipRegion();
+ copyRegion.Exclude(targetWindow->InvalidRegion());
+ targetWindow->GC().CopyRect(sourceRect, destRect,
+ copyRegion, invalidateRegion);
+ } else {
+ targetWindow->GC().CopyRect(sourceRect, destRect,
+ targetWindow->ClipRegion(), invalidateRegion);
+ }
+
+ // Draw parts of the window which have been "copied"
+ // out from under another window.
+ targetWindow->Invalidate(invalidateRegion);
+ }
+ UnlockCursor();
+
+ break;
+ }
+
+ case OP_INVALIDATE: {
+ long windowID = ReadInt32();
+ Rect rect;
+ rect.left = ReadInt32();
+ rect.top = ReadInt32();
+ rect.right = ReadInt32();
+ rect.bottom = ReadInt32();
+
+ Window *targetWindow = LookupWindow(windowID);
+ LockCursor();
+ if (targetWindow)
+ targetWindow->Invalidate(rect);
+ UnlockCursor();
+
+ break;
+ }
+
+ case OP_LOCK_MOUSE_FOCUS:
+ fMouseFocusLocked = true;
+ break;
+
+ default:
+ printf("unrecognized drawing command %d\n", opcode);
+ }
+ }
+}
+
+void WindowManager::SetCursorPos(int x, int y)
+{
+ LockCursor();
+ // a bit of a hack for now
+ ((Renderer_vga*)fScreenRenderer)->SetCursorPosition(x, y);
+ UnlockCursor();
+}
+
+int WindowManager::StartMouseThread(void *_wm)
+{
+ ((WindowManager*) _wm)->MouseThread();
+ return 0;
+}
+
+void WindowManager::MouseThread()
+{
+ SerialMouse *mouse = new SerialMouse(fScreenRenderer->BufferWidth() - 1, fScreenRenderer->BufferHeight()
+ - 1);
+ int cx = 160, cy = 100, buttons = 0;
+ int last_cx = cx;
+ int last_cy = cy;
+ int last_buttons = buttons;
+ while (true) {
+ mouse->GetPos(&cx, &cy, &buttons);
+
+ if (last_cx != cx || last_cy != cy) {
+ SetCursorPos(cx, cy);
+ last_cx = cx;
+ last_cy = cy;
+
+ Window *oldMouseFocus = fCurrentMouseFocus;
+ if (fCurrentMouseFocus == 0 || !fMouseBoundries.Contains(cx, cy)) {
+ // Either there is no focus window, or we have moved out
+ // of the current rectangle that is known to be in this window.
+ // Check to see what window we are over.
+ Window *focusWindow = WindowAtPoint(cx, cy);
+ if (fMouseFocusLocked) {
+ // Mouse focus is locked, don't actually switch focus windows
+ if (focusWindow == fCurrentMouseFocus && !fInFocusLockedWindow) {
+ // Inform the window with locked focus that the mouse has entered
+ Rect screenFrame = fCurrentMouseFocus->LocalToScreen(
+ fCurrentMouseFocus->Bounds());
+ Event evt;
+ evt.what = EVT_MOUSE_ENTER;
+ evt.target = fCurrentMouseFocus->ID();
+ evt.x = cx - screenFrame.left;
+ evt.y = cy - screenFrame.top;
+ fCurrentMouseFocus->PostEvent(&evt);
+ fInFocusLockedWindow = true;
+ } else if (focusWindow != fCurrentMouseFocus && fInFocusLockedWindow) {
+ // Inform the window with the locked focus that the mouse has left.
+ Event evt;
+ evt.what = EVT_MOUSE_LEAVE;
+ evt.target = oldMouseFocus->ID();
+ fCurrentMouseFocus->PostEvent(&evt);
+ fInFocusLockedWindow = false;
+ }
+
+ focusWindow->ClipRegion().FindRect(cx, cy, fMouseBoundries);
+ } else {
+ fCurrentMouseFocus = focusWindow;
+ fCurrentMouseFocus->ClipRegion().FindRect(cx, cy, fMouseBoundries);
+ }
+ }
+
+ if (oldMouseFocus == fCurrentMouseFocus) {
+ // Post a mouse moved message to the current focus window
+ Rect screenFrame = fCurrentMouseFocus->LocalToScreen(
+ fCurrentMouseFocus->Bounds());
+
+ Event evt;
+ evt.what = EVT_MOUSE_MOVED;
+ evt.target = fCurrentMouseFocus->ID();
+ evt.x = cx - screenFrame.left;
+ evt.y = cy - screenFrame.top;
+ fCurrentMouseFocus->PostEvent(&evt);
+ } else {
+ // Inform the old window (if there is one), that the mouse is leaving
+ if (oldMouseFocus) {
+ Event evt;
+ evt.what = EVT_MOUSE_LEAVE;
+ evt.target = oldMouseFocus->ID();
+ oldMouseFocus->PostEvent(&evt);
+ }
+
+ // Inform the new window that the mouse has entered
+ Rect screenFrame = fCurrentMouseFocus->LocalToScreen(
+ fCurrentMouseFocus->Bounds());
+
+ Event evt;
+ evt.what = EVT_MOUSE_ENTER;
+ evt.target = fCurrentMouseFocus->ID();
+ evt.x = cx - screenFrame.left;
+ evt.y = cy - screenFrame.top;
+ fCurrentMouseFocus->PostEvent(&evt);
+ }
+ }
+
+ if (buttons != last_buttons && fCurrentMouseFocus) {
+ // If the user has released the buttons, unlock the mouse focus
+ if (buttons == 0 && fMouseFocusLocked) {
+ InvalidateMouseBoundries();
+ fMouseFocusLocked = false;
+ }
+
+ // Send a button message to the window
+ Rect screenFrame = fCurrentMouseFocus->LocalToScreen(
+ fCurrentMouseFocus->Bounds());
+
+ Event evt;
+ evt.what = buttons != 0 ? EVT_MOUSE_DOWN : EVT_MOUSE_UP;
+ evt.target = fCurrentMouseFocus->ID();
+ evt.x = cx - screenFrame.left;
+ evt.y = cy - screenFrame.top;
+ fCurrentMouseFocus->PostEvent(&evt);
+ last_buttons = buttons;
+ }
+
+ os_sleep(1);
+ }
+}
diff --git a/srv/window/WindowManager.h b/srv/window/WindowManager.h
@@ -0,0 +1,62 @@
+#ifndef _WINDOW_MANAGER_H
+#define _WINDOW_MANAGER_H
+
+#include <blt/qsem.h>
+#include "Rect.h"
+
+class Renderer;
+class Window;
+
+const int kMaxWindows = 255;
+
+class WindowManager {
+public:
+
+ WindowManager(Renderer *screenRenderer);
+ ~WindowManager();
+
+private:
+
+ Window* CreateWindow(Window *parent, const Rect &rect, int eventPort);
+ void DestroyWindow(Window *window);
+ Window* LookupWindow(int id);
+ Window* WindowAtPoint(int x, int y);
+
+ int RequestorPort() const;
+ static int StartDispatchThread(void *windowManager);
+ void DispatchThread();
+ void ReadServicePort(void*, int);
+ int ReadInt32();
+ short ReadInt16();
+ char ReadInt8();
+ void Respond(void *, int);
+
+ void SetCursorPos(int x, int y);
+ static int StartMouseThread(void *_wm);
+ void MouseThread();
+ void LockCursor();
+ void UnlockCursor();
+
+ void InvalidateMouseBoundries();
+
+
+ Window *fWindowArray[kMaxWindows];
+ int fNextWindowID;
+
+ int fServicePort;
+ char *fReceiveBuffer;
+ int fReceiveBufferSize;
+ int fReceiveBufferPos;
+ int fRequestorPort;
+ qsem_t *fCursorLock;
+
+ Rect fMouseBoundries;
+ Window *fCurrentMouseFocus;
+ bool fMouseFocusLocked;
+ bool fInFocusLockedWindow;
+
+ Renderer *fScreenRenderer;
+};
+
+
+#endif
diff --git a/srv/window/assert.h b/srv/window/assert.h
@@ -0,0 +1,7 @@
+#ifndef ASSERT_H
+#define ASSERT_H
+
+#define ASSERT(x)
+#define trespass(x)
+
+#endif
diff --git a/srv/window/font.h b/srv/window/font.h
@@ -0,0 +1,130 @@
+const unsigned char font5x8[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
diff --git a/srv/window/main.cpp b/srv/window/main.cpp
@@ -0,0 +1,290 @@
+#include <blt/namer.h>
+#include <blt/syscall.h>
+#include <blt/conio.h>
+#include <blt/os.h>
+#include <blt/qsem.h>
+#include <string.h>
+#include "Renderer_vga.h"
+#include "GraphicsContext.h"
+#include "Window.h"
+#include "WindowManager.h"
+#include "vga.h"
+
+
+struct ColorMapEntry {
+ int red;
+ int green;
+ int blue;
+} colorTable[255] = {
+ {0, 0, 0},
+ {112, 219, 147},
+ {112, 219, 147},
+ {50, 204, 153},
+ {50, 204, 153},
+ {0, 0, 0},
+ {0, 0, 0},
+ {0, 0, 255},
+ {0, 0, 255},
+ {95, 159, 159},
+ {95, 159, 159},
+ {66, 66, 111},
+ {66, 66, 111},
+ {107, 35, 142},
+ {107, 35, 142},
+ {191, 216, 216},
+ {191, 216, 216},
+ {143, 143, 188},
+ {143, 143, 188},
+ {50, 50, 204},
+ {50, 50, 204},
+ {127, 0, 255},
+ {127, 0, 255},
+ {47, 47, 79},
+ {47, 47, 79},
+ {35, 35, 142},
+ {35, 35, 142},
+ {35, 35, 142},
+ {35, 35, 142},
+ {50, 153, 204},
+ {50, 153, 204},
+ {0, 127, 255},
+ {0, 127, 255},
+ {35, 107, 142},
+ {35, 107, 142},
+ {255, 127, 0},
+ {255, 127, 0},
+ {0, 255, 255},
+ {0, 255, 255},
+ {142, 35, 35},
+ {142, 35, 35},
+ {204, 127, 50},
+ {204, 127, 50},
+ {219, 219, 112},
+ {219, 219, 112},
+ {234, 234, 173},
+ {234, 234, 173},
+ {0, 255, 0},
+ {0, 255, 0},
+ {47, 79, 47},
+ {47, 79, 47},
+ {79, 79, 47},
+ {79, 79, 47},
+ {35, 142, 35},
+ {35, 142, 35},
+ {50, 204, 50},
+ {50, 204, 50},
+ {107, 142, 35},
+ {107, 142, 35},
+ {66, 111, 66},
+ {66, 111, 66},
+ {127, 255, 0},
+ {127, 255, 0},
+ {143, 188, 143},
+ {143, 188, 143},
+ {35, 142, 107},
+ {35, 142, 107},
+ {0, 255, 127},
+ {0, 255, 127},
+ {153, 204, 50},
+ {153, 204, 50},
+ {47, 79, 79},
+ {47, 79, 79},
+ {47, 79, 79},
+ {47, 79, 79},
+ {84, 84, 84},
+ {84, 84, 84},
+ {84, 84, 84},
+ {84, 84, 84},
+ {168, 168, 168},
+ {168, 168, 168},
+ {168, 168, 168},
+ {168, 168, 168},
+ {159, 159, 95},
+ {159, 159, 95},
+ {255, 0, 255},
+ {255, 0, 255},
+ {142, 35, 107},
+ {142, 35, 107},
+ {204, 50, 50},
+ {204, 50, 50},
+ {219, 112, 219},
+ {219, 112, 219},
+ {153, 50, 204},
+ {153, 50, 204},
+ {147, 112, 219},
+ {147, 112, 219},
+ {188, 143, 143},
+ {188, 143, 143},
+ {234, 173, 234},
+ {234, 173, 234},
+ {255, 0, 0},
+ {255, 0, 0},
+ {79, 47, 47},
+ {79, 47, 47},
+ {219, 112, 147},
+ {219, 112, 147},
+ {255, 0, 127},
+ {255, 0, 127},
+ {204, 50, 153},
+ {204, 50, 153},
+ {111, 66, 66},
+ {111, 66, 66},
+ {142, 107, 35},
+ {142, 107, 35},
+ {219, 147, 112},
+ {219, 147, 112},
+ {216, 191, 216},
+ {216, 191, 216},
+ {173, 234, 234},
+ {173, 234, 234},
+ {112, 147, 219},
+ {112, 147, 219},
+ {112, 219, 219},
+ {112, 219, 219},
+ {79, 47, 79},
+ {79, 47, 79},
+ {159, 95, 159},
+ {159, 95, 159},
+ {216, 216, 191},
+ {216, 216, 191},
+ {252, 252, 252},
+ {252, 252, 252},
+ {255, 255, 0},
+ {255, 255, 0},
+ {147, 219, 112},
+ {147, 219, 112},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255},
+ {255, 255, 255} // Transparent color
+};
+
+
+int main()
+{
+ InitVGA();
+ char *vmem = (char*) 0xa0000;
+ area_create(64*1024, 0, (void**) &vmem, AREA_PHYSMAP);
+ memset((void*) vmem, 0, 320 * 200);
+
+ Renderer *screen = new Renderer_vga((char*) vmem, 320, 200, 320);
+ for (int i = 0; i < 256; i++)
+ SetPalette(i, colorTable[i].red, colorTable[i].green, colorTable[i].blue);
+
+ new WindowManager(screen);
+ return 0;
+}
diff --git a/srv/window/protocol.h b/srv/window/protocol.h
@@ -0,0 +1,20 @@
+#ifndef _PROTOCOL_H
+#define _PROTOCOL_H
+
+const char OP_DRAW_LINE = 1;
+const char OP_FILL_RECT = 2;
+const char OP_SET_PEN_COLOR = 3;
+const char OP_DRAW_STRING = 4;
+const char OP_DESTROY_WINDOW = 5;
+const char OP_HIDE_WINDOW = 6;
+const char OP_SHOW_WINDOW = 7;
+const char OP_MAKE_FOCUS = 8;
+const char OP_BEGIN_PAINT = 9;
+const char OP_END_PAINT = 10;
+const char OP_SET_BG_COLOR = 11;
+const char OP_CREATE_WINDOW = 12;
+const char OP_COPY_RECT = 13;
+const char OP_INVALIDATE = 14;
+const char OP_LOCK_MOUSE_FOCUS = 15;
+
+#endif
diff --git a/srv/window/util.h b/srv/window/util.h
@@ -0,0 +1,7 @@
+#ifndef UTIL_H
+#define UTIL_H
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+#endif
diff --git a/srv/window/vga.cpp b/srv/window/vga.cpp
@@ -0,0 +1,104 @@
+/* $Id: $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "vga.h"
+
+#include <i386/io.h>
+
+const int MiscOutputReg = 0x3c2;
+const int DataReg = 0x3c0;
+const int AddressReg = 0x3c0;
+
+const char mode13[][32] = {
+ { 0x03, 0x01, 0x0f, 0x00, 0x0e }, /* 0x3c4, index 0-4*/
+ { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x0e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
+ 0xff }, /* 0x3d4, index 0-0x18*/
+ { 0, 0, 0, 0, 0, 0x40, 0x05, 0x0f, 0xff }, /* 0x3ce, index 0-8*/
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 0x41, 0, 0x0f, 0, 0 } /* 0x3c0, index 0-0x14*/
+};
+
+#define Vga256 0x13 // 320x200x256
+#define TextMode 0x03 // 80x25 text mode
+#define PaletteMask 0x3C6 // bit mask register
+#define PaletteRegisterRead 0x3C7 // read index
+#define PaletteRegisterWrite 0x3C8 // write index
+#define PaletteData 0x3C9 // send/receive data here
+#define RomCharSegment 0xF000
+#define RomCharOffset 0xFA6E
+#define CharWidth 8
+#define CharHeight 8
+
+void SetPalette(int color, int red, int green, int blue)
+{
+
+ outb(0xFF, PaletteMask);
+ outb(color, PaletteRegisterWrite);
+ outb(red, PaletteData);
+ outb(green, PaletteData);
+ outb(blue, PaletteData);
+}
+
+int InitVGA()
+{
+ int i;
+
+ outb_p(0x63, MiscOutputReg);
+ outb_p(0x00, 0x3da);
+
+ for (i=0; i < 5; i++) {
+ outb_p(i, 0x3c4);
+ outb_p(mode13[0][i], 0x3c4+1);
+ }
+
+ outw_p(0x0e11, 0x3d4);
+
+ for (i=0; i < 0x19; i++) {
+ outb_p(i, 0x3d4);
+ outb_p(mode13[1][i], (0x3d4 + 1));
+ }
+
+ for (i=0; i < 0x9; i++) {
+ outb_p(i, 0x3ce);
+ outb_p(mode13[2][i], (0x3ce + 1));
+ }
+
+ inb_p(0x3da);
+
+ for (i=0; i < 0x15; i++) {
+ inw(DataReg);
+ outb_p(i, AddressReg);
+ outb_p(mode13[3][i], DataReg);
+ }
+
+ outb_p(0x20, 0x3c0);
+
+ return 1;
+}
+
diff --git a/srv/window/vga.h b/srv/window/vga.h
@@ -0,0 +1,34 @@
+/* $Id: $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef _vga_h
+#define _vga_h
+
+void SetPalette(int color, int red, int green, int blue);
+int InitVGA();
+
+#endif
diff --git a/util/Makefile b/util/Makefile
@@ -0,0 +1,26 @@
+# $Id: //depot/blt/util/Makefile#3 $
+
+CC=cc
+CFLAGS=-O2
+#-DxBIG_ENDIAN
+#NETSTUFF=-lsocket -lnsl
+
+all: netboot bootmaker dumphex
+
+netboot: netboot.o
+ $(CC) -o netboot netboot.o $(NETSTUFF)
+
+bootmaker: bootmaker.o
+ $(CC) -o bootmaker bootmaker.o
+
+dumphex: dumphex.o
+ $(CC) -o dumphex dumphex.o
+
+dumph: dumph.o
+ $(CC) -o dumph dumph.o
+
+bootblock.h: dumph bootsect.bin
+ ./dumph bootsect.bin > bootblock.h
+
+clean:
+ rm -f netboot bootmaker dumphex *.o *~
diff --git a/util/blt-link b/util/blt-link
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# $Id: //depot/blt/util/link#1 $
+#
+# Copyright 1998 Sidney Cammeresi
+# All rights reserved.
+#
+# You may use this file in accordance with the license of this distribution.
+#
+# Script to generate dynamically linked executables
+
+gcc -nostdlib -nostartfiles $BLTSRCDIR/lib/crt0.o -L$BLTHOME/lib/obj -e _start -Wl,-dynamic-linker,/system/lib/rtld,-T,$BLTSRCDIR/util/blt_i386.x $@
+
diff --git a/util/blt_i386.x b/util/blt_i386.x
@@ -0,0 +1,80 @@
+/* $Id: //depot/blt/util/blt_i386.x#2 $ */
+/* Modified by Sidney Cammeresi */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386",
+ "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0x1000 + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.text : { *(.rel.text) }
+ .rela.text : { *(.rela.text) }
+ .rel.data : { *(.rel.data) }
+ .rela.data : { *(.rela.data) }
+ .rel.rodata : { *(.rel.rodata) }
+ .rela.rodata : { *(.rela.rodata) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.init : { *(.rel.init) }
+ .rela.init : { *(.rela.init) }
+ .rel.fini : { *(.rel.fini) }
+ .rela.fini : { *(.rela.fini) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init : { *(.init) } =0x9090
+ .plt : { *(.plt) }
+ .text :
+ {
+ *(.text)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0x9090
+ _etext = .;
+ PROVIDE (etext = .);
+ .fini : { *(.fini) } =0x9090
+ .rodata : { *(.rodata) }
+ .rodata1 : { *(.rodata1) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN(0x1000) + (ALIGN(8) & (0x1000 - 1));
+ .data :
+ {
+ *(.data)
+ CONSTRUCTORS
+ }
+ .data1 : { *(.data1) }
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ .got : { *(.got.plt) *(.got) }
+ .dynamic : { *(.dynamic) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata : { *(.sdata) }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ .sbss : { *(.sbss) *(.scommon) }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+}
diff --git a/util/bootblock.h b/util/bootblock.h
@@ -0,0 +1,93 @@
+/* $Id: //depot/blt/util/bootblock.h#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+unsigned char bootblock[] = {
+ 0xeb, 0x03, 0x00, 0x00, 0x00, 0xfa, 0x33, 0xc0,
+ 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0xe8, 0xc4, 0x01,
+ 0x36, 0x0f, 0x01, 0x16, 0x4f, 0x7d, 0x0f, 0x20,
+ 0xc0, 0x0c, 0x01, 0x0f, 0x22, 0xc0, 0x66, 0xea,
+ 0x26, 0x7c, 0x00, 0x00, 0x08, 0x00, 0xbb, 0x10,
+ 0x00, 0x8e, 0xdb, 0x8e, 0xc3, 0x8e, 0xd3, 0x24,
+ 0xfe, 0x0f, 0x22, 0xc0, 0xea, 0x39, 0x00, 0xc0,
+ 0x07, 0x33, 0xc0, 0x8e, 0xc0, 0x8e, 0xd8, 0x8e,
+ 0xd0, 0x66, 0xbf, 0x00, 0x00, 0x10, 0x00, 0xbb,
+ 0x02, 0x00, 0x2e, 0x8b, 0x0e, 0x02, 0x00, 0x33,
+ 0xd2, 0xfb, 0xe8, 0x12, 0x01, 0xfa, 0xe8, 0x4b,
+ 0x01, 0x66, 0xa3, 0x00, 0x40, 0x66, 0xc7, 0x06,
+ 0x04, 0x40, 0x00, 0x00, 0x01, 0x00, 0x66, 0x89,
+ 0xc1, 0x66, 0xc1, 0xe9, 0x0c, 0x66, 0x8b, 0x3e,
+ 0x04, 0x40, 0x66, 0x81, 0xc1, 0x00, 0x04, 0x00,
+ 0x00, 0x66, 0x33, 0xc0, 0xf3, 0x67, 0x66, 0xab,
+ 0x66, 0x8b, 0x1e, 0x04, 0x40, 0x66, 0x8b, 0x0e,
+ 0x00, 0x40, 0x66, 0xc1, 0xe9, 0x0c, 0x66, 0xb8,
+ 0x03, 0x00, 0x00, 0x00, 0x66, 0xbf, 0x00, 0x10,
+ 0x00, 0x00, 0x66, 0x67, 0x89, 0x04, 0x3b, 0x66,
+ 0x05, 0x00, 0x10, 0x00, 0x00, 0x66, 0x83, 0xc7,
+ 0x04, 0xe2, 0xef, 0x66, 0x8b, 0x0e, 0x00, 0x40,
+ 0x66, 0xc1, 0xe9, 0x16, 0x66, 0x41, 0x66, 0xa1,
+ 0x04, 0x40, 0x66, 0x05, 0x03, 0x10, 0x00, 0x00,
+ 0x66, 0x33, 0xff, 0x66, 0x67, 0x89, 0x04, 0x3b,
+ 0x66, 0x67, 0x89, 0x84, 0x3b, 0x00, 0x0f, 0x00,
+ 0x00, 0x66, 0x05, 0x00, 0x10, 0x00, 0x00, 0x66,
+ 0x83, 0xc7, 0x04, 0xe2, 0xe6, 0x66, 0xa1, 0x04,
+ 0x40, 0x66, 0x89, 0xc1, 0x0c, 0x03, 0x66, 0x67,
+ 0x89, 0x83, 0xfc, 0x0f, 0x00, 0x00, 0x66, 0x67,
+ 0x8b, 0x1d, 0x74, 0x00, 0x10, 0x00, 0x66, 0x81,
+ 0xc3, 0x00, 0x10, 0x10, 0x00, 0x66, 0xbd, 0x00,
+ 0x00, 0x10, 0x00, 0xb0, 0xcf, 0x2e, 0xa2, 0x5d,
+ 0x01, 0x2e, 0xa2, 0x65, 0x01, 0x2e, 0x0f, 0x01,
+ 0x16, 0x4f, 0x01, 0x0f, 0x22, 0xd9, 0x66, 0xb8,
+ 0x01, 0x00, 0x00, 0x80, 0x0f, 0x22, 0xc0, 0x66,
+ 0xea, 0x27, 0x7d, 0x00, 0x00, 0x08, 0x00, 0x66,
+ 0xb8, 0x10, 0x00, 0x66, 0x8e, 0xd8, 0x66, 0x8e,
+ 0xc0, 0x66, 0x8e, 0xe0, 0x66, 0x8e, 0xe8, 0x66,
+ 0x8e, 0xd0, 0x89, 0xcc, 0x83, 0xec, 0x04, 0xba,
+ 0x04, 0x7c, 0x00, 0x00, 0x55, 0x52, 0x67, 0xff,
+ 0x36, 0x00, 0x40, 0xff, 0xd3, 0xeb, 0xfe, 0xff,
+ 0xff, 0x4f, 0x7d, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x9a, 0x8f, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x92, 0x8f, 0x00, 0x53,
+ 0x51, 0xb0, 0x13, 0x28, 0xd8, 0x8b, 0xcb, 0xbb,
+ 0x00, 0x80, 0xb4, 0x02, 0xcd, 0x13, 0x72, 0x2a,
+ 0x66, 0xbe, 0x00, 0x80, 0x00, 0x00, 0x66, 0x33,
+ 0xc9, 0x88, 0xc1, 0xc1, 0xe1, 0x07, 0xf3, 0x67,
+ 0x66, 0xa5, 0x59, 0x5b, 0x80, 0xf6, 0x01, 0x75,
+ 0x02, 0xfe, 0xc7, 0xb3, 0x01, 0x32, 0xe4, 0x2b,
+ 0xc8, 0x7f, 0xcc, 0xb0, 0x0c, 0xba, 0xf2, 0x03,
+ 0xee, 0xc3, 0xeb, 0xfe, 0xb8, 0x32, 0x31, 0x66,
+ 0xbb, 0xf0, 0x0f, 0x10, 0x00, 0x67, 0x8b, 0x13,
+ 0x67, 0x89, 0x03, 0x67, 0x8b, 0x3b, 0x67, 0x89,
+ 0x13, 0x39, 0xc7, 0x75, 0x09, 0x66, 0x81, 0xc3,
+ 0x00, 0x10, 0x00, 0x00, 0xeb, 0xe7, 0x66, 0x8b,
+ 0xc3, 0x66, 0x2d, 0x00, 0x10, 0x00, 0x00, 0x66,
+ 0x83, 0xc0, 0x10, 0xc3, 0xe8, 0x0f, 0x00, 0x75,
+ 0x1b, 0xb0, 0xd1, 0xe6, 0x64, 0xe8, 0x06, 0x00,
+ 0x75, 0x12, 0xb0, 0xdf, 0xe6, 0x60, 0x66, 0xb9,
+ 0x00, 0x00, 0x02, 0x00, 0xeb, 0x00, 0xe4, 0x64,
+ 0xa8, 0x02, 0xe0, 0xf8, 0xc3, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x55, 0xaa,
+};
diff --git a/util/bootmaker.c b/util/bootmaker.c
@@ -0,0 +1,414 @@
+/* $Id: //depot/blt/util/bootmaker.c#4 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "../include/boot.h"
+
+#include "bootblock.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int make_floppy = 0;
+
+void die(char *s, char *a)
+{
+ fprintf(stderr,"error: ");
+ fprintf(stderr,s,a);
+ fprintf(stderr,"\n");
+ exit(1);
+}
+
+void *loadfile(char *file, int *size)
+{
+ int fd;
+ char *data;
+ struct stat info;
+
+ if((fd = open(file,O_RDONLY)) != -1){
+ if(fstat(fd,&info)){
+ close(fd);
+ *size = 0;
+ return NULL;
+ }
+ data = (char *) malloc(info.st_size);
+ if(read(fd, data, info.st_size) != info.st_size) {
+ close(fd);
+ *size = 0;
+ return NULL;
+ }
+ close(fd);
+ *size = info.st_size;
+ return data;
+ }
+ *size = 0;
+ return NULL;
+}
+
+/* at location 2 is a uint16, set to blocks * 8 */
+int writebootblock(FILE *fp, unsigned int blocks)
+{
+ unsigned char bb[512];
+
+ blocks *= 8;
+
+ memcpy(bb,bootblock,512);
+
+ bb[2] = (blocks & 0x00FF);
+ bb[3] = (blocks & 0xFF00) >> 8;
+
+ fwrite(bb,512,1,fp);
+}
+
+typedef struct _nvpair
+{
+ struct _nvpair *next;
+ char *name;
+ char *value;
+} nvpair;
+
+
+typedef struct _section
+{
+ struct _section *next;
+ char *name;
+ struct _nvpair *firstnv;
+} section;
+
+void print_sections(section *first)
+{
+ nvpair *p;
+
+ while(first){
+ printf("\n[%s]\n",first->name);
+ for(p = first->firstnv; p; p = p->next){
+ printf("%s=%s\n",p->name,p->value);
+ }
+ first = first->next;
+ }
+}
+
+#ifdef xBIG_ENDIAN
+unsigned int fix(unsigned int x)
+{
+ int r;
+ unsigned char *a = (unsigned char *) &x;
+ unsigned char b[4];
+
+ b[0] = a[3];
+ b[1] = a[2];
+ b[2] = a[1];
+ b[3] = a[0];
+
+ r = *((unsigned int *)b);
+ return r;
+
+}
+#else
+#define fix(x) (x)
+#endif
+
+#define stNEWLINE 0
+#define stSKIPLINE 1
+#define stHEADER 2
+#define stLHS 3
+#define stRHS 4
+
+section *first = NULL;
+section *last = NULL;
+
+section *load_ini(char *file)
+{
+ char *data,*end;
+ int size;
+ int state = stNEWLINE;
+ section *cur;
+
+ char *lhs,*rhs;
+
+ if(!(data = loadfile(file,&size))){
+ return NULL;
+ }
+ end = data+size;
+
+ while(data < end){
+ switch(state){
+ case stSKIPLINE:
+ if(*data == '\n'){
+ state = stNEWLINE;
+ }
+ data++;
+ break;
+
+ case stNEWLINE:
+ if(*data == '\n'){
+ data++;
+ break;
+ }
+ if(*data == '['){
+ lhs = data+1;
+ state = stHEADER;
+ data++;
+ break;
+ }
+ if(*data == '#' || *data <= ' '){
+ state = stSKIPLINE;
+ data++;
+ break;
+ }
+ lhs = data;
+ data++;
+ state = stLHS;
+ break;
+ case stHEADER:
+ if(*data == ']'){
+ cur = (section *) malloc(sizeof(section));
+ cur->name = lhs;
+ cur->firstnv = NULL;
+ cur->next = NULL;
+ if(last){
+ last->next = cur;
+ last = cur;
+ } else {
+ last = first = cur;
+ }
+ *data = 0;
+ state = stSKIPLINE;
+ }
+ data++;
+ break;
+ case stLHS:
+ if(*data == '\n'){
+ state = stNEWLINE;
+ }
+ if(*data == '='){
+ *data = 0;
+ rhs = data+1;
+ state = stRHS;
+ }
+ data++;
+ continue;
+ case stRHS:
+ if(*data == '\n'){
+ nvpair *p = (nvpair *) malloc(sizeof(nvpair));
+ p->name = lhs;
+ p->value = rhs;
+ *data = 0;
+ p->next = cur->firstnv;
+ cur->firstnv = p;
+ state = stNEWLINE;
+ }
+ data++;
+ break;
+ }
+ }
+ return first;
+
+}
+
+
+char *getval(section *s, char *name)
+{
+ nvpair *p;
+ for(p = s->firstnv; p; p = p->next){
+ if(!strcmp(p->name,name)) return p->value;
+ }
+ return NULL;
+}
+
+char *getvaldef(section *s, char *name, char *def)
+{
+ nvpair *p;
+ for(p = s->firstnv; p; p = p->next){
+ if(!strcmp(p->name,name)) return p->value;
+ }
+ return def;
+}
+
+#define centry bdir.bd_entry[c]
+void makeboot(section *s, char *outfile)
+{
+ FILE *fp;
+ void *rawdata[64];
+ int rawsize[64];
+ char fill[4096];
+ boot_dir bdir;
+ int i,c;
+ int nextpage = 1; /* page rel offset of next loaded object */
+
+ memset(fill,0,4096);
+
+ memset(&bdir, 0, 4096);
+ for(i=0;i<64;i++){
+ rawdata[i] = NULL;
+ rawsize[i] = 0;
+ }
+
+ c = 1;
+
+ bdir.bd_entry[0].be_type = fix(BE_TYPE_DIRECTORY);
+ bdir.bd_entry[0].be_size = fix(1);
+ bdir.bd_entry[0].be_vsize = fix(1);
+ rawdata[0] = (void *) &bdir;
+ rawsize[0] = 4096;
+
+ strcpy(bdir.bd_entry[0].be_name,"SBBB/Directory");
+
+ while(s){
+ char *type = getvaldef(s,"type","NONE");
+ char *file = getval(s,"file");
+ int vsize;
+ int size;
+ struct stat statbuf;
+
+ if(!type) die("section %s has no type",s->name);
+
+ strncpy(centry.be_name,s->name,32);
+ centry.be_name[31] = 0;
+
+ if(!file) die("section %s has no file",s->name);
+ if(!(rawdata[c] = loadfile(file,&rawsize[c])))
+ die("cannot load \"%s\"",file);
+
+ if(stat(file,&statbuf))
+ die("cannot stat \"%s\"",file);
+ vsize = statbuf.st_size;
+
+ centry.be_size = rawsize[c] / 4096 + (rawsize[c] % 4096 ? 1 : 0);
+ centry.be_vsize =
+ (vsize < centry.be_size) ? centry.be_size : vsize;
+
+ centry.be_offset = nextpage;
+ nextpage += centry.be_size;
+
+ centry.be_size = fix(centry.be_size);
+ centry.be_vsize = fix(centry.be_vsize);
+ centry.be_offset = fix(centry.be_offset);
+
+ if(!strcmp(type,"boot")){
+ centry.be_type = fix(BE_TYPE_BOOTSTRAP);
+ centry.be_code_vaddr = fix(atoi(getvaldef(s,"vaddr","0")));
+ centry.be_code_ventr = fix(atoi(getvaldef(s,"ventry","0")));
+ }
+ if(!strcmp(type,"code")){
+ centry.be_type = fix(BE_TYPE_CODE);
+ centry.be_code_vaddr = fix(atoi(getvaldef(s,"vaddr","0")));
+ centry.be_code_ventr = fix(atoi(getvaldef(s,"ventry","0")));
+ }
+ if(!strcmp(type,"data")){
+ centry.be_type = fix(BE_TYPE_DATA);
+ }
+ if(!strcmp(type,"elf32")){
+ centry.be_type = fix(BE_TYPE_ELF32);
+ }
+
+ if(centry.be_type == BE_TYPE_NONE){
+ die("unrecognized section type \"%s\"",type);
+ }
+
+ c++;
+ s = s->next;
+
+ if(c==64) die("too many sections (>63)",NULL);
+ }
+
+ if(!(fp = fopen(outfile,"w"))){
+ die("cannot write to \"%s\"",outfile);
+ }
+
+ if(make_floppy) {
+ fprintf(stderr,"whoohah!");
+
+ writebootblock(fp, nextpage+1);
+ }
+
+ for(i=0;i<c;i++){
+ fwrite(rawdata[i],rawsize[i],1,fp);
+ if(rawsize[i]%4096) fwrite(fill,4096 - (rawsize[i]%4096),1,fp);
+ }
+ fclose(fp);
+
+
+}
+
+int main(int argc, char **argv)
+{
+ char *file = NULL;
+ section *s;
+
+ if(argc < 2){
+usage:
+ fprintf(stderr,"usage: %s [ --floppy | -f ] [ <inifile> ... ] -o <bootfile>\n",argv[0]);
+ return 1;
+ }
+
+ argc--;
+ argv++;
+
+ while(argc){
+ if(!strcmp(*argv,"--floppy")){
+ make_floppy = 1;
+ } else if(!strcmp(*argv,"-o")){
+ argc--;
+ argv++;
+ if(argc){
+ file = *argv;
+ } else {
+ goto usage;
+ }
+ } else {
+ if(load_ini(*argv) == NULL){
+ fprintf(stderr,"warning: cannot load '%s'\n",*argv);
+ }
+ }
+ argc--;
+ argv++;
+ }
+
+
+ if((argc > 3) && !strcmp(argv[3],"-floppy")){
+ make_floppy = 1;
+ }
+
+ if(!file){
+ fprintf(stderr,"error: no output specified\n");
+ goto usage;
+ }
+
+ if(!first){
+ fprintf(stderr,"error: no data to write?!\n");
+ goto usage;
+ }
+
+ makeboot(first,file);
+
+ return 0;
+}
diff --git a/util/dfp.h b/util/dfp.h
@@ -0,0 +1,126 @@
+/* $Id: //depot/blt/util/dfp.h#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*
+** Distributed Fish Protocol
+** Version 1.0
+**
+** Special Interest Group for Operating Systems
+** Association for Computing Machinery
+** University of Illinios at Urbana-Champaign
+*/
+
+#ifndef _DFP_H
+#define _DFP_H
+
+#ifdef _WIN32
+#include <sys/types.h>
+#include <winsock.h>
+#endif
+
+#ifdef NEED_TYPES
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef char sint8;
+#endif
+
+#define DFP_VERSION 0x0201
+
+#define DEFAULT_DFP_PORT 5049
+
+#define DFP_MIN_SUBTANK_X 0
+#define DFP_MAX_SUBTANK_X 3
+#define DFP_MIN_SUBTANK_Y 0
+#define DFP_MAX_SUBTANK_Y 3
+
+#define DFP_PKT_PING 0
+#define DFP_PKT_PONG 1
+#define DFP_PKT_SEND_FISH 2
+#define DFP_PKT_ACK_FISH 3
+#define DFP_PKT_NACK_FISH 4
+#define DFP_PKT_SYNC_FISH 5
+
+/* pack everything along byte boundaries */
+#pragma pack( 1 )
+
+typedef struct
+{
+ uint16 version;
+ uint8 src_tank_x;
+ uint8 src_tank_y;
+ uint8 dst_tank_x;
+ uint8 dst_tank_y;
+ uint8 type; /* one of DFP_PKT_* */
+ uint8 pad; /* should be 0 */
+ uint16 size; /* size of entire packet */
+} dfp_base;
+
+typedef struct
+{
+ uint8 creator_tank_x;
+ uint8 creator_tank_y;
+ uint8 timestamp[4];
+} dfp_uid;
+
+typedef struct
+{
+ uint8 x;
+ uint8 y;
+ sint8 dx;
+ sint8 dy;
+ uint16 ttl;
+ uint8 name[16];
+} dfp_fish;
+
+
+#define DFP_SIZE_LOCATE 10
+#define DFP_SIZE_CONFIRM 16
+#define DFP_SIZE_TRANSFER 38
+
+
+typedef struct
+{
+ dfp_base base;
+} dfp_pkt_locate;
+
+typedef struct
+{
+ dfp_base base;
+ dfp_uid uid;
+} dfp_pkt_confirm;
+
+typedef struct
+{
+ dfp_base base;
+ dfp_uid uid;
+ dfp_fish fish;
+} dfp_pkt_transfer;
+
+/* restore default packing */
+#pragma pack()
+
+#endif /* __DFP_H */
diff --git a/util/dumph.c b/util/dumph.c
@@ -0,0 +1,59 @@
+/* $Id: //depot/blt/util/dumph.c#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+
+static void dump(unsigned char *x, int sections)
+{
+ int i;
+
+ printf("unsigned char bootblock[] = {\n");
+
+ for(i=0;i<sections;i++){
+ printf("\t0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n\t0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
+ x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],
+ x[8],x[9],x[10],x[11],x[12],x[13],x[14],x[15]);
+ x += 16;
+
+ }
+
+ printf("};\n");
+
+}
+
+int main(int argc, char *argv[])
+{
+ FILE *fp;
+ unsigned char buf[4096*3];
+ if(fp = fopen(argv[1],"r")){
+ fread(buf,1,512,fp);
+ dump(buf,512/16);
+ fclose(fp);
+ }
+ return 0;
+
+}
diff --git a/util/dumphex.c b/util/dumphex.c
@@ -0,0 +1,51 @@
+/* $Id: //depot/blt/util/dumphex.c#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+
+static void dump(unsigned char *x, int sections)
+{
+ int i;
+
+ for(i=0;i<sections;i++){
+ printf("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ 16*i,x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],
+ x[8],x[9],x[10],x[11],x[12],x[13],x[14],x[15]);
+ x += 16;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ FILE *fp;
+ unsigned char buf[4096*3];
+ if(fp = fopen(argv[1],"r")){
+ fread(buf,1,4096*3,fp);
+ dump(buf,4096*3/16);
+ fclose(fp);
+ }
+}
diff --git a/util/fishfinder.c b/util/fishfinder.c
@@ -0,0 +1,108 @@
+/* $Id: //depot/blt/util/fishfinder.c#2 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+
+#undef uint32
+
+#define NEED_TYPES
+#include "dfp.h"
+
+char *types[] = { "PING", "PONG", "SEND", "ACK ", "NAK ", "SYNC" };
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in dst,src;
+ dfp_pkt_transfer dfp,dfp2;
+ char n2[17];
+ int s;
+
+
+ src.sin_family = AF_INET;
+ src.sin_addr.s_addr = htonl(INADDR_ANY);
+ src.sin_port = htons(DEFAULT_DFP_PORT);
+
+ if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ perror("socket");
+
+ if(bind(s, (struct sockaddr *) &src, sizeof(src)) == -1)
+ perror("bind");
+
+ for(;;){
+ if(recvfrom(s,(void *)&dfp,sizeof(dfp),0,NULL,NULL) < 0) {
+ perror("recvfrom");
+ }
+ dfp.base.size = ntohs(dfp.base.size);
+ dfp.base.version = ntohs(dfp.base.version);
+
+ if(dfp.base.version != DFP_VERSION){
+ printf("version mismatch!\n");
+ continue;
+ }
+
+ if(dfp.base.type > 5) continue;
+
+ printf("%s: (%d,%d) -> (%d,%d) ", types[dfp.base.type],
+ dfp.base.src_tank_x, dfp.base.src_tank_y,
+ dfp.base.dst_tank_x, dfp.base.dst_tank_y,
+ dfp.base.size);
+
+ switch(dfp.base.type){
+ case DFP_PKT_PING:
+ case DFP_PKT_PONG:
+ printf("\n");
+ break;
+ case DFP_PKT_SYNC_FISH:
+ case DFP_PKT_SEND_FISH:
+ printf("[%02x%02x%02x%02x%02x%02x] ",
+ dfp.uid.creator_tank_x, dfp.uid.creator_tank_y,
+ dfp.uid.timestamp[0], dfp.uid.timestamp[1],
+ dfp.uid.timestamp[2], dfp.uid.timestamp[3]);
+ strncpy(n2,dfp.fish.name,16);
+ n2[16]=0;
+ printf("@(%3d,%3d) d(%3d,%3d) \"%s\"\n",
+ dfp.fish.x, dfp.fish.y, dfp.fish.dx, dfp.fish.dy, n2);
+ break;
+ case DFP_PKT_NACK_FISH:
+ case DFP_PKT_ACK_FISH:
+ printf("[%02x%02x%02x%02x%02x%02x]\n",
+ dfp.uid.creator_tank_x, dfp.uid.creator_tank_y,
+ dfp.uid.timestamp[0], dfp.uid.timestamp[1],
+ dfp.uid.timestamp[2], dfp.uid.timestamp[3]);
+ break;
+ }
+ }
+
+ close(s);
+ return 0;
+}
diff --git a/util/ic.c b/util/ic.c
@@ -0,0 +1,367 @@
+// RPC Interface Compiler (ic)
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <string.h>
+
+typedef struct ic_type ic_type;
+typedef struct ic_param ic_param;
+typedef struct ic_func ic_func;
+typedef struct ic_ifc ic_ifc;
+
+struct ic_type
+{
+ ic_type *next;
+
+ char *name;
+ enum {
+ BASIC,
+ ARRAY,
+ STRING,
+ STRUCT
+ } type;
+ int size;
+ ic_type *parts;
+};
+
+struct ic_param
+{
+ ic_param *next;
+
+ char *name;
+ ic_type *type;
+ enum {
+ IN = 1,
+ OUT = 2
+ } flags;
+};
+
+struct ic_func
+{
+ ic_func *next;
+
+ char *name;
+ ic_param *params;
+};
+
+struct ic_ifc
+{
+ char *name;
+ char *key;
+ ic_func *funcs;
+};
+
+ic_type *types = NULL;
+
+ic_type builtins[] = {
+ { NULL, "int32", BASIC, 4, NULL },
+ { NULL, "uint32", BASIC, 4, NULL },
+ { NULL, "int16", BASIC, 2, NULL },
+ { NULL, "uint16", BASIC, 2, NULL },
+ { NULL, NULL, BASIC, 0, NULL }
+};
+
+int line = 1;
+char token[256];
+char *data;
+char *file;
+
+void die(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap,fmt);
+ fprintf(stderr,"%s:%d - ",file,line);
+ vfprintf(stderr,fmt,ap);
+ fprintf(stderr,"\n");
+ va_end(ap);
+ exit(1);
+}
+
+
+void next(void)
+{
+ char *x = token;
+
+ if(*data == 0) {
+ token[0] = 0;
+ return;
+ }
+
+eat_space:
+ while(*data <= ' ') {
+ if(*data == '\n') line++;
+ data++;
+ }
+
+ if(*data == '#') {
+ while(*data != '\n') data++;
+ goto eat_space;
+ }
+
+ if(*data == '"') {
+ data++;
+ while(*data != '"') {
+ *x++ = *data++;
+ }
+ *x = 0;
+ data++;
+ return;
+ }
+
+ for(;;){
+ switch(*data){
+ case '{':
+ case '}':
+ case '(':
+ case ')':
+ case ',':
+ case '#':
+ case '"':
+ case ':':
+ if(x == token){
+ *x++ = *data++;
+ }
+ *x = 0;
+ return;
+ default:
+ if(*data <= ' '){
+ *x = 0;
+ return;
+ } else {
+ *x++ = *data++;
+ if((x - token) > 255) die("token too long");
+ }
+ }
+ }
+}
+
+int match(const char *tok)
+{
+ if(!strcmp(token,tok)){
+ next();
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void force(const char *tok)
+{
+ if(strcmp(token,tok)){
+ die("expecting '%s', found '%s'",tok,token);
+ }
+ next();
+}
+
+ic_type *type(void)
+{
+ ic_type *t;
+
+ if(match("string")){
+ t = (ic_type *) malloc(sizeof(ic_type));
+ if(!t) die("out of memory");
+
+ force(":");
+ t->size = atoi(token); next();
+ t->name = "string";
+ t->type = STRING;
+ t->next = NULL;
+ t->parts = NULL;
+
+ return t;
+ }
+
+ for(t = types; t; t = t->next){
+ if(match(t->name)) return t;
+ }
+
+ die("unknown type '%s'",token);
+ return NULL;
+}
+
+ic_param *param(void)
+{
+ ic_param *p = (ic_param*) malloc(sizeof(ic_param));
+ if(!p) die("out of memory");
+
+ if(match("in")){
+ p->flags = IN;
+ } else if(match("out")) {
+ p->flags = OUT;
+ } else {
+ die("expecting 'in' or 'out', found '%s'",token);
+ }
+
+ p->type = type();
+ p->name = strdup(token); next();
+ p->next = NULL;
+
+ return p;
+}
+
+ic_func *function(void)
+{
+ ic_param *p,*last = NULL;
+ ic_func *func = (ic_func*) malloc(sizeof(ic_func));
+ if(!func) die("out of memory");
+
+ func->name = strdup(token); next();
+ func->next = NULL;
+ func->params = NULL;
+
+ force("(");
+
+ for(;;){
+ if(match(")")) {
+ match(";"); /* optional semi */
+ return func;
+ }
+ p = param();
+ if(last) {
+ last->next = p;
+ } else {
+ func->params = p;
+ }
+ last = p;
+ match(",");
+ }
+}
+
+
+
+ic_ifc *interface(void)
+{
+ ic_func *func,*last = NULL;
+ ic_ifc *ifc = (ic_ifc*) malloc(sizeof(ic_ifc));
+
+ if(!ifc) die("out of memory");
+
+ ifc->name = strdup(token); next();
+ ifc->key = strdup(token); next();
+ ifc->funcs = NULL;
+
+ force("{");
+
+ for(;;){
+ if(match("}")) {
+ match(";"); /* optional semi */
+ return ifc;
+ }
+ func = function();
+ if(last){
+ last->next = func;
+ } else {
+ ifc->funcs = func;
+ }
+ last = func;
+ }
+}
+
+void mkheader(FILE *f, ic_ifc *ifc)
+{
+ ic_func *func;
+ ic_param *p;
+ char *upname,*x;
+
+ x = upname = strdup(ifc->name);
+ while(*x) {
+ *x = toupper(*x);
+ x++;
+ }
+ fprintf(f,"/* Generated File - DO NOT EDIT */\n\n");
+ fprintf(f,"#define IFC_%s \"%s\"\n\n",upname,ifc->key);
+ fprintf(f,"typedef struct {\n");
+ for(func = ifc->funcs; func; func = func->next){
+ fprintf(f,"\tstatus_t (*%s)(\n",func->name);
+ fprintf(f,"\t\tconst ifc_handle *handle%s\n",func->params?",":"");
+
+ for(p = func->params; p; p = p->next){
+ fprintf(f,"\t\t%s %s%s\n",p->type->name,p->name,
+ p->next ? "," : "");
+ }
+ fprintf(f,"\t\t);\n");
+ }
+ fprintf(f,"} ifc_%s;\n",ifc->name);
+}
+
+void mkstub(FILE *f, ic_ifc *ifc)
+{
+ ic_func *func;
+ ic_param *p;
+
+ fprintf(f,"/* Generated File - DO NOT EDIT */\n\n");
+
+ /* eject the stubs */
+ for(func = ifc->funcs; func; func = func->next){
+ fprintf(f,"static status_t\n");
+ fprintf(f,"stub_%s(\n",func->name);
+ fprintf(f,"\t)\n");
+ fprintf(f,"{\n");
+ fprintf(f,"\treturn -1;\n");
+ fprintf(f,"}\n\n");
+ }
+
+ /* eject the decl */
+ fprintf(f,"ifc_%s ifc_%s_impl = {\n",ifc->name,ifc->name);
+ for(func = ifc->funcs; func; func = func->next){
+ fprintf(f,"\t&stub_%s%s\n",func->name,func->next?",":"");
+ }
+ fprintf(f,"};\n");
+}
+
+void parse(void)
+{
+ ic_ifc *ifc;
+ next();
+
+ for(;;){
+ if(match("interface")) {
+ ifc = interface();
+ mkheader(stdout,ifc);
+ mkstub(stdout,ifc);
+ }
+ if(match("")) return;
+ die("unexpected token '%s'",token);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int i,fd;
+ struct stat s;
+
+ /* install built-in types */
+ for(i=0;builtins[i].name;i++){
+ builtins[i].next = types;
+ types = builtins + i;
+ }
+
+ if(argc != 2) {
+ fprintf(stderr,"error: no input file\n");
+ return 1;
+ }
+
+ file = argv[1];
+
+ if(((fd = open(file,O_RDONLY)) < 0) || fstat(fd,&s)){
+ fprintf(stderr,"error: cannot open \"%s\"\n",file);
+ return 1;
+ }
+
+ data = (char*) malloc(s.st_size + 1);
+ read(fd, data, s.st_size);
+ data[s.st_size] = 0;
+ close(fd);
+
+ parse();
+}
+
+
+
+
+
+
+\ No newline at end of file
diff --git a/util/namer.ifc b/util/namer.ifc
@@ -0,0 +1,14 @@
+#
+# BLT Naming Service
+#
+
+interface namer "/blt/system/namer" {
+ lookup(
+ in string:256 name,
+ out int32 port
+ )
+ register(
+ in string:256 name,
+ in int32 port
+ )
+}
+\ No newline at end of file
diff --git a/util/netboot.c b/util/netboot.c
@@ -0,0 +1,129 @@
+/* $Id: //depot/blt/util/netboot.c#3 $
+**
+** Copyright 1998 Brian J. Swetland
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions, and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions, and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "../netboot/netboot.h"
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in dst,src;
+ char buf[128];
+ net_boot nb,nbr;
+ int fd;
+ struct timeval timeout;
+ int s,l,i;
+ fd_set read_fds;
+
+ if(argc != 3) {
+ fprintf(stderr,"usage: test <filename> <addr>\n");
+ exit(1);
+
+ }
+ dst.sin_family = AF_INET;
+ dst.sin_addr.s_addr = inet_addr(argv[2]);
+ dst.sin_port = htons(NETBOOT_PORT);
+
+ src.sin_family = AF_INET;
+ src.sin_addr.s_addr = htonl(INADDR_ANY);
+ src.sin_port = htons(NETBOOT_PORT);
+
+ if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ perror("socket");
+
+ if(bind(s, (struct sockaddr *) &src, sizeof(src)) == -1)
+ perror("bind");
+
+ fprintf(stderr,"loading [");
+
+ fd = open(argv[1],O_RDONLY);
+
+ i = 0;
+
+ while(read(fd,&(nb.data),1024) > 0){
+ nb.cmd = htons(NETBOOT_CMD_LOAD);
+ nb.blk = htons(i);
+
+ retry:
+ if(sendto(s, &nb, sizeof(nb), 0, (struct sockaddr *) &dst, sizeof(dst))
+ == -1){
+ perror("sendto");
+ }
+
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+ FD_ZERO(&read_fds);
+ FD_SET(s,&read_fds);
+
+ if(select(s+1, &read_fds, NULL, NULL, &timeout) == 1){
+
+ if(recvfrom(s,&nbr,sizeof(nbr),0,NULL,NULL) < 0) {
+ fprintf(stderr,"e");
+ goto retry;
+ }
+ if(nbr.cmd != htons(NETBOOT_CMD_ACK)) {
+ fprintf(stderr,"e");
+ goto retry;
+ }
+ if(nbr.blk != nb.blk) {
+ fprintf(stderr,"e");
+ goto retry;
+ }
+ fprintf(stderr,".");
+ } else {
+ fprintf(stderr,"T");
+ goto retry;
+ }
+ i++;
+ }
+
+ nb.cmd = htons(NETBOOT_CMD_EXEC);
+ nb.blk = htons(0);
+
+ if(sendto(s, &nb, 4, 0, (struct sockaddr *) &dst, sizeof(dst))
+ == -1){
+ perror("sendto");
+ }
+
+/* if(recvfrom(s,&nb,sizeof(nb),0,NULL,NULL) < 0) perror("recvfrom");
+ if(nb.cmd == htons(NETBOOT_CMD_ACK)) fprintf(stderr,"!");*/
+
+ fprintf(stderr,"] done\n");
+
+ close(s);
+
+ return 0;
+
+}