/* Setup a test canary value. */ movl $0x1234, 0x1000
/* Print the canary to make sure it is really there. */ VGA_PRINT_HEX_4 0x1000
/* Make page 0 point to page frame 1(i.e. virtual address 0 points to physical address 4KB) * by setting bit 12 of the Page Table Entry structure. * * At SETUP_PAGING_4M, page_table has been setup to * point page frame 0(i.e. page 0 point to page frame 0). * Bit 12 is the lowest bit of the "Address of 4KB page frame" field, * By setting it, can relocate page 0 point to page frame 1. */ orw $0x1000, page_table
PAGING_ON
/* THIS is what we've been working for!!! * Even though we mov to 0, the paging circuit reads that as physical address 0x1000, * so the canary value 0x1234 should be modified to 0x5678. **/ movl $0x5678, 0
/* Turn paging back off to prevent it from messing with us. */ PAGING_OFF
/* Print the (hopefully) modified value 0x5678. */ VGA_PRINT_HEX_4 0x1000
/* Setup the first Page Directory entry, which gives us a 4MB(2^10 * 2^12) memory region. * The memory region starts at 0, and the virtual address and physical address are identical. * * The currently executing code is inside that range, or else we'd jump somewhere and die. */ .equ page_directory, __end_align_4k .equ page_table, __end_align_4k + 0x1000 .macro SETUP_PAGING_4M LOCAL page_setup_start page_setup_end PUSH_EADX
/* Page Directory setup. */ mov $page_table, %eax /* Clear the low 12 bits of the first Page Directory entry. */ and $0xF000, %ax /* Set the P, R/W, U/S, and A bits of the first Page Directory entry. */ orb $0b00100111, %al /* Setup the first Page Directory entry. */ mov %eax, page_directory
/* Page table setup. */ mov $0, %eax mov $page_table, %ebx page_setup_start: cmp $0x400, %eax je page_setup_end /* Top 20 address bits. */ mov %eax, %edx shl $12, %edx /* For flag bits 0-7. We only set bit 0 and bit 1: * - bit 0: Page present * - bit 1: Page is writable. * Might work without this as the permission also depends on CR0.WP. */ mov $0b00000011, %dl /* Zero flag bits 8-11 */ and $0xF0, %dh /* Setup the PTE(Page Table Entry). */ mov %edx, (%ebx) inc %eax add $4, %ebx jmp page_setup_start page_setup_end: POP_EDAX .endm
/* * Turn paging on. * The cr3 register does have a format, it is not simply the address of the page directory: * * Many tutorials simply ignore bits 3 and 4, and do a direct address mov to `cr3`. * * This sets the 20 top address bits to their correct value, and puts trash in bits 3 and 4, * but it generally works. */ .macro PAGING_ON /* Tell the CPU where the page directory is. */ mov $page_directory, %eax mov %eax, %cr3
/* Turn paging on. */ mov %cr0, %eax or $0x80000000, %eax mov %eax, %cr0 .endm