12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556 |
- /* xnu.c - load xnu kernel. Thanks to Florian Idelberger for all the
- time he spent testing this
- */
- /*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2009 Free Software Foundation, Inc.
- *
- * GRUB is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GRUB is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <grub/file.h>
- #include <grub/xnu.h>
- #include <grub/cpu/xnu.h>
- #include <grub/mm.h>
- #include <grub/dl.h>
- #include <grub/loader.h>
- #include <grub/machoload.h>
- #include <grub/macho.h>
- #include <grub/cpu/macho.h>
- #include <grub/command.h>
- #include <grub/misc.h>
- #include <grub/extcmd.h>
- #include <grub/env.h>
- #include <grub/i18n.h>
- #include <grub/verify.h>
- #include <grub/safemath.h>
- GRUB_MOD_LICENSE ("GPLv3+");
- #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
- #include <grub/autoefi.h>
- #endif
- struct grub_xnu_devtree_key *grub_xnu_devtree_root = 0;
- static int driverspackagenum = 0;
- static int driversnum = 0;
- int grub_xnu_is_64bit = 0;
- int grub_xnu_darwin_version = 0;
- grub_addr_t grub_xnu_heap_target_start = 0;
- grub_size_t grub_xnu_heap_size = 0;
- struct grub_relocator *grub_xnu_relocator;
- static grub_err_t
- grub_xnu_register_memory (const char *prefix, int *suffix,
- grub_addr_t addr, grub_size_t size);
- grub_err_t
- grub_xnu_heap_malloc (int size, void **src, grub_addr_t *target)
- {
- grub_err_t err;
- grub_relocator_chunk_t ch;
- grub_addr_t tgt;
- if (grub_add (grub_xnu_heap_target_start, grub_xnu_heap_size, &tgt))
- return GRUB_ERR_OUT_OF_RANGE;
- err = grub_relocator_alloc_chunk_addr (grub_xnu_relocator, &ch, tgt, size);
- if (err)
- return err;
- *src = get_virtual_current_address (ch);
- *target = tgt;
- grub_xnu_heap_size += size;
- grub_dprintf ("xnu", "val=%p\n", *src);
- return GRUB_ERR_NONE;
- }
- /* Make sure next block of the heap will be aligned.
- Please notice: aligned are pointers AFTER relocation
- and not the current ones. */
- grub_err_t
- grub_xnu_align_heap (int align)
- {
- grub_xnu_heap_size
- = ALIGN_UP (grub_xnu_heap_target_start+ grub_xnu_heap_size, align)
- - grub_xnu_heap_target_start;
- return GRUB_ERR_NONE;
- }
- /* Free subtree pointed by CUR. */
- void
- grub_xnu_free_devtree (struct grub_xnu_devtree_key *cur)
- {
- struct grub_xnu_devtree_key *d;
- while (cur)
- {
- grub_free (cur->name);
- if (cur->datasize == -1)
- grub_xnu_free_devtree (cur->first_child);
- else if (cur->data)
- grub_free (cur->data);
- d = cur->next;
- grub_free (cur);
- cur = d;
- }
- }
- /* Compute the size of device tree in xnu format. */
- static grub_size_t
- grub_xnu_writetree_get_size (struct grub_xnu_devtree_key *start,
- const char *name)
- {
- grub_size_t ret;
- struct grub_xnu_devtree_key *cur;
- /* Key header. */
- ret = 2 * sizeof (grub_uint32_t);
- /* "name" value. */
- ret += 32 + sizeof (grub_uint32_t)
- + grub_strlen (name) + 4
- - (grub_strlen (name) % 4);
- for (cur = start; cur; cur = cur->next)
- if (cur->datasize != -1)
- {
- int align_overhead;
- align_overhead = 4 - (cur->datasize % 4);
- if (align_overhead == 4)
- align_overhead = 0;
- ret += 32 + sizeof (grub_uint32_t) + cur->datasize + align_overhead;
- }
- else
- ret += grub_xnu_writetree_get_size (cur->first_child, cur->name);
- return ret;
- }
- /* Write devtree in XNU format at curptr assuming the head is named NAME.*/
- static void *
- grub_xnu_writetree_toheap_real (void *curptr,
- struct grub_xnu_devtree_key *start,
- const char *name)
- {
- struct grub_xnu_devtree_key *cur;
- int nkeys = 0, nvals = 0;
- for (cur = start; cur; cur = cur->next)
- {
- if (cur->datasize == -1)
- nkeys++;
- else
- nvals++;
- }
- /* For the name. */
- nvals++;
- *((grub_uint32_t *) curptr) = nvals;
- curptr = ((grub_uint32_t *) curptr) + 1;
- *((grub_uint32_t *) curptr) = nkeys;
- curptr = ((grub_uint32_t *) curptr) + 1;
- /* First comes "name" value. */
- grub_memset (curptr, 0, 32);
- grub_memcpy (curptr, "name", 4);
- curptr = ((grub_uint8_t *) curptr) + 32;
- *((grub_uint32_t *)curptr) = grub_strlen (name) + 1;
- curptr = ((grub_uint32_t *) curptr) + 1;
- grub_memcpy (curptr, name, grub_strlen (name));
- curptr = ((grub_uint8_t *) curptr) + grub_strlen (name);
- grub_memset (curptr, 0, 4 - (grub_strlen (name) % 4));
- curptr = ((grub_uint8_t *) curptr) + (4 - (grub_strlen (name) % 4));
- /* Then the other values. */
- for (cur = start; cur; cur = cur->next)
- if (cur->datasize != -1)
- {
- int align_overhead;
- align_overhead = 4 - (cur->datasize % 4);
- if (align_overhead == 4)
- align_overhead = 0;
- grub_memset (curptr, 0, 32);
- grub_strncpy (curptr, cur->name, 31);
- curptr = ((grub_uint8_t *) curptr) + 32;
- *((grub_uint32_t *) curptr) = cur->datasize;
- curptr = ((grub_uint32_t *) curptr) + 1;
- grub_memcpy (curptr, cur->data, cur->datasize);
- curptr = ((grub_uint8_t *) curptr) + cur->datasize;
- grub_memset (curptr, 0, align_overhead);
- curptr = ((grub_uint8_t *) curptr) + align_overhead;
- }
- /* And then the keys. Recursively use this function. */
- for (cur = start; cur; cur = cur->next)
- if (cur->datasize == -1)
- {
- curptr = grub_xnu_writetree_toheap_real (curptr,
- cur->first_child,
- cur->name);
- if (!curptr)
- return 0;
- }
- return curptr;
- }
- grub_err_t
- grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size)
- {
- struct grub_xnu_devtree_key *chosen;
- struct grub_xnu_devtree_key *memorymap;
- struct grub_xnu_devtree_key *driverkey;
- struct grub_xnu_extdesc *extdesc;
- grub_err_t err;
- void *src;
- err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
- if (err)
- return err;
- /* Device tree itself is in the memory map of device tree. */
- /* Create a dummy value in memory-map. */
- chosen = grub_xnu_create_key (&grub_xnu_devtree_root, "chosen");
- if (! chosen)
- return grub_errno;
- memorymap = grub_xnu_create_key (&(chosen->first_child), "memory-map");
- if (! memorymap)
- return grub_errno;
- driverkey = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*driverkey));
- if (! driverkey)
- return grub_errno;
- driverkey->name = grub_strdup ("DeviceTree");
- if (! driverkey->name)
- {
- err = grub_errno;
- goto fail;
- }
- driverkey->datasize = sizeof (*extdesc);
- driverkey->next = memorymap->first_child;
- memorymap->first_child = driverkey;
- driverkey->data = extdesc
- = (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc));
- if (! driverkey->data)
- {
- err = grub_errno;
- goto fail;
- }
- /* Allocate the space based on the size with dummy value. */
- *size = grub_xnu_writetree_get_size (grub_xnu_devtree_root, "/");
- err = grub_xnu_heap_malloc (ALIGN_UP (*size + 1, GRUB_XNU_PAGESIZE),
- &src, target);
- if (err)
- goto fail;
- /* Put real data in the dummy. */
- extdesc->addr = *target;
- extdesc->size = (grub_uint32_t) *size;
- /* Write the tree to heap. */
- grub_xnu_writetree_toheap_real (src, grub_xnu_devtree_root, "/");
- return GRUB_ERR_NONE;
- fail:
- memorymap->first_child = NULL;
- grub_free (driverkey->data);
- grub_free (driverkey->name);
- grub_free (driverkey);
- return err;
- }
- /* Find a key or value in parent key. */
- struct grub_xnu_devtree_key *
- grub_xnu_find_key (struct grub_xnu_devtree_key *parent, const char *name)
- {
- struct grub_xnu_devtree_key *cur;
- for (cur = parent; cur; cur = cur->next)
- if (grub_strcmp (cur->name, name) == 0)
- return cur;
- return 0;
- }
- struct grub_xnu_devtree_key *
- grub_xnu_create_key (struct grub_xnu_devtree_key **parent, const char *name)
- {
- struct grub_xnu_devtree_key *ret;
- ret = grub_xnu_find_key (*parent, name);
- if (ret)
- return ret;
- ret = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*ret));
- if (! ret)
- return 0;
- ret->name = grub_strdup (name);
- if (! ret->name)
- {
- grub_free (ret);
- return 0;
- }
- ret->datasize = -1;
- ret->next = *parent;
- *parent = ret;
- return ret;
- }
- struct grub_xnu_devtree_key *
- grub_xnu_create_value (struct grub_xnu_devtree_key **parent, const char *name)
- {
- struct grub_xnu_devtree_key *ret;
- ret = grub_xnu_find_key (*parent, name);
- if (ret)
- {
- if (ret->datasize == -1)
- grub_xnu_free_devtree (ret->first_child);
- else if (ret->datasize)
- grub_free (ret->data);
- ret->datasize = 0;
- ret->data = 0;
- return ret;
- }
- ret = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*ret));
- if (! ret)
- return 0;
- ret->name = grub_strdup (name);
- if (! ret->name)
- {
- grub_free (ret);
- return 0;
- }
- ret->next = *parent;
- *parent = ret;
- return ret;
- }
- static grub_err_t
- grub_xnu_unload (void)
- {
- grub_cpu_xnu_unload ();
- grub_xnu_free_devtree (grub_xnu_devtree_root);
- grub_xnu_devtree_root = 0;
- /* Free loaded image. */
- driversnum = 0;
- driverspackagenum = 0;
- grub_relocator_unload (grub_xnu_relocator);
- grub_xnu_relocator = NULL;
- grub_xnu_heap_target_start = 0;
- grub_xnu_heap_size = 0;
- grub_xnu_unlock ();
- return GRUB_ERR_NONE;
- }
- static grub_err_t
- grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
- int argc, char *args[])
- {
- grub_err_t err;
- grub_macho_t macho;
- grub_uint32_t startcode, endcode;
- int i;
- char *ptr;
- void *loadaddr;
- grub_addr_t loadaddr_target;
- if (argc < 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
- grub_xnu_unload ();
- macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, 0);
- if (! macho)
- return grub_errno;
- err = grub_macho_size32 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS,
- args[0]);
- if (err)
- {
- grub_macho_close (macho);
- grub_xnu_unload ();
- return err;
- }
- grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n",
- (unsigned long) endcode, (unsigned long) startcode);
- grub_xnu_relocator = grub_relocator_new ();
- if (!grub_xnu_relocator)
- return grub_errno;
- grub_xnu_heap_target_start = startcode;
- err = grub_xnu_heap_malloc (endcode - startcode, &loadaddr,
- &loadaddr_target);
- if (err)
- {
- grub_macho_close (macho);
- grub_xnu_unload ();
- return err;
- }
- /* Load kernel. */
- err = grub_macho_load32 (macho, args[0], (char *) loadaddr - startcode,
- GRUB_MACHO_NOBSS, &grub_xnu_darwin_version);
- if (err)
- {
- grub_macho_close (macho);
- grub_xnu_unload ();
- return err;
- }
- grub_xnu_entry_point = grub_macho_get_entry_point32 (macho, args[0]);
- if (! grub_xnu_entry_point)
- {
- grub_macho_close (macho);
- grub_xnu_unload ();
- return grub_error (GRUB_ERR_BAD_OS, "couldn't find entry point");
- }
- grub_macho_close (macho);
- err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
- if (err)
- {
- grub_xnu_unload ();
- return err;
- }
- /* Copy parameters to kernel command line. */
- ptr = grub_xnu_cmdline;
- for (i = 1; i < argc; i++)
- {
- if (ptr + grub_strlen (args[i]) + 1
- >= grub_xnu_cmdline + sizeof (grub_xnu_cmdline))
- break;
- grub_memcpy (ptr, args[i], grub_strlen (args[i]));
- ptr += grub_strlen (args[i]);
- *ptr = ' ';
- ptr++;
- }
- /* Replace last space by '\0'. */
- if (ptr != grub_xnu_cmdline)
- *(ptr - 1) = 0;
- err = grub_verify_string (grub_xnu_cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
- if (err)
- return err;
- #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
- err = grub_efiemu_autocore ();
- if (err)
- return err;
- #endif
- grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0);
- grub_xnu_lock ();
- grub_xnu_is_64bit = 0;
- return 0;
- }
- static grub_err_t
- grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
- int argc, char *args[])
- {
- grub_err_t err;
- grub_macho_t macho;
- grub_uint64_t startcode, endcode;
- int i;
- char *ptr;
- void *loadaddr;
- grub_addr_t loadaddr_target;
- if (argc < 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
- grub_xnu_unload ();
- macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, 1);
- if (! macho)
- return grub_errno;
- err = grub_macho_size64 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS,
- args[0]);
- if (err)
- {
- grub_macho_close (macho);
- grub_xnu_unload ();
- return err;
- }
- startcode &= 0x0fffffff;
- endcode &= 0x0fffffff;
- grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n",
- (unsigned long) endcode, (unsigned long) startcode);
- grub_xnu_relocator = grub_relocator_new ();
- if (!grub_xnu_relocator)
- return grub_errno;
- grub_xnu_heap_target_start = startcode;
- err = grub_xnu_heap_malloc (endcode - startcode, &loadaddr,
- &loadaddr_target);
- if (err)
- {
- grub_macho_close (macho);
- grub_xnu_unload ();
- return err;
- }
- /* Load kernel. */
- err = grub_macho_load64 (macho, args[0], (char *) loadaddr - startcode,
- GRUB_MACHO_NOBSS, &grub_xnu_darwin_version);
- if (err)
- {
- grub_macho_close (macho);
- grub_xnu_unload ();
- return err;
- }
- grub_xnu_entry_point = grub_macho_get_entry_point64 (macho, args[0])
- & 0x0fffffff;
- if (! grub_xnu_entry_point)
- {
- grub_macho_close (macho);
- grub_xnu_unload ();
- return grub_error (GRUB_ERR_BAD_OS, "couldn't find entry point");
- }
- grub_macho_close (macho);
- err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
- if (err)
- {
- grub_xnu_unload ();
- return err;
- }
- /* Copy parameters to kernel command line. */
- ptr = grub_xnu_cmdline;
- for (i = 1; i < argc; i++)
- {
- if (ptr + grub_strlen (args[i]) + 1
- >= grub_xnu_cmdline + sizeof (grub_xnu_cmdline))
- break;
- grub_memcpy (ptr, args[i], grub_strlen (args[i]));
- ptr += grub_strlen (args[i]);
- *ptr = ' ';
- ptr++;
- }
- /* Replace last space by '\0'. */
- if (ptr != grub_xnu_cmdline)
- *(ptr - 1) = 0;
- err = grub_verify_string (grub_xnu_cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
- if (err)
- return err;
- #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
- err = grub_efiemu_autocore ();
- if (err)
- return err;
- #endif
- grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0);
- grub_xnu_lock ();
- grub_xnu_is_64bit = 1;
- return 0;
- }
- /* Register a memory in a memory map under name PREFIXSUFFIX
- and increment SUFFIX. */
- static grub_err_t
- grub_xnu_register_memory (const char *prefix, int *suffix,
- grub_addr_t addr, grub_size_t size)
- {
- struct grub_xnu_devtree_key *chosen;
- struct grub_xnu_devtree_key *memorymap;
- struct grub_xnu_devtree_key *driverkey;
- struct grub_xnu_extdesc *extdesc;
- if (! grub_xnu_heap_size)
- return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
- chosen = grub_xnu_create_key (&grub_xnu_devtree_root, "chosen");
- if (! chosen)
- return grub_errno;
- memorymap = grub_xnu_create_key (&(chosen->first_child), "memory-map");
- if (! memorymap)
- return grub_errno;
- driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*driverkey));
- if (! driverkey)
- return grub_errno;
- if (suffix)
- driverkey->name = grub_xasprintf ("%s%d", prefix, (*suffix)++);
- else
- driverkey->name = grub_strdup (prefix);
- if (!driverkey->name)
- {
- grub_free (driverkey);
- return grub_errno;
- }
- driverkey->datasize = sizeof (*extdesc);
- driverkey->next = memorymap->first_child;
- driverkey->data = extdesc
- = (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc));
- if (! driverkey->data)
- {
- grub_free (driverkey->name);
- grub_free (driverkey);
- return grub_errno;
- }
- memorymap->first_child = driverkey;
- extdesc->addr = addr;
- extdesc->size = (grub_uint32_t) size;
- return GRUB_ERR_NONE;
- }
- static inline char *
- get_name_ptr (char *name)
- {
- char *p = name, *p2;
- /* Skip Info.plist. */
- p2 = grub_strrchr (p, '/');
- if (!p2)
- return name;
- if (p2 == name)
- return name + 1;
- p = p2 - 1;
- p2 = grub_strrchr (p, '/');
- if (!p2)
- return name;
- if (p2 == name)
- return name + 1;
- if (grub_memcmp (p2, "/Contents/", sizeof ("/Contents/") - 1) != 0)
- return p2 + 1;
- p = p2 - 1;
- p2 = grub_strrchr (p, '/');
- if (!p2)
- return name;
- return p2 + 1;
- }
- /* Load .kext. */
- static grub_err_t
- grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile,
- const char *filename)
- {
- grub_macho_t macho;
- grub_err_t err;
- grub_file_t infoplist;
- struct grub_xnu_extheader *exthead;
- int neededspace = sizeof (*exthead);
- grub_uint8_t *buf;
- void *buf0;
- grub_addr_t buf_target;
- grub_size_t infoplistsize = 0, machosize = 0;
- char *name, *nameend;
- int namelen;
- if (infoplistname == NULL)
- return grub_error (GRUB_ERR_BAD_FILENAME, N_("missing p-list filename"));
- name = get_name_ptr (infoplistname);
- nameend = grub_strchr (name, '/');
- if (nameend)
- namelen = nameend - name;
- else
- namelen = grub_strlen (name);
- neededspace += namelen + 1;
- if (! grub_xnu_heap_size)
- return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
- /* Compute the needed space. */
- if (binaryfile)
- {
- macho = grub_macho_file (binaryfile, filename, grub_xnu_is_64bit);
- if (!macho)
- grub_file_close (binaryfile);
- else
- {
- if (grub_xnu_is_64bit)
- machosize = grub_macho_filesize64 (macho);
- else
- machosize = grub_macho_filesize32 (macho);
- }
- neededspace += machosize;
- }
- else
- macho = 0;
- infoplist = grub_file_open (infoplistname, GRUB_FILE_TYPE_XNU_INFO_PLIST);
- grub_errno = GRUB_ERR_NONE;
- if (infoplist)
- {
- infoplistsize = grub_file_size (infoplist);
- neededspace += infoplistsize + 1;
- }
- else
- infoplistsize = 0;
- /* Allocate the space. */
- err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
- if (err)
- goto fail;
- err = grub_xnu_heap_malloc (neededspace, &buf0, &buf_target);
- if (err)
- goto fail;
- buf = buf0;
- exthead = (struct grub_xnu_extheader *) buf;
- grub_memset (exthead, 0, sizeof (*exthead));
- buf += sizeof (*exthead);
- /* Load the binary. */
- if (macho)
- {
- exthead->binaryaddr = buf_target + (buf - (grub_uint8_t *) buf0);
- exthead->binarysize = machosize;
- if (grub_xnu_is_64bit)
- err = grub_macho_readfile64 (macho, filename, buf);
- else
- err = grub_macho_readfile32 (macho, filename, buf);
- if (err)
- goto fail;
- grub_macho_close (macho);
- buf += machosize;
- }
- grub_errno = GRUB_ERR_NONE;
- /* Load the plist. */
- if (infoplist)
- {
- exthead->infoplistaddr = buf_target + (buf - (grub_uint8_t *) buf0);
- exthead->infoplistsize = infoplistsize + 1;
- if (grub_file_read (infoplist, buf, infoplistsize)
- != (grub_ssize_t) (infoplistsize))
- {
- grub_file_close (infoplist);
- if (!grub_errno)
- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
- infoplistname);
- return grub_errno;
- }
- grub_file_close (infoplist);
- buf[infoplistsize] = 0;
- buf += infoplistsize + 1;
- }
- grub_errno = GRUB_ERR_NONE;
- exthead->nameaddr = (buf - (grub_uint8_t *) buf0) + buf_target;
- exthead->namesize = namelen + 1;
- grub_memcpy (buf, name, namelen);
- buf[namelen] = 0;
- buf += namelen + 1;
- /* Announce to kernel */
- return grub_xnu_register_memory ("Driver-", &driversnum, buf_target,
- neededspace);
- fail:
- if (macho)
- grub_macho_close (macho);
- return err;
- }
- /* Load mkext. */
- static grub_err_t
- grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)),
- int argc, char *args[])
- {
- grub_file_t file;
- void *loadto;
- grub_addr_t loadto_target;
- grub_err_t err;
- grub_off_t readoff = 0;
- grub_ssize_t readlen = -1;
- struct grub_macho_fat_header head;
- struct grub_macho_fat_arch *archs;
- int narchs, i;
- if (argc != 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
- if (! grub_xnu_heap_size)
- return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
- file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_MKEXT);
- if (! file)
- return grub_errno;
- /* Sometimes caches are fat binary. Errgh. */
- if (grub_file_read (file, &head, sizeof (head))
- != (grub_ssize_t) (sizeof (head)))
- {
- /* I don't know the internal structure of package but
- can hardly imagine a valid package shorter than 20 bytes. */
- grub_file_close (file);
- if (!grub_errno)
- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]);
- return grub_errno;
- }
- /* Find the corresponding architecture. */
- if (grub_be_to_cpu32 (head.magic) == GRUB_MACHO_FAT_MAGIC)
- {
- narchs = grub_be_to_cpu32 (head.nfat_arch);
- archs = grub_calloc (narchs, sizeof (struct grub_macho_fat_arch));
- if (! archs)
- {
- grub_file_close (file);
- return grub_errno;
- }
- if (grub_file_read (file, archs,
- sizeof (struct grub_macho_fat_arch) * narchs)
- != (grub_ssize_t) sizeof(struct grub_macho_fat_arch) * narchs)
- {
- grub_free (archs);
- if (!grub_errno)
- grub_error (GRUB_ERR_READ_ERROR, N_("premature end of file %s"),
- args[0]);
- return grub_errno;
- }
- for (i = 0; i < narchs; i++)
- {
- if (!grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST32
- (grub_be_to_cpu32 (archs[i].cputype)))
- {
- readoff = grub_be_to_cpu32 (archs[i].offset);
- readlen = grub_be_to_cpu32 (archs[i].size);
- }
- if (grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST64
- (grub_be_to_cpu32 (archs[i].cputype)))
- {
- readoff = grub_be_to_cpu32 (archs[i].offset);
- readlen = grub_be_to_cpu32 (archs[i].size);
- }
- }
- grub_free (archs);
- }
- else
- {
- /* It's a flat file. Some sane people still exist. */
- readoff = 0;
- readlen = grub_file_size (file);
- }
- if (readlen == -1)
- {
- grub_file_close (file);
- return grub_error (GRUB_ERR_BAD_OS, "no suitable architecture is found");
- }
- /* Allocate space. */
- err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
- if (err)
- {
- grub_file_close (file);
- return err;
- }
- err = grub_xnu_heap_malloc (readlen, &loadto, &loadto_target);
- if (err)
- {
- grub_file_close (file);
- return err;
- }
- /* Read the file. */
- grub_file_seek (file, readoff);
- if (grub_file_read (file, loadto, readlen) != (grub_ssize_t) (readlen))
- {
- grub_file_close (file);
- if (!grub_errno)
- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]);
- return grub_errno;
- }
- grub_file_close (file);
- /* Pass it to kernel. */
- return grub_xnu_register_memory ("DriversPackage-", &driverspackagenum,
- loadto_target, readlen);
- }
- static grub_err_t
- grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)),
- int argc, char *args[])
- {
- grub_file_t file;
- void *loadto;
- grub_addr_t loadto_target;
- grub_err_t err;
- grub_size_t size;
- if (argc != 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
- if (! grub_xnu_heap_size)
- return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
- file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_RAMDISK);
- if (! file)
- return grub_errno;
- err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
- if (err)
- return err;
- size = grub_file_size (file);
- err = grub_xnu_heap_malloc (size, &loadto, &loadto_target);
- if (err)
- return err;
- if (grub_file_read (file, loadto, size) != (grub_ssize_t) (size))
- {
- grub_file_close (file);
- if (!grub_errno)
- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]);
- return grub_errno;
- }
- return grub_xnu_register_memory ("RAMDisk", 0, loadto_target, size);
- }
- /* Returns true if the kext should be loaded according to plist
- and osbundlereq. Also fill BINNAME. */
- static int
- grub_xnu_check_os_bundle_required (char *plistname,
- const char *osbundlereq,
- char **binname)
- {
- grub_file_t file;
- char *buf = 0, *tagstart = 0, *ptr1 = 0, *keyptr = 0;
- char *stringptr = 0, *ptr2 = 0;
- grub_size_t size;
- int depth = 0;
- int ret;
- int osbundlekeyfound = 0, binnamekeyfound = 0;
- if (binname)
- *binname = 0;
- file = grub_file_open (plistname, GRUB_FILE_TYPE_XNU_INFO_PLIST);
- if (! file)
- return 0;
- size = grub_file_size (file);
- buf = grub_malloc (size);
- if (! buf)
- {
- grub_file_close (file);
- return 0;
- }
- if (grub_file_read (file, buf, size) != (grub_ssize_t) (size))
- {
- grub_file_close (file);
- if (!grub_errno)
- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), plistname);
- return 0;
- }
- grub_file_close (file);
- /* Set the return value for the case when no OSBundleRequired tag is found. */
- if (osbundlereq)
- ret = grub_strword (osbundlereq, "all") || grub_strword (osbundlereq, "-");
- else
- ret = 1;
- /* Parse plist. It's quite dirty and inextensible but does its job. */
- for (ptr1 = buf; ptr1 < buf + size; ptr1++)
- switch (*ptr1)
- {
- case '<':
- tagstart = ptr1;
- *ptr1 = 0;
- if (keyptr && depth == 4
- && grub_strcmp (keyptr, "OSBundleRequired") == 0)
- osbundlekeyfound = 1;
- if (keyptr && depth == 4 &&
- grub_strcmp (keyptr, "CFBundleExecutable") == 0)
- binnamekeyfound = 1;
- if (stringptr && osbundlekeyfound && osbundlereq && depth == 4)
- {
- for (ptr2 = stringptr; *ptr2; ptr2++)
- *ptr2 = grub_tolower (*ptr2);
- ret = grub_strword (osbundlereq, stringptr)
- || grub_strword (osbundlereq, "all");
- }
- if (stringptr && binnamekeyfound && binname && depth == 4)
- {
- if (*binname)
- grub_free (*binname);
- *binname = grub_strdup (stringptr);
- }
- *ptr1 = '<';
- keyptr = 0;
- stringptr = 0;
- break;
- case '>':
- if (! tagstart)
- {
- grub_free (buf);
- grub_error (GRUB_ERR_BAD_OS, "can't parse %s", plistname);
- return 0;
- }
- *ptr1 = 0;
- if (tagstart[1] == '?' || ptr1[-1] == '/')
- {
- osbundlekeyfound = 0;
- *ptr1 = '>';
- break;
- }
- if (depth == 3 && grub_strcmp (tagstart + 1, "key") == 0)
- keyptr = ptr1 + 1;
- if (depth == 3 && grub_strcmp (tagstart + 1, "string") == 0)
- stringptr = ptr1 + 1;
- else if (grub_strcmp (tagstart + 1, "/key") != 0)
- {
- osbundlekeyfound = 0;
- binnamekeyfound = 0;
- }
- *ptr1 = '>';
- if (tagstart[1] == '/')
- depth--;
- else
- depth++;
- break;
- }
- grub_free (buf);
- return ret;
- }
- /* Context for grub_xnu_scan_dir_for_kexts. */
- struct grub_xnu_scan_dir_for_kexts_ctx
- {
- char *dirname;
- const char *osbundlerequired;
- int maxrecursion;
- };
- /* Helper for grub_xnu_scan_dir_for_kexts. */
- static int
- grub_xnu_scan_dir_for_kexts_load (const char *filename,
- const struct grub_dirhook_info *info,
- void *data)
- {
- struct grub_xnu_scan_dir_for_kexts_ctx *ctx = data;
- char *newdirname;
- if (! info->dir)
- return 0;
- if (filename[0] == '.')
- return 0;
- if (grub_strlen (filename) < 5 ||
- grub_memcmp (filename + grub_strlen (filename) - 5, ".kext", 5) != 0)
- return 0;
- newdirname
- = grub_malloc (grub_strlen (ctx->dirname) + grub_strlen (filename) + 2);
- /* It's a .kext. Try to load it. */
- if (newdirname)
- {
- grub_strcpy (newdirname, ctx->dirname);
- newdirname[grub_strlen (newdirname) + 1] = 0;
- newdirname[grub_strlen (newdirname)] = '/';
- grub_strcpy (newdirname + grub_strlen (newdirname), filename);
- grub_xnu_load_kext_from_dir (newdirname, ctx->osbundlerequired,
- ctx->maxrecursion);
- if (grub_errno == GRUB_ERR_BAD_OS)
- grub_errno = GRUB_ERR_NONE;
- grub_free (newdirname);
- }
- return 0;
- }
- /* Load all loadable kexts placed under DIRNAME and matching OSBUNDLEREQUIRED */
- grub_err_t
- grub_xnu_scan_dir_for_kexts (char *dirname, const char *osbundlerequired,
- int maxrecursion)
- {
- struct grub_xnu_scan_dir_for_kexts_ctx ctx = {
- .dirname = dirname,
- .osbundlerequired = osbundlerequired,
- .maxrecursion = maxrecursion
- };
- grub_device_t dev;
- char *device_name;
- grub_fs_t fs;
- const char *path;
- if (! grub_xnu_heap_size)
- return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
- device_name = grub_file_get_device_name (dirname);
- dev = grub_device_open (device_name);
- if (dev)
- {
- fs = grub_fs_probe (dev);
- path = grub_strchr (dirname, ')');
- if (! path)
- path = dirname;
- else
- path++;
- if (fs)
- (fs->fs_dir) (dev, path, grub_xnu_scan_dir_for_kexts_load, &ctx);
- grub_device_close (dev);
- }
- grub_free (device_name);
- return GRUB_ERR_NONE;
- }
- /* Context for grub_xnu_load_kext_from_dir. */
- struct grub_xnu_load_kext_from_dir_ctx
- {
- char *dirname;
- const char *osbundlerequired;
- int maxrecursion;
- char *plistname;
- char *newdirname;
- int usemacos;
- };
- /* Helper for grub_xnu_load_kext_from_dir. */
- static int
- grub_xnu_load_kext_from_dir_load (const char *filename,
- const struct grub_dirhook_info *info,
- void *data)
- {
- struct grub_xnu_load_kext_from_dir_ctx *ctx = data;
- if (grub_strlen (filename) > 15)
- return 0;
- grub_strcpy (ctx->newdirname + grub_strlen (ctx->dirname) + 1, filename);
- /* If the kext contains directory "Contents" all real stuff is in
- this directory. */
- if (info->dir && grub_strcasecmp (filename, "Contents") == 0)
- grub_xnu_load_kext_from_dir (ctx->newdirname, ctx->osbundlerequired,
- ctx->maxrecursion - 1);
- /* Directory "Plugins" contains nested kexts. */
- if (info->dir && grub_strcasecmp (filename, "Plugins") == 0)
- grub_xnu_scan_dir_for_kexts (ctx->newdirname, ctx->osbundlerequired,
- ctx->maxrecursion - 1);
- /* Directory "MacOS" contains executable, otherwise executable is
- on the top. */
- if (info->dir && grub_strcasecmp (filename, "MacOS") == 0)
- ctx->usemacos = 1;
- /* Info.plist is the file which governs our future actions. */
- if (! info->dir && grub_strcasecmp (filename, "Info.plist") == 0
- && ! ctx->plistname)
- ctx->plistname = grub_strdup (ctx->newdirname);
- return 0;
- }
- /* Load extension DIRNAME. (extensions are directories in xnu) */
- grub_err_t
- grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired,
- int maxrecursion)
- {
- struct grub_xnu_load_kext_from_dir_ctx ctx = {
- .dirname = dirname,
- .osbundlerequired = osbundlerequired,
- .maxrecursion = maxrecursion,
- .plistname = 0,
- .usemacos = 0
- };
- grub_device_t dev;
- char *newpath;
- char *device_name;
- grub_fs_t fs;
- const char *path;
- char *binsuffix;
- grub_file_t binfile;
- ctx.newdirname = grub_malloc (grub_strlen (dirname) + 20);
- if (! ctx.newdirname)
- return grub_errno;
- grub_strcpy (ctx.newdirname, dirname);
- ctx.newdirname[grub_strlen (dirname)] = '/';
- ctx.newdirname[grub_strlen (dirname) + 1] = 0;
- device_name = grub_file_get_device_name (dirname);
- dev = grub_device_open (device_name);
- if (dev)
- {
- fs = grub_fs_probe (dev);
- path = grub_strchr (dirname, ')');
- if (! path)
- path = dirname;
- else
- path++;
- newpath = grub_strchr (ctx.newdirname, ')');
- if (! newpath)
- newpath = ctx.newdirname;
- else
- newpath++;
- /* Look at the directory. */
- if (fs)
- (fs->fs_dir) (dev, path, grub_xnu_load_kext_from_dir_load, &ctx);
- if (ctx.plistname && grub_xnu_check_os_bundle_required
- (ctx.plistname, osbundlerequired, &binsuffix))
- {
- if (binsuffix)
- {
- /* Open the binary. */
- char *binname = grub_malloc (grub_strlen (dirname)
- + grub_strlen (binsuffix)
- + sizeof ("/MacOS/"));
- grub_strcpy (binname, dirname);
- if (ctx.usemacos)
- grub_strcpy (binname + grub_strlen (binname), "/MacOS/");
- else
- grub_strcpy (binname + grub_strlen (binname), "/");
- grub_strcpy (binname + grub_strlen (binname), binsuffix);
- grub_dprintf ("xnu", "%s:%s\n", ctx.plistname, binname);
- binfile = grub_file_open (binname, GRUB_FILE_TYPE_XNU_KEXT);
- if (! binfile)
- grub_errno = GRUB_ERR_NONE;
- /* Load the extension. */
- grub_xnu_load_driver (ctx.plistname, binfile,
- binname);
- grub_free (binname);
- grub_free (binsuffix);
- }
- else
- {
- grub_dprintf ("xnu", "%s:0\n", ctx.plistname);
- grub_xnu_load_driver (ctx.plistname, 0, 0);
- }
- }
- grub_free (ctx.plistname);
- grub_device_close (dev);
- }
- grub_free (device_name);
- return GRUB_ERR_NONE;
- }
- static int locked=0;
- static grub_dl_t my_mod;
- /* Load the kext. */
- static grub_err_t
- grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)),
- int argc, char *args[])
- {
- grub_file_t binfile = 0;
- if (! grub_xnu_heap_size)
- return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
- if (argc == 2)
- {
- /* User explicitly specified plist and binary. */
- if (grub_strcmp (args[1], "-") != 0)
- {
- binfile = grub_file_open (args[1], GRUB_FILE_TYPE_XNU_KEXT);
- if (! binfile)
- return grub_errno;
- }
- return grub_xnu_load_driver (grub_strcmp (args[0], "-") ? args[0] : 0,
- binfile, args[1]);
- }
- /* load kext normally. */
- if (argc == 1)
- return grub_xnu_load_kext_from_dir (args[0], 0, 10);
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
- }
- /* Load a directory containing kexts. */
- static grub_err_t
- grub_cmd_xnu_kextdir (grub_command_t cmd __attribute__ ((unused)),
- int argc, char *args[])
- {
- if (argc != 1 && argc != 2)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "directory name required");
- if (! grub_xnu_heap_size)
- return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
- if (argc == 1)
- return grub_xnu_scan_dir_for_kexts (args[0],
- "console,root,local-root,network-root",
- 10);
- else
- {
- char *osbundlerequired = grub_strdup (args[1]), *ptr;
- grub_err_t err;
- if (! osbundlerequired)
- return grub_errno;
- for (ptr = osbundlerequired; *ptr; ptr++)
- *ptr = grub_tolower (*ptr);
- err = grub_xnu_scan_dir_for_kexts (args[0], osbundlerequired, 10);
- grub_free (osbundlerequired);
- return err;
- }
- }
- static inline int
- hextoval (char c)
- {
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'a' && c <= 'z')
- return c - 'a' + 10;
- if (c >= 'A' && c <= 'Z')
- return c - 'A' + 10;
- return 0;
- }
- static inline void
- unescape (char *name, char *curdot, char *nextdot, int *len)
- {
- char *ptr, *dptr;
- dptr = name;
- for (ptr = curdot; ptr < nextdot;)
- if (ptr + 2 < nextdot && *ptr == '%')
- {
- *dptr = (hextoval (ptr[1]) << 4) | (hextoval (ptr[2]));
- ptr += 3;
- dptr++;
- }
- else
- {
- *dptr = *ptr;
- ptr++;
- dptr++;
- }
- *len = dptr - name;
- }
- grub_err_t
- grub_xnu_fill_devicetree (void)
- {
- struct grub_env_var *var;
- FOR_SORTED_ENV (var)
- {
- char *nextdot = 0, *curdot;
- struct grub_xnu_devtree_key **curkey = &grub_xnu_devtree_root;
- struct grub_xnu_devtree_key *curvalue;
- char *name = 0, *data;
- int len;
- if (grub_memcmp (var->name, "XNU.DeviceTree.",
- sizeof ("XNU.DeviceTree.") - 1) != 0)
- continue;
- curdot = var->name + sizeof ("XNU.DeviceTree.") - 1;
- nextdot = grub_strchr (curdot, '.');
- if (nextdot)
- nextdot++;
- while (nextdot)
- {
- name = grub_realloc (name, nextdot - curdot + 1);
- if (!name)
- return grub_errno;
- unescape (name, curdot, nextdot, &len);
- name[len - 1] = 0;
- curkey = &(grub_xnu_create_key (curkey, name)->first_child);
- curdot = nextdot;
- nextdot = grub_strchr (nextdot, '.');
- if (nextdot)
- nextdot++;
- }
- nextdot = curdot + grub_strlen (curdot) + 1;
- name = grub_realloc (name, nextdot - curdot + 1);
- if (!name)
- return grub_errno;
- unescape (name, curdot, nextdot, &len);
- name[len] = 0;
- curvalue = grub_xnu_create_value (curkey, name);
- grub_free (name);
- if (!curvalue)
- return grub_errno;
- data = grub_malloc (grub_strlen (var->value) + 1);
- if (!data)
- return grub_errno;
- unescape (data, var->value, var->value + grub_strlen (var->value),
- &len);
- curvalue->datasize = len;
- curvalue->data = data;
- }
- return grub_errno;
- }
- struct grub_video_bitmap *grub_xnu_bitmap = 0;
- grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode;
- /* Option array indices. */
- #define XNU_SPLASH_CMD_ARGINDEX_MODE 0
- static const struct grub_arg_option xnu_splash_cmd_options[] =
- {
- {"mode", 'm', 0, N_("Background image mode."), N_("stretch|normal"),
- ARG_TYPE_STRING},
- {0, 0, 0, 0, 0, 0}
- };
- static grub_err_t
- grub_cmd_xnu_splash (grub_extcmd_context_t ctxt,
- int argc, char *args[])
- {
- grub_err_t err;
- if (argc != 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
- if (! grub_xnu_heap_size)
- return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
- if (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set &&
- grub_strcmp (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg,
- "stretch") == 0)
- grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH;
- else
- grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_CENTER;
- err = grub_video_bitmap_load (&grub_xnu_bitmap, args[0]);
- if (err)
- grub_xnu_bitmap = 0;
- return err;
- }
- #ifndef GRUB_MACHINE_EMU
- static grub_err_t
- grub_cmd_xnu_resume (grub_command_t cmd __attribute__ ((unused)),
- int argc, char *args[])
- {
- if (argc != 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
- return grub_xnu_resume (args[0]);
- }
- #endif
- void
- grub_xnu_lock (void)
- {
- if (!locked)
- grub_dl_ref (my_mod);
- locked = 1;
- }
- void
- grub_xnu_unlock (void)
- {
- if (locked)
- grub_dl_unref (my_mod);
- locked = 0;
- }
- static grub_command_t cmd_kernel64, cmd_kernel, cmd_mkext, cmd_kext;
- static grub_command_t cmd_kextdir, cmd_ramdisk, cmd_resume;
- static grub_extcmd_t cmd_splash;
- GRUB_MOD_INIT(xnu)
- {
- cmd_kernel = grub_register_command ("xnu_kernel", grub_cmd_xnu_kernel, 0,
- N_("Load XNU image."));
- cmd_kernel64 = grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64,
- 0, N_("Load 64-bit XNU image."));
- cmd_mkext = grub_register_command_lockdown ("xnu_mkext", grub_cmd_xnu_mkext, 0,
- N_("Load XNU extension package."));
- cmd_kext = grub_register_command_lockdown ("xnu_kext", grub_cmd_xnu_kext, 0,
- N_("Load XNU extension."));
- cmd_kextdir = grub_register_command_lockdown ("xnu_kextdir", grub_cmd_xnu_kextdir,
- /*
- * TRANSLATORS: OSBundleRequired is
- * a variable name in xnu extensions
- * manifests. It behaves mostly like
- * GNU/Linux runlevels.
- */
- N_("DIRECTORY [OSBundleRequired]"),
- /*
- * TRANSLATORS: There are many extensions
- * in extension directory.
- */
- N_("Load XNU extension directory."));
- cmd_ramdisk = grub_register_command ("xnu_ramdisk", grub_cmd_xnu_ramdisk, 0,
- /* TRANSLATORS: ramdisk here isn't identifier. It can be translated. */
- N_("Load XNU ramdisk. "
- "It will be available in OS as md0."));
- cmd_splash = grub_register_extcmd ("xnu_splash",
- grub_cmd_xnu_splash, 0, 0,
- N_("Load a splash image for XNU."),
- xnu_splash_cmd_options);
- #ifndef GRUB_MACHINE_EMU
- cmd_resume = grub_register_command ("xnu_resume", grub_cmd_xnu_resume,
- 0, N_("Load an image of hibernated"
- " XNU."));
- #endif
- grub_cpu_xnu_init ();
- my_mod = mod;
- }
- GRUB_MOD_FINI(xnu)
- {
- #ifndef GRUB_MACHINE_EMU
- grub_unregister_command (cmd_resume);
- #endif
- grub_unregister_command (cmd_mkext);
- grub_unregister_command (cmd_kext);
- grub_unregister_command (cmd_kextdir);
- grub_unregister_command (cmd_ramdisk);
- grub_unregister_command (cmd_kernel);
- grub_unregister_extcmd (cmd_splash);
- grub_unregister_command (cmd_kernel64);
- grub_cpu_xnu_fini ();
- }
|