1. A breve aggiorneremo la piattaforma di Reboot per risolvere alcuni problemi con i plug-in, quindi chiediamo ancora un po' di pazienza, Lo staff di Reboot

[Guida] OSDev 2.0 - Come creare un sistema operativo in C++ - Bootloader, GDT e primo kernel

Discussione in 'Software' iniziata da iostream, 17 Ago 2017.

  1. iostream

    iostream Phoenix Wright

    Iscritto:
    13 Ago 2016
    Messaggi:
    4.895
    Like ricevuti:
    1.619
    [​IMG]
    Salve a tutti, in questa serie di guide vi mostrerò come si crea un semplice OS da zero. Questa è la prima guida che mostrerà come avviare l'OS da QEMU e caricare un semplice kernel dal bootloader scritto in assembly.

    Consigliata la lettura dell'introduzione


    Conoscenze richieste

    Fare OSDev è una sfida molto difficile. Gli OS sono i progetti con il più alto rischio di abbandono. Le conoscenze minime richieste sono:
    • Essere familiari con l'informatica e i sistemi di numerazione esadecimale e binario
    • Sapere l'inglese. La maggior parte delle risorse sarà in inglese. Il principale sito a cui riferirsi è osdev.org
    • Conoscere il linguaggio C++ (di conseguenza anche il C) e l'Assembly
    • Conoscere la piattaforma su cui state lavorando (x86 in questo caso)
    • Avere esperienze con la programmazione, i compilatori e soprattutto esperienze con UNIX
    Strumenti richiesti

    • Servirà il compilatore i686-elf-gcc.
      • Se non volete compilare il compilatore scaricatelo da qui
      • Altrimenti seguite la sezione "GCC CrossCompiler" della guida osdev 1.0
    • L'assembler NASM
    • GRUB (su Linux) o ISO9660Generator (su Windows)
    • Un cervello
    • QEMU e/o un PC test
    Il bootloader e la GDT

    Il bootloader verrà caricato da GRUB o ISOLinux (che sono lo stage 1) e dovrà fare queste operazioni:
    • Dichiarare la struttura multiboot per farsi trovare dallo stage 1
    • Creare lo stack e caricarlo nel registro ESP
    • Creare una GDT e caricarla
    • Caricare il kernel in C++
    La struttura multiboot è così:
    • Header | 0x1BADB002
    • Flags | 0x00000003
    • Checksum | 0xE4524FFB | -(Header + Flags)

    Ecco il sorgente del loader (lo metteremo nel file loader.asm):
    Codice:
    [BITS 32] ; Dì a NASM che stiamo scrivendo codice a 32 bit
    
    ; Dichiariamo le constanti per il multiboot
    MB_HEADER equ 0x1BADB002
    MB_FLAGS equ 0x00000003
    MB_CHECKSUM equ -(MB_HEADER + MB_FLAGS)
    
    ; Dichiara la vera intestazione multiboot
    section .multiboot
    align 4  ; L'intestazione deve essere 4byte-aligned
        dd MB_HEADER
        dd MB_FLAGS
        dd MB_CHECKSUM
    
    ; Ora crea lo spazio per lo stack
    section .bss
    align 4
    stack_bot:                        , Parte inferiore dello stack (fine di questo)
    resb 16384                      ; Lascia 16kB di spazio
    stack_top:                        ; Parte superiore dello stack (inizio di questo)
    
    ; Ora il codice vero e proprio
    section .text
    global _start:function (_start.end - _start)
    _start:
        ; Imposta lo stack
        mov esp, stack_top
    
        ; Carica la GDT
        call LoadGDT
    
         ; Chiama il kernel dal C++
         extern main
         call main
    
         ;  Se non ho più niente da fare vado in loop
         cli
    .hang:
         hlt
         jmp .hang
    
    .end:
    
    ; Dichiara la tabella GDT
    GDTC:
      db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
      db 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00
      db 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
      db 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFA, 0xCF, 0x00
      db 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xF2, 0xCF, 0x00
    
    ; Ora dichiara il puntatore alla GDT
    GDTP db 0x27, 0x00, 0x00, 0x00, 0x00
    
    LoadGDT:
       mov dword [GDTP+ 2], GDTC   ; Carica l'indirizzo della GDT nel suo puntatore
       mov dword eax, GDTP               ; Carico il puntatore in EAX
       lgdt [eax]                                     ; Carico la GDT
    FlushDS:                                        ; Ricarica i segmenti dati
       mov dword eax, 0x10                  ; Selettore dati
       mov word ds, eax
       mov word es, eax
       mov word fs, eax
       mov word gs, eax
       mov word ss, eax
       ; Forza il ricaricamento del segmento codice
       jmp 0x08:FlushCS
    FlushCS:
       ret                                                ; Ridai il controllo al loader
    La GDT è una tabella che dice come gestire i registri segmento (divisi in data segment e code segment) le cui voci sono composte dai seguenti bit:

    Bit 0-15Bit 16-31Bit 32-39Bit 40-4748-51Bit 52-55Bit 56-63
    Primi 16 bit del limitePrimi 16 bit della base8 bit dopo i primi 16 bit della baseAccess byteBit 17-20 del limiteFlagsUltimi 8 bit della base
    Invece il puntatore è fatto così:

    Bit 0-15Bit 16-47
    Dimensione della GDT in byte - 1Indirizzo a 32 bit della GDT

    Per maggiori informazioni sulla GDT andare qui

    Il kernel

    Il nostro kernel sarà fatto così:
    Codice:
    int main() {
        return 0xC1A0;
    }
    E' solo un piccolo programma che ritorna il valore 0xC1A0, dove viene ritornato il valore? Nel registro EAX.

    Il linker

    Per creare un eseguibile caricabile da GRUB dovremo creare un file linker (che rimarrà così per quasi tutto il resto della guida):
    Codice:
    ENTRY(_start)
    
    SECTIONS
    {
    . = 1M;
    
    .text BLOCK(4K) : ALIGN(4K)
    {
    *(.multiboot)
    *(.text)
    }
    
    .rodata BLOCK(4K) : ALIGN(4K)
    {
    *(.rodata)
    }
    
    .data BLOCK(4K) : ALIGN(4K)
    {
    *(.data)
    }
    
    .bss BLOCK(4K) : ALIGN(4K)
    {
    *(COMMON)
    *(.bss)
    }
    
    }
    Compilazione

    Creeremo un piccolo Makefile che compila i file:
    Codice:
    CX=i686-elf-g++
    CXFLAGS=-ffreestanding -O2 -Wall -Wextra -fno-exceptions -fno-rtti
    
    AS=nasm
    ASFLAGS=-f elf32
    
    LD=i686-elf-gcc
    LDFLAGS=-T linker.ld -o myos.bin -ffreestanding -O2 -nostdlib -lgcc
    LDFILES=boot.o kernel.o
    
    all: link
    
    boot:
        $(AS) $(ASFLAGS) boot.asm - o boot.o
    
    kernel:
        $(CX) -c kernel.cpp -o kernel.o $(CXFLAGS)
    
    link: boot kernel
        $(LD) $(LDFLAGS) $(LDFILES)
    
    
    Compilate il file eseguendo il comando "make all"

    Funziona?

    Questo OS non è bootable da hardware reale, allora come posso verificare il suo funzionamento? Semplice con QEMU, basta lanciare qemu eseguendo:
    Codice:
    qemu-system-i386 -kernel kernel.bin
    Non verrà scritto niente, ma se andate su View :arrowright: CompatMonitor0 e digitate il comando "print $eax" otterrete un output simile a questo:
    Codice:
    EAX = 0xC1A0
    Conclusioni


    Per questo tutorial è tutto. Il nostro OS non è ancora bootabile da hardware reale, nel prossimo tutorial vedremo come si fa a stampare dei messaggi sullo schermo, come si usa la memoria virtuale e soprattutto come si crea una ISO con Grub e con ISO9660Gen

    Seconda parte disponibile!
     
    #1
    Ultima modifica: 18 Ago 2017
    A lokiu.ox, zoomx, IlVampirelloXY e 2 altri utenti piace questo elemento.
  • MODD3R

    MODD3R Ospite

    L'aspettavo proprio!
     
    #2
  • MattVPP

    MattVPP Livello 11

    Iscritto:
    12 Feb 2016
    Messaggi:
    341
    Like ricevuti:
    184
    @iostream piccolo accorgimento, hai dimenticato il link del compilatore :wink:
     
    #3
    A iostream piace questo elemento.
  • iostream

    iostream Phoenix Wright

    Iscritto:
    13 Ago 2016
    Messaggi:
    4.895
    Like ricevuti:
    1.619
    Fixato e migliorata la parte sul bootloader e sulla GDT. Aggiunto anche la definizione del puntatore alla GDT
     
    #4
    A MODD3R piace questo elemento.
  • Informatico2

    Informatico2 Livello 1

    Iscritto:
    19 Gen 2018
    Messaggi:
    6
    Like ricevuti:
    0
    ma perché dopo la creazione del file loader.asm, non si capisce più nulla?,
    si può usare questa guida per un processore basato su x64?
     
    #5
  • iostream

    iostream Phoenix Wright

    Iscritto:
    13 Ago 2016
    Messaggi:
    4.895
    Like ricevuti:
    1.619
    Se non capisci nulla non fa per te, il codice è chiaro e commentato. Il codice può essere eseguito su pc x64 con bios, anche se viene compilato per x86.

    PS: la serie è stata sospesa per mancanza di tempo
     
    #6
  • Informatico2

    Informatico2 Livello 1

    Iscritto:
    19 Gen 2018
    Messaggi:
    6
    Like ricevuti:
    0
    Intendevo dove e come bisogna salvare i file
     
    #7
  • iostream

    iostream Phoenix Wright

    Iscritto:
    13 Ago 2016
    Messaggi:
    4.895
    Like ricevuti:
    1.619
    Linkare = linker.ld
    Kernel = kernel.c
    Makefile=Makefile

    Ciò dimostra che non hai le conoscenze, perciò fai copia incolla senza capire un tubo
     
    #8
  • Informatico2

    Informatico2 Livello 1

    Iscritto:
    19 Gen 2018
    Messaggi:
    6
    Like ricevuti:
    0
    Io capisco è solo che non so come mettere insieme il tutto, se mi consiglia una guida che spiega le basi per la creazione di un SO la ringrazio
     
    #9
  • iostream

    iostream Phoenix Wright

    Iscritto:
    13 Ago 2016
    Messaggi:
    4.895
    Like ricevuti:
    1.619
    Studiare è la migliore base
    Poi leggere anche
     
    #10
  • Informatico2

    Informatico2 Livello 1

    Iscritto:
    19 Gen 2018
    Messaggi:
    6
    Like ricevuti:
    0
    Se mi dice dove studiare...
     
    #11
  • iostream

    iostream Phoenix Wright

    Iscritto:
    13 Ago 2016
    Messaggi:
    4.895
    Like ricevuti:
    1.619
    Dai libri, non crede? La prima parte della guida spiega le conoscenze necessarie
     
    #12
  • Informatico2

    Informatico2 Livello 1

    Iscritto:
    19 Gen 2018
    Messaggi:
    6
    Like ricevuti:
    0
  • iostream

    iostream Phoenix Wright

    Iscritto:
    13 Ago 2016
    Messaggi:
    4.895
    Like ricevuti:
    1.619
    Inizia con uno sul c, tipo della O'Reilly, poi passa ai manualoni assembly della intel
     
    #14
  • Informatico2

    Informatico2 Livello 1

    Iscritto:
    19 Gen 2018
    Messaggi:
    6
    Like ricevuti:
    0
    C e assembly li conosco e il so che non conosco
     
    #15
  • Sto caricando...

    Condividi questa Pagina