init.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. /* init.c -- Initialize GRUB on the newworld mac (PPC). */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <grub/kernel.h>
  20. #include <grub/dl.h>
  21. #include <grub/disk.h>
  22. #include <grub/mm.h>
  23. #include <grub/partition.h>
  24. #include <grub/normal.h>
  25. #include <grub/fs.h>
  26. #include <grub/setjmp.h>
  27. #include <grub/env.h>
  28. #include <grub/misc.h>
  29. #include <grub/time.h>
  30. #include <grub/ieee1275/console.h>
  31. #include <grub/ieee1275/ofdisk.h>
  32. #ifdef __sparc__
  33. #include <grub/ieee1275/obdisk.h>
  34. #endif
  35. #include <grub/ieee1275/ieee1275.h>
  36. #include <grub/net.h>
  37. #include <grub/offsets.h>
  38. #include <grub/memory.h>
  39. #include <grub/loader.h>
  40. #ifdef __i386__
  41. #include <grub/cpu/tsc.h>
  42. #endif
  43. #ifdef __sparc__
  44. #include <grub/machine/kernel.h>
  45. #endif
  46. /* The maximum heap size we're going to claim at boot. Not used by sparc. */
  47. #ifdef __i386__
  48. #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024)
  49. #else /* __powerpc__ */
  50. #define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024)
  51. #endif
  52. /* RMO max. address at 768 MB */
  53. #define RMO_ADDR_MAX (grub_uint64_t) (768 * 1024 * 1024)
  54. /*
  55. * The amount of OF space we will not claim here so as to leave space for
  56. * the loader and linux to service early allocations.
  57. *
  58. * In 2021, Daniel Axtens claims that we should leave at least 128MB to
  59. * ensure we can load a stock kernel and initrd on a pseries guest with
  60. * a 512MB real memory area under PowerVM.
  61. */
  62. #define RUNTIME_MIN_SPACE (128UL * 1024 * 1024)
  63. extern char _start[];
  64. extern char _end[];
  65. #ifdef __sparc__
  66. grub_addr_t grub_ieee1275_original_stack;
  67. #endif
  68. /* Options vector5 properties. */
  69. #define LPAR 0x80
  70. #define SPLPAR 0x40
  71. #define DYN_RCON_MEM 0x20
  72. #define LARGE_PAGES 0x10
  73. #define DONATE_DCPU_CLS 0x02
  74. #define PCI_EXP 0x01
  75. #define BYTE2 (LPAR | SPLPAR | DYN_RCON_MEM | LARGE_PAGES | DONATE_DCPU_CLS | PCI_EXP)
  76. #define CMOC 0x80
  77. #define EXT_CMO 0x40
  78. #define CMO (CMOC | EXT_CMO)
  79. #define ASSOC_REF 0x80
  80. #define AFFINITY 0x40
  81. #define NUMA 0x20
  82. #define ASSOCIATIVITY (ASSOC_REF | AFFINITY | NUMA)
  83. #define HOTPLUG_INTRPT 0x04
  84. #define HPT_RESIZE 0x01
  85. #define BIN_OPTS (HOTPLUG_INTRPT | HPT_RESIZE)
  86. #define MAX_CPU 256
  87. #define PFO_HWRNG 0x80000000
  88. #define PFO_HW_COMP 0x40000000
  89. #define PFO_ENCRYPT 0x20000000
  90. #define PLATFORM_FACILITIES (PFO_HWRNG | PFO_HW_COMP | PFO_ENCRYPT)
  91. #define SUB_PROCESSORS 1
  92. #define DY_MEM_V2 0x80
  93. #define DRC_INFO 0x40
  94. #define BYTE22 (DY_MEM_V2 | DRC_INFO)
  95. void
  96. grub_exit (void)
  97. {
  98. grub_ieee1275_exit ();
  99. }
  100. /* Translate an OF filesystem path (separated by backslashes), into a GRUB
  101. path (separated by forward slashes). */
  102. static void
  103. grub_translate_ieee1275_path (char *filepath)
  104. {
  105. char *backslash;
  106. backslash = grub_strchr (filepath, '\\');
  107. while (backslash != 0)
  108. {
  109. *backslash = '/';
  110. backslash = grub_strchr (filepath, '\\');
  111. }
  112. }
  113. void (*grub_ieee1275_net_config) (const char *dev, char **device, char **path,
  114. char *bootpath);
  115. void
  116. grub_machine_get_bootlocation (char **device, char **path)
  117. {
  118. char *bootpath;
  119. char *filename;
  120. char *type;
  121. bootpath = grub_ieee1275_get_boot_dev ();
  122. if (! bootpath)
  123. return;
  124. /* Transform an OF device path to a GRUB path. */
  125. type = grub_ieee1275_get_device_type (bootpath);
  126. if (type && grub_strcmp (type, "network") == 0)
  127. {
  128. char *dev, *canon;
  129. char *ptr;
  130. dev = grub_ieee1275_get_aliasdevname (bootpath);
  131. canon = grub_ieee1275_canonicalise_devname (dev);
  132. if (! canon)
  133. return;
  134. ptr = canon + grub_strlen (canon) - 1;
  135. while (ptr > canon && (*ptr == ',' || *ptr == ':'))
  136. ptr--;
  137. ptr++;
  138. *ptr = 0;
  139. if (grub_ieee1275_net_config)
  140. grub_ieee1275_net_config (canon, device, path, bootpath);
  141. grub_free (dev);
  142. grub_free (canon);
  143. }
  144. else
  145. *device = grub_ieee1275_encode_devname (bootpath);
  146. grub_free (type);
  147. filename = grub_ieee1275_get_filename (bootpath);
  148. if (filename)
  149. {
  150. char *lastslash = grub_strrchr (filename, '\\');
  151. /* Truncate at last directory. */
  152. if (lastslash)
  153. {
  154. *lastslash = '\0';
  155. grub_translate_ieee1275_path (filename);
  156. *path = filename;
  157. }
  158. }
  159. grub_free (bootpath);
  160. }
  161. /* Claim some available memory in the first /memory node. */
  162. #ifdef __sparc__
  163. static void
  164. grub_claim_heap (void)
  165. {
  166. grub_mm_init_region ((void *) (grub_modules_get_end ()
  167. + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000);
  168. }
  169. #else
  170. /* Helpers for mm on powerpc. */
  171. /*
  172. * How much memory does OF believe exists in total?
  173. *
  174. * This isn't necessarily the true total. It can be the total memory
  175. * accessible in real mode for a pseries guest, for example.
  176. */
  177. static grub_uint64_t rmo_top;
  178. static int
  179. count_free (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
  180. void *data)
  181. {
  182. if (type != GRUB_MEMORY_AVAILABLE)
  183. return 0;
  184. /* Do not consider memory beyond 4GB */
  185. if (addr > 0xffffffffULL)
  186. return 0;
  187. if (addr + len > 0xffffffffULL)
  188. len = 0xffffffffULL - addr;
  189. *(grub_uint32_t *) data += len;
  190. return 0;
  191. }
  192. static int
  193. regions_claim (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
  194. unsigned int flags, void *data)
  195. {
  196. grub_uint32_t total = *(grub_uint32_t *) data;
  197. grub_uint64_t linux_rmo_save;
  198. if (type != GRUB_MEMORY_AVAILABLE)
  199. return 0;
  200. /* Do not consider memory beyond 4GB */
  201. if (addr > 0xffffffffULL)
  202. return 0;
  203. if (addr + len > 0xffffffffULL)
  204. len = 0xffffffffULL - addr;
  205. if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM))
  206. {
  207. if (addr + len <= 0x180000)
  208. return 0;
  209. if (addr < 0x180000)
  210. {
  211. len = addr + len - 0x180000;
  212. addr = 0x180000;
  213. }
  214. }
  215. /* In theory, firmware should already prevent this from happening by not
  216. listing our own image in /memory/available. The check below is intended
  217. as a safeguard in case that doesn't happen. However, it doesn't protect
  218. us from corrupting our module area, which extends up to a
  219. yet-undetermined region above _end. */
  220. if ((addr < (grub_addr_t) _end) && ((addr + len) > (grub_addr_t) _start))
  221. {
  222. grub_printf ("Warning: attempt to claim over our own code!\n");
  223. len = 0;
  224. }
  225. /*
  226. * Linux likes to claim memory at min(RMO top, 768MB) and works down
  227. * without reference to /memory/available. (See prom_init.c::alloc_down)
  228. *
  229. * If this block contains min(RMO top, 768MB), do not claim below that for
  230. * at least a few MB (this is where RTAS, SML and potentially TCEs live).
  231. *
  232. * We also need to leave enough space for the DT in the RMA. (See
  233. * prom_init.c::alloc_up)
  234. *
  235. * Finally, we also want to make sure that when grub loads the kernel,
  236. * it isn't going to use up all the memory we're trying to reserve! So
  237. * enforce our entire RUNTIME_MIN_SPACE here:
  238. *
  239. * |---------- Top of memory ----------|
  240. * | |
  241. * | available |
  242. * | |
  243. * |---------- 768 MB ----------|
  244. * | |
  245. * | reserved |
  246. * | |
  247. * |--- 768 MB - runtime min space ---|
  248. * | |
  249. * | available |
  250. * | |
  251. * |---------- 0 MB ----------|
  252. *
  253. * Edge cases:
  254. *
  255. * - Total memory less than RUNTIME_MIN_SPACE: only claim up to HEAP_MAX_SIZE.
  256. * (enforced elsewhere)
  257. *
  258. * - Total memory between RUNTIME_MIN_SPACE and 768MB:
  259. *
  260. * |---------- Top of memory ----------|
  261. * | |
  262. * | reserved |
  263. * | |
  264. * |---- top - runtime min space ----|
  265. * | |
  266. * | available |
  267. * | |
  268. * |---------- 0 MB ----------|
  269. *
  270. * This by itself would not leave us with RUNTIME_MIN_SPACE of free bytes: if
  271. * rmo_top < 768MB, we will almost certainly have FW claims in the reserved
  272. * region. We try to address that elsewhere: grub_ieee1275_mm_add_region will
  273. * not call us if the resulting free space would be less than RUNTIME_MIN_SPACE.
  274. */
  275. linux_rmo_save = grub_min (RMO_ADDR_MAX, rmo_top) - RUNTIME_MIN_SPACE;
  276. if (rmo_top > RUNTIME_MIN_SPACE)
  277. {
  278. if (rmo_top <= RMO_ADDR_MAX)
  279. {
  280. if (addr > linux_rmo_save)
  281. {
  282. grub_dprintf ("ieee1275", "rejecting region in RUNTIME_MIN_SPACE reservation (%llx)\n",
  283. addr);
  284. return 0;
  285. }
  286. else if (addr + len > linux_rmo_save)
  287. {
  288. grub_dprintf ("ieee1275", "capping region: (%llx -> %llx) -> (%llx -> %llx)\n",
  289. addr, addr + len, addr, rmo_top - RUNTIME_MIN_SPACE);
  290. len = linux_rmo_save - addr;
  291. }
  292. }
  293. else
  294. {
  295. /*
  296. * we order these cases to prefer higher addresses and avoid some
  297. * splitting issues
  298. */
  299. if (addr < RMO_ADDR_MAX && (addr + len) > RMO_ADDR_MAX)
  300. {
  301. grub_dprintf ("ieee1275",
  302. "adjusting region for RUNTIME_MIN_SPACE: (%llx -> %llx) -> (%llx -> %llx)\n",
  303. addr, addr + len, RMO_ADDR_MAX, addr + len);
  304. len = (addr + len) - RMO_ADDR_MAX;
  305. addr = RMO_ADDR_MAX;
  306. }
  307. else if ((addr < linux_rmo_save) && ((addr + len) > linux_rmo_save))
  308. {
  309. grub_dprintf ("ieee1275", "capping region: (%llx -> %llx) -> (%llx -> %llx)\n",
  310. addr, addr + len, addr, linux_rmo_save);
  311. len = linux_rmo_save - addr;
  312. }
  313. else if (addr >= linux_rmo_save && (addr + len) <= RMO_ADDR_MAX)
  314. {
  315. grub_dprintf ("ieee1275", "rejecting region in RUNTIME_MIN_SPACE reservation (%llx)\n",
  316. addr);
  317. return 0;
  318. }
  319. }
  320. }
  321. if (flags & GRUB_MM_ADD_REGION_CONSECUTIVE && len < total)
  322. return 0;
  323. if (len > total)
  324. len = total;
  325. if (len)
  326. {
  327. grub_err_t err;
  328. /* Claim and use it. */
  329. err = grub_claimmap (addr, len);
  330. if (err)
  331. return err;
  332. grub_mm_init_region ((void *) (grub_addr_t) addr, len);
  333. total -= len;
  334. }
  335. *(grub_uint32_t *) data = total;
  336. if (total == 0)
  337. return 1;
  338. return 0;
  339. }
  340. static int
  341. heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
  342. void *data)
  343. {
  344. return regions_claim (addr, len, type, GRUB_MM_ADD_REGION_NONE, data);
  345. }
  346. static int
  347. region_claim (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
  348. void *data)
  349. {
  350. return regions_claim (addr, len, type, GRUB_MM_ADD_REGION_CONSECUTIVE, data);
  351. }
  352. static grub_err_t
  353. grub_ieee1275_mm_add_region (grub_size_t size, unsigned int flags)
  354. {
  355. grub_uint32_t free_memory = 0;
  356. grub_uint32_t avail = 0;
  357. grub_uint32_t total;
  358. grub_dprintf ("ieee1275", "mm requested region of size %x, flags %x\n",
  359. size, flags);
  360. /*
  361. * Update free memory each time, which is a bit inefficient but guards us
  362. * against a situation where some OF driver goes out to firmware for
  363. * memory and we don't realise.
  364. */
  365. grub_machine_mmap_iterate (count_free, &free_memory);
  366. /* Ensure we leave enough space to boot. */
  367. if (free_memory <= RUNTIME_MIN_SPACE + size)
  368. {
  369. grub_dprintf ("ieee1275", "Cannot satisfy allocation and retain minimum runtime space\n");
  370. return GRUB_ERR_OUT_OF_MEMORY;
  371. }
  372. if (free_memory > RUNTIME_MIN_SPACE)
  373. avail = free_memory - RUNTIME_MIN_SPACE;
  374. grub_dprintf ("ieee1275", "free = 0x%x available = 0x%x\n", free_memory, avail);
  375. if (flags & GRUB_MM_ADD_REGION_CONSECUTIVE)
  376. {
  377. /* first try rounding up hard for the sake of speed */
  378. total = grub_max (ALIGN_UP (size, 1024 * 1024) + 1024 * 1024, 32 * 1024 * 1024);
  379. total = grub_min (avail, total);
  380. grub_dprintf ("ieee1275", "looking for %x bytes of memory (%x requested)\n", total, size);
  381. grub_machine_mmap_iterate (region_claim, &total);
  382. grub_dprintf ("ieee1275", "get memory from fw %s\n", total == 0 ? "succeeded" : "failed");
  383. if (total != 0)
  384. {
  385. total = grub_min (avail, size);
  386. grub_dprintf ("ieee1275", "fallback for %x bytes of memory (%x requested)\n", total, size);
  387. grub_machine_mmap_iterate (region_claim, &total);
  388. grub_dprintf ("ieee1275", "fallback from fw %s\n", total == 0 ? "succeeded" : "failed");
  389. }
  390. }
  391. else
  392. {
  393. /* provide padding for a grub_mm_header_t and region */
  394. total = grub_min (avail, size);
  395. grub_machine_mmap_iterate (heap_init, &total);
  396. grub_dprintf ("ieee1275", "get noncontig memory from fw %s\n", total == 0 ? "succeeded" : "failed");
  397. }
  398. if (total == 0)
  399. return GRUB_ERR_NONE;
  400. else
  401. return GRUB_ERR_OUT_OF_MEMORY;
  402. }
  403. /*
  404. * How much memory does OF believe it has? (regardless of whether
  405. * it's accessible or not)
  406. */
  407. static grub_err_t
  408. grub_ieee1275_total_mem (grub_uint64_t *total)
  409. {
  410. grub_ieee1275_phandle_t root;
  411. grub_ieee1275_phandle_t memory;
  412. grub_uint32_t reg[4];
  413. grub_ssize_t reg_size;
  414. grub_uint32_t address_cells = 1;
  415. grub_uint32_t size_cells = 1;
  416. grub_uint64_t size;
  417. /* If we fail to get to the end, report 0. */
  418. *total = 0;
  419. /* Determine the format of each entry in `reg'. */
  420. if (grub_ieee1275_finddevice ("/", &root))
  421. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find / node");
  422. if (grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells,
  423. sizeof (address_cells), 0))
  424. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine #address-cells");
  425. if (grub_ieee1275_get_integer_property (root, "#size-cells", &size_cells,
  426. sizeof (size_cells), 0))
  427. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine #size-cells");
  428. if (size_cells > address_cells)
  429. address_cells = size_cells;
  430. /* Load `/memory/reg'. */
  431. if (grub_ieee1275_finddevice ("/memory", &memory))
  432. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find /memory node");
  433. if (grub_ieee1275_get_integer_property (memory, "reg", reg,
  434. sizeof (reg), &reg_size))
  435. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine /memory/reg property");
  436. if (reg_size < 0 || (grub_size_t) reg_size > sizeof (reg))
  437. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "/memory response buffer exceeded");
  438. if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS))
  439. {
  440. address_cells = 1;
  441. size_cells = 1;
  442. }
  443. /* Decode only the size */
  444. size = reg[address_cells];
  445. if (size_cells == 2)
  446. size = (size << 32) | reg[address_cells + 1];
  447. *total = size;
  448. return grub_errno;
  449. }
  450. #if defined(__powerpc__)
  451. /* See PAPR or arch/powerpc/kernel/prom_init.c */
  452. struct option_vector2
  453. {
  454. grub_uint8_t byte1;
  455. grub_uint16_t reserved;
  456. grub_uint32_t real_base;
  457. grub_uint32_t real_size;
  458. grub_uint32_t virt_base;
  459. grub_uint32_t virt_size;
  460. grub_uint32_t load_base;
  461. grub_uint32_t min_rma;
  462. grub_uint32_t min_load;
  463. grub_uint8_t min_rma_percent;
  464. grub_uint8_t max_pft_size;
  465. } GRUB_PACKED;
  466. struct option_vector5
  467. {
  468. grub_uint8_t byte1;
  469. grub_uint8_t byte2;
  470. grub_uint8_t byte3;
  471. grub_uint8_t cmo;
  472. grub_uint8_t associativity;
  473. grub_uint8_t bin_opts;
  474. grub_uint8_t micro_checkpoint;
  475. grub_uint8_t reserved0;
  476. grub_uint32_t max_cpus;
  477. grub_uint16_t base_papr;
  478. grub_uint16_t mem_reference;
  479. grub_uint32_t platform_facilities;
  480. grub_uint8_t sub_processors;
  481. grub_uint8_t byte22;
  482. } GRUB_PACKED;
  483. struct pvr_entry
  484. {
  485. grub_uint32_t mask;
  486. grub_uint32_t entry;
  487. };
  488. struct cas_vector
  489. {
  490. struct
  491. {
  492. struct pvr_entry terminal;
  493. } pvr_list;
  494. grub_uint8_t num_vecs;
  495. grub_uint8_t vec1_size;
  496. grub_uint8_t vec1;
  497. grub_uint8_t vec2_size;
  498. struct option_vector2 vec2;
  499. grub_uint8_t vec3_size;
  500. grub_uint16_t vec3;
  501. grub_uint8_t vec4_size;
  502. grub_uint16_t vec4;
  503. grub_uint8_t vec5_size;
  504. struct option_vector5 vec5;
  505. } GRUB_PACKED;
  506. /*
  507. * Call ibm,client-architecture-support to try to get more RMA.
  508. * We ask for 512MB which should be enough to verify a distro kernel.
  509. * We ignore most errors: if we don't succeed we'll proceed with whatever
  510. * memory we have.
  511. */
  512. static void
  513. grub_ieee1275_ibm_cas (void)
  514. {
  515. int rc;
  516. grub_ieee1275_ihandle_t root;
  517. struct cas_args
  518. {
  519. struct grub_ieee1275_common_hdr common;
  520. grub_ieee1275_cell_t method;
  521. grub_ieee1275_ihandle_t ihandle;
  522. grub_ieee1275_cell_t cas_addr;
  523. grub_ieee1275_cell_t result;
  524. } args;
  525. struct cas_vector vector =
  526. {
  527. .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */
  528. .num_vecs = 5 - 1,
  529. .vec1_size = 0,
  530. .vec1 = 0x80, /* ignore */
  531. .vec2_size = 1 + sizeof (struct option_vector2) - 2,
  532. .vec2 = {
  533. 0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48
  534. },
  535. .vec3_size = 2 - 1,
  536. .vec3 = 0x00e0, /* ask for FP + VMX + DFP but don't halt if unsatisfied */
  537. .vec4_size = 2 - 1,
  538. .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */
  539. .vec5_size = 1 + sizeof (struct option_vector5) - 2,
  540. .vec5 = {
  541. 0, BYTE2, 0, CMO, ASSOCIATIVITY, BIN_OPTS, 0, 0, MAX_CPU, 0, 0, PLATFORM_FACILITIES, SUB_PROCESSORS, BYTE22
  542. }
  543. };
  544. INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2);
  545. args.method = (grub_ieee1275_cell_t) "ibm,client-architecture-support";
  546. rc = grub_ieee1275_open ("/", &root);
  547. if (rc)
  548. {
  549. grub_error (GRUB_ERR_IO, "could not open root when trying to call CAS");
  550. return;
  551. }
  552. args.ihandle = root;
  553. args.cas_addr = (grub_ieee1275_cell_t) &vector;
  554. grub_printf ("Calling ibm,client-architecture-support from grub...");
  555. IEEE1275_CALL_ENTRY_FN (&args);
  556. grub_printf ("done\n");
  557. grub_ieee1275_close (root);
  558. }
  559. #endif /* __powerpc__ */
  560. static void
  561. grub_claim_heap (void)
  562. {
  563. grub_err_t err;
  564. grub_uint32_t total = HEAP_MAX_SIZE;
  565. err = grub_ieee1275_total_mem (&rmo_top);
  566. /*
  567. * If we cannot size the available memory, we can't be sure we're leaving
  568. * space for the kernel, initrd and things Linux loads early in boot. So only
  569. * allow further allocations from firmware on success
  570. */
  571. if (err == GRUB_ERR_NONE)
  572. grub_mm_add_region_fn = grub_ieee1275_mm_add_region;
  573. #if defined(__powerpc__)
  574. if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY))
  575. {
  576. /* if we have an error, don't call CAS, just hope for the best */
  577. if (err == GRUB_ERR_NONE && rmo_top < (512 * 1024 * 1024))
  578. grub_ieee1275_ibm_cas ();
  579. }
  580. #endif
  581. grub_machine_mmap_iterate (heap_init, &total);
  582. }
  583. #endif
  584. static void
  585. grub_parse_cmdline (void)
  586. {
  587. grub_ssize_t actual;
  588. char args[256];
  589. if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootargs", &args,
  590. sizeof args, &actual) == 0
  591. && actual > 1)
  592. {
  593. int i = 0;
  594. while (i < actual)
  595. {
  596. char *command = &args[i];
  597. char *end;
  598. char *val;
  599. end = grub_strchr (command, ';');
  600. if (end == 0)
  601. i = actual; /* No more commands after this one. */
  602. else
  603. {
  604. *end = '\0';
  605. i += end - command + 1;
  606. while (grub_isspace(args[i]))
  607. i++;
  608. }
  609. /* Process command. */
  610. val = grub_strchr (command, '=');
  611. if (val)
  612. {
  613. *val = '\0';
  614. grub_env_set (command, val + 1);
  615. }
  616. }
  617. }
  618. }
  619. grub_addr_t grub_modbase;
  620. void
  621. grub_machine_init (void)
  622. {
  623. grub_modbase = ALIGN_UP((grub_addr_t) _end
  624. + GRUB_KERNEL_MACHINE_MOD_GAP,
  625. GRUB_KERNEL_MACHINE_MOD_ALIGN);
  626. grub_ieee1275_init ();
  627. grub_console_init_early ();
  628. grub_claim_heap ();
  629. grub_console_init_lately ();
  630. #ifdef __sparc__
  631. grub_obdisk_init ();
  632. #else
  633. grub_ofdisk_init ();
  634. #endif
  635. grub_parse_cmdline ();
  636. #ifdef __i386__
  637. grub_tsc_init ();
  638. #else
  639. grub_install_get_time_ms (grub_rtc_get_time_ms);
  640. #endif
  641. }
  642. void
  643. grub_machine_fini (int flags)
  644. {
  645. if (flags & GRUB_LOADER_FLAG_NORETURN)
  646. {
  647. #ifdef __sparc__
  648. grub_obdisk_fini ();
  649. #else
  650. grub_ofdisk_fini ();
  651. #endif
  652. grub_console_fini ();
  653. }
  654. }
  655. grub_uint64_t
  656. grub_rtc_get_time_ms (void)
  657. {
  658. grub_uint32_t msecs = 0;
  659. grub_ieee1275_milliseconds (&msecs);
  660. return msecs;
  661. }