#include <grub/command.h>
#include <grub/i18n.h>
#include <grub/bitmap_scale.h>
+#include <grub/cpu/io.h>
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
/* Fill device tree. */
/* FIXME: some entries may be platform-agnostic. Move them to loader/xnu.c. */
-grub_err_t
-grub_cpu_xnu_fill_devicetree (void)
+static grub_err_t
+grub_cpu_xnu_fill_devicetree (grub_uint64_t *fsbfreq_out)
{
struct grub_xnu_devtree_key *efikey;
struct grub_xnu_devtree_key *cfgtablekey;
/* First see if user supplies the value. */
const char *fsbvar = grub_env_get ("fsb");
- if (! fsbvar)
- *((grub_uint64_t *) curval->data) = 0;
- else
- *((grub_uint64_t *) curval->data) = readfrequency (fsbvar);
+ grub_uint64_t fsbfreq = 0;
+ if (fsbvar)
+ fsbfreq = readfrequency (fsbvar);
/* Try autodetect. */
- if (! *((grub_uint64_t *) curval->data))
- *((grub_uint64_t *) curval->data) = guessfsb ();
+ if (! fsbfreq)
+ fsbfreq = guessfsb ();
+ *((grub_uint64_t *) curval->data) = fsbfreq;
+ *fsbfreq_out = fsbfreq;
grub_dprintf ("xnu", "fsb autodetected as %llu\n",
(unsigned long long) *((grub_uint64_t *) curval->data));
/* Setup video for xnu. */
static grub_err_t
-grub_xnu_set_video (struct grub_xnu_boot_params *params)
+grub_xnu_set_video (struct grub_xnu_boot_params_common *params)
{
struct grub_video_mode_info mode_info;
char *tmp;
grub_err_t
grub_xnu_boot (void)
{
- struct grub_xnu_boot_params *bootparams;
+ union grub_xnu_boot_params_any *bootparams;
+ struct grub_xnu_boot_params_common *bootparams_common;
void *bp_in;
grub_addr_t bootparams_target;
grub_err_t err;
grub_size_t devtreelen;
int i;
struct grub_relocator32_state state;
+ grub_uint64_t fsbfreq;
+ int v2 = (grub_xnu_darwin_version >= 11);
+ grub_uint32_t efi_system_table = 0;
err = grub_autoefi_prepare ();
if (err)
if (err)
return err;
- err = grub_cpu_xnu_fill_devicetree ();
+ err = grub_cpu_xnu_fill_devicetree (&fsbfreq);
if (err)
return err;
descriptor_size = 0;
descriptor_version = 0;
- grub_dprintf ("xnu", "eip=%x\n", grub_xnu_entry_point);
+ grub_dprintf ("xnu", "eip=%x, efi=%x\n", grub_xnu_entry_point,
+ (int) grub_autoefi_system_table);
const char *debug = grub_env_get ("debug");
return err;
bootparams = bp_in;
+ grub_memset (bootparams, 0, sizeof (*bootparams));
+ if (v2)
+ {
+ bootparams_common = &bootparams->v2.common;
+ bootparams->v2.fsbfreq = fsbfreq;
+ }
+ else
+ bootparams_common = &bootparams->v1.common;
+
/* Set video. */
- err = grub_xnu_set_video (bootparams);
+ err = grub_xnu_set_video (bootparams_common);
if (err != GRUB_ERR_NONE)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
grub_puts_ (N_("Booting in blind mode"));
- bootparams->lfb_mode = 0;
- bootparams->lfb_width = 0;
- bootparams->lfb_height = 0;
- bootparams->lfb_depth = 0;
- bootparams->lfb_line_len = 0;
- bootparams->lfb_base = 0;
+ bootparams_common->lfb_mode = 0;
+ bootparams_common->lfb_width = 0;
+ bootparams_common->lfb_height = 0;
+ bootparams_common->lfb_depth = 0;
+ bootparams_common->lfb_line_len = 0;
+ bootparams_common->lfb_base = 0;
}
if (grub_autoefi_get_memory_map (&memory_map_size, memory_map,
if (err)
return err;
- grub_memcpy (bootparams->cmdline, grub_xnu_cmdline,
- sizeof (bootparams->cmdline));
+ grub_memcpy (bootparams_common->cmdline, grub_xnu_cmdline,
+ sizeof (bootparams_common->cmdline));
- bootparams->devtree = devtree_target;
- bootparams->devtreelen = devtreelen;
+ bootparams_common->devtree = devtree_target;
+ bootparams_common->devtreelen = devtreelen;
err = grub_autoefi_finish_boot_services (&memory_map_size, memory_map,
&map_key, &descriptor_size,
if (err)
return err;
- bootparams->efi_system_table = (grub_addr_t) grub_autoefi_system_table;
+ if (v2)
+ bootparams->v2.efi_system_table = (grub_addr_t) grub_autoefi_system_table;
+ else
+ bootparams->v1.efi_system_table = (grub_addr_t) grub_autoefi_system_table;
firstruntimepage = (((grub_addr_t) grub_xnu_heap_target_start
+ grub_xnu_heap_size + GRUB_XNU_PAGESIZE - 1)
<= (grub_addr_t) grub_autoefi_system_table
&& curdesc->physical_start + (curdesc->num_pages << 12)
> (grub_addr_t) grub_autoefi_system_table)
- bootparams->efi_system_table
+ efi_system_table
= (grub_addr_t) grub_autoefi_system_table
- curdesc->physical_start + curdesc->virtual_start;
if (SIZEOF_OF_UINTN == 8 && grub_xnu_is_64bit)
lastruntimepage = curruntimepage;
- bootparams->efi_mmap = memory_map_target;
- bootparams->efi_mmap_size = memory_map_size;
- bootparams->efi_mem_desc_size = descriptor_size;
- bootparams->efi_mem_desc_version = descriptor_version;
-
- bootparams->heap_start = grub_xnu_heap_target_start;
- bootparams->heap_size = grub_xnu_heap_size;
- bootparams->efi_runtime_first_page = firstruntimepage;
-
- bootparams->efi_runtime_npages = lastruntimepage - firstruntimepage;
- bootparams->efi_uintnbits = SIZEOF_OF_UINTN * 8;
+ if (v2)
+ {
+ bootparams->v2.efi_uintnbits = SIZEOF_OF_UINTN * 8;
+ bootparams->v2.verminor = GRUB_XNU_BOOTARGSV2_VERMINOR;
+ bootparams->v2.vermajor = GRUB_XNU_BOOTARGSV2_VERMAJOR;
+ bootparams->v2.efi_system_table = efi_system_table;
+ }
+ else
+ {
+ bootparams->v1.efi_uintnbits = SIZEOF_OF_UINTN * 8;
+ bootparams->v1.verminor = GRUB_XNU_BOOTARGSV1_VERMINOR;
+ bootparams->v1.vermajor = GRUB_XNU_BOOTARGSV1_VERMAJOR;
+ bootparams->v1.efi_system_table = efi_system_table;
+ }
- bootparams->verminor = GRUB_XNU_BOOTARGS_VERMINOR;
- bootparams->vermajor = GRUB_XNU_BOOTARGS_VERMAJOR;
+ bootparams_common->efi_runtime_first_page = firstruntimepage;
+ bootparams_common->efi_runtime_npages = lastruntimepage - firstruntimepage;
+ bootparams_common->efi_mem_desc_size = descriptor_size;
+ bootparams_common->efi_mem_desc_version = descriptor_version;
+ bootparams_common->efi_mmap = memory_map_target;
+ bootparams_common->efi_mmap_size = memory_map_size;
+ bootparams_common->heap_start = grub_xnu_heap_target_start;
+ bootparams_common->heap_size = grub_xnu_heap_size;
/* Parameters for asm helper. */
- grub_xnu_stack = bootparams->heap_start
- + bootparams->heap_size + GRUB_XNU_PAGESIZE;
+ grub_xnu_stack = bootparams_common->heap_start
+ + bootparams_common->heap_size + GRUB_XNU_PAGESIZE;
grub_xnu_arg1 = bootparams_target;
grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size,
state.eax = grub_xnu_arg1;
state.esp = grub_xnu_stack;
state.ebp = grub_xnu_stack;
+
+ /* XNU uses only APIC. Disable PIC. */
+ grub_outb (0xff, 0x21);
+ grub_outb (0xff, 0xa1);
+
return grub_relocator32_boot (grub_xnu_relocator, state);
}
#define GRUB_XNU_PAGESIZE 4096
typedef grub_uint32_t grub_xnu_ptr_t;
-struct grub_xnu_boot_params
+struct grub_xnu_boot_params_common
{
- grub_uint16_t verminor;
- grub_uint16_t vermajor;
/* Command line passed to xnu. */
grub_uint8_t cmdline[1024];
grub_xnu_ptr_t heap_start;
/* Last used address by kernel or boot structures minus previous value. */
grub_uint32_t heap_size;
-
/* First memory page containing runtime code or data. */
grub_uint32_t efi_runtime_first_page;
/* First memory page containing runtime code or data minus previous value. */
grub_uint32_t efi_runtime_npages;
+} __attribute__ ((packed));
+
+struct grub_xnu_boot_params_v1
+{
+ grub_uint16_t verminor;
+ grub_uint16_t vermajor;
+ struct grub_xnu_boot_params_common common;
+
grub_uint32_t efi_system_table;
/* Size of grub_efi_uintn_t in bits. */
grub_uint8_t efi_uintnbits;
} __attribute__ ((packed));
-#define GRUB_XNU_BOOTARGS_VERMINOR 5
-#define GRUB_XNU_BOOTARGS_VERMAJOR 1
+#define GRUB_XNU_BOOTARGSV1_VERMINOR 5
+#define GRUB_XNU_BOOTARGSV1_VERMAJOR 1
+
+struct grub_xnu_boot_params_v2
+{
+ grub_uint16_t verminor;
+ grub_uint16_t vermajor;
+
+ /* Size of grub_efi_uintn_t in bits. */
+ grub_uint8_t efi_uintnbits;
+ grub_uint8_t unused[3];
+
+ struct grub_xnu_boot_params_common common;
+
+ grub_uint64_t efi_runtime_first_page_virtual;
+ grub_uint32_t efi_system_table;
+ grub_uint32_t unused2[11];
+ grub_uint64_t fsbfreq;
+ grub_uint32_t unused3[734];
+} __attribute__ ((packed));
+#define GRUB_XNU_BOOTARGSV2_VERMINOR 0
+#define GRUB_XNU_BOOTARGSV2_VERMAJOR 2
+
+union grub_xnu_boot_params_any
+{
+ struct grub_xnu_boot_params_v1 v1;
+ struct grub_xnu_boot_params_v2 v2;
+};
struct grub_xnu_devprop_header
{
extern grub_uint32_t grub_xnu_arg1;
extern char grub_xnu_cmdline[1024];
grub_err_t grub_xnu_boot (void);
-grub_err_t grub_cpu_xnu_fill_devicetree (void);
#endif