2017-08-02 103 views
0

我目前正在開發一個小內核項目,以瞭解更多關於系統開發的內容。我正面臨着一個奇怪的錯誤:我只是製作和調試了一個簡單的內存分配器(kmalloc()和kfree()函數),並且它工作得很好。當我打印由kmalloc()返回的指針的地址時,除了1指針之外,所有東西都可以工作!當我打印這個指針的地址兩次(用kprintf(「addr =%x(%x)」,i64,i64))我看到「addr = 0000(F018)」。 這是代碼和輸出:內核開發,內存分配器和kprintf()奇怪的輸出

Output on QEMU

CKernel.c:

#include "system.h" 
#include "multiboot.h" 
#include "util/util.h" 
#include "cpu/cpu.h" 
#include "video/video.h" 
#include "memory/mem.h" 

void kmain(multiboot_info_t* mbt) 
{ 
    //Current status : 32 bits, protected mode 
    //init 
    vga_setup(); 
    gdt_install(); 
    idt_install(); //TODO : ISRs ! (actually the only interrupt handler is a method that just print "INTERRUPT" and iret) 
    cpu_detect(); //TODO : Special handle INVALID_OPCODE 
    //TODO : Install PAGING //Need basic DYNAMIC ALLOCATION 
    //TODO : Install KHEAP 

    u8* i8 = kmalloc(1, 0); 
    *i8 = 244; 
    kprintf("i8 = %d, addr = %X", *i8, i8); 

    u32* i32 = kmalloc(sizeof(u32), 0); 
    *i32 = 12; 
    kprintf("i32 = %d, addr = %X", *i32, i32); 

    kfree(i8); 

    u64* i64 = kmalloc(sizeof(u64), 0); 
    *i64 = 29999344; 
    kprintf("i64 = %d, addr = %x (%X) (%x)", *i64, i64, i64, i64); 
    kprintf("%d %x %X", i64, i64, i64); 

    //Install ACPI 
    //Install PIC 
    //Install LAPIC/IOAPIC 
    //Install FPU 

    /*asm(" movb $0xFF, %al \n \ 
       outb %al, $0xA1 \n \ 
       outb %al, $0x21 \n");*/ //PIC DISABLING (DEBUG) 
    //asm("sti"); //INTERRUPT ENABLING (DEBUG) 
    //asm("int $0x0"); //INT CALL (DEBUG) 

    //print done message, to see that everything went well 
    kprint("[MAIN] DONE !", 1); 

    //kprintf("Lower memory : %dk (0x%x) Upper memory : %dk (0x%X)", mbt->mem_lower, mbt->mem_lower, mbt->mem_upper, mbt->mem_upper); 

    //kter_install(); 

    //loop infinetely 
    while(1) asm("hlt"); 
} 

kmalloc.c:

#include "../system.h" 
#include "util/util.h" 

typedef struct 
{ 
    u32 size; 
    u8 status; 
} __attribute__ ((packed)) block_header_t; 

#define KHEAP_BASE_START 0xF000 
#define KHEAP_BASE_END 0xFFFF 

u8 base_heap_initialized = 0; 

static void merge_free_blocks(); 

//Possible improvements : SECURITY : ADD a MAGIC number in the header, so that free() verify that it's a valid block (and malloc too) 

void* kmalloc(u32 size, u8 align) 
{ 
    u32 i; 

    if(align == 0) align = size; 

    //No need to merge as kfree() did it for us, right ? 
    //merge_free_blocks(); 

    if(!base_heap_initialized) 
    { 
     block_header_t* base_block = (block_header_t*) KHEAP_BASE_START; 
     base_block->size = KHEAP_BASE_END - (((u32) base_block) + sizeof(block_header_t)); 
     base_block->status = 0; 
     base_heap_initialized = 1; 
    } 

    i = KHEAP_BASE_START; 
    while(i < KHEAP_BASE_END) 
    { 
     block_header_t* currentBlock = (block_header_t*) i; 
     //kprintf("Looking block at %X... (addr = %X) (size = %d) (status = %s)", i, i+sizeof(block_header_t), currentBlock->size, (currentBlock->status ? "RESERVED" : "FREE")); 

     //Check if the current block is free and large enough 
     if(!currentBlock->status && currentBlock->size >= size) 
     { 
      //Apply alignment contraints 
      int am = 0; 
      while((((u32)currentBlock)+sizeof(block_header_t)+am) % align != 0) 
      { 
       //kprint("Alignment : 1B used.", 0); 
       am++; 
       size++; 
      } 

      //Recheck size after alignment contraints 
      if(currentBlock->size >= size) 
      { 
       int oldSize = currentBlock->size; 
       if(oldSize - size > 5) 
       { 
        currentBlock->size = size; 
        //Split the block if it is big 
        block_header_t* newblock = (block_header_t*) (i+sizeof(block_header_t)+currentBlock->size); 
        newblock->size = oldSize-size-5; 
        newblock->status = 0; 
        //kprintf("Setting up new block at %X (size = %d) (cbS = %d)", newblock, newblock->size, currentBlock->size); 
       } 
       //Mark the block as reserved 
       currentBlock->status = 1; 
       //Return the block 
       //kprintf("Returning addr %X", ((u32) (((u32)currentBlock)+sizeof(block_header_t)+am))); 
       return ((void*) ((u32)currentBlock)+sizeof(block_header_t)+am); 
      } 
     } 
     //The current block did not match, skipping to next block 
     i += (currentBlock->size+sizeof(block_header_t)); 
    } 
    //Heap is full : returning null 
    kprint("[GRAVE] [ERROR] The kernel HEAP is FULL ! Returned pointer to NULL !", 2); 
    return ((void*) 0); 
} 

void kfree(void* pointer) 
{ 
    block_header_t* blockHeader = (block_header_t*) (pointer - sizeof(block_header_t)); 
    blockHeader->status = 0; 

    merge_free_blocks(); 
} 

static void merge_free_blocks() 
{ 
    block_header_t* currBlock; 
    u32 i = KHEAP_BASE_START; 

    while(i < KHEAP_BASE_END) 
    { 
     currBlock = (block_header_t*) i; 
     if(!currBlock->status) 
     { 
      //Joining free regions 
      block_header_t* nextBlock; 
      while(!(nextBlock = (block_header_t*) i+sizeof(block_header_t)+currBlock->size)->status) 
      { 
       currBlock->size+= (sizeof(block_header_t)+nextBlock->size); 
       i+=(sizeof(block_header_t)+nextBlock->size); 
      } 
      i += (sizeof(block_header_t)+((u32)currBlock)); 
     } 
     else 
      i+= (sizeof(block_header_t)+((u32)currBlock)); 
    } 
} 

kprintf()函數:

static void vkprintf(const char* args, va_list ap) 
{ 
    char buffer[32]; 

    vga_text_puts("[KERNEL] ", 0b00001111); 
    while(*args) 
    { 
     if(*args == '%') 
     { 
      switch(*(++args)) 
      { 
       case 'u': 
        utoa(va_arg(ap, u32), buffer); 
        vga_text_puts(buffer, 0b00000111); 
        break; 
       case 'i': case 'd': 
        itoa(va_arg(ap, int32_t), buffer); 
        vga_text_puts(buffer, 0b00000111); 
        break; 
       case 'X': /// TODO: make it standardized 
        i2hex(va_arg(ap, u32), buffer, 8); 
        vga_text_puts(buffer, 0b00000111); 
        break; 
       case 'x': 
        i2hex(va_arg(ap, u32), buffer, 4); 
        vga_text_puts(buffer, 0b00000111); 
        break; 
       case 'y': 
        i2hex(va_arg(ap, u32), buffer, 2); 
        vga_text_puts(buffer, 0b00000111); 
        break; 
       case 's': 
        { 
         char* temp = va_arg(ap, char*); 
         vga_text_puts(temp, 0b00000111); 
         break; 
        } 
       case 'c': 
        vga_text_putc((int8_t)va_arg(ap, int32_t), 0b00000111); 
        break; 
       default: 
        vga_text_putc(*args, 0b00000111); 
        break; 
      } 
     } 
     else 
     { 
      vga_text_putc(*args, 0b00000111); 
     } 

     args++; 
    } 
    vga_text_putc('\n', 0b00000111); 
} 

void kprintf(const char* args, ...) 
{ 
    va_list ap; 
    va_start(ap, args); 
    vkprintf(args, ap); 
    va_end(ap); 
} 

對不起,如果這不正確,如果你需要更多的細節,請讓我知道...這個問題並不重要,因爲它似乎指針有正確的地址,但它只是奇怪的,我想要知道爲什麼... 感謝您的閱讀!

+1

您的目標是64位系統嗎?那麼指針的大小是多少?什麼大小是一個'int'(或'u32')?考慮一下,爲什麼標準'printf'有一個特殊的''%p''格式來打印指針('void *')。 –

+0

另外,你的'i2hex'函數在做什麼?最後一個論點的含義是什麼? –

+0

最後,Qemu允許你附加一個調試器。我建議你這樣做,並通過代碼來看看它真的做了什麼。 –

回答

0

好的,問題解決了!這只是u64和我所有的itoa()i2hex()函數的錯誤:它們最多接受32位,所以緩衝區上仍然有32位,它們是由printf而不是其他參數(地址)讀取的, !謝謝你的回答一些程序員老兄,你帶領我去了解決方案!