OSDev.org

The Place to Start for Operating System Developers
It is currently Mon May 20, 2024 2:46 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: Calling "Higher Half" Code from Lower Half
PostPosted: Fri Apr 12, 2024 7:35 am 
Offline

Joined: Thu May 12, 2022 6:04 pm
Posts: 6
After setting up my higher half kernel and enabling paging, I started designing my PMM. Then I realized this is a bit backwards. So now I want to use my PMM to allocate memory for my paging structures. But in my PMM, I need to use functions that are mapped to the higher half (namely, memcpy() and memset()). So calling them outright before enabling paging causes a jump to unallocated memory because the MMU is not performing translations yet. As a workaround, I created a function pointer as such:

typedef void (*memset_func_ptr)(void *, const void *, size_t);
And set it to the VA of memset minus the higher half offset:
memset_func_ptr memset_lowerhalf = (void*)((uintptr_t)&memset - HIGHER_HALF_START_ADDR);

However I feel like this is bad design and leads to less readable code. Have any of you come up with a way to simplify interactions between the lower half and higher half? It just feels to me like setting up the linker file such that the bulk of the kernel is mapped to a virtual address is premature because paging hasn't been enabled yet. But maybe the purpose of this is for debugging the ELF binary? I'm not sure. Any insight would be greatly appreciated.


Top
 Profile  
 
 Post subject: Re: Calling "Higher Half" Code from Lower Half
PostPosted: Fri Apr 12, 2024 8:50 am 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1618
Honestly, the cleanest approach is probably going to be to have the lower half and higher half in different executables. This is what I'm doing to avoid such problems, but then, I have to since I am developing a 64-bit OS (and the lower-half code must be 32-bit). In my case, the loader kernel gets the memory info from multiboot, puts itself in the reserved section, puts the main kernel in the reserved section, and then allocates all the paging structures. At the end, it removes itself from the reserved section and hands those structures in a defined way to the higher-half kernel. In this way, there is no added memory footprint since the loader kernel frees itself at the end.

If you insist on continuing on your path, you can probably automate the process somewhat with macros. Such as (untested)
Code:
#define lower_half(x) ((__typeof__(&x))((uintptr_t)(x) - HIGHER_HALF_START_ADDR))
//and then you use it like:
lower_half(memcpy)(dest, src, len);
But I wouldn't want to use such an approach, because the compiler can emit undecorated calls to memcpy/memmove/memset literally everywhere. So that is why I would suggest separate executables. I think I remember Linux doing something similar, with a boot section that is separate from the rest of the kernel.

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: Calling "Higher Half" Code from Lower Half
PostPosted: Fri Apr 12, 2024 9:21 am 
Offline

Joined: Thu May 12, 2022 6:04 pm
Posts: 6
nullplan wrote:
Honestly, the cleanest approach is probably going to be to have the lower half and higher half in different executables. This is what I'm doing to avoid such problems, but then, I have to since I am developing a 64-bit OS (and the lower-half code must be 32-bit). In my case, the loader kernel gets the memory info from multiboot, puts itself in the reserved section, puts the main kernel in the reserved section, and then allocates all the paging structures. At the end, it removes itself from the reserved section and hands those structures in a defined way to the higher-half kernel. In this way, there is no added memory footprint since the loader kernel frees itself at the end.

If you insist on continuing on your path, you can probably automate the process somewhat with macros. Such as (untested)
Code:
#define lower_half(x) ((__typeof__(&x))((uintptr_t)(x) - HIGHER_HALF_START_ADDR))
//and then you use it like:
lower_half(memcpy)(dest, src, len);
But I wouldn't want to use such an approach, because the compiler can emit undecorated calls to memcpy/memmove/memset literally everywhere. So that is why I would suggest separate executables. I think I remember Linux doing something similar, with a boot section that is separate from the rest of the kernel.



This is very helpful, thank you!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot] and 26 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group