Autor Thema: C Übergang  (Gelesen 6921 mal)

syxce

  • Beiträge: 45
    • Profil anzeigen
Gespeichert
« am: 01. December 2005, 22:03 »
Hallo,
wenn ich nun in C weiter schreiben möchte, wo bzw. wie müsste ich hier einen call machen ?
Und wie muss ich das dann assemblieren oder verbinden wenn ich nun eine bootloader.bin eine kernel.bin und eine kernelc.bin habe ?

danke schon mal


Hier der Code wo ich diesen call zu c machen will:
mov ax, 1000h
mov ds, ax
mov es, ax

push dx ;wieso dx? meinst du ax?
push es
xor ax, ax
mov es, ax
cli
mov word [es:0x21*4], _int0x21 ; Pointer auf den Handler
mov [es:0x21*4+2], cs ; Pointer auf CS
sti
pop es
pop dx

start:
mov si, msg
mov al, 0x01
int 0x21

call getkey
jmp reboot

msg db "Interrupt ausgeführt",13,10,0

_int0x21:
_int0x21_ser0x01: ; funktion 0x01
cmp al, 0x01 ; funktion 0x01 angefragt?
jne _int0x21_end ; nächste Routine checken

_int0x21_ser0x01_start:
lodsb ; nächstes Byte laden
or al, al ; 0-Byte?
jz _int0x21_ser0x01_end
mov ah, 0x0E ; BIOS Teletype
mov bh, 0x00 ; Page 0
mov bl, 0x07 ; Text-Attribute
int 0x10 ; BIOS-Call
jmp _int0x21_ser0x01_start
_int0x21_ser0x01_end:
jmp _int0x21_end

_int0x21_end:
iret


getkey:
mov ah, 0
int 016h
ret

reboot:
db 0EAh
dw 0000h
dw 0FFFFh

zacK

  • Beiträge: 216
    • Profil anzeigen
    • http://www.domae.ch
Gespeichert
« Antwort #1 am: 01. December 2005, 23:04 »
kommt drauf an welches wie du c compilierst. als erstes mal muss du es in ein flat binary compilieren. aussderem mit zum beispiel einem linkerscript den code "positionieren" (wie org bei asm). Dann kommt es auf ein detail an:

1. du kompilierst es zu 16bit code (z.B mit Turbo C 16bit):
dann kannst du die binarys (boot.bin + gelinkte kernelc.o kernelasm.o) zusammenkopieren und auf die diskette schmeissen. im kernelasm.asm must du dann nach int 0x21 und vor msg db "Int..." (call get.. - jmp reboot  brauchts nicht mehr) ein jmp _main (z.B. Bei linux "_" weglassen).
Dazu must du die methode main() noch im kernelasm.asm als extern deklarieren:
nasm -> [EXTERN _main]

2. oder du kompiilierst es zu einem 32 bit code. (z.B mit GCC):
da sieht es noch ein wenig komplizierter aus... erklär ich dir wenn du es so machst.. ^^

gruz

syxce

  • Beiträge: 45
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 02. December 2005, 13:06 »
Ja ich werds mit gcc machen und wäre dir dankbar für eine erklärung  :wink:

greets

zacK

  • Beiträge: 216
    • Profil anzeigen
    • http://www.domae.ch
Gespeichert
« Antwort #3 am: 02. December 2005, 17:15 »
ok.. ^^

du brauchst drei dateien:
kernel16.asm -> darin wechselst du zu Protected Mode etc.
kernel32.asm -> dies brauchst du nur um zum c kernel zu springen
kernelc.c       -> eigendlicher kernel in c

da du nun den kernel in gcc programmierst und ihn in ein 32bit flat binary compilierst musst du dein computer / emulator in einen anderen modus "versetzten". den protected mode. Protected mode hat viele features. unter anderem paging, multitasking, erhöte sicherheit..etc
das machst du im kernel16asm. tee jay hat da ein gute tutorial. übrigens auch für einen c kernel.

kernel32.asm.
da ld ein problem hat wenn du ein 16bit code mit einem 32 bit code zusammenlinken willst, brauchst du noch ein 32bit asm kernel teil. in diesem ist nur der aufruf zum c kernel.

dann linkst du die vorkompilierten kernels (kernel32.asm kernelc.c) zusammen und kopierst am schluss kernel16.bin und kernel.bin zusammen und voila.

schau dir am besten das tutorial vom tee jay an...
wenn du dann noch problemem hast, frag einfach noch mal.

gruss

syxce

  • Beiträge: 45
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 03. December 2005, 17:13 »
Hallo,
ich habe nun das ausprobiert was du gesagt hast doch leider erhalte ich keine Ausgabe, er macht irgendwie gar nichts.
Ich glaube der Fehler liegt im kernel16.asm irgendwo am Ende, für änderungen am code wäre ich echt dankbar da ich es mir dann vielleicht erklären kann !?

Danke schon mal

Hier mein kernel16.asm:

[Bits 16]

mov ax, 1000h
mov ds, ax
mov es, ax

push dx
push es
xor ax, ax
mov es, ax
cli
mov word [es:0x21*4], _int0x21
mov [es:0x21*4+2], cs
sti
pop es
pop dx

start:
mov si, msg
mov al, 0x01
int 0x21

msg db "Meine Aufgabe ist nach C zu wechseln, Taste druecken um neu zu starten",13,10,0

_int0x21:
_int0x21_ser0x01:
cmp al, 0x01
jne _int0x21_end

_int0x21_ser0x01_start:
lodsb
or al, al
jz _int0x21_ser0x01_end
mov ah, 0x0E
mov bh, 0x00
mov bl, 0x07
int 0x10
jmp _int0x21_ser0x01_start
_int0x21_ser0x01_end:
jmp _int0x21_end
_int0x21_end:
iret


jmp start ;GDT überspringen

NULL_Desc:
dd 0
dd 0

CODE_Desc:
dw 0xFFFF ;Segmentgröße Byte 0/1
dw 0 ;Segmentbasisadresse Byte 0/1
db 0 ;Segmentbasisadresse Byte 2
db 10011010b ;Zugriffsberechtigungen
db 11001111b ;Zusatz + Segmentgröße Bits 16 - 19
db 0 ;Segmentbasisadresse Byte 3


DATA_Desc:
dw 0xFFFF
dw 0
db 0
db 0x92
db 0xCF
db 0

gdt:
Limit dw 0 ;Größe der GDT (wird später eingetragen)
Base dd 0 ;Adresse der GDT (wird später eingetragen)


start:

cli ;Interrupts ausschalten

mov eax, cs ;EAX auf derzeitiges Codesegment setzen
mov ds, ax ;DS auf Codesegment setzen

shl eax, 4 ;EAX mit 16 multiplizieren (Lineare Adresse
;des Codesegments errechnen)
mov [CODE_Desc+2], ax ;Lineare Adresse des Codesegmentes als
mov [DATA_Desc+2], ax ;Startadresse des Code- und Datendeskriptors
shr eax, 16 ;eintragen
mov [CODE_Desc+4], al
mov [DATA_Desc+4], al

mov eax, cs ;Startadresse der GDT errechnen
shl eax, 4
add eax, NULL_Desc

mov [Base], eax ;Startadresse der GDT eintragen
mov [Limit], WORD gdt - NULL_Desc -1 ;Größe der GDT errechnen und eintragen

lgdt [gdt] ;GDT laden

mov eax, cr0 ;In den Protected Mode schalten,
or eax, 1 ;indem Bit 0 des CR0 Registers auf 1
mov cr0, eax ;gesetzt wird

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


[BITS 32] ;32 Bit Code erstellen

PMODE:
mov WORD [CODE_Desc+2], 0 ;Code Segmentstartaddresse auf 0 setzen
mov WORD [DATA_Desc+2], 0 ;Daten Segmentstartadresse auf 0 setzen
mov BYTE [CODE_Desc+4], 0 ;Code Segmentstartaddresse auf 0 setzen
mov BYTE [DATA_Desc+4], 0 ;Daten Segmentstartadresse auf 0 setzen

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
mov eax, 0 ;FS und GS mit Null-Deskriptor laden
mov fs, ax
mov gs, ax
mov esp, 0x1FFFFF ;Stack auf unterhalb der 2 MB Grenze setzen

jmp 0x8:0x10000 + PMODE2 ;Sprung in das "neue" Codesegment

PMODE2:
jmp END ;Zum Ende Springen

times 512-($-$$) db 0; ;Da der Linker sich nicht mit ungeraden
;Dateigrößen verträgt, wird diese Datei auf 512
;gepaddet.

END:


Hier mein kernel32.asm:

[Bits 32]

extern _main
global start

start:
call _main

stop:
jmp stop


Und hier mein kernelc.c:

int main()
{
char *Text = "Welcome to Protected Mode";
char *VideoMem = (char*)0xB8000;
 
while(*Text)
{
*VideoMem = *Text;
*VideoMem++;
*VideoMem = 7;
*VideoMem++;
*Text++;
}
 
return(0);
}

SSJ7Gohan

  • Beiträge: 398
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 03. December 2005, 18:05 »
Der Code
jmp      start      ;GDT überspringen

Wird nie ausgeführt, da du nicht zu ihm jumpst oder so.

Ausserdem gibt es das Label start bei dir zweimal. Lass am besten mal deinen Interruptcode am Anfang weg und springe sofort in den Protected Mode.

syxce

  • Beiträge: 45
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 03. December 2005, 18:21 »
Habe ich bereits getestet, geht trotzdem nicht. :?
Diesen Code um in den Protected Mode zu springen habe ich 1:1 von dem Tutorial von TeeJay übernommen.

syxce

  • Beiträge: 45
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 05. December 2005, 19:29 »
Hallo,
nach ewigen probieren habe ich noch immer nicht erreicht was ich haben wollte, obwohl ich genau so vorgegangen bin wie zack es mir beschrieben hat.
Also, ich habe 3 Dateien die ich am Schluss zu einer zusammenfügen möchte, die bootloader.bin, die kernel16.bin, die kernel32.bin und die ckernel.c.
Am Ende sollten alle Dateien unter os.img vereint sein, jetzt wäre icht dankbar wenn mir jemand meinen Fehler erklären könnte, der ckernel sollte normalerweise eine Meldung ausgeben, statt dessen tut der aber gar nichts, warum nur.
Für ÄNDERUNGEN AM CODE wäre ich äußerst dankbar, so kann ich diese Dinge verstehen.
Hier mein kompilier Vorgang und anschließend meine Files:

nasm -f bin -o bootloader.bin bootloader.asm
nasm -f bin -o kernel16.bin kernel16.asm
nasm -f aout -o kernel32.obj kernel32.asm
gcc -ffreestanding -c -Os -o ckernel.obj ckernel.c
ld -T link.txt -o c32kernel.bin
copy bootloader.bin+kernel16.bin+c32kernel.bin os.img (DOS kopieren)

bootloader.bin (Ich hätte es auch mit dem von TeeJay probiert, geht auch nicht):
org 0x7C00

start:

cli
mov ax, 0x9000
mov ss, ax
mov sp, 0
sti

mov [bootdrv], dl

call kernel

mov ax, 0x1000
mov es, ax
mov ds, ax
push ax
mov ax,0
push ax
retf

bootdrv db 0
loadmsg db "Loading...",13,10,0

putstr:
lodsb
or al, al
jz short putstrd

mov ah, 0x0E
mov bx,0x0007
int 0x10
jmp putstr
putstrd:
retn

kernel:

push ds
mov ax, 0
mov dl, [bootdrv]
int 13h
pop ds
jc kernel

load:
mov ax,0x1000
mov es, ax
mov bx,0

mov ah, 2
mov al, 5
mov cx, 2
mov dx, 0
int 13h
jc load
mov si, loadmsg
call putstr
retn

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


Kernel16.bin:
[BITS 16] ;16 Bit Code erstellen
jmp start ;GDT überspringen

NULL_Desc:
dd 0
dd 0

CODE_Desc:
dw 0xFFFF ;Segmentgröße Byte 0/1
dw 0 ;Segmentbasisadresse Byte 0/1
db 0 ;Segmentbasisadresse Byte 2
db 10011010b ;Zugriffsberechtigungen
db 11001111b ;Zusatz + Segmentgröße Bits 16 - 19
db 0 ;Segmentbasisadresse Byte 3


DATA_Desc:
dw 0xFFFF
dw 0
db 0
db 0x92
db 0xCF
db 0

gdt:
Limit dw 0 ;Größe der GDT (wird später eingetragen)
Base dd 0 ;Adresse der GDT (wird später eingetragen)


start:

cli ;Interrupts ausschalten

mov eax, cs ;EAX auf derzeitiges Codesegment setzen
mov ds, ax ;DS auf Codesegment setzen

shl eax, 4 ;EAX mit 16 multiplizieren (Lineare Adresse
;des Codesegments errechnen)
mov [CODE_Desc+2], ax ;Lineare Adresse des Codesegmentes als
mov [DATA_Desc+2], ax ;Startadresse des Code- und Datendeskriptors
shr eax, 16 ;eintragen
mov [CODE_Desc+4], al
mov [DATA_Desc+4], al

mov eax, cs ;Startadresse der GDT errechnen
shl eax, 4
add eax, NULL_Desc

mov [Base], eax ;Startadresse der GDT eintragen
mov [Limit], WORD gdt - NULL_Desc -1 ;Größe der GDT errechnen und eintragen

lgdt [gdt] ;GDT laden

mov eax, cr0 ;In den Protected Mode schalten,
or eax, 1 ;indem Bit 0 des CR0 Registers auf 1
mov cr0, eax ;gesetzt wird

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


[BITS 32] ;32 Bit Code erstellen

PMODE:
mov WORD [CODE_Desc+2], 0 ;Code Segmentstartaddresse auf 0 setzen
mov WORD [DATA_Desc+2], 0 ;Daten Segmentstartadresse auf 0 setzen
mov BYTE [CODE_Desc+4], 0 ;Code Segmentstartaddresse auf 0 setzen
mov BYTE [DATA_Desc+4], 0 ;Daten Segmentstartadresse auf 0 setzen

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
mov eax, 0 ;FS und GS mit Null-Deskriptor laden
mov fs, ax
mov gs, ax
mov esp, 0x1FFFFF ;Stack auf unterhalb der 2 MB Grenze setzen

jmp 0x8:0x10000 + PMODE2 ;Sprung in das "neue" Codesegment

PMODE2:
jmp END ;Zum Ende Springen

times 512-($-$$) db 0; ;Da der Linker sich nicht mit ungeraden
;Dateigrößen verträgt, wird diese Datei auf 512
;gepaddet.

END:



kernel32.bin:
[Bits 32]
extern _main
global start
global _EnableA20Gate

start:

call _main

STOP:
jmp STOP


ckernel.c:

int main()
{
char *Text = "Welcome to Protected Mode";  
char *VideoMem = (char*)0xA8000;  
 
while(*Text)  
{  
*VideoMem = *Text;  
*VideoMem++;  
*VideoMem = 7;  
*VideoMem++;  
*Text++;  
}  

return(0);
}


Meine link.txt falls hier ein Fehler wäre:

OUTPUT_FORMAT("binary")
INPUT(kernel32.obj ckernel.obj)
ENTRY(start)
SECTIONS
{
  .text  0x200 : {
    code = .; _code = .; __code = .;
    *(.text)
    . = ALIGN(1);
  }
  .data  : {
    data = .; _data = .; __data = .;
    *(.data)
    . = ALIGN(1);
  }
  .bss  :
  {
    bss = .; _bss = .; __bss = .;
    *(.bss)
    . = ALIGN(1);
  }
  end = .; _end = .; __end = .;
}


Vielen Dank im voraus

N43

  • Beiträge: 8
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 05. December 2005, 22:32 »
Hallo,

muss es im Linker-Script nicht .text 0x10200 : {heißen?


N43

najjannaj

  • Beiträge: 75
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 06. December 2005, 09:45 »
Zitat
copy bootloader.bin+kernel16.bin+c32kernel.bin os.img (DOS kopieren)



das muss aber wie folgt lauten:


copy /B bootloader.bin+kernel16.bin+c32kernel.bin os.img


Das "/B" ist extrem wichtig!
Gruß
najjannaj

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 06. December 2005, 12:25 »
Was bewirkt denn ein /B ???

DarkThing

  • Beiträge: 652
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 06. December 2005, 14:47 »
Der /B Parameter sagt dem Befehl, dass es sich um Binär-Dateien handelt. Wenn er nicht mit angegeben wird, können nur Text-Files zusammenkopiert werden, da beim ersten nicht brauchbaren Zeichen abgebrochen wird.

najjannaj

  • Beiträge: 75
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 06. December 2005, 14:49 »
Richtig!

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 06. December 2005, 18:12 »
Bei mir gehts auch ohne ????

najjannaj

  • Beiträge: 75
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 09. December 2005, 23:00 »
das sollte aber eigentlich nicht! Wie kannst du sicher sein das es auch ohne geht?

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 10. December 2005, 08:46 »
Ja also, wenn mein Kernel geladen wird, dann kann ich ziemlich sicher sein, dass es geht. Oder nicht ? Und dass der Kernel gladen wird, bin ich mir auch sicher, weil ich dort eine Textausgabe habe.

najjannaj

  • Beiträge: 75
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 11. December 2005, 22:03 »
mh.. seltsam, naja windows eben ^^

 

Einloggen