OSDev.org
https://forum.osdev.org/

How do I construct a pointer to a virtual address?
https://forum.osdev.org/viewtopic.php?f=1&t=36414
Page 1 of 1

Author:  peachsmith [ Sat Jan 04, 2020 10:53 pm ]
Post subject:  How do I construct a pointer to a virtual address?

My current goal is to create a pointer to a contiguous sequence of bytes.
I've enabled paging and have identity mapped the first page table.
As far as I can tell, it looks like I can build a pointer to a single char, but not an array of char.

Here is my attempt at enabling paging, based on the wiki article:
Code:
uint32_t page_directory[1024] __attribute__((aligned(4096)));
uint32_t first_page_table[1024] __attribute__((aligned(4096)));

extern void load_page_directory(uint32_t*);
extern void enable_paging();

void init_paging()
{
   uint32_t i;

   for (i = 0; i < 1024; i++)
   {
      page_directory[i] = 0x00000002;
   }

   // Identity map the first page table
   for (i = 0; i < 1024; i++)
   {
      first_page_table[i] = (i * 0x1000) | 3;
   }

   page_directory[0] = ((uint32_t)first_page_table) | 3;

   load_page_directory(page_directory);
   enable_paging();
}


It was my understanding that on x86 in 32-bit protected mode without PAE enabled, a virtual address is basically a 32-bit number where the 10 most significant bits are the index within a page directory, the next 10 most significant bits are the index within a page table, and the 12 least significant bits are the offset within a physical frame.
If that's the case, then as long as the page table and directory are present, shouldn't the construction of a pointer just be a matter of combining the page directory index, page table index, and frame offset like so?
Code:
uint32_t dir_i = 0;   // directory index [0, 1023]
uint32_t tab_i = 255; // table index     [0, 1023]
uint32_t offset = 0;  // frame offset    [0, 4095]

/**
* The goal of this function is to construct a valid pointer to virtual memory.
* There is currently only one page table with all of its 1024 entries
* populated with identity mapping.
* So the physical addresses 0x00 - 0x3FFFFF are mapped to the virtual
* addresses 0x00 - 0x3FFFFF.
*/
void* build_pointer(size_t n)
{   
   uint32_t v_addr; // a virtual address

   // shift the 10 bit directory index to the left by 22   
   v_addr = dir_i << 22;
   
   // OR the address with the 10-bit table index shifted to the left by 12
   v_addr |= (tab_i << 12);
   
   // for now, we're only allowing allocation within one frame
   // and not worrying about freeing memory
   if (offset + n < 0xFFF)
   {
      v_addr |= offset;
      offset += n;
      return (void*)v_addr;
   }
   
   return NULL;
}


So basically, when I build a pointer to a char near the beginning of a frame, I can set the value pointed to by that pointer to be a single character, but I can't treat the pointer as an array.
Code:
   char* my_char = (char*)build_pointer(3);
   
   my_char[0] = 'A';
   my_char[1] = 'B';
   my_char[2] = 'C';
   
   vga_putchar(my_char[0]); // This prints 'A'
   vga_putchar('\n');
   
   vga_putchar(my_char[1]); // This prints a garbage character
   vga_putchar('\n');
   
   vga_putchar(my_char[2]); // This prints a garbage character
   vga_putchar('\n');


What am I doing wrong?
Is it my alignment?

Author:  nullplan [ Sun Jan 05, 2020 12:48 am ]
Post subject:  Re: How do I construct a pointer to a virtual address?

No, as far as I can see, you've done most of it right. Your problem is the underlying physical memory. In your case, you are identity mapping everything, and the first pointer returned from build_pointer() is 0x000ff000. That is smack in the middle of BIOS ROM, so you cannot write there, or else you destroy the BIOS ROM copy. Use a different page for your experiments, like 0x00001000, which is past the IVT and the BDA and way below the EBDA.

Author:  peachsmith [ Sun Jan 05, 2020 11:24 am ]
Post subject:  Re: How do I construct a pointer to a virtual address?

Thanks! That was the problem.
Looks like I have some reading to do on the x86 physical memory map and detecting memory before I can reliably map frames on the fly.

Author:  bzt [ Sun Jan 05, 2020 11:29 am ]
Post subject:  Re: How do I construct a pointer to a virtual address?

Hi,

@nullplan is right. I'd just like to add that you don't need to construct a pointer. All the translations are done for you by the MMU. See the memory as a contiguous big array of bytes, and don't care which physical page it's mapped to (as long as there's a mapping, present bit set you won't get an exception).

So to "build" a pointer, just simply use
Code:
ptr = 0x00001000;

Because at the early stage it can be very confusing when you're using a physical address or a virtual address, I'd recommend to create two typedefs:
Code:
typedef phys_t uint32_t;
typedef virt_t uint32_t;
and use it like this to make your code more readable:
Code:
ptr = (virt_t)0x00001000;

Cheers,
bzt

Page 1 of 1 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/