Patchwork [U-Boot] image: Implement IH_TYPE_KERNEL_REL

login
register
mail settings
Submitter Stephen Warren
Date Oct. 6, 2011, 10:36 p.m.
Message ID <1317940584-19528-1-git-send-email-swarren@nvidia.com>
Download mbox | patch
Permalink /patch/118181/
State Changes Requested
Headers show

Comments

Stephen Warren - Oct. 6, 2011, 10:36 p.m.
uImage files contain absolute "load" and "entry" addresses. Such a concept
is incompatible with using the same kernel image on multiple SoCs, each with
a potentially different SDRAM base. To support that, create a new image type
IH_TYPE_KERNEL_REL, which is handled identically to IH_TYPE_KERNEL, except
that the "load" and "entry" properties are an offset from the base of SDRAM,
rather than an absolute address.

"An offset from the base of SDRAM" is specified as:
a) CONFIG_SYS_SDRAM_BASE, if set.
b) Otherwise, for ARM, the start address of the first bank of SDRAM known
   to U-Boot.
c) Otherwise, 0.

The exact algorithm is implemented in getenv_bootm_low().

Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
 arch/sh/lib/bootm.c   |    2 +-
 common/cmd_bootm.c    |   16 +++--
 common/image.c        |  178 ++++++++++++++++++++++++++++++++++++++++++-------
 common/lynxkdi.c      |    6 +-
 common/update.c       |    2 +-
 include/image.h       |   30 ++++++--
 tools/default_image.c |    7 +-
 7 files changed, 194 insertions(+), 47 deletions(-)
Kumar Gala - Oct. 7, 2011, 2:13 a.m.
On Oct 6, 2011, at 5:36 PM, Stephen Warren wrote:

> uImage files contain absolute "load" and "entry" addresses. Such a concept
> is incompatible with using the same kernel image on multiple SoCs, each with
> a potentially different SDRAM base. To support that, create a new image type
> IH_TYPE_KERNEL_REL, which is handled identically to IH_TYPE_KERNEL, except
> that the "load" and "entry" properties are an offset from the base of SDRAM,
> rather than an absolute address.
> 
> "An offset from the base of SDRAM" is specified as:
> a) CONFIG_SYS_SDRAM_BASE, if set.
> b) Otherwise, for ARM, the start address of the first bank of SDRAM known
>   to U-Boot.
> c) Otherwise, 0.
> 
> The exact algorithm is implemented in getenv_bootm_low().
> 
> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> ---
> arch/sh/lib/bootm.c   |    2 +-
> common/cmd_bootm.c    |   16 +++--
> common/image.c        |  178 ++++++++++++++++++++++++++++++++++++++++++-------
> common/lynxkdi.c      |    6 +-
> common/update.c       |    2 +-
> include/image.h       |   30 ++++++--
> tools/default_image.c |    7 +-
> 7 files changed, 194 insertions(+), 47 deletions(-)

Can you explain WHY we need this in the commit message.

- k
Wolfgang Denk - Oct. 7, 2011, 6:50 a.m.
Dear Stephen Warren,

In message <1317940584-19528-1-git-send-email-swarren@nvidia.com> you wrote:
> uImage files contain absolute "load" and "entry" addresses. Such a concept
> is incompatible with using the same kernel image on multiple SoCs, each with
> a potentially different SDRAM base. To support that, create a new image type
> IH_TYPE_KERNEL_REL, which is handled identically to IH_TYPE_KERNEL, except
> that the "load" and "entry" properties are an offset from the base of SDRAM,
> rather than an absolute address.
> 
> "An offset from the base of SDRAM" is specified as:
> a) CONFIG_SYS_SDRAM_BASE, if set.
> b) Otherwise, for ARM, the start address of the first bank of SDRAM known
>    to U-Boot.
> c) Otherwise, 0.

I agree with Kumar: it should be sufficient to have this omment in
the code.  But please define "first bank" - does it mena the firs one
initialized, or the lowest start address, or the lowest chip select,
or ... ?


Also, I think you are right, and we should add IH_TYPE_FLATDT_REL as
well.

...
>  	/* Remaining, type dependent properties */
>  	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
>  	    (type == IH_TYPE_RAMDISK) || (type == IH_TYPE_FIRMWARE) ||
> -	    (type == IH_TYPE_FLATDT)) {
> +	    (type == IH_TYPE_FLATDT) || (type == IH_TYPE_KERNEL_REL)) {

Can we please re-arrange this a bit, like that:

	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_KERNEL_REL) ||
	    (type == IH_TYPE_FLATDT) || (type == IH_TYPE_FLATDT_REL) ||
	    (type == IH_TYPE_RAMDISK) || (type == IH_TYPE_FIRMWARE)  ||
	    (type == IH_TYPE_STANDALONE)) {
...

> +		(type == IH_TYPE_FIRMWARE) || (type == IH_TYPE_KERNEL_REL)) {
> +		ret = fit_image_get_load_raw (fit, image_noffset, &raw);
> +		ret |= fit_image_get_load_abs (fit, image_noffset, &abs);

This looks strange to me.  Please add at least a comment what's going
on here.

>  		if (ret)
>  			printf ("unavailable\n");
> -		else
> -			printf ("0x%08lx\n", load);
> +		else {

Need braces in both branches.

>  		if (ret)
>  			printf ("unavailable\n");
> -		else
> -			printf ("0x%08lx\n", entry);
> +		else {

Ditto.

> - * fit_image_get_load - get load address property for a given component image node
> + * fit_image_get_load_raw - get raw load address property for a given component image node

Line too long. [Did you run checkpatch?]

> +/**
> + * fit_image_get_entry_raw - get raw entry point address property for a given component image node

Incorrect multiline comment style.


Hm... this appears to add some additional code.  How much does the
size grow?

Can we make support for relative images optional?

Best regards,

Wolfgang Denk
Stephen Warren - Oct. 7, 2011, 4:11 p.m.
Wolfgang Denk wrote at Friday, October 07, 2011 12:51 AM:
> Dear Stephen Warren,
> 
> In message <1317940584-19528-1-git-send-email-swarren@nvidia.com> you wrote:
> > uImage files contain absolute "load" and "entry" addresses. Such a concept
> > is incompatible with using the same kernel image on multiple SoCs, each with
> > a potentially different SDRAM base. To support that, create a new image type
> > IH_TYPE_KERNEL_REL, which is handled identically to IH_TYPE_KERNEL, except
> > that the "load" and "entry" properties are an offset from the base of SDRAM,
> > rather than an absolute address.
> >
> > "An offset from the base of SDRAM" is specified as:
> > a) CONFIG_SYS_SDRAM_BASE, if set.
> > b) Otherwise, for ARM, the start address of the first bank of SDRAM known
> >    to U-Boot.
> > c) Otherwise, 0.
> 
> I agree with Kumar: it should be sufficient to have this omment in
> the code.

OK. I was trying to make the commit comment standalone so people could
read and understand it without having to go read the whole patch to find
the comment too. I guess I can drop it from the commit description if
you want.

> But please define "first bank" - does it mena the firs one
> initialized, or the lowest start address, or the lowest chip select,
> or ... ?

It's the following currently:

gd->bd->bi_dram[0].start

* How would you describe this; "the first DRAM bank registered with
U-Boot"?

* Is this a good value to use, or should getenv_bootm_low() search through
all banks to find the one with lowest address or something?

> Also, I think you are right, and we should add IH_TYPE_FLATDT_REL as
> well.

OK.

...
> > - * fit_image_get_load - get load address property for a given component image node
> > + * fit_image_get_load_raw - get raw load address property for a given component image node
> 
> Line too long. [Did you run checkpatch?]

Yes, but I though (evidently incorrectly) that the first sentence of
function comments was supposed to be one line for grep'ability.

...
> Hm... this appears to add some additional code.  How much does the
> size grow?

At least when building for Tegra, this adds 576 bytes text, and 136 bytes
rodata. That's about a 0.4% size increase to each section.

> Can we make support for relative images optional?

I guess it's possible. It'll mean a heck of a lot of ifdef's in the
middle of all those multi-test if statements that work on a variety of
image types though. Are the size increases above as large as you feared;
is it worth making it optional?

Thanks for the review.
Wolfgang Denk - Oct. 9, 2011, 6:40 p.m.
Dear Stephen Warren,

In message <74CDBE0F657A3D45AFBB94109FB122FF173B23B262@HQMAIL01.nvidia.com> you wrote:
>
> > But please define "first bank" - does it mena the firs one
> > initialized, or the lowest start address, or the lowest chip select,
> > or ... ?
> 
> It's the following currently:
> 
> gd->bd->bi_dram[0].start
> 
> * How would you describe this; "the first DRAM bank registered with
> U-Boot"?

I would even add above explanation to the commen, i. e. something
like:

	first DRAM bank registered with U-Boot (i. e.
	bd->bi_dram[0].start).

> * Is this a good value to use, or should getenv_bootm_low() search through
> all banks to find the one with lowest address or something?

I would expect that this works on most (all?) of the existing boards;
if a board maps higher addresses first we will probably have to
discuss if this is not a bug.

> > Hm... this appears to add some additional code.  How much does the
> > size grow?
> 
> At least when building for Tegra, this adds 576 bytes text, and 136 bytes
> rodata. That's about a 0.4% size increase to each section.

0.4% of the total image size, not of the code size of this source
file, right?

> I guess it's possible. It'll mean a heck of a lot of ifdef's in the
> middle of all those multi-test if statements that work on a variety of
> image types though. Are the size increases above as large as you feared;
> is it worth making it optional?

0.5 KiB of code is actually quite a lot on some small systems - and
most of them will never need this feature.  This is actually only
needed for ARM so far, so for a _large_ number of boards this is just
overhead.

Best regards,

Wolfgang Denk

Patch

diff --git a/arch/sh/lib/bootm.c b/arch/sh/lib/bootm.c
index 57273fa..71a42b1 100644
--- a/arch/sh/lib/bootm.c
+++ b/arch/sh/lib/bootm.c
@@ -72,7 +72,7 @@  int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima
 	void (*kernel) (void) = (void (*)(void))images->ep;
 	/* empty_zero_page */
 	unsigned char *param
-		= (unsigned char *)image_get_load(images->legacy_hdr_os);
+		= (unsigned char *)image_get_load_raw(images->legacy_hdr_os);
 	/* Linux kernel command line */
 	char *cmdline = (char *)param + COMMAND_LINE;
 	/* PAGE_SIZE */
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 8909ee7..1b93954 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -237,7 +237,7 @@  static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 		images.os.os = image_get_os (os_hdr);
 
 		images.os.end = image_get_image_end (os_hdr);
-		images.os.load = image_get_load (os_hdr);
+		images.os.load = image_get_load_abs (os_hdr);
 		break;
 #if defined(CONFIG_FIT)
 	case IMAGE_FORMAT_FIT:
@@ -264,7 +264,8 @@  static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 
 		images.os.end = fit_get_end (images.fit_hdr_os);
 
-		if (fit_image_get_load (images.fit_hdr_os, images.fit_noffset_os,
+		if (fit_image_get_load_abs (images.fit_hdr_os,
+					images.fit_noffset_os,
 					&images.os.load)) {
 			puts ("Can't get image load address!\n");
 			show_boot_progress (-112);
@@ -279,10 +280,10 @@  static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 
 	/* find kernel entry point */
 	if (images.legacy_hdr_valid) {
-		images.ep = image_get_ep (&images.legacy_hdr_os_copy);
+		images.ep = image_get_ep_abs (&images.legacy_hdr_os_copy);
 #if defined(CONFIG_FIT)
 	} else if (images.fit_uname_os) {
-		ret = fit_image_get_entry (images.fit_hdr_os,
+		ret = fit_image_get_entry_abs (images.fit_hdr_os,
 				images.fit_noffset_os, &images.ep);
 		if (ret) {
 			puts ("Can't get entry point property!\n");
@@ -295,7 +296,8 @@  static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 	}
 
 	if (((images.os.type == IH_TYPE_KERNEL) ||
-	     (images.os.type == IH_TYPE_MULTI)) &&
+	     (images.os.type == IH_TYPE_MULTI) ||
+	     (images.os.type == IH_TYPE_KERNEL_REL)) &&
 	    (images.os.os == IH_OS_LINUX)) {
 		/* find ramdisk */
 		ret = boot_get_ramdisk (argc, argv, &images, IH_INITRD_ARCH,
@@ -813,7 +815,8 @@  static int fit_check_kernel (const void *fit, int os_noffset, int verify)
 	}
 
 	show_boot_progress (106);
-	if (!fit_image_check_type (fit, os_noffset, IH_TYPE_KERNEL)) {
+	if (!fit_image_check_type (fit, os_noffset, IH_TYPE_KERNEL) &&
+	    !fit_image_check_type (fit, os_noffset, IH_TYPE_KERNEL_REL) ) {
 		puts ("Not a kernel image\n");
 		show_boot_progress (-106);
 		return 0;
@@ -890,6 +893,7 @@  static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char * const
 		/* get os_data and os_len */
 		switch (image_get_type (hdr)) {
 		case IH_TYPE_KERNEL:
+		case IH_TYPE_KERNEL_REL:
 			*os_data = image_get_data (hdr);
 			*os_len = image_get_data_size (hdr);
 			break;
diff --git a/common/image.c b/common/image.c
index d38ce4a..808c97d 100644
--- a/common/image.c
+++ b/common/image.c
@@ -136,6 +136,7 @@  static const table_entry_t uimage_type[] = {
 	{	IH_TYPE_INVALID,    NULL,	  "Invalid Image",	},
 	{	IH_TYPE_IMXIMAGE,   "imximage",   "Freescale i.MX Boot Image",},
 	{	IH_TYPE_KERNEL,	    "kernel",	  "Kernel Image",	},
+	{	IH_TYPE_KERNEL_REL, "kernel_rel", "Relative Kernel Image",},
 	{	IH_TYPE_KWBIMAGE,   "kwbimage",   "Kirkwood Boot Image",},
 	{	IH_TYPE_MULTI,	    "multi",	  "Multi-File Image",	},
 	{	IH_TYPE_OMAPIMAGE,  "omapimage",  "TI OMAP SPL With GP CH",},
@@ -160,6 +161,7 @@  static const table_entry_t uimage_comp[] = {
 
 uint32_t crc32 (uint32_t, const unsigned char *, uint);
 uint32_t crc32_wd (uint32_t, const unsigned char *, uint, uint);
+static ulong image_addr_raw_to_abs(uint8_t type, ulong raw);
 #if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
 static void genimg_print_time (time_t timestamp);
 #endif
@@ -191,6 +193,18 @@  int image_check_dcrc (const image_header_t *hdr)
 	return (dcrc == image_get_dcrc (hdr));
 }
 
+uint32_t image_get_load_abs (const image_header_t *hdr)
+{
+	return image_addr_raw_to_abs(image_get_type(hdr),
+					image_get_load_raw(hdr));
+}
+
+uint32_t image_get_ep_abs (const image_header_t *hdr)
+{
+	return image_addr_raw_to_abs(image_get_type(hdr),
+					image_get_ep_raw(hdr));
+}
+
 /**
  * image_multi_count - get component (sub-image) count
  * @hdr: pointer to the header of the multi component image
@@ -301,6 +315,7 @@  void image_print_contents (const void *ptr)
 {
 	const image_header_t *hdr = (const image_header_t *)ptr;
 	const char *p;
+	uint32_t raw, abs;
 
 #ifdef USE_HOSTCC
 	p = "";
@@ -317,8 +332,20 @@  void image_print_contents (const void *ptr)
 	image_print_type (hdr);
 	printf ("%sData Size:    ", p);
 	genimg_print_size (image_get_data_size (hdr));
-	printf ("%sLoad Address: %08x\n", p, image_get_load (hdr));
-	printf ("%sEntry Point:  %08x\n", p, image_get_ep (hdr));
+
+	raw = image_get_load_raw (hdr);
+	abs = image_get_load_abs (hdr);
+	if (abs == raw)
+		printf ("%sLoad Address: %08x\n", p, abs);
+	else
+		printf ("%sLoad Address: %08x (relative %08x)\n", p, abs, raw);
+
+	raw = image_get_ep_raw (hdr);
+	abs = image_get_ep_abs (hdr);
+	if (abs == raw)
+		printf ("%sEntry Point:  %08x\n", p, abs);
+	else
+		printf ("%sEntry Point:  %08x (relative %08x)\n", p, abs, raw);
 
 	if (image_check_type (hdr, IH_TYPE_MULTI) ||
 			image_check_type (hdr, IH_TYPE_SCRIPT)) {
@@ -495,6 +522,18 @@  void memmove_wd (void *to, void *from, size_t len, ulong chunksz)
 }
 #endif /* !USE_HOSTCC */
 
+ulong image_addr_raw_to_abs(uint8_t type, ulong raw)
+{
+	ulong abs = raw;
+
+#ifndef USE_HOSTCC
+	if (type == IH_TYPE_KERNEL_REL)
+		abs += getenv_bootm_low();
+#endif
+
+	return abs;
+}
+
 void genimg_print_size (uint32_t size)
 {
 #ifndef USE_HOSTCC
@@ -891,7 +930,7 @@  int boot_get_ramdisk (int argc, char * const argv[], bootm_headers_t *images,
 
 			rd_data = image_get_data (rd_hdr);
 			rd_len = image_get_data_size (rd_hdr);
-			rd_load = image_get_load (rd_hdr);
+			rd_load = image_get_load_raw (rd_hdr);
 			break;
 #if defined(CONFIG_FIT)
 		case IMAGE_FORMAT_FIT:
@@ -953,7 +992,7 @@  int boot_get_ramdisk (int argc, char * const argv[], bootm_headers_t *images,
 			rd_data = (ulong)data;
 			rd_len = size;
 
-			if (fit_image_get_load (fit_hdr, rd_noffset, &rd_load)) {
+			if (fit_image_get_load_raw (fit_hdr, rd_noffset, &rd_load)) {
 				puts ("Can't get ramdisk subimage load address!\n");
 				show_boot_progress (-129);
 				return 1;
@@ -1445,7 +1484,7 @@  int boot_get_fdt (int flag, int argc, char * const argv[], bootm_headers_t *imag
 			image_start = (ulong)fdt_hdr;
 			image_end = image_get_image_end (fdt_hdr);
 
-			load_start = image_get_load (fdt_hdr);
+			load_start = image_get_load_raw (fdt_hdr);
 			load_end = load_start + image_get_data_size (fdt_hdr);
 
 			if ((load_start < image_end) && (load_end > image_start)) {
@@ -1540,7 +1579,7 @@  int boot_get_fdt (int flag, int argc, char * const argv[], bootm_headers_t *imag
 				image_start = (ulong)fit_hdr;
 				image_end = fit_get_end (fit_hdr);
 
-				if (fit_image_get_load (fit_hdr, fdt_noffset,
+				if (fit_image_get_load_raw (fit_hdr, fdt_noffset,
 							&load_start) == 0) {
 					load_end = load_start + size;
 
@@ -1922,7 +1961,7 @@  void fit_image_print (const void *fit, int image_noffset, const char *p)
 	char *desc;
 	uint8_t type, arch, os, comp;
 	size_t size;
-	ulong load, entry;
+	ulong raw, abs;
 	const void *data;
 	int noffset;
 	int ndepth;
@@ -1961,33 +2000,44 @@  void fit_image_print (const void *fit, int image_noffset, const char *p)
 	/* Remaining, type dependent properties */
 	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
 	    (type == IH_TYPE_RAMDISK) || (type == IH_TYPE_FIRMWARE) ||
-	    (type == IH_TYPE_FLATDT)) {
+	    (type == IH_TYPE_FLATDT) || (type == IH_TYPE_KERNEL_REL)) {
 		fit_image_get_arch (fit, image_noffset, &arch);
 		printf ("%s  Architecture: %s\n", p, genimg_get_arch_name (arch));
 	}
 
-	if (type == IH_TYPE_KERNEL) {
+	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_KERNEL_REL)) {
 		fit_image_get_os (fit, image_noffset, &os);
 		printf ("%s  OS:           %s\n", p, genimg_get_os_name (os));
 	}
 
 	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
-		(type == IH_TYPE_FIRMWARE)) {
-		ret = fit_image_get_load (fit, image_noffset, &load);
+		(type == IH_TYPE_FIRMWARE) || (type == IH_TYPE_KERNEL_REL)) {
+		ret = fit_image_get_load_raw (fit, image_noffset, &raw);
+		ret |= fit_image_get_load_abs (fit, image_noffset, &abs);
 		printf ("%s  Load Address: ", p);
 		if (ret)
 			printf ("unavailable\n");
-		else
-			printf ("0x%08lx\n", load);
+		else {
+			if (abs == raw)
+				printf ("0x%08lx\n", abs);
+			else
+				printf ("0x%08lx (relative 0x%08lx)\n", abs, raw);
+		}
 	}
 
-	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE)) {
-		fit_image_get_entry (fit, image_noffset, &entry);
+	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
+	    (type == IH_TYPE_KERNEL_REL)) {
+		ret = fit_image_get_entry_raw (fit, image_noffset, &raw);
+		ret |= fit_image_get_entry_abs (fit, image_noffset, &abs);
 		printf ("%s  Entry Point:  ", p);
 		if (ret)
 			printf ("unavailable\n");
-		else
-			printf ("0x%08lx\n", entry);
+		else {
+			if (abs == raw)
+				printf ("0x%08lx\n", abs);
+			else
+				printf ("0x%08lx (relative 0x%08lx)\n", abs, raw);
+		}
 	}
 
 	/* Process all hash subnodes of the component image node */
@@ -2275,19 +2325,23 @@  int fit_image_get_comp (const void *fit, int noffset, uint8_t *comp)
 }
 
 /**
- * fit_image_get_load - get load address property for a given component image node
+ * fit_image_get_load_raw - get raw load address property for a given component image node
  * @fit: pointer to the FIT format image header
  * @noffset: component image node offset
  * @load: pointer to the uint32_t, will hold load address
  *
- * fit_image_get_load() finds load address property in a given component image node.
- * If the property is found, its value is returned to the caller.
+ * fit_image_get_load_raw() finds load address property in a given component
+ * image node.  If the property is found, its value is returned to the caller.
+ *
+ * Note that this function returns the raw value encoded into the image file;
+ * the actual value U-Boot will use may be different for "relative" image
+ * formats.
  *
  * returns:
  *     0, on success
  *     -1, on failure
  */
-int fit_image_get_load (const void *fit, int noffset, ulong *load)
+int fit_image_get_load_raw (const void *fit, int noffset, ulong *load)
 {
 	int len;
 	const uint32_t *data;
@@ -2303,19 +2357,58 @@  int fit_image_get_load (const void *fit, int noffset, ulong *load)
 }
 
 /**
- * fit_image_get_entry - get entry point address property for a given component image node
+ * fit_image_get_load_abs - get absolute load address property for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @load: pointer to the uint32_t, will hold load address
+ *
+ * fit_image_get_load_abs() finds load address property in a given component
+ *  image node. If the property is found, its value is returned to the caller.
+ *
+ * Note that this function returns the absolute value that U-Boot should
+ * use when actually loading images, or relocating them to the load address.
+ *
+ * returns:
+ *     0, on success
+ *     -1, on failure
+ */
+int fit_image_get_load_abs (const void *fit, int noffset, ulong *load)
+{
+	int ret;
+	ulong raw;
+	uint8_t type;
+
+	ret = fit_image_get_load_raw(fit, noffset, &raw);
+	if (ret)
+		return ret;
+
+	ret = fit_image_get_type (fit, noffset, &type);
+	if (ret)
+		return ret;
+
+	*load = image_addr_raw_to_abs(type, raw);
+	return 0;
+}
+
+/**
+ * fit_image_get_entry_raw - get raw entry point address property for a given component image node
  * @fit: pointer to the FIT format image header
  * @noffset: component image node offset
  * @entry: pointer to the uint32_t, will hold entry point address
  *
- * fit_image_get_entry() finds entry point address property in a given component image node.
- * If the property is found, its value is returned to the caller.
+ * fit_image_get_entry_raw() finds entry point address property in a given
+ * component image node.  If the property is found, its value is returned to
+ * the caller.
+ *
+ * Note that this function returns the raw value encoded into the image file;
+ * the actual value U-Boot will use may be different for "relative" image
+ * formats.
  *
  * returns:
  *     0, on success
  *     -1, on failure
  */
-int fit_image_get_entry (const void *fit, int noffset, ulong *entry)
+int fit_image_get_entry_raw (const void *fit, int noffset, ulong *entry)
 {
 	int len;
 	const uint32_t *data;
@@ -2331,6 +2424,41 @@  int fit_image_get_entry (const void *fit, int noffset, ulong *entry)
 }
 
 /**
+ * fit_image_get_entry_abs - get absolute entry point address property for a given component image node
+ * @fit: pointer to the FIT format image header
+ * @noffset: component image node offset
+ * @entry: pointer to the uint32_t, will hold entry point address
+ *
+ * fit_image_get_entry_abs() finds entry point address property in a given
+ * component image node.  If the property is found, its value is returned to
+ * the caller.
+ *
+ * Note that this function returns the absolute value that U-Boot should
+ * use when actually executing images.
+ *
+ * returns:
+ *     0, on success
+ *     -1, on failure
+ */
+int fit_image_get_entry_abs (const void *fit, int noffset, ulong *ep)
+{
+	int ret;
+	ulong raw;
+	uint8_t type;
+
+	ret = fit_image_get_entry_raw(fit, noffset, &raw);
+	if (ret)
+		return ret;
+
+	ret = fit_image_get_type (fit, noffset, &type);
+	if (ret)
+		return ret;
+
+	*ep = image_addr_raw_to_abs(type, raw);
+	return 0;
+}
+
+/**
  * fit_image_get_data - get data property and its size for a given component image node
  * @fit: pointer to the FIT format image header
  * @noffset: component image node offset
diff --git a/common/lynxkdi.c b/common/lynxkdi.c
index b23135b..3fd4807 100644
--- a/common/lynxkdi.c
+++ b/common/lynxkdi.c
@@ -25,10 +25,10 @@  DECLARE_GLOBAL_DATA_PTR;
 #if defined(CONFIG_MPC8260) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
 void lynxkdi_boot (image_header_t *hdr)
 {
-	void (*lynxkdi)(void) = (void(*)(void))image_get_ep (hdr);
+	void (*lynxkdi)(void) = (void(*)(void))image_get_ep_raw (hdr);
 	lynxos_bootparms_t *parms = (lynxos_bootparms_t *)0x0020;
 	bd_t *kbd;
-	u32 *psz = (u32 *)(image_get_load (hdr) + 0x0204);
+	u32 *psz = (u32 *)(image_get_load_raw (hdr) + 0x0204);
 
 	memset (parms, 0, sizeof(*parms));
 	kbd = gd->bd;
@@ -42,7 +42,7 @@  void lynxkdi_boot (image_header_t *hdr)
 	 */
 	if (le32_to_cpu (*psz) == image_get_data_size (hdr)) {	/* FIXME: NOT SURE HERE ! */
 		char *args;
-		char *cmdline = (char *)(image_get_load (hdr) + 0x020c);
+		char *cmdline = (char *)(image_get_load_raw (hdr) + 0x020c);
 		int len;
 
 		printf ("Booting Bluecat KDI ...\n");
diff --git a/common/update.c b/common/update.c
index a19f136..b35ef91 100644
--- a/common/update.c
+++ b/common/update.c
@@ -230,7 +230,7 @@  static int update_fit_getparams(const void *fit, int noffset, ulong *addr,
 	if (fit_image_get_data(fit, noffset, &data, (size_t *)size))
 		return 1;
 
-	if (fit_image_get_load(fit, noffset, (ulong *)fladdr))
+	if (fit_image_get_load_raw(fit, noffset, (ulong *)fladdr))
 		return 1;
 
 	*addr = (ulong)data;
diff --git a/include/image.h b/include/image.h
index 352e4a0..678a5dd 100644
--- a/include/image.h
+++ b/include/image.h
@@ -144,6 +144,14 @@ 
  *	U-Boot's command interpreter; this feature is especially
  *	useful when you configure U-Boot to use a real shell (hush)
  *	as command interpreter (=> Shell Scripts).
+ *
+ * Types named IH_TYPE_xxx_REL have load and entry point addresses specified
+ * relative to "the base of SDRAM", where that is specified as:
+ * a) CONFIG_SYS_SDRAM_BASE, if set.
+ * b) Otherwise, for ARM, the start address of the first bank of SDRAM known
+ *     to U-Boot.
+ * c) Otherwise, 0.
+ * The exact algorithm is implemented in getenv_bootm_low().
  */
 
 #define IH_TYPE_INVALID		0	/* Invalid Image		*/
@@ -159,6 +167,7 @@ 
 #define IH_TYPE_IMXIMAGE	10	/* Freescale IMXBoot Image	*/
 #define IH_TYPE_UBLIMAGE	11	/* Davinci UBL Image		*/
 #define IH_TYPE_OMAPIMAGE	12	/* TI OMAP Config Header Image	*/
+#define IH_TYPE_KERNEL_REL	13	/* OS Kernel Image		*/
 
 /*
  * Compression Types
@@ -181,8 +190,8 @@  typedef struct image_header {
 	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
 	uint32_t	ih_time;	/* Image Creation Timestamp	*/
 	uint32_t	ih_size;	/* Image Data Size		*/
-	uint32_t	ih_load;	/* Data	 Load  Address		*/
-	uint32_t	ih_ep;		/* Entry Point Address		*/
+	uint32_t	ih_load_raw;	/* Data	 Load  Address		*/
+	uint32_t	ih_ep_raw;	/* Entry Point Address		*/
 	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
 	uint8_t		ih_os;		/* Operating System		*/
 	uint8_t		ih_arch;	/* CPU architecture		*/
@@ -371,10 +380,13 @@  image_get_hdr_l (magic)		/* image_get_magic */
 image_get_hdr_l (hcrc)		/* image_get_hcrc */
 image_get_hdr_l (time)		/* image_get_time */
 image_get_hdr_l (size)		/* image_get_size */
-image_get_hdr_l (load)		/* image_get_load */
-image_get_hdr_l (ep)		/* image_get_ep */
+image_get_hdr_l (load_raw)	/* image_get_load_raw */
+image_get_hdr_l (ep_raw)	/* image_get_ep_raw */
 image_get_hdr_l (dcrc)		/* image_get_dcrc */
 
+uint32_t image_get_load_abs (const image_header_t *hdr);
+uint32_t image_get_ep_abs (const image_header_t *hdr);
+
 #define image_get_hdr_b(f) \
 	static inline uint8_t image_get_##f(const image_header_t *hdr) \
 	{ \
@@ -429,8 +441,8 @@  image_set_hdr_l (magic)		/* image_set_magic */
 image_set_hdr_l (hcrc)		/* image_set_hcrc */
 image_set_hdr_l (time)		/* image_set_time */
 image_set_hdr_l (size)		/* image_set_size */
-image_set_hdr_l (load)		/* image_set_load */
-image_set_hdr_l (ep)		/* image_set_ep */
+image_set_hdr_l (load_raw)	/* image_set_load_raw */
+image_set_hdr_l (ep_raw)	/* image_set_ep_raw */
 image_set_hdr_l (dcrc)		/* image_set_dcrc */
 
 #define image_set_hdr_b(f) \
@@ -603,8 +615,10 @@  int fit_image_get_os (const void *fit, int noffset, uint8_t *os);
 int fit_image_get_arch (const void *fit, int noffset, uint8_t *arch);
 int fit_image_get_type (const void *fit, int noffset, uint8_t *type);
 int fit_image_get_comp (const void *fit, int noffset, uint8_t *comp);
-int fit_image_get_load (const void *fit, int noffset, ulong *load);
-int fit_image_get_entry (const void *fit, int noffset, ulong *entry);
+int fit_image_get_load_raw (const void *fit, int noffset, ulong *load);
+int fit_image_get_load_abs (const void *fit, int noffset, ulong *load);
+int fit_image_get_entry_raw (const void *fit, int noffset, ulong *entry);
+int fit_image_get_entry_abs (const void *fit, int noffset, ulong *ep);
 int fit_image_get_data (const void *fit, int noffset,
 				const void **data, size_t *size);
 
diff --git a/tools/default_image.c b/tools/default_image.c
index f5bad47..fe420ba 100644
--- a/tools/default_image.c
+++ b/tools/default_image.c
@@ -35,7 +35,8 @@  static image_header_t header;
 
 static int image_check_image_types (uint8_t type)
 {
-	if ((type > IH_TYPE_INVALID) && (type < IH_TYPE_FLATDT))
+	if ((type > IH_TYPE_INVALID) && (type < IH_TYPE_FLATDT) ||
+	    (type == IH_TYPE_KERNEL_REL))
 		return EXIT_SUCCESS;
 	else
 		return EXIT_FAILURE;
@@ -113,8 +114,8 @@  static void image_set_header (void *ptr, struct stat *sbuf, int ifd,
 	image_set_magic (hdr, IH_MAGIC);
 	image_set_time (hdr, sbuf->st_mtime);
 	image_set_size (hdr, sbuf->st_size - sizeof(image_header_t));
-	image_set_load (hdr, params->addr);
-	image_set_ep (hdr, params->ep);
+	image_set_load_raw (hdr, params->addr);
+	image_set_ep_raw (hdr, params->ep);
 	image_set_dcrc (hdr, checksum);
 	image_set_os (hdr, params->os);
 	image_set_arch (hdr, params->arch);