I finaly managed to enable paging, i have imported the VMM code of frost OS and adapted to my kernel. i understand well how it works now
like frost, it doe not use High Half kernel model:
* the kernel is identity maped to itself , also the console buffer, the vesa lfb are identity mapped
* the gui thread and the idle thread use the kernel's page directory
* each processes have they page directory
* the thread uses the page directory of the owner process
* when the scheduler switch to the thread, it activate the thread's page directory
* when i load a process from an executable (a flat binary): it create a new page directory for it, and activate it; so it can copy the binay data to the app address's space (0x40000000 or 1GiB)
* when a page directory is activated, it is automaticaly synced with the previous page directory (the bottom 255 entries corresponding to the first Gib is copied, so the kernel space is always sync accross all pages directories)
it work well when i load multiples processes before the timer is enabled:
* each process runs, and can receive events from the kernel
i have only a problem when the process ask the kernel to load an executable trought a syscall; the process is well created, and the task also. but when the scheduler switch to that newly created task, it returns a "Invalid OPCode", . (this bug does'nt occurs when the process is asking to create a thread in it's address space,it is like the image was not correctly located to the target location )
Note: when i alocate a physical page (in KMM.bas, method 'PageAlloc') , i map it to a free hole (bellow the 1 gig limit) int the current's context page directory and return the virtual address => normaly when i switch to another task this new mapping should be also synced
for now, the only workaround i have found, is to identity map the physical memory to itself (512 MB with qemu) , when i do that, all work well, there is no more pagefault. but this situation is not ideal (it will not work if there is more than 1gib in the machine)
the code is shared in my github at https://github.com/stephaneweg/little-os
maybe someone can look at it and see if he could find a problem with my logic (the bug is probably somewhere in Kernel/Src/Process.bas, kernel/Src/Thread.Bas, kernel/Src/KMM.bas , kernel/SRC/VMM.Bas , kernel/SRC/Scheduler.bas)
Problem with paging when switch to a newly created Process
Re: Problem with paging when switch to a newly created Proce
Hi,
This isn't to address the original issue but just an idea for consideration: with demand paging all of the issues provided are mitigated: the idea is that when we create a process, we create an address space for it but do not switch to it nor load the process into it. When we execute the process, we let it page fault: then, and only then, do we bring in the pages needed from the executable image into memory and map it. There will be a lot of page faults at the start, however it will gradually diminish and you will end up using a lot less memory in the process. You also won't need to worry about loading anything when creating a process.
This isn't to address the original issue but just an idea for consideration: with demand paging all of the issues provided are mitigated: the idea is that when we create a process, we create an address space for it but do not switch to it nor load the process into it. When we execute the process, we let it page fault: then, and only then, do we bring in the pages needed from the executable image into memory and map it. There will be a lot of page faults at the start, however it will gradually diminish and you will end up using a lot less memory in the process. You also won't need to worry about loading anything when creating a process.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Re: Problem with paging when switch to a newly created Proce
And from thé page fault handler how could i know from where it should load thé executable file?
Re: Problem with paging when switch to a newly created Proce
Hi,
In the case of demand paging, you have (1) the image associated with the process, (2) no PTE's set up for it yet. When a page fault occurs, we are given (3) the address of the faulting instruction. There is another detail however that is used for page swapping -- it is what I call System PTE's. Note I am not aware of any standard terminology here; I call them System PTE's as opposed to Device PTE's and Transitional PTE's. System PTE's have the Active bit set to 0 but contain bit fields used to store operating system specific information about how to find the page. So if the page fault occurs and the address maps to a System PTE we can always grab the page from disk. This idea can easily be extended for demand paging since all processes require a page directory anyways. With this setup, you would set up the page directory with System PTE's so the operating system can confirm valid addresses in the page fault handler and be able to determine the Page Number the respective PTE references to map it in.
In other words, the question of "how could i know from where it should load the executable file" is answered in the same way page swapping works when pages are moved to disk and we have to find and load them again. In summary, you already have a page directory full of inactive PTE's: so store the information in there about where things map. When you bring in a page, the System PTE becomes a Device PTE (valid x86 format) with the Active bit set.
When loading the process, we "map" it into the paging structures with the active bit set to 0 so we can find it later when we actually pull in the data from disk.
The page fault handler might look something like this:
In the case of demand paging, you have (1) the image associated with the process, (2) no PTE's set up for it yet. When a page fault occurs, we are given (3) the address of the faulting instruction. There is another detail however that is used for page swapping -- it is what I call System PTE's. Note I am not aware of any standard terminology here; I call them System PTE's as opposed to Device PTE's and Transitional PTE's. System PTE's have the Active bit set to 0 but contain bit fields used to store operating system specific information about how to find the page. So if the page fault occurs and the address maps to a System PTE we can always grab the page from disk. This idea can easily be extended for demand paging since all processes require a page directory anyways. With this setup, you would set up the page directory with System PTE's so the operating system can confirm valid addresses in the page fault handler and be able to determine the Page Number the respective PTE references to map it in.
In other words, the question of "how could i know from where it should load the executable file" is answered in the same way page swapping works when pages are moved to disk and we have to find and load them again. In summary, you already have a page directory full of inactive PTE's: so store the information in there about where things map. When you bring in a page, the System PTE becomes a Device PTE (valid x86 format) with the Active bit set.
When loading the process, we "map" it into the paging structures with the active bit set to 0 so we can find it later when we actually pull in the data from disk.
The page fault handler might look something like this:
Code: Select all
PUBLIC void ExPageFault(IN VIRTUAL_ADDRESS address) {
if (!IsUserModeAddress (address))
Bugcheck(EX_PAGE_FAULT);
if (IsSystemPTE(GetPteFromAddress(address)) {
ExMapSystemPTE (address);
ExLoadPage(address);
}
TerminateProcess(EX_PAGE_FAULT);
}
PUBLIC void ExMapSystemPTE (IN VIRTUAL_ADDRESS address) {
PPTE pte;
pte = GetPteFromAddress (address);
pte->u.PFN = AllocFrame ();
pte->active = 1;
}
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}