Calling function from ARM microcontroller's ROM by using pointer to this function?

ivanahepjuk Source

I am working with cec1702 (cortex m4 from microchip), this device a has cryptographic engine, but it is accessible only through microchip's API. I don't want to use official API, because I am trying to use minimal setup only with gcc and for API I would need to download the whole IDE, also I need just a couple of functions..

In document about device's ROM I've founded this list of API functions and their symdef table, for example:

api_rng_mode                        = 0x00007425; 
api_rng_get_random_bytes            = 0x00007441; 

Prototypes of this two functions look like this:

void api_rng_mode(uint8_t tmode_pseudo);
uint32_t api_rng_get_random_bytes ( uint8_t *pbuff8,uint32_t num_bytes);

MY PLAN is to use those functions only by defining pointers to them, but am Am I actually doing it right? For those 2 examples I am using this definitions:

#define api_rng_mode (void(*)(uint8_t))0x00007425
#define api_get_random_bytes (uint32_t(*(uint8_t,uint32_t))0x00007441

And in code I call them like this:

(*api_get_random_bytes)(p, numberofbytes);

But so far it doesn't look working... Any ideas?



answered 5 days ago Ulrich Eckhardt #1

The code may well be correct, but it is borderline unreadable with the added problem of macros that don't respect scopes. Therefore:

// alias the function types by just adding a `typedef`
typedef void api_rng_mode_function(uint8_t tmode_pseudo);
typedef uint32_t api_rng_get_random_bytes_function( uint8_t *pbuff8,uint32_t num_bytes);

That also makes it easier to e.g. mock the functions for unit tests. Then, define pointers to these functions:

// TODO: Add reference to documentation where these magic numbers came from!
api_rng_mode_function*const api_rng_mode = 0x00007425;
api_rng_get_random_bytes_function*const api_rng_get_random_bytes = 0x00007441;

You can then call the according functions using plain function syntax:

uint8_t buffer[17];
uint32_t res = api_rng_get_random_bytes(buffer, sizeof buffer);

Note that the explicit dereferencing (with *) isn't necessary, although it can be done.

The only thing that might still cause problems now is "calling conventions", which is the stack protocol, i.e. the way how arguments are passed on the stack. If the calling function pushes them in the wrong order or if the called function expects some arguments in registers instead, you may need to tell the compiler or even write some inline assembly.

answered 5 days ago P__J__ #2

If you want yo use defines you need to pas the parameters as well

#define api_rng_mode(p) ((void(*)(uint8_t))0x00007425)(p)
#define api_get_random_bytes(p,s) ((uint32_t (*)(uint8_t *,uint32_t))0x00007441)(p,s)

But actually I would wrap them into the inline functions like this:

inline uint32_t api_get_random_bytes(uint8_t *buff, uint32_t size)
    return ((uint32_t (*)(uint8_t *,uint32_t))0x00007441)(buff,size);

comments powered by Disqus