summaryrefslogtreecommitdiff
path: root/sys/arch/sgi/stand/boot
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2012-03-19 17:38:32 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2012-03-19 17:38:32 +0000
commit227e066fd9009304a6c891f3cb9faf2854a5ece1 (patch)
treeb8c52235f5a79e4ba42e7efbf3ffa12f32b30de6 /sys/arch/sgi/stand/boot
parent5f9c7bf79f6f68b257dd9c5b019b47217ab87267 (diff)
Teach the bootblocks how to load kernel from tftp (i.e. when OSLoadPartition
is bootp() instead of a disk). Kind of ugly because of the usual `can't seek' problem causing kernels with symbols to be read from the network twice. While there, add a 32 bit ECOFF boot block, not hooked to the build yet, to be used shortly.
Diffstat (limited to 'sys/arch/sgi/stand/boot')
-rw-r--r--sys/arch/sgi/stand/boot/Makefile5
-rw-r--r--sys/arch/sgi/stand/boot/arcbios.c15
-rw-r--r--sys/arch/sgi/stand/boot/boot.c6
-rw-r--r--sys/arch/sgi/stand/boot/conf.c11
-rw-r--r--sys/arch/sgi/stand/boot/diskio.c4
-rw-r--r--sys/arch/sgi/stand/boot/filesystem.c4
-rw-r--r--sys/arch/sgi/stand/boot/netfs.c291
-rw-r--r--sys/arch/sgi/stand/boot/netfs.h43
-rw-r--r--sys/arch/sgi/stand/boot/netio.c84
9 files changed, 449 insertions, 14 deletions
diff --git a/sys/arch/sgi/stand/boot/Makefile b/sys/arch/sgi/stand/boot/Makefile
index 2774eb6009c..d27ca2d696f 100644
--- a/sys/arch/sgi/stand/boot/Makefile
+++ b/sys/arch/sgi/stand/boot/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.11 2009/05/14 18:57:43 miod Exp $
+# $OpenBSD: Makefile,v 1.12 2012/03/19 17:38:31 miod Exp $
NOMAN= noman
@@ -11,7 +11,8 @@ CFLAGS+= -D__INTERNAL_LIBSA_CREAD ${STANDALONE}
AFLAGS+= ${SAABI}
S= ${.CURDIR}/../../../..
-SRCS= start.S boot.c filesystem.c conf.c diskio.c arcbios.c strstr.c
+SRCS= start.S arcbios.c boot.c conf.c diskio.c filesystem.c \
+ netfs.c netio.c strstr.c
.PATH: ${S}/lib/libsa
SRCS+= loadfile.c
diff --git a/sys/arch/sgi/stand/boot/arcbios.c b/sys/arch/sgi/stand/boot/arcbios.c
index 3c67a23dffc..ed7e32951c2 100644
--- a/sys/arch/sgi/stand/boot/arcbios.c
+++ b/sys/arch/sgi/stand/boot/arcbios.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: arcbios.c,v 1.14 2011/04/09 20:46:33 miod Exp $ */
+/* $OpenBSD: arcbios.c,v 1.15 2012/03/19 17:38:31 miod Exp $ */
/*-
* Copyright (c) 1996 M. Warner Losh. All rights reserved.
* Copyright (c) 1996-2004 Opsycon AB. All rights reserved.
@@ -47,6 +47,8 @@ static const struct systypes {
char *sys_name;
int sys_ip;
} sys_types[] = {
+ { "SGI-IP20", 20 },
+ { "SGI-IP22", 22 },
{ "SGI-IP30", 30 },
{ "SGI-IP32", 32 }
};
@@ -244,11 +246,15 @@ devopen(struct open_file *f, const char *fname, char **file)
int rc, i, n;
ecp = cp = fname;
+ namebuf[0] = '\0';
/*
* Scan the component list and find device and partition.
*/
- if (strncmp(cp, "dksc(", 5) == 0) {
+ if (strncmp(cp, "bootp()", 7) == 0) {
+ strlcpy(devname, "bootp", sizeof(devname));
+ strlcpy(namebuf, cp, sizeof(namebuf));
+ } else if (strncmp(cp, "dksc(", 5) == 0) {
strncpy(devname, "scsi", sizeof(devname));
cp += 5;
cp = boot_getnr(cp, &i);
@@ -257,7 +263,6 @@ devopen(struct open_file *f, const char *fname, char **file)
cp = boot_getnr(cp, &i);
/* i = target id */
if (*cp++ == ',') {
-
memcpy(namebuf, fname, cp - fname);
namebuf[cp - fname] = '\0';
strlcat(namebuf, "0)", sizeof namebuf);
@@ -291,10 +296,10 @@ devopen(struct open_file *f, const char *fname, char **file)
*/
dp = devsw;
n = ndevs;
- while(n--) {
+ while (n--) {
if (strcmp(devname, dp->dv_name) == 0) {
rc = (dp->dv_open)(f, namebuf, partition, 0);
- if (!rc) {
+ if (rc == 0) {
f->f_dev = dp;
if (file && *cp != '\0')
*file = (char *)cp;
diff --git a/sys/arch/sgi/stand/boot/boot.c b/sys/arch/sgi/stand/boot/boot.c
index 8af5f540b7b..89d99cf33b5 100644
--- a/sys/arch/sgi/stand/boot/boot.c
+++ b/sys/arch/sgi/stand/boot/boot.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: boot.c,v 1.18 2011/04/09 20:46:33 miod Exp $ */
+/* $OpenBSD: boot.c,v 1.19 2012/03/19 17:38:31 miod Exp $ */
/*
* Copyright (c) 2004 Opsycon AB, www.opsycon.se.
@@ -187,6 +187,10 @@ check_phdr(void *v)
uint64_t addr;
switch (IP) {
+ case 20:
+ case 22:
+ addr = 0xffffffff88000000ULL >> 28;
+ break;
case 27:
addr = 0xa800000000000000ULL >> 28;
break;
diff --git a/sys/arch/sgi/stand/boot/conf.c b/sys/arch/sgi/stand/boot/conf.c
index caa763f7b8f..b8c70ac1a01 100644
--- a/sys/arch/sgi/stand/boot/conf.c
+++ b/sys/arch/sgi/stand/boot/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.4 2011/03/13 00:13:53 deraadt Exp $ */
+/* $OpenBSD: conf.c,v 1.5 2012/03/19 17:38:31 miod Exp $ */
/*
* Copyright (c) 1997 Per Fogelstrom
@@ -34,11 +34,16 @@ extern int noioctl();
int diostrategy(void *, int, daddr32_t, size_t, void *, size_t *);
int dioopen(struct open_file *, ...);
int dioclose(struct open_file *);
-
#define dioioctl noioctl
+int netstrategy(void *, int, daddr32_t, size_t, void *, size_t *);
+int netopen(struct open_file *, ...);
+int netclose(struct open_file *);
+#define netioctl noioctl
+
struct devsw devsw[] = {
- { "scsi", diostrategy, dioopen, dioclose, dioioctl }
+ { "scsi", diostrategy, dioopen, dioclose, dioioctl },
+ { "bootp", netstrategy, netopen, netclose, netioctl }
};
int ndevs = (sizeof(devsw)/sizeof(devsw[0]));
diff --git a/sys/arch/sgi/stand/boot/diskio.c b/sys/arch/sgi/stand/boot/diskio.c
index e1bc49c51df..5768439a799 100644
--- a/sys/arch/sgi/stand/boot/diskio.c
+++ b/sys/arch/sgi/stand/boot/diskio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: diskio.c,v 1.6 2011/03/13 00:13:53 deraadt Exp $ */
+/* $OpenBSD: diskio.c,v 1.7 2012/03/19 17:38:31 miod Exp $ */
/*
* Copyright (c) 2000 Opsycon AB (www.opsycon.se)
@@ -45,7 +45,7 @@ struct dio_softc {
};
int
-diostrategy(void *devdata, int rw, daddr32_t bn, u_int reqcnt, void *addr,
+diostrategy(void *devdata, int rw, daddr32_t bn, size_t reqcnt, void *addr,
size_t *cnt)
{
struct dio_softc *sc = (struct dio_softc *)devdata;
diff --git a/sys/arch/sgi/stand/boot/filesystem.c b/sys/arch/sgi/stand/boot/filesystem.c
index e4f0fce6f00..c8c6efcffad 100644
--- a/sys/arch/sgi/stand/boot/filesystem.c
+++ b/sys/arch/sgi/stand/boot/filesystem.c
@@ -35,9 +35,11 @@
#include <stand.h>
#include <ufs.h>
+#include "netfs.h"
struct fs_ops file_system[] = {
- { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, ufs_stat }
+ { netfs_open, netfs_close, netfs_read, netfs_write, netfs_seek, netfs_stat },
+ { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, ufs_stat },
};
int nfsys = sizeof(file_system)/sizeof(struct fs_ops);
diff --git a/sys/arch/sgi/stand/boot/netfs.c b/sys/arch/sgi/stand/boot/netfs.c
new file mode 100644
index 00000000000..07d61b352d8
--- /dev/null
+++ b/sys/arch/sgi/stand/boot/netfs.c
@@ -0,0 +1,291 @@
+/* $OpenBSD: netfs.c,v 1.1 2012/03/19 17:38:31 miod Exp $ */
+
+/*-
+ * Copyright (c) 2001 Steve Murphree, Jr.
+ * 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 TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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.
+ */
+
+/*
+ * TFTP file system.
+ */
+
+#include <sys/param.h>
+#include <lib/libkern/libkern.h>
+#include <stand.h>
+
+#include <sys/stat.h>
+
+#include "netfs.h"
+
+/*
+ * In-core open file.
+ */
+struct tftp_file {
+ char filename[128];
+ off_t f_seekp; /* seek pointer */
+ char *f_buf; /* buffer for data block */
+ off_t f_off; /* index into buffer for data block */
+ daddr32_t f_buf_blkno; /* block number of data block */
+ size_t f_buf_size;
+};
+
+#define TFTP_BLOCK_SHIFT 9
+#define TFTP_BLOCK_SIZE (1<<TFTP_BLOCK_SHIFT) /* 512 by tftp convention */
+#define TFTP_BLOCK_NO(x) ((x >> TFTP_BLOCK_SHIFT) + 1)
+#define TFTP_BLOCK_OFF(x) (x % TFTP_BLOCK_SIZE)
+
+static int tftp_read_file(struct open_file *, char **, size_t *);
+
+/*
+ * Read a portion of a file into an internal buffer. Return
+ * the location in the buffer and the amount in the buffer.
+ */
+
+char tftp_buf[TFTP_BLOCK_SIZE]; /* static */
+struct tftp_file tftp_ctrl;
+
+static int
+tftp_read_file(f, buf_p, size_p)
+ struct open_file *f;
+ char **buf_p; /* out */
+ size_t *size_p; /* out */
+{
+ struct tftp_file *fp = (struct tftp_file *)f->f_fsdata;
+ long off;
+ daddr32_t file_block;
+ size_t block_size;
+ int i, rc;
+
+ off = TFTP_BLOCK_OFF(fp->f_seekp);
+ file_block = TFTP_BLOCK_NO(fp->f_seekp);
+ block_size = TFTP_BLOCK_SIZE;
+
+ if (file_block == fp->f_buf_blkno + 1) {
+ /*
+ * Normal, incremental block transfer.
+ */
+ rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ file_block, block_size, fp->f_buf, &fp->f_buf_size);
+ if (rc)
+ return (rc);
+ if (!(file_block % 4)) /* twiddle every 4 blocks */
+ twiddle();
+ fp->f_buf_blkno = file_block;
+ } else if (file_block > fp->f_buf_blkno + 1) {
+ /*
+ * Read ahead to the requested block; If we need
+ * those we skipped, see below.
+ */
+ for (i = (fp->f_buf_blkno + 1); i <= file_block; i++) {
+ rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ i, block_size, fp->f_buf, &fp->f_buf_size);
+ if (rc)
+ return (rc);
+ }
+ fp->f_buf_blkno = file_block;
+ } else if (file_block < fp->f_buf_blkno) {
+ /*
+ * Uh oh... We can't rewind. Reopen the file
+ * and start again.
+ */
+ char filename[128];
+
+ strlcpy(filename, fp->filename, sizeof filename);
+ netfs_close(f);
+ netfs_open(filename, f);
+
+ /* restore f_seekp reset by netfs_open() */
+ fp->f_seekp = (file_block - 1) * TFTP_BLOCK_SIZE + off;
+ for (i = 1; i <= file_block; i++) {
+ rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ i, block_size, fp->f_buf, &fp->f_buf_size);
+ if (rc)
+ return (rc);
+ }
+ fp->f_buf_blkno = file_block;
+ }
+
+ /*
+ * Return address of byte in buffer corresponding to
+ * offset, and size of remainder of buffer after that
+ * byte.
+ */
+ *buf_p = fp->f_buf + off;
+ *size_p = fp->f_buf_size - off;
+
+ /*
+ * But truncate buffer at end of file.
+ */
+ if (fp->f_buf_size > block_size){
+ twiddle();
+ return(EIO);
+ }
+
+
+ return (0);
+}
+
+/*
+ * Open a file.
+ */
+int
+netfs_open(path, f)
+ char *path;
+ struct open_file *f;
+{
+ struct tftp_file *fp;
+ int rc = 0;
+extern int netstrategy(void *, int, daddr32_t, size_t, void *, size_t *);
+
+ if (f->f_dev->dv_strategy != netstrategy)
+ return EINVAL;
+
+ /* locate file system specific data structure and zero it.*/
+ fp = &tftp_ctrl;
+ bzero(fp, sizeof(struct tftp_file));
+ f->f_fsdata = (void *)fp;
+ fp->f_seekp = 0;
+ fp->f_buf = tftp_buf;
+ bzero(fp->f_buf, TFTP_BLOCK_SIZE);
+ fp->f_buf_size = 0;
+
+ strlcpy(fp->filename, path, sizeof fp->filename);
+
+ twiddle();
+ rc = (f->f_dev->dv_open)(f, path);
+ return (rc);
+}
+
+int
+netfs_close(f)
+ struct open_file *f;
+{
+ struct tftp_file *fp = (struct tftp_file *)f->f_fsdata;
+
+ fp->f_buf = (void *)0;
+ f->f_fsdata = (void *)0;
+ (f->f_dev->dv_close)(f);
+ return (0);
+}
+
+/*
+ * Copy a portion of a file into kernel memory.
+ * Cross block boundaries when necessary.
+ */
+int
+netfs_read(f, start, size, resid)
+ struct open_file *f;
+ void *start;
+ size_t size;
+ size_t *resid; /* out */
+{
+ struct tftp_file *fp = (struct tftp_file *)f->f_fsdata;
+ size_t csize;
+ char *buf;
+ size_t buf_size;
+ int rc = 0;
+ char *addr = start;
+
+ while (size != 0) {
+ rc = tftp_read_file(f, &buf, &buf_size);
+ if (rc)
+ break;
+
+ csize = size;
+ if (csize > buf_size)
+ csize = buf_size;
+
+ bcopy(buf, addr, csize);
+
+ fp->f_seekp += csize;
+ addr += csize;
+ size -= csize;
+ }
+ if (resid)
+ *resid = size;
+ return (rc);
+}
+
+/*
+ * Not implemented.
+ */
+int
+netfs_write(f, start, size, resid)
+ struct open_file *f;
+ void *start;
+ size_t size;
+ size_t *resid; /* out */
+{
+
+ return (EROFS);
+}
+
+/*
+ * We only see forward. We can't rewind.
+ */
+off_t
+netfs_seek(f, offset, where)
+ struct open_file *f;
+ off_t offset;
+ int where;
+{
+ struct tftp_file *fp = (struct tftp_file *)f->f_fsdata;
+
+ switch (where) {
+ case SEEK_SET:
+ fp->f_seekp = offset;
+ break;
+ case SEEK_CUR:
+ fp->f_seekp += offset;
+ break;
+ case SEEK_END:
+ errno = EIO;
+ return (-1);
+ break;
+ default:
+ return (-1);
+ }
+ return (fp->f_seekp);
+}
+
+int
+netfs_stat(f, sb)
+ struct open_file *f;
+ struct stat *sb;
+{
+ return EIO;
+}
+
+#ifndef NO_READDIR
+int
+netfs_readdir (struct open_file *f, char *name)
+{
+ return EIO;
+}
+#endif
+
diff --git a/sys/arch/sgi/stand/boot/netfs.h b/sys/arch/sgi/stand/boot/netfs.h
new file mode 100644
index 00000000000..f6e1c4b44da
--- /dev/null
+++ b/sys/arch/sgi/stand/boot/netfs.h
@@ -0,0 +1,43 @@
+/* $OpenBSD: netfs.h,v 1.1 2012/03/19 17:38:31 miod Exp $ */
+
+/*-
+ * Copyright (c) 2001 Steve Murphree, Jr.
+ * 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 TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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.
+ */
+
+int netfs_open(char *path, struct open_file *f);
+int netfs_close(struct open_file *f);
+int netfs_read(struct open_file *f, void *buf,
+ size_t size, size_t *resid);
+int netfs_write(struct open_file *f, void *buf,
+ size_t size, size_t *resid);
+off_t netfs_seek(struct open_file *f, off_t offset, int where);
+int netfs_stat(struct open_file *f, struct stat *sb);
+#ifndef NO_READDIR
+int netfs_readdir(struct open_file *f, char *name);
+#endif
diff --git a/sys/arch/sgi/stand/boot/netio.c b/sys/arch/sgi/stand/boot/netio.c
new file mode 100644
index 00000000000..2a25d7f8aa0
--- /dev/null
+++ b/sys/arch/sgi/stand/boot/netio.c
@@ -0,0 +1,84 @@
+/* $OpenBSD: netio.c,v 1.1 2012/03/19 17:38:31 miod Exp $ */
+
+/*
+ * Copyright (c) 2012 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#include <sys/param.h>
+#include <lib/libkern/libkern.h>
+#include <stand.h>
+
+#include <mips64/arcbios.h>
+
+int
+netstrategy(void *devdata, int rw, daddr32_t bn, size_t reqcnt, void *addr,
+ size_t *cnt)
+{
+ long fd = (long)devdata;
+ long result;
+ int rc;
+
+ rc = Bios_Read(fd, addr, reqcnt, &result);
+ if (rc != 0)
+ return (EIO);
+
+ *cnt = result;
+ return 0;
+}
+
+int
+netopen(struct open_file *f, ...)
+{
+ char *path;
+ long fd;
+ int rc;
+ va_list ap;
+
+ va_start(ap, f);
+ path = va_arg(ap, char *);
+ va_end(ap);
+
+ /* to match netfs.c filename buffers... */
+ if (strlen(path) > 128 - 1)
+ return ENAMETOOLONG;
+
+ rc = Bios_Open(path, 0, &fd);
+ if (rc != 0) {
+ switch (rc) {
+ case arc_EACCES:
+ return EACCES;
+ case arc_EISDIR:
+ return EISDIR;
+ case arc_ENOENT:
+ return ENOENT;
+ default:
+ return ENXIO;
+ }
+ }
+
+ f->f_devdata = (void *)fd;
+
+ return 0;
+}
+
+int
+netclose(struct open_file *f)
+{
+ long fd = (long)f->f_devdata;
+
+ (void)Bios_Close(fd);
+ return 0;
+}