@@ 334,7 334,10 @@ static int patch_elf_info(void)
if (strncmp(line, "cpu model", 9) == 0) {
/* OCTEON uses a different page_offset. */
if (strstr(line, "Octeon"))
- elf_info64.page_offset = 0x8000000000000000ULL;
+ elf_info64.page_offset = OCTEON_PAGE_OFFSET;
+ /* LOONGSON uses a different page_offset. */
+ else if (strstr(line, "Loongson"))
+ elf_info64.page_offset = LOONGSON_PAGE_OFFSET;
break;
}
}
@@ 13,6 13,8 @@ int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
#endif
#define __pa(x) ((unsigned long)(X) & 0x7fffffff)
+#define LOONGSON_PAGE_OFFSET 0xffffffff80000000ULL
+#define OCTEON_PAGE_OFFSET 0x8000000000000000ULL
#define CRASH_MAX_MEMMAP_NR (KEXEC_MAX_SEGMENTS + 1)
#define CRASH_MAX_MEMORY_RANGES (MAX_MEMORY_RANGES + 2)
@@ 40,6 40,77 @@ static const int probe_debug = 0;
#define CMDLINE_PREFIX "kexec "
static char cmdline_buf[COMMAND_LINE_SIZE] = CMDLINE_PREFIX;
+/* Converts unsigned long to ascii string. */
+static void ultoa(unsigned long i, char *str)
+{
+ int j = 0, k;
+ char tmp;
+
+ do {
+ str[j++] = i % 10 + '0';
+ } while ((i /= 10) > 0);
+ str[j] = '\0';
+
+ /* Reverse the string. */
+ for (j = 0, k = strlen(str) - 1; j < k; j++, k--) {
+ tmp = str[k];
+ str[k] = str[j];
+ str[j] = tmp;
+ }
+}
+
+/* Adds initrd parameters to command line. */
+static int cmdline_add_initrd(char *cmdline, unsigned long addr, char *new_para)
+{
+ int cmdlen, len;
+ char str[30], *ptr;
+
+ ptr = str;
+ strcpy(str, new_para);
+ ptr += strlen(str);
+ ultoa(addr, ptr);
+ len = strlen(str);
+ cmdlen = strlen(cmdline) + len;
+ if (cmdlen > (COMMAND_LINE_SIZE - 1))
+ die("Command line overflow\n");
+ strcat(cmdline, str);
+
+ return 0;
+}
+
+/* add initrd to cmdline to compatible with previous platforms. */
+static int patch_initrd_info(char *cmdline, unsigned long base,
+ unsigned long size)
+{
+ const char cpuinfo[] = "/proc/cpuinfo";
+ char line[MAX_LINE];
+ FILE *fp;
+ unsigned long page_offset = PAGE_OFFSET;
+
+ fp = fopen(cpuinfo, "r");
+ if (!fp) {
+ fprintf(stderr, "Cannot open %s: %s\n",
+ cpuinfo, strerror(errno));
+ return -1;
+ }
+ while (fgets(line, sizeof(line), fp) != 0) {
+ if (strncmp(line, "cpu model", 9) == 0) {
+ if (strstr(line, "Loongson")) {
+ /* LOONGSON64 uses a different page_offset. */
+ if (arch_options.core_header_type ==
+ CORE_TYPE_ELF64)
+ page_offset = LOONGSON_PAGE_OFFSET;
+ cmdline_add_initrd(cmdline,
+ page_offset + base, " rd_start=");
+ cmdline_add_initrd(cmdline, size, " rd_size=");
+ break;
+ }
+ }
+ }
+ fclose(fp);
+ return 0;
+}
+
int elf_mips_probe(const char *buf, off_t len)
{
struct mem_ehdr ehdr;
@@ 171,9 242,10 @@ int elf_mips_load(int argc, char **argv, const char *buf, off_t len,
/* Now that the buffer for initrd is prepared, update the dtb
* with an appropriate location */
dtb_set_initrd(&dtb_buf, &dtb_length, initrd_base, initrd_base + initrd_size);
- }
-
+ /* Add the initrd parameters to cmdline */
+ patch_initrd_info(cmdline_buf, initrd_base, initrd_size);
+ }
/* This is a legacy method for commandline passing used
* currently by Octeon CPUs only */
add_buffer(info, cmdline_buf, sizeof(cmdline_buf),