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