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?