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.


Nachrichten - Tele

Seiten: [1]
1
Es lag an meiner eigenen Schusseligkeit. Wie ihr schon geschrieben habt, waren meine Flags für vmm_alloc falsch gesetzt und so wurden die Task-Stacks
falsch alloziert. Dadurch kam der Zugriff auf eine Kernel-Page, welche ja für den Usertask gedacht war :-P

Paging funktioniert zumindest (vorerst..), jetzt gehts an den Scheduler!

Ich danke für Eure Hilfe!

Der Tele
2
Dann verstehe ich den Wikiartikel http://www.lowlevel.eu/wiki/Exception#Page_Fault falsch.
Dort steht zu Bit 0
Zitat
Wenn gelöscht, dann wurde der Fault durch eine nicht aktive Page ausgelös
Da es gesetzt ist, dachte ich es handelt sich um eine aktive Page = kein Fehler?
3
Ah vielen Dank!
Das war zumindest der Fehler. Der Errorcode hat sich so jetzt von 0x7 auf 0x5 verringert :-)
Bleibt noch das gesetzte 2'te Bit, welches sagt, dass das Programm Usermode-Rechte hat. Nun gut stimmt ja auch. Das Bit sollte also richtig sein.
Was sagt mir aber in diesem Falle der PageFault aus? Ein richtiger Errorcode ist das ja nicht mehr..
4
Ich muss einen Schritt zurück gehen.
Die Exception hat sich als doch als Page Fault herausgestellt, ich vermute eine General Protection vorher durch veraltete Object-Dateien und Code-Reste.
Die Fehlerbeschreibung bleibt aber die Selbe.
Der Errorcode des Page Faults jedenfalls ist 0x7, also denke ich die ersten Bit's 0-2 sind gesetzt?
Das wäre dann ja
  • Nicht durch eine aktive Page, Bit 0 ist ja gesetzt
  • Ein Schreibzugriff
  • Task im Usermode
Kann ich zumindest bestätigen, auch Bit 1 mit Schreibzugriff scheint korrekt zu sein, der Instruction Pointer des Tasks zeigt auf push 0x41das wäre ja der Parameter meines putchar('A')Das macht der Task nämlich.
cr2 zeigt auf 0x402fe4 was jedenfalls laut qemu's info mem gemappt sein sollte:
0000000000000000-0000000000400000 0000000000400000 urw
0000000000400000-0000000000407000 0000000000007000 -rw

LG,

Der Tele
5
Vielen Dank für Eure Antworten!

Ich habe mich am Wochenende nochmal damit beschäftigt und da leider mein Mapping immer noch kaputt war, hab ich testweise mal die ersten 4MB komplett gemappt.
ich weis, unschön ist aber zum Testen.
Leider bekomme ich eine General Protection immer wenn einer meiner Userspace Tasks irgendwas machen möchte. Ohne jetzt wieder mit viel Code zu kommen:
Kann man (pauschal) sagen woher eine General Protection kommt? Ein Page Fault ist es ja nicht, also stimmt was anderes nicht.
Oder sind die Möglichkeiten eines Fehlers da zu groß?
Wenn meine Tasks nur aus while(1); bestehen, läufts :-P Aber sobald etwas wie puts verwendet wird, knallt es. Und zwar beim Code wo der Parameter auf den Stack kommt.

LG,

Der Tele
6
Vielen Dank für die Antwort  :-)

Mir ist eine Thematik aber noch nicht klar:
Zitat
Für das Mappen eines Page Directory und allen zugehörigen Page Tables gibt es einen Trick: Wenn ein Eintrag eines Page Directory wieder auf ein Page Directory (z.B. sich selbst) zeigt, dann wird dieses Page Directory an dieser Stelle als Page Table verwendet. Dadurch werden alle enthaltenen Page Tables hintereinander in den virtuellen Speicher gemappt. Dieser Trick wird oft für das aktuelle Page Directory benutzt, d.h. ein bestimmter Eintrag in jedem PD zeigt wieder auf das PD selbst.
Das verstehe ich nicht. Ich muss alle benutzen Page Directory Einträge mappen, damit die CPU bei Übersetzung der Adressen die dazugehörige Page Table findet?
Klingt logisch. Mit "ein Page Directory Eintrag" ist doch die Adresse einer Page Table gemeint? Muss ich dann nicht auch alle Pages innerhalb einer Table mappen?

Ein anderes Thema: Um nach aktiviertem Paging auf das Page Directory zugreifen zu können, brauche ich die virtuelle Adresse des Page Directorys.
Mappe ich dazu einfach die virtuelle Adresse des Page Directory auf die Physische?
kernel_context->pagedir_virt = get_free_page(kernel_context);
map_page(kernel_context, kernel_context->pagedir_virt, kernel_context->pagedir_phys);

Wie man merkt, komme ich beim Thema Paging echt durcheinander..

Der Tele
7
Vielen Dank für die Tipps, das mit Qemu ist wirklich sehr hilfreich.
Ich habe auch gleich einen Fehler, zumindest passt mein Mapping noch nicht zu 100%.
Ich habe die Multiboot-Struktur gemappt, beim Zugriff bekomme ich allerdings einen PageFault.
info mem gibt mir auch nur
00000000000b8000-000000000025c000 00000000001a4000 urw
aus und das sieht mir nach Videobuffer aus. Aber da sind doch 0x1a4000 viel zu viel?
8
Vielen Dank für deine Antwort!

Was meinst du mit 1:1-Mapping?
falls du kein 1:1-Mapping für alle Page Tables hast, die Adresse in eine virtuelle Adresse übersetzen.
Hab ich im Tutorial etwas überlesen?
Ja genau, mit VMM_USED ist das Present Bit gemeint.
Wenn ich die Flags herausfiltern möchte, reicht es, diese mit '&' zu clearen, damit der Pointer funktioniert?
Du solltest dir auch bewusst sein, dass *page_table den ersten Eintrag in der PT zurückgibt
Oh, die Dereferenzierung da macht auch wenig Sinn. Das wäre dann aber die erste Page der Page Table?

EDIT:

Ich habe mir alles nochmal durchgelesen und etwas gefixed. Mein get_free_page sieht jetzt so aus:
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++) {

// used page table
if (context->pagedir[i] & VMM_USED) {
page_table = (uint32_t *)(context->pagedir[i] & ~0xFFF);

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

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

return NULL;
}

In meiner vmm_init mappe ich Kernel und Videobuffer und alloziiere nach dem Setzen des cr0-Registers einen Int-Pointer.
Da ich nach dem Bootvorgang eine "5" ausgegeben bekomme, sollte dies ja heißen, dass Paging erfolgreich die Adresse übersetzt hat, oder?
Wenn ich mir die Adressen mal anschaue, sind dies im Moment 1:1 Übersetzungen, sollte dann also richtig sein?
void vmm_init(void) {
uint32_t cr0;
kernel_context = create_context();

// map kernel
map_page_range(kernel_context, KERNEL_START, KERNEL_START, KERNEL_END, 1);

// map video buffer
map_page_range(kernel_context, 0xb8000, 0xb8000, (0xb8000 + (2 * 25 * 80)), 1);


vmm_activate_memory_context(kernel_context);

// set bit 31 in register cr0 to enable paging
asm volatile("mov %%cr0, %0" : "=r" (cr0));
cr0 |= (1 << 31);
asm volatile("mov %0, %%cr0" : : "r" (cr0));

int* test = (int *)vmm_alloc(kernel_context, sizeof(int));
*test = 5;

printf("%d\n", *test);
}
9
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
10
Vielen Dank Kevin, richtig geraten. Die Sache mit dem Static  :-D
Wieder etwas dazugelernt
11
Vielen Dank für Eure Antworten!

Nach etlichem herumprobieren habe ich das Problem gefunden:
Ich habe nicht wie im Tutorial vorgegeben gdt und idt in eine Datei gepackt, sondern in zwei getrennte Dateien. Das hatte zur Folge, dass ich das TSS auch in beiden Dateien brauchte.
Daher habe ich eine weitere Date tss.h hinzugefügt, welche lediglich das TSS enthält. Da war der Fehler. Anscheinend ließ sich dies nicht in beide Dateien einfügen.

Jetzt habe ich gdt und idt in eine Datei, ebenso das TSS eingepackt und siehe da, meine Tasks laufen auf Ring 3  :-D
Hat jemand von Euch eine Erklärung dafür, dass sich das TSS so verhalten hat?
12
Vielen Dank für Deine Rückmeldung!

Habe jetzt qemu mitloggen lassen, werde aber nicht schlau aus dem Log:
Servicing hardware INT=0x20
----------------
IN:
0x00100814:  sub    $0x8,%esp
0x00100817:  push   %edx
0x00100818:  push   $0x102510
0x0010081d:  call   0x100e70
Scheint erstmal richtig zu sein. Der Hardware Interrupt vom Timer kommt schonmal. Dannach exlodiert qemu dann.
Schreibe ich eine Logausgabe so:
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"); }
}
Hält qemu wie erwartet an, ich bekomme aber kein Hardware Int im Log?
Eine Frage: Wie schaffe ich es, dass qemu sich nicht schließt nachdem er crashed? Sonst sehe ich meine printf's nicht. Oder anders, gibt es die Möglichkeit, dass qemu den Bildschirminhalt in eine Datei umleitet?

Grüße,

Der Tele
13
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