Enabling Long Mode [fixed]

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
speal
Member
Member
Posts: 43
Joined: Wed Mar 07, 2007 10:09 am
Location: Minneapolis, Minnesota
Contact:

Enabling Long Mode [fixed]

Post by speal »

Before this code, the following things have been set up, and are working:
1. GDT
2. IDT with handlers
3. Interrupts enabled

main.cpp:

Code: Select all

inline void disableInterrupts()
{
    asm("cli");
}

inline void enablePAE()
{
    asm("mov %cr4, %eax");
    asm("or $0x20, %eax");
    asm("mov %eax, %cr4");
}

inline void installPaging()
{
    asm("mov $0xA00000, %eax");
    asm("mov %eax, %cr3");
}

inline void enableLongMode()
{
    asm("mov $0xC0000080, %ecx");
    asm("rdmsr");
    asm("bts $8, %eax");
    asm("wrmsr");
}

inline void enablePaging()
{
    asm("mov %cr0, %eax");
    asm("bts $31, %eax");
    asm("mov %eax, %cr0");
}

//Create the bottom level page table at 'address' and identity map 2MB of pages
void makePageTable(addr64_t address, addr64_t start)
{
    addr64_t* entries = (addr64_t*)address;
    
    //Mask out the bottom twelve bits of start
    start = start & 0x000FFFFFFFFFF000LL;
    
    int i=0;
    while(i < 512)
    {
	//Set entry to start, with read/write and present bits on
	entries[i] = start | 0x3;
	start += 0x1000;
	i++;
    }
    
    screen.printf("%i: %X\n",511,entries[511]);
}

void makePageDir(addr64_t address)
{
    addr64_t* entries = (addr64_t*)address;
    
    int i=0;
    while(i < 512)
    {
	entries[i] = 0LL;
	i++;
    }
}

void makePageDirEntry(addr64_t address, uint32_t lowbit, addr64_t entry)
{
    addr64_t* entries = (addr64_t*)address;
    uint32_t index = (address >> lowbit) & 0x1FFL;
    
    if(index < 512)
    {
	//Mask out the last 12 bits
	entry = entry & 0x000FFFFFFFFFF000LL; 
	
	//Set entry, and turn on read/write and present bits
	entries[index] = entry | 0x3;
    }
    else
	screen.println("Big error!");
}
    
extern "C" void _main()
{
    screen.clear();
    screen.println("Welcome to my OS64!\n");
    
    screen.printf("%x\n",idt);
    
    screen.println("Disabling Interrupts...");
    disableInterrupts();
    
    screen.println("Enabling Physical Address Extensions...");
    enablePAE();
    
    screen.println("Creating Page Tables...");
    //Create 8MB of identity mapped page tables
    makePageTable(0xA03000,0x000000);
    makePageTable(0xA04000,0x200000);
    makePageTable(0xA05000,0x400000);
    makePageTable(0xA06000,0x600000);
    
    //Make the L2 page directory
    makePageDir(0xA02000);
    makePageDirEntry(0xA02000, 21,0xA03000);
    makePageDirEntry(0xA02000, 21,0xA04000);
    makePageDirEntry(0xA02000, 21,0xA05000);
    makePageDirEntry(0xA02000, 21,0xA06000);
    
    //Make the L3 page directory
    makePageDir(0xA01000);
    makePageDirEntry(0xA01000, 30,0xA02000);
    
    //Make the L4 page directory
    makePageDir(0xA00000);
    makePageDirEntry(0xA00000, 39,0xA01000);
    
    screen.println("Installing Page Tables...");
    installPaging();
    
    screen.println("Enabling Long Mode...");
    enableLongMode();
    
    screen.println("Enabling Paging...");
    enablePaging();
    
    for(;;);
}
All I'm doing (I think) is creating the 4-level paging structures at 10MB. The code as shown will triple-fault and reset the system. If I comment out the call to enablePaging(), the kernel reaches the for(;;); and hangs like you'd expect.

So, what's wrong here?
speal
Member
Member
Posts: 43
Joined: Wed Mar 07, 2007 10:09 am
Location: Minneapolis, Minnesota
Contact:

Post by speal »

I know this whole thing is weird, but here's what I did:

Code: Select all

void makePageDirEntry(addr64_t dir, addr64_t address, uint32_t lowbit, addr64_t entry)
{
    addr64_t* entries = (addr64_t*)dir;
    uint32_t index = (address >> lowbit) & 0x1FFLL;
    
    if(index < 512)
    {
	//Mask out the last 12 bits
	entry = entry & 0x000FFFFFFFFFF000LL; 
	
	//Set entry, and turn on read/write and present bits
	entries[index] = entry | 0x3;
    }
    else
	screen.println("Big error!");
}
I was confusing virtual and physical addresses. This new makePageDirEntry() function is then used like this:

Code: Select all

//Make the L2 page directory
    makePageDir(0xA02000);
    makePageDirEntry(0xA02000, 0x000000, 21, 0xA03000);
    makePageDirEntry(0xA02000, 0x200000, 21, 0xA04000);
    makePageDirEntry(0xA02000, 0x400000, 21, 0xA05000);
    makePageDirEntry(0xA02000, 0x600000, 21, 0xA06000);
    
    //Make the L3 page directory
    makePageDir(0xA01000);
    makePageDirEntry(0xA01000, 0x000000, 30, 0xA02000);
    makePageDirEntry(0xA01000, 0x200000, 30, 0xA02000);
    makePageDirEntry(0xA01000, 0x400000, 30, 0xA02000);
    makePageDirEntry(0xA01000, 0x600000, 30, 0xA02000);
    
    //Make the L4 page directory
    makePageDir(0xA00000);
    makePageDirEntry(0xA00000, 0x000000, 39, 0xA01000);
    makePageDirEntry(0xA00000, 0x200000, 39, 0xA01000);
    makePageDirEntry(0xA00000, 0x400000, 39, 0xA01000);
    makePageDirEntry(0xA00000, 0x600000, 39, 0xA01000);
I realize I don't need the duplicate entries above L2, but it makes it a little easier to follow.[/code]
Post Reply