Hi,
Is there any way to get information about stack and heap at runtime in a C function? I'm looking for a var/table/way to get Stack_Base, Heap_base, Stack_limit and heap_limit at runtime.
That's because I'm trying to make a very very small multitasking kernel for Cortex-M3 and I need somehow to know the Stack memory avail for my alloc routines.
Regards,
Christos Houtouridis, Electrical Engineer
Hi again.
Yes. But where is that RAM, used as stack, after init and what's the size of it? A kernel needs to know the avail memory.
Christos Houtouridis
That depends on the hardware your kernel is designed to run on. The point is: you should not care. If you program builds/links, you have the RAM you need and that's it !
Somehow, you need to invent tasks.
You either use an existing OS kernel. Then that kernel documentation tells you if the stacks for the tasks are statically assigned or dynamically assigned or if you have to supply the stack blocks as parameter when creating the tasks.
Or you write your own OS kernel - in that case it is totally up to you to figure out what to do with the available RAM in the processor.
The startup code normally set up one stack for the main loop (i.e. the stack used when entering main()". Depending on architecture, it may set up a number of extra stacks for interrupt handlers etc.
But unless the OS kernel replaces the normal startup file, then the space for task stacks are created as normal array variables, or by allocating using malloc()/new or by some OS-specific heap implementation.
So: if you make a kernel for task switching, then you decide how to use the RAM. So you will know (after having decided what to do) how to know everything (or nothing or something in between) about stack space etc.
Any kernel that is able to switch stack when task-switching must also be able to figure out if the current stack position is still within the supplied stack, or if the stack pointer have moved out-of-bounds.
So in the end, it really isn't much we can help you with. Only you - the designer of your OS kernel - can know the answers to your questions.
For start thanks for your answers. And even if I dont understand how this thread became a discussion about kernel development, I have to explain a little more about the "situation".
Our kernel does very few staff. Among them it/he allocates memory for tasks and by task I mean functions. This kernel is to be compiled together with the rest of the project each time. Our kernel doesn't have its own malloc/free mechanism nor advanced memory management nor uses MPU. for mm I just want to keep track of how much memory i have for stack, how much memory a task asks for (at task creation) and the kernel will give the memory to the task for stack. After that the context switching routine will know where to go(SP and PC) for each task at switching.
But.... CCARM has a user configuration trick for stack and heap initialization in startupxxx.s. CCARM also calculates how much ram he needs for globals/ZI etc and leaves the rest to the user for stack and heap. I dont want to mess with the globals. So i need to know where CCARM put the stack and heap in order to take that memory and give it to my simple memory allocator.
Thats why i have ask. "Is there any way to get information about stack and heap at runtime in a C function? I'm looking for a var/table/way to get Stack_Base, Heap_base, Stack_limit and heap_limit at runtime."
The Stack_Base, Heap_base etc are the values that CCARM initialize. I only need them when the kernel starts. Not hole the time. How can I retrieve them?
I also have to tell you that I'm Electrical Engineer and not a software engineer. So be kind :)
And even if I dont understand how this thread became a discussion about kernel development
How could it possibly avoid to be? What you're asking about is kernel development, after all.
But since you seem to have only listed quite a number of features your kernel doesn't have, but hardly any that it does, that makes it hard to get a feel for what kind of kernel development it is.
But.... CCARM has
Just in case: that name appears mispelled, and the nearest correct spelling would be sign of trouble. CARM is a long since discontinued compiler for ARM. These days you should be using the RealView compiler, a.k.a. armcc.
I also have to tell you that I'm Electrical Engineer and not a software engineer.
Then seriously, please get yourself one to help you out. Or just use one of the existing RTOSes instead of rolling your own. Designing an RTOS kernel, even a little one, takes some rather special expertise that your line of education most likely didn't provide. Nor can that expertise be fully replaced by internet advice.
Just in case: that name appears misspelled, and the nearest correct spelling would be sign of trouble. CARM is a long since discontinued compiler for ARM. These days you should be using the RealView compiler, a.k.a. armcc.
Yes you're right. It's armcc and not ccarm. Sorry.
And yes my kernel will be very small and I also avoid features in the previous post. But It's a forum post. What should I wrote?
Anyway. Is there any way to retrieve the place and size of the stack (and heap), that initially ARMCC placed in RAM? This is the same technique a UNIX-like kernel does when loads the RAM info from BIOS at boot time, in order to init the virtual page allocator and the kernel's free range list. I want to do the same thing but with a simpler allocator and with a smaller portion of ram. I will leave the globals and the compilers loading mechanism out.
In startupxxx.s there is Stack_Mem, Stack_Size etc but i don't know how to get their values. I also found struct __initial_stackheap{ unsigned heap_base, stack_base, heap_limit, stack_limit; }; But i didn't figure out how to fill it without re-init the stack and heap.
PS: I should probably publish my project after and also post here the link.
There are no ARMCC that magically place any initial stack or heap into RAM.
There is a startup file, where _you_ specify stack size and heap size.
Next thing - a task for small embedded processors are normally threads - not processes. So they don't allocate any memory for any global variables. All threads share the same global memory - each thread then have own stack space for auto variables.
And you - who implement tasks - can implement solutions for thread-local storage, i.e. for a function call or a global pointer to point at memory reserved for this specific thread. And when you do a task-switch, you remap so another task asking for thread-local storage gets a pointer to different memory.
Next thing: It doesn't matter what compiler you have. When _you_ implement this kernel, then _you_ need to implement a function similar to:
create_thread(tread_function_ptr, stack_pointer,stack_size)
and let stack_pointer point to a global block of RAM (statically or dynamically allocated).
Or you can skip the parameter "stack_pointer" and just supply a "stack_size" parameter - and then let the kernel _you_ write perform the allocation.
So turn it anyway around: It is still _you_, the user of your kernel, that must specify how much stack space each task needs. And you, the user of the kernel, who have to specify how large heap to have. Or implement a different solution instead of malloc()/new - especially since malloc() and new both suffer from potential memory fragmentation. Having 20kB free space on the heap doesn't mean that the 20kB are a single, continuous, block. It can just as well be 10 small 2kB blocks or one 10kB block and 100 blocks of 100 bytes each.
So we are discussing design of kernel functionality just because it is _you_ (or a consultant you pay) who have to implement the functionality you are requesting. But only after you have first managed to set together a specification for how it is expected to function.
A common way to have threads is to have:
uint64_t main_stack[MAIN_STACK_SIZE/8]; uint64_t io_stack[IO_STACK_SIZE/8]; uint64_t alarm_stack[ALARM_STACK_SIZE/8]; void main_task(void) { ... } void io_task(void) { ... } void alarm_task(void) { ... } void main(void) { os_init(); os_start_task(main_task,main_stack,MAIN_STACK_SIZE); os_start_task(io_task,io_stack,IO_STACK_SIZE); os_start_task(alarm_task,alarm_stack,ALARM_STACK_SIZE); os_start_scheduling(); // Doesn't return - starts slicing time between available tasks. }
Dear Per,
For start I have to say that I agree with both of your messages. It is exactly how you describe it. Now. You said "There is a startup file, where _you_ specify stack size and heap size"
And this is the reason I need to pass this _user_demand_ to my kernel. I dont want to specify the avail RAM sizes in two places both the startupxxx.s and in some xxconfig.h header. I need to know how much memory the _user_ (probably me again) decide to left for stack/heap in the startupxxx.s. So my kernel will read this information and do its magic. That's why I ask for a way to read the Stack_base etc...(the labels used in the startup file).
Of course there are ways like "read the SP just after the system init" or "do a search using exception handler", or even "do specify eventually RAM sizes and addresses in two places", but I seek for a much more elegant way.
I have to say that this is not the first time i make my own kernel. I have made one for x86. It is just the first time that i build something so freaking small. And I will make it a small module to use it beside any "my-kernel-compatible" project.
Again - you don't seem to have read the above comments very well - there is no real advantage in having a configuration indicating the amount of memory avail to the kernel. Now rewind, read this sentence once again (exit infinite loop). You don't need this if you allocate all the memory you need in compile time - end of discussion. What is the problem?
Dear Tamir,
There is no problem with that. I just want to avoid the "compile time alloc" thing. Of-course if I can not find a solution i'll use something like that
uint8_t kstack_privil[KERNEL_PRIVILEGED_STACK_SIZE]; uint8_t kstack_unprivil[KERNEL_UNPRIVILEGED_STACK_SIZE];
And I'll make the allocator to give stack slices from these tables.
Christos.
You can always allocate memory from the heap. But remember that systems that are built using such a kernel will require the have heap space allocated as well.