Blame SOURCES/0142-Improve-FreeDOS-direct-loading-support-compatibility.patch

f96e0b
From be56f8f0420fa5efc55ac9789d41c6307a84bef0 Mon Sep 17 00:00:00 2001
f96e0b
From: "C. Masloch" <pushbx@38.de>
f96e0b
Date: Sun, 27 Jan 2013 16:07:25 +0100
f96e0b
Subject: [PATCH 142/482] 	Improve FreeDOS direct loading support
f96e0b
 compatibility.
f96e0b
f96e0b
	* include/grub/i386/relocator.h (grub_relocator16_state):
f96e0b
	New member ebp.
f96e0b
	* grub-core/lib/i386/relocator.c (grub_relocator16_ebp): New extern
f96e0b
	variable.
f96e0b
	(grub_relocator16_boot): Handle %ebp.
f96e0b
	* grub-core/lib/i386/relocator16.S: Likewise.
f96e0b
	* grub-core/loader/i386/pc/freedos.c:
f96e0b
	Load BPB to pass kernel which partition to load from.
f96e0b
	Check that kernel file is not too large.
f96e0b
	Set register dl to BIOS unit number as well.
f96e0b
---
f96e0b
 ChangeLog                          | 15 ++++++++++
f96e0b
 grub-core/lib/i386/relocator.c     |  2 ++
f96e0b
 grub-core/lib/i386/relocator16.S   |  5 ++++
f96e0b
 grub-core/loader/i386/pc/freedos.c | 61 ++++++++++++++++++++++++++++++++++----
f96e0b
 include/grub/i386/relocator.h      |  1 +
f96e0b
 5 files changed, 79 insertions(+), 5 deletions(-)
f96e0b
f96e0b
diff --git a/ChangeLog b/ChangeLog
f96e0b
index 8c4d087..f5cb7dc 100644
f96e0b
--- a/ChangeLog
f96e0b
+++ b/ChangeLog
f96e0b
@@ -1,3 +1,18 @@
f96e0b
+2013-01-27  C. Masloch  <pushbx@38.de>
f96e0b
+
f96e0b
+	Improve FreeDOS direct loading support compatibility.
f96e0b
+
f96e0b
+	* include/grub/i386/relocator.h (grub_relocator16_state):
f96e0b
+	New member ebp.
f96e0b
+	* grub-core/lib/i386/relocator.c (grub_relocator16_ebp): New extern
f96e0b
+	variable.
f96e0b
+	(grub_relocator16_boot): Handle %ebp.
f96e0b
+	* grub-core/lib/i386/relocator16.S: Likewise.
f96e0b
+	* grub-core/loader/i386/pc/freedos.c:
f96e0b
+	Load BPB to pass kernel which partition to load from.
f96e0b
+	Check that kernel file is not too large.
f96e0b
+	Set register dl to BIOS unit number as well.
f96e0b
+
f96e0b
 2013-01-22  Colin Watson  <cjwatson@ubuntu.com>
f96e0b
 
f96e0b
 	* util/grub-reboot.in (usage): Document the need for
f96e0b
diff --git a/grub-core/lib/i386/relocator.c b/grub-core/lib/i386/relocator.c
f96e0b
index df25b30..0170eed 100644
f96e0b
--- a/grub-core/lib/i386/relocator.c
f96e0b
+++ b/grub-core/lib/i386/relocator.c
f96e0b
@@ -54,6 +54,7 @@ extern grub_uint16_t grub_relocator16_sp;
f96e0b
 extern grub_uint32_t grub_relocator16_edx;
f96e0b
 extern grub_uint32_t grub_relocator16_ebx;
f96e0b
 extern grub_uint32_t grub_relocator16_esi;
f96e0b
+extern grub_uint32_t grub_relocator16_ebp;
f96e0b
 
f96e0b
 extern grub_uint16_t grub_relocator16_keep_a20_enabled;
f96e0b
 
f96e0b
@@ -225,6 +226,7 @@ grub_relocator16_boot (struct grub_relocator *rel,
f96e0b
   grub_relocator16_ss = state.ss;
f96e0b
   grub_relocator16_sp = state.sp;
f96e0b
 
f96e0b
+  grub_relocator16_ebp = state.ebp;
f96e0b
   grub_relocator16_ebx = state.ebx;
f96e0b
   grub_relocator16_edx = state.edx;
f96e0b
   grub_relocator16_esi = state.esi;
f96e0b
diff --git a/grub-core/lib/i386/relocator16.S b/grub-core/lib/i386/relocator16.S
f96e0b
index e79d875..c8d6f86 100644
f96e0b
--- a/grub-core/lib/i386/relocator16.S
f96e0b
+++ b/grub-core/lib/i386/relocator16.S
f96e0b
@@ -259,6 +259,11 @@ VARIABLE(grub_relocator16_edx)
f96e0b
 VARIABLE(grub_relocator16_ebx)
f96e0b
 	.long	0
f96e0b
 
f96e0b
+	/* movl imm32, %ebp.  */
f96e0b
+	.byte	0x66, 0xbd
f96e0b
+VARIABLE(grub_relocator16_ebp)
f96e0b
+	.long	0
f96e0b
+
f96e0b
 	/* Cleared direction flag is of no problem with any current
f96e0b
 	   payload and makes this implementation easier.  */
f96e0b
 	cld
f96e0b
diff --git a/grub-core/loader/i386/pc/freedos.c b/grub-core/loader/i386/pc/freedos.c
f96e0b
index f1eed57..e685c6e 100644
f96e0b
--- a/grub-core/loader/i386/pc/freedos.c
f96e0b
+++ b/grub-core/loader/i386/pc/freedos.c
f96e0b
@@ -32,6 +32,7 @@
f96e0b
 #include <grub/video.h>
f96e0b
 #include <grub/mm.h>
f96e0b
 #include <grub/cpu/relocator.h>
f96e0b
+#include <grub/machine/chainloader.h>
f96e0b
 
f96e0b
 GRUB_MOD_LICENSE ("GPLv3+");
f96e0b
 
f96e0b
@@ -40,8 +41,23 @@ static struct grub_relocator *rel;
f96e0b
 static grub_uint32_t ebx = 0xffffffff;
f96e0b
 
f96e0b
 #define GRUB_FREEDOS_SEGMENT         0x60
f96e0b
+#define GRUB_FREEDOS_ADDR            (GRUB_FREEDOS_SEGMENT << 4)
f96e0b
 #define GRUB_FREEDOS_STACK_SEGMENT         0x1fe0
f96e0b
-#define GRUB_FREEDOS_STACK_POINTER         0x8000
f96e0b
+#define GRUB_FREEDOS_STACK_BPB_POINTER     0x7c00
f96e0b
+#define GRUB_FREEDOS_BPB_ADDR        ((GRUB_FREEDOS_STACK_SEGMENT << 4) \
f96e0b
+                                       + GRUB_FREEDOS_STACK_BPB_POINTER)
f96e0b
+
f96e0b
+/* FreeDOS boot.asm passes register sp as exactly this. Importantly,
f96e0b
+   it must point below the BPB (to avoid overwriting any of it). */
f96e0b
+#define GRUB_FREEDOS_STACK_POINTER         (GRUB_FREEDOS_STACK_BPB_POINTER \
f96e0b
+                                             - 0x60)
f96e0b
+
f96e0b
+/* In this, the additional 8192 bytes are the stack reservation; the
f96e0b
+   remaining parts trivially give the maximum allowed size. */
f96e0b
+#define GRUB_FREEDOS_MAX_SIZE        ((GRUB_FREEDOS_STACK_SEGMENT << 4) \
f96e0b
+                                       + GRUB_FREEDOS_STACK_POINTER \
f96e0b
+                                       - GRUB_FREEDOS_ADDR \
f96e0b
+                                       - 8192)
f96e0b
 
f96e0b
 static grub_err_t
f96e0b
 grub_freedos_boot (void)
f96e0b
@@ -49,14 +65,16 @@ grub_freedos_boot (void)
f96e0b
   struct grub_relocator16_state state = { 
f96e0b
     .cs = GRUB_FREEDOS_SEGMENT,
f96e0b
     .ip = 0,
f96e0b
-    .ds = 0,
f96e0b
+
f96e0b
+    .ds = GRUB_FREEDOS_STACK_SEGMENT,
f96e0b
     .es = 0,
f96e0b
     .fs = 0,
f96e0b
     .gs = 0,
f96e0b
     .ss = GRUB_FREEDOS_STACK_SEGMENT,
f96e0b
     .sp = GRUB_FREEDOS_STACK_POINTER,
f96e0b
+    .ebp = GRUB_FREEDOS_STACK_BPB_POINTER,
f96e0b
     .ebx = ebx,
f96e0b
-    .edx = 0,
f96e0b
+    .edx = ebx,
f96e0b
     .a20 = 1
f96e0b
   };
f96e0b
   grub_video_set_mode ("text", 0, 0);
f96e0b
@@ -79,8 +97,9 @@ grub_cmd_freedos (grub_command_t cmd __attribute__ ((unused)),
f96e0b
 {
f96e0b
   grub_file_t file = 0;
f96e0b
   grub_err_t err;
f96e0b
-  void *kernelsys;
f96e0b
+  void *bs, *kernelsys;
f96e0b
   grub_size_t kernelsyssize;
f96e0b
+  grub_device_t dev;
f96e0b
 
f96e0b
   if (argc == 0)
f96e0b
     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
f96e0b
@@ -95,12 +114,44 @@ grub_cmd_freedos (grub_command_t cmd __attribute__ ((unused)),
f96e0b
   if (! file)
f96e0b
     goto fail;
f96e0b
 
f96e0b
+  {
f96e0b
+    grub_relocator_chunk_t ch;
f96e0b
+    err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_FREEDOS_BPB_ADDR,
f96e0b
+					   GRUB_DISK_SECTOR_SIZE);
f96e0b
+    if (err)
f96e0b
+      goto fail;
f96e0b
+    bs = get_virtual_current_address (ch);
f96e0b
+  }
f96e0b
+
f96e0b
   ebx = grub_get_root_biosnumber ();
f96e0b
+  dev = grub_device_open (0);
f96e0b
+
f96e0b
+  if (dev && dev->disk)
f96e0b
+    {
f96e0b
+      err = grub_disk_read (dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, bs);
f96e0b
+      if (err)
f96e0b
+	{
f96e0b
+	  grub_device_close (dev);
f96e0b
+	  goto fail;
f96e0b
+	}
f96e0b
+      grub_chainloader_patch_bpb (bs, dev, ebx);
f96e0b
+    }
f96e0b
+
f96e0b
+  if (dev)
f96e0b
+    grub_device_close (dev);
f96e0b
 
f96e0b
   kernelsyssize = grub_file_size (file);
f96e0b
+
f96e0b
+  if (kernelsyssize > GRUB_FREEDOS_MAX_SIZE)
f96e0b
+    {
f96e0b
+      grub_error (GRUB_ERR_BAD_OS,
f96e0b
+		  N_("file `%s' is too large"), argv[0]);
f96e0b
+      goto fail;
f96e0b
+    }
f96e0b
+
f96e0b
   {
f96e0b
     grub_relocator_chunk_t ch;
f96e0b
-    err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_FREEDOS_SEGMENT << 4,
f96e0b
+    err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_FREEDOS_ADDR,
f96e0b
 					   kernelsyssize);
f96e0b
     if (err)
f96e0b
       goto fail;
f96e0b
diff --git a/include/grub/i386/relocator.h b/include/grub/i386/relocator.h
f96e0b
index 46becb8..5f89a7e 100644
f96e0b
--- a/include/grub/i386/relocator.h
f96e0b
+++ b/include/grub/i386/relocator.h
f96e0b
@@ -49,6 +49,7 @@ struct grub_relocator16_state
f96e0b
   grub_uint32_t ebx;
f96e0b
   grub_uint32_t edx;
f96e0b
   grub_uint32_t esi;
f96e0b
+  grub_uint32_t ebp;
f96e0b
   int a20;
f96e0b
 };
f96e0b
 
f96e0b
-- 
f96e0b
1.8.2.1
f96e0b