Let's start with a simple question, i.e. such a functions:
Code: Select all
int get_addr_in_pte(u32int addr)
{
return (addr >> 12) & 4095;
}
Code: Select all
int get_addr_in_pgd(u32int addr)
{
return addr >> 22;
}
Code: Select all
int get_addr_in_pte(u32int addr)
{
return (addr >> 12) & 4095;
}
Code: Select all
int get_addr_in_pgd(u32int addr)
{
return addr >> 22;
}
your code suggests you're calculating protected mode addresses, not long mode addresses. In long mode, you have:antoni wrote:I read "paging" and "setting up long mode" articles from OSDev wiki
Code: Select all
v & 4095 = offset within page
(v >> 12) & 511 = first level index (PTE), each entry covers 4096 bytes
(v >> (9+12)) & 511 = second level index (PDE) each entry covers 2M
(v >> (9+9+12)) & 511 = third level index, each entry covers 1G
(v >> (9+9+9+12) & 511 = fourth level index, each entry covers 512G
(v >> (9+9+9+9+12) & 65535 = fifth level index, either full 0, or full 1 bits; covers all virtual address space
Code: Select all
void flushcr3()
{
asm("movl %cr3, %eax \n\t movl %eax, %cr3");
}
Code: Select all
paging.c: Assembler messages:
paging.c:56: Error: unsupported instruction `mov'
paging.c:57: Error: unsupported instruction `mov'
Thanks, it worked for me.I would recommend putting it in an assembly language file. Inline ASM is very tricky.
The idea is you have a chain reverse references, rooted in the description of your physical page structure. When you add a virtual mapping to a physical page, a record of that reverse mapping is added to the chain of such references:antoni wrote:There are various structures in memory (multiboot info, ACPI, etc.) that I know the physical address of. I could simply map this same physical address to this same virtual address, but if I want a consistent address space without holes then I need to map virtual addresses to different physical addresses. But in such case I need to know their virtual addresses.
(My kernel only has one address space.)
Code: Select all
struct rmap {
process_address_space asid;
void * address;
struct rmap * next;
};
struct p_page {
/* Stuff describing this physical page */
/* Mappings of this physical page */
struct rmap * rmaps;
};
void add_reverse_mapping(page_t pagenum, process_address_space asid, void * address)
{
struct p_page * page = getpagestruct(pagenum);
struct rmap * rmap = malloc(sizeof(*rmap));
enter_critical_section(page);
rmap->next = page->rmaps;
rmap->asid = asid;
rmap->address = address;
page->rmaps = next;
leave_critical_section(page);
}
void walk_reverse_mapping(page_t pagenum, void (*callback)(process_address_space asid, void * address))
{
struct p_page * page = getpagestruct(pagenum);
enter_critical_section(page);
struct rmap * rmap = page->rmaps;
while(rmap) {
struct rmap * next = rmap->next;
callback(rmap->asid, rmap->address);
rmap = next;
}
leave_critical_section(page);
}
Code: Select all
void unmap_virtual_address(process_address_space asid, void * address);
void unmap_page(page_t pagenum)
{
walk_reverse_mapping(pagenum, unmap_virtual_address);
}
Exactly. You don't tend to need reverse mappings until you have to manage multiple mappings to pages. Until that time, if you have a one to one virtual to physical mapping, as you probably will do for structures such as ACPI data, then you just need the virtual address.iansjack wrote: But the physical address won't have a corresponding virtual address until you have created the mapping. And that means you already know the virtual address as you chose it.
No need to store them.antoni wrote:OK.
But in ACPI tables there are physical addresses of other tables etc. So, of course, I know their virtual addresses in the moment of creating mapping, but where to store them?
Should I update table's content and fill it with virtual addresses? In such case this tables will be filled with both physical and virtual addresses (as I need and thus parse just a small part of this tables) which will be confusing and lead to errors.
I can also store this pointers in my own structures which is hard to implement.
Let's assume ACPI tables is at physical address P, mapped at virtual address V. Every time you read a pointer from the tables, doantoni wrote:And what do you do in your OS?
Code: Select all
effective_ptr = acpi_ptr - P + V
Should be one block only, but if there are more blocks, then just use V1, V2 etc. one for each block depending where you've mapped that block. Just iterate through the memory map, you should find the blocks with starting address and size. If not, then use the RSDP and map the tables as you parse them, you can find the size of each table in their headers. The point is, remove the base physical ACPI address, and add the virtual one where you've mapped (no need to map contiguously, you could map each table at a different page if you'd like).antoni wrote:From what BZT said, I presume that ACPI tables are not distributed throughout the memory, but are in one consistent, homogenous block? If so, how to find its size and where it starts?
I can find RSDP, RSDT, FADT and other tables, but to use offest to describe their location I would have to know where block they are in starts and how big is it.