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.
This commit is contained in:
C. Masloch 2013-01-27 16:07:25 +01:00 committed by Vladimir 'phcoder' Serbinenko
parent 7782b8a62f
commit 08bcec5020
5 changed files with 82 additions and 8 deletions

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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;
ebx = grub_get_root_biosnumber ();
kernelsyssize = grub_file_size (file);
{
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_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_ADDR,
kernelsyssize);
if (err)
goto fail;

View file

@ -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;
};