2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2009 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/file.h>
21 #include <grub/disk.h>
23 #include <grub/cpu/xnu.h>
25 #include <grub/loader.h>
26 #include <grub/autoefi.h>
27 #include <grub/i386/tsc.h>
28 #include <grub/i386/cpuid.h>
29 #include <grub/efi/api.h>
30 #include <grub/i386/pit.h>
31 #include <grub/misc.h>
32 #include <grub/charset.h>
33 #include <grub/term.h>
34 #include <grub/command.h>
35 #include <grub/i18n.h>
36 #include <grub/bitmap_scale.h>
37 #include <grub/cpu/io.h>
39 #define min(a,b) (((a) < (b)) ? (a) : (b))
40 #define max(a,b) (((a) > (b)) ? (a) : (b))
42 #define DEFAULT_VIDEO_MODE "auto"
44 char grub_xnu_cmdline
[1024];
45 grub_uint32_t grub_xnu_entry_point
, grub_xnu_arg1
, grub_xnu_stack
;
47 /* Aliases set for some tables. */
54 static struct tbl_alias table_aliases
[] =
56 {GRUB_EFI_ACPI_20_TABLE_GUID
, "ACPI_20"},
57 {GRUB_EFI_ACPI_TABLE_GUID
, "ACPI"},
60 struct grub_xnu_devprop_device_descriptor
62 struct grub_xnu_devprop_device_descriptor
*next
;
63 struct grub_xnu_devprop_device_descriptor
**prev
;
64 struct property_descriptor
*properties
;
65 struct grub_efi_device_path
*path
;
70 utf16_strlen (grub_uint16_t
*in
)
73 for (i
= 0; in
[i
]; i
++);
77 /* Read frequency from a string in MHz and return it in Hz. */
79 readfrequency (const char *str
)
81 grub_uint64_t num
= 0;
89 digit
= grub_tolower (*str
) - '0';
95 num
= num
* 10 + digit
;
106 digit
= grub_tolower (*str
) - '0';
113 num
= num
+ mul
* digit
;
123 /* Thanks to Kabyl for precious information about Intel architecture. */
127 const grub_uint64_t sane_value
= 100000000;
128 grub_uint32_t manufacturer
[3], max_cpuid
, capabilities
, msrlow
;
129 grub_uint32_t a
, b
, d
, divisor
;
131 if (! grub_cpu_is_cpuid_supported ())
134 grub_cpuid (0, max_cpuid
, manufacturer
[0], manufacturer
[2], manufacturer
[1]);
136 /* Only Intel for now is done. */
137 if (grub_memcmp (manufacturer
, "GenuineIntel", 12) != 0)
140 /* Check Speedstep. */
144 grub_cpuid (1, a
, b
, capabilities
, d
);
146 if (! (capabilities
& (1 << 7)))
149 /* Read the multiplier. */
150 asm volatile ("movl $0x198, %%ecx\n"
159 /* (2000ULL << 32) / grub_tsc_rate */
160 /* Assumption: TSC frequency is over 2 MHz. */
161 v
= 0xffffffff / grub_tsc_rate
;
163 /* v is at most 2000 off from (2000ULL << 32) / grub_tsc_rate.
164 Since grub_tsc_rate < 2^32/2^11=2^21, so no overflow.
166 r
= (2000ULL << 32) - v
* grub_tsc_rate
;
167 v
+= r
/ grub_tsc_rate
;
169 divisor
= ((msrlow
>> 7) & 0x3e) | ((msrlow
>> 14) & 1);
172 return grub_divmod64 (v
, divisor
, 0);
175 struct property_descriptor
177 struct property_descriptor
*next
;
178 struct property_descriptor
**prev
;
180 grub_uint16_t
*name16
;
186 static struct grub_xnu_devprop_device_descriptor
*devices
= 0;
189 grub_xnu_devprop_remove_property (struct grub_xnu_devprop_device_descriptor
*dev
,
192 struct property_descriptor
*prop
;
193 prop
= grub_named_list_find (GRUB_AS_NAMED_LIST (dev
->properties
), name
);
195 return GRUB_ERR_NONE
;
197 grub_free (prop
->name
);
198 grub_free (prop
->name16
);
199 grub_free (prop
->data
);
201 grub_list_remove (GRUB_AS_LIST (prop
));
203 return GRUB_ERR_NONE
;
207 grub_xnu_devprop_remove_device (struct grub_xnu_devprop_device_descriptor
*dev
)
210 struct property_descriptor
*prop
;
212 grub_list_remove (GRUB_AS_LIST (dev
));
214 for (prop
= dev
->properties
; prop
; )
216 grub_free (prop
->name
);
217 grub_free (prop
->name16
);
218 grub_free (prop
->data
);
224 grub_free (dev
->path
);
227 return GRUB_ERR_NONE
;
230 struct grub_xnu_devprop_device_descriptor
*
231 grub_xnu_devprop_add_device (struct grub_efi_device_path
*path
, int length
)
233 struct grub_xnu_devprop_device_descriptor
*ret
;
235 ret
= grub_zalloc (sizeof (*ret
));
239 ret
->path
= grub_malloc (length
);
245 ret
->pathlen
= length
;
246 grub_memcpy (ret
->path
, path
, length
);
248 grub_list_push (GRUB_AS_LIST_P (&devices
), GRUB_AS_LIST (ret
));
254 grub_xnu_devprop_add_property (struct grub_xnu_devprop_device_descriptor
*dev
,
255 grub_uint8_t
*utf8
, grub_uint16_t
*utf16
,
256 int utf16len
, void *data
, int datalen
)
258 struct property_descriptor
*prop
;
260 prop
= grub_malloc (sizeof (*prop
));
265 prop
->name16
= utf16
;
266 prop
->name16len
= utf16len
;
268 prop
->length
= datalen
;
269 prop
->data
= grub_malloc (prop
->length
);
273 grub_free (prop
->name
);
274 grub_free (prop
->name16
);
277 grub_memcpy (prop
->data
, data
, prop
->length
);
278 grub_list_push (GRUB_AS_LIST_P (&dev
->properties
),
279 GRUB_AS_LIST (prop
));
280 return GRUB_ERR_NONE
;
284 grub_xnu_devprop_add_property_utf8 (struct grub_xnu_devprop_device_descriptor
*dev
,
285 char *name
, void *data
, int datalen
)
288 grub_uint16_t
*utf16
;
292 utf8
= (grub_uint8_t
*) grub_strdup (name
);
296 len
= grub_strlen (name
);
297 utf16
= grub_malloc (sizeof (grub_uint16_t
) * len
);
304 utf16len
= grub_utf8_to_utf16 (utf16
, len
, utf8
, len
, NULL
);
312 err
= grub_xnu_devprop_add_property (dev
, utf8
, utf16
,
313 utf16len
, data
, datalen
);
321 return GRUB_ERR_NONE
;
325 grub_xnu_devprop_add_property_utf16 (struct grub_xnu_devprop_device_descriptor
*dev
,
326 grub_uint16_t
*name
, int namelen
,
327 void *data
, int datalen
)
330 grub_uint16_t
*utf16
;
333 utf16
= grub_malloc (sizeof (grub_uint16_t
) * namelen
);
336 grub_memcpy (utf16
, name
, sizeof (grub_uint16_t
) * namelen
);
338 utf8
= grub_malloc (namelen
* 4 + 1);
345 *grub_utf16_to_utf8 ((grub_uint8_t
*) utf8
, name
, namelen
) = '\0';
347 err
= grub_xnu_devprop_add_property (dev
, utf8
, utf16
,
348 namelen
, data
, datalen
);
356 return GRUB_ERR_NONE
;
360 grub_cpu_xnu_unload (void)
362 struct grub_xnu_devprop_device_descriptor
*dev1
, *dev2
;
364 for (dev1
= devices
; dev1
; )
367 grub_xnu_devprop_remove_device (dev1
);
373 grub_cpu_xnu_fill_devprop (void)
375 struct grub_xnu_devtree_key
*efikey
;
376 int total_length
= sizeof (struct grub_xnu_devprop_header
);
377 struct grub_xnu_devtree_key
*devprop
;
378 struct grub_xnu_devprop_device_descriptor
*device
;
380 struct grub_xnu_devprop_header
*head
;
385 efikey
= grub_xnu_create_key (&grub_xnu_devtree_root
, "efi");
389 for (device
= devices
; device
; device
= device
->next
)
391 struct property_descriptor
*propdesc
;
392 total_length
+= sizeof (struct grub_xnu_devprop_device_header
);
393 total_length
+= device
->pathlen
;
395 for (propdesc
= device
->properties
; propdesc
; propdesc
= propdesc
->next
)
397 total_length
+= sizeof (grub_uint32_t
);
398 total_length
+= sizeof (grub_uint16_t
)
399 * (propdesc
->name16len
+ 1);
400 total_length
+= sizeof (grub_uint32_t
);
401 total_length
+= propdesc
->length
;
406 devprop
= grub_xnu_create_value (&(efikey
->first_child
), "device-properties");
410 devprop
->data
= grub_malloc (total_length
);
411 devprop
->datasize
= total_length
;
416 head
->length
= total_length
;
418 head
->num_devices
= numdevs
;
419 for (device
= devices
; device
; )
421 struct grub_xnu_devprop_device_header
*devhead
;
422 struct property_descriptor
*propdesc
;
424 devhead
->num_values
= 0;
427 grub_memcpy (ptr
, device
->path
, device
->pathlen
);
428 ptr
= (char *) ptr
+ device
->pathlen
;
430 for (propdesc
= device
->properties
; propdesc
; )
437 *len
= 2 * propdesc
->name16len
+ sizeof (grub_uint16_t
)
438 + sizeof (grub_uint32_t
);
442 grub_memcpy (name
, propdesc
->name16
, 2 * propdesc
->name16len
);
443 name
+= propdesc
->name16len
;
445 /* NUL terminator. */
450 *len
= propdesc
->length
+ sizeof (grub_uint32_t
);
453 grub_memcpy (ptr
, propdesc
->data
, propdesc
->length
);
454 ptr
= (char *) ptr
+ propdesc
->length
;
456 grub_free (propdesc
->name
);
457 grub_free (propdesc
->name16
);
458 grub_free (propdesc
->data
);
460 propdesc
= propdesc
->next
;
462 devhead
->num_values
++;
465 devhead
->length
= (char *) ptr
- (char *) devhead
;
467 device
= device
->next
;
473 return GRUB_ERR_NONE
;
477 grub_cmd_devprop_load (grub_command_t cmd
__attribute__ ((unused
)),
478 int argc
, char *args
[])
481 void *buf
, *bufstart
, *bufend
;
482 struct grub_xnu_devprop_header
*head
;
487 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
489 file
= grub_file_open (args
[0]);
492 size
= grub_file_size (file
);
493 buf
= grub_malloc (size
);
496 grub_file_close (file
);
499 if (grub_file_read (file
, buf
, size
) != (grub_ssize_t
) size
)
501 grub_file_close (file
);
504 grub_file_close (file
);
507 bufend
= (char *) buf
+ size
;
510 for (i
= 0; i
< grub_le_to_cpu32 (head
->num_devices
) && buf
< bufend
; i
++)
512 struct grub_efi_device_path
*dp
, *dpstart
;
513 struct grub_xnu_devprop_device_descriptor
*dev
;
514 struct grub_xnu_devprop_device_header
*devhead
;
523 buf
= (char *) buf
+ GRUB_EFI_DEVICE_PATH_LENGTH (dp
);
525 while (!GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp
) && buf
< bufend
);
527 dev
= grub_xnu_devprop_add_device (dpstart
, (char *) buf
530 for (j
= 0; j
< grub_le_to_cpu32 (devhead
->num_values
) && buf
< bufend
;
533 grub_uint32_t
*namelen
;
534 grub_uint32_t
*datalen
;
535 grub_uint16_t
*utf16
;
545 buf
= (char *) buf
+ *namelen
- sizeof (grub_uint32_t
);
555 buf
= (char *) buf
+ *datalen
- sizeof (grub_uint32_t
);
558 err
= grub_xnu_devprop_add_property_utf16
559 (dev
, utf16
, (*namelen
- sizeof (grub_uint32_t
)
560 - sizeof (grub_uint16_t
)) / sizeof (grub_uint16_t
),
561 data
, *datalen
- sizeof (grub_uint32_t
));
564 grub_free (bufstart
);
570 grub_free (bufstart
);
571 return GRUB_ERR_NONE
;
574 /* Fill device tree. */
575 /* FIXME: some entries may be platform-agnostic. Move them to loader/xnu.c. */
577 grub_cpu_xnu_fill_devicetree (grub_uint64_t
*fsbfreq_out
)
579 struct grub_xnu_devtree_key
*efikey
;
580 struct grub_xnu_devtree_key
*cfgtablekey
;
581 struct grub_xnu_devtree_key
*curval
;
582 struct grub_xnu_devtree_key
*runtimesrvkey
;
583 struct grub_xnu_devtree_key
*platformkey
;
586 /* The value "model". */
587 /* FIXME: may this value be sometimes different? */
588 curval
= grub_xnu_create_value (&grub_xnu_devtree_root
, "model");
591 curval
->datasize
= sizeof ("ACPI");
592 curval
->data
= grub_strdup ("ACPI");
593 curval
= grub_xnu_create_value (&grub_xnu_devtree_root
, "compatible");
596 curval
->datasize
= sizeof ("ACPI");
597 curval
->data
= grub_strdup ("ACPI");
600 efikey
= grub_xnu_create_key (&grub_xnu_devtree_root
, "efi");
604 /* Information about firmware. */
605 curval
= grub_xnu_create_value (&(efikey
->first_child
), "firmware-revision");
608 curval
->datasize
= (SYSTEM_TABLE_SIZEOF (firmware_revision
));
609 curval
->data
= grub_malloc (curval
->datasize
);
612 grub_memcpy (curval
->data
, (SYSTEM_TABLE_VAR(firmware_revision
)),
615 curval
= grub_xnu_create_value (&(efikey
->first_child
), "firmware-vendor");
619 2 * (utf16_strlen (SYSTEM_TABLE_PTR (firmware_vendor
)) + 1);
620 curval
->data
= grub_malloc (curval
->datasize
);
623 grub_memcpy (curval
->data
, SYSTEM_TABLE_PTR (firmware_vendor
),
626 curval
= grub_xnu_create_value (&(efikey
->first_child
), "firmware-abi");
629 curval
->datasize
= sizeof ("EFI32");
630 curval
->data
= grub_malloc (curval
->datasize
);
633 if (SIZEOF_OF_UINTN
== 4)
634 grub_memcpy (curval
->data
, "EFI32", curval
->datasize
);
636 grub_memcpy (curval
->data
, "EFI64", curval
->datasize
);
638 /* The key "platform". */
639 platformkey
= grub_xnu_create_key (&(efikey
->first_child
),
644 /* Pass FSB frequency to the kernel. */
645 curval
= grub_xnu_create_value (&(platformkey
->first_child
), "FSBFrequency");
648 curval
->datasize
= sizeof (grub_uint64_t
);
649 curval
->data
= grub_malloc (curval
->datasize
);
653 /* First see if user supplies the value. */
654 const char *fsbvar
= grub_env_get ("fsb");
655 grub_uint64_t fsbfreq
= 0;
657 fsbfreq
= readfrequency (fsbvar
);
658 /* Try autodetect. */
660 fsbfreq
= guessfsb ();
661 *((grub_uint64_t
*) curval
->data
) = fsbfreq
;
662 *fsbfreq_out
= fsbfreq
;
663 grub_dprintf ("xnu", "fsb autodetected as %llu\n",
664 (unsigned long long) *((grub_uint64_t
*) curval
->data
));
666 cfgtablekey
= grub_xnu_create_key (&(efikey
->first_child
),
667 "configuration-table");
671 /* Fill "configuration-table" key. */
672 for (i
= 0; i
< SYSTEM_TABLE (num_table_entries
); i
++)
675 struct grub_xnu_devtree_key
*curkey
;
676 grub_efi_packed_guid_t guid
;
679 /* Retrieve current key. */
680 #ifdef GRUB_MACHINE_EFI
683 grub_efi_system_table
->configuration_table
[i
].vendor_table
;
684 guid
= grub_efi_system_table
->configuration_table
[i
].vendor_guid
;
687 if (SIZEOF_OF_UINTN
== 4)
689 ptr
= (void *) (grub_addr_t
) ((grub_efiemu_configuration_table32_t
*)
690 SYSTEM_TABLE_PTR (configuration_table
))[i
]
693 ((grub_efiemu_configuration_table32_t
*)
694 SYSTEM_TABLE_PTR (configuration_table
))[i
].vendor_guid
;
698 ptr
= (void *) (grub_addr_t
) ((grub_efiemu_configuration_table64_t
*)
699 SYSTEM_TABLE_PTR (configuration_table
))[i
]
702 ((grub_efiemu_configuration_table64_t
*)
703 SYSTEM_TABLE_PTR (configuration_table
))[i
].vendor_guid
;
707 /* The name of key for new table. */
708 grub_snprintf (guidbuf
, sizeof (guidbuf
), "%08x-%04x-%04x-%02x%02x-",
709 guid
.data1
, guid
.data2
, guid
.data3
, guid
.data4
[0],
711 for (j
= 2; j
< 8; j
++)
712 grub_snprintf (guidbuf
+ grub_strlen (guidbuf
),
713 sizeof (guidbuf
) - grub_strlen (guidbuf
),
714 "%02x", guid
.data4
[j
]);
715 /* For some reason GUID has to be in uppercase. */
716 for (j
= 0; guidbuf
[j
] ; j
++)
717 if (guidbuf
[j
] >= 'a' && guidbuf
[j
] <= 'f')
718 guidbuf
[j
] += 'A' - 'a';
719 curkey
= grub_xnu_create_key (&(cfgtablekey
->first_child
), guidbuf
);
723 curval
= grub_xnu_create_value (&(curkey
->first_child
), "guid");
726 curval
->datasize
= sizeof (guid
);
727 curval
->data
= grub_malloc (curval
->datasize
);
730 grub_memcpy (curval
->data
, &guid
, curval
->datasize
);
732 /* The value "table". */
733 curval
= grub_xnu_create_value (&(curkey
->first_child
), "table");
736 curval
->datasize
= SIZEOF_OF_UINTN
;
737 curval
->data
= grub_malloc (curval
->datasize
);
740 if (SIZEOF_OF_UINTN
== 4)
741 *((grub_uint32_t
*) curval
->data
) = (grub_addr_t
) ptr
;
743 *((grub_uint64_t
*) curval
->data
) = (grub_addr_t
) ptr
;
746 for (j
= 0; j
< ARRAY_SIZE(table_aliases
); j
++)
747 if (grub_memcmp (&table_aliases
[j
].guid
, &guid
, sizeof (guid
)) == 0)
749 if (j
!= ARRAY_SIZE(table_aliases
))
751 curval
= grub_xnu_create_value (&(curkey
->first_child
), "alias");
754 curval
->datasize
= grub_strlen (table_aliases
[j
].name
) + 1;
755 curval
->data
= grub_malloc (curval
->datasize
);
758 grub_memcpy (curval
->data
, table_aliases
[j
].name
, curval
->datasize
);
762 /* Create and fill "runtime-services" key. */
763 runtimesrvkey
= grub_xnu_create_key (&(efikey
->first_child
),
767 curval
= grub_xnu_create_value (&(runtimesrvkey
->first_child
), "table");
770 curval
->datasize
= SIZEOF_OF_UINTN
;
771 curval
->data
= grub_malloc (curval
->datasize
);
774 if (SIZEOF_OF_UINTN
== 4)
775 *((grub_uint32_t
*) curval
->data
)
776 = (grub_addr_t
) SYSTEM_TABLE_PTR (runtime_services
);
778 *((grub_uint64_t
*) curval
->data
)
779 = (grub_addr_t
) SYSTEM_TABLE_PTR (runtime_services
);
781 return GRUB_ERR_NONE
;
785 grub_xnu_boot_resume (void)
787 struct grub_relocator32_state state
;
789 state
.esp
= grub_xnu_stack
;
790 state
.ebp
= grub_xnu_stack
;
791 state
.eip
= grub_xnu_entry_point
;
792 state
.eax
= grub_xnu_arg1
;
794 return grub_relocator32_boot (grub_xnu_relocator
, state
, 0);
797 /* Setup video for xnu. */
799 grub_xnu_set_video (struct grub_xnu_boot_params_common
*params
)
801 struct grub_video_mode_info mode_info
;
806 struct grub_video_bitmap
*bitmap
= NULL
;
808 modevar
= grub_env_get ("gfxpayload");
809 /* Consider only graphical 32-bit deep modes. */
810 if (! modevar
|| *modevar
== 0)
811 err
= grub_video_set_mode (DEFAULT_VIDEO_MODE
,
812 GRUB_VIDEO_MODE_TYPE_PURE_TEXT
813 | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK
,
814 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS
);
817 tmp
= grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE
, modevar
);
820 err
= grub_video_set_mode (tmp
,
821 GRUB_VIDEO_MODE_TYPE_PURE_TEXT
822 | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK
,
823 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS
);
830 err
= grub_video_get_info (&mode_info
);
836 if (grub_xnu_bitmap_mode
== GRUB_XNU_BITMAP_STRETCH
)
837 err
= grub_video_bitmap_create_scaled (&bitmap
,
841 GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST
);
843 bitmap
= grub_xnu_bitmap
;
848 if (grub_xnu_bitmap_mode
== GRUB_XNU_BITMAP_STRETCH
)
849 err
= grub_video_bitmap_create_scaled (&bitmap
,
853 GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST
);
855 bitmap
= grub_xnu_bitmap
;
862 x
= mode_info
.width
- bitmap
->mode_info
.width
;
864 y
= mode_info
.height
- bitmap
->mode_info
.height
;
866 err
= grub_video_blit_bitmap (bitmap
,
867 GRUB_VIDEO_BLIT_REPLACE
,
872 min (bitmap
->mode_info
.width
,
874 min (bitmap
->mode_info
.height
,
880 grub_errno
= GRUB_ERR_NONE
;
884 err
= grub_video_get_info_and_fini (&mode_info
, &framebuffer
);
888 params
->lfb_width
= mode_info
.width
;
889 params
->lfb_height
= mode_info
.height
;
890 params
->lfb_depth
= mode_info
.bpp
;
891 params
->lfb_line_len
= mode_info
.pitch
;
893 params
->lfb_base
= (grub_addr_t
) framebuffer
;
894 params
->lfb_mode
= bitmap
? GRUB_XNU_VIDEO_SPLASH
895 : GRUB_XNU_VIDEO_TEXT_IN_VIDEO
;
897 return GRUB_ERR_NONE
;
904 union grub_xnu_boot_params_any
*bootparams
;
905 struct grub_xnu_boot_params_common
*bootparams_common
;
907 grub_addr_t bootparams_target
;
909 grub_efi_uintn_t memory_map_size
= 0;
911 grub_addr_t memory_map_target
;
912 grub_efi_uintn_t map_key
= 0;
913 grub_efi_uintn_t descriptor_size
= 0;
914 grub_efi_uint32_t descriptor_version
= 0;
915 grub_uint64_t firstruntimepage
, lastruntimepage
;
916 grub_uint64_t curruntimepage
;
917 grub_addr_t devtree_target
;
918 grub_size_t devtreelen
;
920 struct grub_relocator32_state state
;
921 grub_uint64_t fsbfreq
= 100000000;
922 int v2
= (grub_xnu_darwin_version
>= 11);
923 grub_uint32_t efi_system_table
= 0;
925 err
= grub_autoefi_prepare ();
929 err
= grub_cpu_xnu_fill_devprop ();
933 err
= grub_cpu_xnu_fill_devicetree (&fsbfreq
);
937 err
= grub_xnu_fill_devicetree ();
941 /* Page-align to avoid following parts to be inadvertently freed. */
942 err
= grub_xnu_align_heap (GRUB_XNU_PAGESIZE
);
946 /* Pass memory map to kernel. */
951 descriptor_version
= 0;
953 grub_dprintf ("xnu", "eip=%x, efi=%p\n", grub_xnu_entry_point
,
954 grub_autoefi_system_table
);
956 const char *debug
= grub_env_get ("debug");
958 if (debug
&& (grub_strword (debug
, "all") || grub_strword (debug
, "xnu")))
960 grub_puts_ (N_("Press any key to launch xnu"));
964 /* Relocate the boot parameters to heap. */
965 err
= grub_xnu_heap_malloc (sizeof (*bootparams
),
966 &bp_in
, &bootparams_target
);
971 grub_memset (bootparams
, 0, sizeof (*bootparams
));
974 bootparams_common
= &bootparams
->v2
.common
;
975 bootparams
->v2
.fsbfreq
= fsbfreq
;
978 bootparams_common
= &bootparams
->v1
.common
;
981 err
= grub_xnu_set_video (bootparams_common
);
982 if (err
!= GRUB_ERR_NONE
)
985 grub_errno
= GRUB_ERR_NONE
;
986 grub_puts_ (N_("Booting in blind mode"));
988 bootparams_common
->lfb_mode
= 0;
989 bootparams_common
->lfb_width
= 0;
990 bootparams_common
->lfb_height
= 0;
991 bootparams_common
->lfb_depth
= 0;
992 bootparams_common
->lfb_line_len
= 0;
993 bootparams_common
->lfb_base
= 0;
996 if (grub_autoefi_get_memory_map (&memory_map_size
, memory_map
,
997 &map_key
, &descriptor_size
,
998 &descriptor_version
) < 0)
1001 /* We will do few allocations later. Reserve some space for possible
1002 memory map growth. */
1003 memory_map_size
+= 20 * descriptor_size
;
1004 err
= grub_xnu_heap_malloc (memory_map_size
,
1005 &memory_map
, &memory_map_target
);
1009 err
= grub_xnu_writetree_toheap (&devtree_target
, &devtreelen
);
1013 grub_memcpy (bootparams_common
->cmdline
, grub_xnu_cmdline
,
1014 sizeof (bootparams_common
->cmdline
));
1016 bootparams_common
->devtree
= devtree_target
;
1017 bootparams_common
->devtreelen
= devtreelen
;
1019 err
= grub_autoefi_finish_boot_services (&memory_map_size
, memory_map
,
1020 &map_key
, &descriptor_size
,
1021 &descriptor_version
);
1026 bootparams
->v2
.efi_system_table
= (grub_addr_t
) grub_autoefi_system_table
;
1028 bootparams
->v1
.efi_system_table
= (grub_addr_t
) grub_autoefi_system_table
;
1030 firstruntimepage
= (((grub_addr_t
) grub_xnu_heap_target_start
1031 + grub_xnu_heap_size
+ GRUB_XNU_PAGESIZE
- 1)
1032 / GRUB_XNU_PAGESIZE
) + 20;
1033 curruntimepage
= firstruntimepage
;
1035 for (i
= 0; (unsigned) i
< memory_map_size
/ descriptor_size
; i
++)
1037 grub_efi_memory_descriptor_t
*curdesc
= (grub_efi_memory_descriptor_t
*)
1038 ((char *) memory_map
+ descriptor_size
* i
);
1040 curdesc
->virtual_start
= curdesc
->physical_start
;
1042 if (curdesc
->type
== GRUB_EFI_RUNTIME_SERVICES_DATA
1043 || curdesc
->type
== GRUB_EFI_RUNTIME_SERVICES_CODE
)
1045 curdesc
->virtual_start
= curruntimepage
<< 12;
1046 curruntimepage
+= curdesc
->num_pages
;
1047 if (curdesc
->physical_start
1048 <= (grub_addr_t
) grub_autoefi_system_table
1049 && curdesc
->physical_start
+ (curdesc
->num_pages
<< 12)
1050 > (grub_addr_t
) grub_autoefi_system_table
)
1052 = (grub_addr_t
) grub_autoefi_system_table
1053 - curdesc
->physical_start
+ curdesc
->virtual_start
;
1054 if (SIZEOF_OF_UINTN
== 8 && grub_xnu_is_64bit
)
1055 curdesc
->virtual_start
|= 0xffffff8000000000ULL
;
1059 lastruntimepage
= curruntimepage
;
1063 bootparams
->v2
.efi_uintnbits
= SIZEOF_OF_UINTN
* 8;
1064 bootparams
->v2
.verminor
= GRUB_XNU_BOOTARGSV2_VERMINOR
;
1065 bootparams
->v2
.vermajor
= GRUB_XNU_BOOTARGSV2_VERMAJOR
;
1066 bootparams
->v2
.efi_system_table
= efi_system_table
;
1070 bootparams
->v1
.efi_uintnbits
= SIZEOF_OF_UINTN
* 8;
1071 bootparams
->v1
.verminor
= GRUB_XNU_BOOTARGSV1_VERMINOR
;
1072 bootparams
->v1
.vermajor
= GRUB_XNU_BOOTARGSV1_VERMAJOR
;
1073 bootparams
->v1
.efi_system_table
= efi_system_table
;
1076 bootparams_common
->efi_runtime_first_page
= firstruntimepage
;
1077 bootparams_common
->efi_runtime_npages
= lastruntimepage
- firstruntimepage
;
1078 bootparams_common
->efi_mem_desc_size
= descriptor_size
;
1079 bootparams_common
->efi_mem_desc_version
= descriptor_version
;
1080 bootparams_common
->efi_mmap
= memory_map_target
;
1081 bootparams_common
->efi_mmap_size
= memory_map_size
;
1082 bootparams_common
->heap_start
= grub_xnu_heap_target_start
;
1083 bootparams_common
->heap_size
= grub_xnu_heap_size
;
1085 /* Parameters for asm helper. */
1086 grub_xnu_stack
= bootparams_common
->heap_start
1087 + bootparams_common
->heap_size
+ GRUB_XNU_PAGESIZE
;
1088 grub_xnu_arg1
= bootparams_target
;
1090 grub_autoefi_set_virtual_address_map (memory_map_size
, descriptor_size
,
1091 descriptor_version
, memory_map
);
1093 state
.eip
= grub_xnu_entry_point
;
1094 state
.eax
= grub_xnu_arg1
;
1095 state
.esp
= grub_xnu_stack
;
1096 state
.ebp
= grub_xnu_stack
;
1098 /* XNU uses only APIC. Disable PIC. */
1099 grub_outb (0xff, 0x21);
1100 grub_outb (0xff, 0xa1);
1102 return grub_relocator32_boot (grub_xnu_relocator
, state
, 0);
1105 static grub_command_t cmd_devprop_load
;
1108 grub_cpu_xnu_init (void)
1110 cmd_devprop_load
= grub_register_command ("xnu_devprop_load",
1111 grub_cmd_devprop_load
,
1112 /* TRANSLATORS: `device-properties'
1115 0, N_("Load `device-properties' dump."));
1119 grub_cpu_xnu_fini (void)
1121 grub_unregister_command (cmd_devprop_load
);