OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Apr 19, 2024 4:05 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 14 posts ] 
Author Message
 Post subject: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 2:03 am 
Offline

Joined: Fri Aug 25, 2017 6:03 am
Posts: 7
I am trying to make my OS and trying to implement paging. This is all the paging code.
Code:
   #include "paging.h"
   #include "kheap.h"

   unsigned int* current_dir;

   void init_paging() {
      unsigned int* kernel_directory = (unsigned int*)kmalloc_a(sizeof(unsigned int*) * TABLES_PER_DIRECTORY);
      
      int i, j, address = 0;
                             // 1024
      for(i = 0; i < TABLES_PER_DIRECTORY; i++) {
         kernel_directory[i] = (unsigned int) address;
         unsigned int* table = (unsigned int*) kernel_directory[i];
                                // 1024
         for(j = 0; j < PAGES_PER_TABLE; j++) {
            table[j] = address | 5;    // accessible by all, r/w, present
            address += PAGE_SIZE;  // 4096
         }
         
         kernel_directory[i] |= 5; // same
      }
      
      switch_page_directory(kernel_directory);
      enable_paging();
      
   }

   void enable_paging() {
      write_cr0(read_cr0() | 0x80000000);
   }

   void switch_page_directory(unsigned int* dir) {
      current_dir = dir;
      write_cr3((unsigned int)(dir));
   }


My main function calls init_paging(). After calling it, the screen has some patterns on it indicating that physical 0xb8000 was not mapped to virtual 0xb8000. I am attempting identity paging.

According to the wiki, A page directory entry is essentially a pointer to an array of pages (with the zeros used for flags) and each page table entry a.k.a. page is a number which specifies the physical address of the page. My question is, what specifies the virtual address of a particular page? This is my workspace: https://drive.google.com/open?id=10CsXU ... 1tTkhCjw7y
paging.h has a lot of unused clutter.


Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 2:23 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

agdever wrote:
I am trying to make my OS and trying to implement paging. This is all the paging code.
Code:
   #include "paging.h"
   #include "kheap.h"

   unsigned int* current_dir;

   void init_paging() {
      unsigned int* kernel_directory = (unsigned int*)kmalloc_a(sizeof(unsigned int*) * TABLES_PER_DIRECTORY);
      
      int i, j, address = 0;
                             // 1024
      for(i = 0; i < TABLES_PER_DIRECTORY; i++) {
         kernel_directory[i] = (unsigned int) address;
         unsigned int* table = (unsigned int*) kernel_directory[i];
                                // 1024

I think you forgot to do "address += PAGE_SIZE;" here; which would cause the same physical page of RAM to be used for both a page table and a normal page, which would cause one or both of them to be overwritten/corrupted.

I'd be tempted to have a separate function, like this:

Code:
uint64_t alloc_physical_page(void) {
    uint64_t physical_page = address;
    address += PAGE_SIZE;
    return physical_page;
}


This would make it a lot easier to improve/change later (e.g. add support for "Error: ran out of memory", etc).


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.


Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 3:13 am 
Offline

Joined: Fri Aug 25, 2017 6:03 am
Posts: 7
Thx for replying Brendan.

Code:
   #include "paging.h"
   #include "kheap.h"

   unsigned int* current_dir;

   void init_paging() {
      unsigned int* kernel_directory = (unsigned int*)kmalloc_a(sizeof(unsigned int*) * TABLES_PER_DIRECTORY);
      
      int i, j, address = 0;
      
      for(i = 0; i < TABLES_PER_DIRECTORY; i++) {
         kernel_directory[i] = (unsigned int) address;
         unsigned int* table = (unsigned int*) kernel_directory[i];
         
         address += PAGE_SIZE;
         
         for(j = 0; j < PAGES_PER_TABLE; j++) {
            table[j] = address | 5;    // accessible by all, r/w, present
            address += PAGE_SIZE;
         }
         
         kernel_directory[i] |= 5; // same
      }
      
      switch_page_directory(kernel_directory);
      enable_paging();
      
   }

   void enable_paging() {
      write_cr0(read_cr0() | 0x80000001);
   }

   void switch_page_directory(unsigned int* dir) {
      current_dir = dir;
      write_cr3((unsigned int)(dir));
   }


Now, the virtual machine is crashing again and again and restarting


Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 4:27 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

agdever wrote:
Now, the virtual machine is crashing again and again and restarting


Sorry - I had to be somewhere else and rushed things earlier. I saw "kernel_directory[i] = (unsigned int) address;" and thought you were using "address += PAGE_SIZE;" as a simple physical memory manager during early boot (until later in boot when kernel initialises a proper memory manager after paging is enabled). Now I see that I was mistaken - you're using "kmalloc_a()" to allocate a physical page for the page directory, which means that you should probably also be using "kmalloc_a()" to allocate a physical page for each page table; like this:

Code:
   void init_paging() {
      unsigned int* kernel_directory = (unsigned int*)kmalloc_a(sizeof(unsigned int*) * TABLES_PER_DIRECTORY);
      
      int i, j, address = 0;
      
      for(i = 0; i < TABLES_PER_DIRECTORY; i++) {
         kernel_directory[i] = (unsigned int*)kmalloc_a(sizeof(unsigned int*) * PAGES_PER_TABLE);
         unsigned int* table = (unsigned int*) kernel_directory[i];
         
         for(j = 0; j < PAGES_PER_TABLE; j++) {
            table[j] = address | 5;    // accessible by all, r/w, present
            address += PAGE_SIZE;
         }
         
         kernel_directory[i] |= 5; // same
      }


I also notice that you're mapping the first 4 GiB of the physical address space into the virtual address space, so that it's effectively identical to not using paging at all. This is relatively silly (all it does is waste RAM for page tables, etc).

Typically you want to map the kernel from where it is in physical memory (e.g. physical address 0x00100000) to where you actually want it (e.g. the virtual address 0xC0000000); and then have a single identity mapped page for a tiny little piece of code that does "write_cr0(read_cr0() | 0x80000001);" and jumps to where the kernel actually is; then you want to unmap that single identity mapped page so that all of "user-space" (all of the virtual address space from 0x000000000 to 0xBFFFFFFFF) contains nothing at all (so that it's nice and clean, ready for when you start a process). You also have to figure out what to do with the current stack (easiest is to discard the old stack and initialise a new one in kernel space after).

Note that the initial code to setup paging (and the initial physical memory manager) probably should be written in pure assembly language; partly because it's running at the wrong address (because kernel hasn't been mapped where it should be yet) and partly because you can't change the stack while a C function is relying on it. This is why most people either have a very simple initial physical memory manager that's used before paging is enabled, or just use RAM that was reserved in the ".bss" to avoid having any initial physical memory manager; and then have a proper physical memory manager that's used after paging is enabled.


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.


Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 5:00 am 
Offline

Joined: Fri Aug 25, 2017 6:03 am
Posts: 7
Firstly, the kmalloc_a you added was there before in my original one. I removed it because nothing was working :(
Also, the cast in front of that should be an integer not a pointer even though it acts like one but it doesn't matter.

Now, after making it kmalloc_a, random patterns on my screen appear. This is probably because physical 0xb8000 was not mapped to virtual 0xb8000 or random stuff appeared in the 0xb8000 randomly and I should not think much and simply reset it. Your comments? Also, how do I know that I am doing identity mapping here?

This is the new code:

Code:
#include "paging.h"
#include "kheap.h"
#include "system.h"

#define BITS_IN_A_BYTE 8

unsigned int* current_dir;

unsigned int *frames;
unsigned int nframes = PAGES_PER_TABLE * TABLES_PER_DIRECTORY;

void init_paging() {
   unsigned int* kernel_directory = (unsigned int*)kmalloc_a(sizeof(unsigned int*) * TABLES_PER_DIRECTORY);
   
   int i, j, address = 0;
   
   for(i = 0; i < TABLES_PER_DIRECTORY; i++) {
      kernel_directory[i] = kmalloc_a(sizeof(unsigned int) * PAGES_PER_TABLE);
      unsigned int* table = (unsigned int*) kernel_directory[i];
      
      for(j = 0; j < PAGES_PER_TABLE; j++) {
         table[j] = address | 5;    // accessible by all, r/w, present
         address += PAGE_SIZE;
      }
      
      kernel_directory[i] |= 5; // same
   }
   
   switch_page_directory(kernel_directory);
   enable_paging();
   
}

void enable_paging() {
   write_cr0(read_cr0() | 0x80000001);
}

void switch_page_directory(unsigned int* dir) {
   current_dir = dir;
   write_cr3((unsigned int)(dir));
}



Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 6:02 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

agdever wrote:
Firstly, the kmalloc_a you added was there before in my original one. I removed it because nothing was working :(
Also, the cast in front of that should be an integer not a pointer even though it acts like one but it doesn't matter.

Now, after making it kmalloc_a, random patterns on my screen appear. This is probably because physical 0xb8000 was not mapped to virtual 0xb8000 or random stuff appeared in the 0xb8000 randomly and I should not think much and simply reset it. Your comments? Also, how do I know that I am doing identity mapping here?

This is the new code:


That looks like it should work to me.

The next step would be to run it inside an emulator with a nice debugger. For example, (assuming Bochs) you could put a breakpoint before the "write_cr0(read_cr0() | 0x80000001);", then single-step until the "mov cr0, .." happens and inspect the virtual address space (using "info tab") to see if it looks right; then keep single stepping to see what happens after that (and see which writes causes the random patterns to appear on the screen).


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.


Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 6:08 am 
Offline

Joined: Fri Aug 25, 2017 6:03 am
Posts: 7
I'm using Qemu


Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 6:18 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

agdever wrote:
I'm using Qemu


That should be fine - Qemu has a built in "monitor" (debugger) that you can use that supports most of the same features. I'm just less familiar with Qemu's built in debugger (can't remember the commands, etc).


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.


Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 6:27 am 
Offline

Joined: Fri Aug 25, 2017 6:03 am
Posts: 7
After some old school debugging, here's what I found:
Code:
#include "paging.h"
#include "kheap.h"
#include "system.h"

#define BITS_IN_A_BYTE 8

unsigned int* current_dir;

unsigned int *frames;
unsigned int nframes = PAGES_PER_TABLE * TABLES_PER_DIRECTORY;

void init_paging() {
   ........
      for(j = 0; j < PAGES_PER_TABLE; j++) {
         table[j] = address | 5;    // accessible by all, r/w, present
         //if(address == 0) for(;;);
         address += PAGE_SIZE;
         if(address == 0) for(;;);
      }


On removing the comments from the first infinite loop, the screen stays okay, on commenting it out as shown in the code, it becomes crappy. Do you know what this means?


Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 7:21 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

agdever wrote:
On removing the comments from the first infinite loop, the screen stays okay, on commenting it out as shown in the code, it becomes crappy. Do you know what this means?


Maybe it means that "kmalloc_a()" returned the physical address 0xB8000 (the address of the frame buffer), and your paging code wrote data to the address it allocated (filling the frame buffer/screen) before paging is enabled. Maybe it means that something after the "for(;;)" causes an exception and your exception handler triggers itself, so "infinite recursion" causes your stack to continue growing until it overwrites everything (including the frame buffer/screen). Maybe it means you're executing code that was compiled for 32-bit while you're in (16-bit) real mode (yes, this has happened before!). Maybe an IRQ handler corrupts a register and causes strange things to happen.

Maybe 3 years ago you wrote code to test the screen by writing a "random" pattern to the screen, but now you've forgotten that code is still there and don't realise that there isn't any bug at all! ;)

If you posted all of your code (a link to it) I could probably carefully inspect all of it and might find the real cause of the problem that way; but that won't really help you in the long run (there's always going to be another bug sooner or later).


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.


Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 7:34 am 
Offline

Joined: Fri Aug 25, 2017 6:03 am
Posts: 7
O shoot, I meant the other way...

Code:

for(j = 0; j < PAGES_PER_TABLE; j++) {
         table[j] = address | 5;    // accessible by all, r/w, present
         //if(address == 0) for(;;);
         address += PAGE_SIZE;
         if(address == 0) for(;;);
      }



On commenting the first loop out, the screen becomes crappy (as shown in code), on removing the comments, it becomes normal. It stops address from incrementing. It is the incrementing of the address variable causing the goof up. My workspace there in the first post.


Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 8:24 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,
agdever wrote:
O shoot, I meant the other way...

Code:

for(j = 0; j < PAGES_PER_TABLE; j++) {
         table[j] = address | 5;    // accessible by all, r/w, present
         //if(address == 0) for(;;);
         address += PAGE_SIZE;
         if(address == 0) for(;;);
      }



On commenting the first loop out, the screen becomes crappy (as shown in code), on removing the comments, it becomes normal. It stops address from incrementing. It is the incrementing of the address variable causing the goof up.


If the "//if(address == 0) for(;;);" is uncommented, it stops the address from incrementing and also stops the outer "for(j = 0; j < PAGES_PER_TABLE; j++)" loop (which means that "table[j] = address | 5;" is only executed once when j is zero), and it also stops everything that is after the loop.

It's extremely unlikely that "address += PAGE_SIZE;" is the problem; and very likely that the problem is in one of the many other things that commenting "//if(address == 0) for(;;);" stops.


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.


Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 8:42 am 
Offline

Joined: Fri Aug 25, 2017 6:03 am
Posts: 7
I printed the table address in the i loop when the value at address 0xb8000 wasn't 'H' (it is supposed to be). Guess what I found??

B8000 :lol: :x :P :oops: :cry: :shock:

Now, I need to somehow stop allocating in video memory :P

Any good ideas?


Top
 Profile  
 
 Post subject: Re: How to know the virtual and physical address of a page?
PostPosted: Fri Mar 16, 2018 9:52 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

agdever wrote:
I printed the table address in the i loop when the value at address 0xb8000 wasn't 'H' (it is supposed to be). Guess what I found??

B8000 :lol: :x :P :oops: :cry: :shock:

Now, I need to somehow stop allocating in video memory :P

Any good ideas?


It'd be a lot easier to just use statically allocated memory for your initial page directory and page tables. You can do this like:

Code:
#define INITIAL_PAGE_TABLES TABLES_PER_DIRECTORY

static uint32_t page_directory[TABLES_PER_DIRECTORY] __attribute__ ((aligned (4096)));
static uint32_t page_tables[INITIAL_PAGE_TABLES][PAGES_PER_TABLE] __attribute__ ((aligned (4096)));

void init_paging() {
    uint32_t address;
    for(int i = 0; i < INITIAL_PAGE_TABLES; i++) {
        kernel_directory[i] = page_tables[i] | 5;
        for(int j = 0; j < PAGES_PER_TABLE; j++) {
            page_tables[i][j] = address | 5;
            address += PAGE_SIZE;
        }
    }

   switch_page_directory(page_directory);
   enable_paging();
}


Of course this is still a waste of memory (the "page_tables[][]" will consume 4 MiB of RAM for no sane reason), but it'd be trivial to change it (e.g. use "#define INITIAL_PAGE_TABLES 1" so that you only use one page table - enough to identity map the first 4 MiB, which is probably still 4 times more than you actually need).


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.


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot] and 102 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