All of lore.kernel.org
 help / color / mirror / Atom feed
From: Robert Millan <rmh@aybabtu.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: [PATCH] decouple mmap parsing and implement Multiboot mmap in the loader
Date: Tue, 12 Aug 2008 15:25:15 +0200	[thread overview]
Message-ID: <20080812132515.GA13942@thorin> (raw)
In-Reply-To: <20080811220723.GA22204@thorin>

[-- Attachment #1: Type: text/plain, Size: 724 bytes --]

On Tue, Aug 12, 2008 at 12:07:23AM +0200, Robert Millan wrote:
> 
> Does anyone see a problem in this?  If so, then I think we'd need a function
> that can for example handle a third argument, for example `type', for this
> purpose.

Actually, adding that third argument was trivial, so I've done that.

Here's a new patch.  This one additionally takes advantage of the new
framework to implement Multiboot mmap in the loader (you can test it using
docs/kernel.c in GRUB Legacy source).

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."

[-- Attachment #2: mmap.diff --]
[-- Type: text/x-diff, Size: 16274 bytes --]

2008-08-12  Robert Millan  <rmh@aybabtu.com>

	* conf/i386-pc.rmk (kernel_img_SOURCES): Add `kern/i386/pc/mmap.c'.

	* include/grub/i386/pc/init.h: Include `<grub/multiboot.h>'.
	(GRUB_MACHINE_MEMORY_AVAILABLE, GRUB_MACHINE_MEMORY_RESERVED): New
	macros.
	(grub_mmap_iterate): New function declaration.
	(struct grub_machine_mmap_entry): Move from here ...
	* include/grub/multiboot.h (struct grub_mmap_entry): ... to here.
	Update all users.
	(GRUB_MMAP_MEMORY_AVAILABLE, GRUB_MMAP_MEMORY_RESERVED): New
	macros.

	* kern/i386/pc/init.c (grub_machine_init): Replace hardcoded region
	type check value with `GRUB_MACHINE_MEMORY_AVAILABLE'.
	Move e820 parsing from here ...
	* kern/i386/pc/mmap.c: New file.
	(grub_mmap_iterate): ... to here.

	* include/grub/i386/coreboot/memory.h: Remove `<grub/err.h>'.
	(GRUB_LINUXBIOS_MEMORY_AVAILABLE): Rename (for consistency) to ...
	(GRUB_MACHINE_MEMORY_AVAILABLE): ... this.  Update all users.
	(grub_available_iterate): Redeclare to return `void', and redeclare
	its hook to use grub_uint64_t as addr and size parameters, and rename
	to ...
	(grub_mmap_iterate): ... this.  Update all users.

	* kern/i386/coreboot/mmap.c (grub_mmap_iterate): Simplify parser loop
	to make it more readable.

	* loader/i386/pc/multiboot.c (mmap_addr, mmap_length): New variables.
	(grub_get_multiboot_mmap_len, grub_fill_multiboot_mmap): New functions.
	(grub_multiboot_load_elf32): Allocate an extra region after the payload,
	and put the Multiboot memory map there.
	(grub_multiboot): If the loader we're using supports Multiboot memory
	map, refer to it in the Multiboot Information Structure.

Index: conf/i386-pc.rmk
===================================================================
--- conf/i386-pc.rmk	(revision 1800)
+++ conf/i386-pc.rmk	(working copy)
@@ -43,7 +43,8 @@
 	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/time.c \
-	kern/i386/dl.c kern/i386/pc/init.c kern/parser.c kern/partition.c \
+	kern/i386/dl.c kern/i386/pc/init.c kern/i386/pc/mmap.c \
+	kern/parser.c kern/partition.c \
 	kern/i386/tsc.c kern/i386/pit.c \
 	kern/generic/rtc_get_time_ms.c \
 	kern/generic/millisleep.c \
Index: kern/i386/pc/init.c
===================================================================
--- kern/i386/pc/init.c	(revision 1800)
+++ kern/i386/pc/init.c	(working copy)
@@ -132,9 +132,6 @@
 void
 grub_machine_init (void)
 {
-  grub_uint32_t cont;
-  struct grub_machine_mmap_entry *entry
-    = (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
   int i;
   
   /* Initialize the console as early as possible.  */
@@ -156,55 +153,35 @@
     add_mem_region (GRUB_MEMORY_MACHINE_RESERVED_END,
 		    grub_lower_mem - GRUB_MEMORY_MACHINE_RESERVED_END);
   
-  /* Check if grub_get_mmap_entry works.  */
-  cont = grub_get_mmap_entry (entry, 0);
-
-  if (entry->size)
-    do
-      {
-	/* Avoid the lower memory.  */
-	if (entry->addr < 0x100000)
-	  {
-	    if (entry->len <= 0x100000 - entry->addr)
-	      goto next;
-
-	    entry->len -= 0x100000 - entry->addr;
-	    entry->addr = 0x100000;
-	  }
-	
-	/* Ignore >4GB.  */
-	if (entry->addr <= 0xFFFFFFFF && entry->type == 1)
-	  {
-	    grub_addr_t addr;
-	    grub_size_t len;
-
-	    addr = (grub_addr_t) entry->addr;
-	    len = ((addr + entry->len > 0xFFFFFFFF)
-		   ? 0xFFFFFFFF - addr
-		   : (grub_size_t) entry->len);
-	    add_mem_region (addr, len);
-	  }
-	
-      next:
-	if (! cont)
-	  break;
-	
-	cont = grub_get_mmap_entry (entry, cont);
-      }
-    while (entry->size);
-  else
+  auto int hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
     {
-      grub_uint32_t eisa_mmap = grub_get_eisa_mmap ();
-
-      if (eisa_mmap)
+      /* Avoid the lower memory.  */
+      if (addr < 0x100000)
 	{
-	  add_mem_region (0x100000, (eisa_mmap & 0xFFFF) << 10);
-	  add_mem_region (0x1000000, eisa_mmap & ~0xFFFF);
+	  if (size <= 0x100000 - addr)
+	    return 0;
+	  
+	  size -= 0x100000 - addr;
+	  addr = 0x100000;
 	}
-      else
-	add_mem_region (0x100000, grub_get_memsize (1) << 10);
+	
+      /* Ignore >4GB.  */
+      if (addr <= 0xFFFFFFFF && type == GRUB_MMAP_MEMORY_AVAILABLE)
+	{
+	  grub_size_t len;
+	  
+	  len = (grub_size_t) ((addr + size > 0xFFFFFFFF)
+		 ? 0xFFFFFFFF - addr
+		 : size);
+	  add_mem_region (addr, len);
+	}
+
+      return 0;
     }
 
+  grub_mmap_iterate (hook);
+  
   compact_mem_regions ();
 
   /* Add the memory regions to free memory, except for the region starting
Index: kern/i386/pc/mmap.c
===================================================================
--- kern/i386/pc/mmap.c	(revision 0)
+++ kern/i386/pc/mmap.c	(revision 0)
@@ -0,0 +1,60 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2004,2005,2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/machine/init.h>
+#include <grub/machine/memory.h>
+#include <grub/types.h>
+
+void
+grub_mmap_iterate (int (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t))
+{
+  grub_uint32_t cont;
+  struct grub_mmap_entry *entry
+    = (struct grub_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
+  
+  /* Check if grub_get_mmap_entry works.  */
+  cont = grub_get_mmap_entry (entry, 0);
+
+  if (entry->size)
+    do
+      {
+	if (hook (entry->addr, entry->len,
+		  /* Multiboot mmaps have been defined to match with the E820 definition.
+		     Therefore, we can just pass type through.  */
+		  entry->type))
+	  break;
+
+	if (! cont)
+	  break;
+
+	cont = grub_get_mmap_entry (entry, cont);
+      }
+    while (entry->size);
+  else
+    {
+      grub_uint32_t eisa_mmap = grub_get_eisa_mmap ();
+
+      if (eisa_mmap)
+	{
+	  if (hook (0x100000, (eisa_mmap & 0xFFFF) << 10, GRUB_MMAP_MEMORY_AVAILABLE) == 0)
+	    hook (0x1000000, eisa_mmap & ~0xFFFF, GRUB_MMAP_MEMORY_AVAILABLE);
+	}
+      else
+	hook (0x100000, grub_get_memsize (1) << 10, GRUB_MMAP_MEMORY_AVAILABLE);
+    }
+}
Index: kern/i386/coreboot/init.c
===================================================================
--- kern/i386/coreboot/init.c	(revision 1800)
+++ kern/i386/coreboot/init.c	(working copy)
@@ -82,12 +82,9 @@
   grub_lower_mem = GRUB_MEMORY_MACHINE_LOWER_USABLE;
   grub_upper_mem = 0;
 
-  auto int heap_init (mem_region_t);
-  int heap_init (mem_region_t mem_region)
+  auto int heap_init (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int heap_init (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
   {
-    grub_uint64_t addr = mem_region->addr;
-    grub_uint64_t size = mem_region->size;
-
 #if GRUB_CPU_SIZEOF_VOID_P == 4
     /* Restrict ourselves to 32-bit memory space.  */
     if (addr > ULONG_MAX)
@@ -101,7 +98,7 @@
 
     grub_upper_mem = grub_max (grub_upper_mem, addr + size);
 
-    if (mem_region->type != GRUB_LINUXBIOS_MEMORY_AVAILABLE)
+    if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
       return 0;
 
     /* Avoid the lower memory.  */
@@ -134,7 +131,7 @@
     return 0;
   }
 
-  grub_available_iterate (heap_init);
+  grub_mmap_iterate (heap_init);
 
   /* This variable indicates size, not offset.  */
   grub_upper_mem -= GRUB_MEMORY_MACHINE_UPPER_START;
Index: kern/i386/coreboot/mmap.c
===================================================================
--- kern/i386/coreboot/mmap.c	(revision 1800)
+++ kern/i386/coreboot/mmap.c	(working copy)
@@ -63,8 +63,8 @@
   return 0;
 }
 
-grub_err_t
-grub_available_iterate (int (*hook) (mem_region_t))
+void
+grub_mmap_iterate (int (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t))
 {
   mem_region_t mem_region;
 
@@ -77,11 +77,17 @@
     mem_region =
       (mem_region_t) ((long) table_item +
 				 sizeof (struct grub_linuxbios_table_item));
-    for (; (long) mem_region < (long) table_item + (long) table_item->size;
-	 mem_region++)
-      if (hook (mem_region))
-	return 1;
+    while ((long) mem_region < (long) table_item + (long) table_item->size)
+      {
+	if (hook (mem_region->addr, mem_region->size,
+		  /* Multiboot mmaps match with the coreboot mmap definition.
+		     Therefore, we can just pass type through.  */
+		  mem_region->type))
+	  return 1;
 
+	mem_region++;
+      }
+
     return 0;
   }
 
Index: include/grub/i386/pc/init.h
===================================================================
--- include/grub/i386/pc/init.h	(revision 1800)
+++ include/grub/i386/pc/init.h	(working copy)
@@ -1,6 +1,6 @@
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2002,2004,2005,2007  Free Software Foundation, Inc.
+ *  Copyright (C) 2002,2004,2005,2007,2008  Free Software Foundation, Inc.
  *
  *  GRUB is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -21,6 +21,8 @@
 
 #include <grub/types.h>
 #include <grub/symbol.h>
+#include <grub/multiboot.h>	/* For struct grub_mmap_entry, which is also
+				   needed by Multiboot.  */
 
 /* Get the memory size in KB. If EXTENDED is zero, return conventional
    memory, otherwise return extended memory.  */
@@ -30,19 +32,18 @@
    in 1KB parts, and upper 16 bits are above 16MB in 64KB parts.  */
 grub_uint32_t grub_get_eisa_mmap (void);
 
-struct grub_machine_mmap_entry
-{
-  grub_uint32_t size;
-  grub_uint64_t addr;
-  grub_uint64_t len;
-  grub_uint32_t type;
-} __attribute__((packed));
+/* Multiboot mmaps have been defined to match with the E820 definition.  */
+#define GRUB_MACHINE_MEMORY_AVAILABLE	GRUB_MMAP_MEMORY_AVAILABLE
+#define GRUB_MACHINE_MEMORY_RESERVED	GRUB_MMAP_MEMORY_RESERVED
 
 /* Get a memory map entry. Return next continuation value. Zero means
    the end.  */
-grub_uint32_t EXPORT_FUNC(grub_get_mmap_entry) (struct grub_machine_mmap_entry *entry,
+grub_uint32_t EXPORT_FUNC(grub_get_mmap_entry) (struct grub_mmap_entry *entry,
 				   grub_uint32_t cont);
 
+void EXPORT_FUNC(grub_mmap_iterate)
+     (int (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t));
+
 /* Turn on/off Gate A20.  */
 void grub_gate_a20 (int on);
 
Index: include/grub/i386/coreboot/memory.h
===================================================================
--- include/grub/i386/coreboot/memory.h	(revision 1800)
+++ include/grub/i386/coreboot/memory.h	(working copy)
@@ -25,7 +25,6 @@
 
 #ifndef ASM_FILE
 #include <grub/types.h>
-#include <grub/err.h>
 #endif
 
 #define GRUB_MEMORY_MACHINE_LOWER_USABLE		0x9fc00		/* 640 kiB - 1 kiB */
@@ -55,13 +54,13 @@
 {
   grub_uint64_t addr;
   grub_uint64_t size;
-#define GRUB_LINUXBIOS_MEMORY_AVAILABLE	1
+#define GRUB_MACHINE_MEMORY_AVAILABLE		1
   grub_uint32_t type;
 };
 typedef struct grub_linuxbios_mem_region *mem_region_t;
 
-grub_err_t EXPORT_FUNC(grub_available_iterate)
-     (int (*hook) (mem_region_t));
+void EXPORT_FUNC(grub_mmap_iterate)
+     (int (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t));
 
 #endif
 
Index: include/grub/multiboot.h
===================================================================
--- include/grub/multiboot.h	(revision 1800)
+++ include/grub/multiboot.h	(working copy)
@@ -1,7 +1,7 @@
 /* multiboot.h - multiboot header file with grub definitions. */
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2003,2007  Free Software Foundation, Inc.
+ *  Copyright (C) 2003,2007,2008  Free Software Foundation, Inc.
  *
  *  GRUB is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -101,6 +101,16 @@
   grub_uint16_t vbe_interface_len;
 };
 
+struct grub_mmap_entry
+{
+  grub_uint32_t size;
+  grub_uint64_t addr;
+  grub_uint64_t len;
+#define GRUB_MMAP_MEMORY_AVAILABLE	1
+#define GRUB_MMAP_MEMORY_RESERVED	2
+  grub_uint32_t type;
+} __attribute__((packed));
+
 struct grub_mod_list
 {
   /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
Index: loader/i386/pc/multiboot.c
===================================================================
--- loader/i386/pc/multiboot.c	(revision 1800)
+++ loader/i386/pc/multiboot.c	(working copy)
@@ -103,14 +103,60 @@
       grub_free ((void *) mbi->cmdline);
       grub_free (mbi);
     }
-
-
+  
   mbi = 0;
   grub_dl_unref (my_mod);
 
   return GRUB_ERR_NONE;
 }
 
+/* FIXME: grub_uint32_t will break for addresses above 4 GiB, but is mandated
+   by the spec.  Is there something we can do about it?  */
+static grub_uint32_t mmap_addr = 0;
+static grub_uint32_t mmap_length;
+
+/* Return the length of the Multiboot mmap that will be needed to allocate
+   our platform's map.  */
+static grub_uint32_t
+grub_get_multiboot_mmap_len ()
+{
+  grub_size_t count = 0;
+
+  auto int hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int hook (grub_uint64_t addr __attribute__ ((unused)),
+	    grub_uint64_t size __attribute__ ((unused)),
+	    grub_uint32_t type __attribute__ ((unused)))
+    {
+      count++;
+      return 0;
+    }
+  
+  grub_mmap_iterate (hook);
+  
+  return count * sizeof (struct grub_mmap_entry);
+}
+
+/* Fill previously allocated Multiboot mmap.  */
+static void
+grub_fill_multiboot_mmap (struct grub_mmap_entry *first_entry)
+{
+  struct grub_mmap_entry *mmap_entry = (struct grub_mmap_entry *) first_entry;
+
+  auto int hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
+    {
+      mmap_entry->addr = addr;
+      mmap_entry->len = size;
+      mmap_entry->type = type;
+      mmap_entry->size = sizeof (struct grub_mmap_entry) - sizeof (mmap_entry->size);
+      mmap_entry++;
+
+      return 0;
+    }
+
+  grub_mmap_iterate (hook);
+}
+
 /* Check if BUFFER contains ELF32.  */
 static int
 grub_multiboot_is_elf32 (void *buffer)
@@ -152,7 +198,11 @@
 	if (phdr(i)->p_paddr > phdr(highest_segment)->p_paddr)
 	  highest_segment = i;
       }
-  grub_multiboot_payload_size = (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr;
+
+  mmap_length = grub_get_multiboot_mmap_len ();
+
+  grub_multiboot_payload_size = ((phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr
+				 + mmap_length);
   grub_multiboot_payload_dest = phdr(lowest_segment)->p_paddr;
 
   if (playground)
@@ -196,6 +246,12 @@
 
 #undef phdr
 
+  grub_fill_multiboot_mmap ((struct grub_mmap_entry *) (grub_multiboot_payload_orig
+							+ grub_multiboot_payload_size
+							- mmap_length));
+
+  mmap_addr = grub_multiboot_payload_dest + grub_multiboot_payload_size - mmap_length;
+
   if (grub_multiboot_payload_dest >= grub_multiboot_payload_orig)
     entry = (grub_addr_t) playground;
   else
@@ -437,12 +493,18 @@
 
   grub_memset (mbi, 0, sizeof (struct grub_multiboot_info));
 
-  mbi->flags = MULTIBOOT_INFO_MEMORY;
-
   /* Convert from bytes to kilobytes.  */
   mbi->mem_lower = grub_lower_mem / 1024;
   mbi->mem_upper = grub_upper_mem / 1024;
+  mbi->flags |= MULTIBOOT_INFO_MEMORY;
 
+  if (mmap_addr)
+    {
+      mbi->mmap_addr = mmap_addr;
+      mbi->mmap_length = mmap_length;
+      mbi->flags |= MULTIBOOT_INFO_MEM_MAP;
+    }
+
   for (i = 0, len = 0; i < argc; i++)
     len += grub_strlen (argv[i]) + 1;
 
Index: loader/i386/bsd.c
===================================================================
--- loader/i386/bsd.c	(revision 1800)
+++ loader/i386/bsd.c	(working copy)
@@ -313,7 +313,7 @@
 grub_openbsd_boot (void)
 {
   char *buf = (char *) GRUB_BSD_TEMP_BUFFER;
-  struct grub_machine_mmap_entry mmap;
+  struct grub_mmap_entry mmap;
   struct grub_openbsd_bios_mmap *pm;
   struct grub_openbsd_bootargs *pa;
   grub_uint32_t bootdev, biosdev, unit, slice, part, cont;

  reply	other threads:[~2008-08-12 13:26 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-08-11 15:22 [PATCH] decouple mmap parsing by using grub_available_iterate() Robert Millan
2008-08-11 15:39 ` Vesa Jääskeläinen
2008-08-11 21:24   ` Robert Millan
2008-08-11 22:07     ` Robert Millan
2008-08-12 13:25       ` Robert Millan [this message]
2008-08-12 16:29         ` [PATCH] decouple mmap parsing and implement Multiboot mmap in the loader Robert Millan
2008-08-12 22:38           ` Robert Millan
2008-08-12 23:44             ` Robert Millan
2008-08-13 17:52               ` Marco Gerards
2008-08-13 19:51                 ` Robert Millan
2008-08-16 14:50                   ` Marco Gerards
2008-08-17 16:31                     ` Robert Millan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080812132515.GA13942@thorin \
    --to=rmh@aybabtu.com \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.