Eigenes OS?


  • Mod

    @+gjm+: hast Du die Trennung bereits praktisch durchgeführt?

    Ich habe mal versuchsweise getrennt, stürzt aber noch beim Kernel laden ab.

    Ansonsten müsste ich nochmal step-by-step versuchsweise den Code in kleineren Häppchen von kernel.asm nach boot.asm schleppen.
    Dann könnte man nämlich mal coff testen.

    Nachfolgender Code klappt (s.u.).


  • Mod

    Einen Fehler habe ich step-by-step gefunden:

    cli               ; clear interrupts
        lgdt [gdtr]       ; load GDT via GDTR (defined in file "gtd.inc")	
        jmp 0x8:PM        ; http://www.nasm.us/doc/nasmdo10.html#section-10.1
    

    muss im 16-bit-Teil stehen.

    Das macht mir noch ein Problem. So sieht es momentan aus (läuft!):

    boot.asm
    ..

    kernel.asm
    ..

    Frage: wie werde ich den 16 bit Teil in kernel.asm noch los? Ich springe ja vom bootloader nach 0x8000 (Kernelstart).



  • Erhard Henkes schrieb:

    Frage: wie werde ich den 16 bit Teil in kernel.asm noch los? Ich springe ja vom bootloader nach 0x8000 (Kernelstart).

    Ganz einfach: Im Bootloader in den Protected Mode schalten (lgdt und cr0 laden), und dann mit jmp 0x08:0x8000 in den Kernel springen (d.h. im Bootloader ist auch kein 32 Bit Teil). Im Kernel kannst du dann direkt mit 32 Bit Code anfangen, und musst die Segmentregister erstmal laden. Danach solltest du dann nochmal eine GDT im Kernel laden, falls der Bootloader irgendwann überschrieben wird.



  • Der boot.asm muß somit nur folgendes hinzugefügt werden:

    (...)
    .A20_done: 
    
     cli
     lgdt [gdtr]
    
     mov eax, cr0
     or  eax, 1
     mov cr0, eax
    
    ; jmp 0x8000
     jmp 0x8:0x8000    ; Ist zwar ein 16-bit-FAR-Jmp, allerdings
                       ; wird hier CS mit "index" 8 der GDT geladen (da in PM).
                       ; Deshalb wird der Code ab Sprungziel von der CPU
                       ; als 'BITS 32' interpretiert (s. CODE_Desc in der gdt.inc).
    (...)
    %include 'gdt.inc' ; <- Achtung : die gdt.inc ist nun hier und nicht mehr in der kernel.asm.
    
     times 510-($-$$) hlt 
     db 0x55 
     db 0xAA
    

    Nun sollte nur noch in der boot.asm "BITS 16"-Code sein. 🙂


  • Mod

    Danke! Hat gut funktioniert. Der boot sector ist immer noch halb leer, hat also noch Luft für notwendige Ergänzungen. 🙂

    kernel.asm stellt sich nun wie folgt dar (ich lade GDT dort auf Anraten nochmals, ist das so im Code richtig umgesetzt?):

    [Bits 32]
    [global KernelStart]
    KernelStart:
        mov    ax, 0x10
        mov    ds, ax        ; data descriptor --> data, stack and extra segment
        mov    ss, ax           
        mov    es, ax
        xor    eax, eax      ; null desriptor --> FS and GS
        mov    fs, ax
        mov    gs, ax
        mov    esp, 0x200000 ; set stack below 2 MB limit
    
        lgdt [gdtr]          ; load GDT via GDTR (defined in file "gtd.inc")	
    
    [extern _main]           ; entry point in ckernel.c
        call _main           ; ->-> C-Kernel
        jmp $
    
    ;;;;;;;;;;;;
    ; Includes ;
    ;;;;;;;;;;;;
    
        %include "gdt.inc"
    

    Die 16/32-Bit-Trennung ist damit gelungen, endlich. Ein kleiner Meilenstein. 🙂

    Nun geht auch folgendes:

    nasmw -O32 -f bin boot.asm -o boot.bin            
    nasmw -O32 -f coff kernel.asm -o kernel.o
    

    Aber hier gibt es noch ein kleines Problem, auch noch mit KernelStart:

    C:\DJGPP\bin/ld.exe: warning: cannot find entry symbol KernelStart; defaulting to 00008000 <--- Wieso dies?
    ckernel.o(.text+0x1f8):ckernel.c: undefined reference to \_file\_data_end' ckernel.o(.text+0x1fd):ckernel.c: undefined reference to_file_data_start'
    ckernel.o(.text+0x215):ckernel.c: undefined reference to \_file\_data_end' ckernel.o(.text+0x21a):ckernel.c: undefined reference to_file_data_start'
    ckernel.o(.text+0x220):ckernel.c: undefined reference to \_file\_data_start' gdt.o(.text+0xf6):gdt.c: undefined reference to_gdt_flush'
    gdt.o(.text+0xfb):gdt.c: undefined reference to \_tss\_flush' idt.o(.text+0x70):idt.c: undefined reference to_idt_flush'
    isrs.o(.text+0xe):isrs.c: undefined reference to _isr0' isrs.o(.text+0x21):isrs.c: undefined reference to_isr1'
    ...
    isrs.o(.text+0x29e):isrs.c: undefined reference to _isr127' irq.o(.text+0xc5):irq.c: undefined reference to_irq0'
    ...
    irq.o(.text+0x1f7):irq.c: undefined reference to _irq15' paging.o(.text+0x522):paging.c: undefined reference to_copy_page_physical'
    task.o(.text+0x23b):task.c: undefined reference to \_irq\_tail' task.o(.text+0x3c1):task.c: undefined reference to_irq_tail'
    task.o(.text+0x7f2):task.c: undefined reference to `_read_eip'
    make.exe: *** [all] Error 1

    Ich möchte die Syntax mit dem führenden Unterstrich in C behalten. Tipp?



  • ich lade GDT dort auf Anraten nochmals, ...

    😕 Das macht hier keinen Sinn weil gelten würde : "alte GDT == neue GDT". Ausserdem müssten dann die Segmentregister erst wieder mit den Deskriptoren der "neuen" GDT initialisiert werden bevor sie "Wirkung" zeigen.

    C:\DJGPP\bin/ld.exe: warning: cannot find entry symbol KernelStart; defaulting to 00008000 <--- Wieso dies?

    Das Symbol (Label ?) "KernelStart" ist nirgendwo in der kernel.asm definiert. 🙂


  • Mod

    ich lade GDT dort auf Anraten nochmals, ...
    😕 Das macht hier keinen Sinn weil gelten würde : "alte GDT == neue GDT". Ausserdem müssten dann die Segmentregister erst wieder mit den Deskriptoren der "neuen" GDT initialisiert werden bevor sie "Wirkung" zeigen.

    Also wieder weg. 😉
    Der Bereich unter 08:0x8000 wird später nicht beschrieben.

    Das Symbol (Label ?) "KernelStart" ist nirgendwo in der kernel.asm definiert. 🙂

    Mit aout war/ist das kein Problem. Braucht coff das anders? Habe da noch nichts gefunden. 😕

    kernel.asm:

    [Bits 32]
    [global KernelStart]
    
    KernelStart:
        mov    ax, 0x10
        mov    ds, ax      ; data descriptor --> data, stack and extra segment
        mov    ss, ax           
        mov    es, ax
        xor    eax, eax    ; null desriptor --> FS and GS
        mov    fs, ax
        mov    gs, ax
        mov    esp, 0x200000 ; set stack below 2 MB limit
    
    [extern _main]         ; entry point in ckernel.c
    	call _main ; ->-> C-Kernel
        jmp $
    

    Das war doch vorher auch nicht anders (da hatte ich nur RealMode).
    Warum ist COFF so seltsam? 🙂



  • Ganz schön zickenhaft der ld. Probiere mal folgendes in der kernel.asm:

    [BITS 32]
    
    section .text ; <- jawohl lieber ld, "KernelStart" ist nun auch in der section .text :) 
    
    [global KernelStart]
    
    KernelStart:
        mov    ax, 0x10
    
    (...)
    

  • Mod

    Hat wirklich geholfen. Warum schluckt der ld das beim aout-Format und motzt erst beim COFF-Format. Merkwürdiges Verhalten. 😃 Man lernt nie aus.

    Hilft auch gegen das Ignorieren der C-Funktionen. 🙂

    Offenbar weiß der Linker beim COFF nicht, wo das Programm anfängt?! 😃

    Damit sind wir zumindest den Schritt aout --> coff gegangen. 👍

    nasmw -O32 -f coff kernel.asm -o kernel.o
    nasmw -O32 -f coff isr.asm -o isr.o
    nasmw -O32 -f coff process.asm -o process.o
    nasmw -O32 -f coff flush.asm -o flush.o
    

    Vielleicht hilft es bei der Benutzung von Linkern höherer Versionen, die bisher mit aout Probleme hatten. 🙂


  • Mod

    Wenn wir schon bei so grausamen Themen sind. Ich wollte mal mein opulentes makefile umstellen auf eine variable Darstellung (vor allem, damit man compiler leicht tauschen kann). Hier klappt aber die Umsetzung c --> o und asm --> coff noch nicht, wenn ich das richtig sehe:

    # Makefile for PrettyOS
    
    SOURCES=	kernel.o		\
    		ckernel.o			\
    		isr.o		        \
    		video.o				\
    		flush.o				\
    		gdt.o				\
    		idt.o				\
    		isrs.o				\
    		irq.o				\
    		util.o				\
    		math.o				\
    		timer.o				\
    		keyboard.o			\
    		process.o			\
    		ordered_array.o		\
    		paging.o			\
    		kheap.o				\
    		descriptor_tables.o	\
    		task.o				\
    		fs.o				\
    		initrd.o			\
    		syscall.o
    
    CFLAGS=	-Wall		\
    		-O          
    
    LDFLAGS= -T kernel.ld -Map kernel.map
    ASFLAGS= -fcoff
    
    CC=gcc
    NASM=nasmw
    AS=as
    
    all:
    	nasmw      -f bin file_data.asm -o file_data.dat
    	nasmw -O32 -f bin boot.asm -o boot.bin            
    	make -s link
    	make -s image	
    
    link:
    	ld $(LDFLAGS) -o ckernel.bin $(SOURCES)
    
    image:
    	cmd /c copy /b boot.bin + ckernel.bin MyOS    
    	cmd /c rename MyOS MyOS.bin
    	del MyOS
    
    	partcopy MyOS.bin 0 7000 -f0	
    
    .s.o:
    	$(NASM) $(ASFLAGS) $<
    
    .c.o:
    	$(CC) -c $(CFLAGS) -o $@ $<
    
    .a.o:
    	$(AS) $(ASFLAGS) -o $<
    

    G:\OSDev\Test\49>make
    nasmw -f bin file_data.asm -o file_data.dat
    nasmw -O32 -f bin boot.asm -o boot.bin
    make -s link
    C:\DJGPP\bin/ld.exe: cannot open kernel.o: No such file or directory (ENOENT)
    make.exe[1]: *** [link] Error 1
    make.exe: *** [all] Error 2

    Offensichtlich baut er keine xxx.o aus den xxx.c. und kein coff aus asm. 🙄

    Wo ist der Hauptfehler? Baue so was sonst nie selbst.



  • Kann ich nicht folgen. Eine "kernel.o" existiert doch, generiert via

    nasmw -O32 -f coff kernel.asm -o kernel.o
    

    ?


  • Mod

    nasmw -O32 -f coff kernel.asm -o kernel.o

    Nein ich wollte das aktuelle makefile komplett durch dieses ersetzen.

    habe folgendes noch geändert:

    .asm.o:
    	$(NASM) $(ASFLAGS) $<
    

    Da stand vorher s.o.:

    G:\OSDev\Test\49>make
    nasmw -f bin file_data.asm -o file_data.dat
    nasmw -O32 -f bin boot.asm -o boot.bin
    make -s link
    C:\DJGPP\bin/ld.exe: cannot open ckernel.o: No such file or directory (ENOENT)
    make.exe[1]: *** [link] Error 1
    make.exe: *** [all] Error 2

    Ich sehe aber kein kernel.o im Verzeichnis.

    Wenn ich das -s(ilent) weg nehme:

    G:\OSDev\Test\49>make
    nasmw -f bin file_data.asm -o file_data.dat
    nasmw -O32 -f bin boot.asm -o boot.bin
    make link
    make.exe[1]: Entering directory g:/OSDev/Test/49' ld -T kernel.ld -Map kernel.map -o ckernel.bin kernel.o ckernel.o isr.o video.o flush.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o process.o orde red\_array.o paging.o kheap.o descriptor\_tables.o task.o fs.o initrd.o syscall.o C:\\DJGPP\\bin/ld.exe: cannot open ckernel.o: No such file or directory (ENOENT) make.exe[1]: *** [link] Error 1 make.exe[1]: Leaving directoryg:/OSDev/Test/49'
    make.exe: *** [all] Error 2



  • +gjm+ schrieb:

    ich lade GDT dort auf Anraten nochmals, ...

    😕 Das macht hier keinen Sinn weil gelten würde : "alte GDT == neue GDT". Ausserdem müssten dann die Segmentregister erst wieder mit den Deskriptoren der "neuen" GDT initialisiert werden bevor sie "Wirkung" zeigen.

    Der Zweck ist wie gesagt Problemen vorzubeugen, wenn der Bootsektor überschrieben wird, weil die GDT beim LGDT nicht in die CPU geladen wird. Wenn die GDT, die sich außerhalb des Kernels befindet, überschrieben wird, weil die Speicherverwaltung den Bereich, wo der Bootsektor war, als freien Speicher empfinden, knallt es beim Nachladen der Segmentregister.

    Das Laden der Segmentregister ist nicht zwingend notwendig, sofern alte und neue GDT den selben Inhalt haben. (Und wenn die Segmentregister nicht aus Versehen mit alten Selektoren geladen werden, ist es auch kein Problem eine neue GDT anzulegen.)

    Aber wenn Erhard die guten 32 KByte RAM da unten verrotten lassen will, soll mir recht sein. Hat er ja schließlich für bezahlt. ^^

    Erhard Henkes schrieb:

    Ich sehe aber kein kernel.o im Verzeichnis.

    Weil du kein Target abhängig von den $(SOURCES) gemacht hast. Make weiß nicht, dass die Objektdateien vorher gebaut werden müssen, weil du es ihm nicht gesagt hast.


  • Mod

    Ich dachte, dieses

    .c.o:
    	$(CC) -c $(CFLAGS) -o $@ $<
    

    kümmert sich bereits darum. Wenn das nur faul rum hängt, fliegt's raus. 😃
    .c.o sei auch obsolet, habe ich irgendwo gelesen. Dieses $@ $< finde ich auch irgendwie unlesbaren Mist.

    Die sechs Assemblerzeilen schreibe ich nun lieber fix rein, nur mit Variable für Format und Flags.

    TARGET des Link-Vorgangs ist für mich ckernel.bin, oder?

    So wird brav kompiliert, ich kann den Compiler und die Flags zumindest variabel austauschen und verstehe das makefile noch bestens. Das doppelte Aufführen der Dateinamen muss allerdings noch weg, aber unbedingt leserlich und klar nach vollziehbar.

    # Makefile for PrettyOS
    
    ASFLAGS= -O32 -f coff
    
    TARGET= ckernel.bin
    OBJ= kernel.o ckernel.o isr.o video.o flush.o gdt.o	\
    		idt.o isrs.o irq.o util.o math.o timer.o keyboard.o \
    		process.o ordered_array.o paging.o kheap.o descriptor_tables.o \
    		task.o fs.o initrd.o syscall.o
    
    LDFLAGS= -T kernel.ld -Map kernel.map
    LD= ld
    
    CFLAGS=	-Wall -O          
    CC= gcc
    
    all:
    	nasmw      -f bin file_data.asm -o file_data.dat
    	nasmw -O32 -f bin boot.asm -o boot.bin  
    	nasmw $(ASFLAGS) kernel.asm -o kernel.o
    	nasmw $(ASFLAGS) isr.asm -o isr.o
    	nasmw $(ASFLAGS) process.asm -o process.o
    	nasmw $(ASFLAGS) flush.asm -o flush.o
    	make compile
    	make link
    	make image	
    
    compile:	
    	$(CC)  $(CFLAGS)  -c ckernel.c -o ckernel.o    
    	$(CC)  $(CFLAGS)  -c video.c -o video.o -O1
    	$(CC)  $(CFLAGS)  -c math.c -o math.o -O1
    	$(CC)        -O   -c util.c -o util.o -O1
    	$(CC)  $(CFLAGS)  -c gdt.c -o gdt.o
    	$(CC)  $(CFLAGS)  -c idt.c -o idt.o
    	$(CC)  $(CFLAGS)  -c isrs.c -o isrs.o	
    	$(CC)  $(CFLAGS)  -c irq.c -o irq.o
    	$(CC)  $(CFLAGS)  -c timer.c -o timer.o 	
    	$(CC)  $(CFLAGS)  -c keyboard.c -o keyboard.o
    	$(CC)  $(CFLAGS)  -c ordered_array.c -o ordered_array.o
    	$(CC)  $(CFLAGS)  -c paging.c -o paging.o
    	$(CC)  $(CFLAGS)  -c kheap.c -o kheap.o
    	$(CC)  $(CFLAGS)  -c descriptor_tables.c -o descriptor_tables.o
    	$(CC)  $(CFLAGS)  -c task.c -o task.o 
    	$(CC)  $(CFLAGS)  -c fs.c -o fs.o
    	$(CC)  $(CFLAGS)  -c initrd.c -o initrd.o  
    	$(CC)  $(CFLAGS)  -c syscall.c -o syscall.o
    
    link:
    	$(LD) $(LDFLAGS) -o $(TARGET) $(OBJ)
    
    image:
    	cmd /c copy /b boot.bin + ckernel.bin MyOS    
    	del *.coff
    	del *.o
    	del *.bin
    	cmd /c rename MyOS MyOS.bin
    	del MyOS
    
    	partcopy MyOS.bin 0 7000 -f0
    

    Wie kann ich diesen Teil mit "compile:" allgemein ablaufen lassen analog dem Linker-Befehl? Da die o alle aus c kommen, sollte das gehen.

    Sollte man die o (OBJECTS) oder die c (SOURCES, wie unten stehend) auflisten? Ich habe das mit den obj-Dateien bevorzugt, also den Linker-Vorgang in den Mittelpunkt gerückt, weil ja auch obj-Dateien von NASM zu verarbeiten sind.

    Bei makefiles stehe ich immer grundsätzlich auf dem Schlauch, weil jedes Vorbild anders aussieht und die Tutorials absolut nix taugen, weil diese keine klare Linie vorgeben. Vielleicht gibt es auch einfach keine. 😃

    So in etwa findet man es z.B. (Bsp. mit C++, mit diesem obsolet-Stil .cpp.o, den Linker finde ich dort z.B. nicht, Compile- und Link-Vorgang verquickt, irgendwie viel unverständliches Zeugs, die letzte Zeile habe ich ja oben gerade gekillt, weil sie noch nicht gearbeitet hat, lag da nur so rum, ich habe sie aber verstanden trotz wildcards):

    CC=g++
    CFLAGS=-c -Wall
    LDFLAGS=
    SOURCES=main.cpp hello.cpp factorial.cpp
    OBJECTS=$(SOURCES:.cpp=.o)
    EXECUTABLE=hello

    all: $(SOURCES) $(EXECUTABLE)

    $(EXECUTABLE): (OBJECTS)(OBJECTS) (CC) $(LDFLAGS) $(OBJECTS) -o $@

    .cpp.o:
    $(CC) $(CFLAGS) $< -o $@

    Am schlimmsten finde ich so etwas "SOURCES:.cpp=.o" mit diesem Doppelpunkt.
    Vielleicht kann mir da jemand auf die Sprünge helfen. Ich finde es gut, wenn Compile- und Link-Vorgang getrennt dargestellt werden, weil dies bei einem OS wichtig ist.

    So etwas wie
    $(CC) $(CFLAGS) -c $(SOURCES) -o $(OBJECTS)
    wäre gut verständlich. Dann müsste man aber die c-Dateien noch allgemein als Sources angeben. Habe dies probiert, hat aber nicht geklappt. Vielleicht kann jemand meine Idee doch noch zum Laufen bringen:

    # Makefile for PrettyOS

    # Assemble
    ASFLAGS= -O32 -f coff

    # Compile
    SOURCES= ???.c
    CFLAGS= -Wall -O
    CC= gcc

    # Link
    OBJ= kernel.o ckernel.o isr.o video.o flush.o gdt.o \
    idt.o isrs.o irq.o util.o math.o timer.o keyboard.o \
    process.o ordered_array.o paging.o kheap.o descriptor_tables.o \
    task.o fs.o initrd.o syscall.o
    TARGET= ckernel.bin
    LDFLAGS= -T kernel.ld -Map kernel.map
    LD= ld

    all:
    nasmw -f bin file_data.asm -o file_data.dat
    nasmw -O32 -f bin boot.asm -o boot.bin
    nasmw $(ASFLAGS) kernel.asm -o kernel.o
    nasmw $(ASFLAGS) isr.asm -o isr.o
    nasmw $(ASFLAGS) process.asm -o process.o
    nasmw $(ASFLAGS) flush.asm -o flush.o
    make compile
    make link
    make image

    compile:
    ??? #Idee: $(CC) $(CFLAGS) -c $(SOURCES) -o $(OBJECTS)

    link:
    $(LD) $(LDFLAGS) -o $(TARGET) $(OBJ)

    image:
    cmd /c copy /b boot.bin + ckernel.bin MyOS
    del *.o
    del *.bin
    cmd /c rename MyOS MyOS.bin
    partcopy MyOS.bin 0 7000 -f0

    c.o.:
    $(CC) -c $(CFLAGS) -o $@ $<


  • Mod

    Aber wenn Erhard die guten 32 KByte RAM da unten verrotten lassen will, soll mir recht sein. Hat er ja schließlich für bezahlt. ^^

    Ja, aber man muss ja auch andere denken. 🙂 Der Speicher bis 0x00008000 sollte nach dem Boot-Vorgang schon wieder genutzt werden können, aber irgendwo muss das GDT ja dann liegen, z.B. nach dem Kernel-Ende:

    Das gute PrettyOS hat das ja alles schon im C-Kernel eingebaut, wenn ich das richtig sehe, und das wird in main() nach Bildschirmlöschen und Begrüßen umgehend installiert:

    flush.asm (siehe lgdt [...] )
    ..

    Dieses gdt_flush wird mittels gdt_install in main() aufgerufen:
    ..

    int main()
    {
        k_clear_screen();
        printformat("Welcome to PrettyOS ... \n");
        // GDT, IDT, ISRS, IRQ, timer, keyboard, paging, interrupts, multitasking
        gdt_install();
    //...
    }
    

    Ist das so o.k.? Die GDT sitzt dann bei der Adresse &gdt. Ich habe zur Kontrolle ein printformat eingebaut:

    Welcome to PrettyOS ...
    gdt: 0000D480h

    Den Verschwendungsvorwurf kann ich so nicht auf mir sitzen lassen. 😉 😃


  • Mod

    Bezüglich makefile bin ich nun komplett umgeschwenkt und verwende Folgendes:

    SOURCES = kernel.asm $(filter-out file_data.asm boot.asm kernel.asm make_initrd.c,$(wildcard *.asm *.c))
    OBJECTS = $(addsuffix .o,$(basename $(SOURCES)))
    
    ASFLAGSBIN= -O32 -f bin
    ASFLAGSCOFF= -O32 -f coff
    NASM = nasmw
    
    CFLAGS= -Wall -O          
    CC= gcc
    
    LDFLAGS= -T kernel.ld -Map kernel.map
    LD= ld
    
    all: boot.bin ckernel.bin
    	make -s image
    	make -s floppyimage
    
    process.asm: file_data.dat file_data.da1
    
    file_data.dat: file_data.asm
    	$(NASM) $(ASFLAGSBIN) $< -o $@
    
    boot.bin: boot.asm
    	$(NASM) $(ASFLAGSBIN) $< -o $@
    
    %.o: %.asm
    	$(NASM) $(ASFLAGSCOFF) $< -o $@
    
    ckernel.bin: $(OBJECTS)
    	$(LD) $(LDFLAGS) $+ -o $@ 
    
    image:
    	cmd /c copy /b boot.bin + ckernel.bin MyOS    
    	del *.o
    	del *.bin
    	cmd /c rename MyOS MyOS.bin
    
    floppyimage:	
    	partcopy MyOS.bin 0 7000 -f0	
    
    # $<	Erste Abhängigkeit
    # $@	Name des Targets
    # $+	Liste aller Abhängigkeiten
    

    Trotz Verwendung von $<, $+ und $@ finde ich diesen ziel- bzw. abhängigkeitsbezogenen Stil ebenfalls gut nachvollziehbar.
    Ich bin immer wieder verblüfft über die vielfältigen Möglichkeiten, die diese Makefile-Syntax bietet. 😃



  • Von den vielfältigen Möglichkeiten abgesehen, die man in 20 Jahren nicht mal genutzt hat - und die noch vielfältigeren, die man noch gar nicht kennt. 😉
    Und bei den ganzen Tools, die in einem Compilerpaket immer dabei sind, fehlt mir immer noch eines, was komplexe zeilenübergreifende Ersetzungen mit Berücksichtigung von Klammerebenen erlaubt. Reguläre Ausdrücke sind viel zu schwach. Aber das wäre ein anderes Projekt 😉


  • Mod

    Da das Verständnis für das Thema (Virtual) Filesystem/Files (Filesystem-Header, File-Header) wichtig ist, habe ich am Beispiel der RAM Disk manuell (mit dem Hex-Editor, damit man mitdenken und abzählen muss, was man macht) ein viertes File (nämlich genau unser winziges 29-Byte-TEST-Programm) in das Filesystem "eingeklinkt". Die Daten werden via Filesystem (Zahl 4 im Filesystem-Header zeigt 4 Files an, File-Header zeigt Name, Offset und Länge an, allerdings nicht Filetyp oder anderes, alos noch sehr primitiv, aber es geht ja noch ums Prinzip) gefunden, in ein lokales Array auf dem Stack gelesen, zur Sicherung an eine neue Stelle in ein globales Array (address_TEST in der Sektion bss; da überlege ich noch, was eigentlich der beste Platz ist) transferiert, im Prozess 'test' als Funktion aufgerufen und ausgeführt.

    Damit wurde nun genau genommen ein (zugegebenermaßen kleines) Programm "von Disk geladen" und in Multitasking "ausgeführt". Das Grundprinzip funktioniert aber auch im User-Bereich mit Datenbereich, Stack, User-Lib etc. gleich.

    http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId216641
    http://www.henkessoft.de/OS_Dev/Downloads/20090621_36x_load_file_TEST.zip


  • Mod

    Das Thema user mode und syscalls habe ich hier beschrieben:
    http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId338709

    Ich verzichte bei Systemaufrufen auf einen Task-Wechsel und verwende den fault_handler (exceptions) und syscall_handler zum Aufruf der gewünschten Kernel-Funktion. Die Assemblerroutine kümmert sich um den korrekten Kontextwechsel von Ring 3 nach Ring 0 und zurück.
    http://www.henkessoft.de/OS_Dev/Bilder/syscall.PNG


  • Mod

    Ein ganz wichtiger Punkt ist nun der Einsatz eines Cross-Compilers/-Linkers, der vor allem auch das ELF-Format erlaubt, das man für andere Hobby-OS und später für User-Programme benötigt. Man benötigt allerdings auch ein brauchbares make-Tool, das alle Anforderungen erfüllt, findet man nun alles hier, natürlich alles einfach und übersichtlich nachzuvollziehen:
    http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId42018

    Wichtig ist, dass man nun aus Assembler-Quellcode leicht elf-object- und mittels des linkers der cross-compiler-tools daraus elf-executable-Dateien herstellen kann. Es ist nun die nächste Aufgabe diese elf-Programme seitens Pretty-OS im "user space" zum Laufen zu bringen. Dann kann man zur Zeit mittels incbin und Einbinden in die RAM Disk Programme im VFS "loadable" zur Verfügung stellen.
    Dort sollte z.B. später die Programme

    init,
    vielleicht noch einge Treiber
    und eine shell

    stehen. Das wäre dann eine interessante Aufgabe für das Assembler-Forum, solche kleinen Programme in Assembler zu erstellen.

    nasm(w) -felf -o file.o file.asm
    i586-elf-ld -T user.ld -nostdinc -o program.elf file.o

    user.ld:

    ENTRY(_start)
    OUTPUT_FORMAT(elf32-i386)
    
    SECTIONS
    {
        . = 0x400100;
    
        .text :
        {
          *(.text*)
        }
        .data :
        {
          *(.data*)
          *(.rodata*)
        }
        .bss :
        {
          *(.bss*)
        }
    }
    

    Setzt man kein Linkerscript ein

    i586-elf-ld -nostdinc -o program.elf file.o

    so ergibt sich die default Adresse: 0x08048000 + program_offset
    http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId95189

    Kann jemand erklären, warum gerade diese Adresse verwendet wird?

    Mit Einsatz der Cross-Tools ist das Thema Linux und GRUB damit vorerst vom Tisch, wie gewünscht. 🙂

    Nächstes kapitel wird richtiger user mode, denn bisher wurde der kernel als user mode / read-only eingesetzt (ein Erbe von JM's Tut.)


Anmelden zum Antworten