Skip to contentSkip to conversation

initrd problem

DISCUSSION Ed Martini 4 participants 11 messages Mar 10, 2005 – Mar 25, 2005 MIPS

lore
Share & tools
lore

Ed Martini

author
#0 lore raw

Background:

I'm trying to get 2.6.11 to run on a MIPS Malta board with Yamon. The kernel that comes with the board is 2.4.18 with an embedded ramdisk that runs some scripts to install RPMS via NFS or CD-ROM. The kernel is converted to s-records via objcopy(1), and loaded into memory via tftp. I want to do something similar with 2.6.latest.

Problem:

On or about Nov 21 of last year, the CONFIG_EMBEDDED_RAMDISK disappeared.

http://www.linux-mips.org/archives/linux-mips/2004-11/msg00135.html

In it's place it is suggested to use the tools in arch/mips/boot, so I tried it. I can cross-compile the kernel, and I get an ELF vmlinux. I can convert it to ecoff with elf2ecoff, and attach an initrd image with addinitrd. The problem begins here. I end up with an ecoff format kernel which is not recognized by objcopy(1), and therefore no s-records.

It seems there is a program called gensrec that would do the job, but google doesn't want to tell me where to get it. Some IRIX binary perhaps?

Solution?

Should I put CONFIG_EMBEDDED_RAMDISK and its ilk back into my kernel, or write an ELF version of addinitrd? Other ideas?

Thanks in advance.

#1 lore raw
Quoted 12 lines · Ed Martini

Background:

I'm trying to get 2.6.11 to run on a MIPS Malta board with Yamon. The kernel that comes with the board is 2.4.18 with an embedded ramdisk that runs some scripts to install RPMS via NFS or CD-ROM. The kernel is converted to s-records via objcopy(1), and loaded into memory via tftp. I want to do something similar with 2.6.latest.

Problem:

On or about Nov 21 of last year, the CONFIG_EMBEDDED_RAMDISK disappeared.

http://www.linux-mips.org/archives/linux-mips/2004-11/msg00135.html

In it's place it is suggested to use the tools in arch/mips/boot, so I tried it. I can cross-compile the kernel, and I get an ELF vmlinux. I can convert it to ecoff with elf2ecoff, and attach an initrd image with addinitrd. The problem begins here. I end up with an ecoff format kernel which is not recognized by objcopy(1), and therefore no s-records.

Quoted 7 lines

It seems there is a program called gensrec that would do the job, but google doesn't want to tell me where to get it. Some IRIX binary perhaps?

Solution?

Should I put CONFIG_EMBEDDED_RAMDISK and its ilk back into my kernel, or write an ELF version of addinitrd? Other ideas?

Thanks in advance.

The future is purportedly in the feature known as initramfs. See the file Documentation/early-userpace/README for more details on how that is supposed to work.

That said, I tried initramfs a few times, but either due to lack of understanding, or broken support code in 2.6.10, I couldn't get it to properly load an initrd bundled in, so I forward-ported a patch I wrote that originally fixed CONFIG_EMBEDDED_RAMDISK to work with any ABI to 2.6.10, and it worked rather well. I'm sticking with this method until I find more/better docs on how to use initramfs properly.

If you're interested, the patch I use can be found here:
http://dev.gentoo.org/~kumba/mips/misc/misc-2.6.10-add-ramdisk-back.patch [2.6.10]
http://dev.gentoo.org/~kumba/mips/misc/misc-2.6.11-add-ramdisk-back.patch [2.6.11]

--Kumba

Signature · 1 line
"Such is oft the course of deeds that move the wheels of the world: small hands do them because they must, while the eyes of the great are elsewhere." --Elrond
#2 lore raw
In reply to Ed Martini
Quoted 10 lines · Ed Martini

I'm trying to get 2.6.11 to run on a MIPS Malta board with Yamon. The kernel that comes with the board is 2.4.18 with an embedded ramdisk that runs some scripts to install RPMS via NFS or CD-ROM. The kernel is converted to s-records via objcopy(1), and loaded into memory via tftp. I want to do something similar with 2.6.latest.

Problem:

On or about Nov 21 of last year, the CONFIG_EMBEDDED_RAMDISK disappeared.

Quoted 7 lines

http://www.linux-mips.org/archives/linux-mips/2004-11/msg00135.html

In it's place it is suggested to use the tools in arch/mips/boot, so I tried it. I can cross-compile the kernel, and I get an ELF vmlinux. I can convert it to ecoff with elf2ecoff, and attach an initrd image with addinitrd. The problem begins here. I end up with an ecoff format kernel which is not recognized by objcopy(1), and therefore no s-records.

I guess that was an act of desperation - YAMON needs SRECs to be happy but doesn't know anything about SRECs.

Quoted 2 lines

It seems there is a program called gensrec that would do the job, but google doesn't want to tell me where to get it. Some IRIX binary perhaps?

make vmlinux.srec; the resulting file will be in arch/mips/boot/vmlinux.srec.

Quoted 2 lines

Should I put CONFIG_EMBEDDED_RAMDISK and its ilk back into my kernel, or write an ELF version of addinitrd? Other ideas?

Things vanish for a reason ... Try CONFIG_INITRAMFS_SOURCE instead.

Ralf

author
#3 lore raw
Quoted 11 lines · Ralf Baechle
Quoted 3 lines · Ed Martini

Should I put CONFIG_EMBEDDED_RAMDISK and its ilk back into my kernel, or write an ELF version of addinitrd? Other ideas?

Things vanish for a reason ... Try CONFIG_INITRAMFS_SOURCE instead.

Ralf

Ok. Then let's get rid of it completly, and provide a replacement that works.

There were vestiges of embedded initrd in the ld script that were confusing when trying to sort things out. That, in conjunction with Documentation/initrd.txt made it hard to discover early user space and initramfs when coming from the old world (2.4).

Also, unless you move the location of .init.ramfs, it gets freed twice, leading to a panic.

From the documentation alone it's impossible to figure out how to build your initramfs. In various places the docs refer to the initial executable as /linuxrc, /kinit, /init, and possibly others. If you read init/main.c you see that for an initramfs, your initial process will be started from /init.

arch/mips/kernel/vmlinux.lds.S 2005-03-15 14:34:00.339164936 -0800 renamed from arch/mips/kernel/vmlinux.lds.S 2005-03-15 13:41:51.000000000 -0800 +7 -11
diff -urN linux-2.6.11-linux-mips.org/arch/mips/kernel/vmlinux.lds.S linux/arch/mips/kernel/vmlinux.lds.S
@@ -54,13 +54,6 @@
 
    *(.data)
 
-   /* Align the initial ramdisk image (INITRD) on page boundaries. */
-   . = ALIGN(4096);
-   __rd_start = .;
-   *(.initrd)
-   . = ALIGN(4096);
-   __rd_end = .;
-
    CONSTRUCTORS
  }
  _gp = . + 0x8000;
@@ -82,6 +75,13 @@
 
  _edata =  .;   /* End of data section */
 
+   /* Align the initial ramfs image on page boundaries. */
+   /* It will be freed by init/initramfs.c */
+  . = ALIGN(4096);
+  __initramfs_start = .;
+  .init.ramfs : { *(.init.ramfs) }
+  __initramfs_end = .;
+
  /* will be freed after init */
  . = ALIGN(4096);  /* Init code and data */
  __init_begin = .;
@@ -118,10 +118,6 @@
  .con_initcall.init : { *(.con_initcall.init) }
  __con_initcall_end = .;
  SECURITY_INIT
-  . = ALIGN(4096);
-  __initramfs_start = .;
-  .init.ramfs : { *(.init.ramfs) }
-  __initramfs_end = .;
  . = ALIGN(32);
  __per_cpu_start = .;
  .data.percpu  : { *(.data.percpu) }
#4 lore raw
Quoted 2 lines · Ed Martini

Ok. Then let's get rid of it completly, and provide a replacement that works.

Way to go.

Quoted 4 lines

There were vestiges of embedded initrd in the ld script that were confusing when trying to sort things out. That, in conjunction with Documentation/initrd.txt made it hard to discover early user space and initramfs when coming from the old world (2.4).

Correct and I've applied that part of your patch already while thinking about the problem you describe below.

Quoted 2 lines

Also, unless you move the location of .init.ramfs, it gets freed twice, leading to a panic.

Interesting one. When I tested the code recently it did work for me and it shouldn't have changed since. The way this is supposed to work is by setting the page_count to 1 by using set_page_count and unmarking the page as reserved, so after that point a free_page should actually succeed - even if done twice as you've observed, first in populate_rootfs then once more in free_initmem.

It seems a frighteningly bad idea though since it relies on no memory from the initrd range being allocated between the two calls - or it would end being freed by force, in use or not. On startup Linux tends to allocate memory starting from high address towards low addresses which must be why we usually get away with this one.

Quoted 5 lines

From the documentation alone it's impossible to figure out how to build your initramfs. In various places the docs refer to the initial executable as /linuxrc, /kinit, /init, and possibly others. If you read init/main.c you see that for an initramfs, your initial process will be started from /init.

I guess I read the code so I didn't notice the lacking qualities of the documentation ...

Ralf

author
#5 lore raw

initrd/initramfs problem

What fails is when CONFIG_BLK_DEV_INITRD and CONFIG_INITRAMFS_SOURCE are both set. I realize (now) that I don't need initrd at all, and initramfs works fine by itself, as you have tested. It seems that the kernel may need some exclusion between these two mechanisms while the difference is sorted out.

I'm not totally up on Kconfig files, but maybe something like this in drivers/block/Kconfig:

config INITRAMFS_SOURCE
string "Initramfs source file(s)"
default ""
depends on BLK_DEV_INITRD=n

Regarding the documenation it would have been helpful to me if Documentation/initrd.txt had a reference to Documentation/early-userspace/README. I'm not sure who maintains that directory, or I'd send a suggestion. tldp.org?

THX
Ed Martini

Original context: http://www.linux-mips.org/archives/linux-mips/2005-03/index.html

Quoted 33 lines · Ralf Baechle
Quoted 3 lines · Ed Martini

Also, unless you move the location of .init.ramfs, it gets freed twice, leading to a panic.

Interesting one. When I tested the code recently it did work for me and it shouldn't have changed since. The way this is supposed to work is by setting the page_count to 1 by using set_page_count and unmarking the page as reserved, so after that point a free_page should actually succeed - even if done twice as you've observed, first in populate_rootfs then once more in free_initmem.

It seems a frighteningly bad idea though since it relies on no memory from the initrd range being allocated between the two calls - or it would end being freed by force, in use or not. On startup Linux tends to allocate memory starting from high address towards low addresses which must be why we usually get away with this one.

Quoted 3 lines

From the documentation alone it's impossible to figure out how to build your initramfs. In various places the docs refer to the initial executable as /linuxrc, /kinit, /init, and possibly others. If you read init/main.c you see that for an initramfs, your initial process will be started from /init.

I guess I read the code so I didn't notice the lacking qualities of the documentation ...

Ralf

author
#6 lore raw

initrd/initramfs problem

In reply to Ralf Baechle

What fails is when CONFIG_BLK_DEV_INITRD and CONFIG_INITRAMFS_SOURCE are both set. I realize (now) that I don't need initrd at all, and initramfs works fine by itself, as you have tested. It seems that the kernel may need some exclusion between these two mechanisms while the difference is sorted out.

I'm not totally up on Kconfig files, but maybe something like this in drivers/block/Kconfig:

config INITRAMFS_SOURCE
string "Initramfs source file(s)"
default ""
depends on BLK_DEV_INITRD=n

Regarding the documenation it would have been helpful to me if Documentation/initrd.txt had a reference to Documentation/early-userspace/README. I'm not sure who maintains that directory, or I'd send a suggestion. tldp.org?

THX
Ed Martini

Original context: http://www.linux-mips.org/archives/linux-mips/2005-03/index.html

Quoted 32 lines · Ralf Baechle
Quoted 3 lines · Ed Martini

Also, unless you move the location of .init.ramfs, it gets freed twice, leading to a panic.

Interesting one. When I tested the code recently it did work for me and it shouldn't have changed since. The way this is supposed to work is by setting the page_count to 1 by using set_page_count and unmarking the page as reserved, so after that point a free_page should actually succeed - even if done twice as you've observed, first in populate_rootfs then once more in free_initmem.

It seems a frighteningly bad idea though since it relies on no memory from the initrd range being allocated between the two calls - or it would end being freed by force, in use or not. On startup Linux tends to allocate memory starting from high address towards low addresses which must be why we usually get away with this one.

Quoted 3 lines

From the documentation alone it's impossible to figure out how to build your initramfs. In various places the docs refer to the initial executable as /linuxrc, /kinit, /init, and possibly others. If you read init/main.c you see that for an initramfs, your initial process will be started from /init.

I guess I read the code so I didn't notice the lacking qualities of the documentation ...

Ralf

author
#7 lore raw

Observations on LLSC and SMP

In reply to Ralf Baechle

In include/asm-mips/ atomic.h, bitops.h and system.h there are a bunch of inline functions which contain this logic:

       if (cpu_has_llsc && R10000_LLSC_WAR) {
               __asm__ (stuff)
       } else if (cpu_has_llsc) {
               __asm__ (other stuff)
       } else {
               C lang stuff;
       }

My two observations relate to both code size and runtime performance. These observations don't affect my situation, so I'm not inclined to spend a bunch of time on it, but maybe someone else is interested. This should be especially interesting since these inline functions are used all over the kernel, so it might actually make a marginally significant difference.

I suppose there's a reason this code is the way it is. If so, feel free to ignore me or flame away.

1. If the first part of the if were an ifdef instead it would result in a code size reduction as well as a runtime performance gain.

2. In atomic.h the "C lang stuff" is wrapped with a spinlock. In the SMP case the spinlock will result in code that contains ll and sc instructions, so I infer that there are no SMP system configs that use CPUs that don't have the ll and sc instructions.

Paranoid version:
-----

       if (cpu_has_llsc) {
#ifdef R10000_LLSC_WAR
               __asm__ (stuff)
#else
               __asm__ (other stuff)
#endif
       } else {
#ifdef CONFIG_SMP
               panic("SMP on CPUs with no LLSC is broken\n");
#else
               C lang stuff;
#endif
       }

-----
Most efficient version:
-----
#ifndef CONFIG_SMP
if (cpu_has_llsc)

#endif
       {
#ifdef R10000_LLSC_WAR
               __asm__ (stuff)
#else
               __asm__ (other stuff)
#endif
       }

-----

#8 lore raw

Re: Observations on LLSC and SMP

Quoted 2 lines · Ed Martini

1. If the first part of the if were an ifdef instead it would result in a code size reduction as well as a runtime performance gain.

You should spend a little time playing with an optimizing compiler. They're capable of working out when a condition will always be false.

Quoted 4 lines

2. In atomic.h the "C lang stuff" is wrapped with a spinlock. In the SMP case the spinlock will result in code that contains ll and sc instructions, so I infer that there are no SMP system configs that use CPUs that don't have the ll and sc instructions.

That's correct. It is not practical to implement SMP without a mutex primitive.

Signature · 2 lines
Daniel Jacobowitz
CodeSourcery, LLC
author
#9 lore raw

Re: Observations on LLSC and SMP

Quoted 10 lines · Daniel Jacobowitz
Quoted 3 lines · Ed Martini

1. If the first part of the if were an ifdef instead it would result in a code size reduction as well as a runtime performance gain.

You should spend a little time playing with an optimizing compiler. They're capable of working out when a condition will always be false.

Yes, but in the case where R10000_LLSC_WAR is true, but cpu_has_llsc returns false there are still two wasted tests, and two blocks of code that the compiler can't optimize out.

#10 lore raw

Re: Observations on LLSC and SMP

Quoted 10 lines · Ed Martini
Quoted 8 lines · Daniel Jacobowitz
Quoted 4 lines · Ed Martini

1. If the first part of the if were an ifdef instead it would result in a code size reduction as well as a runtime performance gain.

Quoted 7 lines
Quoted 4 lines

You should spend a little time playing with an optimizing compiler. They're capable of working out when a condition will always be false.

Yes, but in the case where R10000_LLSC_WAR is true, but cpu_has_llsc returns false there are still two wasted tests, and two blocks of code that the compiler can't optimize out.

Not only is cpu_has_llsc often a constant, R10000_LLSC_WAR will never be true if the CPU does not have LL/SC.

Signature · 2 lines
Daniel Jacobowitz
CodeSourcery, LLC