changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/bcm/bootargs.c

changeset 7309: 889b634159e5
parent: fc141b91ed8a
child: 7789bbc91c22
author: cinap_lenrek@felloff.net
date: Thu, 25 Jul 2019 08:19:12 +0200
permissions: -rw-r--r--
description: bcm, bcm64: add support for device tree parameter passing

the new raspberry pi 4 firmware for arm64 seems to have
broken atag support. so we now parse the device tree
structure to get the bootargs and memory configuration.
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 
7 #define BOOTARGS ((char*)CONFADDR)
8 #define BOOTARGSLEN ((KZERO+REBOOTADDR)-CONFADDR)
9 
10 #define MAXCONF 64
11 static char *confname[MAXCONF];
12 static char *confval[MAXCONF];
13 static int nconf;
14 static char maxmem[11];
15 
16 static int
17 findconf(char *k)
18 {
19  int i;
20 
21  for(i = 0; i < nconf; i++)
22  if(cistrcmp(confname[i], k) == 0)
23  return i;
24  return -1;
25 }
26 
27 static void
28 addconf(char *k, char *v)
29 {
30  int i;
31 
32  i = findconf(k);
33  if(i < 0){
34  if(nconf >= MAXCONF)
35  return;
36  i = nconf++;
37  confname[i] = k;
38  }
39  confval[i] = v;
40 }
41 
42 static void
43 plan9iniinit(char *s, int cmdline)
44 {
45  char *toks[MAXCONF];
46  int i, c, n;
47  char *v;
48 
49  if((c = *s) < ' ' || c >= 0x80)
50  return;
51  if(cmdline)
52  n = tokenize(s, toks, MAXCONF);
53  else
54  n = getfields(s, toks, MAXCONF, 1, "\n");
55  for(i = 0; i < n; i++){
56  if(toks[i][0] == '#')
57  continue;
58  v = strchr(toks[i], '=');
59  if(v == nil)
60  continue;
61  *v++ = '\0';
62  addconf(toks[i], v);
63  }
64 }
65 
66 typedef struct Devtree Devtree;
67 struct Devtree
68 {
69  uchar *base;
70  uchar *end;
71  char *stab;
72  char path[1024];
73 };
74 
75 enum {
76  DtHeader = 0xd00dfeed,
77  DtBeginNode = 1,
78  DtEndNode = 2,
79  DtProp = 3,
80  DtEnd = 9,
81 };
82 
83 static u32int
84 beget4(uchar *p)
85 {
86  return (u32int)p[0]<<24 | (u32int)p[1]<<16 | (u32int)p[2]<<8 | (u32int)p[3];
87 }
88 
89 static void
90 devtreeprop(char *path, char *key, void *val, int len)
91 {
92  if(strcmp(path, "/memory") == 0 && strcmp(key, "reg") == 0 && len == 3*4){
93  if(findconf("*maxmem") < 0){
94  uvlong top;
95 
96  top = (uvlong)beget4((uchar*)val)<<32 | beget4((uchar*)val+4);
97  top += beget4((uchar*)val+8);
98  snprint(maxmem, sizeof(maxmem), "%#llux", top);
99  addconf("*maxmem", maxmem);
100  }
101  return;
102  }
103  if(strcmp(path, "/chosen") == 0 && strcmp(key, "bootargs") == 0){
104  if(len > BOOTARGSLEN)
105  len = BOOTARGSLEN;
106  memmove(BOOTARGS, val, len);
107  plan9iniinit(BOOTARGS, 1);
108  return;
109  }
110 }
111 
112 static uchar*
113 devtreenode(Devtree *t, uchar *p, char *cp)
114 {
115  uchar *e = (uchar*)t->stab;
116  char *s;
117  int n;
118 
119  if(p+4 > e || beget4(p) != DtBeginNode)
120  return nil;
121  p += 4;
122  if((s = memchr((char*)p, 0, e - p)) == nil)
123  return nil;
124  n = s - (char*)p;
125  cp += n;
126  if(cp >= &t->path[sizeof(t->path)])
127  return nil;
128  memmove(cp - n, (char*)p, n);
129  *cp = 0;
130  p += (n + 4) & ~3;
131  while(p+12 <= e && beget4(p) == DtProp){
132  n = beget4(p+4);
133  if(p + 12 + n > e)
134  return nil;
135  s = t->stab + beget4(p+8);
136  if(s < t->stab || s >= (char*)t->end
137  || memchr(s, 0, (char*)t->end - s) == nil)
138  return nil;
139  devtreeprop(t->path, s, p+12, n);
140  p += 12 + ((n + 3) & ~3);
141  }
142  while(p+4 <= e && beget4(p) == DtBeginNode){
143  *cp = '/';
144  p = devtreenode(t, p, cp+1);
145  if(p == nil)
146  return nil;
147  }
148  if(p+4 > e || beget4(p) != DtEndNode)
149  return nil;
150  return p+4;
151 }
152 
153 static int
154 parsedevtree(uchar *base, uintptr len)
155 {
156  Devtree t[1];
157  u32int total;
158 
159  if(len < 28 || beget4(base) != DtHeader)
160  return -1;
161  total = beget4(base+4);
162  if(total < 28 || total > len)
163  return -1;
164  t->base = base;
165  t->end = t->base + total;
166  t->stab = (char*)base + beget4(base+12);
167  if(t->stab >= (char*)t->end)
168  return -1;
169  devtreenode(t, base + beget4(base+8), t->path);
170  return 0;
171 }
172 
173 typedef struct Atag Atag;
174 struct Atag {
175  u32int size; /* size of atag in words, including this header */
176  u32int tag; /* atag type */
177  union {
178  u32int data[1]; /* actually [size-2] */
179  /* AtagMem */
180  struct {
181  u32int size;
182  u32int base;
183  } mem;
184  /* AtagCmdLine */
185  char cmdline[1]; /* actually [4*(size-2)] */
186  };
187 };
188 
189 enum {
190  AtagNone = 0x00000000,
191  AtagCore = 0x54410001,
192  AtagMem = 0x54410002,
193  AtagCmdline = 0x54410009,
194 };
195 
196 static int
197 parseatags(char *base, uintptr len)
198 {
199  char x, *e = base;
200  Atag *a;
201 
202  if(e+8 > base+len)
203  return -1;
204  a = (Atag*)e;
205  if(a->tag != AtagCore)
206  return -1;
207  while(a->tag != AtagNone){
208  e += a->size * sizeof(u32int);
209  if(a->size < 2 || e < (char*)a || e > base+len)
210  break;
211  switch(a->tag){
212  case AtagMem:
213  if(findconf("*maxmem") < 0){
214  snprint(maxmem, sizeof(maxmem), "%ud", a->mem.base+a->mem.size);
215  addconf("*maxmem", maxmem);
216  }
217  break;
218  case AtagCmdline:
219  x = *e;
220  *e = 0;
221  plan9iniinit(a->cmdline, 1);
222  *e = x;
223  break;
224  }
225  if(e+8 > base+len)
226  break;
227  a = (Atag*)e;
228  }
229  return 0;
230 }
231 
232 void
233 bootargsinit(uintptr pa)
234 {
235  uintptr len;
236 
237  /*
238  * kernel gets DTB/ATAGS pointer in R0 on entry
239  */
240  if(pa != 0 && (len = cankaddr(pa)) != 0){
241  void *va = KADDR(pa);
242  if(parseatags(va, len) == 0 || parsedevtree(va, len) == 0)
243  return;
244  }
245 
246  /*
247  * /dev/reboot case, check CONFADDR
248  */
249  if(parseatags(BOOTARGS, BOOTARGSLEN) != 0)
250  plan9iniinit(BOOTARGS, 0);
251 }
252 
253 char*
254 getconf(char *name)
255 {
256  int i;
257 
258  if((i = findconf(name)) < 0)
259  return nil;
260  return confval[i];
261 }
262 
263 void
264 setconfenv(void)
265 {
266  int i;
267 
268  for(i = 0; i < nconf; i++){
269  if(confname[i][0] != '*')
270  ksetenv(confname[i], confval[i], 0);
271  ksetenv(confname[i], confval[i], 1);
272  }
273 }
274 
275 void
276 writeconf(void)
277 {
278  char *p, *q;
279  int n;
280 
281  p = getconfenv();
282  if(waserror()) {
283  free(p);
284  nexterror();
285  }
286 
287  /* convert to name=value\n format */
288  for(q=p; *q; q++) {
289  q += strlen(q);
290  *q = '=';
291  q += strlen(q);
292  *q = '\n';
293  }
294  n = q - p + 1;
295  if(n >= BOOTARGSLEN)
296  error("kernel configuration too large");
297  memmove(BOOTARGS, p, n);
298  memset(BOOTARGS+n, 0, BOOTARGSLEN-n);
299  poperror();
300  free(p);
301 }