Subject: Re: kernel stack trace
To: None <port-dreamcast@netbsd.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-dreamcast
Date: 09/21/2002 18:38:12
In article <200209210418.g8L4IsI12985@pl374.nas911.nara.nttpc.ne.jp>
itohy@netbsd.org wrote:

> >  > Adding kloader with bootinfo support (like hpc* ports)
> >  > would be easiest way.
> 
> Hmm, but I don't have the source code of boot loader....

Attached is a diff for kloader (written by uch).
More cleanup is needed (most code should be shared amoung other ports),
and it doesn't have bootinfo support, though.
---
Izumi Tsutsui
tsutsui@ceres.dti.ne.jp

Index: conf/files.dreamcast
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/conf/files.dreamcast,v
retrieving revision 1.20
diff -u -r1.20 files.dreamcast
--- conf/files.dreamcast	2002/09/06 13:19:55	1.20
+++ conf/files.dreamcast	2002/09/21 09:22:33
@@ -18,6 +18,11 @@
 file	arch/dreamcast/dreamcast/clock_machdep.c
 file	arch/sh3/sh3/disksubr.c				disk
 
+file	arch/dreamcast/dreamcast/kloader.c		kloader
+defflag	opt_kloader.h	KLOADER
+defflag	debug_kloader.h	KLOADER_DEBUG
+defparam opt_kloader_kernel_path.h	KLOADER_KERNEL_PATH
+
 defparam opt_memsize.h	IOM_ROM_BEGIN IOM_ROM_SIZE IOM_RAM_BEGIN IOM_RAM_SIZE
 
 #
Index: dreamcast/machdep.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dreamcast/machdep.c,v
retrieving revision 1.21
diff -u -r1.21 machdep.c
--- dreamcast/machdep.c	2002/05/10 20:14:39	1.21
+++ dreamcast/machdep.c	2002/09/21 09:22:33
@@ -79,6 +79,9 @@
 #include "opt_kgdb.h"
 #include "opt_memsize.h"
 #include "scif.h"
+#include "opt_kloader.h"
+#include "opt_kloader_kernel_path.h"
+#include "opt_md.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -100,6 +103,7 @@
 #include <sh3/cpu.h>
 #include <sh3/exception.h>
 #include <machine/intr.h>
+#include <machine/kloader.h>
 
 #include <dev/cons.h>
 
@@ -107,6 +111,13 @@
 char machine[] = MACHINE;		/* dreamcast */
 char machine_arch[] = MACHINE_ARCH;	/* sh3el */
 
+#ifdef KLOADER
+#ifndef KLOADER_KERNEL_PATH
+#define KLOADER_KERNEL_PATH "/netbsd"
+#endif
+static char kernel_path[] = KLOADER_KERNEL_PATH;
+#endif
+
 void main(void) __attribute__((__noreturn__));
 void dreamcast_startup(void) __attribute__((__noreturn__));
 
@@ -179,6 +190,10 @@
 	strcpy(cpu_model, "SEGA Dreamcast\n");
 
 	sh_startup();
+
+#ifdef FORCE_RB_SINGLE
+	boothowto |= RB_SINGLE;
+#endif
 }
 
 int
@@ -210,6 +225,15 @@
 		goto haltsys;
 	}
 
+#ifdef KLOADER
+	if ((howto & RB_HALT) == 0) {
+		if ((howto & RB_STRING) && bootstr != NULL) {
+			printf("loading a new kernel: %s\n", bootstr);
+			kloader_reboot_setup(bootstr);
+		} else
+			kloader_reboot_setup(kernel_path);
+	}
+#endif
 	boothowto = howto;
 	if ((howto & RB_NOSYNC) == 0 && waittime < 0) {
 		waittime = 0;
@@ -237,6 +261,14 @@
 		printf("Please press any key to reboot.\n\n");
 		cngetc();
 	}
+#ifdef KLOADER
+	else {
+		kloader_reboot();
+		printf("\n");
+		printf("Failed to load a new kernel.\n");
+		cngetc();
+	}
+#endif
 
 	printf("rebooting...\n");
 	cpu_reset();
--- /dev/null	Sat Sep 21 08:34:31 2002
+++ dreamcast/kloader.c	Sat Sep 21 18:21:40 2002
@@ -0,0 +1,393 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
+ * 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 NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 "opt_kloader.h"
+#include "debug_kloader.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/namei.h>
+#include <sys/fcntl.h>
+#define ELFSIZE	32
+#include <sys/exec_elf.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <sh3/cache.h>
+#include <sh3/cache_sh4.h>
+#include <sh3/mmu_sh4.h>
+
+#include <machine/kloader.h>
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#ifdef KLOADER_DEBUG
+int	kloader_debug = 1;
+#define	DPRINTF(fmt, args...)						\
+	if (kloader_debug)						\
+		printf("%s: " fmt, __FUNCTION__ , ##args) 
+#define	_DPRINTF(fmt, args...)						\
+	if (kloader_debug)						\
+		printf(fmt, ##args) 
+#define	DPRINTFN(n, arg)						\
+	if (kloader_debug > (n))					\
+		printf("%s: " fmt, __FUNCTION__ , ##args) 
+#else
+#define	DPRINTF(arg...)		((void)0)
+#define	_DPRINTF(arg...)	((void)0)
+#define DPRINTFN(n, arg...)	((void)0)
+#endif
+
+struct kloader_page_tag {
+	u_int32_t next;
+	u_int32_t src;
+	u_int32_t dst;
+	u_int32_t sz;
+};
+#define BUCKET_SIZE	(PAGE_SIZE - sizeof(struct kloader_page_tag))
+
+STATIC struct {
+	struct pglist pg_head;
+#define PG_VADDR(pg)	SH3_PHYS_TO_P1SEG(VM_PAGE_TO_PHYS(pg))
+	struct vm_page *cur_pg;
+	struct vnode *vp;
+	vaddr_t entry;
+	struct kloader_page_tag *tagstart;
+	void (*loader)(vaddr_t, struct kloader_page_tag *);
+	int setuped;
+} kloader;
+
+extern paddr_t avail_start, avail_end;
+STATIC void kloader_boot(u_int32_t, struct kloader_page_tag *);
+STATIC int kloader_load(void);
+STATIC int kloader_alloc_memory(size_t);
+STATIC void kloader_load_segment(vaddr_t, vsize_t, off_t, size_t);
+STATIC void kloader_load_segment_end(void);
+STATIC void kloader_load_bucket(vaddr_t, off_t, size_t);
+
+STATIC struct vnode *kloader_open(const char *);
+STATIC void kloader_close(void);
+STATIC int kloader_read(size_t, size_t, void *);
+
+#ifdef KLOADER_DEBUG
+STATIC void kloader_dump(vaddr_t, struct kloader_page_tag *);
+#endif
+
+void
+kloader_reboot_setup(const char *filename)
+{
+
+	DPRINTF("boot file name: %s\n", filename);
+	kloader.vp = kloader_open(filename);
+	if (kloader.vp == NULL)
+		return;
+
+	if (kloader_load() != 0)
+		goto end;
+
+	kloader.setuped = 1;
+#ifdef KLOADER_DEBUG
+	kloader_dump(kloader.entry, kloader.tagstart);
+#endif
+ end:
+	kloader_close();
+}
+
+void
+kloader_reboot()
+{
+
+	if (!kloader.setuped)
+		return;
+
+	sh_icache_sync_all();
+	(*kloader.loader)(kloader.entry, kloader.tagstart);
+	/* NOTREACHED */
+}
+
+int
+kloader_load()
+{
+	Elf_Ehdr eh;
+	Elf_Phdr ph[16], *p;
+	Elf_Shdr sh[16];
+	vaddr_t kv;
+	size_t sz;
+	int i;
+
+	/* read kernel's ELF header */
+	kloader_read(0, sizeof(Elf_Ehdr), &eh);
+  
+	if (eh.e_ident[EI_MAG0] != ELFMAG0 ||
+	    eh.e_ident[EI_MAG1] != ELFMAG1 ||
+	    eh.e_ident[EI_MAG2] != ELFMAG2 ||
+	    eh.e_ident[EI_MAG3] != ELFMAG3) {
+		DPRINTF("not a ELF file\n");
+		return (1);
+	}
+
+	/* read section header */
+	kloader_read(eh.e_shoff, eh.e_shentsize * eh.e_shnum, sh);
+
+	/* read program header */
+	kloader_read(eh.e_phoff, eh.e_phentsize * eh.e_phnum, ph);
+
+	/* calcurate memory size */
+	DPRINTF("file size: ");
+	for (sz = 0, i = 0; i < eh.e_phnum; i++) {
+		if (ph[i].p_type == PT_LOAD) {
+			size_t filesz = ph[i].p_filesz;
+			_DPRINTF("+0x%x", filesz);
+			sz += round_page(filesz);
+		}
+	}
+	_DPRINTF(" entry: %08x\n", eh.e_entry);
+
+	/* get memory for new kernel */
+	if (kloader_alloc_memory(sz) != 0)
+		return (1);
+
+	/* copy newkernel to memory */
+	for (i = 0, p = ph; i < eh.e_phnum; i++, p++) {
+		if (p->p_type == PT_LOAD) {
+			size_t filesz = p->p_filesz;
+			size_t memsz = p->p_memsz;
+			off_t fileofs = p->p_offset;
+			kv = p->p_vaddr;
+			DPRINTF("[%d] vaddr 0x%08lx file size 0x%x"
+				" mem size 0x%x\n", i, kv, filesz, memsz);
+			kloader_load_segment(kv, memsz, fileofs, filesz);
+			kv += memsz;
+		}
+	}
+	/* end tag */
+	kloader_load_segment_end();
+
+	/* copy loader code */
+	KDASSERT(kloader.cur_pg);
+	kloader.loader = (void *)PG_VADDR(kloader.cur_pg);
+
+	memcpy(kloader.loader, kloader_boot, PAGE_SIZE);
+
+	kloader.entry = eh.e_entry;
+
+	return (0);
+}
+
+int
+kloader_alloc_memory(size_t sz)
+{
+	int n, error;
+
+	n = (sz + BUCKET_SIZE - 1) / BUCKET_SIZE + 1; /* 2nd loader */
+
+	error = uvm_pglistalloc(n * PAGE_SIZE, avail_start, avail_end,
+	    PAGE_SIZE, 0, &kloader.pg_head, n, 0);
+	if (error) {
+		DPRINTF("can't allocate memory.\n");
+		return (1);
+	}
+
+	kloader.cur_pg = TAILQ_FIRST(&kloader.pg_head);
+	kloader.tagstart = (void *)PG_VADDR(kloader.cur_pg);
+
+	return (0);
+}
+
+void kloader_load_segment(vaddr_t kv, vsize_t memsz, off_t fileofs,
+    size_t filesz)
+{
+	int i, n;
+
+	if (filesz == 0)
+		return;
+
+	n = filesz / BUCKET_SIZE;
+	for (i = 0; i < n; i ++) {
+		kloader_load_bucket(kv, fileofs, BUCKET_SIZE);
+		kv += BUCKET_SIZE;
+		fileofs += BUCKET_SIZE;
+	}
+
+	n = filesz % BUCKET_SIZE;
+	if (n) {
+		kloader_load_bucket(kv, fileofs, n);
+	}
+}
+
+void
+kloader_load_segment_end()
+{
+	struct vm_page *pg;
+
+	pg = TAILQ_PREV(kloader.cur_pg, pglist, pageq);
+	
+	((struct kloader_page_tag *)PG_VADDR(pg))->next = 0;
+}
+
+void
+kloader_load_bucket(vaddr_t kv, off_t ofs, size_t sz)
+{
+	struct vm_page *pg = kloader.cur_pg;
+	vaddr_t addr = PG_VADDR(pg);
+	struct kloader_page_tag *tag = (void *)addr;
+
+	KDASSERT(pg != NULL);
+
+	tag->src = addr + sizeof(struct kloader_page_tag);
+	tag->dst = kv;
+	tag->sz = sz;
+
+	kloader_read(ofs, sz, (void *)tag->src);
+
+	pg = TAILQ_NEXT(pg, pageq);
+	tag->next = PG_VADDR(pg);
+	kloader.cur_pg = pg;
+}
+
+/*
+ * file access
+ */
+struct vnode *
+kloader_open(const char *filename)
+{
+	struct proc *p = curproc;
+	struct nameidata nid;
+
+	NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p);
+
+	if (namei(&nid) != 0) {
+		DPRINTF("namei failed (%s)\n", filename);
+		return (0);
+	}
+
+	if (vn_open(&nid, FREAD, 0) != 0) {
+		DPRINTF("open failed\n");
+		return (0);
+	}
+
+	return (nid.ni_vp);
+}
+
+void
+kloader_close()
+{
+	struct proc *p = curproc;
+	struct vnode *vp = kloader.vp;
+
+	VOP_UNLOCK(vp, 0);
+	vn_close(vp, FREAD, p->p_ucred, p);
+}
+
+int
+kloader_read(size_t ofs, size_t size, void *buf)
+{
+	struct proc *p = curproc;
+	struct vnode *vp = kloader.vp;
+	size_t resid;
+	int error;
+
+	error = vn_rdwr(UIO_READ, vp, buf, size, ofs, UIO_SYSSPACE,
+	    IO_NODELOCKED | IO_SYNC, p->p_ucred, &resid, p);
+
+	if (error)
+		DPRINTF("read error.\n");
+
+	return (error);
+}
+
+void
+kloader_boot(u_int32_t entry, struct kloader_page_tag *p)
+{
+	int tmp;
+
+	/* Disable interrupt. block exception. */
+	__asm__ __volatile__(
+		"stc	sr, %1;"
+		"or	%0, %1;"
+		"ldc	%1, sr" : : "r"(0x500000f0), "r"(tmp));
+
+	/* Now I run on P1, TLB flush. and disable. */
+	SH4_TLB_DISABLE;
+
+	do {
+		u_int32_t *dst =(u_int32_t *)p->dst;
+		u_int32_t *src =(u_int32_t *)p->src;
+		u_int32_t sz = p->sz / sizeof (int);
+		while (sz--)
+			*dst++ = *src++;
+	} while ((p = (struct kloader_page_tag *)p->next) != 0);
+
+	SH7750_CACHE_FLUSH();
+
+	/* jump to kernel entry. */
+	__asm__ __volatile__(
+		"jmp	@%0;"
+		"nop;"
+		: : "r"(entry));
+	/* NOTREACHED */
+}
+
+#ifdef KLOADER_DEBUG
+void
+kloader_dump(vaddr_t entry, struct kloader_page_tag *tag)
+{
+	struct kloader_page_tag *p, *op;
+	int i, n;
+
+	p = tag;
+	i = 0, n = 30;
+	do  {
+		if (i < n) {
+			DPRINTF("[%d] next 0x%08x src 0x%08x dst 0x%08x"
+			    " sz 0x%x\n", i, p->next, p->src, p->dst, p->sz);
+		} else if (i == n) {
+			DPRINTF("[...]\n");
+		}
+		op = p;
+		i++;
+	} while ((p = (struct kloader_page_tag *)(p->next)) != 0);
+  
+	DPRINTF("[%d(last)] next 0x%08x src 0x%08x dst 0x%08x sz 0x%x\n",
+	    i - 1, op->next, op->src, op->dst, op->sz);
+}
+#endif /* KLOADER_DEBUG */
+
--- /dev/null	Sat Sep 21 08:34:31 2002
+++ include/kloader.h	Sat Sep 21 18:21:40 2002
@@ -0,0 +1,37 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
+ * 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 NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+void kloader_reboot_setup(const char *);
+void kloader_reboot(void);