Physical Memory Manager
Re:Physical Memory Manager
there are another reasons for using a page struct. all rely to the fact that "shortcuts" to some infos must be stored in the page frame itself.
some problems i encountred with a stack management system
- suppose you want to free a page table'frame when no entries are mapped into it. if you have page struct you could use a reference count for the page struct and check it with a constant time operation. without a page struct you must loop over all entries to ensure no pages are mapped into this table.
- when you choose to implement a "less fragmentation" kernel heap manager like the slab system. when you want to free an object from a slab/cache manager. you have a void* pointer and you need to find the slab owning this object. with a page struct you can store a pointer to the slab (or another region struct) in this struct and find slab for that void* address simply by checking the page owning this address. wihtout a page struct you need to store a "head" for every object you allocate from the slab.
i'm not sure for the rest (swapp, pages per process) but i think there is a way of doing it without the need of preexistent pages structs (for ex allocating pages structs dynamically whenn needed).
some problems i encountred with a stack management system
- suppose you want to free a page table'frame when no entries are mapped into it. if you have page struct you could use a reference count for the page struct and check it with a constant time operation. without a page struct you must loop over all entries to ensure no pages are mapped into this table.
- when you choose to implement a "less fragmentation" kernel heap manager like the slab system. when you want to free an object from a slab/cache manager. you have a void* pointer and you need to find the slab owning this object. with a page struct you can store a pointer to the slab (or another region struct) in this struct and find slab for that void* address simply by checking the page owning this address. wihtout a page struct you need to store a "head" for every object you allocate from the slab.
i'm not sure for the rest (swapp, pages per process) but i think there is a way of doing it without the need of preexistent pages structs (for ex allocating pages structs dynamically whenn needed).
Re:Physical Memory Manager
I've now managed to use GRUB to get the memory map, etc. When running it in Bochs, this is my output:
And now I have a theoretical question: What is in the gap between 9FC00 and 100000? Where is my kernel? I found the video memory to be loacated in this gap (B8000), for example. And anyway, in the lower memory, there would also be the CMOS map, wouldn't it? So wouldn't it be best to only use memory in upper memory? BTW, can there be more divisions than these two?
Code: Select all
Lower memory: 639Kb
Upper memory: 130048Kb
Memory map:
Map entry:
Base address = 0
Length = 9FC00
Type = 1
Map entry:
Base address = 100000
Length = 7F00000
Type = 1
Re:Physical Memory Manager
See the FAQ - EBDA and ROM.Candamir wrote: What is in the gap between 9FC00 and 100000?
You can find out yourself by defining symbols in your linker script and reading them in your kernel code. There are many threads on this in the forum, and I think, also examples in the FAQ.Where is my kernel?
0x00000400 - 0x000004ff. If you want to use the CMOS map, yes, don't use that area.And anyway, in the lower memory, there would also be the CMOS map, wouldn't it? So wouldn't it be best to only use memory in upper memory?
Yes, sure.BTW, can there be more divisions than these two?
Every good solution is obvious once you've found it.
Re:Physical Memory Manager
Well, I looked up the FAQ and found out that when one's playing with memory below the offset of upper memory, there are quite a few things I wouldn't like to touch (VGA buffer, CMOS, etc.).
And there isn't thaaaaaaaat much memory in lower memory, so would it be feasible to just map my upper memory? Is there anything mapped (devices, anything) I should know in the um?
And BTW, If there can be more than two "partitions", how can I find out which of those belong to lower memory and which not? Is this possible only with the GRUB map or should I sum the lengths of parts until I reach the size given in lower_memory_size (also from GRUB)?
And there isn't thaaaaaaaat much memory in lower memory, so would it be feasible to just map my upper memory? Is there anything mapped (devices, anything) I should know in the um?
And BTW, If there can be more than two "partitions", how can I find out which of those belong to lower memory and which not? Is this possible only with the GRUB map or should I sum the lengths of parts until I reach the size given in lower_memory_size (also from GRUB)?
Re:Physical Memory Manager
Hi,
Use BIOS Interrupt 0x15, eax = 0xE820. This is the same memory map that GRUB will give you, and it'll tell you everything I listed above (except for the hot plug RAM areas and any usable RAM between 0x000C0000 and 0x000FFFFF).
Any entry in this list that is marked as type 0x00000001 is usable RAM, that your OS could/should use - you could probably just ignore anything not marked as type 0x00000001.
Please note that Ralph Brown's Interrupt List is getting a little old - for the most "up-to-date" description of what Interrupt 0x15, eax = 0xE820 could return, see the specification for ACPI version 3.0.
Cheers,
Brendan
For an example, a modern single-CPU machine with 4 GB of RAM could look like this:Candamir wrote:And there isn't thaaaaaaaat much memory in lower memory, so would it be feasible to just map my upper memory? Is there anything mapped (devices, anything) I should know in the um?
- 0x00000000 to 0x000004FF - BIOS Data Area
0x00000500 to 0x0009F2FF - Usable RAM
0x0009F300 to 0x0009FFFF - Extended BIOS Data Area
0x000A0000 to 0x000BFFFF - Video display memory mapping
0x000A0000 to 0x000BFFFF - SMM state save area (under the video display memory)
0x000C0000 to 0x000CFFFF - Video ROM
0x000D0000 to 0x000D7FFF - SCSI ROM
0x000D8000 to 0x000DFFFF - Usable RAM
0x000E0000 to 0x000FFFFF - BIOS ROM
0x00100000 to 0x00EFFFFF - Usable RAM
0x00F00000 to 0x00FFFFFF - Hole for memory mapped ISA devices
0x01000000 to 0x1FFFC7FF - Usable RAM
0x1FFFC800 to 0x1FFFCFFF - ACPI non-volatile space
0x1FFFE000 to 0x1FFFFFFF - ACPI reclaimable space
0x20000000 to 0x3FFFFFFF - Usable RAM
0x40000000 to 0x7FFFFFFF - Faulty RAM
0x80000000 to 0xBFFFFFFF - Usable RAM
0xC0000000 to 0xFEBFFFFF - Hole for memory mapped PCI devices
0xFEC00000 to 0xFEC00FFF - I/O APIC
0xFEC01000 to 0xFECFFFFF - Reserved for I/O APICs
0xFED00000 to 0xFEEFFFFF - Unused (potential HPET area?)
0xFEE00000 to 0xFEE00FFF - Local APIC
0xFEE01000 to 0xFEFFFFFF - Reserved for local APICs
0xFF000000 to 0xFFCFFFFF - Reserved for BIOS ROM
0xFFD00000 to 0xFFFFFFFF - The actual BIOS ROM
0x100000000 to 0x13FFFFFFF - Usable RAM
0x140000000 to 0x3FFFFFFFF - Unused (empty)
0x400000000 to 0x43FFFFFFF - Hot plug RAM area 1 (unused)
0x440000000 to 0x47FFFFFFF - Hot plug RAM area 2 (unused)
0x480000000 to 0x4BFFFFFFF - Hot plug RAM area 3 (unused)
0x4C0000000 to 0x4FFFFFFFF - Hot plug RAM area 4 (unused)
0x500000000 to 0xFFFFFFFFF - Unused (empty)
Candamir wrote:And BTW, If there can be more than two "partitions", how can I find out which of those belong to lower memory and which not? Is this possible only with the GRUB map or should I sum the lengths of parts until I reach the size given in lower_memory_size (also from GRUB)?
Use BIOS Interrupt 0x15, eax = 0xE820. This is the same memory map that GRUB will give you, and it'll tell you everything I listed above (except for the hot plug RAM areas and any usable RAM between 0x000C0000 and 0x000FFFFF).
Any entry in this list that is marked as type 0x00000001 is usable RAM, that your OS could/should use - you could probably just ignore anything not marked as type 0x00000001.
Please note that Ralph Brown's Interrupt List is getting a little old - for the most "up-to-date" description of what Interrupt 0x15, eax = 0xE820 could return, see the specification for ACPI version 3.0.
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re:Physical Memory Manager
One thing that confused me (or my kernel rather) about the BIOS memory map is the fact that it was given in totally random order on my machine, unlike in the emulators, so you might want to sort it first.
Re:Physical Memory Manager
Well, what actually confused me was that Brendan listed +-20 different memory regions, and using GRUB in Bochs, I only got two of them... :-\ Or doesn't GRUB pass the entire memory map? Must I thus implement my own boot loader?
Re:Physical Memory Manager
The map is passed exactly as the BIOS gives it so it all depends on your BIOS.
Its simple until you throw in a large amount of memory (some number of gig), local and IO APICS, memory mapped hardware and all the other 'fun' bits (or bytes, or gigs ).
Its simple until you throw in a large amount of memory (some number of gig), local and IO APICS, memory mapped hardware and all the other 'fun' bits (or bytes, or gigs ).
Re:Physical Memory Manager
Hi,
I'm working to fix this though (and a few other problems)....
Of course I also posted a complex memory map rather than something you'd see every day - 4 GB of RAM, an "ACPI 3.0" faulty RAM entry, and "hot plug" areas (which isn't too likely for desktop machine).
Cheers,
Brendan
The BIOS used by Bochs (and Qemu) is a little broken - it returns RAM below 1 MB, RAM above 1 MB and nothing else. This is wrong. Bochs/Qemu should at least return system areas (they don't support ACPI yet).Candamir wrote:Well, what actually confused me was that Brendan listed +-20 different memory regions, and using GRUB in Bochs, I only got two of them... :-\ Or doesn't GRUB pass the entire memory map? Must I thus implement my own boot loader?
I'm working to fix this though (and a few other problems)....
Of course I also posted a complex memory map rather than something you'd see every day - 4 GB of RAM, an "ACPI 3.0" faulty RAM entry, and "hot plug" areas (which isn't too likely for desktop machine).
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re:Physical Memory Manager
While Bochs / QEMU have a "faulty" memory map, it is fully usuable, right?
As in, you can put stuff in the memory areas the memory map gives you. It just isn't as complete as a map will be on a real PC, right?
I also cleaned your example up a bit Brendan, this to more clearly indicate your memory actually goes above "4 GB" (ie, larger than 32-bits) [the total available memory in that sample is of course different]:
As in, you can put stuff in the memory areas the memory map gives you. It just isn't as complete as a map will be on a real PC, right?
I also cleaned your example up a bit Brendan, this to more clearly indicate your memory actually goes above "4 GB" (ie, larger than 32-bits) [the total available memory in that sample is of course different]:
Code: Select all
0x0 0000 0000 to 0x0 0000 04FF - BIOS Data Area
0x0 0000 0500 to 0x0 0009 F2FF - Usable RAM
0x0 0009 F300 to 0x0 0009 FFFF - Extended BIOS Data Area
0x0 000A 0000 to 0x0 000B FFFF - Video display memory mapping
0x0 000A 0000 to 0x0 000B FFFF - SMM state save area (under the video display memory)
0x0 000C 0000 to 0x0 000C FFFF - Video ROM
0x0 000D 0000 to 0x0 000D 7FFF - SCSI ROM
0x0 000D 8000 to 0x0 000D FFFF - Usable RAM
0x0 000E 0000 to 0x0 000F FFFF - BIOS ROM
0x0 0010 0000 to 0x0 00EF FFFF - Usable RAM
0x0 00F0 0000 to 0x0 00FF FFFF - Hole for memory mapped ISA devices
0x0 0100 0000 to 0x0 1FFF C7FF - Usable RAM
0x0 1FFF C800 to 0x0 1FFF CFFF - ACPI non-volatile space
0x0 1FFF E000 to 0x0 1FFF FFFF - ACPI reclaimable space
0x0 2000 0000 to 0x0 3FFF FFFF - Usable RAM
0x0 4000 0000 to 0x0 7FFF FFFF - Faulty RAM
0x0 8000 0000 to 0x0 BFFF FFFF - Usable RAM
0x0 C000 0000 to 0x0 FEBF FFFF - Hole for memory mapped PCI devices
0x0 FEC0 0000 to 0x0 FEC0 0FFF - I/O APIC
0x0 FEC0 1000 to 0x0 FECF FFFF - Reserved for I/O APICs
0x0 FED0 0000 to 0x0 FEEF FFFF - Unused (potential HPET area?)
0x0 FEE0 0000 to 0x0 FEE0 0FFF - Local APIC
0x0 FEE0 1000 to 0x0 FEFF FFFF - Reserved for local APICs
0x0 FF00 0000 to 0x0 FFCF FFFF - Reserved for BIOS ROM
0x0 FFD0 0000 to 0x0 FFFF FFFF - The actual BIOS ROM
0x1 0000 0000 to 0x1 3FFF FFFF - Usable RAM
0x1 4000 0000 to 0x3 FFFF FFFF - Unused (empty)
0x4 0000 0000 to 0x4 3FFF FFFF - Hot plug RAM area 1 (unused)
0x4 4000 0000 to 0x4 7FFF FFFF - Hot plug RAM area 2 (unused)
0x4 8000 0000 to 0x4 BFFF FFFF - Hot plug RAM area 3 (unused)
0x4 C000 0000 to 0x4 FFFF FFFF - Hot plug RAM area 4 (unused)
0x5 0000 0000 to 0xF FFFF FFFF - Unused (empty)
Re:Physical Memory Manager
Hi,
The problem comes when you're configuring hardware. For example, if you're relocating or assigning memory mapped PCI devices you'd probably look for the highest address not used for anything else, and you'd end up overlapping the areas used by the I/O APIC, local APIC and BIOS because these areas aren't reported as "system" areas.
Of course this isn't the main reason I started my own BIOS - currently my BIOS handles up to 255 CPUs with any combination of chips/cores/hyper-threading and a variety of NUMA configurations, with either version 1.1 or 1.4 of the multi-processor specification tables, and either no ACPI, version 1.0, version 2.0 or version 3.0 of the ACPI tables (with everything auto-detected and auto-created according to BIOS settings).
This means I can create a wide variety of "system topologies" to test my OS in, which is extremely powerful when combined with choice of CPUs and other options that Bochs supports.
Cheers,
Brendan
That depends - the OS can safely use all RAM that is reported.Rob wrote:While Bochs / QEMU have a "faulty" memory map, it is fully usuable, right?
The problem comes when you're configuring hardware. For example, if you're relocating or assigning memory mapped PCI devices you'd probably look for the highest address not used for anything else, and you'd end up overlapping the areas used by the I/O APIC, local APIC and BIOS because these areas aren't reported as "system" areas.
Of course this isn't the main reason I started my own BIOS - currently my BIOS handles up to 255 CPUs with any combination of chips/cores/hyper-threading and a variety of NUMA configurations, with either version 1.1 or 1.4 of the multi-processor specification tables, and either no ACPI, version 1.0, version 2.0 or version 3.0 of the ACPI tables (with everything auto-detected and auto-created according to BIOS settings).
This means I can create a wide variety of "system topologies" to test my OS in, which is extremely powerful when combined with choice of CPUs and other options that Bochs supports.
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re:Physical Memory Manager
I've now implemented by pmm_malloc and pmm_free methods, and they work and are used in my OS to allocate and free single pages. Allright. But when it comes to allocate more pages than just one, I'm stuck. I mean, it's relatively easy to implement a malloc for more than one page, but how can I achieve that the free method knows how many pages it should release when it's only argument is a pointer to the first page?
I'm using a stack/bitmap: Every address (4k-aligned) has an unsigned long. These longs are all linearly stored and when I allocate them, I set bit 0 (reverse when freeing). This is possible because in 4k-aligned addresses, the last n bits (not sure how many) are always 0, so we can use them for other purposes). This is the bitmap part. But now, when a page is allocated or freed, it's index in the array is stored and so, the allocation for one single page is always constant: It takes only one step. That's the stack part.
Could you please tell me if this design (I'm sure it's nothing new) is working and please answer the question in the first paragraph?
Thanks
I'm using a stack/bitmap: Every address (4k-aligned) has an unsigned long. These longs are all linearly stored and when I allocate them, I set bit 0 (reverse when freeing). This is possible because in 4k-aligned addresses, the last n bits (not sure how many) are always 0, so we can use them for other purposes). This is the bitmap part. But now, when a page is allocated or freed, it's index in the array is stored and so, the allocation for one single page is always constant: It takes only one step. That's the stack part.
Could you please tell me if this design (I'm sure it's nothing new) is working and please answer the question in the first paragraph?
Thanks
Re:Physical Memory Manager
The calling code will know the amount of pages it has allocated, therefore it will know how many pages it needs to free. You should take the number of pages to free as an additional parameter. Or if you were to use a structure to describe the page, you could store the allocation in a linked list.Candamir wrote: But when it comes to allocate more pages than just one, I'm stuck. I mean, it's relatively easy to implement a malloc for more than one page, but how can I achieve that the free method knows how many pages it should release when it's only argument is a pointer to the first page?
Cheers,
The Senaus
Re:Physical Memory Manager
@ Candamir:
Your confusion is a result of you naming your functions [tt]...malloc()[/tt] and [tt]...free()[/tt]. You got caught in thinking that they should behave exactly as their user-space namesakes...
My advice is, never name a function after a standard one (malloc(), printf()) if it does not behave exactly like the standard defines. Consciously chose a name that cannot be confused with a standard lib name, ideally using CamelCase naming to make it really, really clear. Call it [tt]AllocPage()[/tt] and [tt]FreePage()[/tt], for example.
Once you did that, you will realize that you are perfectly free to accept and return whatever values you see fit, and to devise whatever design you can think of, because you are in control of both the PMM and your user-space malloc() / free().
That being said, you could keep a table in kernel-space telling you that page X was the first in a chunk of Y pages, and freeing that many pages when page X is released. That keeps this bookkeeping in kernel space, which is to be preferred over the user-space malloc() keeping the information in user space (where it can be corrupted by malware).
Your confusion is a result of you naming your functions [tt]...malloc()[/tt] and [tt]...free()[/tt]. You got caught in thinking that they should behave exactly as their user-space namesakes...
My advice is, never name a function after a standard one (malloc(), printf()) if it does not behave exactly like the standard defines. Consciously chose a name that cannot be confused with a standard lib name, ideally using CamelCase naming to make it really, really clear. Call it [tt]AllocPage()[/tt] and [tt]FreePage()[/tt], for example.
Once you did that, you will realize that you are perfectly free to accept and return whatever values you see fit, and to devise whatever design you can think of, because you are in control of both the PMM and your user-space malloc() / free().
That being said, you could keep a table in kernel-space telling you that page X was the first in a chunk of Y pages, and freeing that many pages when page X is released. That keeps this bookkeeping in kernel space, which is to be preferred over the user-space malloc() keeping the information in user space (where it can be corrupted by malware).
Every good solution is obvious once you've found it.
Re:Physical Memory Manager
Well, I actually think that the physical memory manager doesn't even need to allocate variable size memory chunks. That could be fairly easy made the task of the userland malloc. And the physical memory manager doesn't have to worry about continuous memory chunks, as with paging enabled, two memory blocks can be given virtual addresses so that the /appear/ as continuous, which is ok. Is this correct?
I would like to thank all the people who helped me to design my physical memory manager and I hope that this post shall be of use to other people in the same situation I was. I am now trying to implement paging/virtual addressing, so I think I shall create a topic for that...
Thanks
I would like to thank all the people who helped me to design my physical memory manager and I hope that this post shall be of use to other people in the same situation I was. I am now trying to implement paging/virtual addressing, so I think I shall create a topic for that...
Thanks