#include <grub/efi/disk.h>
#include <grub/command.h>
#include <grub/i18n.h>
+#include <grub/net.h>
+#if defined (__i386__) || defined (__x86_64__)
+#include <grub/macho.h>
+#include <grub/i386/macho.h>
+#endif
+
+GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
grub_free (file_path);
grub_free (cmdline);
cmdline = 0;
+ file_path = 0;
grub_dl_unref (my_mod);
return GRUB_ERR_NONE;
grub_efi_boot_services_t *b;
grub_efi_status_t status;
grub_efi_uintn_t exit_data_size;
- grub_efi_char16_t *exit_data;
+ grub_efi_char16_t *exit_data = NULL;
b = grub_efi_system_table->boot_services;
status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
grub_error (GRUB_ERR_BAD_OS, buf);
grub_free (buf);
}
- else
- grub_error (GRUB_ERR_BAD_OS, "unknown error");
}
+ else
+ grub_error (GRUB_ERR_BAD_OS, "unknown error");
}
if (exit_data)
efi_call_1 (b->free_pool, exit_data);
- grub_chainloader_unload ();
+ grub_loader_unset ();
return grub_errno;
}
fp->header.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE;
fp->header.subtype = GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE;
- size = len * sizeof (grub_efi_char16_t) + sizeof (*fp);
+
+ size = grub_utf8_to_utf16 (fp->path_name, len * GRUB_MAX_UTF16_PER_UTF8,
+ (const grub_uint8_t *) str, len, 0);
+ for (p = fp->path_name; p < fp->path_name + size; p++)
+ if (*p == '/')
+ *p = '\\';
+
+ size = size * sizeof (grub_efi_char16_t) + sizeof (*fp);
fp->header.length[0] = (grub_efi_uint8_t) (size & 0xff);
fp->header.length[1] = (grub_efi_uint8_t) (size >> 8);
- for (p = fp->path_name; len > 0; len--, p++, str++)
- {
- /* FIXME: this assumes that the path is in ASCII. */
- *p = (grub_efi_char16_t) (*str == '/' ? '\\' : *str);
- }
}
static grub_efi_device_path_t *
file_path = grub_malloc (size
+ ((grub_strlen (dir_start) + 1)
+ * GRUB_MAX_UTF16_PER_UTF8
* sizeof (grub_efi_char16_t))
+ sizeof (grub_efi_file_path_device_path_t) * 2);
if (! file_path)
grub_ssize_t size;
grub_efi_status_t status;
grub_efi_boot_services_t *b;
- grub_efi_handle_t dev_handle = 0;
grub_device_t dev = 0;
grub_efi_device_path_t *dp = 0;
grub_efi_loaded_image_t *loaded_image;
char *filename;
+ void *boot_image = 0;
+ grub_efi_handle_t dev_handle = 0;
if (argc == 0)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
filename = argv[0];
grub_dl_ref (my_mod);
goto fail;
if (dev->disk)
+ dev_handle = grub_efidisk_get_device_handle (dev->disk);
+ else if (dev->net && dev->net->server)
{
- dev_handle = grub_efidisk_get_device_handle (dev->disk);
- if (dev_handle)
- dp = grub_efi_get_device_path (dev_handle);
+ grub_net_network_level_address_t addr;
+ struct grub_net_network_level_interface *inf;
+ grub_net_network_level_address_t gateway;
+ grub_err_t err;
+
+ err = grub_net_resolve_address (dev->net->server, &addr);
+ if (err)
+ goto fail;
+
+ err = grub_net_route_address (addr, &gateway, &inf);
+ if (err)
+ goto fail;
+
+ dev_handle = grub_efinet_get_device_handle (inf->card);
}
- if (! dev->disk || ! dev_handle || ! dp)
+ if (dev_handle)
+ dp = grub_efi_get_device_path (dev_handle);
+
+ if (! dp)
{
grub_error (GRUB_ERR_BAD_DEVICE, "not a valid root device");
goto fail;
grub_efi_print_device_path (file_path);
size = grub_file_size (file);
+ if (!size)
+ {
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ filename);
+ goto fail;
+ }
pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12);
status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES,
pages, &address);
if (status != GRUB_EFI_SUCCESS)
{
- grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate %u pages", pages);
+ grub_dprintf ("chain", "Failed to allocate %u pages\n",
+ (unsigned int) pages);
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
goto fail;
}
- if (grub_file_read (file, (void *) ((grub_addr_t) address), size) != size)
+ boot_image = (void *) ((grub_addr_t) address);
+ if (grub_file_read (file, boot_image, size) != size)
{
if (grub_errno == GRUB_ERR_NONE)
- grub_error (GRUB_ERR_BAD_OS, "too small");
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ filename);
goto fail;
}
+#if defined (__i386__) || defined (__x86_64__)
+ if (size >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
+ {
+ struct grub_macho_fat_header *head = boot_image;
+ if (head->magic
+ == grub_cpu_to_le32_compile_time (GRUB_MACHO_FAT_EFI_MAGIC))
+ {
+ grub_uint32_t i;
+ struct grub_macho_fat_arch *archs
+ = (struct grub_macho_fat_arch *) (head + 1);
+ for (i = 0; i < grub_cpu_to_le32 (head->nfat_arch); i++)
+ {
+ if (GRUB_MACHO_CPUTYPE_IS_HOST_CURRENT (archs[i].cputype))
+ break;
+ }
+ if (i == grub_cpu_to_le32 (head->nfat_arch))
+ {
+ grub_error (GRUB_ERR_BAD_OS, "no compatible arch found");
+ goto fail;
+ }
+ if (grub_cpu_to_le32 (archs[i].offset)
+ > ~grub_cpu_to_le32 (archs[i].size)
+ || grub_cpu_to_le32 (archs[i].offset)
+ + grub_cpu_to_le32 (archs[i].size)
+ > (grub_size_t) size)
+ {
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ filename);
+ goto fail;
+ }
+ boot_image = (char *) boot_image + grub_cpu_to_le32 (archs[i].offset);
+ size = grub_cpu_to_le32 (archs[i].size);
+ }
+ }
+#endif
+
status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
- (void *) ((grub_addr_t) address), size,
- &image_handle);
+ boot_image, size,
+ &image_handle);
if (status != GRUB_EFI_SUCCESS)
{
if (status == GRUB_EFI_OUT_OF_RESOURCES)
if (file)
grub_file_close (file);
- if (file_path)
- grub_free (file_path);
+ grub_free (file_path);
if (address)
efi_call_2 (b->free_pages, address, pages);