Autor Thema: Eigener Bootloader?!  (Gelesen 13736 mal)

CubeCoder

  • Beiträge: 4
    • Profil anzeigen
Gespeichert
« am: 08. June 2019, 19:01 »
Hallo lowlevel-Community,
ich bin neu hier und stürme gleich mit einem komischen Thema für einen "Anfänger" herein :D.
Aber ich will nur mal Meinungen einholen und vllt. auch Anfänge und Hilfen. Wie ihr wahrscheinlich schon im Titel gesehen habt möchte ich gerne meinen eigenen Bootloader schreiben...
Zu aller erst ja ich weiß mann sollte eher zu grub oder anderen vorgefertigten Bootloadern greifen (so steht es ja uch in der Wiki auf dieser Seite) aber ich will auch die Funktionsweise von Bootloadern verstehen und das kann ich am besten wenn ich gleich sehe welche Zeile welchen befehl, etc. ausführt.
Und ich will auch keines falls einen riesigen programmieren sondern er soll lediglich den Kernel laden...
Ich habe schon bisschen rum getüftelt aber nichts gescheites hinbekommen.
Deswegen wäre ich sehr dankbar wenn mir hier jmd weiterhilft sofern es nicht viel zu schwer ist einen Bootloader zu coden der den Kernel lädt.
Eigentlich ist das auch der Knackpunkt ich weiß nicht so genau wie man den Kernel lädt...
Für aller art Antworten wäre ich dankbar!

Markus

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 08. June 2019, 23:12 »
Hallo,

der "klassische" Bootloader liegt im ersten Sektor des Bootlaufwerkes und wird von einem BIOS an die Adresse 0x7C00 geladen und dort ausgeführt (d.h. CS:IP zeigt auf die richtige Adresse, aber die genauen Werte sind nicht bekannt). Außerdem steht in DL das Bootlaufwerk (0x00 für Diskette, 0x80 für Festplatte). Dein Bootloader muss nun den Kernel auf dem Bootlaufwerk finden können, in den Speicher laden können und aufrufen können. Ich gehe mal von einer Diskette aus, da ist das alles einfacher.

Schritt 1: "Kernel finden". Entweder, du hast ein Dateisystem (z.B. FAT12) auf deiner Bootdiskette, dann muss dein Bootloader dieses Dateisystem soweit lesen können, um den Kernel zu finden. Oder du klebst den Kernel einfach hinten an den Bootsektor ran, dann weißt du, wo er anfängt. Du musst außerdem wissen, wie groß der Kernel ist.

Schritt 2: "Kernel laden". Das BIOS stellt dir den "int 13h" zur Verfügung, mit dem du Sektoren von den Laufwerken lesen kannst. Details gibt es z.B. bei RBIL. In Schritt 1 hast du rausgefunden, welche Sektoren du lesen musst, also musst du nur noch entscheiden, wo die Daten im Speicher hinsollen (unterhalb von 640 KB!) und die passende Anzahl der Sektoren lesen. Für Disketten musst du noch von LBA nach CHS umrechnen, oder du hast deine Sektoradressen direkt als CHS.

Schritt 3: "Kernel anspringen". In Schritt 2 hast du festgelegt, wo dein Kernel hingeladen wurde. Jetzt musst du noch wissen, wo der Einsprungpunkt ist (im Zweifelsfall das erste Byte, aber das hängt vom Kernel ab!), also machst du einfach einen FAR CALL an diese Adresse. Die genauen Werte für CS:IP legst du diesmal selbst fest.

Es gibt genug Bootloader, die du dir anschauen kannst. Vielleicht nicht gerade GRUB, aber der Bootcode von FreeDOS ist halbwegs gut kommentiert.

Hoffe, es nützt.

Gruß,
Svenska

CubeCoder

  • Beiträge: 4
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 09. June 2019, 12:33 »
Hallo,

erstaml danke Svenska! Ich habe mir jz mal das FAT12 Dateisystem in der Wiki und den Bootcode von FreeDOS angeschaut komme aber nicht so recht weiter...
Hier ist mein anfang weiß aber nicht ob das jetzt so richtig ist:
Code: (assembly) [Auswählen]
segment .text
%define BASE 0x7C00

org BASE

Entry:
jmp short _start
nop

%define    OSName         'MSWIN4.1'
%define    BytesPerSec    512
%define    SecPerClus     1
%define    RsvdSecCnt     1
%define    NumFATs        2
%define    RootEntCnt     224
%define    TotSec         2880
%define    MediaType      0xF0
%define    FATSize        9
%define    SecPerTrack    18
%define    NumHeads       2
%define    HiddenSec      0
%define    TotSec32       0
%define    DrvNum         0x00
%define    Reserved       0
%define    VolumeID       0
%define    FileSysType    "FAT12 "

dw 0xAA55

;%define Sektoren TotSec - RsvdSecCnt - (NumFATs * FATSize) - RootDirSectors
;%define Cluster  Sektoren/SecPerClus

_start:
cli
cld
xor ax, ax
mov ds, ax
mov bp, BASE

mov dl, 0x00
Außerdem verstehe ich nicht so recht das mit der FAT-Tabelle muss man jetzt alle 2880 Sektoren mit einer anderen 12 BIT zahl bestücken?

Markus
« Letzte Änderung: 09. June 2019, 12:44 von CubeCoder »

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 09. June 2019, 14:15 »
Hallo,

du solltest mit einem FAR JMP anfangen, denn der setzt CS:IP auf bekannte Werte (z.B. CS=0x07C0, IP=0x0000), und dann auch DS=ES auf die gleichen Werte wie CS setzen. Das "dw 0xAA55" muss an das Ende des Bootsektors (also die Bytes 510/511), nicht irgendwo in die Mitte. Und du solltest DL nicht überschreiben, sondern irgendwo sichern (das BIOS füllt da den richtigen Wert rein).

Was den FAT-Sektor angeht, kann ich dir spontan nicht helfen. Damit habe ich mich nie groß befasst. :-)
Am einfachsten, du formatierst eine normale Diskette und popelst die Metadaten auseinander.

Gruß,
Svenska

CubeCoder

  • Beiträge: 4
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 09. June 2019, 21:43 »
Okay ich habe es jetzt hinbekommen

hier der code:

Code: (asm) [Auswählen]
org 0x7C00

section .text

mov [bootdrive], dl

call load_kernel

jmp 0x07C0:0x0000

load_kernel:
mov dl, [bootdrive]
xor ax, ax
int 0x13
jc load_kernel

load_kernel1:
mov ax, 0x1000
mov es, ax
xor bx, bx

mov dl, [bootdrive]
mov al, 10
mov ch, 0
mov cl, 2
mov dh, 0
mov ah, 2
int 0x13
jc load_kernel1

ret

section .data

bootdrive db 0

times 510-($-$$) hlt
dw 0xAA55

und dann danke für die Hilfe!

Markus

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 09. June 2019, 22:10 »
Der Code sieht falsch aus, zumindest wenn er einen FAT-Bootsektor beschreiben soll.

Ungetestet und aus dem Handgelenk geschüttelt:
org 7C00h
section .text

jmp near start ; springe über BPB (bios parameter block)

.db "xxxxxxxx" ; oem name
; die restlichen fat-metadaten (BPB)

start:
    jmp far 0000h:start2 ; setze CS:IP

start2:
    mov ax, cs ; setze CS=DS=ES
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0FFFEh ; setze stack an ca. 64 KB

    mov [bootdrive], dl ; speichere bootlaufwerk

    ; hier geht der lade-code los
    ; also kernel suchen, laden und ausführen


section .data
  bootdrive db 1

times 510-($-$$) nop
dw 0xAA55
« Letzte Änderung: 09. June 2019, 22:12 von Svenska »

CubeCoder

  • Beiträge: 4
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 10. June 2019, 10:37 »
Okay...
naja jetzt funktioniert er erstmal werde den dann nach und nach noch verbessern

Markus

 

Einloggen