diff options
| -rw-r--r-- | arch/ppc64/boot/addnote.c | 60 | ||||
| -rw-r--r-- | arch/ppc64/kernel/prom_init.c | 107 |
2 files changed, 157 insertions, 10 deletions
diff --git a/arch/ppc64/boot/addnote.c b/arch/ppc64/boot/addnote.c index 66ff8103bf4d..719663a694bb 100644 --- a/arch/ppc64/boot/addnote.c +++ b/arch/ppc64/boot/addnote.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <unistd.h> | 19 | #include <unistd.h> |
| 20 | #include <string.h> | 20 | #include <string.h> |
| 21 | 21 | ||
| 22 | /* CHRP note section */ | ||
| 22 | char arch[] = "PowerPC"; | 23 | char arch[] = "PowerPC"; |
| 23 | 24 | ||
| 24 | #define N_DESCR 6 | 25 | #define N_DESCR 6 |
| @@ -31,6 +32,29 @@ unsigned int descr[N_DESCR] = { | |||
| 31 | 0x4000, /* load-base */ | 32 | 0x4000, /* load-base */ |
| 32 | }; | 33 | }; |
| 33 | 34 | ||
| 35 | /* RPA note section */ | ||
| 36 | char rpaname[] = "IBM,RPA-Client-Config"; | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Note: setting ignore_my_client_config *should* mean that OF ignores | ||
| 40 | * all the other fields, but there is a firmware bug which means that | ||
| 41 | * it looks at the splpar field at least. So these values need to be | ||
| 42 | * reasonable. | ||
| 43 | */ | ||
| 44 | #define N_RPA_DESCR 8 | ||
| 45 | unsigned int rpanote[N_RPA_DESCR] = { | ||
| 46 | 0, /* lparaffinity */ | ||
| 47 | 64, /* min_rmo_size */ | ||
| 48 | 0, /* min_rmo_percent */ | ||
| 49 | 40, /* max_pft_size */ | ||
| 50 | 1, /* splpar */ | ||
| 51 | -1, /* min_load */ | ||
| 52 | 0, /* new_mem_def */ | ||
| 53 | 1, /* ignore_my_client_config */ | ||
| 54 | }; | ||
| 55 | |||
| 56 | #define ROUNDUP(len) (((len) + 3) & ~3) | ||
| 57 | |||
| 34 | unsigned char buf[512]; | 58 | unsigned char buf[512]; |
| 35 | 59 | ||
| 36 | #define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) | 60 | #define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) |
| @@ -69,7 +93,7 @@ main(int ac, char **av) | |||
| 69 | { | 93 | { |
| 70 | int fd, n, i; | 94 | int fd, n, i; |
| 71 | int ph, ps, np; | 95 | int ph, ps, np; |
| 72 | int nnote, ns; | 96 | int nnote, nnote2, ns; |
| 73 | 97 | ||
| 74 | if (ac != 2) { | 98 | if (ac != 2) { |
| 75 | fprintf(stderr, "Usage: %s elf-file\n", av[0]); | 99 | fprintf(stderr, "Usage: %s elf-file\n", av[0]); |
| @@ -81,7 +105,8 @@ main(int ac, char **av) | |||
| 81 | exit(1); | 105 | exit(1); |
| 82 | } | 106 | } |
| 83 | 107 | ||
| 84 | nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4; | 108 | nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr); |
| 109 | nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote); | ||
| 85 | 110 | ||
| 86 | n = read(fd, buf, sizeof(buf)); | 111 | n = read(fd, buf, sizeof(buf)); |
| 87 | if (n < 0) { | 112 | if (n < 0) { |
| @@ -104,7 +129,7 @@ main(int ac, char **av) | |||
| 104 | np = GET_16BE(E_PHNUM); | 129 | np = GET_16BE(E_PHNUM); |
| 105 | if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) | 130 | if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) |
| 106 | goto notelf; | 131 | goto notelf; |
| 107 | if (ph + (np + 1) * ps + nnote > n) | 132 | if (ph + (np + 2) * ps + nnote + nnote2 > n) |
| 108 | goto nospace; | 133 | goto nospace; |
| 109 | 134 | ||
| 110 | for (i = 0; i < np; ++i) { | 135 | for (i = 0; i < np; ++i) { |
| @@ -117,12 +142,12 @@ main(int ac, char **av) | |||
| 117 | } | 142 | } |
| 118 | 143 | ||
| 119 | /* XXX check that the area we want to use is all zeroes */ | 144 | /* XXX check that the area we want to use is all zeroes */ |
| 120 | for (i = 0; i < ps + nnote; ++i) | 145 | for (i = 0; i < 2 * ps + nnote + nnote2; ++i) |
| 121 | if (buf[ph + i] != 0) | 146 | if (buf[ph + i] != 0) |
| 122 | goto nospace; | 147 | goto nospace; |
| 123 | 148 | ||
| 124 | /* fill in the program header entry */ | 149 | /* fill in the program header entry */ |
| 125 | ns = ph + ps; | 150 | ns = ph + 2 * ps; |
| 126 | PUT_32BE(ph + PH_TYPE, PT_NOTE); | 151 | PUT_32BE(ph + PH_TYPE, PT_NOTE); |
| 127 | PUT_32BE(ph + PH_OFFSET, ns); | 152 | PUT_32BE(ph + PH_OFFSET, ns); |
| 128 | PUT_32BE(ph + PH_FILESZ, nnote); | 153 | PUT_32BE(ph + PH_FILESZ, nnote); |
| @@ -134,11 +159,26 @@ main(int ac, char **av) | |||
| 134 | PUT_32BE(ns + 8, 0x1275); | 159 | PUT_32BE(ns + 8, 0x1275); |
| 135 | strcpy(&buf[ns + 12], arch); | 160 | strcpy(&buf[ns + 12], arch); |
| 136 | ns += 12 + strlen(arch) + 1; | 161 | ns += 12 + strlen(arch) + 1; |
| 137 | for (i = 0; i < N_DESCR; ++i) | 162 | for (i = 0; i < N_DESCR; ++i, ns += 4) |
| 138 | PUT_32BE(ns + i * 4, descr[i]); | 163 | PUT_32BE(ns, descr[i]); |
| 164 | |||
| 165 | /* fill in the second program header entry and the RPA note area */ | ||
| 166 | ph += ps; | ||
| 167 | PUT_32BE(ph + PH_TYPE, PT_NOTE); | ||
| 168 | PUT_32BE(ph + PH_OFFSET, ns); | ||
| 169 | PUT_32BE(ph + PH_FILESZ, nnote2); | ||
| 170 | |||
| 171 | /* fill in the note area we point to */ | ||
| 172 | PUT_32BE(ns, strlen(rpaname) + 1); | ||
| 173 | PUT_32BE(ns + 4, sizeof(rpanote)); | ||
| 174 | PUT_32BE(ns + 8, 0x12759999); | ||
| 175 | strcpy(&buf[ns + 12], rpaname); | ||
| 176 | ns += 12 + ROUNDUP(strlen(rpaname) + 1); | ||
| 177 | for (i = 0; i < N_RPA_DESCR; ++i, ns += 4) | ||
| 178 | PUT_32BE(ns, rpanote[i]); | ||
| 139 | 179 | ||
| 140 | /* Update the number of program headers */ | 180 | /* Update the number of program headers */ |
| 141 | PUT_16BE(E_PHNUM, np + 1); | 181 | PUT_16BE(E_PHNUM, np + 2); |
| 142 | 182 | ||
| 143 | /* write back */ | 183 | /* write back */ |
| 144 | lseek(fd, (long) 0, SEEK_SET); | 184 | lseek(fd, (long) 0, SEEK_SET); |
| @@ -155,11 +195,11 @@ main(int ac, char **av) | |||
| 155 | exit(0); | 195 | exit(0); |
| 156 | 196 | ||
| 157 | notelf: | 197 | notelf: |
| 158 | fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]); | 198 | fprintf(stderr, "%s does not appear to be an ELF file\n", av[1]); |
| 159 | exit(1); | 199 | exit(1); |
| 160 | 200 | ||
| 161 | nospace: | 201 | nospace: |
| 162 | fprintf(stderr, "sorry, I can't find space in %s to put the note\n", | 202 | fprintf(stderr, "sorry, I can't find space in %s to put the note\n", |
| 163 | av[0]); | 203 | av[1]); |
| 164 | exit(1); | 204 | exit(1); |
| 165 | } | 205 | } |
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index 8dffa9ae2623..b0b784f9a4ea 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c | |||
| @@ -493,6 +493,113 @@ static void __init early_cmdline_parse(void) | |||
| 493 | } | 493 | } |
| 494 | 494 | ||
| 495 | /* | 495 | /* |
| 496 | * To tell the firmware what our capabilities are, we have to pass | ||
| 497 | * it a fake 32-bit ELF header containing a couple of PT_NOTE sections | ||
| 498 | * that contain structures that contain the actual values. | ||
| 499 | */ | ||
| 500 | static struct fake_elf { | ||
| 501 | Elf32_Ehdr elfhdr; | ||
| 502 | Elf32_Phdr phdr[2]; | ||
| 503 | struct chrpnote { | ||
| 504 | u32 namesz; | ||
| 505 | u32 descsz; | ||
| 506 | u32 type; | ||
| 507 | char name[8]; /* "PowerPC" */ | ||
| 508 | struct chrpdesc { | ||
| 509 | u32 real_mode; | ||
| 510 | u32 real_base; | ||
| 511 | u32 real_size; | ||
| 512 | u32 virt_base; | ||
| 513 | u32 virt_size; | ||
| 514 | u32 load_base; | ||
| 515 | } chrpdesc; | ||
| 516 | } chrpnote; | ||
| 517 | struct rpanote { | ||
| 518 | u32 namesz; | ||
| 519 | u32 descsz; | ||
| 520 | u32 type; | ||
| 521 | char name[24]; /* "IBM,RPA-Client-Config" */ | ||
| 522 | struct rpadesc { | ||
| 523 | u32 lpar_affinity; | ||
| 524 | u32 min_rmo_size; | ||
| 525 | u32 min_rmo_percent; | ||
| 526 | u32 max_pft_size; | ||
| 527 | u32 splpar; | ||
| 528 | u32 min_load; | ||
| 529 | u32 new_mem_def; | ||
| 530 | u32 ignore_me; | ||
| 531 | } rpadesc; | ||
| 532 | } rpanote; | ||
| 533 | } fake_elf = { | ||
| 534 | .elfhdr = { | ||
| 535 | .e_ident = { 0x7f, 'E', 'L', 'F', | ||
| 536 | ELFCLASS32, ELFDATA2MSB, EV_CURRENT }, | ||
| 537 | .e_type = ET_EXEC, /* yeah right */ | ||
| 538 | .e_machine = EM_PPC, | ||
| 539 | .e_version = EV_CURRENT, | ||
| 540 | .e_phoff = offsetof(struct fake_elf, phdr), | ||
| 541 | .e_phentsize = sizeof(Elf32_Phdr), | ||
| 542 | .e_phnum = 2 | ||
| 543 | }, | ||
| 544 | .phdr = { | ||
| 545 | [0] = { | ||
| 546 | .p_type = PT_NOTE, | ||
| 547 | .p_offset = offsetof(struct fake_elf, chrpnote), | ||
| 548 | .p_filesz = sizeof(struct chrpnote) | ||
| 549 | }, [1] = { | ||
| 550 | .p_type = PT_NOTE, | ||
| 551 | .p_offset = offsetof(struct fake_elf, rpanote), | ||
| 552 | .p_filesz = sizeof(struct rpanote) | ||
| 553 | } | ||
| 554 | }, | ||
| 555 | .chrpnote = { | ||
| 556 | .namesz = sizeof("PowerPC"), | ||
| 557 | .descsz = sizeof(struct chrpdesc), | ||
| 558 | .type = 0x1275, | ||
| 559 | .name = "PowerPC", | ||
| 560 | .chrpdesc = { | ||
| 561 | .real_mode = ~0U, /* ~0 means "don't care" */ | ||
| 562 | .real_base = ~0U, | ||
| 563 | .real_size = ~0U, | ||
| 564 | .virt_base = ~0U, | ||
| 565 | .virt_size = ~0U, | ||
| 566 | .load_base = ~0U | ||
| 567 | }, | ||
| 568 | }, | ||
| 569 | .rpanote = { | ||
| 570 | .namesz = sizeof("IBM,RPA-Client-Config"), | ||
| 571 | .descsz = sizeof(struct rpadesc), | ||
| 572 | .type = 0x12759999, | ||
| 573 | .name = "IBM,RPA-Client-Config", | ||
| 574 | .rpadesc = { | ||
| 575 | .lpar_affinity = 0, | ||
| 576 | .min_rmo_size = 64, /* in megabytes */ | ||
| 577 | .min_rmo_percent = 0, | ||
| 578 | .max_pft_size = 48, /* 2^48 bytes max PFT size */ | ||
| 579 | .splpar = 1, | ||
| 580 | .min_load = ~0U, | ||
| 581 | .new_mem_def = 0 | ||
| 582 | } | ||
| 583 | } | ||
| 584 | }; | ||
| 585 | |||
| 586 | static void __init prom_send_capabilities(void) | ||
| 587 | { | ||
| 588 | unsigned long offset = reloc_offset(); | ||
| 589 | ihandle elfloader; | ||
| 590 | int ret; | ||
| 591 | |||
| 592 | elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader")); | ||
| 593 | if (elfloader == 0) { | ||
| 594 | prom_printf("couldn't open /packages/elf-loader\n"); | ||
| 595 | return; | ||
| 596 | } | ||
| 597 | ret = call_prom("call-method", 3, 1, ADDR("process-elf-header"), | ||
| 598 | elfloader, ADDR(&fake_elf)); | ||
| 599 | call_prom("close", 1, 0, elfloader); | ||
| 600 | } | ||
| 601 | |||
| 602 | /* | ||
| 496 | * Memory allocation strategy... our layout is normally: | 603 | * Memory allocation strategy... our layout is normally: |
| 497 | * | 604 | * |
| 498 | * at 14Mb or more we vmlinux, then a gap and initrd. In some rare cases, initrd | 605 | * at 14Mb or more we vmlinux, then a gap and initrd. In some rare cases, initrd |
