aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc64
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-05-01 11:58:45 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-01 11:58:45 -0400
commit66faf9845a05905d75da380767e93455f3e6d620 (patch)
treed58eb784e69f952ae7ac28271fd8482fee727e6b /arch/ppc64
parent58366af5861eee1479426380e3c91ecb334c301d (diff)
[PATCH] ppc64: tell firmware about kernel capabilities
On pSeries systems, according to the platform architecture specs, we are supposed to be supplying a structure to firmware that tells firmware about our capabilities, such as which version of the data structures that describe available memory we are expecting to see. The way we end up having to supply this data structure is a bit gross, since it was designed for AIX and doesn't suit us very well. This patch adds the code to supply this data structure to the firmware. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/ppc64')
-rw-r--r--arch/ppc64/boot/addnote.c60
-rw-r--r--arch/ppc64/kernel/prom_init.c107
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 */
22char arch[] = "PowerPC"; 23char 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 */
36char 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
45unsigned 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
34unsigned char buf[512]; 58unsigned 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 */
500static 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
586static 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