* [PATCH 10/15] bootwrapper: add cpio file extraction library.
From: Milton Miller @ 2007-07-10 22:11 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, David Gibson
In-Reply-To: <boot-6-00.miltonm@bga.com>
Add a library to search through a cpio or initramfs to a specified
path contained in a cpio.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
Status: tested and working.
This file is designed to also be usable in a stand alone user space
application.
Index: work.git/arch/powerpc/boot/cpio.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ work.git/arch/powerpc/boot/cpio.c 2007-07-10 04:03:40.000000000 -0500
@@ -0,0 +1,306 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2007 IBM Corporation.
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ *
+ */
+
+#include "cpio.h"
+#include "string.h"
+
+struct cpio_header {
+ char ino[8];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char nlink[8];
+ char mtime[8];
+ char filesize[8];
+ char maj[8];
+ char min[8];
+ char rmaj[8];
+ char rmin[8];
+ char namesize[8];
+ char chksum[8];
+} cpio_header_buf;
+
+static int check_magic(char magic[6])
+{
+ return !memcmp(magic,"070701",6) || !memcmp(magic,"070702",6);
+}
+
+static int read_magic(struct gunzip_state *stream)
+{
+ int len;
+ char magic[6];
+
+ len = gunzip_partial(stream, magic, sizeof(magic));
+ if (len == 0)
+ return 0;
+
+ if (len == sizeof(magic) && check_magic(magic))
+ return len;
+
+
+ /* Not the right magic or short read. We might have stumbled
+ * onto a compressed archive immediately following an
+ * uncompressed one, or just some NUL bytes at the end of the
+ * archive. Inform the higher layers by the negative length.
+ */
+ return -len;
+}
+
+static int get_cpio_header(struct gunzip_state *stream)
+{
+ int len;
+
+ len = read_magic(stream);
+ if (len <= 0)
+ return len;
+
+ gunzip_exactly(stream, &cpio_header_buf, sizeof(cpio_header_buf));
+ len += sizeof(cpio_header_buf);
+
+ return len;
+}
+
+static unsigned int cpio_str_to_num(char hexascii[8])
+{
+ unsigned int num = 0;
+ char c;
+ int d;
+
+ for (d=0; d < 8; d++) {
+ c = hexascii[d];
+ num <<= 4;
+ if (c >= '0' && c <= '9') {
+ num += c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ num += c - 'A' + 10;
+ } else if (c >= 'a' && c <= 'f') {
+ num += c - 'a' + 10;
+ } else {
+ cpio_error("bad cpio archive header: "
+ "invalid a hex digit");
+ }
+ }
+
+ return num;
+}
+
+static char name_buf[MAX_PATH+1];
+static const char cpio_end[] = "TRAILER!!!";
+#define CPIO_END_LEN sizeof(cpio_end)
+
+/* check_next_file
+ * Look for @path in @stream. Set @consumed to the number of bytes
+ * succesfully read and processed. return 1 on match, 0 for discarding
+ * an unmatched file, -1 on end of archive (either detected trailer or
+ * EOF on stream), or -(1 + bytes read) for a short read or bad magic
+ * number. (For the short or bad read, the consumed is not changed).
+ */
+static int check_next_file(char *path, int pathlen,
+ struct gunzip_state *stream, int *consumed)
+{
+ int len, total, match;
+
+ if (pathlen > MAX_PATH) {
+ cpio_error("path too long to search\n");
+ }
+ total = get_cpio_header(stream);
+ if (total <= 0)
+ return total - 1;
+
+ len = cpio_str_to_num(cpio_header_buf.namesize);
+
+ if (len == pathlen || len == CPIO_END_LEN) {
+ gunzip_exactly(stream, name_buf, len);
+ total += len;
+ match = !strcmp(name_buf, path);
+ if (!match && !cpio_str_to_num(cpio_header_buf.filesize))
+ match = -!strcmp(name_buf, cpio_end);
+ } else {
+ gunzip_discard(stream, len);
+ total += len;
+ name_buf[0] = '\0';
+ match = 0;
+ }
+
+ len = total % 4;
+ if (len) {
+ gunzip_discard(stream, 4 - len);
+ total += 4 - len;
+ }
+
+ if (!match) {
+ len = cpio_str_to_num(cpio_header_buf.filesize);
+ gunzip_discard(stream, len);
+ total += len;
+
+ len = total % 4;
+ if (len) {
+ gunzip_discard(stream, 4 - len);
+ total += 4 - len;
+ }
+ }
+
+ *consumed += total;
+ return match;
+}
+
+static char *this_buf;
+static int this_archive;
+
+/* find_in_cpio.
+ * find a pathname @path in a single cpio archive described by @stream.
+ * Return is the same as check_next_file.
+ */
+int find_in_cpio(char *path, struct gunzip_state *stream)
+{
+ int found;
+ int pathlen = strlen(path) + 1;
+
+ this_archive = 0;
+ do {
+ found = check_next_file(path, pathlen, stream, &this_archive);
+ } while (found == 0);
+
+ return found;
+}
+
+/* find_in_initramfs
+ * Search a initramfs buffer for a given path name. Returns 0 on
+ * not found, or 1 with @state ready to read the file.
+ *
+ * Note: this returns the first match, not the last. The kernel
+ * decompressor effectivly uses the last match. This code also
+ * doesn't worry about the directories in the path existing.
+ */
+int find_in_initramfs(char *path, char *buf, int len,
+ struct gunzip_state *stream)
+{
+ int found, total = 0;
+ int pathlen = strlen(path) + 1;
+ int *ibuf;
+
+ do {
+ /* get to word boundary, but stop if not NUL */
+ for (; total % 4 && total < len - 4; total++)
+ if (buf[total])
+ break;
+
+ if ((total % 4) == 0) {
+ /* fast forward over NUL words. */
+ for (ibuf = (int *)&buf[total];
+ total < len - sizeof(*ibuf) && !*ibuf;
+ ibuf++)
+ total += sizeof(*ibuf);
+ }
+
+ /* check remainder of a short archive -- it must all be
+ * zero as both gzip header and cpio header are bigger
+ * than this.
+ */
+ if (total >= len - 4) {
+ for (;total < len; total++) {
+ if (buf[len]) {
+ cpio_error("Junk at end of buffer");
+ }
+ }
+ break;
+ } else if (total % 4) {
+ /*
+ * If we are unalinged and not at the end of the buffer
+ * we must be following a compressed archive. Only
+ * NUL and gzip headers are allowed. We skipped NUL.
+ */
+ if (!(buf[total] == 0x1b && buf[total + 1] == 0x8b))
+ cpio_error("unalinged junk in buffer");
+ }
+
+ this_buf = buf + total;
+ this_archive = 0;
+
+ gunzip_start(stream, this_buf, len - total);
+
+ do {
+ found = check_next_file(path, pathlen, stream,
+ &this_archive);
+ } while (!found);
+
+ if (found > 0)
+ return found;
+
+ if (stream->s.workspace) {
+ int discard;
+
+ if (found < -1) {
+ cpio_error("Junk in compressed archive");
+ }
+
+ /* we either found EOF or TRAILER!!!. In the later
+ * case we need to discard to the end of the gzip
+ * contents.
+ */
+ do {
+ discard = gunzip_partial(stream, name_buf,
+ MAX_PATH);
+ this_archive += discard;
+ } while (discard);
+
+ /*
+ * Peek at how many input bytes were consumed.
+ * reset our consumed input.
+ */
+ total += stream->s.total_in + 8;
+
+ /* clean up zlib */
+ discard = gunzip_finish(stream, name_buf, 0);
+ } else {
+ if (this_archive % 4) {
+ cpio_error("Archive not multiple of 4?");
+ }
+ total += this_archive;
+
+ if (!this_archive) {
+ cpio_error("junk between archives");
+ }
+ /* don't check the < -1 of found, it might be an
+ * archive. This will be caught by the !this_archive
+ * check on the next loop.
+ */
+ }
+ } while (total < len);
+
+ return 0;
+}
+
+void get_cpio_info(void **archive_start, int *consumed)
+{
+ *archive_start = this_buf;
+ *consumed = this_archive;
+}
+
+int get_cpio_file_mode(void)
+{
+ return cpio_str_to_num(cpio_header_buf.mode);
+}
+
+int get_cpio_file_size(void)
+{
+ return cpio_str_to_num(cpio_header_buf.filesize);
+}
Index: work.git/arch/powerpc/boot/cpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ work.git/arch/powerpc/boot/cpio.h 2007-07-10 04:03:40.000000000 -0500
@@ -0,0 +1,12 @@
+#include "gunzip_util.h"
+
+extern int find_in_cpio(char *path, struct gunzip_state *stream);
+extern int find_in_initramfs(char *path, char *buf, int len,
+ struct gunzip_state *state);
+extern void get_cpio_info(void **archive_start, int *consumed);
+extern int get_cpio_file_size(void);
+extern int get_cpio_file_mode(void);
+
+#define MAX_PATH 256
+
+extern void cpio_error(char *msg);
Index: work.git/arch/powerpc/boot/Makefile
===================================================================
--- work.git.orig/arch/powerpc/boot/Makefile 2007-07-10 04:02:24.000000000 -0500
+++ work.git/arch/powerpc/boot/Makefile 2007-07-10 04:03:57.000000000 -0500
@@ -36,13 +36,13 @@ $(obj)/ebony.o: BOOTCFLAGS += -mcpu=440
zlib := inffast.c inflate.c inftrees.c
zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
-zliblinuxheader := zlib.h zconf.h zutil.h
+zliblinuxheader := zlib.h zconf.h zutil.h stat.h
$(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
- flatdevtree_conv.c marshal.c memranges.c kexec.c \
+ flatdevtree_conv.c marshal.c memranges.c kexec.c cpio.c \
ns16550.c serial.c simple_alloc.c div64.S util.S rtas.c \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
44x.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c
^ permalink raw reply
* [PATCH 9/15] bootwrapper: rtas support
From: Milton Miller @ 2007-07-10 22:11 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, David Gibson
In-Reply-To: <boot-6-00.miltonm@bga.com>
This code provides a console write that calls put-term-char.
To avoid PIC relocation of the absolute rtas addresses, hide the
actual call to rtas in assembly and declare all variables as int.
An instantiated rtas will be protected by a reserved range in the
device tree, so no explicit call to add_occupied_range is needed
here.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
Removed use_call_rtas(); instead put asm() at the file level.
Index: work.git/arch/powerpc/boot/rtas.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ work.git/arch/powerpc/boot/rtas.c 2007-07-10 04:39:43.000000000 -0500
@@ -0,0 +1,146 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2007 IBM Corporation.
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ *
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "flatdevtree.h"
+
+static int rtas_entry;
+static int rtas_base;
+static int rtas_size;
+
+static void find_rtas(void)
+{
+ int rc;
+ void *devp;
+ char *str;
+
+ devp = finddevice("/rtas");
+ if (! devp)
+ return;
+
+ str = "linux,rtas-entry";
+ rc = getprop(devp, str, &rtas_entry, sizeof(rtas_entry));
+ if (rc < 0)
+ return;
+ if (rc != sizeof(rtas_entry))
+ goto fail;
+
+ str = "rtas-size";
+ rc = getprop(devp, str, &rtas_size, sizeof(rtas_size));
+ if (rc < 0)
+ return;
+ if (rc != sizeof(rtas_size))
+ goto fail;
+
+ str = "linux,rtas-base";
+ rc = getprop(devp, str, &rtas_base, sizeof(rtas_base));
+ if (rc < 0) {
+ printf("rtas-size but no linux,rtas-base in /rtas. "
+ "disabling wrapper rtas interface\n\r");
+ rtas_entry = 0;
+ return;
+ }
+
+ if (rc != sizeof(rtas_base))
+ goto fail;
+
+ return;
+
+
+fail:
+ printf("Unexpected length %d of %s property in /rtas.\n\r"
+ "disabling wrapper rtas interface\n\r", rc, str);
+ rtas_entry = 0;
+ return;
+}
+
+/*
+ * PIC relocation of function pointers happens at call time.
+ * We have an absolute out-of-image address. So tell C they
+ * are just integers, and hide the call as an out-of-file
+ * function.
+ */
+__asm__ (
+ " .globl call_rtas\n"
+ " call_rtas: mtctr 5\n"
+ " bctr\n"
+ );
+
+void call_rtas(int args[], int base, int entry);
+
+
+static int put_term_char;
+
+static void rtas_put_term_write(const char *buf, int len)
+{
+ int i, args[5];
+
+ args[0] = put_term_char;
+ args[1] = 1; /* num inputs */
+ args[2] = 1; /* num outputs */
+
+ for (i=0; i < len; ) {
+ args[3] = buf[i];
+ args[4] = 0;
+
+ call_rtas(args, rtas_base, rtas_entry);
+ if (args[4] == 0) /* SUCCESS */
+ i++;
+ else if (args[4] == -1) /* HARDWARE_ERROR */
+ break;
+ /* else retry */
+ }
+}
+
+int rtas_console_init(void)
+{
+ void *devp;
+ int rc;
+
+
+ devp = finddevice("/rtas");
+ if (!devp)
+ return -1;
+
+ if (!rtas_entry)
+ find_rtas();
+ if (!rtas_entry)
+ return -1;
+
+ rc = getprop(devp, "put-term-char", &put_term_char,
+ sizeof(put_term_char));
+ if (rc == sizeof(put_term_char))
+ console_ops.write = rtas_put_term_write;
+ else
+ put_term_char = -1;
+
+ return put_term_char == -1 ? -1 : 0;
+}
+
+/* for debug, hard code */
+void use_rtas_console(int entry, int base, int tc)
+{
+ rtas_entry = entry;
+ rtas_base = base;
+ put_term_char = tc;
+ console_ops.write = rtas_put_term_write;
+}
Index: work.git/arch/powerpc/boot/ops.h
===================================================================
--- work.git.orig/arch/powerpc/boot/ops.h 2007-07-10 04:39:43.000000000 -0500
+++ work.git/arch/powerpc/boot/ops.h 2007-07-10 04:40:11.000000000 -0500
@@ -94,6 +94,8 @@ void flush_cache(void *, unsigned long);
int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size);
int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr);
void kexec_platform_init(struct boot_param_header *dt_blob);
+int rtas_console_init(void);
+void use_rtas_console(int entry, int base, int tc);
/* marshal slave cpus around to kernel */
void move_slaves_up(void);
Index: work.git/arch/powerpc/boot/kexec.c
===================================================================
--- work.git.orig/arch/powerpc/boot/kexec.c 2007-07-10 04:39:43.000000000 -0500
+++ work.git/arch/powerpc/boot/kexec.c 2007-07-10 04:40:11.000000000 -0500
@@ -33,6 +33,9 @@ static void find_console_from_tree(void)
{
int rc = -1;
+ rc = rtas_console_init();
+ if (!rc)
+ return;
if (rc) {
/* no console, oh well */
}
Index: work.git/arch/powerpc/boot/Makefile
===================================================================
--- work.git.orig/arch/powerpc/boot/Makefile 2007-07-10 04:39:43.000000000 -0500
+++ work.git/arch/powerpc/boot/Makefile 2007-07-10 04:40:11.000000000 -0500
@@ -43,7 +43,7 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
flatdevtree_conv.c marshal.c memranges.c kexec.c \
- ns16550.c serial.c simple_alloc.c div64.S util.S \
+ ns16550.c serial.c simple_alloc.c div64.S util.S rtas.c \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
44x.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c
src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c crt0_kexec.S \
^ permalink raw reply
* [PATCH 8/15] bootwrapper: convert flatdevtree to version 16
From: Milton Miller @ 2007-07-10 22:10 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, David Gibson
In-Reply-To: <boot-6-00.miltonm@bga.com>
kexec-tools still produces a version 2 device tree, while the
libraries in the wrapper only support version 16 and later.
Add a routine to convert a v2 flat device tree to a v16 one inplace
by inserting OF_DT_NOP and chomping full path. Make space for new
headers by moving and then chomping the OF_DT_NOPs.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
Rediffed Makefile
Index: work.git/arch/powerpc/boot/flatdevtree_conv.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ work.git/arch/powerpc/boot/flatdevtree_conv.c 2007-07-10 16:08:20.000000000 -0500
@@ -0,0 +1,280 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corporation 2007
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ */
+#include "flatdevtree.h"
+#include "stdio.h"
+#include "ops.h"
+
+#define MIN_VERSION 2
+#define OUT_VERSION 16
+#define OUT_COMPAT 16
+
+#ifdef NO_CHECK
+static int check_v123_tree(u32 *start, u32 *limit)
+{
+ return 0;
+}
+#else
+/**
+ * check_v123_tree - check integrety of a version 1, 2, or 3 tree
+ * @start: the start of the device tree struct
+ * @limit: the end of the region for the struct
+ * structural checks on device_tree
+ */
+static int check_v123_tree(u32 *start, u32 *limit)
+{
+ u32 len;
+ int depth = 0;
+ u32 *dtp = start;
+
+ while (dtp < limit)
+ switch (*dtp) {
+ case OF_DT_END:
+ if (depth)
+ return -1;
+ return ++dtp - start;
+ case OF_DT_NOP:
+ dtp++;
+ break;
+ case OF_DT_END_NODE:
+ dtp++;
+ depth--;
+ break;
+ case OF_DT_BEGIN_NODE:
+ len = strlen((char *)(++dtp));
+ /* check path is suffix to previous? */
+ dtp += 1 + (len / 4);
+ depth++;
+ break;
+ case OF_DT_PROP:
+ len = dtp[1];
+ dtp += 3;
+ if ((len >= 8) && ((long)dtp & 4))
+ dtp++;
+ dtp += (len + 3) / 4;
+ break;
+ default:
+ return -1;
+ }
+ return -1; /* no OF_DT_END */
+}
+#endif
+
+/**
+ * nop_to_v16 - add %OF_DT_NOP to hide alignment differences
+ * @dtp: pointer to the beginning of the struct area to modify
+ * insert %OF_DT_NOP into the dt_struct @dtp to make it v16 from v1, 2, or 3.
+ */
+static int nop_to_v16(u32 *dtp)
+{
+ int nops = 0;
+ char *p, *s;
+ int len;
+ u32 *next;
+
+ while (*dtp != OF_DT_END)
+ switch (*dtp) {
+ case OF_DT_BEGIN_NODE:
+ /* v2 & v3 names are full path, v16+ is relative */
+ p = (char *)(++dtp);
+ len = strlen(p);
+ next = dtp + 1 + len / 4;
+
+ for (s = p + len; *s != '/'; s--)
+ if (s == p)
+ fatal("name %s has no '/'", p);
+
+ len -= s++ - p; /* not the slash but the nul */
+ memmove(p, s, len);
+ while (len % 4)
+ p[len++] = '\0';
+ dtp += len / 4;
+ while (dtp != next) {
+ *dtp++ = OF_DT_NOP;
+ nops++;
+ }
+ break;
+ case OF_DT_PROP:
+ /* convert from align_8 to align_4 via prefixing nop */
+ len = dtp[1];
+ if ((len >= 8) && !((long)dtp & 4)) {
+ memmove(dtp+1, dtp, 12);
+ *dtp++ = OF_DT_NOP;
+ nops++;
+ }
+ dtp += 3 + (len + 3)/4;
+ break;
+ default:
+ fatal("%s: unrecognised tag %d at %p\n", __FUNCTION__,
+ *dtp, dtp);
+ case OF_DT_NOP:
+ nops ++;
+ /* fall through */
+ case OF_DT_END_NODE:
+ dtp ++;
+ break;
+ }
+ return nops;
+}
+
+#if MIN_VERSION < 3 || OUT_VERSION > 16
+/**
+ * move_nops_fwd - move nops in a v16 dt_struct to the beginning
+ * @start - device tree starting address
+ * @count - number of %OF_DT_NOP cells to move
+ */
+static void move_nops_fwd(u32 *start, int count)
+{
+ u32 *dtp = start;
+ int len;
+ while (count)
+ switch (*dtp) {
+ case OF_DT_NOP:
+ memmove(start+1,start,(dtp-start) * 4);
+ *start++ = OF_DT_NOP;
+ dtp++;
+ count--;
+ break;
+ case OF_DT_END_NODE:
+ dtp++;
+ break;
+ case OF_DT_BEGIN_NODE:
+ len = strlen((char *)(++dtp));
+ dtp += 1 + len / 4;
+ break;
+ case OF_DT_PROP:
+ len = dtp[1];
+ dtp += 3 + (len + 3) / 4;
+ break;
+ case OF_DT_END:
+ fatal("Not enough nops -- need %d more\n", count);
+ return;
+ default:
+ fatal("%s: unknown tag %d at %p", __FUNCTION__, *dtp, dtp)
+ }
+}
+#endif
+
+/**
+ * conv_flattree_inplace upgrade the version of a boot_param_header
+ * @tree: pointer to the device tree header to convert
+ *
+ * Converts a v1, 2, 3 device tree (of at least MIN_VERSION)
+ * in place to OUT_VERSION (16) format, usable by flatdevtree.c
+ */
+void conv_flattree_inplace(struct boot_param_header *tree)
+{
+ u32 *dtp;
+ u32 need = 0, nops;
+ int slen;
+
+ if (tree->magic != OF_DT_HEADER)
+ fatal("%s: no magic", __FUNCTION__);
+
+ if (tree->last_comp_version > 3)
+ return; /* don't know what to do */
+
+ if (tree->version < MIN_VERSION) {
+ printf("%s: Warning: can't handle version %d tree\n",
+ __FUNCTION__, tree->version);
+ return;
+ }
+
+ if (tree->version < 2)
+ need++; /* boot_cpu_id */
+
+ if (tree->version < 3)
+ need++; /* dt_string_size */
+
+ if (OUT_VERSION > 16)
+ need++; /* dt_struct_size */
+
+ dtp = (void *)tree + tree->off_dt_struct;
+
+ slen = check_v123_tree(dtp, (void *)tree + tree->totalsize);
+ if (slen < 0)
+ fatal("device tree check failed\n");
+
+ nops = nop_to_v16(dtp);
+
+ if (need & 1) /* keep 8 byte alignment of mem reserve */
+ need++;
+
+ if (need > nops)
+ fatal("Didn't find enough space to add new header fields\n\r"
+ "(needed %d found %d tree %p)", need, nops, tree);
+
+ /* ok now compress the dtb struct */
+ move_nops_fwd(dtp, need);
+ dtp += need;
+
+ /*
+ * move mem_rsvmap and dt_strings if they are before dt_struct
+ * onto our nops . Adjust start addresses for the 3 sections.
+ */
+ if ((tree->off_mem_rsvmap < tree->off_dt_struct) ||
+ (tree->off_dt_strings < tree->off_dt_struct)) {
+ int start, end;
+ void *ptr;
+
+ if (tree->off_mem_rsvmap < tree->off_dt_strings)
+ start = tree->off_mem_rsvmap;
+ else
+ start = tree->off_dt_strings;
+
+ end = tree->off_dt_struct;
+ ptr = (void *)tree + start;
+
+ memmove(ptr + 4 * need, ptr, end - start);
+
+ if (tree->off_mem_rsvmap < tree->off_dt_struct)
+ tree->off_mem_rsvmap += 4 * need;
+ if (tree->off_dt_strings < tree->off_dt_struct)
+ tree->off_dt_strings += 4 * need;
+ }
+ tree->off_dt_struct += 4 * need;
+
+ /* ok now we have space to extend the header. */
+ if (tree->version < 2 && MIN_VERSION < 2) {
+ tree->boot_cpuid_phys = 0; /* default, caller can fix */
+ }
+
+ /* calculate size of dt_strings_size */
+ if (tree->version < 3 && MIN_VERSION < 3) {
+ int end = tree->totalsize;
+
+ if (tree->off_dt_strings < tree->off_mem_rsvmap)
+ end = tree->off_mem_rsvmap;
+
+ if ((tree->off_dt_strings < tree->off_dt_struct) &&
+ (end > tree->off_dt_struct))
+ end = tree->off_dt_struct;
+
+ tree->dt_strings_size = end - tree->off_dt_strings;
+ }
+
+#if OUT_VERSION > 16
+ tree->dt_struct_size = 4 * slen;
+#endif
+
+ tree->version = OUT_VERSION;
+ tree->last_comp_version = OUT_COMPAT;
+
+ return;
+}
Index: work.git/arch/powerpc/boot/Makefile
===================================================================
--- work.git.orig/arch/powerpc/boot/Makefile 2007-07-10 16:05:13.000000000 -0500
+++ work.git/arch/powerpc/boot/Makefile 2007-07-10 16:05:13.000000000 -0500
@@ -42,7 +42,7 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
- marshal.c memranges.c kexec.c \
+ flatdevtree_conv.c marshal.c memranges.c kexec.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
44x.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c
Index: work.git/arch/powerpc/boot/ops.h
===================================================================
--- work.git.orig/arch/powerpc/boot/ops.h 2007-07-10 16:05:13.000000000 -0500
+++ work.git/arch/powerpc/boot/ops.h 2007-07-10 16:05:13.000000000 -0500
@@ -80,7 +80,10 @@ struct loader_info {
};
extern struct loader_info loader_info;
+struct boot_param_header;
+
void start(void);
+void conv_flattree_inplace(struct boot_param_header *tree);
int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device);
int serial_console_init(void);
int ns16550_console_init(void *devp, struct serial_console_data *scdp);
Index: work.git/arch/powerpc/boot/kexec.c
===================================================================
--- work.git.orig/arch/powerpc/boot/kexec.c 2007-07-10 16:05:13.000000000 -0500
+++ work.git/arch/powerpc/boot/kexec.c 2007-07-10 16:05:13.000000000 -0500
@@ -162,6 +162,7 @@ void kexec_platform_init(struct boot_par
move_slaves_up();
setup_initial_heap();
+ conv_flattree_inplace(dt_blob);
early_scan_flat_tree(dt_blob);
/* drivers can malloc and read the tree, but not realloc later
^ permalink raw reply
* [PATCH 7/15] bootwrapper: Add kexec callable zImage wrapper
From: Milton Miller @ 2007-07-10 22:10 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, David Gibson
In-Reply-To: <boot-6-00.miltonm@bga.com>
This code creates a 32 bit zImage wrapper for a 32 or 64 bit PowerPC
Linux kernel. This allows you to kexec a zImage with its compressed
vmlinux instead of the uncompressed vmlinux elf. The elf is also
packaged as a 64 bit elf for use by kexec-tools for 64 bit kernels.
Limitations:
The memory node off the root with a name starting with "memory" must
contain enough free memory (not in the reserved ranges) in the first
reg range to uncompress the the kernel with padding.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
I split a few more routines out from this file.
I removed the call serial_console_init because some of the serial
console require a loader supplied virtural address mapping which
will not exist when called from kexec.
Successfully boots from and to a 64 bit kernel when loaded at 0 and
when loaded after the kernel _end on machines with with initrds,
rtas, and various other data reserved.
The next patch needed to load using kexec-tools without an externally
generated flat device tree.
Index: work.git/arch/powerpc/boot/kexec.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ work.git/arch/powerpc/boot/kexec.c 2007-07-10 16:37:30.000000000 -0500
@@ -0,0 +1,181 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corporation 2007
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "flatdevtree.h"
+#include "page.h"
+#include "types.h"
+
+extern char _start[];
+extern char _end[];
+
+BSS_STACK(16*1024);
+
+static void find_console_from_tree(void)
+{
+ int rc = -1;
+
+ if (rc) {
+ /* no console, oh well */
+ }
+}
+
+/* fixme: use find_device_by_type "memory" and xlate_reg */
+static void find_rmo_end(void)
+{
+ unsigned int na, ns, reg[4], *rp;
+ void *devp;
+ int rc;
+
+ devp = finddevice("/");
+ if (!devp)
+ fatal("Ack, device-tree root");
+ rc = getprop(devp, "#address-cells", &na, sizeof(na));
+ if (rc != sizeof(na))
+ fatal("Ack, no #address-cells in root");
+ rc = getprop(devp, "#size-cells", &ns, sizeof(ns));
+ if (rc != sizeof(ns))
+ fatal("Ack, no #size-cells in root");
+ if (!na || !ns || na + ns > ARRAY_SIZE(reg))
+ fatal("#addr-cells or #size-cells unusable");
+ do {
+ devp = finddevice("/memory@0");
+ if (!devp)
+ devp = finddevice("/memory");
+ if (!devp)
+ devp = finddevice("/memory@00000000");
+ if (!devp)
+ devp = finddevice("/memory@0000000000000000");
+ if (!devp)
+ fatal("Ack, can't find memory");
+ rc = getprop(devp, "reg", reg, sizeof(reg));
+ if (rc < (na + ns) * sizeof(int))
+ fatal("Ack, no valid reg property in memory");
+
+ rp = ®[0];
+ while (na--) {
+ if (*rp)
+ fatal("didn't find memory at 0");
+ rp++;
+ }
+ while (--ns) {
+ if (*rp) {
+ /* first range >= 4G , use 2G */
+ rmo_end = (void *)0x80000000;
+ return;
+ }
+ rp++;
+ }
+ } while (0);
+
+ rmo_end = (void *)*rp;
+}
+
+/**
+ * setup_initial_heap - setup a small heap in the bss
+ * Using a preallocated heap, setup for scanning the device tree.
+ * Intended for the initial read while the tree will remain read-only so
+ * a minimal malloc and search limit can be used. This way we don't have
+ * lots of data or bss to clear.
+ */
+static void setup_initial_heap(void)
+{
+ static char initial_heap[8*1024];
+ void *heap_end;
+
+ heap_end = simple_alloc_init(initial_heap,
+ sizeof(initial_heap) * 7 / 8,
+ sizeof(long), 64);
+
+ if (heap_end - sizeof(initial_heap) > (void *)&initial_heap[0])
+ fatal("Initial heap too big\n\r");
+}
+
+static void early_scan_flat_tree(struct boot_param_header *dt_blob)
+{
+ int rc;
+
+ rc = ft_init(dt_blob, dt_blob->totalsize, 50);
+ if (rc)
+ fatal("couldn't initialize device-tree\n\r");
+
+ find_rmo_end();
+ dt_find_initrd();
+}
+
+static void init_flat_tree(struct boot_param_header *dt_blob)
+{
+ int rc;
+
+ rc = ft_init(dt_blob, dt_blob->totalsize, /* max_finddevice */ 1024);
+ if (rc)
+ fatal("Unable to initialize device_tree library!\n\r");
+}
+
+static void *saved_vmlinux_addr;
+
+static void *kexec_vmlinux_alloc(unsigned long size)
+{
+ void *addr;
+
+ addr = ranges_vmlinux_alloc(size);
+
+ saved_vmlinux_addr = addr;
+ return addr;
+}
+
+static void kexec_fixups(void)
+{
+ wait_slaves_moved();
+}
+
+static unsigned long (*finalize_chain)(void);
+
+static unsigned long kexec_finalize(void)
+{
+ send_slaves_to_kernel(saved_vmlinux_addr);
+
+ return finalize_chain();
+}
+
+void kexec_platform_init(struct boot_param_header *dt_blob)
+{
+ slaves_are_low();
+ move_slaves_up();
+
+ setup_initial_heap();
+ early_scan_flat_tree(dt_blob);
+
+ /* drivers can malloc and read the tree, but not realloc later
+ * or modify the tree now.
+ */
+ if (!console_ops.write)
+ find_console_from_tree();
+
+ add_known_ranges(dt_blob);
+ ranges_init_malloc();
+ init_flat_tree(dt_blob);
+
+ platform_ops.vmlinux_alloc = kexec_vmlinux_alloc;
+ platform_ops.fixups = kexec_fixups;
+ finalize_chain = dt_ops.finalize;
+ dt_ops.finalize = kexec_finalize;
+}
Index: work.git/arch/powerpc/boot/crt0_kexec.S
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ work.git/arch/powerpc/boot/crt0_kexec.S 2007-07-10 16:37:30.000000000 -0500
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2007 IBM Corporation.
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ *
+ */
+ /*
+ * The kernel calls out to the first image with
+ * r3 = boot cpu, r4 = entrypoint, r5 = 0
+ *
+ * kexec-tools purgatory calls this as it would a linux kernel:
+ * r3 = boot block, r4 = entrypoint, r5 = 0
+ *
+ * The boot block boot_cpu field has been filled in.
+ *
+ * kexec-tools and its purgatory are suppposed to copy SMP_SLAVE_SIZE
+ * bytes from the from entry point, but aparently instead it copies
+ * from the image start.
+ */
+ .globl _zimage_start
+_zimage_start:
+
+#include "marshal_low.S"
+
+ .globl _zimage_start_plat
+_zimage_start_plat:
+ b _zimage_start_lib
+
+ .globl platform_init
+platform_init:
+ b kexec_platform_init
Index: work.git/arch/powerpc/boot/wrapper
===================================================================
--- work.git.orig/arch/powerpc/boot/wrapper 2007-07-10 16:30:15.000000000 -0500
+++ work.git/arch/powerpc/boot/wrapper 2007-07-10 16:37:30.000000000 -0500
@@ -133,6 +133,12 @@ coff)
platformo=$object/of.o
lds=$object/zImage.coff.lds
;;
+kexec)
+ platformo=$object/crt0_kexec.o
+ ;;
+kexec64)
+ platformo="-e _zimage_start_64 $object/crt0_kexec.o"
+ ;;
miboot|uboot)
# miboot and U-boot want just the bare bits, not an ELF binary
ext=bin
@@ -190,6 +196,9 @@ uboot)
fi
exit 0
;;
+kexec64)
+ ${CROSS}objcopy -O elf64-powerpc $ofile
+ ;;
esac
addsec() {
Index: work.git/arch/powerpc/boot/Makefile
===================================================================
--- work.git.orig/arch/powerpc/boot/Makefile 2007-07-10 16:34:28.000000000 -0500
+++ work.git/arch/powerpc/boot/Makefile 2007-07-10 16:37:30.000000000 -0500
@@ -42,11 +42,11 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
- marshal.c memranges.c \
+ marshal.c memranges.c kexec.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
44x.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c
-src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \
+src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c crt0_kexec.S \
cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
ps3-head.S ps3-hvcall.S ps3.c
src-boot := $(src-wlib) $(src-plat) empty.c
@@ -126,6 +126,9 @@ quiet_cmd_wrap = WRAP $@
cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \
$(if $3, -s $3)$(if $4, -d $4)$(if $5, -i $5) vmlinux
+kexec-$(CONFIG_PPC32) += zImage.kexec
+kexec-$(CONFIG_PPC64) += zImage.kexec64
+
image-$(CONFIG_PPC_PSERIES) += zImage.pseries
image-$(CONFIG_PPC_MAPLE) += zImage.pseries
image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries
@@ -138,6 +141,7 @@ image-$(CONFIG_PPC_HOLLY) += zImage.hol
image-$(CONFIG_PPC_PRPMC2800) += zImage.prpmc2800
image-$(CONFIG_PPC_ISERIES) += zImage.iseries
image-$(CONFIG_DEFAULT_UIMAGE) += uImage
+image-$(CONFIG_KEXEC) += $(kexec-y)
ifneq ($(CONFIG_DEVICE_TREE),"")
image-$(CONFIG_PPC_83xx) += cuImage.83xx
@@ -151,7 +155,7 @@ ifeq ($(CONFIG_PPC32),y)
image-$(CONFIG_PPC_PMAC) += zImage.coff zImage.miboot
endif
-initrd- := $(patsubst zImage%, zImage.initrd%, $(image-n) $(image-))
+initrd- := $(patsubst zImage%, zImage.initrd%, $(image-n) $(image-) $(kexec-))
initrd-y := $(patsubst zImage%, zImage.initrd%, \
$(patsubst treeImage%, treeImage.initrd%, $(image-y)))
initrd-y := $(filter-out $(image-y), $(initrd-y))
@@ -219,8 +223,8 @@ install: $(CONFIGURE) $(addprefix $(obj)
sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" $<
# anything not in $(targets)
-clean-files += $(image-) $(initrd-) zImage zImage.initrd cuImage.* treeImage.* \
- otheros.bld
+clean-files += $(image-) $(initrd-) zImage zImage.initrd cuImage.* \
+ treeImage.* $(kexec-)
# clean up files cached by wrapper
clean-kernel := vmlinux.strip vmlinux.bin
Index: work.git/arch/powerpc/boot/ops.h
===================================================================
--- work.git.orig/arch/powerpc/boot/ops.h 2007-07-10 16:34:28.000000000 -0500
+++ work.git/arch/powerpc/boot/ops.h 2007-07-10 16:37:30.000000000 -0500
@@ -90,6 +90,7 @@ void *simple_alloc_init(char *base, unsi
void flush_cache(void *, unsigned long);
int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size);
int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr);
+void kexec_platform_init(struct boot_param_header *dt_blob);
/* marshal slave cpus around to kernel */
void move_slaves_up(void);
^ permalink raw reply
* [PATCH 6/15] bootwrapper: switch 64 bit cpus to 32 bit mode
From: Milton Miller @ 2007-07-10 22:09 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, David Gibson
In-Reply-To: <boot-6-00.miltonm@bga.com>
Add code to check if the processor is in 64 or 32 bit mode using
only instructions from the 32 bit subset. If the processor is in
64 bit mode, switch to 32 bit mode by clearing MSR[SF].
Also add a 64 bit procedure descriptor to use as a elf64 entry
point.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
Merged into crt0.S instead of a separate file with a separate entry
point.
Index: kernel/arch/powerpc/boot/crt0.S
===================================================================
--- kernel.orig/arch/powerpc/boot/crt0.S 2007-07-10 03:33:36.000000000 -0500
+++ kernel/arch/powerpc/boot/crt0.S 2007-07-10 03:39:08.000000000 -0500
@@ -17,11 +17,47 @@
_zimage_start_opd:
.long _zimage_start, 0, 0, 0
+ /* a procedure descriptor used when pretending to be elf64_powerpc */
+ .balign 8
+ .globl _zimage_start_64
+_zimage_start_64:
+ .long 0, _zimage_start /* big endian, supported reloc ppc32 */
+ .long 0, 0, 0, 0, 0, 0
+
+
.weak _zimage_start
.globl _zimage_start
_zimage_start:
.globl _zimage_start_lib
_zimage_start_lib:
+ /* Check if the processor is running in 32 bit mode, using
+ * only 32 bit instructions which should be safe on 32 and
+ * 64 bit processors.
+ *
+ * Subtract the bottom 32 bits of MSR from the full value
+ * recording the result. Since MSR[SF] is in the high word,
+ * the result will be not-equal iff in 32 bit mode (either
+ * the processor is a 32 bit processor or MSR[SF] = 0).
+ */
+ mfmsr r0 /* grab whole msr */
+ rlwinm r8,r0,0,0,31 /* extract bottom word */
+ subf. r8,r8,r0 /* subtract, same? */
+ beq 0f /* yes: we are 32 bit mode */
+
+ /* We are in 64-bit mode. This program must run in 32 bit
+ * mode. Assume we are actually running somewhere in the
+ * low 32 bits of the address space, so we can just turn
+ * off MSR[SF] which is bit 0.
+ */
+ .machine push
+ .machine "ppc64"
+ rldicl r0,r0,0,1
+ sync
+ mtmsrd r0
+ isync
+ .machine pop
+0: /* We are now in 32-bit mode */
+
/* Work out the offset between the address we were linked at
and the address where we're running. */
bl 1f
^ permalink raw reply
* [PATCH 5/15] bootwrapper: occupied memory ranges
From: Milton Miller @ 2007-07-10 22:09 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, David Gibson
In-Reply-To: <boot-6-00.miltonm@bga.com>
Add a set of library routines to manage gross memory allocations.
This code uses an array in bss to store upto 32 entrys with merging
representing a range of memory below rmo_end (aka end of real mode
memory at 0).
To use this code, a platform would set rmo_end, call occupy_memory,
then then call init_malloc for fine grain allocation.
Also, an optional vmlinux_alloc.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
Fixed a bug when extending across multiple ranges.
Cleaned up documentation
Index: work.git/arch/powerpc/boot/memranges.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ work.git/arch/powerpc/boot/memranges.c 2007-07-10 03:48:29.000000000 -0500
@@ -0,0 +1,242 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corporation 2007
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "flatdevtree.h"
+#include "page.h"
+#include "types.h"
+
+extern char _start[], _end[];
+
+void *rmo_end;
+
+static struct {
+ void *start, *end;
+} ranges[32];
+static int num_ranges;
+
+/**
+ * add_occupied_range - mark a range as occupied
+ * @start: start of range pointer
+ * @end: end of range pointer
+ *
+ * Mark the range from @start to @end as occupied.
+ * Ignore anything above rmo_end.
+ */
+void add_occupied_range(void *start, void *end)
+{
+ int i, j;
+
+ if (start == end)
+ return;
+ if (start > rmo_end)
+ return;
+ if (end > rmo_end)
+ end = rmo_end;
+ if (start > end)
+ fatal("%s: BUG: start %p > end %p\n\r", __FUNCTION__,
+ start, end);
+
+ printf("add %p %p: ", start, end);
+
+ for (i=0; i < num_ranges; i++)
+ if (start <= ranges[i].end)
+ break;
+
+ /* extend and merge any overlapping ranges */
+ if (i < num_ranges && end >= ranges[i].start) {
+ ranges[i].start = min(start, ranges[i].start);
+ for (j=i; j < num_ranges; j++)
+ if (end >= ranges[j].start)
+ end = max(end, ranges[j].end);
+ else
+ break;
+ ranges[i].end = end;
+
+ if (j == i + 1) {
+ printf("extending range %d to %p %p\n\r", i,
+ ranges[i].start, ranges[i].end);
+ } else {
+ printf("merged ranges %d to %d now %p %p\n\r", i, j,
+ ranges[i].start, ranges[i].end);
+
+ ++i;
+ memmove(&ranges[i], &ranges[j],
+ (num_ranges - j) * sizeof(ranges[0]));
+ num_ranges -= j-i;
+ }
+ } else {
+ /* insert a new range */
+ if (num_ranges >= ARRAY_SIZE(ranges) - 1)
+ fatal("Too many memory ranges to track\n");
+
+ printf("inserting range %d between %p and %p\n\r",
+ i, i ? ranges[i-1].end : 0,
+ i == num_ranges ? rmo_end : ranges[i].start);
+
+ memmove(&ranges[i+1], &ranges[i],
+ (num_ranges - i) * sizeof(ranges[0]));
+ num_ranges++;
+
+ ranges[i].start = start;
+ ranges[i].end = end;
+ }
+}
+
+/**
+ * add_occupied_range_ulong - mark a range as occupied
+ * @start: start of block to occupy
+ * @end: start of block to occupy
+ *
+ * Call add_occupied_range() after casting to ulong @start and @end to
+ * void * pointers.
+ */
+void add_occupied_range_ulong(unsigned long start, unsigned long end)
+{
+ add_occupied_range((void *)start, (void *)end);
+}
+
+/**
+ * add_known_ranges - occupy some known regions
+ * @dt_blob: a flattend device tree to occupy, or NULL to skip
+ *
+ * call add_occupied_range() for the wrapper, loader supplied initrd,
+ * and, if not %NULL, the device tree blob @dt_blob and any reserved
+ * memory ranges therein.
+ */
+void add_known_ranges(struct boot_param_header *dt_blob)
+{
+ unsigned long long rstart, rlen, rend, *rsrv;
+
+ add_occupied_range(_start, _end);
+
+ add_occupied_range_ulong(loader_info.initrd_addr,
+ loader_info.initrd_addr + loader_info.initrd_size);
+
+ if (dt_blob == NULL)
+ return;
+
+ add_occupied_range(dt_blob, (void *)dt_blob + dt_blob->totalsize);
+
+ /* only support 8-byte reserve map. Only care about < 4G */
+ rsrv = (void *)dt_blob + dt_blob->off_mem_rsvmap;
+ do {
+ rstart = *rsrv++;
+ rlen = *rsrv++;
+ rend = rstart + rlen;
+
+ if (rlen && rstart < UINT_MAX) {
+ if (rend < UINT_MAX)
+ add_occupied_range_ulong(rstart, rend);
+ else
+ add_occupied_range_ulong(rstart, UINT_MAX);
+ }
+ } while (rlen);
+}
+
+/**
+ * ranges_init_malloc - initialize malloc heap in a free memory range.
+ *
+ * Call simple_alloc_init using the largest gap between occupied ranges.
+ * Does not consider before the first or after the last range.
+ */
+void ranges_init_malloc(void)
+{
+ int i;
+ unsigned long size = 0;
+ void *heap_start, *heap_end;
+
+ /*
+ * Allow the beginning for the kernel and the end for
+ * other things the platform might want to have reserved.
+ */
+
+ heap_start = NULL; /* avoid gcc warning */
+ for (i=1; i < num_ranges; i++) {
+ unsigned long newsize;
+
+ newsize = ranges[i].start - ranges[i-1].end;
+ if (newsize > size) {
+ size = newsize;
+ heap_start = ranges[i-1].end;
+ }
+ }
+
+ if (size < 4 * 1024 * 1024)
+ fatal("Can't find a sutiable gap (largest 0x%lx)", size);
+
+ printf("putting heap between %p and %p size 0x%lx\n\r", heap_start,
+ heap_start + size, size);
+ heap_end = simple_alloc_init(heap_start, size * 7 / 8,
+ PAGE_SIZE, /* max num alloc */ 4096);
+ if (heap_end > (heap_start + size))
+ fatal("heap alloc overflowed gap (%p)\n\r", heap_end);
+
+ add_occupied_range(heap_start, heap_end);
+}
+
+/**
+ * ranges_vmlinux_alloc - an optonal kernel allocator.
+ * @size: the image size of the kernel
+ *
+ * Searches for a location to put the kernel, then reserve that range
+ * and the area to which the kernel will relocate itself. First try
+ * address %0. If that is blocked by a previos call to add_occupied_range(),
+ * try malloc(). If that also fails search for free space between the
+ * occupied ranges or between the last range and rmo_end.
+ */
+void *ranges_vmlinux_alloc(unsigned long size)
+{
+ void *addr;
+ int i;
+
+ /* Assume _start to _end is occupied */
+ addr = (void *)0;
+ if (addr + size < ranges[0].start)
+ goto occupy;
+
+ addr = malloc(size);
+ if (addr)
+ goto out;
+
+ for (i=1; i < num_ranges; i++) {
+ if (size < ranges[i].start - ranges[i-1].end)
+ goto occupy_range;
+ }
+ if (size < rmo_end - ranges[i-1].end)
+ goto occupy_range;
+
+ fatal("Unable to find a 0x%lx byte gap for the kernel\n", size);
+
+occupy_range:
+ addr = ranges[i-1].end;
+occupy:
+ add_occupied_range(addr, addr + size);
+out:
+ /*
+ * Assume the kernel will decompress to 0, but don't implicity
+ * create a new gap below the current first range.
+ */
+ if ((unsigned long)ranges[0].end < size)
+ add_occupied_range_ulong(0, size);
+
+ return addr;
+}
Index: work.git/arch/powerpc/boot/ops.h
===================================================================
--- work.git.orig/arch/powerpc/boot/ops.h 2007-07-10 03:48:20.000000000 -0500
+++ work.git/arch/powerpc/boot/ops.h 2007-07-10 03:48:29.000000000 -0500
@@ -22,6 +22,8 @@
typedef void (*kernel_entry_t)(unsigned long r3, unsigned long r4, void *r5);
+struct boot_param_header;
+
/* Platform specific operations */
struct platform_ops {
void (*fixups)(void);
@@ -96,6 +98,14 @@ void send_slaves_to_kernel(void *vmlinux
void slaves_are_low(void);
void wait_slaves_moved(void);
+/* memory ranges */
+extern void *rmo_end;
+void add_occupied_range(void *start, void *end);
+void add_occupied_range_ulong(unsigned long start, unsigned long end);
+void add_known_ranges(struct boot_param_header *dt_blob);
+void ranges_init_malloc(void);
+void *ranges_vmlinux_alloc(unsigned long size);
+
static inline void *finddevice(const char *name)
{
return (dt_ops.finddevice) ? dt_ops.finddevice(name) : NULL;
Index: work.git/arch/powerpc/boot/Makefile
===================================================================
--- work.git.orig/arch/powerpc/boot/Makefile 2007-07-10 03:48:20.000000000 -0500
+++ work.git/arch/powerpc/boot/Makefile 2007-07-10 03:48:29.000000000 -0500
@@ -42,7 +42,7 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
- marshal.c \
+ marshal.c memranges.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
44x.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c
^ permalink raw reply
* [PATCH 4/15] bootwrapper: smp support code
From: Milton Miller @ 2007-07-10 22:08 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, David Gibson
In-Reply-To: <boot-6-00.miltonm@bga.com>
Support code to move cpus around, both a spin loop and c code to
move the cpus before uncompressing and copying the kernel to 0.
The low level code is designed to be included in a crt0 or other
assembly file because it may need to be at a fixed location or there
may be other entry point requirements.
Note: this code works with kernel head_64.S. head_6xx.S needs the
0x60 entry point (it currently uses something closer to 0xC0; but
the similar code is at 0xC4); the other heads don't appear to support
SMP.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
Cleaned up documentation. Hopefully the format is correct.
Removed the #if 1 #else #endif
Move hidden asm code outside function instead of branching over it.
This code has previously survied days of kexec stress and also works
when the next stage is itself (ie zBoot to zImage).
Index: work.git/arch/powerpc/boot/marshal_low.S
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ work.git/arch/powerpc/boot/marshal_low.S 2007-07-10 03:48:20.000000000 -0500
@@ -0,0 +1,103 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2007 IBM Corporation.
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ *
+ */
+
+#include "ppc_asm.h"
+
+ .text
+ /*
+ * This code is designed to be a kexec entry point block.
+ * That is, it has both code for the master cpu that begins
+ * at offset 0 as linked into the image, and a sequence of
+ * 0x100 bytes that, when copied to address 0, forms the
+ * wait loop for slave cpus. Each slave should have its
+ * unique hardware cpu identifier in r3 before entering
+ * this code.
+ */
+ .globl master
+master: b _zimage_start_plat
+
+ .global slave_wait
+slave_wait:
+ /* r3 cpu id, r4 slaves_wait, r5 cpu bit, r6 cpu mask word offset */
+
+ /* set our bit in the slaves mask */
+98: lwarx r7,r4,r6
+ or r8,r7,r5
+ stwcx. r8,r4,r6
+ bne 98b
+
+ and. r8,r7,r5
+ bnel- err_slave
+
+99: lwz r7,gohere-slave_wait(r4)
+ cmpwi 0,r7,0
+ beq 99b
+ mtctr r7
+ mr r4,r7
+ bctr
+
+
+ .global gohere
+gohere: .long 0 /* when set the slave moves */
+
+
+err_slave:
+ stw r5,slave_error-slave_wait(4) /* no locking */
+ blr
+
+ .globl slave_error /* set when slave detects error */
+slave_error:
+ .long 0
+
+ /*
+ * The slaves may be in 32 or 64 bit mode, we don't care
+ * r3 is the slave cpu number, matching the device tree.
+ */
+ .org master+0x60
+ .globl slave
+slave: bl 1f
+1: mflr r4
+ addi r4,r4,slave_wait-1b /* code assumes r4=slave_wait */
+ li r5,1
+ rlwnm r5,r5,r3,0,31 /* bit within word */
+ rlwinm r6,r3,32-5+2,4,29 /* word in array */
+ addi r6,r6,slaves-slave_wait /* relative to r4, slave_wait */
+ b slave_wait
+
+ .org master+0x80 /* put locked bitmask data in another line */
+ .global slaves
+slaves:
+
+ .globl slaves_end;
+slaves_end = 0f
+
+#if 0
+ /* today, the 32 bit kernel starts slaves at 0xc0
+ * but this limits us to cpu to 512 vs 1024
+ */
+ .org master+0xc0
+0: b slave
+#endif
+
+
+ .org master+0x100 /* we must fit in 0x100 bytes */
+0:
+
Index: work.git/arch/powerpc/boot/marshal.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ work.git/arch/powerpc/boot/marshal.c 2007-07-10 03:48:20.000000000 -0500
@@ -0,0 +1,275 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright (C) 2007 IBM Corporation.
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "reg.h"
+
+extern unsigned int gohere[], master[], slave_wait[], slaves[], slaves_end[];
+extern unsigned int slave_error[1];
+
+static unsigned int slaves_run_here[SMP_SLAVE_SIZE / sizeof(unsigned int)];
+static unsigned int *slaves_were_here = master;
+static unsigned int *slaves_goto_here = master;
+
+/**
+ * check_slave_errors - check if the slaves have set the error flag.
+ * @slaves_here ... the location that the slaves should be spinning.
+ */
+static void check_slave_errors(unsigned int *slaves_here)
+{
+ unsigned int *error = slave_error - master + slaves_here;
+
+ if (*error) {
+ printf("WARNING: error detected by one or more slave cpus!!\n\r"
+ "WARNING: This probably means you have duplicate cpu ids\n\r");
+ /* exit() */
+ }
+}
+
+/**
+ * wait_slaves_moved - wait for the slaves to catch up
+ *
+ * Wait until all slaves that checked in the previous location have
+ * checked into the current location. Seperate so we can do other
+ * work while we wait for them to catch up.
+ */
+void wait_slaves_moved(void)
+{
+ int offset = slaves - master;
+ int len = sizeof(slaves_end[0]) * (slaves_end - slaves);
+ int printed = 0;
+ unsigned int *to = slaves_goto_here;
+ unsigned int *from = slaves_were_here;
+
+ from += offset;
+ to += offset;
+
+ if (from == to)
+ return;
+
+ while (memcmp(from, to, len)) {
+ if (!printed) {
+ printf("waiting for slave cpus to move...");
+ printed = 1;
+ HMT_LOW;
+ barrier();
+ }
+ /* check from is superset of to */
+ }
+ if (printed) {
+ HMT_MEDIUM;
+ printf("done.\n\r");
+ }
+
+ slaves_were_here = slaves_goto_here;
+}
+
+/**
+ * move_slaves_here - move slaves to a specified address.
+ * @addr: location of %SMP_SLAVE_SIZE buffer to place code and spin
+ *
+ * Tell slaves to go from their current location to a buffer @addr
+ * of %SMP_SLAVE_SIZE bytes somewhere in memory.
+ */
+void move_slaves_here(void *addr)
+{
+ unsigned int *move_slaves_here = addr;
+ unsigned int *tell_them = gohere - master + slaves_goto_here;
+ unsigned int *goto_here = slave_wait - master + move_slaves_here;
+ unsigned int *wait_here = gohere - master + move_slaves_here;
+
+ if (move_slaves_here == slaves_goto_here)
+ return; /* already there */
+
+ wait_slaves_moved(); /* one move at a time */
+
+ printf("moving slave cpus from %p to %p\n\r", slaves_goto_here,
+ move_slaves_here);
+
+ memcpy(move_slaves_here, master, SMP_SLAVE_SIZE);
+ memset(move_slaves_here + (slaves - master), 0,
+ (slaves_end - slaves) * sizeof(slaves_end[0]));
+ *wait_here = 0;
+
+ flush_cache(move_slaves_here, SMP_SLAVE_SIZE);
+
+ check_slave_errors(slaves_were_here);
+
+ *tell_them = (unsigned int)goto_here;
+ slaves_goto_here = move_slaves_here;
+}
+
+/**
+ * move_slaves_up - move slaves from somewhere low to our bss.
+ * Call before decompressing the kernel to address 0.
+ */
+void move_slaves_up(void)
+{
+ move_slaves_here(slaves_run_here);
+}
+
+/**
+ * slaves_are_low - Assert that the slaves are spinning at 0, and move them
+ * Assert that the slaves are running in a copy of the marshall code
+ * that was copied to address 0. Ask them to go up to our bss, as we
+ * know we have to move them away from 0.
+ */
+void slaves_are_low(void)
+{
+ slaves_goto_here = slaves_were_here = (void *)0;
+ move_slaves_up();
+}
+
+/**
+ * wait_slave_checkout - wait for slaves to execute checkout store.
+ * @checkout - slave checkout flag array
+ *
+ * Wait for every slave who checked in at slaves_were_here to
+ * perform the stb to @checkout before the branch to self spin loop.
+ */
+static void wait_slave_checkout(char *checkout)
+{
+ unsigned int *end = slaves_end - master + slaves_were_here;
+ unsigned int *from = slaves - master + slaves_were_here;;
+ unsigned int bit;
+ int i, ncpus = 0;
+ char *waiting = "waiting on slaves to go to kernel...";
+
+ for (i=0; from < end; from++)
+ for (bit = 1; bit; i++, bit <<= 1)
+ if (*from & bit) {
+ ncpus++;
+ while (!checkout[i]) {
+ if (waiting) {
+ printf(waiting);
+ waiting = NULL;
+ }
+ HMT_LOW;
+ barrier();
+ }
+ }
+
+ if (waiting == NULL)
+ printf("done.\n\r");
+
+ printf("moved %d slaves to the kernel.\n\r", ncpus);
+}
+
+/* The slave checkin code ... used by checkout_slaves_to_kernel below */
+extern unsigned int slave_checkout_begin[], slave_checkout_spin[];
+asm ("\
+ .globl slave_checkout_begin ;\
+ .globl slave_checkout_spin ;\
+slave_checkout_begin: ;\
+ lwz 7,0(0) ;\
+ li 8,1 ;\
+ stbx 8,7,3 ;\
+slave_checkout_spin: ;\
+ b $ ;\
+");
+
+
+/**
+ * checkout_slaves_to_kernel - send SMP slaves to the kernel
+ * @tell_them - the expected marshalling buffer for the slaves
+ *
+ * Actively move slaves spinning on @tell_them to 0x60. Since we
+ * don't know what code is there, replace it with our one code that
+ * ends with a byte store and branch to self, with the branch at 0x60.
+ * After the stores complete, we can restore the rest of the line,
+ * flush, then restore the remaining line.
+ */
+static void checkout_slaves_to_kernel(unsigned int *tell_them)
+{
+ int to, spin;
+ unsigned int *from, *low, save[SMP_SLAVE_SIZE/sizeof(unsigned int)];
+ char *checkout;
+
+ checkout = malloc(1024);
+ if (checkout == NULL)
+ fatal("can't malloc slave checkout buffer");
+ memset(checkout, 0, 1024);
+
+ low = (unsigned int *)0;
+ memcpy(save, low, SMP_SLAVE_SIZE);
+
+ to = spin = 0x60 / sizeof(int);
+
+ to++;
+ from = slave_checkout_spin;
+ while (from >= slave_checkout_begin)
+ low[--to] = *from--;
+
+ low[0] = (unsigned int)checkout;
+ flush_cache(low, SMP_SLAVE_SIZE);
+
+ *tell_them = (unsigned int)(low + to);
+
+ wait_slave_checkout(checkout);
+
+ /* at this point, all have completed the store at %0x5c and are at
+ * the branch to self at %0x60. Restore the rest of the vector,
+ * flush cache, then do the final store replacing the spin and
+ * flush again.
+ */
+ low[0] = save[0];
+ for (;to < spin; to++)
+ low[to] = save[to];
+ flush_cache(low, SMP_SLAVE_SIZE);
+ low[to] = save[to];
+ flush_cache(low, SMP_SLAVE_SIZE);
+
+}
+
+/**
+ * send_slaves_to_kernel - send SMP slaves to the kernel
+ * @vmlinux_addr: address vmlinux was decompressed to (where to get slave loop)
+ *
+ * Send slaves currently running in the marshalling system to the slave code
+ * in the next kernel which has been uncompressed at address @vmlinux_addr.
+ * Copies the first %SMP_SLAVE_SIZE bytes of the image to address %0 and
+ * then tells the slaves to go to %0x60.
+ */
+void send_slaves_to_kernel(void *vmlinux_addr)
+{
+ unsigned int *tell_them = gohere - master + slaves_goto_here;
+
+ if ((unsigned long)slaves_goto_here < SMP_SLAVE_SIZE) {
+ if ((unsigned long)vmlinux_addr < SMP_SLAVE_SIZE)
+ fatal("ERROR: slaves were not marshaled before "
+ "decompressing the kernel to 0!\n");
+ move_slaves_up();
+ send_slaves_to_kernel(vmlinux_addr);
+ return;
+ }
+
+ wait_slaves_moved();
+
+ if (vmlinux_addr) {
+ memcpy((void *)0, vmlinux_addr, SMP_SLAVE_SIZE);
+ flush_cache((void *)0, SMP_SLAVE_SIZE);
+ } else {
+ printf("kernel was decompressed to 0\n\r");
+ }
+ check_slave_errors(slaves_goto_here);
+
+ checkout_slaves_to_kernel(tell_them);
+}
Index: work.git/arch/powerpc/boot/Makefile
===================================================================
--- work.git.orig/arch/powerpc/boot/Makefile 2007-07-10 03:48:11.000000000 -0500
+++ work.git/arch/powerpc/boot/Makefile 2007-07-10 03:48:20.000000000 -0500
@@ -42,6 +42,7 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
+ marshal.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
44x.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c
Index: work.git/arch/powerpc/boot/reg.h
===================================================================
--- work.git.orig/arch/powerpc/boot/reg.h 2007-07-10 03:48:11.000000000 -0500
+++ work.git/arch/powerpc/boot/reg.h 2007-07-10 03:48:20.000000000 -0500
@@ -19,4 +19,9 @@ static inline u32 mfpvr(void)
register void *__stack_pointer asm("r1");
#define get_sp() (__stack_pointer)
+#define HMT_MEDIUM asm volatile("or 2,2,2")
+#define HMT_LOW asm volatile("or 1,1,1")
+#define barrier() asm volatile("":::"memory")
+
+
#endif /* _PPC_BOOT_REG_H */
Index: work.git/arch/powerpc/boot/ops.h
===================================================================
--- work.git.orig/arch/powerpc/boot/ops.h 2007-07-10 03:48:15.000000000 -0500
+++ work.git/arch/powerpc/boot/ops.h 2007-07-10 03:48:20.000000000 -0500
@@ -18,6 +18,7 @@
#define COMMAND_LINE_SIZE 512
#define MAX_PATH_LEN 256
#define MAX_PROP_LEN 256 /* What should this be? */
+#define SMP_SLAVE_SIZE 256 /* Size of SMP slave block, kexec/kernel */
typedef void (*kernel_entry_t)(unsigned long r3, unsigned long r4, void *r5);
@@ -84,10 +85,17 @@ int ns16550_console_init(void *devp, str
int mpsc_console_init(void *devp, struct serial_console_data *scdp);
void *simple_alloc_init(char *base, unsigned long heap_size,
unsigned long granularity, unsigned long max_allocs);
-extern void flush_cache(void *, unsigned long);
+void flush_cache(void *, unsigned long);
int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size);
int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr);
+/* marshal slave cpus around to kernel */
+void move_slaves_up(void);
+void move_slaves_here(void *where);
+void send_slaves_to_kernel(void *vmlinux_addr);
+void slaves_are_low(void);
+void wait_slaves_moved(void);
+
static inline void *finddevice(const char *name)
{
return (dt_ops.finddevice) ? dt_ops.finddevice(name) : NULL;
^ permalink raw reply
* [PATCH 3/15] boot: simplfy gunzip_finish
From: Milton Miller @ 2007-07-10 22:08 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, David Gibson
In-Reply-To: <boot-6-00.miltonm@bga.com>
Call gunzip_partial to calculate the remaining length and copy the
data to the user buffer. This makes it shorter and reduces
duplication.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
Index: work.git/arch/powerpc/boot/gunzip_util.c
===================================================================
--- work.git.orig/arch/powerpc/boot/gunzip_util.c 2007-07-10 03:47:35.000000000 -0500
+++ work.git/arch/powerpc/boot/gunzip_util.c 2007-07-10 03:47:39.000000000 -0500
@@ -194,13 +194,10 @@ int gunzip_finish(struct gunzip_state *s
{
int len;
+ len = gunzip_partial(state, dst, dstlen);
+
if (state->s.workspace) {
- len = gunzip_partial(state, dst, dstlen);
zlib_inflateEnd(&state->s);
- } else {
- /* uncompressed image */
- len = min(state->s.avail_in, (unsigned)dstlen);
- memcpy(dst, state->s.next_in, len);
}
return len;
^ permalink raw reply
* [PATCH 2/15] boot: record header bytes in gunzip_start
From: Milton Miller @ 2007-07-10 22:08 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, David Gibson
In-Reply-To: <boot-6-00.miltonm@bga.com>
Record the number of header bytes skipped in the total bytes read field.
This is needed for the initramfs parsing code to find the end of the zip file.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
Index: work.git/arch/powerpc/boot/gunzip_util.c
===================================================================
--- work.git.orig/arch/powerpc/boot/gunzip_util.c 2007-07-10 03:44:41.000000000 -0500
+++ work.git/arch/powerpc/boot/gunzip_util.c 2007-07-10 03:47:35.000000000 -0500
@@ -78,6 +78,7 @@ void gunzip_start(struct gunzip_state *s
fatal("inflateInit2 returned %d\n\r", r);
}
+ state->s.total_in = hdrlen;
state->s.next_in = src + hdrlen;
state->s.avail_in = srclen - hdrlen;
}
^ permalink raw reply
* [PATCH 1/15] boot: find initrd location from device-tree
From: Milton Miller @ 2007-07-10 22:07 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, David Gibson
In-Reply-To: <boot-6-00.miltonm@bga.com>
Some platforms have a boot agent that can create or modify properties in
the device-tree and load images into memory. Provide a helper to set
loader_info used by prep_initrd().
Signed-off-by: Milton Miller <miltonm@bga.com>
---
Moved to devtree.c as suggested.
define UNIT_MAX hardcoded as requested.
Print exactly why we are not propagting loader supplied initrd knowledge to
wrapper code.
Having start_prop and end_prop as variables allows several source lines
to fit in 80 columns.
Index: work.git/arch/powerpc/boot/ops.h
===================================================================
--- work.git.orig/arch/powerpc/boot/ops.h 2007-07-10 03:44:41.000000000 -0500
+++ work.git/arch/powerpc/boot/ops.h 2007-07-10 03:45:51.000000000 -0500
@@ -159,6 +159,7 @@ void dt_fixup_clock(const char *path, u3
void __dt_fixup_mac_addresses(u32 startindex, ...);
#define dt_fixup_mac_addresses(...) \
__dt_fixup_mac_addresses(0, __VA_ARGS__, NULL)
+void dt_find_initrd(void);
static inline void *find_node_by_linuxphandle(const u32 linuxphandle)
Index: work.git/arch/powerpc/boot/types.h
===================================================================
--- work.git.orig/arch/powerpc/boot/types.h 2007-07-10 03:44:41.000000000 -0500
+++ work.git/arch/powerpc/boot/types.h 2007-07-10 03:45:51.000000000 -0500
@@ -12,6 +12,8 @@ typedef short s16;
typedef int s32;
typedef long long s64;
+#define UINT_MAX 0xFFFFFFFF
+
#define min(x,y) ({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
Index: work.git/arch/powerpc/boot/devtree.c
===================================================================
--- work.git.orig/arch/powerpc/boot/devtree.c 2007-07-10 03:44:41.000000000 -0500
+++ work.git/arch/powerpc/boot/devtree.c 2007-07-10 03:45:51.000000000 -0500
@@ -1,6 +1,7 @@
/*
* devtree.c - convenience functions for device tree manipulation
* Copyright 2007 David Gibson, IBM Corporation.
+ * Copyright 2007 Milton Miller, IBM Corporation.
* Copyright (c) 2007 Freescale Semiconductor, Inc.
*
* Authors: David Gibson <david@gibson.dropbear.id.au>
@@ -305,3 +306,68 @@ int dt_xlate_addr(void *node, u32 *buf,
memcpy(dt_xlate_buf, buf, buflen);
return dt_xlate(node, 0, buflen / 4, xlated_addr, NULL);
}
+
+/**
+ * dt_find_initrd - set loader initrd location based on existing properties
+ *
+ * finds the linux,initrd-start and linux,initrd-end properties in
+ * the /chosen node and sets the loader initrd fields accordingly.
+ *
+ * Use this if your loader sets the properties to allow other code to
+ * relocate the tree and/or cause r3 and r4 to be set on true OF
+ * platforms.
+ */
+void dt_find_initrd(void)
+{
+ int rc;
+ unsigned long long initrd_start, initrd_end;
+ void *devp;
+ static const char start_prop[] = "linux,initrd-start";
+ static const char end_prop[] = "linux,initrd-end";
+
+ devp = finddevice("/chosen");
+ if (! devp) {
+ return;
+ }
+
+ rc = getprop(devp, start_prop, &initrd_start, sizeof(initrd_start));
+ if (rc < 0)
+ return; /* not found */
+ /* The properties had to be 8 bytes until 2.6.22 */
+ if (rc == sizeof(unsigned long)) {
+ unsigned long tmp;
+ memcpy(&tmp, &initrd_start, rc);
+ initrd_start = tmp;
+ } else if (rc != sizeof(initrd_start)) { /* now they can be 4 */
+ printf("unexpected length of %s in /chosen!\n\r", start_prop);
+ return;
+ }
+
+ rc = getprop(devp, end_prop, &initrd_end, sizeof(initrd_end));
+ if (rc < 0) {
+ printf("chosen has %s but no %s!\n\r", start_prop, end_prop);
+ return;
+ }
+ if (rc == sizeof(unsigned long)) {
+ unsigned long tmp;
+ memcpy(&tmp, &initrd_end, rc);
+ initrd_end = tmp;
+ } else if (rc != sizeof(initrd_end)) {
+ printf("unexpected length of %s in /chosen!\n\r", end_prop);
+ return;
+ }
+
+ /* Check for presence, ignore if (partially) loaded above 32 bits */
+ if (initrd_start == initrd_end) {
+ printf("ignoring empty device-tree supplied initrd\n");
+ } else if (initrd_start > initrd_end) {
+ printf("ignoring device-tree supplied initrd: start 0x%llx"
+ " > end 0x%llx \n", initrd_start, initrd_end);
+ } else if (initrd_end > UINT_MAX) {
+ printf("ignoring device-tree supplied initrd:"
+ " end 0x%llx > 32 bits\n", initrd_end);
+ } else {
+ loader_info.initrd_addr = initrd_start;
+ loader_info.initrd_size = initrd_end - initrd_start;
+ }
+}
^ permalink raw reply
* [PATCH 0/15] bootwrapper: support for kexec to zImage
From: Milton Miller @ 2007-07-10 22:07 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, David Gibson
This series creates a 32 bit zImage wrapper for a 32 or 64 bit PowerPC
Linux kernel. This allows you to kexec a zImage with its compressed
vmlinux instead of the uncompressed vmlinux elf. The elf is also
packaged as a 64 bit elf for use by kexec-tools for 64 bit kernels.
This series also adds code to extract the vmlinux elf file from an
initramfs (or other platform supplied location). This allows one
to load the elf once (compressed) and use it both for userspace and
for the actual boot.
milton
^ permalink raw reply
* Re: [PATCH] ide: Use inline function for eieio
From: Bartlomiej Zolnierkiewicz @ 2007-07-10 21:58 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: linux-ide, linuxppc-dev
In-Reply-To: <469384B3.1080502@ru.mvista.com>
[ added Kou back to cc: ]
On Tuesday 10 July 2007, Sergei Shtylyov wrote:
> Hello.
>
> Kumar Gala wrote:
> > Move to using inline function variant of eieio instead of inline assmebly.
>
> > Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
applied
Please use host driver name ("scc_pata" in this case) instead of "ide" in
the patch summary if your changes are limited to a single host driver.
This helps later when going through git logs.
> Acked-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
added
Thanks,
Bart
^ permalink raw reply
* Re: Resend: [PATCH] oprofile support for Power 5++
From: Maynard Johnson @ 2007-07-10 21:33 UTC (permalink / raw)
To: willschm; +Cc: linuxppc-dev, Michael Neuling, mjw
In-Reply-To: <1184101660.22547.104.camel@farscape.rchland.ibm.com>
Will Schmidt wrote:
> On Tue, 2007-07-10 at 15:31 -0500, Michael Neuling wrote:
>
>>>>Does it make more sense to call this "ppc64/power5+rev3"?
>>>>
>>>
>>>This is a change to support new counter setup for oprofile. It may be the
>>>same if there is a revision 4 or 5 etc. So since the internal name was ++
I have no idea if there will be a revision 4, etc, but I'm assuming the
behavior would be the same as rev 3. So I'm not in favor of changing
this string to include "rev3" in it. But whatever decision is made, I
hope it can be made soon. The OProfile community is testing a release
candidate right now that includes the userspace portion of this issue
which checks for the string "ppc64/power5++". We hope to GA this next
oprofile release very soon.
Thanks.
-Maynard
>>>I followed that convention.
>
>
> There is an oprofile change already made, or in-flight, or at least
> submitted, that will be looking for the "power5++" string, so if the
> string changes here, it'll need to be changed there too.
>
> ( http://article.gmane.org/gmane.linux.oprofile/4670 )
>
>
>>I'm not too fussed, but if rev 4 comes out, the counters change and we
>>need power5+++, it's gonna look pretty silly :-)
>
>
> silly, but would be funny to see. :-)
>
>
>>Mikey
>>_______________________________________________
>>Linuxppc-dev mailing list
>>Linuxppc-dev@ozlabs.org
>>https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
>
^ permalink raw reply
* Re: Resend: [PATCH] oprofile support for Power 5++
From: Will Schmidt @ 2007-07-10 21:07 UTC (permalink / raw)
To: Michael Neuling; +Cc: linuxppc-dev, mjw
In-Reply-To: <911.1184099498@neuling.org>
On Tue, 2007-07-10 at 15:31 -0500, Michael Neuling wrote:
> > >
> > > Does it make more sense to call this "ppc64/power5+rev3"?
> > >
> > This is a change to support new counter setup for oprofile. It may be the
> > same if there is a revision 4 or 5 etc. So since the internal name was ++
> > I followed that convention.
There is an oprofile change already made, or in-flight, or at least
submitted, that will be looking for the "power5++" string, so if the
string changes here, it'll need to be changed there too.
( http://article.gmane.org/gmane.linux.oprofile/4670 )
>
> I'm not too fussed, but if rev 4 comes out, the counters change and we
> need power5+++, it's gonna look pretty silly :-)
silly, but would be funny to see. :-)
>
> Mikey
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* Re: Resend: [PATCH] oprofile support for Power 5++
From: Michael Neuling @ 2007-07-10 20:31 UTC (permalink / raw)
To: mjw; +Cc: linuxppc-dev
In-Reply-To: <4693E7EF.4020708@linux.vnet.ibm.com>
> >
> > Does it make more sense to call this "ppc64/power5+rev3"?
> >
> This is a change to support new counter setup for oprofile. It may be the
> same if there is a revision 4 or 5 etc. So since the internal name was ++
> I followed that convention.
I'm not too fussed, but if rev 4 comes out, the counters change and we
need power5+++, it's gonna look pretty silly :-)
Mikey
^ permalink raw reply
* Re: [patch 5/6] Update the 83xx/85xx/86xx boards device tree
From: Segher Boessenkool @ 2007-07-10 20:28 UTC (permalink / raw)
To: Zang Roy-r61911; +Cc: linuxppc-dev list, Paul Mackerras
In-Reply-To: <1184082783.20129.193.camel@localhost.localdomain>
> Indentify pci, pcie host by compatible property
> "fsl,mpc83xx-pci","83xx"
> "fsl,mpc85xx-pci","85xx"
> "fsl,mpc86xx-pci","86xx"
> and
> "fsl, mpc85xx-pciex","85xx"
> "fsl, mpc86xx-pciex","86xx"
This can't ever work -- if you see "compatible" = "85xx",
what is it? PCI or PCIe? Or something else perhaps, maybe
a CPU or an I2C controller or who-knows-what?
Segher
^ permalink raw reply
* Re: [patch 3/6] Add 8548 CDS PCI express controller node and PCI-X device node
From: Segher Boessenkool @ 2007-07-10 20:25 UTC (permalink / raw)
To: Zang Roy-r61911; +Cc: linuxppc-dev list, Paul Mackerras
In-Reply-To: <1184082728.20129.187.camel@localhost.localdomain>
> pci1: pci@8000 {
> interrupt-map-mask = <1f800 0 0 7>;
Set the mask to <1800 0 0 7>, and you need only 16
entries to encode the swizzle. Except...
> + /* bus 1 , idsel 0x2 Tsi310 bridge secondary */
...interrupts on bus 1 should be swizzled on bus 1, not
at the PHB. Really. It is a horrible workaround for a
non-existing problem to do it here, and I promise you
it _will_ come back to hurt you later. Not a threat,
just a promise :-)
> - compatible = "85xx";
> + compatible = "fsl,mpc85xx-pci","85xx";
No more "xx" please...
> + pci@a000 {
> + interrupt-map-mask = <f800 0 0 7>;
> + interrupt-map = <
> +
> + /* IDSEL 0x0 (PEX) */
> + 00000 0 0 1 &mpic 0 1
> + 00000 0 0 2 &mpic 1 0
> + 00000 0 0 3 &mpic 2 0
> + 00000 0 0 4 &mpic 3 0>;
Why sense 0 for all but the first entry in this map?
> + compatible = "fsl,mpc86xx-pciex","86xx";
And "xx" again. Aren't the 85- and 86- PCIe controllers
compatible, btw?
Segher
^ permalink raw reply
* Re: Resend: [PATCH] oprofile support for Power 5++
From: Mike Wolf @ 2007-07-10 20:11 UTC (permalink / raw)
To: Michael Neuling; +Cc: linuxppc-dev
In-Reply-To: <14287.1184096639@neuling.org>
Michael Neuling wrote:
>> The patch has not been included and there have been no comments so
>> I'm resending.
>>
>> This patch adds a new oprofile cpu type for Power 5 revision 3 chips.
>> The new name is ppc64/power5++ and is used so that the performance
>> counters can be set up correctly.
>>
>
> Does it make more sense to call this "ppc64/power5+rev3"?
>
This is a change to support new counter setup for oprofile. It may be the
same if there is a revision 4 or 5 etc. So since the internal name was ++
I followed that convention.
> Mikey
>
>
>> Signed-off-by: Mike Wolf <mjw@us.ibm.com>
>>
>> --------
>> linux-2.6.18.ppc64.orig/arch/powerpc/kernel/cputable.c 2006-09-19 22:4
>>
> 2:06.000000000 -0500
>
>> +++ linux-2.6.18.ppc64/arch/powerpc/kernel/cputable.c 2007-06-11 12:29:47.000
>>
> 000000 -0500
>
>> @@ -236,6 +236,21 @@
>> .oprofile_mmcra_sipr = MMCRA_SIPR,
>> .platform = "power5",
>> },
>> + { /* Power5++ */
>> + .pvr_mask = 0xffffff00,
>> + .pvr_value = 0x003b0300,
>> + .cpu_name = "POWER5+ (gs)",
>> + .cpu_features = CPU_FTRS_POWER5,
>> + .cpu_user_features = COMMON_USER_POWER5_PLUS,
>> + .icache_bsize = 128,
>> + .dcache_bsize = 128,
>> + .num_pmcs = 6,
>> + .oprofile_cpu_type = "ppc64/power5++",
>> + .oprofile_type = PPC_OPROFILE_POWER4,
>> + .oprofile_mmcra_sihv = MMCRA_SIHV,
>> + .oprofile_mmcra_sipr = MMCRA_SIPR,
>> + .platform = "power5+",
>> + },
>> { /* Power5 GS */
>> .pvr_mask = 0xffff0000,
>> .pvr_value = 0x003b0000,
>>
>> _______________________________________________
>> Linuxppc-dev mailing list
>> Linuxppc-dev@ozlabs.org
>> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>>
>>
^ permalink raw reply
* [PATCH] fix idr_get_new_above id alias bugs
From: Jim Houston @ 2007-07-10 20:05 UTC (permalink / raw)
To: Hoang-Nam Nguyen
Cc: linux-kernel, openib-general, Stefan Roscher, linuxppc-dev,
raisch, Andrew Morton
In-Reply-To: <200707041611.30056.hnguyen@linux.vnet.ibm.com>
Hi Everyone,
Hoang-Nam Nguyen reported a bug in idr_get_new_above()
which occurred with a starting id value like 0x3ffffffc.
His test module easily reproduced the problem. Thanks.
The test revealed the following bugs:
1. Relying on shift operations which have undefined results
e.g.: 1 << n where n > word size. On i386 an integer shift
only uses the low 5 bits of the shift count.
2. An off by one error which prevented the top most layer
of the radix tree from being allocated. This meant that
sub_alloc() would allocate an entry in the existing portion
of the radix tree which aliased the requested address. When
it tried to allocate id 0x40000000, it might use the slot
belonging to id 0.
3. There was also a failure in the code which walked back up
the tree if an allocation failed. The normal case is to
descend the tree checking the starting id value against the
bitmap at each level. If the bit is set, we know that the
entire sub-tree is full and we can short cut the search.
We may still descend to the lowest level and find that the
portion of the id space we want is full. In this case we
need to walk back up the tree and continue the search.
The existing code just returned to the previous level and
continued. This resulted in an attempt to allocate an id
above 0x3ffffffc using the slot for id 0x3ffffc00 instead of
0x40000000 which it then claimed to have allocated. The same
problem occurs with 0x3ff as the requested id value if it
is already in use.
With this patch, idr.c should work as advertised allocating id
values in the range 0...0x7fffffff. Andrew had speculated that
it should allow the full range 0...0xffffffff to be used. I was
tempted to make changes to allow this, but it would require changes
to API, e.g. making the starting id value and the return value
unsigned.
Signed-off-by: Jim Houston <jim.houston@ccur.com>
--
Index: linux-2.6.22-rc7/include/linux/idr.h
===================================================================
--- linux-2.6.22-rc7.orig/include/linux/idr.h 2007-04-25 23:08:32.000000000 -0400
+++ linux-2.6.22-rc7/include/linux/idr.h 2007-07-06 16:46:31.000000000 -0400
@@ -18,17 +18,9 @@
#if BITS_PER_LONG == 32
# define IDR_BITS 5
# define IDR_FULL 0xfffffffful
-/* We can only use two of the bits in the top level because there is
- only one possible bit in the top level (5 bits * 7 levels = 35
- bits, but you only use 31 bits in the id). */
-# define TOP_LEVEL_FULL (IDR_FULL >> 30)
#elif BITS_PER_LONG == 64
# define IDR_BITS 6
# define IDR_FULL 0xfffffffffffffffful
-/* We can only use two of the bits in the top level because there is
- only one possible bit in the top level (6 bits * 6 levels = 36
- bits, but you only use 31 bits in the id). */
-# define TOP_LEVEL_FULL (IDR_FULL >> 62)
#else
# error "BITS_PER_LONG is not 32 or 64"
#endif
Index: linux-2.6.22-rc7/lib/idr.c
===================================================================
--- linux-2.6.22-rc7.orig/lib/idr.c 2007-04-25 23:08:32.000000000 -0400
+++ linux-2.6.22-rc7/lib/idr.c 2007-07-10 11:05:19.000000000 -0400
@@ -105,8 +105,8 @@
id = *starting_id;
p = idp->top;
- l = idp->layers;
- pa[l--] = NULL;
+ l = idp->layers - 1;
+ pa[l] = NULL;
while (1) {
/*
* We run around this while until we reach the leaf node...
@@ -117,8 +117,14 @@
if (m == IDR_SIZE) {
/* no space available go back to previous layer. */
l++;
- id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;
- if (!(p = pa[l])) {
+ id = (id | ((1 << (IDR_BITS * l)) - 1));
+ while (((id >> (IDR_BITS * l)) & IDR_MASK) == IDR_MASK)
+ l++;
+ id++;
+ p = pa[l-1];
+ if ((id >= MAX_ID_BIT) || (id < 0))
+ return -3;
+ if (!p) {
*starting_id = id;
return -2;
}
@@ -141,7 +147,7 @@
p->ary[m] = new;
p->count++;
}
- pa[l--] = p;
+ pa[--l] = p;
p = p->ary[m];
}
/*
@@ -159,7 +165,7 @@
*/
n = id;
while (p->bitmap == IDR_FULL) {
- if (!(p = pa[++l]))
+ if (!(p = pa[l++]))
break;
n = n >> IDR_BITS;
__set_bit((n & IDR_MASK), &p->bitmap);
@@ -186,7 +192,7 @@
* Add a new layer to the top of the tree if the requested
* id is larger than the currently allocated space.
*/
- while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) {
+ while ((layers < MAX_LEVEL) && (id & ((~0) << (layers*IDR_BITS)))) {
layers++;
if (!p->count)
continue;
@@ -299,7 +305,7 @@
static void sub_remove(struct idr *idp, int shift, int id)
{
struct idr_layer *p = idp->top;
- struct idr_layer **pa[MAX_LEVEL];
+ struct idr_layer **pa[MAX_LEVEL+1];
struct idr_layer ***paa = &pa[0];
int n;
@@ -392,7 +398,7 @@
/* Mask off upper bits we don't use for the search. */
id &= MAX_ID_MASK;
- if (id >= (1 << n))
+ if ((n <= MAX_ID_SHIFT) && (id & ((~0) << n)))
return NULL;
while (n > 0 && p) {
@@ -425,7 +431,7 @@
id &= MAX_ID_MASK;
- if (id >= (1 << n))
+ if ((n <= MAX_ID_SHIFT) && (id & ((~0) << n)))
return ERR_PTR(-EINVAL);
n -= IDR_BITS;
^ permalink raw reply
* Re: Resend: [PATCH] oprofile support for Power 5++
From: Michael Neuling @ 2007-07-10 19:43 UTC (permalink / raw)
To: mjw; +Cc: linuxppc-dev
In-Reply-To: <4693CC5B.4020207@linux.vnet.ibm.com>
> The patch has not been included and there have been no comments so
> I'm resending.
>
> This patch adds a new oprofile cpu type for Power 5 revision 3 chips.
> The new name is ppc64/power5++ and is used so that the performance
> counters can be set up correctly.
Does it make more sense to call this "ppc64/power5+rev3"?
Mikey
>
> Signed-off-by: Mike Wolf <mjw@us.ibm.com>
>
> --------
> linux-2.6.18.ppc64.orig/arch/powerpc/kernel/cputable.c 2006-09-19 22:4
2:06.000000000 -0500
> +++ linux-2.6.18.ppc64/arch/powerpc/kernel/cputable.c 2007-06-11 12:29:47.000
000000 -0500
> @@ -236,6 +236,21 @@
> .oprofile_mmcra_sipr = MMCRA_SIPR,
> .platform = "power5",
> },
> + { /* Power5++ */
> + .pvr_mask = 0xffffff00,
> + .pvr_value = 0x003b0300,
> + .cpu_name = "POWER5+ (gs)",
> + .cpu_features = CPU_FTRS_POWER5,
> + .cpu_user_features = COMMON_USER_POWER5_PLUS,
> + .icache_bsize = 128,
> + .dcache_bsize = 128,
> + .num_pmcs = 6,
> + .oprofile_cpu_type = "ppc64/power5++",
> + .oprofile_type = PPC_OPROFILE_POWER4,
> + .oprofile_mmcra_sihv = MMCRA_SIHV,
> + .oprofile_mmcra_sipr = MMCRA_SIPR,
> + .platform = "power5+",
> + },
> { /* Power5 GS */
> .pvr_mask = 0xffff0000,
> .pvr_value = 0x003b0000,
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
^ permalink raw reply
* Re: [PATCH v2][POWERPC] document ipic level/sense info
From: Segher Boessenkool @ 2007-07-10 19:37 UTC (permalink / raw)
To: Kumar Gala; +Cc: Stuart Yoder, paulus, linuxppc-dev
In-Reply-To: <473A9535-CF43-4299-8D23-B97E50B5BEC3@kernel.crashing.org>
>>> ... but it is probably worthwhile commentting that sense types 1 & 4
>>> are not supported; just to fill in the obvious gaps. :-)
>>
>> Same for sense types 0, 3, 5, 6, ...
>>
>> Just name the sense types 0 and 1, similar to what all other
>> OF interrupt controller bindings do.
>
> I'm not really keen on changing the values at this point. I think
> we are stuck with them.
Yeah, unless you create a new binding for the same hardware.
Not that I recommend that of course. I suppose the lesson
is to document a device binding as soon as possible, not
months after the corresponding code and trees are out (or to
mark all such code/trees clearly as "preliminary").
Segher
^ permalink raw reply
* Re: [PATCH v2][POWERPC] document ipic level/sense info
From: Segher Boessenkool @ 2007-07-10 19:34 UTC (permalink / raw)
To: Yoder Stuart-B08248; +Cc: linuxppc-dev, paulus
In-Reply-To: <9696D7A991D0824DBA8DFAC74A9C5FA3030162AA@az33exm25.fsl.freescale.net>
>>>> +Sense and level information follows the Linux convention
>>>> +(specified in include/linux/interrupt.h) and should be encoded
>>>> +as follows:
>>>> +
>>>> + 2 = high to low edge sensitive type enabled
>>>> + 8 = active low level sensitive type enabled
>>
>>> ... but it is probably worthwhile commentting that sense types 1 & 4
>>> are not supported; just to fill in the obvious gaps. :-)
>>
>> Same for sense types 0, 3, 5, 6, ...
>>
>> Just name the sense types 0 and 1, similar to what all other
>> OF interrupt controller bindings do.
>
> Actually, all I am trying to do with this patch is document the
> current state of things. The 2/8 sense type usage has been that
> way for a long time, and I'll defer to the 83xx maintainers
> if they see any value in changing it.
>
> Right now there are many DTS files with level/sense set to values
> like 8 and no indication anywhere where those values came from.
Ah right, too bad then. Just document that only 2 and 8 make
sense on current hardware, in that case.
Segher
^ permalink raw reply
* Re: [PATCH 1/2] [ide] mmio ide support
From: Linas Vepstas @ 2007-07-10 18:49 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz
Cc: linuxppc-dev, linux-kernel, Arnd Bergmann, linux-ide
In-Reply-To: <200707081515.42105.bzolnier@gmail.com>
On Sun, Jul 08, 2007 at 03:15:41PM +0200, Bartlomiej Zolnierkiewicz wrote:
>
> > on the argument that drivers/ide/ is going away soon. Most
> > current distros have already moved over to using libata
> > exclusively.
>
> The in-kernel default for PATA systems is still IDE subsystem.
In part because libata still does not yet work correctly
for at least some (older) ide chipsets (like mine).
--linas
^ permalink raw reply
* Re: [PATCH 3/4] Extend the DMA-engine API.
From: Dan Williams @ 2007-07-10 18:41 UTC (permalink / raw)
To: Zhang Wei; +Cc: linuxppc-dev, akpm, paulus, linux-kernel
In-Reply-To: <11840607111926-git-send-email-wei.zhang@freescale.com>
On 7/10/07, Zhang Wei <wei.zhang@freescale.com> wrote:
> Add channel wait queue and transfer callback dma_xfer_callback().
> If the DMA controller and driver support interrupt, when the
> transfer is finished, it will wakeup the wait queue
> and call the callback function of the channel.
>
> Add dma_async_raw_xfer() to API and device_raw_xfer() to struct dma_device
> for RAW physical address DMA transfer, which will be used at transfer
> between I/O address and memory address.
>
Please review the async_tx API patch series[1], it should meet your
needs. What you call "raw" mode support is now default for the
dmaengine driver interface. I plan to request that this series be
merged for 2.6.23.
Regards,
Dan
[1]http://marc.info/?l=linux-raid&w=2&r=1&s=md-accel&q=b
^ permalink raw reply
* Re: [PATCH] Infinite loop/always true check possible with unsigned counter.
From: Manish Ahuja @ 2007-07-10 18:39 UTC (permalink / raw)
To: Paul Mackerras; +Cc: ppc-dev
In-Reply-To: <18067.23198.856592.39397@cargo.ozlabs.ibm.com>
Paul Mackerras wrote:
> Andreas Schwab writes:
>
>
>>>> ??? There is no rgn->cnt involved in the comparison.
>>>>
>>> Look further down in lmb_add_region; there is a second for loop that
>>> does
>>>
>>> for (i = rgn->cnt-1; i >= 0; i--)
>>>
>> Which is exactly the one quoted above. I still don't see your point.
>>
>
> You're right - my mistake.
>
> Paul.
>
I presume the patch is good then. Do I need to change anything ?
Thanks,
Manish
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox