Populate multiboot information structure before calling OS.
[people/xl0/gpxe.git] / src / arch / i386 / image / multiboot.c
index cbab6a5..653794c 100644 (file)
 #include <gpxe/uaccess.h>
 #include <gpxe/image.h>
 #include <gpxe/segment.h>
+#include <gpxe/memmap.h>
 #include <gpxe/elf.h>
 
-/** Boot modules must be page aligned */
-#define MB_FLAG_PGALIGN 0x00000001
-
-/** Memory map must be provided */
-#define MB_FLAG_MEMMAP 0x00000002
-
-/** Video mode information must be provided */
-#define MB_FLAG_VIDMODE 0x00000004
-
-/** Image is a raw multiboot image (not ELF) */
-#define MB_FLAG_RAW 0x00010000
-
 /** Multiboot flags that we support */
 #define MB_SUPPORTED_FLAGS ( MB_FLAG_PGALIGN | MB_FLAG_MEMMAP | \
                             MB_FLAG_VIDMODE | MB_FLAG_RAW )
@@ -74,8 +63,54 @@ struct multiboot_header_info {
  * @v image            ELF file
  * @ret rc             Return status code
  */
-static int multiboot_execute ( struct image *image __unused ) {
-       return -ENOTSUP;
+static int multiboot_execute ( struct image *image ) {
+       static const char *bootloader_name = "gPXE " VERSION;
+       struct multiboot_info mbinfo;
+       struct memory_map memmap;
+       struct multiboot_memory_map mbmemmap[ sizeof ( memmap.regions ) /
+                                             sizeof ( memmap.regions[0] ) ];
+       unsigned int i;
+
+       /* Populate multiboot information structure */
+       memset ( &mbinfo, 0, sizeof ( mbinfo ) );
+
+       /* Set boot loader name */
+       mbinfo.flags |= MBI_FLAG_LOADER;
+       mbinfo.boot_loader_name = virt_to_phys ( bootloader_name );
+       
+       /* Get memory map */
+       get_memmap ( &memmap );
+       memset ( mbmemmap, 0, sizeof ( mbmemmap ) );
+       for ( i = 0 ; i < memmap.count ; i++ ) {
+               mbmemmap[i].size = sizeof ( mbmemmap[i] );
+               mbmemmap[i].base_addr = memmap.regions[i].start;
+               mbmemmap[i].length = ( memmap.regions[i].end -
+                                      memmap.regions[i].start );
+               mbmemmap[i].type = MBMEM_RAM;
+               mbinfo.mmap_length += sizeof ( mbmemmap[i] );
+               if ( memmap.regions[i].start == 0 )
+                       mbinfo.mem_lower = memmap.regions[i].end;
+               if ( memmap.regions[i].start == 0x100000 )
+                       mbinfo.mem_upper = ( memmap.regions[i].end - 0x100000);
+       }
+       mbinfo.flags |= ( MBI_FLAG_MEM | MBI_FLAG_MMAP );
+       mbinfo.mmap_addr = virt_to_phys ( &mbmemmap[0].base_addr );
+
+       /* Set command line, if present */
+       if ( image->cmdline ) {
+               mbinfo.flags |= MBI_FLAG_CMDLINE;
+               mbinfo.cmdline = virt_to_phys ( image->cmdline );
+       }
+
+       /* Jump to OS with flat physical addressing */
+       __asm__ __volatile__ ( PHYS_CODE ( "xchgw %%bx,%%bx\n\t"
+                                          "call *%%edi\n\t" )
+                              : : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
+                                  "b" ( virt_to_phys ( &mbinfo ) ),
+                                  "D" ( image->entry )
+                              : "ecx", "edx", "esi", "ebp" );
+
+       return -ECANCELED;
 }
 
 /**