# HG changeset patch # User John Tsiombikas # Date 1301168354 -7200 # Node ID 098b1cb5eeaa748fb49f16adcb78c324701c301e # Parent 2cbc2b922e49843471e2f47ea435d14a53dcf959 forgot to add a shitload of files diff -r 2cbc2b922e49 -r 098b1cb5eeaa src/boot/mboot.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/boot/mboot.h Sat Mar 26 21:39:14 2011 +0200 @@ -0,0 +1,103 @@ +#ifndef MBOOT_H_ +#define MBOOT_H_ + +#include + +#define MB_MEM (1 << 0) +#define MB_BOOTDEV (1 << 1) +#define MB_CMDLINE (1 << 2) +#define MB_MODULES (1 << 3) +#define MB_AOUT_SYM (1 << 4) +#define MB_ELF_SHDR (1 << 5) +#define MB_MMAP (1 << 6) +#define MB_DRIVES (1 << 7) +#define MB_CFGTAB (1 << 8) +#define MB_LDRNAME (1 << 9) +#define MB_APM (1 << 10) +#define MB_GFX (1 << 11) + +#define MB_MEM_VALID 1 +#define MB_DRIVE_CHS 0 +#define MB_DRIVE_LBA 1 + +struct mboot_module { + uint32_t start_addr, end_addr; + char *str; + uint32_t reserved; +}; + +struct mboot_elf_shdr_table { + uint32_t num; + uint32_t size; + uint32_t addr; + uint32_t shndx; +}; + +struct mboot_mmap { + uint32_t skip; + uint32_t base_low, base_high; + uint32_t length_low, length_high; + uint32_t type; +}; + +struct mboot_drive { + uint32_t size; + uint8_t id; + uint8_t mode; + uint16_t cyl; + uint8_t heads, sect; + uint16_t ports[1]; /* zero-terminated */ +} __attribute__ ((packed)); + +struct mboot_apm { + uint16_t ver; + uint16_t cseg; + uint32_t offs; + uint16_t cseg16; + uint16_t dseg; + uint16_t flags; + uint16_t cseg_len; + uint16_t cseg16_len; + uint16_t dseg_len; +} __attribute__ ((packed)); + +struct mboot_vbe { + uint32_t ctl_info; + uint32_t mode_info; + uint16_t mode; + uint16_t ifseg, ifoffs, iflen; +} __attribute__ ((packed)); + + +/* multiboot information structure */ +struct mboot_info { + uint32_t flags; + /* mem_lower: available low memory (up to 640kb) + * mem_upper: available upper memory (from 1mb and upwards) + */ + uint32_t mem_lower, mem_upper; + /* boot device fields: MSB -> [part3|part2|part1|drive] <- LSB */ + uint32_t boot_dev; + char *cmdline; + /* loaded kernel modules */ + uint32_t mods_count; + struct mboot_module *mods; + /* elf sections table */ + struct mboot_elf_shdr_table elf; + /* memory map */ + uint32_t mmap_len; + struct mboot_mmap *mmap; + /* drives table */ + uint32_t drives_len; + struct mboot_drive *drives; + /* address of BIOS ROM configuration table */ + uint32_t cfgtable; + char *boot_loader_name; + /* advanced power management */ + struct mboot_apm *apm; + /* video bios extensions */ + struct mboot_vbe vbe; +}; + + +#endif /* MBOOT_H_ */ diff -r 2cbc2b922e49 -r 098b1cb5eeaa src/mem.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem.c Sat Mar 26 21:39:14 2011 +0200 @@ -0,0 +1,40 @@ +#include +#include "mem.h" +#include "panic.h" +#include "vm.h" + +/* end of kernel image */ +extern int _end; + +static uint32_t brk; + +void init_mem(struct mboot_info *mb) +{ + /* start the physical allocated break at the end of + * the kernel image + */ + brk = (uint32_t)&_end; +} + +uint32_t alloc_phys_page(void) +{ + uint32_t addr, dbg_prev_brk; + + if(ADDR_TO_PGOFFS(brk)) { + /* brk is not aligned, find the next page-aligned address */ + addr = (brk + PGSIZE) & ~PGOFFS_MASK; + } else { + /* brk is aligned, so we can use that address directly */ + addr = brk; + } + + if(addr >= MAX_BRK) { + panic("alloc_phys_page() out of early alloc space"); + } + + dbg_prev_brk = brk; + brk = addr + PGSIZE; /* move the break to the end of the page */ + + printf("DBG: alloc_phys_page(): %x (brk %x -> %x)\n", addr, dbg_prev_brk, brk); + return addr; +} diff -r 2cbc2b922e49 -r 098b1cb5eeaa src/mem.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem.h Sat Mar 26 21:39:14 2011 +0200 @@ -0,0 +1,12 @@ +#ifndef MEM_H_ +#define MEM_H_ + +#include "mboot.h" + +/* maximum break for the early allocator */ +#define MAX_BRK 0x400000 + +void init_mem(struct mboot_info *mb); +uint32_t alloc_phys_page(void); + +#endif /* MEM_H_ */ diff -r 2cbc2b922e49 -r 098b1cb5eeaa src/vm-asm.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vm-asm.S Sat Mar 26 21:39:14 2011 +0200 @@ -0,0 +1,27 @@ + .text +/* enable_paging(void) + * sets the cr0 bit 31 which enables page translation */ + .globl enable_paging +enable_paging: + movl %cr0, %eax + orl $0x80000000, %eax + movl %eax, %cr0 + ret + +/* set_pgdir_addr(uint32_t addr) + * sets the address of the page directory by writing to cr3, which + * also results in a TLB flush. */ + .globl set_pgdir_addr +set_pgdir_addr: + movl 4(%esp), %eax + movl %eax, %cr3 + ret + +/* get_fault_addr(void) + * returns the contents of control register 2, which provides + * the faulting address during a page fault exception + */ + .globl get_fault_addr +get_fault_addr: + movl %cr2, %eax + ret diff -r 2cbc2b922e49 -r 098b1cb5eeaa src/vm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vm.c Sat Mar 26 21:39:14 2011 +0200 @@ -0,0 +1,147 @@ +#include +#include +#include +#include "vm.h" +#include +#include "intr.h" +#include "mem.h" +#include "panic.h" + + +/* defined in vm-asm.S */ +void enable_paging(void); +void set_pgdir_addr(uint32_t addr); +uint32_t get_fault_addr(void); + +static void pgfault(int inum, uint32_t err); + +/* page directory */ +static uint32_t pgdir[1024]; + +#define KMEM_START 0xc0000000 +#define IDMAP_START 0xa0000 + +#define ATTR_PGDIR_MASK 0x3f +#define ATTR_PGTBL_MASK 0x1ff +#define ADDR_PGENT_MASK 0xfffff000 + +#define PAGEFAULT 14 + +void init_vm(struct mboot_info *mb) +{ + init_mem(mb); + + memset(pgdir, 0, sizeof pgdir); + + /* map the video memory and kernel code 1-1 */ + map_mem_range(IDMAP_START, MAX_BRK - IDMAP_START, IDMAP_START, 0); + + interrupt(PAGEFAULT, pgfault); + + set_pgdir_addr((int32_t)pgdir); + enable_paging(); +} + +void map_page(int vpage, int ppage, unsigned int attr) +{ + uint32_t *pgtbl; + int diridx = PAGE_TO_PGTBL(vpage); + int pgidx = PAGE_TO_PGTBL_PG(vpage); + + if(!(pgdir[diridx] & PG_PRESENT)) { + uint32_t addr = alloc_phys_page(); + pgtbl = (uint32_t*)addr; + pgdir[diridx] = addr | (attr & ATTR_PGDIR_MASK) | PG_PRESENT; + } else { + pgtbl = (uint32_t*)(pgdir[diridx] & ADDR_PGENT_MASK); + } + + pgtbl[pgidx] = PAGE_TO_ADDR(ppage) | (attr & ATTR_PGTBL_MASK) | PG_PRESENT; +} + +void unmap_page(int vpage) +{ + uint32_t *pgtbl; + int diridx = PAGE_TO_PGTBL(vpage); + int pgidx = PAGE_TO_PGTBL_PG(vpage); + + if(!(pgdir[diridx] & PG_PRESENT)) { + goto err; + } + pgtbl = (uint32_t*)(pgdir[diridx] & ADDR_PGENT_MASK); + + if(!(pgtbl[pgidx] & PG_PRESENT)) { + goto err; + } + pgtbl[pgidx] = 0; + + return; +err: + printf("unmap_page(%d): page already not mapped\n", vpage); +} + +void map_page_range(int vpg_start, int pgcount, int ppg_start, unsigned int attr) +{ + int i; + + for(i=0; iflags & MB_MMAP) { + struct mboot_mmap *mem, *mmap_end; + + mem = mb->mmap; + mmap_end = (struct mboot_mmap*)((char*)mb->mmap + mb->mmap_len); + + printf("memory map:\n"); + while(mem < mmap_end) { + unsigned int end = mem->base_low + mem->length_low; + char *type = mem->type == MB_MEM_VALID ? "free:" : "hole:"; + + printf(" %s %x - %x (%u bytes)\n", type, mem->base_low, end, mem->length_low); + mem = (struct mboot_mmap*)((char*)mem + mem->skip + sizeof mem->skip); + } + } + + if(mb->flags & MB_MEM) { + printf("lower memory: %ukb, upper mem: %ukb\n", mb->mem_lower, mb->mem_upper); + } +*/ + +static void pgfault(int inum, uint32_t err) +{ + printf("~~~~ PAGE FAULT ~~~~\n"); + + printf("fault address: %x\n", get_fault_addr()); + + if(err & PG_PRESENT) { + if(err & 8) { + printf("reserved bit set in some paging structure\n"); + } else { + printf("%s protection violation ", (err & PG_WRITABLE) ? "write" : "read"); + printf("in %s mode\n", err & PG_USER ? "user" : "kernel"); + } + } else { + printf("page not present\n"); + } +} diff -r 2cbc2b922e49 -r 098b1cb5eeaa src/vm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vm.h Sat Mar 26 21:39:14 2011 +0200 @@ -0,0 +1,42 @@ +#ifndef VM_H_ +#define VM_H_ + +#include +#include "mboot.h" + +/* page mapping flags */ +#define PG_PRESENT (1 << 0) +#define PG_WRITABLE (1 << 1) +#define PG_USER (1 << 2) +#define PG_WRITE_THROUGH (1 << 3) +#define PG_NOCACHE (1 << 4) +#define PG_ACCESSED (1 << 5) +#define PG_DIRTY (1 << 6) +#define PG_TYPE (1 << 7) +/* PG_GLOBAL mappings won't flush from TLB */ +#define PG_GLOBAL (1 << 8) + + +#define PGSIZE 4096 +#define PGOFFS_MASK 0xfff +#define PGNUM_MASK 0xfffff000 + +#define ADDR_TO_PAGE(x) ((uint32_t)(x) >> 12) +#define PAGE_TO_ADDR(x) ((uint32_t)(x) << 12) + +#define ADDR_TO_PGTBL(x) ((uint32_t)(x) >> 22) +#define ADDR_TO_PGTBL_PG(x) (((uint32_t)(x) >> 12) & 0x3ff) +#define ADDR_TO_PGOFFS(x) ((uint32_t)(x) & PGOFFS_MASK) + +#define PAGE_TO_PGTBL(x) ((uint32_t)(x) >> 10) +#define PAGE_TO_PGTBL_PG(x) ((uint32_t)(x) & 0x3ff) + + +void init_vm(struct mboot_info *mb); + +void map_page(int vpage, int ppage, unsigned int attr); +void map_page_range(int vpg_start, int pgcount, int ppg_start, unsigned int attr); + +void map_mem_range(uint32_t vaddr, size_t sz, uint32_t paddr, unsigned int attr); + +#endif /* VM_H_ */