Hi!
OK, I rewrote the patch. Now it uses inline assembly and memory map function name was changed. I also add "ebx" to clobbered registers list because I have recently found that it also can be clobbered (it marked as "Reserverd" in documentation => it can be clobbered).
Is it good now? What do you think?
Ruslan.
ChangeLog:
2005-08-16 Ruslan Nikolaev <[EMAIL PROTECTED]>
* loader/i386/pc/multiboot.c (grub_multiboot_mmap): New function.
(grub_x86_64_cpu): Likewise.
(grub_multiboot_load_elf64): Make sure that we have deal with x86_64 CPU.
(grub_rescue_cmd_multiboot): Added mmap support.
(grub_multiboot_load_elf64): Make sure that we have deal with x86_64 CPU.
(grub_rescue_cmd_multiboot): Added mmap support.
* include/grub/i386/pc/init.h: Function grub_get_mmap_entry is exportable now.
PATCH:
diff -urN old/grub-1.90/include/grub/i386/pc/init.h new/grub-1.90/include/grub/i386/pc/init.h
--- old/grub-1.90/include/grub/i386/pc/init.h 2005-01-31 21:40:25.000000000 +0000
+++ new/grub-1.90/include/grub/i386/pc/init.h 2005-08-16 03:58:23.000000000 +0000
@@ -48,7 +48,7 @@
/* Get a memory map entry. Return next continuation value. Zero means
the end. */
-grub_uint32_t grub_get_mmap_entry (struct grub_machine_mmap_entry *entry,
+grub_uint32_t EXPORT_FUNC (grub_get_mmap_entry) (struct grub_machine_mmap_entry *entry,
grub_uint32_t cont);
/* Turn on/off Gate A20. */
diff -urN old/grub-1.90/loader/i386/pc/multiboot.c new/grub-1.90/loader/i386/pc/multiboot.c
--- old/grub-1.90/loader/i386/pc/multiboot.c 2005-07-31 15:56:54.000000000 +0000
+++ new/grub-1.90/loader/i386/pc/multiboot.c 2005-08-16 04:22:35.939871456 +0000
@@ -25,7 +25,6 @@
* - a.out support
* - boot device
* - symbol table
- * - memory map
* - drives table
* - ROM configuration table
* - APM table
@@ -35,6 +34,7 @@
#include <grub/machine/loader.h>
#include <grub/machine/multiboot.h>
#include <grub/machine/init.h>
+#include <grub/machine/memory.h>
#include <grub/elf.h>
#include <grub/file.h>
#include <grub/err.h>
@@ -81,6 +81,42 @@
return GRUB_ERR_NONE;
}
+/* Detect x86_64 CPU */
+static __inline__ int grub_x86_64_cpu (void)
+{
+ int res;
+
+ __asm__ __volatile__ (
+ "pushf;" /* Save EFLAGS */
+ "pushf;"
+ "popl %%eax;"
+ "xorl $0x200000, %%eax;" /* Change ID(21) bit */
+ "pushl %%eax;"
+ "popf;"
+ "pushf;"
+ "popl %%edx;"
+ "popf;" /* Restore EFLAGS */
+ "xorl %%edx, %%edx;"
+ "jnz 1f;"
+ "movl $0x80000000, %%eax;" /* Any function > 0x80000000? */
+ "cpuid;"
+ "cmpl $0x80000000, %%eax;"
+ "jbe 1f;"
+ "movl $0x80000001, %%eax;" /* Does CPU supports long mode? */
+ "cpuid;"
+ "xorl %%eax, %%eax;"
+ "btl $29, %%edx;"
+ "jc 2f;"
+ "1: movl $0xFFFFFFFF, %%eax;"
+ "2:"
+ : "=a" (res)
+ :
+ : "%ebx", "%ecx", "%edx"
+ );
+
+ return res;
+}
+
/* Check if BUFFER contains ELF32. */
static int
grub_multiboot_is_elf32 (void *buffer)
@@ -172,6 +208,10 @@
|| ehdr->e_machine != EM_X86_64)
return grub_error(GRUB_ERR_UNKNOWN_OS, "no valid ELF header found");
+ /* First we must ensure that we have deal with x86_64 processor */
+ if (grub_x86_64_cpu () < 0)
+ return grub_error (GRUB_ERR_UNKNOWN_OS, "you have a pure x86 system but the kernel requires x86_64 one");
+
if (ehdr->e_type != ET_EXEC)
return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type");
@@ -233,11 +273,77 @@
return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class");
}
+/* Get memory map */
+static grub_err_t
+grub_multiboot_get_memmap(void **mmap_addr, grub_uint32_t *mmap_length)
+{
+ char *addr, *old_addr;
+ grub_size_t buf_size = 4096;
+ grub_uint32_t length = 0;
+ grub_uint32_t cont, entry_size;
+ struct grub_machine_mmap_entry *mmap_entry
+ = (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
+
+ /* Check if grub_get_mmap_entry works. */
+ cont = grub_get_mmap_entry (mmap_entry, 0);
+ if (mmap_entry->size)
+ {
+ /* Allocate buffer for memory map */
+ addr = grub_malloc (4096);
+ if (! addr)
+ return grub_errno;
+
+ do
+ {
+ entry_size = mmap_entry->size + sizeof(mmap_entry->size);
+ /* If buffer is small then reallocate it */
+ if (length + entry_size > buf_size)
+ {
+ buf_size += 4096;
+ old_addr = addr;
+ addr = grub_realloc(old_addr, buf_size);
+ if (! addr)
+ goto mem_out;
+ }
+
+ grub_memcpy (addr + length, mmap_entry, entry_size);
+ length += entry_size;
+
+ if (! cont)
+ break;
+
+ /* Get next entry */
+ cont = grub_get_mmap_entry (mmap_entry, cont);
+ } while (mmap_entry->size);
+
+ /* Truncate buffer to apropriate size */
+ old_addr = addr;
+ addr = grub_realloc (old_addr, length);
+ if (! addr)
+ {
+ mem_out:
+ grub_free(old_addr);
+ return grub_errno;
+ }
+
+ *mmap_addr = addr;
+ *mmap_length = length;
+ }
+ else
+ {
+ *mmap_addr = 0;
+ *mmap_length = 0;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
void
grub_rescue_cmd_multiboot (int argc, char *argv[])
{
grub_file_t file = 0;
char buffer[GRUB_MB_SEARCH], *cmdline = 0, *p;
+ void *mmap_addr = 0;
struct grub_multiboot_header *header;
grub_ssize_t len;
int i;
@@ -297,12 +403,27 @@
if (! mbi)
goto fail;
- mbi->flags = GRUB_MB_INFO_MEMORY;
+ mbi->flags = 0;
+
+ if (header->flags & GRUB_MB_MEMORY_INFO)
+ {
+
+ mbi->flags |= GRUB_MB_INFO_MEMORY;
/* Convert from bytes to kilobytes. */
mbi->mem_lower = grub_lower_mem / 1024;
mbi->mem_upper = grub_upper_mem / 1024;
+ /* Get memory map */
+ if (grub_multiboot_get_memmap (&mmap_addr, &mbi->mmap_length) != GRUB_ERR_NONE)
+ goto fail;
+
+ mbi->mmap_addr = (grub_uint32_t) mmap_addr;
+ if (mmap_addr)
+ mbi->flags |= GRUB_MB_INFO_MEM_MAP;
+
+ }
+
for (i = 0, len = 0; i < argc; i++)
len += grub_strlen (argv[i]) + 1;
@@ -334,6 +455,7 @@
if (grub_errno != GRUB_ERR_NONE)
{
grub_free (cmdline);
+ grub_free (mmap_addr);
grub_free (mbi);
grub_dl_unref (my_mod);
}
--- old/grub-1.90/include/grub/i386/pc/init.h 2005-01-31 21:40:25.000000000 +0000
+++ new/grub-1.90/include/grub/i386/pc/init.h 2005-08-16 03:58:23.000000000 +0000
@@ -48,7 +48,7 @@
/* Get a memory map entry. Return next continuation value. Zero means
the end. */
-grub_uint32_t grub_get_mmap_entry (struct grub_machine_mmap_entry *entry,
+grub_uint32_t EXPORT_FUNC (grub_get_mmap_entry) (struct grub_machine_mmap_entry *entry,
grub_uint32_t cont);
/* Turn on/off Gate A20. */
diff -urN old/grub-1.90/loader/i386/pc/multiboot.c new/grub-1.90/loader/i386/pc/multiboot.c
--- old/grub-1.90/loader/i386/pc/multiboot.c 2005-07-31 15:56:54.000000000 +0000
+++ new/grub-1.90/loader/i386/pc/multiboot.c 2005-08-16 04:22:35.939871456 +0000
@@ -25,7 +25,6 @@
* - a.out support
* - boot device
* - symbol table
- * - memory map
* - drives table
* - ROM configuration table
* - APM table
@@ -35,6 +34,7 @@
#include <grub/machine/loader.h>
#include <grub/machine/multiboot.h>
#include <grub/machine/init.h>
+#include <grub/machine/memory.h>
#include <grub/elf.h>
#include <grub/file.h>
#include <grub/err.h>
@@ -81,6 +81,42 @@
return GRUB_ERR_NONE;
}
+/* Detect x86_64 CPU */
+static __inline__ int grub_x86_64_cpu (void)
+{
+ int res;
+
+ __asm__ __volatile__ (
+ "pushf;" /* Save EFLAGS */
+ "pushf;"
+ "popl %%eax;"
+ "xorl $0x200000, %%eax;" /* Change ID(21) bit */
+ "pushl %%eax;"
+ "popf;"
+ "pushf;"
+ "popl %%edx;"
+ "popf;" /* Restore EFLAGS */
+ "xorl %%edx, %%edx;"
+ "jnz 1f;"
+ "movl $0x80000000, %%eax;" /* Any function > 0x80000000? */
+ "cpuid;"
+ "cmpl $0x80000000, %%eax;"
+ "jbe 1f;"
+ "movl $0x80000001, %%eax;" /* Does CPU supports long mode? */
+ "cpuid;"
+ "xorl %%eax, %%eax;"
+ "btl $29, %%edx;"
+ "jc 2f;"
+ "1: movl $0xFFFFFFFF, %%eax;"
+ "2:"
+ : "=a" (res)
+ :
+ : "%ebx", "%ecx", "%edx"
+ );
+
+ return res;
+}
+
/* Check if BUFFER contains ELF32. */
static int
grub_multiboot_is_elf32 (void *buffer)
@@ -172,6 +208,10 @@
|| ehdr->e_machine != EM_X86_64)
return grub_error(GRUB_ERR_UNKNOWN_OS, "no valid ELF header found");
+ /* First we must ensure that we have deal with x86_64 processor */
+ if (grub_x86_64_cpu () < 0)
+ return grub_error (GRUB_ERR_UNKNOWN_OS, "you have a pure x86 system but the kernel requires x86_64 one");
+
if (ehdr->e_type != ET_EXEC)
return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type");
@@ -233,11 +273,77 @@
return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class");
}
+/* Get memory map */
+static grub_err_t
+grub_multiboot_get_memmap(void **mmap_addr, grub_uint32_t *mmap_length)
+{
+ char *addr, *old_addr;
+ grub_size_t buf_size = 4096;
+ grub_uint32_t length = 0;
+ grub_uint32_t cont, entry_size;
+ struct grub_machine_mmap_entry *mmap_entry
+ = (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
+
+ /* Check if grub_get_mmap_entry works. */
+ cont = grub_get_mmap_entry (mmap_entry, 0);
+ if (mmap_entry->size)
+ {
+ /* Allocate buffer for memory map */
+ addr = grub_malloc (4096);
+ if (! addr)
+ return grub_errno;
+
+ do
+ {
+ entry_size = mmap_entry->size + sizeof(mmap_entry->size);
+ /* If buffer is small then reallocate it */
+ if (length + entry_size > buf_size)
+ {
+ buf_size += 4096;
+ old_addr = addr;
+ addr = grub_realloc(old_addr, buf_size);
+ if (! addr)
+ goto mem_out;
+ }
+
+ grub_memcpy (addr + length, mmap_entry, entry_size);
+ length += entry_size;
+
+ if (! cont)
+ break;
+
+ /* Get next entry */
+ cont = grub_get_mmap_entry (mmap_entry, cont);
+ } while (mmap_entry->size);
+
+ /* Truncate buffer to apropriate size */
+ old_addr = addr;
+ addr = grub_realloc (old_addr, length);
+ if (! addr)
+ {
+ mem_out:
+ grub_free(old_addr);
+ return grub_errno;
+ }
+
+ *mmap_addr = addr;
+ *mmap_length = length;
+ }
+ else
+ {
+ *mmap_addr = 0;
+ *mmap_length = 0;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
void
grub_rescue_cmd_multiboot (int argc, char *argv[])
{
grub_file_t file = 0;
char buffer[GRUB_MB_SEARCH], *cmdline = 0, *p;
+ void *mmap_addr = 0;
struct grub_multiboot_header *header;
grub_ssize_t len;
int i;
@@ -297,12 +403,27 @@
if (! mbi)
goto fail;
- mbi->flags = GRUB_MB_INFO_MEMORY;
+ mbi->flags = 0;
+
+ if (header->flags & GRUB_MB_MEMORY_INFO)
+ {
+
+ mbi->flags |= GRUB_MB_INFO_MEMORY;
/* Convert from bytes to kilobytes. */
mbi->mem_lower = grub_lower_mem / 1024;
mbi->mem_upper = grub_upper_mem / 1024;
+ /* Get memory map */
+ if (grub_multiboot_get_memmap (&mmap_addr, &mbi->mmap_length) != GRUB_ERR_NONE)
+ goto fail;
+
+ mbi->mmap_addr = (grub_uint32_t) mmap_addr;
+ if (mmap_addr)
+ mbi->flags |= GRUB_MB_INFO_MEM_MAP;
+
+ }
+
for (i = 0, len = 0; i < argc; i++)
len += grub_strlen (argv[i]) + 1;
@@ -334,6 +455,7 @@
if (grub_errno != GRUB_ERR_NONE)
{
grub_free (cmdline);
+ grub_free (mmap_addr);
grub_free (mbi);
grub_dl_unref (my_mod);
}
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel