Beiträge anzeigen

Diese Sektion erlaubt es dir alle Beiträge dieses Mitglieds zu sehen. Beachte, dass du nur solche Beiträge sehen kannst, zu denen du auch Zugriffsrechte hast.


Themen - Tele

Seiten: [1]
1
Hallo Forum!

Ich beschäftige mich gerade mit der Paging-Implementierung und bin nun bei der Implementierung von vmm_alloc().
Ich halte mich an das hier im Wiki gestellte Tutorial, daher die Namensgleicheiten was Funktionen, Variablen, etc. angeht.
Hauptsächlich geht es mir um die Berechnung einer freien virtuellen Adresse.
Hierzu habe ich folgende Funktion get_free_page, welche mir für einen gegebenen context die erste nicht belegte virtuelle Adresse zurückliefert.
Mit dieser kann ich dann ein map_page() machen, mit vorher alloziierter physischer Page.
static uintptr_t get_free_page(struct vmm_context_t* context) {
uint32_t* page_table;
uint32_t page;
int i;
int j;

// loop page tables in context
for (i = 0; i < 1024; i++) {
page_table = context->pagedir[i];

// used page table
if (*page_table & VMM_USED) {

// loop pages
for (j = 0; j < 1024; j++) {
page = page_table[j];

// check if page is used
if (page == 0) {
return (i << 22) + ((j << 12));
}
}
}
}

return NULL;
}
Ist das soweit richtig oder ist mein Grundgedanke schon falsch?
Eine weitere Frage:
Nachdem ich mir eine physische Page alloziert habe und diese ausgebe, ist diese 0x1000. Das entspräche doch den ersten 4KB im RAM, oder?
Wenn dem so ist, funktioniert mein pmm-mapping auch nicht, denn da sollte zumindest Kernel + Multiboot + Videobuffer gemappt sein, also eine Adresse > 0x1000 rauskommen.
Oder liege ich hier auch falsch?
Ich hoffe jemand kann Licht in mein Dunkel bringen :-)

Viele Grüße,

Der Tele
2
Hallo Lowlevel-Forum!

Ich bin der Tele, 20 Jahre alt und Student. Ich hab bereits eine Ausbildung zum Informationstechnischen Assistenten hinter mir und jetzt studiere ich dual
Wirtschaftsinformatik. Ich interessiere mich schon lange für das Entwickeln von Betriebssystemen, insbesondere Linux hat es mir angetan.
Jetzt habe ich den Schritt gewagt und damit angefangen und, tja stehe direkt vor einem (für mich) unlösbaren Problems:

Ich habe fleissig das Tutorial verfolgt und bin jetzt beim Multitasking. Ich muss dazu sagen, dass ich mein Betriebssystem anhand anderer Tutorials bereits erweitert habe, so verfüge ich über einen GCC-Crosscompiler und eine (gaaaaaanz kleine) eigene libc Implementierung (stdio, etc.).

Leider spuckt mir Qemu ein "Trying to execute code outside RAM or ROM at 0x66000000" aus und da komme ich nicht weiter.
Ich habe alle Beiträge in diesem Forum bezüglich ähnlicher Fehler durch, half leider nichts. Lange Rede, kurzer Sinn: Ich erbitte euch um Hilfe und hier ist mein Code:

kernel.c
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>

#include <kernel/tty.h>
#include <kernel/gdt.h>
#include <kernel/idt.h>
#include <kernel/kbc.h>
#include <kernel/task.h>

static uint8_t stack_a[4096];
static uint8_t stack_b[4096];

static uint8_t user_stack_a[4096];
static uint8_t user_stack_b[4096];

void task_a(void);
void task_b(void);

void kernel_early(void) {
terminal_init();

gdt_init();
kbc_init();

task_init_task(stack_a, user_stack_a, task_a, 0);
task_init_task(stack_b, user_stack_b, task_b, 1);
idt_init();
}

void kernel_main(void) {
printf("OSWAN has successfully booted\n");

while(1);
}

void task_a(void) {
while (1) {
putchar('A');
}
}

void task_b(void) {
while (1) {
putchar('B');
}
}

idt.c
#include <kernel/idt.h>
#include <kernel/gdt.h>
#include <kernel/kbc.h>
#include <kernel/syscl.h>
#include <kernel/ports.h>
#include <kernel/task.h>
#include <stdio.h>

#define IDT_FLAG_INTERRUPT_GATE 0xe
#define IDT_FLAG_PRESENT 0x80
#define IDT_FLAG_RING0 0x00
#define IDT_FLAG_RING3 0x60

#define IDT_NR_EXCEPTION_LAST   0x1f
#define IDT_NR_IRQ_FIRST 0x20
#define IDT_NR_IRQ_LAST 0x2f
#define IDT_NR_SOFTWARE 0x30

#define IDT_ENTRIES 256

// Exceptions
extern void intr_stub_0(void);
extern void intr_stub_1(void);
extern void intr_stub_2(void);
extern void intr_stub_3(void);
extern void intr_stub_4(void);
extern void intr_stub_5(void);
extern void intr_stub_6(void);
extern void intr_stub_7(void);
extern void intr_stub_8(void);
extern void intr_stub_9(void);
extern void intr_stub_10(void);
extern void intr_stub_11(void);
extern void intr_stub_12(void);
extern void intr_stub_13(void);
extern void intr_stub_14(void);
extern void intr_stub_15(void);
extern void intr_stub_16(void);
extern void intr_stub_17(void);
extern void intr_stub_18(void);

// IRQ
extern void intr_stub_32(void);
extern void intr_stub_33(void);
extern void intr_stub_34(void);
extern void intr_stub_35(void);
extern void intr_stub_36(void);
extern void intr_stub_37(void);
extern void intr_stub_38(void);
extern void intr_stub_39(void);
extern void intr_stub_40(void);
extern void intr_stub_41(void);
extern void intr_stub_42(void);
extern void intr_stub_43(void);
extern void intr_stub_44(void);
extern void intr_stub_45(void);
extern void intr_stub_46(void);
extern void intr_stub_47(void);

// System Call
extern void intr_stub_48(void);

static long long unsigned int idt[IDT_ENTRIES];

static void idt_set_entry(int i, void (*fn)(), unsigned int selector, int flags) {
unsigned long int handler = (unsigned long int)fn;

idt[i] = handler & 0xffffLL;
idt[i] |= (selector & 0xffffLL) << 16;
idt[i] |= (flags & 0xffLL) << 40;
idt[i] |= ((handler >> 16) & 0xffffLL) << 48;
}

static void pic_init(void) {

/* Initialize Master-PIC */
/* ICW (Initializazion Control Word) 1-4 */
// Initial command
outb(0x20, 0x11);
// Interrupt NR for IRQ 0
outb(0x21, 0x20);
// Slave-PIC at IRQ 2
outb(0x21, 0x04);
// ICW 4 0x01 is set for PC's
outb(0x21, 0x01);

/* Initialize Slave-PIC */
/* ICW (Initializazion Control Word) 1-4 */
// Initial command
outb(0xa0, 0x11);
// Interrupt NR for IRQ 8
outb(0xa1, 0x28);
// Slave-PIC at IRQ 2
outb(0xa1, 0x02);
// ICW 4 0x01 is set for PC's
outb(0xa1, 0x01);

// Activate all IRQ's for Master and Slave
outb(0x20, 0x0);
outb(0xa0, 0x0);
}

void idt_init(void) {
struct {
unsigned short int limit;
void* base;
} __attribute__((packed)) idtp = {
.limit = IDT_ENTRIES * 8 - 1,
.base = idt,
};

pic_init();

idt_set_entry(0,  intr_stub_0,  0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(1,  intr_stub_1,  0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(2,  intr_stub_2,  0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(3,  intr_stub_3,  0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(4,  intr_stub_4,  0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(5,  intr_stub_5,  0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(6,  intr_stub_6,  0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(7,  intr_stub_7,  0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(8,  intr_stub_8,  0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(9,  intr_stub_9,  0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(10, intr_stub_10, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(11, intr_stub_11, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(12, intr_stub_12, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(13, intr_stub_13, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(14, intr_stub_14, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(15, intr_stub_15, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(16, intr_stub_16, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(17, intr_stub_17, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(18, intr_stub_18, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);

idt_set_entry(32, intr_stub_32, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(33, intr_stub_33, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(34, intr_stub_34, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(35, intr_stub_35, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(36, intr_stub_36, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(37, intr_stub_37, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(38, intr_stub_38, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(39, intr_stub_39, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(40, intr_stub_40, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(41, intr_stub_41, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(42, intr_stub_42, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(43, intr_stub_43, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(44, intr_stub_44, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(45, intr_stub_45, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(46, intr_stub_46, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);
idt_set_entry(47, intr_stub_47, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT);

idt_set_entry(48, intr_stub_48, 0x8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING3 | IDT_FLAG_PRESENT);

// load the adress of idtp to register the IDT in the CPU
asm volatile("lidt %0" : : "m" (idtp));

// set the Interrupt Flag (if) in the cpu
asm volatile("sti");
}

struct cpu_state* idt_handle_interrupt(struct cpu_state* cpu) {
struct cpu_state* new_cpu = cpu;
uint32_t intr = cpu->intr;

if (intr <= IDT_NR_EXCEPTION_LAST) {
printf("Exception %d! System halt\n", intr);

// cli unsets the Interrupt Flag (if) in the cpu so interrupts are ignored.
// hlt halts until an interrupt occures.
// cli and hlt are used together to hang the kernel
while (1) { asm volatile("cli; hlt"); }
}
else if (intr >= IDT_NR_IRQ_FIRST && intr <= IDT_NR_IRQ_LAST) {

if (intr == 0x20) {
new_cpu = task_schedule(cpu);
tss[1] = (uint32_t)(new_cpu + 1);

//printf("%d, %d, %d\n", cpu->intr, cpu->esp, cpu->eip);

//while (1) { asm volatile("cli; hlt"); }
}

// IRQ 1 is Keyboard. Handle control to kbc
if (intr == IDT_NR_IRQ_FIRST + 1) {
kbc_handle_key();
}

// EOI (End Of Interrupt)
// Tells the pic the interrupt has been handled successfully.
// If this isn't send, we wont receive further hardware interrupts.
if (intr >= 0x28) {
// EOI for Slave-PIC
outb(0xa0, 0x20);
}
// EOI for Master-PIC
outb(0x20, 0x20);
}
// Software Interrupt. Handle control to syscl
else if (intr == IDT_NR_SOFTWARE) {
syscl_handle_interrupt(cpu);
}
else {
printf("Unknown Interrupt! System halt\n");
while (1) { asm volatile("cli; hlt"); }
}

return new_cpu;
}

gdt.c
#include <kernel/gdt.h>
#include <kernel/tss.h>
#include <stdint.h>

#define GDT_FLAG_DATASEG 0x02
#define GDT_FLAG_CODESEG 0x0a
#define GDT_FLAG_TSS 0x09

#define GDT_FLAG_SEGMENT 0x10
#define GDT_FLAG_RING0 0x00
#define GDT_FLAG_RING3 0x60
#define GDT_FLAG_PRESENT 0x80

#define GDT_FLAG_4K 0x800
#define GDT_FLAG_32_BIT 0x400

#define GDT_ENTRIES 6
static uint64_t gdt[GDT_ENTRIES];

static void gdt_set_entry(int i, unsigned int base, unsigned int limit, int flags) {
gdt[i] = limit & 0xffffLL;
gdt[i] |= (base & 0xffffffLL) << 16;
gdt[i] |= (flags & 0xffLL) << 40;
gdt[i] |= ((limit >> 16) & 0xfLL) << 48;
gdt[i] |= ((flags >> 8) & 0xffLL) << 52;
gdt[i] |= ((base >> 24) & 0xffLL) << 56;
}

void gdt_init(void) {
struct {
uint16_t limit;
void* base;
} __attribute__((packed)) gdtp = {
.limit = GDT_ENTRIES * 8 - 1,
.base = gdt,
};

gdt_set_entry(0, 0, 0, 0);

gdt_set_entry(1, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT | GDT_FLAG_CODESEG | GDT_FLAG_4K | GDT_FLAG_PRESENT);
gdt_set_entry(2, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT | GDT_FLAG_DATASEG | GDT_FLAG_4K | GDT_FLAG_PRESENT);

gdt_set_entry(3, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT | GDT_FLAG_CODESEG | GDT_FLAG_4K | GDT_FLAG_PRESENT | GDT_FLAG_RING3);
gdt_set_entry(4, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT | GDT_FLAG_DATASEG | GDT_FLAG_4K | GDT_FLAG_PRESENT | GDT_FLAG_RING3);

gdt_set_entry(5, (uint32_t)tss, sizeof(tss), GDT_FLAG_TSS | GDT_FLAG_PRESENT | GDT_FLAG_RING3);

asm volatile("lgdt %0" : : "m" (gdtp));

asm volatile(
"mov $0x10, %ax;"
"mov %ax, %ds;"
"mov %ax, %es;"
"mov %ax, %ss;"
"ljmp $0x8, $.1;"
".1:"
);

// load Task Register
asm volatile("ltr %%ax" : : "a" (5 << 3));
}

intr_stub.S
//  Macro function for non-exception stubs
//  pushes zero and stub nr on stack
//  jumps into intr_common_handler
.macro intr_stub nr
.global intr_stub_\nr
intr_stub_\nr:
    pushl $0
    pushl $\nr
    jmp intr_common_handler
.endm

//  Macro function for exception stubs
//  pushes exception nr and stub nr on stack
//  jumps into intr_common_handler
.macro intr_stub_error_code nr
.global intr_stub_\nr
intr_stub_\nr:
    pushl $\nr
    jmp intr_common_handler
.endm

//  Some exceptions have an additional error code
//  for this exceptions, the intr_stub_error_code macro is used
//  other stubs pushes instead zero of the stack
intr_stub 0
intr_stub 1
intr_stub 2
intr_stub 3
intr_stub 4
intr_stub 5
intr_stub 6
intr_stub 7
intr_stub_error_code 8
intr_stub 9
intr_stub_error_code 10
intr_stub_error_code 11
intr_stub_error_code 12
intr_stub_error_code 13
intr_stub_error_code 14
intr_stub 15
intr_stub 16
intr_stub_error_code 17
intr_stub 18

// IRQs
intr_stub 32
intr_stub 33
intr_stub 34
intr_stub 35
intr_stub 36
intr_stub 37
intr_stub 38
intr_stub 39
intr_stub 40
intr_stub 41
intr_stub 42
intr_stub 43
intr_stub 44
intr_stub 45
intr_stub 46
intr_stub 47

// Syscall
intr_stub 48

//  c function from idt.h
.extern idt_handle_interrupt
intr_common_handler:
    // Save cpu registers
    push %ebp
    push %edi
    push %esi
    push %edx
    push %ecx
    push %ebx
    push %eax

    mov $0x10, %ax
    mov %ax, %ds
    mov %ax, %es

    // Call c function handler
    push %esp
    call idt_handle_interrupt
    mov %eax, %esp

    mov $0x23, %ax
    mov %ax, %ds
    mov %ax, %es
     
    // load cpu register
    pop %eax
    pop %ebx
    pop %ecx
    pop %edx
    pop %esi
    pop %edi
    pop %ebp

    // pop error code and interrupt nr from stack
    add $8, %esp

    iret

task.c
#include <kernel/task.h>

static int current_task = -1;
static int num_tasks = 2;
static struct cpu_state* task_states[2];

void task_init_task(uint8_t* stack, uint8_t* user_stack, void* entry, unsigned int nr) {
    struct cpu_state new_state = {
        .eax = 0,
        .ebx = 0,
        .ecx = 0,
        .edx = 0,
        .esi = 0,
        .edi = 0,
        .ebp = 0,
        .esp = (uint32_t) user_stack + 4096,
        .eip = (uint32_t) entry,
 
        /* Ring-3-Segmentregister */
        .cs  = 0x18 | 0x03,
        .ss  = 0x20 | 0x03,
 
        /* IRQs einschalten (IF = 1) */
        .eflags = 0x200,
    };
 
    /*
     * Den angelegten CPU-Zustand auf den Stack des Tasks kopieren, damit es am
     * Ende so aussieht als waere der Task durch einen Interrupt unterbrochen
     * worden. So kann man dem Interrupthandler den neuen Task unterschieben
     * und er stellt einfach den neuen Prozessorzustand "wieder her".
     */
    struct cpu_state* state = (void*) (stack + 4096 - sizeof(new_state));
    *state = new_state;
 
    task_states[nr] = state;
}
 
/*
 * Gibt den Prozessorzustand des naechsten Tasks zurueck. Der aktuelle
 * Prozessorzustand wird als Parameter uebergeben und gespeichert, damit er
 * beim naechsten Aufruf des Tasks wiederhergestellt werden kann
 */
struct cpu_state* task_schedule(struct cpu_state* cpu) {
    /*
     * Wenn schon ein Task laeuft, Zustand sichern. Wenn nicht, springen wir
     * gerade zum ersten Mal in einen Task. Diesen Prozessorzustand brauchen
     * wir spaeter nicht wieder.
     */
    if (current_task >= 0) {
        task_states[current_task] = cpu;
    }
 
    /*
     * Naechsten Task auswaehlen. Wenn alle durch sind, geht es von vorne los
     */
    current_task++;
    current_task %= num_tasks;
 
    /* Prozessorzustand des neuen Tasks aktivieren */
    cpu = task_states[current_task];
 
    return cpu;
}

So das wärs dann soweit (sofern ich nichts vergessen habe).
Ich freue mich auf eine schöne Zeit hier im Forum!

Grüße,
Der Tele
Seiten: [1]

Einloggen