~ubuntu-branches/ubuntu/precise/kexec-tools/precise-proposed

« back to all changes in this revision

Viewing changes to kexec/arch/ppc64/fs2dt.c

  • Committer: Bazaar Package Importer
  • Author(s): Andy Whitcroft
  • Date: 2011-05-23 11:23:37 UTC
  • mfrom: (2.2.6 sid)
  • Revision ID: james.westby@ubuntu.com-20110523112337-p2640osyy937p45i
Tags: 1:2.0.2-1ubuntu1
* Merge with Debian.
  - Drop DEBIAN.readme taking debian upstream version
  - Drop ubuntu patch arm-higher-initrd-load-addr dpatch as initrd
    locations are now calculated from the current size assuming maximum
    compression of * 4.
  - Remaining changes:
    + Run aclocal during build; build-dep on automake1.9.
    + Add and install kdump init script and initramfs snippet; depend on
      initramfs-tools and call the update-initramfs trigger.  Also call
      update-grub after update-initramfs trigger.
    + Default to not kexecing a kernel on boot in the automatically
      generated conffile.
    + --no-undefined is a linker option, not a gcc option.

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
 
36
36
#define MAXPATH 1024            /* max path name length */
37
37
#define NAMESPACE 16384         /* max bytes for property names */
38
 
#define TREEWORDS 65536         /* max 32 bit words for property values */
 
38
#define INIT_TREE_WORDS 65536   /* Initial num words for prop values */
39
39
#define MEMRESERVE 256          /* max number of reserved memory blocks */
40
 
#define MAX_MEMORY_RANGES 1024
 
40
#define MEM_RANGE_CHUNK_SZ 2048 /* Initial num dwords for mem ranges */
41
41
 
42
42
static char pathname[MAXPATH], *pathstart;
43
43
static char propnames[NAMESPACE] = { 0 };
44
 
static unsigned dtstruct[TREEWORDS] __attribute__ ((aligned (8))), *dt;
 
44
static unsigned *dt_base, *dt;
 
45
static unsigned int dt_cur_size;
45
46
static unsigned long long mem_rsrv[2*MEMRESERVE] = { 0, 0 };
46
47
 
47
48
static int crash_param = 0;
48
49
static char local_cmdline[COMMAND_LINE_SIZE] = { "" };
49
50
extern mem_rgns_t usablemem_rgns;
50
51
static struct bootblock bb[1];
 
52
extern int my_debug;
 
53
 
 
54
/* Before we add something to the dt, reserve N words using this.
 
55
 * If there isn't enough room, it's realloced -- and you don't overflow and
 
56
 * splat bits of your heap. 
 
57
 */
 
58
void dt_reserve(unsigned **dt_ptr, unsigned words)
 
59
{
 
60
        if (((*dt_ptr - dt_base) + words) >= dt_cur_size) {
 
61
                int offset;
 
62
                unsigned int new_size = dt_cur_size + INIT_TREE_WORDS;
 
63
                unsigned *new_dt = realloc(dt_base, new_size*4);
 
64
 
 
65
                if (!new_dt)
 
66
                        die("unrecoverable error: Can't realloc %d bytes for "
 
67
                            "device tree\n", new_size*4);
 
68
                offset = *dt_ptr - dt_base;
 
69
                dt_base = new_dt;
 
70
                dt_cur_size = new_size;
 
71
                *dt_ptr = dt_base + offset;
 
72
                memset(*dt_ptr, 0, (new_size - offset)*4);
 
73
        }
 
74
}
51
75
 
52
76
void reserve(unsigned long long where, unsigned long long length)
53
77
{
124
148
{
125
149
        char fname[MAXPATH], *bname;
126
150
        uint64_t buf[32];
127
 
        uint64_t ranges[2*MAX_MEMORY_RANGES];
 
151
        uint64_t *ranges;
 
152
        int ranges_size = MEM_RANGE_CHUNK_SZ;
128
153
        uint64_t base, end, loc_base, loc_end;
129
 
        int range, rlen = 0, i;
130
 
        int rngs_cnt, tmp_indx;
 
154
        size_t i, rngs_cnt, range;
 
155
        int rlen = 0;
 
156
        int tmp_indx;
131
157
 
132
158
        strcpy(fname, pathname);
133
159
        bname = strrchr(fname, '/');
140
166
                die("unrecoverable error: error seeking in \"%s\": %s\n",
141
167
                        pathname, strerror(errno));
142
168
 
 
169
        ranges = malloc(ranges_size*8);
 
170
        if (!ranges)
 
171
                die("unrecoverable error: can't alloc %d bytes for ranges.\n",
 
172
                    ranges_size*8);
 
173
 
143
174
        rlen = 0;
144
175
        for (i = 0; i < num_of_lmbs; i++) {
145
176
                if (read(fd, buf, 24) < 0)
155
186
 
156
187
                rngs_cnt = 0;
157
188
                for (range = 0; range < usablemem_rgns.size; range++) {
 
189
                        int add = 0;
158
190
                        loc_base = usablemem_rgns.ranges[range].start;
159
191
                        loc_end = usablemem_rgns.ranges[range].end;
160
192
                        if (loc_base >= base && loc_end <= end) {
161
 
                                ranges[rlen++] = loc_base;
162
 
                                ranges[rlen++] = loc_end - loc_base;
163
 
                                rngs_cnt++;
 
193
                                add = 1;
164
194
                        } else if (base < loc_end && end > loc_base) {
165
195
                                if (loc_base < base)
166
196
                                        loc_base = base;
167
197
                                if (loc_end > end)
168
198
                                        loc_end = end;
 
199
                                add = 1;
 
200
                        }
 
201
 
 
202
                        if (add) {
 
203
                                if (rlen >= (ranges_size-2)) {
 
204
                                        ranges_size += MEM_RANGE_CHUNK_SZ;
 
205
                                        ranges = realloc(ranges, ranges_size*8);
 
206
                                        if (!ranges)
 
207
                                                die("unrecoverable error: can't"
 
208
                                                    " realloc %d bytes for"
 
209
                                                    " ranges.\n",
 
210
                                                    ranges_size*8);
 
211
                                }
169
212
                                ranges[rlen++] = loc_base;
170
213
                                ranges[rlen++] = loc_end - loc_base;
171
214
                                rngs_cnt++;
172
215
                        }
173
216
                }
174
 
                /* Store the count of (base, size) duple */
175
 
                ranges[tmp_indx] = rngs_cnt;
 
217
                if (rngs_cnt == 0) {
 
218
                        /* We still need to add a counter for every LMB because
 
219
                         * the kernel parsing code is dumb.  We just have
 
220
                         * a zero in this case, with no following base/len.
 
221
                         */
 
222
                        ranges[tmp_indx] = 0;
 
223
                        /* rlen is already just tmp_indx+1 as we didn't write
 
224
                         * anything.  Check array size here, as we'll probably
 
225
                         * go on for a while writing zeros now.
 
226
                         */
 
227
                        if (rlen >= (ranges_size-1)) {
 
228
                                ranges_size += MEM_RANGE_CHUNK_SZ;
 
229
                                ranges = realloc(ranges, ranges_size*8);
 
230
                                if (!ranges)
 
231
                                        die("unrecoverable error: can't"
 
232
                                            " realloc %d bytes for"
 
233
                                            " ranges.\n",
 
234
                                            ranges_size*8);
 
235
                        }
 
236
                } else {
 
237
                        /* Store the count of (base, size) duple */
 
238
                        ranges[tmp_indx] = rngs_cnt;
 
239
                }
176
240
        }
177
241
                
178
242
        rlen = rlen * sizeof(uint64_t);
179
243
        /*
180
244
         * Add linux,drconf-usable-memory property.
181
245
         */
 
246
        dt_reserve(&dt, 4+((rlen + 3)/4));
182
247
        *dt++ = 3;
183
248
        *dt++ = rlen;
184
249
        *dt++ = propnum("linux,drconf-usable-memory");
185
250
        if ((rlen >= 8) && ((unsigned long)dt & 0x4))
186
251
                dt++;
187
 
        memcpy(dt, &ranges, rlen);
 
252
        memcpy(dt, ranges, rlen);
 
253
        free(ranges);
188
254
        dt += (rlen + 3)/4;
189
255
}
190
256
 
191
 
static void add_usable_mem_property(int fd, int len)
 
257
static void add_usable_mem_property(int fd, size_t len)
192
258
{
193
259
        char fname[MAXPATH], *bname;
194
260
        uint64_t buf[2];
195
 
        uint64_t ranges[2*MAX_MEMORY_RANGES];
 
261
        uint64_t *ranges;
 
262
        int ranges_size = MEM_RANGE_CHUNK_SZ;
196
263
        uint64_t base, end, loc_base, loc_end;
197
 
        int range, rlen = 0;
 
264
        size_t range;
 
265
        int rlen = 0;
 
266
        ssize_t slen;
198
267
 
199
268
        strcpy(fname, pathname);
200
269
        bname = strrchr(fname,'/');
205
274
 
206
275
        if (len < 2 * sizeof(uint64_t))
207
276
                die("unrecoverable error: not enough data for mem property\n");
208
 
        len = 2 * sizeof(uint64_t);
 
277
        slen = 2 * sizeof(uint64_t);
209
278
 
210
279
        if (lseek(fd, 0, SEEK_SET) < 0)
211
280
                die("unrecoverable error: error seeking in \"%s\": %s\n",
212
281
                    pathname, strerror(errno));
213
 
        if (read(fd, buf, len) != len)
 
282
        if (read(fd, buf, slen) != slen)
214
283
                die("unrecoverable error: error reading \"%s\": %s\n",
215
284
                    pathname, strerror(errno));
216
285
 
219
288
        base = buf[0];
220
289
        end = base + buf[1];
221
290
 
 
291
        ranges = malloc(ranges_size*8);
 
292
        if (!ranges)
 
293
                die("unrecoverable error: can't alloc %d bytes for ranges.\n",
 
294
                    ranges_size*8);
 
295
 
222
296
        for (range = 0; range < usablemem_rgns.size; range++) {
 
297
                int add = 0;
223
298
                loc_base = usablemem_rgns.ranges[range].start;
224
299
                loc_end = usablemem_rgns.ranges[range].end;
225
300
                if (loc_base >= base && loc_end <= end) {
226
 
                        ranges[rlen++] = loc_base;
227
 
                        ranges[rlen++] = loc_end - loc_base;
 
301
                        add = 1;
228
302
                } else if (base < loc_end && end > loc_base) {
229
303
                        if (loc_base < base)
230
304
                                loc_base = base;
231
305
                        if (loc_end > end)
232
306
                                loc_end = end;
 
307
                        add = 1;
 
308
                }
 
309
                if (add) {
 
310
                        if (rlen >= (ranges_size-2)) {
 
311
                                ranges_size += MEM_RANGE_CHUNK_SZ;
 
312
                                ranges = realloc(ranges, ranges_size*8);
 
313
                                if (!ranges)
 
314
                                        die("unrecoverable error: can't realloc"
 
315
                                            "%d bytes for ranges.\n",
 
316
                                            ranges_size*8);
 
317
                        }
233
318
                        ranges[rlen++] = loc_base;
234
319
                        ranges[rlen++] = loc_end - loc_base;
235
320
                }
249
334
        /*
250
335
         * No add linux,usable-memory property.
251
336
         */
 
337
        dt_reserve(&dt, 4+((rlen + 3)/4));
252
338
        *dt++ = 3;
253
339
        *dt++ = rlen;
254
340
        *dt++ = propnum("linux,usable-memory");
255
341
        if ((rlen >= 8) && ((unsigned long)dt & 0x4))
256
342
                dt++;
257
 
        memcpy(dt,&ranges,rlen);
 
343
        memcpy(dt, ranges, rlen);
 
344
        free(ranges);
258
345
        dt += (rlen + 3)/4;
259
346
}
260
347
 
262
349
static void putprops(char *fn, struct dirent **nlist, int numlist)
263
350
{
264
351
        struct dirent *dp;
265
 
        int i = 0, fd, len;
 
352
        int i = 0, fd;
 
353
        size_t len;
 
354
        ssize_t slen;
266
355
        struct stat statbuf;
267
356
 
268
357
        for (i = 0; i < numlist; i++) {
311
400
 
312
401
                len = statbuf.st_size;
313
402
 
 
403
                dt_reserve(&dt, 4+((len + 3)/4));
314
404
                *dt++ = 3;
315
405
                *dt++ = len;
316
406
                *dt++ = propnum(fn);
323
413
                        die("unrecoverable error: could not open \"%s\": %s\n",
324
414
                            pathname, strerror(errno));
325
415
 
326
 
                if (read(fd, dt, len) != len)
 
416
                slen = read(fd, dt, len);
 
417
                if (slen < 0)
327
418
                        die("unrecoverable error: could not read \"%s\": %s\n",
328
419
                            pathname, strerror(errno));
 
420
                if ((size_t)slen != len)
 
421
                        die("unrecoverable error: short read from\"%s\"\n",
 
422
                            pathname);
329
423
 
330
424
                checkprop(fn, dt, len);
331
425
 
347
441
 * Compare function used to sort the device-tree directories
348
442
 * This function will be passed to scandir.
349
443
 */
350
 
static int comparefunc(const void *dentry1, const void *dentry2)
 
444
static int comparefunc(const struct dirent **dentry1,
 
445
                       const struct dirent **dentry2)
351
446
{
352
447
        char *str1 = (*(struct dirent **)dentry1)->d_name;
353
448
        char *str2 = (*(struct dirent **)dentry2)->d_name;
377
472
        struct dirent **namelist;
378
473
        int numlist, i;
379
474
        struct stat statbuf;
 
475
        int plen;
380
476
 
 
477
        plen = *pathstart ? strlen(pathstart) : 1;
 
478
        /* Reserve space for string packed to words; e.g. string length 10 
 
479
         * occupies 3 words, length 12 occupies 4 (for terminating \0s).  
 
480
         * So round up & include the \0:
 
481
         */
 
482
        dt_reserve(&dt, 1+((plen + 4)/4));
381
483
        *dt++ = 1;
382
484
        strcpy((void *)dt, *pathstart ? pathstart : "/");
383
 
        while(*dt)
384
 
                dt++;
385
 
        if (dt[-1] & 0xff)
386
 
                dt++;
 
485
        dt += ((plen + 4)/4);
387
486
 
388
487
        numlist = scandir(pathname, &namelist, 0, comparefunc);
389
488
        if (numlist < 0)
404
503
        if (initrd_base && !strcmp(basename,"/chosen/")) {
405
504
                int len = 8;
406
505
                unsigned long long initrd_end;
 
506
 
 
507
                dt_reserve(&dt, 12); /* both props, of 6 words ea. */
407
508
                *dt++ = 3;
408
509
                *dt++ = len;
409
510
                *dt++ = propnum("linux,initrd-start");
434
535
        if (!strcmp(basename,"/chosen/")) {
435
536
                size_t cmd_len = 0;
436
537
                char *param = NULL;
 
538
                char filename[MAXPATH];
 
539
                char *buff;
 
540
                int fd;
437
541
 
438
542
                cmd_len = strlen(local_cmdline);
439
543
                if (cmd_len != 0) {
446
550
 
447
551
                /* ... if not, grab root= from the old command line */
448
552
                if (!param) {
449
 
                        char filename[MAXPATH];
450
553
                        FILE *fp;
451
554
                        char *last_cmdline = NULL;
452
555
                        char *old_param;
474
577
                cmd_len = cmd_len + 1;
475
578
 
476
579
                /* add new bootargs */
 
580
                dt_reserve(&dt, 4+((cmd_len+3)/4));
477
581
                *dt++ = 3;
478
582
                *dt++ = cmd_len;
479
583
                *dt++ = propnum("bootargs");
483
587
                dt += (cmd_len + 3)/4;
484
588
 
485
589
                fprintf(stderr, "Modified cmdline:%s\n", local_cmdline);
 
590
 
 
591
                /*
 
592
                 * Determine the platform type/stdout type, so that purgatory
 
593
                 * code can print 'I'm in purgatory' message. Currently only
 
594
                 * pseries/hvcterminal is supported.
 
595
                 */
 
596
                strcpy(filename, pathname);
 
597
                strncat(filename, "linux,stdout-path", MAXPATH);
 
598
                fd = open(filename, O_RDONLY);
 
599
                if (fd == -1) {
 
600
                        printf("Unable to find %s, printing from purgatory is diabled\n",
 
601
                                                                                                                filename);
 
602
                        goto no_debug;
 
603
                }
 
604
                if (fstat(fd, &statbuf)) {
 
605
                        printf("Unable to stat %s, printing from purgatory is diabled\n",
 
606
                                                                                                                filename);
 
607
                        close(fd);
 
608
                        goto no_debug;
 
609
 
 
610
                }
 
611
 
 
612
                buff = malloc(statbuf.st_size);
 
613
                if (!buff) {
 
614
                        printf("Can not allocate memory for buff\n");
 
615
                        close(fd);
 
616
                        goto no_debug;
 
617
                }
 
618
                read(fd, buff, statbuf.st_size);
 
619
                close(fd);
 
620
                strncpy(filename, "/proc/device-tree/", MAXPATH);
 
621
                strncat(filename, buff, MAXPATH);
 
622
                strncat(filename, "/compatible", MAXPATH);
 
623
                fd = open(filename, O_RDONLY);
 
624
                if (fd == -1) {
 
625
                        printf("Unable to find %s printing from purgatory is diabled\n",
 
626
                                                                                                                filename);
 
627
                        goto no_debug;
 
628
                }
 
629
                if (fstat(fd, &statbuf)) {
 
630
                        printf("Unable to stat %s printing from purgatory is diabled\n",
 
631
                                                                                                                filename);
 
632
                        close(fd);
 
633
                        goto no_debug;
 
634
                }
 
635
                buff = realloc(buff, statbuf.st_size);
 
636
                if (!buff) {
 
637
                        printf("Can not allocate memory for buff\n");
 
638
                        close(fd);
 
639
                        goto no_debug;
 
640
                }
 
641
                read(fd, buff, statbuf.st_size);
 
642
                if (!strcmp(buff, "hvterm1") || !strcmp(buff, "hvterm-protocol"))
 
643
                        my_debug = 1;
 
644
                close(fd);
 
645
                free(buff);
486
646
        }
487
647
 
 
648
no_debug:
488
649
        for (i=0; i < numlist; i++) {
489
650
                dp = namelist[i];
490
651
                strcpy(dn, dp->d_name);
501
662
                        putnode();
502
663
        }
503
664
 
 
665
        dt_reserve(&dt, 1);
504
666
        *dt++ = 2;
505
667
        dn[-1] = '\0';
506
668
        free(namelist);
518
680
        strcpy(pathname, "/proc/device-tree/");
519
681
 
520
682
        pathstart = pathname + strlen(pathname);
521
 
        dt = dtstruct;
 
683
 
 
684
        dt_cur_size = INIT_TREE_WORDS;
 
685
        dt_base = malloc(dt_cur_size*4);
 
686
        if (!dt_base) {
 
687
                die("Can't malloc %d bytes for dt struct!\n", dt_cur_size*4);
 
688
        }
 
689
        memset(dt_base, 0, dt_cur_size*4);
 
690
 
 
691
        dt = dt_base;
522
692
 
523
693
        if (cmdline)
524
694
                strcpy(local_cmdline, cmdline);
525
695
 
526
696
        putnode();
 
697
        dt_reserve(&dt, 1);
527
698
        *dt++ = 9;
528
699
 
529
700
        len = sizeof(bb[0]);
538
709
 
539
710
        bb->off_dt_struct = bb->off_mem_rsvmap + len;
540
711
 
541
 
        len = dt - dtstruct;
 
712
        len = dt - dt_base;
542
713
        len *= sizeof(unsigned);
543
714
        bb->off_dt_strings = bb->off_dt_struct + len;
544
715
 
558
729
        tlen = bb->off_mem_rsvmap;
559
730
        memcpy(buf+tlen, mem_rsrv, bb->off_dt_struct - bb->off_mem_rsvmap);
560
731
        tlen = tlen + (bb->off_dt_struct - bb->off_mem_rsvmap);
561
 
        memcpy(buf+tlen, dtstruct,  bb->off_dt_strings - bb->off_dt_struct);
 
732
        memcpy(buf+tlen, dt_base,  bb->off_dt_strings - bb->off_dt_struct);
562
733
        tlen = tlen +  (bb->off_dt_strings - bb->off_dt_struct);
563
734
        memcpy(buf+tlen, propnames,  bb->totalsize - bb->off_dt_strings);
564
735
        tlen = tlen + bb->totalsize - bb->off_dt_strings;
565
736
        *sizep = tlen;
 
737
        free(dt_base);
566
738
        return 0;
567
739
}