首页 > 解决方案 > C 写入绝对地址不会更新值

问题描述

我正在尝试为我的 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

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

任何想法将不胜感激。

先感谢您。

[编辑] 这是我使用的引导加载程序:

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:

我的链接.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

标签: cmemorymemory-managementpaginationkernel

解决方案


问题在于保护模式和实模式,当计算机启动时,它会在 16 位实模式下启动,这使您能够处理 1 MB 的数据。一切都将不适合阅读/写作。如果我将 IMPORTANT_SEGMENT 更改为 0x300000 它可以工作。

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


推荐阅读