Share code between bootloader and application

I will use one MCU with integrated USB OTG peripheral for two purposes:

- bootloader for firmware upgrade from USB pendrive

- USB connection to an Android smartphone during application

As you know, USB Host stack is a complex piece of code that has a high Flash size. In my scenario, I need two different USB Host: one for bootloader and one for application.

Is there a possibility to share the USB Host stack between bootloader and application in some way?

Most probably, I'll use a Cortex-Mx MCU with gcc toolchain.

Reply to
pozz
Loading thread data ...

Overlay linkers used to do this kind of thing, but really the right answer now is to create a jump table or a C++ object that implements a virtual interface, and expose it from the bootloader. Then in the application code all you need is a single pointer. Essentially it becomes your USB Host BIOS.

You just need to ensure that any and all library code that gets dragged in is appropriate to both environments, for example, any memory that gets allocated in the bootloader gets freed there too, not by a free() in the app code.

Clifford Heath.

Reply to
Clifford Heath

Yes.

--
Grant Edwards               grant.b.edwards        Yow! MY income is ALL 
                                  at               disposable! 
 Click to see the full signature
Reply to
Grant Edwards

Sure, however, normally boot-loader and application assume that they own everything, and you must ensure no conflicts, by:

1) fix and reserve any static RAM required for the shared code (USB Host and file system) 2) make sure IRQ routing to the USB stack is consistent 3) publish the addresses of anything public in bootloader as an API at a fixed address (table of entry points to functions and ISRs) 4) ensure there is no conflict between C/C++ RTL used in shared code and your application

Avoid dynamic memory in shared code! Reserve and fix memory required for entry point table and dedicated RAM in your linker scripts, and you're all set.

Hope that helps! Best Regards, Dave

Reply to
Dave Nadler

That depends on the capabilities that you require in each "instance" of the stack. Also, on the environment in which you expect each instance to operate! It's usually easier to write a piece of code to rely on MORE facilities (than less).

Typically, boot loaders want to be as "slim" as possible. This helps ensure they are "correct" (no latent bugs that will cause your boot loader to misperform at a later date -- leaving you "stuck"). It also tends to make it easier to "step away" from the boot loader after the image has been pulled in -- less scaffolding to tear down as you transition to "application mode" (e.g., did you remember to disable any services upon which the loader relied that might conflict with services in the application's run-time?)

Reply to
Don Y

If he needs to read USB drives from the bootloader, he's already crossed the Rubicon as far as code complexity goes. Beyond that he just needs to control risks.

I might implement a bootloader for the bootloader, for when things REALLY mess up.

--
Tim Wescott 
Wescott Design Services 
 Click to see the full signature
Reply to
Tim Wescott

What everyone has said so far, plus:

I'm going to go ahead and call it a BIOS here, because that's basically what you're doing.

Whatever you do you need to make sure to make the API between BIOS and application code as consistent as possible. So -- a jump table, or a single address that gets called with parameters, or possibly a guaranteed- unused interrupt that you hijack to branch to the BIOS.

What you absolutely positively don't want to do is to just link the boot code, then link the application code against the boot code's 'native' addresses -- that will pretty much guarantee that each application version will be firmly tied to a boot code version. You want to have a system that maintains interoperability between as wide a range of boot and applications versions. The less interoperability there is, the bigger the configuration nightmare gets.

--
Tim Wescott 
Wescott Design Services 
 Click to see the full signature
Reply to
Tim Wescott

I disagree. I can see lots of opportunities to trim a USB stack that is intended to:

- have COMPLETE control of the hardware

- only talk to one endpoint at a time ("ever")

- has no need to poll

- only support a single ("simple") device class

- not support sub-devices

- operate at a (reduced) data rate that *it* controls

- only support bulk transfers (infinite retries)

- etc.

The OP can potentially pick a single "device" and refuse to "understand" other devices -- even those in the same device class!

Look at the alternative of a full-fledged stack that has to potentially be able to talk to any device class, multiple endpoints per device, multiple devices concurrently, support isochronous transfers, etc. all WHILE ALSO SUPPORTING THE CONCURRENT PRESENCE OF COMPETING "APPLICATIONS".

It's comparable to talking to a UART in *simplex* mode from userland without the benefit of a driver: just spinning on the status register waiting for a character to arrive, retrieving the character, then spinning again -- until the 289 characters that you EXPECT to receive have arrived (in that buffer[289]), THEN checking to see if they make sense before using them.

Contrast that with pulling in characters while "doing something else", parsing the message on the fly and being able to tolerate variations in the data stream (without "Please reboot")

Reply to
Don Y

I suspect that unless you're an absolute freaking USB expert that you'd end up with fragile code. The first thing I would expect is code that only works with certain USB sticks. Not being a freaking USB expert I wouldn't know what else may happen -- but I'd be wary of Something Bad happening.

But, yes, if you pulled it off it may well be smaller.

--
Tim Wescott 
Wescott Design Services 
 Click to see the full signature
Reply to
Tim Wescott

Il 07/06/2016 20:25, Tim Wescott ha scritto:

Il 07/06/2016 20:25, Tim Wescott ha scritto: > On Tue, 07 Jun 2016 21:15:13 +1000, Clifford Heath wrote: > >> On 07/06/16 20:49, pozz wrote: >>> I will use one MCU with integrated USB OTG peripheral for two purposes: >>> >>> - bootloader for firmware upgrade from USB pendrive - USB connection to >>> an Android smartphone during application >>> >>> As you know, USB Host stack is a complex piece of code that has a high >>> Flash size. >>> In my scenario, I need two different USB Host: one for bootloader and >>> one for application. >>> >>> Is there a possibility to share the USB Host stack between bootloader >>> and application in some way? >>> >>> Most probably, I'll use a Cortex-Mx MCU with gcc toolchain. >> >> Overlay linkers used to do this kind of thing, but really the right >> answer now is to create a jump table or a C++ object that implements a >> virtual interface, and expose it from the bootloader. Then in the >> application code all you need is a single pointer. Essentially it >> becomes your USB Host BIOS. >> >> You just need to ensure that any and all library code that gets dragged >> in is appropriate to both environments, for example, any memory that >> gets allocated in the bootloader gets freed there too, not by a free() >> in the app code. >> >> Clifford Heath. > > What everyone has said so far, plus: > > I'm going to go ahead and call it a BIOS here, because that's basically > what you're doing. > > Whatever you do you need to make sure to make the API between BIOS and > application code as consistent as possible. So -- a jump table, or a > single address that gets called with parameters, or possibly a guaranteed- > unused interrupt that you hijack to branch to the BIOS. > > What you absolutely positively don't want to do is to just link the boot > code, then link the application code against the boot code's 'native' > addresses -- that will pretty much guarantee that each application > version will be firmly tied to a boot code version. You want to have a > system that maintains interoperability between as wide a range of boot > and applications versions. The less interoperability there is, the > bigger the configuration nightmare gets. >

Thank for your suggestions and advices. I understand perfectly what you are saying, but it's very difficult for me to really implement them in C and linker script.

It should be nice if there is some example, even about a totally different application, on the net that shows how to achieve what I'd like to do: sharing a set of functions (USB Host stack) between bootloader and application.

Nowadays silicon manufacturers (NXP, Freescale, Microchip, Atmel, ...) publish a lot of example code for their evaluation boards, maybe one of those example shows what I'm trying to do.

Reply to
pozz

Then either your tools or you need upgrading. Sorry if that's too blunt

-- but there's no softer way to put it.

On the bright side, the self-upgrade should be fun.

Locate a function or a jump vector at some fixed point in the boot code, in a way that it will never, ever change. Then use an ioctl-like call to that one spot from the app code. Make sure that the boot code has adequate RAM.

This WILL require dinking with the linker script, or with the project parameters if you use an IDE -- and if you use an IDE, you're almost guaranteed that the protection will be broken with some future upgrade.

In general the example code that I see is written by applications engineers who are both fresh out of school and borderline incompetent. They serve to demonstrate how bits of hardware work, but they usually do so in the stupidest possible manner, which is usually also a manner that makes it impossible to incorporate them into reasonably-written code.

Not that I'm, like, biased or anything, but I would not expect the authors of the crap that I see to even be able to do what's necessary, much less express it in an understandable manner.

--
Tim Wescott 
Wescott Design Services 
 Click to see the full signature
Reply to
Tim Wescott

Tactically, this isn't that great of an idea. You sort of want the bootloader to be ... firewalled from the application. Applications updates fail. USB drives are unreliable.

If the applications update fails and leaves the device bricked....

--
Les Cargill
Reply to
Les Cargill

There's no reason that the stack can't be in a protected "boot sector" of the flash -- and still accessed by the application (whether that application is loaded into an "unprotected" portion of the flash

*or* executes out of RAM).
Reply to
Don Y

If the USB code is within the bootloader, the application cannot interfere with bootloading nor brick the device.

USB drivers ARE unreliable, weekly we have to tell a customer to reformat a USB drive and try again (after FAT corruption on pulling stick out prior writes completed).

Tactically it is an OK idea IFF you're willing to live with inability to update the USB stack. Two weeks ago I had to update the USB stack in a product, and that would not have been possible if the USB stack was in the bootloader...

Hope that clarifies! Best Regards, Dave

Reply to
Dave Nadler

to:

it's not the USB the problem here, it's how the data in the FAT FS are hand led. You would have the same problem with a SD Card.

Bye Jack

Reply to
Jack

itto:

ndled.

Yep, but to the user its a "USB stick problem" Too bad these buggers don't all use a journaling file system, but then the file system code might not fit into small embedded devices...

Reply to
Dave Nadler

1) Add an MicroSD card. 2) Use OTB.

IMO.

--
Les Cargill
Reply to
Les Cargill

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.