C写入绝对地址不会更新值

时间:2019-05-25 17:32:15

标签: c memory memory-management pagination kernel

我正在尝试为我的C内核编写一个基本的页面管理器。代码如下:

#define NUM_PAGES 1024
#define PAGE_SIZE 4096
#define NULL 0

#define IMPORTANT_SEGMENT 0xC0900000

struct page {
    void * addr;
    int in_use;
};

struct page CORE_FILE[NUM_PAGES];

void mem_init() {   
    for (int i = 0; i < NUM_PAGES; i++) {
        CORE_FILE[i].addr = (void*)IMPORTANT_SEGMENT+PAGE_SIZE*i;
        CORE_FILE[i].in_use = 0;        
    }
}

void * allocate() {

    for (int i = 0; i < NUM_PAGES; i++) {
        if (!CORE_FILE[i].in_use) {
            CORE_FILE[i].in_use = 1;        
            return CORE_FILE[i].addr;
        }   
    }

    return NULL;
}

int deallocate(void* p) {

    for (int i = 0; i < NUM_PAGES; i++) {
        if (CORE_FILE[i].addr == p && CORE_FILE[i].in_use) {
            CORE_FILE[i].in_use = 0;
            return 0;
        }   
    }
    return -1;
}

CORE_FILE是一个结构数组,其中仅包含一个用于告知页面是否正在使用的字段和一个地址(即使用从IMPORTANT_SEGMENT = 0xC0900000增长的连续地址)。

当我打电话给allocate()时,它返回给我正确的void*,例如我将其强制转换为char,但是当我写地址时,它什么也没做。

我检查了GDB指向的地址,它是正确的地址。 但是当我检查其内容时,它们尚未更新(仍然为0)。

void kmain(void) {
    mem_init();
    int * addr = (int*)allocate();
    *addr = 5;
}

我给qemu 4 GB的RAM执行:

qemu-system-i386 -m 4G -kernel kernel -gdb tcp::5022

也许我正在写一个不存在的内存,或者也许之后我会覆盖地址内容。我不知道。

任何想法都会受到赞赏。

谢谢。

[edit]这是使用以下程序的引导加载程序即时通讯

bits 32
section .text
        ;multiboot spec
        align 4
        dd 0x1BADB002              ;magic
        dd 0x00                    ;flags
        dd - (0x1BADB002 + 0x00)   ;checksum. m+f+c should be zero

global start
global keyboard_handler
global read_port
global write_port
global load_idt

extern kmain        ;this is defined in the c file
extern keyboard_handler_main

read_port:
    mov edx, [esp + 4]
            ;al is the lower 8 bits of eax
    in al, dx   ;dx is the lower 16 bits of edx
    ret

write_port:
    mov   edx, [esp + 4]    
    mov   al, [esp + 4 + 4]  
    out   dx, al  
    ret

load_idt:
    mov edx, [esp + 4]
    lidt [edx]
    sti                 ;turn on interrupts
    ret

keyboard_handler:                 
    call    keyboard_handler_main
    iretd

start:
    cli                 ;block interrupts
    mov esp, stack_space
    call kmain
    hlt                 ;halt the CPU

section .bss
resb 8192; 8KB for stack
stack_space:

我的link.ld

OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS
 {
   . = 0x100000;
   .text : { *(.text) }
   . = 0x200000;
   .data : { *(.data) }
   . = 0x300000;
   .bss  : { *(.bss)  }
 }

Edit2:我用它编译

nasm -f elf32 kernel.asm -o kasm.o
gcc -g -fno-stack-protector -fno-builtin -m32 -c memory.c -o memory.o
gcc -g -fno-stack-protector -fno-builtin -m32 -c kernel.c -o kc.o
ld -m elf_i386 -T link.ld -o kernel kasm.o memory.o kc.o

1 个答案:

答案 0 :(得分:1)

问题在于保护模式和实模式,当计算机启动时,它以16位实模式启动,因此您可以寻址1 MB的数据。上面的所有内容都不适合读/写。如果我将IMPORTANT_SEGMENT更改为0x300000,它将起作用。

现在我必须创建并加载我的gdt,启用a20线,启用保护模式,设置寄存器并跳转到我的代码。