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 - nnosdev

Seiten: [1] 2 3 4
1
Lowlevel-Coding / Re: ISR Common Stub -> INT13
« am: 29. January 2014, 17:21 »
Sorry falls das jetzt eine doofe Frage ist, aber wieso hört das dann nicht VOR Isr_Handler auf zu laufen? Dort schreibe ich auch den werd 0x10 in DS rein. Und meiner Meinung nach mache ich danach genau dasselbe nochmal (im Moment zumindest) oder bin ich total verpeilt hier?
2
Lowlevel-Coding / Re: ISR Common Stub -> INT13
« am: 29. January 2014, 11:06 »
Okay mal angenommen ich initialisiere den Task im Kernel-Mode und mache folgendes:


isr_common_stub:
; save cpu state by pushing
; main purpose registers onto the stack

pusha 

mov eax, ds
push eax

mov eax, 0x10
mov ds, eax
        mov es, eax

push esp
call Isr_Handler ; call interrupt handler
mov esp, eax

pop eax
mov ds, eax ; get old values
        mov es, eax

popa

add esp, 8 ; pop error code, interrupt number
sti ; enable interrupts
iret ; interrupt return

Also zur Info: struct cpu_state hat in den ersten 4 bytes (uint32) platz für das Register DS. Was ich hier im Grunde mache ist einen Task der im Kernelmode läuft auf den Stack pushen, DS und ES für den Kernelmode laden > Isr_Handler aufrufen > und alles wiederherstellen. Jedoch scheitert es hier bei der Instruktion nach "pop eax" bzw. das erneute Laden des Registers DS ..

Ich muss mir das dann zu hause nochmal anschauen aber ich komme nicht dahinter was hier fliegt ..


Edit: Kombinieren will ich sie nicht aber nach möglichkeit ein wenig vergleichen. Ich musste ganz schön nachdenken warum bei eurem Tutorial nach dem Interrupt Handler "mov esp, eax" steht was ja den Stack wechselt. Als ich verstanden habe WARUM das funktioniert hab ich erst verstanden wie schön das ist :D
3
Lowlevel-Coding / Re: ISR Common Stub -> INT13
« am: 28. January 2014, 23:38 »
Kann es sein, dass der eigenltiche Teil, nämlich das schalten in Ring 3, hier ausgelassen wurde?

Fehlt hier nicht so etwas wie das hier:

void switch_to_user_mode()
{
   // Set up a stack structure for switching to user mode.
   asm volatile("  \
     cli; \
     mov $0x23, %ax; \
     mov %ax, %ds; \
     mov %ax, %es; \
     mov %ax, %fs; \
     mov %ax, %gs; \
                   \
     mov %esp, %eax; \
     pushl $0x23; \
     pushl %eax; \
     pushf; \
     pushl $0x1B; \
     push $1f; \
     iret; \
   1: \
     ");
}
4
Lowlevel-Coding / Re: ISR Common Stub -> INT13
« am: 27. January 2014, 12:20 »
[ISR] Exception captured. Kernel stopped.
CPU State:
     INT: 13, RING: 0, ERRCODE: 0x0

     EAX: 0x1034D2 EBP: 0x1057F4 EBX: 0x0 ECX: 0x0
     EDI: 0x0 EDX: 0x0 EIP: 0x100DAC ESI: 0x0
     ESP: 0x1057B8 EFLAGS: 0x10216
     CS:  0x8 DS:  0x0 SS:  0x0

Das ist noch die letzte Meldung die ich vom Kernel bekomme bevor ich ihn anhalte.

@Tutorial: Das mag schon sein jedoch macht mir das fürs erste nichts aus. Ich will nur mal einen Kernel haben bei dem Paging funktioniert und Programme im Usermode laufen können. Ich muss noch rein wachsen in die os-entwickling ;)

@Interrupts ausschalten: Ist nur ein kleines hobby OS :P

@Switch: Ich verstehe die Frage nicht. Ich meine gar keinen switch. Der Task wird im Kernel mode gestartet und fürs erste bleibt er auch da. Im moment wird der task im kernel mode auf den Stack gepusht und sollte 1 zu 1 wiederhergestellt werden und das alles ohne jemals den kernel mode verlassen zu haben.

*
 *
 */
cpu_state* Thread_Init(Thread *self, uint32_t *entry, uint8_t *stack)
{
cpu_state new_state = {

.ds = 0,

.eax = 0,
.ebx = 0,
.ecx = 0,
.edx = 0,
.esi = 0,
.edi = 0,
.ebp = 0,
.esp = (uint32_t) stack,
.eip = (uint32_t) entry,

/* Ring-0-Segmentregister */
.cs = 0x08,
.ss = 0x20,

/* Turn on IRQ (IF = 1) */
.eflags = 0x202,

//.useresp = 0,
};

/*
* Copying the new cpu-state on the thread stack let it looks like
* the thread has been interrupted by an interrupt. That way the
* scheduler will just start scheduling this new thread.
*/
cpu_state *state = (void*) (stack + STACK_SIZE - sizeof(new_state));

*state = new_state;

return state;
}

5
Lowlevel-Coding / Re: ISR Common Stub -> INT13
« am: 27. January 2014, 09:34 »
:D okay dann nenne ich es ab jetzt GP. Ich verstehe aber nicht wieso ich den bekomme da ich nie vom kernel mode in einen anderen switche ..
6
Lowlevel-Coding / Re: ISR Common Stub -> INT13
« am: 26. January 2014, 20:11 »
Erstmal ein allgemeiner Kommentar, der mit dem Problem nichts zu tun hat: Wenn dein Interrupthandler mit cli anfängt, machst du was falsch. Informier dich über den Unterschied zwischen Interrupt und Trap Gates und nimm das passende anstatt IF im Handler manuell zu ändern.

Das nächste ist, dass Segmentregister nur 16 Bit breit sind. Du solltest also ax statt eax benutzen. Ich bin mir nicht sicher, was dein Assembler aus mov eax, ds macht. Speziell bin ich mir unsicher, was mit den oberen 16 Bit passiert. Auch das dürfte nicht das Problem sein, weil du ja nachher beim mov ds, eax wieder eine 16-Bit-Truncation bekommst und dann egal ist, ob in den oberen 16 Bit noch Müll stand.

Ist es der erste Userspace-Entry, der schiefgeht, oder kannst du am Anfang erfolgreich switchen und der Fehler passiert später? Bei ersterem müssten wir die ursprüngliche Initialisierung des Stacks anschauen, bei letzterem den Anfang des Interrupthandlers, der ds sichert. Hilfreich wäre es auch noch, wenn du den Wert von eax beim GPF rausbekommen könntest (z.B. durch den Registerdump von qemu -d int,  oder den Errorcode).

Ich halte mich an dieses tutorial hier:  http://www.jamesmolloy.co.uk/tutorial_html/4.-The%20GDT%20and%20IDT.html
An dieser Stelle die Interrupts abzuschalten mag vielleicht an einem Gewissen Punkt nicht empfehlenswert sein aber im Moment würde ich gern wissen warum ich einen INT13 bekomme ^^

Ich switche noch gar nicht in den Userspace. Hier will ich nur mal in den Kernel mode switchen bei einem Interrupt und den vorigen mode wieder herstellen ( nach dem interrupt ). Es passiert aber noch kein tatsächlicher switch in den user mode
7
Lowlevel-Coding / Re: ISR Common Stub -> INT13
« am: 26. January 2014, 20:07 »
Poste mal einen Qemu interrupt-Log!
BENUTZTE_QEMU_BINARY -d int -kernel KERNELSoweit ich rauslesen kann scheinst du ein #gp-Fault zu haben.

Das Logfile ist leer. Ich halte den Kernel an nach INT13. Hätte qemu mir was loggen sollen?

bei einem struct cpu_state * kannst du nacheinander alle Register in umgekehrter reinfolge pushen:
        push ebp
push edi
push esi
push edx
push ecx
push ebx
push eax
push esp

Das mache ich bereits. Gebe mit pusha alle register auf den stack (siehe code).




danach musst du um 4 incrementieren.

In meinem Fall um 8. Pushe die Interrupt Nummer noch zusätzlich auf den Stack..
8
Lowlevel-Coding / ISR Common Stub -> INT13
« am: 24. January 2014, 11:42 »
Hallo Leute,

ich weiß nicht woran das hier liegt. Folgendes passiert bei mir:


%macro isr_stub 1
global isr%1
isr%1:
cli
push byte 0
push byte %1
jmp isr_common_stub
%endmacro

isr_common_stub:
; save cpu state by pushing
; main purpose registers onto the stack

pusha 

mov eax, ds
push eax

mov eax, 0x10
mov ds, eax
        mov es, eax
        mov fs, eax
mov gs, eax

push esp
call Isr_Handler ; call interrupt handler
mov esp, eax

pop eax
mov ds, eax ; get old ds
        ;mov es, eax
        ;mov fs, eax
;mov gs, eax

popa

add esp, 8 ; pop error code, interrupt number
sti ; enable interrupts
iret ; interrupt return

Nachdem das Programm vom Isr_Handler zurückkehrt löst es bei der Instruktion mov ds, eax einen INT13 aus. Kommentiere ich dies Instruktion aus läuft alles soweit ohne Probleme.

Der Plan ist VOR Isr_Handler den Kernel-Mode aufzusetzen indem zuvor das verwendete DS Register gepush wird und dnach die Register entpsrechend gesetzt werden. Nach Isr_Handler will ich das alte DS wieder auslesen und in das Register schreiben.

Ich komme nicht wirklich dahinter was das Problem ist..

cpu_state* Isr_Handler(cpu_state *state) {

if (state->int_no <= 0x1F) {
dprint("[ISR] Exception captured. Kernel stopped.");

dprint("CPU State:");
dprint("     INT: %d, RING: %d, ERRCODE: 0x%X\n"
"\n"
"     EAX: 0x%X EBP: 0x%X EBX: 0x%X ECX: 0x%X\n"
"     EDI: 0x%X EDX: 0x%X EIP: 0x%X ESI: 0x%X\n"
"     ESP: 0x%X EFLAGS: 0x%X\n"
"     CS:  0x%X DS:  0x%X SS:  0x%X", state->int_no,
state->useresp, state->err_code, state->eax, state->ebp, state->ebx,
state->ecx, state->edi, state->edx, state->eip, state->esi,
state->esp, state->eflags, state->cs, state->ds, state->ss);

while (1) {
// Stop CPU
asm volatile ("cli; hlt");
}
}
// Hardware-Interrupts
if (state->int_no >= 0x20 && state->int_no <= 0x2f) {

dprint("[ISR] Hardware interrupt 0x%X received.", state->int_no);
  dprint("     INT: %d, RING: %d, ERRCODE: 0x%X\n"
          "\n"
          "     EAX: 0x%X EBP: 0x%X EBX: 0x%X ECX: 0x%X\n"
          "     EDI: 0x%X EDX: 0x%X EIP: 0x%X ESI: 0x%X\n"
          "     ESP: 0x%X EFLAGS: 0x%X\n"
          "     CS:  0x%X DS:  0x%X SS:  0x%X\n",
          state->int_no, state->useresp, state->err_code,
          state->eax,    state->ebp,     state->ebx,      state->ecx,
          state->edi,    state->edx,     state->eip,      state->esi,
          state->esp,    state->eflags,
          state->cs,     state->ds,      state->ss);

  //uint32_t tss[32] = { 0x00, 0x00, 0x10 };

// Call Scheduler
if (state->int_no == 0x20) {
state = Scheduler_Schedule(scheduler, state);
}

if (state->int_no >= 0x28) {
// TODO Keyboard driver
outb(0xA0, 0x20);
}

outb(0x20, 0x20); // End of interrupt (EOI)
return state;
}

9
OS-Design / Re: malloc(), free()
« am: 16. January 2013, 20:46 »
Hi!

Danke für die Antwort, hab das mittlerweile schon von weiteren Quellen bestätigt bekommen, dass das anscheinend tatsächlich so funktioniert. Kam mir etwas komisch vor und verstehe deine Bedenken :D


LG; Stefan
10
OS-Design / malloc(), free()
« am: 16. January 2013, 13:35 »
Hallo Leute!

Für eine Übung auf der Uni müssen wir u.A. einen Task erledigen, bei dem malloc() und free() für den Userspace zu implementieren sind. Ich bin im Moment noch der Meinung malloc() soweit in Ordnung implementiert zu haben und zwar wie folgt:

Über sbrk() stelle ich fest wie viel Speicher dem Programm zur Verfügung steht und verwalte von malloc() reservierten Speicher in einer doppelt verketten Liste über die ich feststellen kann, ob bei einem weiteren malloc() zwischen zwei Datenbereichen Platz ist oder ob neuer Speicher vom Kernel angefordert werden muss.

Soweit so gut..

Unser Kernel verwaltet seinen Speicher mit "Virtual Memory Areas". Das hab nicht ich implementiert, aber im Grunde gibt es einen VMA, der sozusagen unseren Heap repräsentiert und wächst, wenn man über malloc() Speicher anfordert. sbrk() vergrößert also ggf. diesen Bereich und die entsprechenden Pages werden gemappt.

Nun zum eigentlichen Problem:

Angenommen ein Userspace-Programm reserviert sich unmengen an Speicher.. Hausnummer: 1GB in diversen Arrays und am Schluss noch einen Pointer auf einen Integer am Ende der Daten. Wenn dieses Programm nun seinen gesamten Speicher bis auf diesen letzten einen Pointer freigibt, dann weiß zwar malloc(), dass am Heap Speicher frei wurde, aber der Kernel würde den VMA nicht verkleinern (können), da das Programm ja nach wie vor der Pointer auf den Integer am Ende der Daten gültig ist. Demnach würden die Pages gemappt bleiben und der RAM, obwohl schon ge-free()-d, "voll" bleiben.

Habe ich nun etwas falsch verstanden oder übersehe ich da etwas? Ich konnte nirgendwo eine Erklärung finden wann/wie/wo bei einem Aufruf von free() Speicher nicht nur am Heap freigegeben wird sondern eben auch tatsächlich Pages ungemappt werden um den physikalischen Speicher zu leeren.

Wäre dankbar für einen Schubs in die richtige Richtung!

LG Stefan :)
11
Lowlevel-Coding / Re: Stack nach Interrupt..
« am: 07. October 2012, 15:21 »
Ah jetzt hab ichs!

Okay also am Stack liegt dann einfach:

Stack Segment Pointer
Stack Pointer
EFLAGS
Code Segment Pointer
Index Pointer (Nächste Instruktion)
Error Code
Interrupt Nummer
EAX
ECX
.
.
EDI
DS
Return Address
TOP OF STACK

Ich glaub dann hab ichs ^^
12
Lowlevel-Coding / Stack nach Interrupt..
« am: 07. October 2012, 11:08 »
Hallo Leute, bei mir funktioniert zwar soweit alles wunderbar, jedoch habe ich an einer bestimmten Stelle versucht genauer zu verstehen warum bis jetzt alles funktioniert und da kamen ein paar ungereimtheiten ans Licht.

Das hier ist mein struct für den CPU-Zustand:

typedef struct cpu_state_struct {
uint32_t ds;

uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t esp;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;

uint32_t int_no, err_code;
uint32_t eip, cs, eflags, useresp, ss; // um usersp und ss geht es...
} cpu_state;

Und hier der common_stub für die Interrupts:

isr_common_stub:
; pusha: (E)AX, (E)CX, (E)DX, (E)BX, (E)SP, (E)BP, (E)SI, (E)DI
; pushes these registers in that order on the stack
pusha

        mov eax, ds
push eax

push esp ; pointer to cpu_state structure
call Isr_Handler
mov esp, eax

pop eax
popa

add esp, 8
sti ; enable interrupts
iret ; interrupt return

Nun zu meiner Frage: Hier steht, auf Seite 346, steht:

The primary difference is that with the INT n
instruction, the EFLAGS register is pushed onto the stack before the return address. (The return
address is a far address consisting of the current values of the CS and EIP registers.) Returns
from interrupt procedures are handled with the IRET instruction, which pops the EFLAGS
information and return address from the stack.



In diesem Tutorial steht:

u32int eip, cs, eflags, useresp, ss; // Pushed by the processor automatically.

allerdings konnte ich dafür noch keinen Nachweis finden. CS:EIP bzw. EFLAGS ist klar, steht auch so in der Dokumentation aber mir fehlen noch die restlichen 8 Byte in dieser Rechnung. Also wann bzw. wo werden diese "automatisch" vom Prozessor gepusht? Was habe ich übersehen?

LG
13
Lowlevel-Coding / Re: Assembler: mov eax, [esp+8]
« am: 28. July 2012, 20:19 »
Ein gutes Beispiel dafür wie man den Wald vor lauter Bäumen übersieht.

Können wir so tun als hätte ich das nicht gefragt? ^^

Danke für die Antwort MNemo!
14
Lowlevel-Coding / Assembler: mov eax, [esp+8]
« am: 28. July 2012, 19:17 »
Hallo Leute!

Ich hab einfach nichts gefunden.. warum darf man das so nicht machen (nach einem call):

_manipulate:
    mov eax, [esp+8]    ; First parameter
    mov ebx, [esp+12]   ; Second parameter
   
    mov byte [eax+11], bl
   
    ret

sondern muss zuerst ebp auf den Stack legen um dann mit ebp auf die Parameter zugreifen
zu können:

_manipulate:
    push ebp
    mov ebp, esp
   
    mov eax, [ebp+8]    ; First parameter
    mov ebx, [ebp+12]   ; Second parameter
   
    mov byte [eax+11], bl
   
    pop ebp
    ret

Ich kann ja esp auch anders manipulieren wie zb sub esp, 4 oder ähnliches.. Warum
bekomme ich bei einer indirekten Adressierung einen Segfault?
15
Offtopic / Re: Eigene CPU
« am: 20. July 2012, 00:01 »
http://mycpu.eu/
Der hat sowas selber gemacht auch mit TTL-Bausteinen. Ist aber glaube ich ein CISC.

Wahnsinn....
16
Na ich denke dann werde ich am besten einfach mal drauf loscoden was die Tutorials so hergeben und freue mich wenn ich auch mal von solchen Aha!-Erlebnissen berichten kann :D
17
Okay :D

Also vielleicht sollte ich mir gerade als Einsteiger nicht so viel Gedanken um Nachhaltigkeit machen da man beim ersten Versuch vermutlich sowieso scheitert ein sehr schönes Design zu entwickeln für einen Kernel :D

Das soll jetzt nicht zu pessimistisch klingen, aber ihr stimmt mir sicher zu, dass einiges dazu gehört um sowas einigermaßen sauber und nachvollziehbar zu schreiben.
18
Hallo Leute!

Also ich hab parallel zum Tutorial von lowlevel.eu auch noch ein anderes (jamesmolloy.co.uk) offen.
Dabei fällt sofort auf, dass die Reihenfolge nicht dieselbe ist. Außerdem wird bei jamesmolloy.co.uk auch ein VFS
behandelt. Jetzt wollte ich fragen:

Macht es einen Unterschied in welcher Reihenfolge ich die essentiellen Elemente des Systems implementiere oder
gibt es Wege wie man es besser bzw. schlechter machen kann? Was wäre eurer Meinung nach die vernünftigste
Reihenfolge?
19
Danke für den Tipp Jidder! Zwar durch Umwege aber vor allem durch den Tipp mit dem Stack-Pointer bin ich - ziemlich umständlich - dann auf den Punkt gekommen, der den Fehler verursacht hat.

Es hat zwar echt gedauert den durchaus offensichtlichen Fehler zu finden, aber ich hab dafür immerhin ne Menge gelernt. ^^

Der Fehler war, dass ich "Dieser Teil muss aufgerufen werden, bevor Hardwareinterrupts aktiviert werden." gekonnt ignoriert habe und die Interrupts enabled habe bevor der Scheduler korrekt initialisiert wurde. Ich hätte das eigentlich sofort sehen müssen und es roch eigentlich schon die ganze Zeit nach einem "Timing-Problem".

Danke Leute für eure Hilfe!

Gdt_Init();
Idt_Init();

Thread init_threads[2];
cpu_state *init_states[2];
init_states[0] = Thread_Init(&init_threads[0], (uint32_t*)&task_a, stack_a);
init_states[1] = Thread_Init(&init_threads[1], (uint32_t*)&task_b, stack_b);

Scheduler_Init(scheduler, init_states, 2);

Idt_EnableHardwareInterrupts();
20
So das sieht jetzt etwas hässlich aus:


Das ist outb(). Die wird am Ende für das End Of Interrupt Signal gecallt mit outb(0x20, 0x20);

static inline void outb(uint16_t port, uint8_t val)
{
  1016c0: 55                    push   ebp
  1016c1: 89 e5                mov    ebp,esp
  1016c3: 83 ec 08              sub    esp,0x8
  1016c6: 8b 55 08              mov    edx,DWORD PTR [ebp+0x8]
  1016c9: 8b 45 0c              mov    eax,DWORD PTR [ebp+0xc]
  1016cc: 66 89 55 fc          mov    WORD PTR [ebp-0x4],dx
  1016d0: 88 45 f8              mov    BYTE PTR [ebp-0x8],al
   __asm__ __volatile__ (
  1016d3: 0f b6 45 f8          movzx  eax,BYTE PTR [ebp-0x8]
  1016d7: 0f b7 55 fc          movzx  edx,WORD PTR [ebp-0x4]
  1016db: ee                    out    dx,al
   "outb %b0, %w1"
   :
   : "a"(val), "d"(port));
}
  1016dc: c9                    leave 
  1016dd: c3                    ret

Direkt nach "ret" springt die CPU an eine Stelle an der sie nichts verloren hat. Es muss also am Stack liegen. Aber wie bekomme ich heraus wo der Fehler passiert? Ich kann mir den Stack nicht ausgeben lassen da das System vorher crasht.

Hier die letzten drei Schritte aufgezeichnet mit gdb. Man sieht wie nach "ret" etwas Falsches im EIP Register steht.

(gdb) stepi
27    __asm__ __volatile__ (

(gdb) stepi
0x001016d7 27    __asm__ __volatile__ (

(gdb) stepi
0x001016db 27    __asm__ __volatile__ (

(gdb) info registers
eax            0xb7 183
ecx            0x0 0
edx            0x6667 26215
ebx            0x0 0
esp            0xffffffb0 0xffffffb0
ebp            0xffffffb8 0xffffffb8
esi            0x0 0
edi            0x0 0
eip            0x1016db 0x1016db <outb+27>
eflags         0x82 [ SF ]
cs             0x8 8
ss             0x10 16
ds             0x10 16
es             0x10 16
fs             0x10 16
gs             0x10 16

(gdb) stepi
31 }

(gdb) info registers
eax            0xb7 183
ecx            0x0 0
edx            0x6667 26215
ebx            0x0 0
esp            0xffffffb0 0xffffffb0
ebp            0xffffffb8 0xffffffb8
esi            0x0 0
edi            0x0 0
eip            0x1016dc 0x1016dc <outb+28>
eflags         0x82 [ SF ]
cs             0x8 8
ss             0x10 16
ds             0x10 16
es             0x10 16
fs             0x10 16
gs             0x10 16

(gdb) stepi
0x001016dd in outb (port=26215, val=183 '\267')
    at arch/x86/common/source/../../../../debug/include/../../arch/x86/ports/include/Ports.h:31
31 }

(gdb) info registers
eax            0xb7 183
ecx            0x0 0
edx            0x6667 26215
ebx            0x0 0
esp            0xffffffbc 0xffffffbc
ebp            0x66042454 0x66042454
esi            0x0 0
edi            0x0 0
eip            0x1016dd 0x1016dd <outb+29>
eflags         0x82 [ SF ]
cs             0x8 8
ss             0x10 16
ds             0x10 16
es             0x10 16
fs             0x10 16
gs             0x10 16

(gdb) stepi
0x67c2af0f in ?? ()

(gdb) info registers
eax            0xb7 183
ecx            0x0 0
edx            0x6667 26215
ebx            0x0 0
esp            0xffffffc0 0xffffffc0
ebp            0x66042454 0x66042454
esi            0x0 0
edi            0x0 0
eip            0x67c2af0f 0x67c2af0f
eflags         0x82 [ SF ]
cs             0x8 8
ss             0x10 16
ds             0x10 16
es             0x10 16
fs             0x10 16
gs             0x10 16
Seiten: [1] 2 3 4

Einloggen