summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2010-02-17 21:25:50 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2010-02-17 21:25:50 +0000
commitfab147de8183bc711673520efc974d172c1e2050 (patch)
tree68dc90043fdbae636bc6bdc0a580b97f85dcc70f
parentf063e6044f09e58905b6d171b45e72679045f203 (diff)
If PMON has loaded an initrd binary, and this binary looks like a valid
ELF image, assume it's the kernel and try to boot it immediately. This allows a Gdium system with both the bootloader and the kernel image on an ext2fs partition, with `al' pointing to the bootblocks and `rd' pointing to the kernel in PMON environment, to boot a kernel with proper kernel symbols, for the first time. (please don't get me started on how reliable `load -k' is on the Gdium) Bump bootblocks version to 0.2.
-rw-r--r--sys/arch/loongson/stand/boot/Makefile.inc4
-rw-r--r--sys/arch/loongson/stand/boot/conf.c20
-rw-r--r--sys/arch/loongson/stand/boot/libsa.h24
-rw-r--r--sys/arch/loongson/stand/boot/machdep.c91
-rw-r--r--sys/arch/loongson/stand/boot/rd.c133
5 files changed, 236 insertions, 36 deletions
diff --git a/sys/arch/loongson/stand/boot/Makefile.inc b/sys/arch/loongson/stand/boot/Makefile.inc
index 751bf25a1df..804b2e456bf 100644
--- a/sys/arch/loongson/stand/boot/Makefile.inc
+++ b/sys/arch/loongson/stand/boot/Makefile.inc
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile.inc,v 1.1 2010/02/17 19:51:30 miod Exp $
+# $OpenBSD: Makefile.inc,v 1.2 2010/02/17 21:25:49 miod Exp $
.include "${.CURDIR}/../Makefile.inc"
@@ -18,7 +18,7 @@ AFLAGS+= ${SAABI}
.PATH: ${BOOTDIR}
SRCS= start.S
-SRCS+= conf.c cons.c dev.c devopen.c exec.c machdep.c
+SRCS+= conf.c cons.c dev.c devopen.c exec.c machdep.c rd.c
.PATH: ${S}/arch/loongson/loongson
SRCS+= pmon.c pmon32.S
diff --git a/sys/arch/loongson/stand/boot/conf.c b/sys/arch/loongson/stand/boot/conf.c
index 2562b38c4ec..32d41b78545 100644
--- a/sys/arch/loongson/stand/boot/conf.c
+++ b/sys/arch/loongson/stand/boot/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.2 2010/02/16 21:28:39 miod Exp $ */
+/* $OpenBSD: conf.c,v 1.3 2010/02/17 21:25:49 miod Exp $ */
/*
* Copyright (c) 1982, 1986, 1990, 1993
@@ -39,7 +39,7 @@
#include <lib/libsa/ufs.h>
#include <lib/libsa/cd9660.h>
-const char version[] = "0.1";
+const char version[] = "0.2";
#if 0 /* network code not compiled in */
int debug = 0;
#endif
@@ -48,6 +48,9 @@ int debug = 0;
* Device configuration
*/
struct devsw devsw[] = {
+ /* initrd */
+ { "rd", rd_iostrategy, rd_ioopen, rd_ioclose, noioctl },
+ /* ATA storage device */
{ "wd", pmon_iostrategy, pmon_ioopen, pmon_ioclose, noioctl }
};
int ndevs = NENTS(devsw);
@@ -56,10 +59,15 @@ int ndevs = NENTS(devsw);
* Filesystem configuration
*/
struct fs_ops file_system[] = {
- { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek,
- ufs_stat, ufs_readdir },
- { cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek,
- cd9660_stat, cd9660_readdir }
+ /* initrd ``filesystem'' */
+ { rdfs_open, rdfs_close, rdfs_read, rdfs_write,
+ rdfs_seek, rdfs_stat, rdfs_readdir },
+ /* ufs filesystem */
+ { ufs_open, ufs_close, ufs_read, ufs_write,
+ ufs_seek, ufs_stat, ufs_readdir },
+ /* cd9660 filesystem - in case a cd image is dd'ed on non USB media */
+ { cd9660_open, cd9660_close, cd9660_read, cd9660_write,
+ cd9660_seek, cd9660_stat, cd9660_readdir }
};
int nfsys = NENTS(file_system);
diff --git a/sys/arch/loongson/stand/boot/libsa.h b/sys/arch/loongson/stand/boot/libsa.h
index f0f87ac873d..c727d7985e4 100644
--- a/sys/arch/loongson/stand/boot/libsa.h
+++ b/sys/arch/loongson/stand/boot/libsa.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: libsa.h,v 1.2 2010/02/16 21:28:39 miod Exp $ */
+/* $OpenBSD: libsa.h,v 1.3 2010/02/17 21:25:49 miod Exp $ */
/*
* Copyright (c) 2010 Miodrag Vallat.
@@ -20,6 +20,9 @@
#define DEFAULT_KERNEL_ADDRESS 0
+/* where the initrd is loaded */
+#define INITRD_BASE PHYS_TO_CKSEG0(0x04000000)
+
/*
* MD interfaces for MI boot(9)
*/
@@ -42,6 +45,25 @@ int pmon_iostrategy(void *, int, daddr_t, size_t, void *, size_t *);
int pmon_ioopen(struct open_file *, ...);
int pmon_ioclose(struct open_file *);
+/*
+ * INITRD I/O
+ */
+int rd_iostrategy(void *, int, daddr_t, size_t, void *, size_t *);
+int rd_ioopen(struct open_file *, ...);
+int rd_ioclose(struct open_file *);
+int rd_isvalid(void);
+
+/*
+ * INITRD ``filesystem''
+ */
+int rdfs_open(char *path, struct open_file *f);
+int rdfs_close(struct open_file *f);
+int rdfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
+int rdfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
+off_t rdfs_seek(struct open_file *f, off_t offset, int where);
+int rdfs_stat(struct open_file *f, struct stat *sb);
+int rdfs_readdir(struct open_file *f, char *name);
+
extern int pmon_argc;
extern int32_t *pmon_argv;
extern int32_t *pmon_envp;
diff --git a/sys/arch/loongson/stand/boot/machdep.c b/sys/arch/loongson/stand/boot/machdep.c
index 46f529be831..05c74f5c0c2 100644
--- a/sys/arch/loongson/stand/boot/machdep.c
+++ b/sys/arch/loongson/stand/boot/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.2 2010/02/16 21:28:39 miod Exp $ */
+/* $OpenBSD: machdep.c,v 1.3 2010/02/17 21:25:49 miod Exp $ */
/*
* Copyright (c) 2010 Miodrag Vallat.
@@ -48,6 +48,13 @@
#include <machine/pmon.h>
#include <stand/boot/cmd.h>
+void gdium_abort(void);
+int is_gdium;
+int boot_rd;
+
+extern int bootprompt;
+extern char *kernelfile;
+
/*
* Console
*/
@@ -134,6 +141,15 @@ devboot(dev_t dev, char *path)
int i;
/*
+ * If we are booting the initrd image, things are easy...
+ */
+
+ if (dev != 0) {
+ strlcpy(path, "rd0a", BOOTDEVLEN);
+ return;
+ }
+
+ /*
* First, try to figure where we have been loaded from; we'll assume
* the default device to load the kernel from is the same.
*
@@ -203,7 +219,7 @@ devboot(dev_t dev, char *path)
}
/*
- * Ugly clock routines
+ * Ugly (lack of) clock routines
*/
time_t
@@ -221,44 +237,65 @@ machdep()
{
const char *envvar;
+ /*
+ * Since we can't have non-blocking input, we will try to
+ * autoload the kernel pointed to by the `bsd' environment
+ * variable, and fallback to interactive mode if the variable
+ * is empty or the load fails.
+ */
+
+ if (boot_rd == 0) {
+ envvar = pmon_getenv("bsd");
+ if (envvar != NULL) {
+ bootprompt = 0;
+ kernelfile = (char *)envvar;
+ } else {
+ if (is_gdium)
+ gdium_abort();
+ }
+ }
+}
+
+int
+main()
+{
+ const char *envvar;
+
cninit();
/*
* Figure out whether we are running on a Gdium system, which
- * has an horribly castrated PMON. If we do, return immediately.
+ * has an horribly castrated PMON. If we do, the best we can do
+ * is boot an initrd image.
*/
envvar = pmon_getenv("Version");
- if (envvar != NULL && strncmp(envvar, "Gdium", 5) == 0) {
- /* Here's a nickel, kid. Get yourself a better firmware */
- printf("\n\nSorry, OpenBSD boot blocks do not work on Gdium, "
- "because of dire firmware limitations.\n"
- "Also, the firmware has reset the USB controller so you "
- "will need to power cycle.\n"
- "We would apologize for this incovenience, but we have "
- "no control about the firmware of your machine.\n\n");
- _rtt();
- }
+ if (envvar != NULL && strncmp(envvar, "Gdium", 5) == 0)
+ is_gdium = 1;
/*
- * Since we can't have non-blocking input, we will try to
- * autoload the kernel pointed to by the `bsd' environment
- * variable, and fallback to interactive mode if the variable
- * is empty or the load fails.
+ * Check if we have a valid initrd loaded.
*/
- envvar = pmon_getenv("bsd");
- if (envvar != NULL) {
- extern int bootprompt;
- extern char *kernelfile;
+ envvar = pmon_getenv("rd");
+ if (envvar != NULL && *envvar != '\0')
+ boot_rd = rd_isvalid();
+ if (boot_rd != 0)
bootprompt = 0;
- kernelfile = (char *)envvar;
- }
+
+ boot(boot_rd);
+ return 0;
}
-int
-main()
+void
+gdium_abort()
{
- boot(0);
- return 0;
+ /* Here's a nickel, kid. Get yourself a better firmware */
+ printf("\n\nSorry, OpenBSD boot blocks do not work on Gdium, "
+ "because of dire firmware limitations.\n"
+ "Also, the firmware has reset the USB controller so you "
+ "will need to power cycle.\n"
+ "We would apologize for this incovenience, but we have "
+ "no control about the firmware of your machine.\n\n");
+ _rtt();
}
diff --git a/sys/arch/loongson/stand/boot/rd.c b/sys/arch/loongson/stand/boot/rd.c
new file mode 100644
index 00000000000..5a00bfd4b76
--- /dev/null
+++ b/sys/arch/loongson/stand/boot/rd.c
@@ -0,0 +1,133 @@
+/* $OpenBSD: rd.c,v 1.1 2010/02/17 21:25:49 miod Exp $ */
+
+/*
+ * Copyright (c) 2010 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/types.h>
+#include "libsa.h"
+#include <machine/cpu.h>
+#include <machine/param.h>
+#include <sys/exec_elf.h>
+
+static off_t rdoffs;
+
+/*
+ * INITRD I/O
+ */
+
+int
+rd_iostrategy(void *f, int rw, daddr_t dblk, size_t size, void *buf,
+ size_t *rsize)
+{
+ /* never invoked directly */
+ return ENXIO;
+}
+
+int
+rd_ioopen(struct open_file *f, ...)
+{
+ return 0;
+}
+
+int
+rd_ioclose(struct open_file *f)
+{
+ return 0;
+}
+
+int
+rd_isvalid()
+{
+ Elf64_Ehdr *elf64 = (Elf64_Ehdr *)INITRD_BASE;
+
+ if (memcmp(elf64->e_ident, ELFMAG, SELFMAG) != 0 ||
+ elf64->e_ident[EI_CLASS] != ELFCLASS64 ||
+ elf64->e_ident[EI_DATA] != ELFDATA2LSB ||
+ elf64->e_type != ET_EXEC || elf64->e_machine != EM_MIPS)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * INITRD filesystem
+ */
+int
+rdfs_open(char *path, struct open_file *f)
+{
+ if (f->f_dev->dv_open == rd_ioopen) {
+ rdoffs = 0;
+ return 0;
+ }
+
+ return EINVAL;
+}
+
+int
+rdfs_close(struct open_file *f)
+{
+ return 0;
+}
+
+int
+rdfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+ if (size != 0) {
+ bcopy((void *)(INITRD_BASE + rdoffs), buf, size);
+ rdoffs += size;
+ }
+ *resid = 0;
+
+ return 0;
+}
+
+int
+rdfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+ return EIO;
+}
+
+off_t
+rdfs_seek(struct open_file *f, off_t offset, int where)
+{
+ switch (where) {
+ case 0: /* SEEK_SET */
+ rdoffs = offset;
+ break;
+ case 1: /* SEEK_CUR */
+ rdoffs += offset;
+ break;
+ default:
+ errno = EIO;
+ return -1;
+ }
+
+ return rdoffs;
+}
+
+int
+rdfs_stat(struct open_file *f, struct stat *sb)
+{
+ return EIO;
+}
+
+#ifndef NO_READDIR
+int
+rdfs_readdir(struct open_file *f, char *path)
+{
+ return EIO;
+}
+#endif