Subject: Some ASM code to C
To: None <port-i386@netbsd.org>
From: Julio M. Merino Vidal <jmmv84@gmail.com>
List: port-i386
Date: 02/12/2006 12:51:34
--Boundary-00=_GFy7Dmr/9gngB7L
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Hi,

I've converted the code in locore.S that fetches the parameters passed in
by the boot loader from ASM to C.  It may look longer, but I believe it is
easier to understand.  It took me a while to understand what was going on
the first time I looked there (specially the part that deals with bootinfo).

Patch attached.  Comments?

-- 
Julio M. Merino Vidal <jmmv84@gmail.com>
The Julipedia - http://julipedia.blogspot.com/

--Boundary-00=_GFy7Dmr/9gngB7L
Content-Type: text/x-diff;
  charset="us-ascii";
  name="patch.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="patch.diff"

Index: locore.S
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/locore.S,v
retrieving revision 1.37
diff -u -p -r1.37 locore.S
--- locore.S	3 Feb 2006 11:08:24 -0000	1.37
+++ locore.S	12 Feb 2006 11:46:47 -0000
@@ -95,7 +95,6 @@
 #include <machine/segments.h>
 #include <machine/specialreg.h>
 #include <machine/trap.h>
-#include <machine/bootinfo.h>
 
 #if NLAPIC > 0
 #include <machine/i82489reg.h>
@@ -158,13 +157,9 @@
 	.data
 
 	.globl	_C_LABEL(cpu)
-	.globl	_C_LABEL(esym),_C_LABEL(boothowto)
-	.globl	_C_LABEL(bootinfo),_C_LABEL(atdevbase)
-#ifdef COMPAT_OLDBOOT
-	.globl	_C_LABEL(bootdev)
-#endif
+	.globl	_C_LABEL(esym)
+	.globl	_C_LABEL(atdevbase)
 	.globl	_C_LABEL(proc0paddr),_C_LABEL(PDPpaddr)
-	.globl	_C_LABEL(biosbasemem),_C_LABEL(biosextmem)
 	.globl	_C_LABEL(gdt)
 #ifdef I586_CPU
 	.globl	_C_LABEL(idt)
@@ -197,20 +192,9 @@ _C_LABEL(lapic_tpr):
 
 _C_LABEL(cpu):		.long	0	# are we 386, 386sx, or 486,
 					#   or Pentium, or..
-_C_LABEL(esym):		.long	0	# ptr to end of syms
 _C_LABEL(atdevbase):	.long	0	# location of start of iomem in virtual
 _C_LABEL(proc0paddr):	.long	0
 _C_LABEL(PDPpaddr):	.long	0	# paddr of PDP, for libkvm
-#ifndef REALBASEMEM
-_C_LABEL(biosbasemem):	.long	0	# base memory reported by BIOS
-#else
-_C_LABEL(biosbasemem):	.long	REALBASEMEM
-#endif
-#ifndef REALEXTMEM
-_C_LABEL(biosextmem):	.long	0	# extended memory reported by BIOS
-#else
-_C_LABEL(biosextmem):	.long	REALEXTMEM
-#endif
 
 	.space 512
 tmpstk:
@@ -256,71 +240,21 @@ _C_LABEL(Multiboot_Header):
 	pushl	%ebx		# Address of Multiboot information
 	call	_C_LABEL(multiboot_pre_reloc)
 	addl	$4,%esp
-	jmp	3f
+	jmp	2f
 #endif
 
 1:
 	/*
-	 * Load parameters from stack
-	 * (howto, [bootdev], bootinfo, esym, basemem, extmem).
+	 * At this point, we know that a NetBSD-specific boot loader
+	 * booted this kernel.  The stack carries the following parameters:
+	 * (boothowto, [bootdev], bootinfo, esym, biosbasemem, biosextmem),
+	 * 4 bytes each.
 	 */
-	movl	4(%esp),%eax
-	movl	%eax,RELOC(boothowto)
-#ifdef COMPAT_OLDBOOT
-	movl	8(%esp),%eax
-	movl	%eax,RELOC(bootdev)
-#endif
-	movl	12(%esp),%eax
+	addl	$4,%esp		# Discard return address to boot loader
+	call	_C_LABEL(native_loader)
+	addl	$24,%esp
 
-	testl	%eax, %eax
-	jz	1f
-	movl	(%eax), %ebx		/* number of entries */
-	movl	$RELOC(bootinfo), %edi
-	movl	%ebx, (%edi)
-	addl	$4, %edi
 2:
-	testl	%ebx, %ebx
-	jz	1f
-	addl	$4, %eax
-	movl	(%eax), %ecx		/* address of entry */
-	pushl	%eax
-	pushl	(%ecx)			/* len */
-	pushl	%ecx
-	pushl	%edi
-	addl	(%ecx), %edi		/* update dest pointer */
-	cmpl	$_RELOC(_C_LABEL(bootinfo) + BOOTINFO_MAXSIZE), %edi
-	jg	2f
-	call	_C_LABEL(memcpy)
-	addl	$12, %esp
-	popl	%eax
-	subl	$1, %ebx
-	jmp	2b
-2:	/* cleanup for overflow case */
-	addl	$16, %esp
-	movl	$RELOC(bootinfo), %edi
-	subl	%ebx, (%edi)		/* correct number of entries */
-1:
-
- 	movl	16(%esp),%eax
-	testl	%eax,%eax
-	jz	1f
-	addl	$KERNBASE,%eax
-1: 	movl	%eax,RELOC(esym)
-
-	movl	RELOC(biosextmem),%eax
-	testl	%eax,%eax
-	jnz	1f
-	movl	20(%esp),%eax
-	movl	%eax,RELOC(biosextmem)
-1:
-	movl	RELOC(biosbasemem),%eax
-	testl	%eax,%eax
-	jnz	1f
-	movl	24(%esp),%eax
-	movl	%eax,RELOC(biosbasemem)
-1:
-
-3:
 	/* First, reset the PSL. */
 	pushl	$PSL_MBO
 	popfl
Index: machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.570
diff -u -p -r1.570 machdep.c
--- machdep.c	3 Feb 2006 11:08:24 -0000	1.570
+++ machdep.c	12 Feb 2006 11:46:48 -0000
@@ -1,12 +1,12 @@
 /*	$NetBSD: machdep.c,v 1.570 2006/02/03 11:08:24 jmmv Exp $	*/
 
 /*-
- * Copyright (c) 1996, 1997, 1998, 2000, 2004 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996, 1997, 1998, 2000, 2004, 2006 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
- * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
- * Simulation Facility, NASA Ames Research Center.
+ * by Charles M. Hannum, by Jason R. Thorpe of the Numerical Aerospace
+ * Simulation Facility, NASA Ames Research Center and by Julio M. Merino Vidal.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -276,6 +276,114 @@ void	add_mem_cluster(uint64_t, uint64_t,
 
 extern int time_adjusted;
 
+struct bootinfo	bootinfo;
+int *esym;
+extern int boothowto;
+
+/* Base memory reported by BIOS. */
+#ifndef REALBASEMEM
+int	biosbasemem = 0;
+#else
+int	biosbasemem = REALBASEMEM;
+#endif
+
+/* Extended memory reported by BIOS. */
+#ifndef REALEXTMEM
+int	biosextmem = 0;
+#else
+int	biosextmem = REALEXTMEM;
+#endif
+
+/* Representation of the bootinfo structure constructed by a NetBSD native
+ * boot loader.  Only be used by native_loader(). */
+struct bootinfo_source {
+	uint32_t bs_naddrs;
+	paddr_t bs_addrs[1]; /* Actually longer. */
+};
+
+/* Only called by locore.h; no need to be in a header file. */
+void	native_loader(int, int, struct bootinfo_source *, paddr_t, int, int);
+
+/*
+ * Called as one of the very first things during system startup (just after
+ * the boot loader gave control to the kernel image), this routine is in
+ * charge of retrieving the parameters passed in by the boot loader and
+ * storing them in the appropriate kernel variables.
+ *
+ * WARNING: Because the kernel has not yet relocated itself to KERNBASE,
+ * special care has to be taken when accessing memory because absolute
+ * addresses (referring to kernel symbols) do not work.  So:
+ *
+ *     1) Avoid jumps to absolute addresses (such as gotos and switches).
+ *     2) To access global variables use their physical address, which
+ *        can be obtained using the RELOC macro.
+ */
+void
+native_loader(int bl_boothowto, int bl_bootdev,
+    struct bootinfo_source *bl_bootinfo, paddr_t bl_esym,
+    int bl_biosbasemem, int bl_biosextmem)
+{
+#define RELOC(type, x) ((type)((vaddr_t)(x) - KERNBASE))
+
+	*RELOC(int *, &boothowto) = bl_boothowto;
+
+#ifdef COMPAT_OLDBOOT
+	/*
+	 * Pre-1.3 boot loaders gave the boot device as a parameter
+	 * (instead of a bootinfo entry).
+	 */
+	*RELOC(int *, &bootdev) = bl_bootdev;
+#endif
+
+	/*
+	 * The boot loader provides a physical, non-relocated address
+	 * for the symbols table's end.  We need to convert it to a
+	 * virtual address.
+	 */
+	if (bl_esym != 0)
+		*RELOC(int **, &esym) = (int *)((vaddr_t)bl_esym + KERNBASE);
+	else
+		*RELOC(int **, &esym) = 0;
+
+	/*
+	 * Copy bootinfo entries (if any) from the boot loader's
+	 * representation to the kernel's bootinfo space.
+	 */
+	if (bl_bootinfo != NULL) {
+		size_t i;
+		uint8_t *data;
+		struct bootinfo *bidest;
+
+		bidest = RELOC(struct bootinfo *, &bootinfo);
+
+		data = &bidest->bi_data[0];
+
+		for (i = 0; i < bl_bootinfo->bs_naddrs; i++) {
+			struct btinfo_common *bc;
+
+			bc = (struct btinfo_common *)(bl_bootinfo->bs_addrs[i]);
+
+			if ((paddr_t)(data + bc->len) >
+			    (paddr_t)(&bidest->bi_data[0] + BOOTINFO_MAXSIZE))
+				break;
+
+			memcpy(data, bc, bc->len);
+			data += bc->len;
+		}
+		bidest->bi_nentries = i;
+	}
+
+	/*
+	 * Configure biosbasemem and biosextmem only if they were not
+	 * explicitly given during the kernel's build.
+	 */
+	if (*RELOC(int *, &biosbasemem) == 0)
+		*RELOC(int *, &biosbasemem) = bl_biosbasemem;
+	if (*RELOC(int *, &biosextmem) == 0)
+		*RELOC(int *, &biosextmem) = bl_biosextmem;
+#undef RELOC
+}
+
 /*
  * Machine-dependent startup code
  */
@@ -1869,7 +1977,6 @@ init386(paddr_t first_avail)
 #if NKSYMS || defined(DDB) || defined(LKM)
 	{
 		extern int end;
-		extern int *esym;
 		struct btinfo_symtab *symtab;
 
 #ifdef DDB

--Boundary-00=_GFy7Dmr/9gngB7L--