Page 1 of 2
Calculate the address spaces my kernel is occupying?
Posted: Thu Jul 28, 2022 7:42 pm
by nightcrawler
I have set the starting address of my linker to be at 16 bytes using linker.ld:
Code: Select all
ENTRY(_start)
SECTIONS
{
. = 16;
}
I'm not sure if this config makes all the .data and .text sections to be right next to each other?
If it does then is there a way to see how much memory the kernel itself is occupying after grub loads it into memory? i.e how can the kernel tell where the safe and free address space starts which wont overwrite the kernel itself?
For the sake of simplicity don't worry about stack at the moment.
Re: Calculate the address spaces my kernel is occupying?
Posted: Thu Jul 28, 2022 8:03 pm
by nexos
Yes, change your linker script to this
Code: Select all
ENTRY(_start)
SECTIONS
{
. = 16;
.text : ALIGN(4K)
{
*(.text)
}
/* Read-only data. */
.rodata : ALIGN(4K)
{
*(.rodata)
}
/* Read-write data (initialized) */
.data : ALIGN(4K)
{
*(.data)
}
/* Read-write data (uninitialized) and stack */
.bss : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
end = .;
}
Then in you C code do:
Code: Select all
extern uint32_t end[];
uint32_t ksize = end - 16;
ksize contains the size of you kernel in bytes.
I included sections in the above linker script because it's a good idea to be explicit about alignment. One more thing: putting your kernel's base at address 0x16 is not a good idea for a number of reasons. That region of memory is reserved by the BIOS. I recommend putting your kernel at 0x100000, as that is not used by the BIOS for anything.
Look at the
memory map page on the wiki for more info on this.
Re: Calculate the address spaces my kernel is occupying?
Posted: Thu Jul 28, 2022 8:18 pm
by nightcrawler
Thank you, can a pointer be used instead of the array? i.e something like this
```
extern uint32_t *end;
```
or an array must be used?
Re: Calculate the address spaces my kernel is occupying?
Posted: Thu Jul 28, 2022 8:54 pm
by nightcrawler
Looks like it has to be an array, compiler needs to do it's trick where it makes an array look like a pointer. It's not allocating an actual pointer variable, so arrays are needed.
Re: Calculate the address spaces my kernel is occupying?
Posted: Fri Jul 29, 2022 2:00 am
by davmac314
nexos wrote:Yes, change your linker script to this
Code: Select all
ENTRY(_start)
SECTIONS
{
. = 16;
.text : ALIGN(4K)
That seems a little whack. Since you've just set ". = 16" won't the next line put ".text" right on the 4k mark? Which means ". = 16" is effectively ". = 4K".
Then in you C code do:
Code: Select all
extern uint32_t end[];
uint32_t ksize = end - 16;
ksize contains the size of you kernel in bytes.
No, it won't, due to the kernel really starting at 4k and due to the fact that subtracting 16 from a uint32_t pointer will effectively subtract 64 (i.e. 16 * sizeof(uint32_t)) before the conversion back to integer. And you really should use a cast (from pointer type back to uint32_t). (And if this is for a 64-bit kernel you'll want to use a uint64_t instead, or you'll get a compilation error).
I suggest using an opaque, never-defined struct type instead of an array, and casting to char * for the arithmetic:
Code: Select all
extern struct opaque end;
uint32_t ksize = (uint32_t)((char *)&end - 32);
(Though as I said, subtracting 32 probably won't give you the right answer here anyway).
Using an incomplete struct type prevents you from accidentally using the *value* instead of the *address*.
One more thing: putting your kernel's base at address 0x16 is not a good idea for a number of reasons. That region of memory is reserved by the BIOS. I recommend putting your kernel at 0x100000, as that is not used by the BIOS for anything.
The address is virtual, it doesn't need to correspond to the physical address where the kernel is loaded.
Re: Calculate the address spaces my kernel is occupying?
Posted: Fri Jul 29, 2022 4:24 am
by kzinti
Building on the previous reply, why not simply define a symbol at the start of the kernel as well. This way you don't need to do any arithmetics using magic numbers. Another suggestion would be to just declare the symbols as char[] and get rid of the casts. Finally use size_t to hold the kernel size, don't hardcode a uint32_t or uint64_t there...
Code: Select all
extern char _kernel_start[];
extern char _kernel_end[];
...
size_t kernel_size = _kernel_end - kernel_start;
Re: Calculate the address spaces my kernel is occupying?
Posted: Fri Jul 29, 2022 4:44 am
by nexos
davmac314 wrote:That seems a little whack. Since you've just set ". = 16" won't the next line put ".text" right on the 4k mark? Which means ". = 16" is effectively ". = 4K".
It depends on if you count alignment space a part of the kernel. But it would make more sense to just align the entire base on a 4K aligned area.
davmac314 wrote:No, it won't, due to the kernel really starting at 4k and due to the fact that subtracting 16 from a uint32_t pointer will effectively subtract 64 (i.e. 16 * sizeof(uint32_t)) before the conversion back to integer. And you really should use a cast (from pointer type back to uint32_t). (And if this is for a 64-bit kernel you'll want to use a uint64_t instead, or you'll get a compilation error).
I suggest using an opaque, never-defined struct type instead of an array, and casting to char * for the arithmetic:
I admit that part of my post was erroneous. I would recommend this then:
Code: Select all
extern uint8_t end;
uint32_t ksize = (uint32_t)&end - 16;
Then you avoid the the more confusing casts.
davmac314 wrote:The address is virtual, it doesn't need to correspond to the physical address where the kernel is loaded.
The OP hasn't specified if they have set up paging, so I don't know.
Thank you, can a pointer be used instead of the array? i.e something like this
```
extern uint32_t *end;
```
or an array must be used?
It could be a pointer, using would just need to take the address of the pointer, e.g.:
Code: Select all
extern uint32_t* end;
uint32_t ksize = (uint32_t)&end - 16;
kzinti wrote:Building on the previous reply, why not simply define a symbol at the start of the kernel as well.
That's a good idea. I would definitely recommend doing that.
Re: Calculate the address spaces my kernel is occupying?
Posted: Fri Jul 29, 2022 12:49 pm
by nightcrawler
Is `ALIGN(4K)` really needed here? Can it be omitted or the value changed? Also I don't have paging enabled.
Re: Calculate the address spaces my kernel is occupying?
Posted: Fri Jul 29, 2022 2:07 pm
by nexos
nightcrawler wrote:Is `ALIGN(4K)` really needed here? Can it be omitted or the value changed? Also I don't have paging enabled.
If paging is not used, than it is not needed.
Re: Calculate the address spaces my kernel is occupying?
Posted: Fri Jul 29, 2022 2:56 pm
by nightcrawler
So my original method
Code: Select all
ENTRY(_start)
SECTIONS
{
. = 16;
}
is ok to use? or we still need sections without alignment?
Re: Calculate the address spaces my kernel is occupying?
Posted: Fri Jul 29, 2022 3:46 pm
by nexos
Yes, as long as you define the start and end symbols as kzinti suggested. Also, remember that with paging disabled, you should probably put your kernel above 0x100000, as 0x16 physical is reserved.
Re: Calculate the address spaces my kernel is occupying?
Posted: Fri Jul 29, 2022 4:49 pm
by nightcrawler
Thanks, so in its current form, would it look like this?
Code: Select all
ENTRY(_start)
SECTIONS
{
. = 16;
start = .;
end = .;
}
i.e `start` is put before `16` or after it?
Re: Calculate the address spaces my kernel is occupying?
Posted: Fri Jul 29, 2022 6:28 pm
by kzinti
Why do you want that 16 there at all? What is it doing for you?
Re: Calculate the address spaces my kernel is occupying?
Posted: Fri Jul 29, 2022 8:36 pm
by nightcrawler
Assume its any other number, like 1M, would this work?
Re: Calculate the address spaces my kernel is occupying?
Posted: Fri Jul 29, 2022 9:21 pm
by nexos
You need to explicitly put the sections between start and end. As it currently stands, the sections will probably be after the end symbol.