Autor Thema: C - Kernel wird nicht geladen  (Gelesen 10927 mal)

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #20 am: 20. August 2009, 11:48 »
Hi,

00065895575-i-@006f0018-[CPU0 ] >> add dword ptr ds:[eax], eax : 0100
ausgeführt wurde. Also muss da der Fehler sein.
Jedoch finde ich im Assembler-Code (boot.asm) kein
"add", aber den Register "eax".
Wenn du den Code nicht als deinen erkennst, dann heißt das, dass dein Bootloader/Kernel irgendwo ins Nirvana springt, oder dass sich dein Kernel nicht an der Stelle befindet, wo der Bootloader hinspringt. Ich vermute letzteres.

Zitat
Die 0100 ähnelt der Addresse
dess Kernels, fehlt halt eine Null, die habe ich anschließend rangehängt
also beim jmp, jetzt siehts so aus:
Hinter dem Assemblerbefehl steht immer der Maschinencode in Hexadezimaldarstellung. Die Ähnlichkeit mit irgendwelchen Adressen hat an dieser Stelle nichts zu bedeuten. Wenn dein Programmfluss irgendwo im Nirvana landet, dann ist dieser Speicher einfach mit zufälligen Werten, je nach Art des Speichers auch mit Nullen (0x00) oder Einsen (0xFF) gefüllt.

Das Interessante hier ist nicht der Befehl selbst, sondern der Zustand der CPU. Der Wert des Befehlszählers (RIP bzw. EIP) ist 00000000006f0018, was weit ab von deinem Programm ist.

Zitat
00002609039-i-@00010006-[CPU0 ] >> and byte ptr gs:[edi+ebp*2+0x20], dh : 6520746F20
00002609039-e-@00010006-[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
Dies mal ist der Maschinencode wesentlich interessanter. 6520746F20 sieht aus wie ASCII Code und zwar entspricht der genau dem "e to " aus deinem "Welcome to Protected Mode". Das heißt die CPU versucht die Daten auszuführen, weil die Daten in deiner Binärdatei vor dem Code liegen.

Als du die Ausgabe entfernt hast, hast du auch diesen String aus deinem Programm entfernt. Dann war der Datenbereich deines Programms leer und wieder der Code das erste in deinem Progamm. Das Fehler liegt also in dem Prozess, wie du den Kernel erstellst, nicht am Code des Kernels.

Der String landet in der *(.rodata) oder *(.rdata) Sektion je nach Compiler. Änder mal dein Linkerskript so, dass du die Sektionen erwähnst:
INPUT("kernel.o")
ENTRY(_begin)
SECTIONS
{
  .text  0x10000 :
  {
    *(.text)
    *(.rdata)
    *(.rodata)
  }
  .data  :
  {
    *(.data)
  }
  .bss  :
  {
    *(.bss)
  }
}

Außerdem würde ich dir mal empfehlen, dich mehr mit den Werkzeugen auseinander zu setzen. objdump kann dir viele Informationen über deine Objekt-Dateien (und über deinen Kernel solange er nicht eine Binärdatei ist) liefern, mit ndisasm, welches bei NASM dabei ist, kannst du den Kernel, wenn er eine flache Binärdatei ist, disassemblieren. Außerdem könntest du dich mal mit dem Debugger von Bochs auseinander setzen. Mit lb 0x7c00 kannst du da einen Breakpoint an den Anfang des Bootloaders setzen, mit c kommst du dann bis zu diesem Breakpoint, mit s kannst du single steppen und mit n kannst du einen step over (z.B. über BIOS Interrupts) machen.

All diese Programme haben außerdem Handbücher, die online verfügbar sind.
« Letzte Änderung: 20. August 2009, 11:51 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #21 am: 20. August 2009, 12:51 »
Ich habs jetzt, der Fehler war im C Code, ich habe das ausprobiert:

int begin() {
char *vidmem = (char *) 0xB8000;
unsigned int i=0;
while(i < (80*25*2)) {
vidmem[i]='G';
i++;
vidmem[i]=0x06;
i++;
};

for(;;);
}

Da wird der Bildschirm mit "G" gefüllt.
Aber wenn ich eine Funktion aufrufen will, in dem man ein
char übergeben muss, wird die Funktion net ausgeführt.
z.B.:

void printf(char *text);

int begin() {
printf("TEST");
while(1);
}

void printf(char *text) {
   char *vidmem = (char *) 0xB8000;
   unsigned int i=0;
   while(i < (80*25*2))
   {
      vidmem[i]='G';
      i++;
      vidmem[i]=0x06;
      i++;
   };
};

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #22 am: 20. August 2009, 13:24 »
Aber wenn ich eine Funktion aufrufen will, in dem man ein
char übergeben muss, wird die Funktion net ausgeführt.
z.B.:

void printf(char *text);

int begin() {
printf("TEST");
while(1);
}
Hast du den Code genau so ausprobiert? In dem Fall sollte gcc keine Optimierung vornehmen.  Ansonsten optimiert gcc an so nem printf scheinbar manchmal. Siehe dazu das Zitat aus einem anderen Thread:

Der GCC optimiert ein printf("foo\n") zu einem puts("foo"), weil ein standardkonformes puts automatisch ein \n ausgibt.

Ich schätze da gibts es mindestens folgende Möglichkeiten:
- printf nicht printf nennen
- oder standardkonformes puts implementieren
- oder angeblich soll da -fno-builtin oder -fno-builtin-printf helfen.

-> http://www.ciselant.de/projects/gcc_printf/gcc_printf.html
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #23 am: 20. August 2009, 13:26 »
Hmm..... ich kann nur char´s übergeben, die net mehr als 2 Zeichen enthalten,
also z.B. printf("hi"); , das geht, aber printf("hih"); geht nicht.

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #24 am: 20. August 2009, 13:28 »
@MNemo

Ich habe die Funktion auch schon unbenannt in "v_print", hilft aber auch nix  :-(.

void v_print(char *msg);

int begin() {
v_print("Die");

while(1);
}

void v_print(char *msg) {
char *vidmem = (char *) 0xB8000;
unsigned int i=0;
unsigned int s=0;
while(s < sizeof(msg) - 1) {
vidmem[i]=msg[s];
i++;
vidmem[i]=0x06;
i++;
s++;
}
}

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #25 am: 20. August 2009, 13:44 »
void v_print(char *msg) {
char *vidmem = (char *) 0xB8000;
unsigned int i=0;
unsigned int s=0;
while(s < sizeof(msg) - 1) {
vidmem[i]=msg[s];
i++;
vidmem[i]=0x06;
i++;
s++;
}
}
Emm… Ja…

Deine C Kenntnisse sind ja nicht gerade berauschend.
sizeof(msg) wird dir immer 4(bzw. bei 64-Bit CPUs 8 ) liefern. weil msg nur mal ein Pointer ist. und die sind 4 bzw. 8 Byte groß.

du solltest dir bei der String Ausgabe eher von nutzen machen, dass c-strings ein Null-Byte am ende haben.

BTW: ein char ist _ein_ Zeichen. ein string ist ein array aus chars mit einem 0-Byte(char) am ende
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #26 am: 20. August 2009, 13:56 »
Das Problem liegt da woanders, wie gesagt, wenn ich an eine Funktion ein Char-Array übergebe und deren inhalt länger als 2 Zeichen ist dann wird die Funktion nichmal aufgerufen.

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #27 am: 20. August 2009, 14:02 »
was sagt den
$ objdump -d kernel.odazu?
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

Cjreek

  • Beiträge: 104
    • Profil anzeigen
Gespeichert
« Antwort #28 am: 20. August 2009, 14:04 »
Hi,

versuch doch mal folgendes:

void v_print(char *msg) {
  char *vidmem = (char *) 0xB8000;
  int i = 0;
  int j = 0;
  while ((byte)msg[i] != 0)
  {
     vidmem[j] = msg[i];
     j++;
     vidmem[j] = (char)0x07
     j++;
     i++;
  }
}

Für Syntaxfehler übernehme ich keine Haftung. Bin kein C-ler  :-D
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #29 am: 20. August 2009, 14:05 »
file format pe-i386
Disassembly of section .text:

00000000 <.text>:
   0:   44              inc    %esp
   1:   65 72 00        jb     4 <_begin>

00000004 <_begin>:
   4:   55              push   %ebp
   5:   89 e5           mov    %esp,%ebp
   7:   68 00 00 00 00  push   $0x0
   c:   e8 13 00 00 00  call   24 <_v_print>
  11:   83 c4 04        add    $0x4,%esp
  14:   eb 02           jmp    18 <_begin+0x14>
  16:   eb 08           jmp    20 <_begin+0x1c>
  18:   eb fa           jmp    14 <_begin+0x10>
  1a:   8d b6 00 00 00  lea    0x0(%esi),%esi
  1f:   00
  20:   89 ec           mov    %ebp,%esp
  22:   5d              pop    %ebp
  23:   c3              ret

00000024 <_v_print>:
  24:   55              push   %ebp
  25:   89 e5           mov    %esp,%ebp
  27:   83 ec 10        sub    $0x10,%esp
  2a:   c7 45 fc 00 80  movl   $0xb8000,0xfffffffc(%ebp)
  2f:   0b 00
  31:   c7 45 f8 00 00  movl   $0x0,0xfffffff8(%ebp)
  36:   00 00
  38:   c7 45 f4 00 00  movl   $0x0,0xfffffff4(%ebp)
  3d:   00 00
  3f:   90              nop
  40:   8b 45 08        mov    0x8(%ebp),%eax
  43:   8b 55 f4        mov    0xfffffff4(%ebp),%edx
  46:   01 d0           add    %edx,%eax
  48:   80 38 00        cmpb   $0x0,(%eax)
  4b:   75 03           jne    50 <_v_print+0x2c>
  4d:   eb 31           jmp    80 <_v_print+0x5c>
  4f:   90              nop
  50:   8b 45 fc        mov    0xfffffffc(%ebp),%eax
  53:   8b 55 f8        mov    0xfffffff8(%ebp),%edx
  56:   01 d0           add    %edx,%eax
  58:   8b 55 08        mov    0x8(%ebp),%edx
  5b:   8b 4d f4        mov    0xfffffff4(%ebp),%ecx
  5e:   01 ca           add    %ecx,%edx
  60:   8a 0a           mov    (%edx),%cl
  62:   88 08           mov    %cl,(%eax)
  64:   ff 45 f8        incl   0xfffffff8(%ebp)
  67:   8b 45 fc        mov    0xfffffffc(%ebp),%eax
  6a:   8b 55 f8        mov    0xfffffff8(%ebp),%edx
  6d:   01 d0           add    %edx,%eax
  6f:   c6 00 06        movb   $0x6,(%eax)
  72:   ff 45 f8        incl   0xfffffff8(%ebp)
  75:   ff 45 f4        incl   0xfffffff4(%ebp)
  78:   eb c6           jmp    40 <_v_print+0x1c>
  7a:   8d b6 00 00 00  lea    0x0(%esi),%esi
  7f:   00
  80:   89 ec           mov    %ebp,%esp
  82:   5d              pop    %ebp
  83:   c3              ret

00000084 <_v_clear>:
  84:   55              push   %ebp
  85:   89 e5           mov    %esp,%ebp
  87:   83 ec 10        sub    $0x10,%esp
  8a:   c7 45 fc 00 80  movl   $0xb8000,0xfffffffc(%ebp)
  8f:   0b 00
  91:   c7 45 f8 00 00  movl   $0x0,0xfffffff8(%ebp)
  96:   00 00
  98:   81 7d f8 9f 0f  cmpl   $0xf9f,0xfffffff8(%ebp)
  9d:   00 00
  9f:   76 02           jbe    a3 <_v_clear+0x1f>
  a1:   eb 1e           jmp    c1 <_v_clear+0x3d>
  a3:   8b 45 fc        mov    0xfffffffc(%ebp),%eax
  a6:   8b 55 f8        mov    0xfffffff8(%ebp),%edx
  a9:   01 d0           add    %edx,%eax
  ab:   c6 00 20        movb   $0x20,(%eax)
  ae:   ff 45 f8        incl   0xfffffff8(%ebp)
  b1:   8b 45 fc        mov    0xfffffffc(%ebp),%eax
  b4:   8b 55 f8        mov    0xfffffff8(%ebp),%edx
  b7:   01 d0           add    %edx,%eax
  b9:   c6 00 07        movb   $0x7,(%eax)
  bc:   ff 45 f8        incl   0xfffffff8(%ebp)
  bf:   eb d7           jmp    98 <_v_clear+0x14>
  c1:   89 ec           mov    %ebp,%esp
  c3:   5d              pop    %ebp
  c4:   c3              ret

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #30 am: 20. August 2009, 14:14 »
Zitat
c:   e8 13 00 00 00  call   24 <_v_print>
also der Aufruf findet eindeutig statt.

ändere mal diese Zeile in deinem linkscript
    *(.rodata)
zu
    *(.rodata*)
gcc steckt strings AFAIK in sections mit namen wie
 .rodata-str-XY
vielleicht ist dein string ja einfach nicht mit gelinkt.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #31 am: 20. August 2009, 14:33 »
Jetzt kann ich maximal ne 3-Zeichen-Char-Array an eine Funktion übergeben  :-D. Mehr geht nich....

Link.ld

INPUT("C:\Users\Pk3\Desktop\C_Kernel\kernel.o")
ENTRY(_begin)
SECTIONS
{
  .text  0x10000 :
  {
    *(.text)
    *(.rdata)
    *(.rodata*)
  }
  .data  :
  {
    *(.data)
  }
  .bss  :
  {
    *(.bss)
  }
}

kernel.c
void v_print(char *msg);
void v_clear();

int begin() {
v_print("Derd");
while(1);
}

void v_print(char *msg) {
char *vidmem = (char *) 0xB8000;
unsigned int i=0;
unsigned int s=0;
while(msg[s] != 0) {
vidmem[i]=msg[s];
i++;
vidmem[i]=0x06;
i++;
s++;
}
}

void v_clear() {
char *vidmem = (char *) 0xb8000;
unsigned int i=0;
while(i < (80*25*2)) {
vidmem[i]=' ';
i++;
vidmem[i]=0x07;
i++;
}
}

boot.asm
[BITS 16]
org 0x7c00

%define STACKSEGMENT  0x9000 ; lineare Adresse des Stacks  : 0x90000
%define STACKSIZE     0x200 ; Größe des Stacks     : 512Byte
%define KERNELSEGMENT 0x1000 ; lineare Adresse des Kernels : 0x10000

jmp START
 
GDTR:
limit  dw (GDT_END - GDT - 1)
base   dd (0)
GDT:
NULL_DESCRIPTOR EQU $-GDT

dd 0
dd 0
CODE_DESCRIPTOR EQU $-GDT
dw 0ffffh
dw 0
db 0
db 09ah
db 0cfh
db 0
DATA_DESCRIPTOR EQU $-GDT
dw 0ffffh
dw 0
db 0
db 092h
db 0cfh
db 0
GDT_END:

START:
cli ; keine Interrupts
mov ax, STACKSEGMENT
mov ss, ax ; Stacksegment setzen
mov sp, STACKSIZE ; Größe des Stacks festlegen
xor ax, ax ; ax = 0
mov ds, ax ; Datensegment auf 0 setzen
sti

xor bx, bx ; Ziel-Offset : 0x0
mov ax, KERNELSEGMENT ; Ziel-Segment : 0x1000
mov es, ax
mov ah, 0x2 ; Funktion 0x2 : Sektor lesen
mov al, 1 ; Anzahl der Sektoren : 1
mov ch, 0 ; Track        : 0
mov cl, 2 ; LSN : 2
mov dh, 0 ; Head : 0
mov dl, 0 ; Laufwerk     : A
int 0x13 ; Interrupt    : 0x13

cli ; keine Interrupts
mov ax, cs ; Code-Segment holen
mov ds, ax ; Daten-Segment gleichsetzen
xor eax, eax ; ax = 0
mov es, ax ; Extra-Segment auf Null setzen
 
mov si, GDT ; Quelle : GDT
xor di, di ; Ziel : 0x0000
mov cx, 6 ; 6 DoubleWords kopieren (ganze GDT)
rep movsd

lgdt [GDTR]
 
mov eax, cr0
or eax, 1 ; Bit0 setzen (PE-Bit enabled)
mov cr0, eax

db 0xea ; FAR-JUMP zum Codesegment
dw (PMODE)
dw 0x8

[BITS 32] ; 32 Bit-Code erstellen
PMODE:
xor      eax, eax
mov      eax, 2 ; Selektor für das Datensegment erstellen
shl      eax, 3
 
mov ds, ax ; Daten-, Stack- und Extrasegment mit
mov ss, ax ; Datensegmentdeskriptor laden
mov es, ax
xor ax, ax
mov fs, ax ; fs und gs mit Nulldeskriptor laden
mov gs, ax
mov esp, 09000h ; Stack setzen

jmp 08h:010000h

times 512-($-$$)-2 db 0
dw 0x0AA55

DerHartmut

  • Beiträge: 236
    • Profil anzeigen
    • Mein Blog
Gespeichert
« Antwort #32 am: 20. August 2009, 15:05 »
Mach aus dem char* vidmem mal bitte ein unsigned long *vidmem = (unsigned long *)0xB8000
$_="krJhruaesrltre c a cnp,ohet";$_.=$1,print$2while s/(..)(.)//;
Nutze die Macht, nutze Perl ;-)

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #33 am: 20. August 2009, 15:08 »
Dein code tut bei mir ohne Probleme.

$ nasm -f bin boot.asm
$ gcc -m32 -ffreestanding -fleading-underscore -c kernel.c
$ ld -melf_i386 -T link.ld -o kernel.bin kernel.o
$ dd if=/dev/zero of=floppy.img bs=512 count=2880
$ cat boot kernel.bin | dd of=floppy.img conv=notrunc
$ qemu -fda floppy.img

Ich spare mir das objcopy mit
OUTPUT_FORMAT( "binary" ) im linkerscript

@hartmut: warum denn das?
[edit]ich kann mir nicht vorstellen das es tut wenn man alle 4 bzw. 8 byte abwechselnd ein Daten- und Attribut-Byte in den RAM schreibt.[/edit]
« Letzte Änderung: 20. August 2009, 15:19 von MNemo »
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

DerHartmut

  • Beiträge: 236
    • Profil anzeigen
    • Mein Blog
Gespeichert
« Antwort #34 am: 20. August 2009, 15:09 »
Weil ich es so gemacht habe *G*
$_="krJhruaesrltre c a cnp,ohet";$_.=$1,print$2while s/(..)(.)//;
Nutze die Macht, nutze Perl ;-)

Pk3

  • Beiträge: 52
    • Profil anzeigen
    • Xyross
Gespeichert
« Antwort #35 am: 20. August 2009, 16:06 »
@MNemo

-m32 -fleading-underscore
So funktionierts, jetzt geht alles, danke an alle  :-D!

 

Einloggen