1

So I'm developing for an embedded Linux system and we had some trouble with an external watchdog chip which needed to be fed very early in the boot process.

More specifically, from what we could work out it would this external watchdog would cause a reset while the kernel was decompressing its image in the pre-boot environment. Not enough down time before it starts needing to be fed, which should probably have been sorted in hardware as it is external, but an internal software solution is wanted.

The solution from one of our developers was to put in some extra code into...

int zlib_inflate(z_streamp strm, int flush) in the lib/zlib_inflate/inflate.c kernel code

This new code periodically toggles the watchdog pin during the decompression.

Now besides the fact that I feel like this is a little bit of a dirty hack. It does work, and it has raised an interesting point in my mind. Because this lib is used after boot as well. So is there a nice way for a bit of code detecting whether you're in the pre-boot environment? So it could only preform this toggling pre-boot and not when the lib is used later.

As an aside, I'm also interested in any ideas to avoid the hack in the first place.

sawdust
  • 16,103
  • 3
  • 40
  • 50
Clayton Mills
  • 86
  • 1
  • 9
  • *"Because this lib is used after boot as well."* -- Wouldn't the boot decompressor have its own copy of this library code? Otherwise you would have a chicken versus egg situation. – sawdust Feb 18 '15 at 18:27
  • 1
    If you're using U-Boot in the boot sequence, then don't use a **zImage** kernel image, but a compressed **Image** file. And use the decompressors built-in to U-Boot. u-boot-2014.07/lib/zlib/inflate.c seems to have hooks to perform watchdog reset. See Wolfgang Denk's quote in http://stackoverflow.com/questions/22322304/image-vs-zimage-vs-uimage/22338835#22338835 – sawdust Feb 18 '15 at 18:45
  • I'm sure it has its own compiled binary copy but from what I can tell it is compiled from the same source. Which has the hack coded into it. We are using u-boot, I'll have a look into it. Thanks. – Clayton Mills Feb 18 '15 at 18:51

4 Answers4

3

So is there a nice way for a bit of code detecting whether you're in the pre-boot environment?

You're asking an XY question.
The solution to the X problem can be cleanly solved if you are using U-Boot.
(BTW instead of "pre-boot", i.e. before boot, you probably mean "boot", i.e. before the kernel is started.)

If you're using U-Boot in the boot sequence, then you do not have to hack any boot or kernel code. Apparently you are booting a self-extracting compressed kernel in a zImage (or a zImage within a uImage) file. The hack-free solution is described by U-Boot's author/maintainer, Wolfgang Denk:

It is much better to use normal (uncompressed) kernel image, compress it using just gzip, and use this as poayload for mkimage. This way U-Boot does the uncompresiong instead of including yet another uncompressor with each kernel image.

So instead of make uImage, do a simple make.
Compress the Image file, and then encapsulate it with the U-Boot wrapper using mkimage (and specify the compression algorithm that was applied so that U-Boot can use its built-in decompressor) to produce your uImage file.

When U-Boot loads this uImage file, the wrapper will indicate that it's a compressed file.
U-Boot will execute its internal decompressor library, which (in recent versions) is already watchdog aware.

sawdust
  • 16,103
  • 3
  • 40
  • 50
  • Confirmed this answer and that u-boot decompression is watchdog aware back at the version we are using (which is v2012.10). Thanks @sawdust. – Clayton Mills Feb 19 '15 at 09:32
  • My apologies, you're right my terminology "pre-boot" could be confusing. I was attempting to signify the point when the image is being decompressed, which as you correctly said, is still technically part of "boot". Though comments in the kernel source seem to refer to the code that is performing the decompression as being either in or out of the "pre-boot environment". – Clayton Mills Feb 19 '15 at 10:52
1

Quick and dirty solution off the top of my head:

Make a global static variable in the file that's initialized to 1, and as long as it's 1, consider that "pre-boot".

Add a *_initcall (choose whichever fits your needs. I'm not sure when the kernel is decompressed) to set it to 0.

See include/linux/init.h in the kernel tree for initcall levels.

talshorer
  • 662
  • 3
  • 9
  • Similar to what we had come up with. Defined a global int flag = 1 in a portion of code that was boot specific and the same int flag = 0 in a portion of code that was for the rest of kernel. Then defined it as an extern int in the decompression code and used it to gate the watchdog toggle. It works as the linker only finds the one for each instance during linking. Just feels so dirty, so thought there might be a cleaner way. – Clayton Mills Feb 18 '15 at 19:07
0

See @sawdust answer for an answer on how to achieve the watchdog feeding without having to hack the kernel code.

However this does not fully address the original question of how to detect that code is being compiled in the "pre-boot environment", as it is called within kernel source.

Files within the kernel such as ...

include/linux/decompress/mm.h

lib/decompress_inflate.c

And to a lesser extent (it isn't commented as clearly)...

lib/decompress_unlzo.c

Seem to check the STATIC definition to set "pre-boot environment" differences. Such as in this excerpt from include/linux/decompress/mm.h ...

#ifdef STATIC

/* Code active when included from pre-boot environment: */

...

#else /* STATIC */

/* Code active when compiled standalone for use when loading ramdisk: */

...

#endif /* STATIC */
Clayton Mills
  • 86
  • 1
  • 9
0

Another idea can be disabling watchdog from bootloader and enabling it from user space once system has booted completely.

Hercules dd
  • 215
  • 1
  • 5