Hello, here is the version with changelog, fix for freebsd_module and
licencing corrections.
If nobody objects I'll commit it soon
Enjoy


On Sun, Apr 12, 2009 at 9:19 PM, Bean <bean12...@gmail.com> wrote:

> Hi,
>
> This patch allows you to load amd64 freebsd kernel directly, here is an
> example:
>
> set root=(hd0,1,a)
> freebsd /boot/kernel/kernel
> freebsd_loadenv /boot/device.hints
> set FreeBSD.vfs.root.mountfrom=ufs:/dev/ad0s1a
> boot
>
> Test successfully on FreeBSD 7.1 amd64.
>
> --
> Bean
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
>
diff --git a/ChangeLog b/ChangeLog
index ca0ab43..bd1776b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2009-04-21  Bean  <bean12...@gmail.com> Vladimir Serbinenko <phco...@gmail.com>
+
+	FreeBSD 64-bit support
+
+	* conf/i386-pc.rmk (bsd_mod_SOURCES): add loader/i386/bsd_helper.S 
+	and loader/i386/bsd_trampoline.S
+	(bsd_mod_ASFLAGS): new variable
+	* include/grub/i386/bsd.h (FREEBSD_MODINFOMD_SMAP): new definition
+	(FREEBSD_MODTYPE_KERNEL64): likewise
+	(grub_bsd64_trampoline_start): likewise
+	(grub_bsd64_trampoline_end): likewise
+	(grub_bsd64_trampoline_selfjump): likewise
+	(grub_bsd64_trampoline_gdt): likewise
+	* include/grub/i386/loader.h (grub_unix_real_boot): moved from here ...
+	* include/grub/i386/bsd.h (grub_unix_real_boot): ... moved here
+	* kern/i386/loader.S (grub_unix_real_boot): moved from here ...
+	* loader/i386/bsd_helper.S (grub_unix_real_boot): moved here
+	* include/grub/gpt_partition.h (grub_gpt_partentry): Corrected the type 
+	of "attrib" member
+	* loader/i386/bsd_pagetable.c: new file
+	* loader/i386/bsd_trampoline.S: likewise
+	* loader/i386/bsd.c (ALIGN_QWORD): new macro
+	(ALIGN_VAR): likewise
+	(entry_hi): new variable
+	(kern_end_mdofs): likewise
+	(is_64bit): likewise
+	(grub_freebsd_add_meta): use ALIGN_VAR
+	(grub_e820_mmap): new declaration
+	(grub_freebsd_add_mmap): new function
+	(grub_freebsd_add_meta_module): support 64 bit kernels
+	(grub_freebsd_list_modules): use ALIGN_VAR
+	(gdt_descriptor): new declaration
+	(grub_freebsd_boot): support 64 bit kernels
+	(grub_bsd_elf64_hook): new function
+	(grub_bsd_load_elf): support elf64
+
+
 2009-04-19  Vladimir Serbinenko <phco...@gmail.com>
 
 	Correct GPT definition
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 265b250..bf2516d 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -301,9 +301,10 @@ aout_mod_CFLAGS = $(COMMON_CFLAGS)
 aout_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For bsd.mod
-bsd_mod_SOURCES = loader/i386/bsd.c
+bsd_mod_SOURCES = loader/i386/bsd.c loader/i386/bsd_helper.S loader/i386/bsd_trampoline.S
 bsd_mod_CFLAGS = $(COMMON_CFLAGS)
 bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
+bsd_mod_ASFLAGS = $(COMMON_ASFLAGS)
 
 # For usb.mod
 usb_mod_SOURCES = bus/usb/usb.c bus/usb/usbtrans.c bus/usb/usbhub.c
diff --git a/include/grub/i386/bsd.h b/include/grub/i386/bsd.h
index f50f18e..3706f4d 100644
--- a/include/grub/i386/bsd.h
+++ b/include/grub/i386/bsd.h
@@ -80,9 +80,12 @@
 #define FREEBSD_MODINFOMD_SHDR		0x0009	/* section header table */
 #define FREEBSD_MODINFOMD_NOCOPY	0x8000	/* don't copy this metadata to the kernel */
 
+#define FREEBSD_MODINFOMD_SMAP		0x1001
+
 #define FREEBSD_MODINFOMD_DEPLIST	(0x4001 | FREEBSD_MODINFOMD_NOCOPY)  /* depends on */
 
 #define FREEBSD_MODTYPE_KERNEL		"elf kernel"
+#define FREEBSD_MODTYPE_KERNEL64	"elf64 kernel"
 #define FREEBSD_MODTYPE_MODULE		"elf module"
 #define FREEBSD_MODTYPE_RAW		"raw"
 
@@ -222,4 +225,11 @@ struct grub_netbsd_btinfo_bootdisk
   int partition;
 };
 
+void grub_unix_real_boot (grub_addr_t entry, ...)
+     __attribute__ ((cdecl,noreturn));
+
+extern grub_uint8_t grub_bsd64_trampoline_start, grub_bsd64_trampoline_end;
+extern grub_uint32_t grub_bsd64_trampoline_selfjump;
+extern grub_uint32_t grub_bsd64_trampoline_gdt;
+
 #endif /* ! GRUB_BSD_CPU_HEADER */
diff --git a/include/grub/i386/loader.h b/include/grub/i386/loader.h
index afd3eb9..72a44d0 100644
--- a/include/grub/i386/loader.h
+++ b/include/grub/i386/loader.h
@@ -32,7 +32,4 @@ extern grub_size_t EXPORT_VAR(grub_os_area_size);
 
 grub_err_t EXPORT_FUNC(grub_linux16_boot) (void);
 
-void EXPORT_FUNC(grub_unix_real_boot) (grub_addr_t entry, ...)
-     __attribute__ ((cdecl,noreturn));
-
 #endif /* ! GRUB_LOADER_CPU_HEADER */
diff --git a/kern/i386/loader.S b/kern/i386/loader.S
index bbd2187..3e9c713 100644
--- a/kern/i386/loader.S
+++ b/kern/i386/loader.S
@@ -118,25 +118,3 @@ linux_setup_seg:
 	.word	0
 	.code32
 
-/*
- * Use cdecl calling convention for *BSD kernels.
- */
-
-FUNCTION(grub_unix_real_boot)
-
-        call    EXT_C(grub_dl_unload_all)
-
-	/* Interrupts should be disabled.  */
-        cli
-
-	/* Discard `grub_unix_real_boot' return address.  */
-        popl    %eax
-
-        /* Fetch `entry' address ...  */
-        popl	%eax
-
-        /*
-         * ... and put our return address in its place. The kernel will
-         * ignore it, but it expects %esp to point to it.
-         */
-        call	*%eax
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index 355cb3f..167cd0b 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -1,6 +1,6 @@
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *  Copyright (C) 2008, 2009  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
@@ -33,17 +33,19 @@
 #include <grub/command.h>
 
 #define ALIGN_DWORD(a)	ALIGN_UP (a, 4)
+#define ALIGN_QWORD(a)	ALIGN_UP (a, 8)
+#define ALIGN_VAR(a)	((is_64bit) ? (ALIGN_QWORD(a)) : (ALIGN_DWORD(a)))
 #define ALIGN_PAGE(a)	ALIGN_UP (a, 4096)
 
 #define MOD_BUF_ALLOC_UNIT	4096
 
 static int kernel_type;
 static grub_dl_t my_mod;
-static grub_addr_t entry, kern_start, kern_end;
+static grub_addr_t entry, entry_hi, kern_start, kern_end;
 static grub_uint32_t bootflags;
 static char *mod_buf;
-static grub_uint32_t mod_buf_len, mod_buf_max;
-static int is_elf_kernel;
+static grub_uint32_t mod_buf_len, mod_buf_max, kern_end_mdofs;
+static int is_elf_kernel, is_64bit;
 
 static const char freebsd_opts[] = "DhaCcdgmnpqrsv";
 static const grub_uint32_t freebsd_flags[] =
@@ -135,11 +137,58 @@ grub_freebsd_add_meta (grub_uint32_t type, void *data, grub_uint32_t len)
   if (len)
     grub_memcpy (mod_buf + mod_buf_len, data, len);
 
-  mod_buf_len = ALIGN_DWORD (mod_buf_len + len);
+  mod_buf_len = ALIGN_VAR (mod_buf_len + len);
 
   return GRUB_ERR_NONE;
 }
 
+struct grub_e820_mmap
+{
+  grub_uint64_t addr;
+  grub_uint64_t size;
+  grub_uint32_t type;
+} __attribute__((packed));
+
+static grub_err_t
+grub_freebsd_add_mmap (void)
+{
+  grub_size_t len = 0;
+  struct grub_e820_mmap *mmap = 0;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+			     grub_uint32_t type)
+    {
+      if (mmap)
+	{
+	  mmap->addr = addr;
+	  mmap->size = size;
+	  mmap->type = type;
+	  mmap++;
+	}
+      else
+	len += sizeof (struct grub_e820_mmap);
+
+      return 0;
+    }
+
+  struct grub_e820_mmap *mmap_buf;
+
+  grub_machine_mmap_iterate (hook);
+  mmap_buf = mmap = grub_malloc (len);
+  if (! mmap)
+    return grub_errno;
+
+  grub_machine_mmap_iterate (hook);
+
+  grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
+			 FREEBSD_MODINFOMD_SMAP, mmap_buf, len);
+
+  grub_free (mmap_buf);
+
+  return grub_errno;
+}
+
 static grub_err_t
 grub_freebsd_add_meta_module (int is_kern, int argc, char **argv,
 			      grub_addr_t addr, grub_uint32_t size)
@@ -166,13 +215,31 @@ grub_freebsd_add_meta_module (int is_kern, int argc, char **argv,
       argv++;
     }
   else
-    type = (is_kern) ? FREEBSD_MODTYPE_KERNEL : FREEBSD_MODTYPE_RAW;
+    type = ((is_kern) ?
+	    ((is_64bit) ? FREEBSD_MODTYPE_KERNEL64 : FREEBSD_MODTYPE_KERNEL)
+	    : FREEBSD_MODTYPE_RAW);
 
-  if ((grub_freebsd_add_meta (FREEBSD_MODINFO_TYPE, type,
+  if (is_64bit)
+    {
+      grub_uint64_t addr64 = addr, size64 = size; 
+      if ((grub_freebsd_add_meta (FREEBSD_MODINFO_TYPE, type,
 			      grub_strlen (type) + 1)) ||
-      (grub_freebsd_add_meta (FREEBSD_MODINFO_ADDR, &addr, sizeof (addr))) ||
-      (grub_freebsd_add_meta (FREEBSD_MODINFO_SIZE, &size, sizeof (size))))
-    return grub_errno;
+	  (grub_freebsd_add_meta (FREEBSD_MODINFO_ADDR, &addr64, 
+				  sizeof (addr64))) ||
+	  (grub_freebsd_add_meta (FREEBSD_MODINFO_SIZE, &size64, 
+				  sizeof (size64))))
+	return grub_errno;
+    }
+  else
+    {
+      if ((grub_freebsd_add_meta (FREEBSD_MODINFO_TYPE, type,
+				  grub_strlen (type) + 1)) ||
+	  (grub_freebsd_add_meta (FREEBSD_MODINFO_ADDR, &addr, 
+				  sizeof (addr))) ||
+	  (grub_freebsd_add_meta (FREEBSD_MODINFO_SIZE, &size, 
+				  sizeof (size))))
+	return grub_errno;
+    }
 
   if (argc)
     {
@@ -202,6 +269,23 @@ grub_freebsd_add_meta_module (int is_kern, int argc, char **argv,
 	}
     }
 
+  if (is_kern)
+    {
+      int len = (is_64bit) ? 8 : 4;
+      grub_uint64_t data = 0;
+
+      if ((grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
+				  FREEBSD_MODINFOMD_HOWTO, &data, 4)) ||
+	  (grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
+				  FREEBSD_MODINFOMD_ENVP, &data, len)) ||
+	  (grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
+				  FREEBSD_MODINFOMD_KERNEND, &data, len)))
+	return grub_errno;
+      kern_end_mdofs = mod_buf_len - len;
+
+      return grub_freebsd_add_mmap ();
+    }
+
   return GRUB_ERR_NONE;
 }
 
@@ -241,10 +325,19 @@ grub_freebsd_list_modules (void)
 	  }
 	}
 
-      pos = ALIGN_DWORD (pos + size);
+      pos = ALIGN_VAR (pos + size);
     }
 }
 
+/* This function would be here but it's under different licence. */
+#include "bsd_pagetable.c"
+
+struct gdt_descriptor
+{
+  grub_uint16_t limit;
+  void *base;
+} __attribute__ ((packed));
+
 static grub_err_t
 grub_freebsd_boot (void)
 {
@@ -291,6 +384,9 @@ grub_freebsd_boot (void)
 
   if (is_elf_kernel)
     {
+      grub_addr_t md_ofs;
+      int ofs;
+
       if (grub_freebsd_add_meta (FREEBSD_MODINFO_END, 0, 0))
 	return grub_errno;
 
@@ -298,12 +394,70 @@ grub_freebsd_boot (void)
       bi.bi_modulep = kern_end;
 
       kern_end = ALIGN_PAGE (kern_end + mod_buf_len);
+
+      if (is_64bit)
+	kern_end += 4096 * 4;
+
+      md_ofs = bi.bi_modulep + kern_end_mdofs;
+      ofs = (is_64bit) ? 16 : 12;
+      *((grub_uint32_t *) md_ofs) = kern_end;
+      md_ofs -= ofs;
+      *((grub_uint32_t *) md_ofs) = bi.bi_envp;
+      md_ofs -= ofs;
+      *((grub_uint32_t *) md_ofs) = bootflags;
     }
 
   bi.bi_kernend = kern_end;
 
-  grub_unix_real_boot (entry, bootflags | FREEBSD_RB_BOOTINFO, bootdev,
-		       0, 0, 0, &bi, bi.bi_modulep, kern_end);
+  if (is_64bit)
+    {
+      grub_uint32_t *gdt;
+      grub_uint8_t *trampoline;
+      void (*launch_trampoline) (grub_addr_t entry, ...)
+	__attribute__ ((cdecl, regparm (0)));
+      grub_uint8_t *pagetable;
+
+      struct gdt_descriptor *gdtdesc;
+
+      pagetable = (grub_uint8_t *) (kern_end - 16384);
+      fill_bsd64_pagetable (pagetable);
+
+      /* Create GDT. */
+      gdt = (grub_uint32_t *) (kern_end - 4096);
+      gdt[0] = 0;
+      gdt[1] = 0;
+      gdt[2] = 0;
+      gdt[3] = 0x00209800;
+      gdt[4] = 0;
+      gdt[5] = 0x00008000;
+
+      /* Create GDT descriptor. */
+      gdtdesc = (struct gdt_descriptor *) (kern_end - 4096 + 24);
+      gdtdesc->limit = 24;
+      gdtdesc->base = gdt;
+
+      /* Prepare trampoline. */
+      trampoline = (grub_uint8_t *) (kern_end - 4096 + 24 
+				     + sizeof (struct gdt_descriptor));
+      launch_trampoline = (void  __attribute__ ((cdecl, regparm (0))) 
+			   (*) (grub_addr_t entry, ...)) trampoline;
+      grub_bsd64_trampoline_gdt = (grub_uint32_t) gdtdesc;
+      grub_bsd64_trampoline_selfjump 
+	= (grub_uint32_t) (trampoline + 6
+			   + ((grub_uint8_t *) &grub_bsd64_trampoline_selfjump 
+			      - &grub_bsd64_trampoline_start));
+
+      /* Copy trampoline. */
+      grub_memcpy (trampoline, &grub_bsd64_trampoline_start, 
+		   &grub_bsd64_trampoline_end - &grub_bsd64_trampoline_start);
+
+      /* Launch trampoline. */
+      launch_trampoline (entry, entry_hi, pagetable, bi.bi_modulep, 
+			 kern_end);
+    }
+  else
+    grub_unix_real_boot (entry, bootflags | FREEBSD_RB_BOOTINFO, bootdev,
+			 0, 0, 0, &bi, bi.bi_modulep, kern_end);
 
   /* Not reached.  */
   return GRUB_ERR_NONE;
@@ -478,6 +632,29 @@ grub_bsd_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr)
 }
 
 static grub_err_t
+grub_bsd_elf64_hook (Elf64_Phdr * phdr, grub_addr_t * addr)
+{
+  Elf64_Addr paddr;
+
+  paddr = phdr->p_paddr & 0xffffff;
+
+  if ((paddr < grub_os_area_addr)
+      || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size))
+    return grub_error (GRUB_ERR_OUT_OF_RANGE, "Address 0x%x is out of range",
+		       paddr);
+
+  if ((!kern_start) || (paddr < kern_start))
+    kern_start = paddr;
+
+  if (paddr + phdr->p_memsz > kern_end)
+    kern_end = paddr + phdr->p_memsz;
+
+  *addr = paddr;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
 grub_bsd_load_elf (grub_elf_t elf)
 {
   kern_start = kern_end = 0;
@@ -487,6 +664,13 @@ grub_bsd_load_elf (grub_elf_t elf)
       entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF;
       return grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0);
     }
+  else if (grub_elf_is_elf64 (elf))
+    {
+      is_64bit = 1;
+      entry = elf->ehdr.ehdr64.e_entry & 0xffffffff;
+      entry_hi = (elf->ehdr.ehdr64.e_entry >> 32) & 0xffffffff;
+      return grub_elf64_load (elf, grub_bsd_elf64_hook, 0, 0);
+    }
   else
     return grub_error (GRUB_ERR_BAD_OS, "invalid elf");
 }
diff --git a/loader/i386/bsd_helper.S b/loader/i386/bsd_helper.S
new file mode 100644
index 0000000..23c8610
--- /dev/null
+++ b/loader/i386/bsd_helper.S
@@ -0,0 +1,45 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008, 2009 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/symbol.h>
+	
+	.p2align	2
+	
+
+	.code32
+
+/*
+ * Use cdecl calling convention for *BSD kernels.
+ */
+
+FUNCTION(grub_unix_real_boot)
+
+	/* Interrupts should be disabled.  */
+        cli
+
+	/* Discard `grub_unix_real_boot' return address.  */
+        popl    %eax
+
+        /* Fetch `entry' address ...  */
+        popl	%eax
+
+        /*
+         * ... and put our return address in its place. The kernel will
+         * ignore it, but it expects %esp to point to it.
+         */
+        call	*%eax
diff --git a/loader/i386/bsd_pagetable.c b/loader/i386/bsd_pagetable.c
new file mode 100644
index 0000000..522a19c
--- /dev/null
+++ b/loader/i386/bsd_pagetable.c
@@ -0,0 +1,84 @@
+
+/*-
+ * Copyright (c) 1998  Michael Smith <msm...@freebsd.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009  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/>.
+ */
+
+
+static void
+fill_bsd64_pagetable (grub_uint8_t *target)
+{
+  grub_uint64_t *pt2, *pt3, *pt4;
+  int i;
+
+#define PG_V		0x001
+#define PG_RW		0x002
+#define PG_U		0x004
+#define PG_PS		0x080
+
+  pt4 = (grub_uint64_t *) target;
+  pt3 = (grub_uint64_t *) (target + 4096);
+  pt2 = (grub_uint64_t *) (target + 8192);
+  
+  grub_memset ((char *) target, 0, 4096 * 3);
+
+  /*
+   * This is kinda brutal, but every single 1GB VM memory segment points to
+   * the same first 1GB of physical memory.  But it is how BSD expects 
+   * it to be.
+   */
+  for (i = 0; i < 512; i++)
+    {
+      /* Each slot of the level 4 pages points to the same level 3 page */
+      pt4[i] = (grub_addr_t) &pt3[0];
+      pt4[i] |= PG_V | PG_RW | PG_U;
+
+      /* Each slot of the level 3 pages points to the same level 2 page */
+      pt3[i] = (grub_addr_t) &pt2[0];
+      pt3[i] |= PG_V | PG_RW | PG_U;
+      
+      /* The level 2 page slots are mapped with 2MB pages for 1GB. */
+      pt2[i] = i * (2 * 1024 * 1024);
+      pt2[i] |= PG_V | PG_RW | PG_PS | PG_U;
+    }
+}
diff --git a/loader/i386/bsd_trampoline.S b/loader/i386/bsd_trampoline.S
new file mode 100644
index 0000000..b283a87
--- /dev/null
+++ b/loader/i386/bsd_trampoline.S
@@ -0,0 +1,121 @@
+
+/*-
+ * Copyright (c) 2003  Peter Wemm <pe...@freebsd.org>
+ * Copyright (C) 2009  Free Software 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009  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/>.
+ */
+
+	
+#define MSR_EFER	0xc0000080
+#define EFER_LME	0x00000100
+#define CR4_PAE		0x00000020
+#define CR4_PSE		0x00000010
+#define CR0_PG		0x80000000
+
+#include <grub/symbol.h>
+
+	.p2align	2
+	
+	.code32	
+
+	
+VARIABLE(grub_bsd64_trampoline_start)
+
+	/* Discard `grub_unix_real_boot' return address.  */
+        popl    %eax
+
+        /* entry  */
+        popl	%edi
+
+        /* entry_hi  */
+        popl	%esi
+
+	cli
+
+	/* Turn on EFER.LME.  */
+	movl	$MSR_EFER, %ecx
+	rdmsr
+	orl	$EFER_LME, %eax
+        wrmsr
+
+	/* Turn on PAE.  */
+	movl	%cr4, %eax
+	orl	$(CR4_PAE | CR4_PSE), %eax
+	movl	%eax, %cr4
+
+	/* Set %cr3 for PT4.  */
+	popl	%eax
+	movl    %eax, %cr3
+
+	/* Push a dummy return address.  */
+	pushl	%eax
+
+	/* Turn on paging (implicitly sets EFER.LMA).  */
+	movl	%cr0, %eax
+	orl	$CR0_PG, %eax
+	movl	%eax, %cr0
+
+	/* Now we're in compatability mode. set %cs for long mode.  */
+	/* lgdt */
+	.byte 0x0f
+	.byte 0x01
+	.byte 0x15
+VARIABLE (grub_bsd64_trampoline_gdt)
+	.long 0x0
+	
+	/* ljmp */
+	.byte 0xea
+VARIABLE (grub_bsd64_trampoline_selfjump)
+	.long 0x0
+	.word 0x08
+
+	.code64
+
+bsd64_longmode:
+         /* We're still running V=P, jump to entry point.  */
+	movl	%esi, %eax
+	salq	$32, %rax
+	orq	%rdi, %rax
+	pushq	%rax
+	ret
+VARIABLE(grub_bsd64_trampoline_end)
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to