1
votes

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.

4
"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
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 stackoverflow.com/questions/22322304/image-vs-zimage-vs-uimage/…sawdust
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

4 Answers

2
votes

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.

1
votes

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.

0
votes

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 */
0
votes

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