return 0;
}
+/*
+ * How much memory does OF believe it has? (regardless of whether
+ * it's accessible or not)
+ */
+static grub_err_t
+grub_ieee1275_total_mem (grub_uint64_t *total)
+{
+ grub_ieee1275_phandle_t root;
+ grub_ieee1275_phandle_t memory;
+ grub_uint32_t reg[4];
+ grub_ssize_t reg_size;
+ grub_uint32_t address_cells = 1;
+ grub_uint32_t size_cells = 1;
+ grub_uint64_t size;
+
+ /* If we fail to get to the end, report 0. */
+ *total = 0;
+
+ /* Determine the format of each entry in `reg'. */
+ if (grub_ieee1275_finddevice ("/", &root))
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find / node");
+ if (grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells,
+ sizeof (address_cells), 0))
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine #address-cells");
+ if (grub_ieee1275_get_integer_property (root, "#size-cells", &size_cells,
+ sizeof (size_cells), 0))
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine #size-cells");
+
+ if (size_cells > address_cells)
+ address_cells = size_cells;
+
+ /* Load `/memory/reg'. */
+ if (grub_ieee1275_finddevice ("/memory", &memory))
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find /memory node");
+ if (grub_ieee1275_get_integer_property (memory, "reg", reg,
+ sizeof (reg), ®_size))
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine /memory/reg property");
+ if (reg_size < 0 || (grub_size_t) reg_size > sizeof (reg))
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "/memory response buffer exceeded");
+
+ if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS))
+ {
+ address_cells = 1;
+ size_cells = 1;
+ }
+
+ /* Decode only the size */
+ size = reg[address_cells];
+ if (size_cells == 2)
+ size = (size << 32) | reg[address_cells + 1];
+
+ *total = size;
+
+ return grub_errno;
+}
+
+#if defined(__powerpc__)
+
+/* See PAPR or arch/powerpc/kernel/prom_init.c */
+struct option_vector2
+{
+ grub_uint8_t byte1;
+ grub_uint16_t reserved;
+ grub_uint32_t real_base;
+ grub_uint32_t real_size;
+ grub_uint32_t virt_base;
+ grub_uint32_t virt_size;
+ grub_uint32_t load_base;
+ grub_uint32_t min_rma;
+ grub_uint32_t min_load;
+ grub_uint8_t min_rma_percent;
+ grub_uint8_t max_pft_size;
+} GRUB_PACKED;
+
+struct pvr_entry
+{
+ grub_uint32_t mask;
+ grub_uint32_t entry;
+};
+
+struct cas_vector
+{
+ struct
+ {
+ struct pvr_entry terminal;
+ } pvr_list;
+ grub_uint8_t num_vecs;
+ grub_uint8_t vec1_size;
+ grub_uint8_t vec1;
+ grub_uint8_t vec2_size;
+ struct option_vector2 vec2;
+ grub_uint8_t vec3_size;
+ grub_uint16_t vec3;
+ grub_uint8_t vec4_size;
+ grub_uint16_t vec4;
+} GRUB_PACKED;
+
+/*
+ * Call ibm,client-architecture-support to try to get more RMA.
+ * We ask for 512MB which should be enough to verify a distro kernel.
+ * We ignore most errors: if we don't succeed we'll proceed with whatever
+ * memory we have.
+ */
+static void
+grub_ieee1275_ibm_cas (void)
+{
+ int rc;
+ grub_ieee1275_ihandle_t root;
+ struct cas_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t method;
+ grub_ieee1275_ihandle_t ihandle;
+ grub_ieee1275_cell_t cas_addr;
+ grub_ieee1275_cell_t result;
+ } args;
+ struct cas_vector vector =
+ {
+ .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */
+ .num_vecs = 4 - 1,
+ .vec1_size = 0,
+ .vec1 = 0x80, /* ignore */
+ .vec2_size = 1 + sizeof (struct option_vector2) - 2,
+ .vec2 = {
+ 0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48
+ },
+ .vec3_size = 2 - 1,
+ .vec3 = 0x00e0, /* ask for FP + VMX + DFP but don't halt if unsatisfied */
+ .vec4_size = 2 - 1,
+ .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */
+ };
+
+ INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2);
+ args.method = (grub_ieee1275_cell_t) "ibm,client-architecture-support";
+ rc = grub_ieee1275_open ("/", &root);
+ if (rc)
+ {
+ grub_error (GRUB_ERR_IO, "could not open root when trying to call CAS");
+ return;
+ }
+ args.ihandle = root;
+ args.cas_addr = (grub_ieee1275_cell_t) &vector;
+
+ grub_printf ("Calling ibm,client-architecture-support from grub...");
+ IEEE1275_CALL_ENTRY_FN (&args);
+ grub_printf ("done\n");
+
+ grub_ieee1275_close (root);
+}
+
+#endif /* __powerpc__ */
+
static void
grub_claim_heap (void)
{
unsigned long total = 0;
+#if defined(__powerpc__)
+ if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY))
+ {
+ grub_uint64_t rma_size;
+ grub_err_t err;
+
+ err = grub_ieee1275_total_mem (&rma_size);
+ /* if we have an error, don't call CAS, just hope for the best */
+ if (err == GRUB_ERR_NONE && rma_size < (512 * 1024 * 1024))
+ grub_ieee1275_ibm_cas ();
+ }
+#endif
+
grub_machine_mmap_iterate (heap_init, &total);
}
#endif