C Запись по абсолютному адресу не обновляет значение - PullRequest
1 голос
/ 25 мая 2019

Я пытаюсь написать простой менеджер страниц для моего ядра 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 ГБ ОЗУ, выполняя с:

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:

My 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 Ответ

1 голос
/ 26 мая 2019

Проблема в защищенном и реальном режиме, когда компьютер загружается, это происходит в 16-битном реальном режиме, что позволяет вам обращаться к 1 МБ данных.Все это не подходит для чтения / записи.Если я изменил IMPORTANT_SEGMENT на 0x300000, он работает.

Теперь мне нужно создать и загрузить свой gdt, включить строку a20, включить защищенный режим, установить регистры и перейти к моему коду.

...