Lowlevel

Lowlevel => Softwareentwicklung => Thema gestartet von: lolxdfly am 05. September 2013, 21:52

Titel: GRUB4DOS C++Kernel
Beitrag von: lolxdfly am 05. September 2013, 21:52
Hi,
ich bin nach http://www.lowlevel.eu/w/index.php?title=C%2B%2B-Kernel_mit_GRUB&oldid=11074#Kompilieren_und_Linken (http://www.lowlevel.eu/w/index.php?title=C%2B%2B-Kernel_mit_GRUB&oldid=11074#Kompilieren_und_Linken) vorgegangen.
Danach hab ich mir ein GRUB Image erstellt (http://www.lowlevel.eu/wiki/GRUB#GRUB_legacy (http://www.lowlevel.eu/wiki/GRUB#GRUB_legacy)).
Allerdings habe ich BFI mit cmd unter windows ausgeführt und bootlace unter DOSBOX, weil ich mir keine mbr.bin erstellen konnte. Habe ein Win7 64-bit System!
Jetzt hab ich das Image geladen und es erscheint das GRUB4DOS-Menu. Ich war zuerst glücklich, aber dann... nunja wie lade ich jetzt mein C++-Kernel???
Man kann dort verschiedene Sachen auswählen(find and load [komisches krams] of [Irgendeine Windows version]). Wenn es mein Kernel ist, wieso steht dann da was mit Windows?? O.o
Wenn ich eins auswähle komme ich in die grub-console...

lolxdfly
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: streetrunner am 05. September 2013, 22:18
Versuch es mal mit der Taste "c", damit solltest du in die Grub-Konsole kommen. Da dann deinen Kernel laden und booten.
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: lolxdfly am 06. September 2013, 14:33
Wie kann ich den Kernel laden?? Hab im Internet nix gutes gedunden. Einige sagen mit find, aber mit find gehts nich. Wenn ich ls eingeb, ist der kernel dort mit aufgelistet! kann ich mein Kernel nicht automatisch laden lassen?
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: Svenska am 06. September 2013, 16:57
Wenn ich mich recht entsinne, basiert GRUB4DOS nicht auf dem Grub2-Code.
Das heisst, dass du eine menu.lst benötigst, die du ins gleiche Verzeichnis legst, wie den GRUB4DOS selbst. Diese sollte dann beim Start von GRUB geladen und ausgeführt werden.

Wenn du den Kernel von der GRUB-Console laden kannst, kannst du ihn auch von einer menu.lst laden.
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: lolxdfly am 06. September 2013, 17:54
Stimmt! Das Menu wird von der menu.lst gesteuert. Dort hab ich die Einträge gefunden, die die Windows-menupunkte anzeigen.

Aber mit welchem Befehl läd man nun den Kernel?? mit
Zitat
boot
bootet man ihn. :-D

EDIT: hab mit
Zitat
kernel /kernel.bin
den Kernel geladen!
Wenn ich ihn mit boot ausführe erscheint ein kurzer Text, denn ich nicht so schnell lesen kann und dann komm ich wieder auf das Grub4Dos menu?
Hab den kernel unverendert aus dem TuT genommen. Muss man vielleicht sowas wie pause einfügen??
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: streetrunner am 06. September 2013, 19:53
Wenn du in das GRUB4DOS-Menü zurückkommst heißt dass, das dein Emulator neu gebootet hat, so fern man das so nennen kann. Das heißt dass irgendetwas mit deinem Kernel so nicht stimmt, dass sich der Emulator veranlasst fühlt dies zu tuen.

Woran es genau liegt kann dir normalerweise der Emulator sagen. Qemu kannst du in der Konsole mit "qemu -d int, cpu_reset" starten, dann schreibt das Programm alle Interrrupts und Resets in eine Datei namens qemu.txt. Wie das bei anderen Emulatoren geht weiß ich nicht ich nutze nur qemu.
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: lolxdfly am 06. September 2013, 20:47
Quemu läuft nicht auf meinem PC. Kommt immer Disk-error. Bis jetzt hab ich es immer mit dem Limbo-Emulator auf meinem Android Phone gemacht.  :-D
Damit läuft es wenigstens^^
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: Svenska am 07. September 2013, 00:05
Dann solltest du vielleicht mal deine Umgebung zum Laufen bringen. :roll:
Spätestens, wenn du deinen Kernel mal so richtig debuggen musst, wirst du deine helle Freude an einer schlecht/nur teilweise funktionierenden Umgebung haben. Und du wirst irgendwann richtig debuggen müssen...
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: lolxdfly am 07. September 2013, 19:58
Ich verwende jetzt Bochs-2.6.2! Er kann es aber auch nicht laden :(. Nur der Limbo-Emulator auf meinem Handy kann es...
Ich hab den log von Bochs mal im Anhang reingepackt.
Außerdem ist hier noch meine Boch-config: http://www.file-upload.net/download-8053099/bochsrc.bxrc.html
 (http://www.file-upload.net/download-8053099/bochsrc.bxrc.html)
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: Svenska am 08. September 2013, 00:00
Hallo,

das Log besagt, dass weder Diskette, noch Festplatte noch CD-Laufwerk bootfähig sind, also dein Image nicht funktioniert. Für multiboot-Kernel ist der einfachste Bootloader allerdings in Qemu integriert (qemu -kernel kernel.bin), der kann auch multiboot-Module.

Für Images gibt es verschiedene Möglichkeiten, wobei Grub am flexibelsten einsetzbar ist. Persönlich finde ich Syslinux (FAT) und Isolinux (CDs) allerdings einfacher zu handhaben, wobei für das alles ein Windows-Host insgesamt nicht unbedingt optimal ist.

Gruß,
Svenska
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: Jidder am 08. September 2013, 00:43
Außerdem ist der .bxrc zu entnehmen, dass gar kein Image geladen werden soll.
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: lolxdfly am 08. September 2013, 11:53
Außerdem ist der .bxrc zu entnehmen, dass gar kein Image geladen werden soll.
Ja, habe ich auch gemerkt! Wenn es versuche zu starten und es dann fehlschlägt entfernt er den Eintrag mit dem Image -.-

Hallo,

das Log besagt, dass weder Diskette, noch Festplatte noch CD-Laufwerk bootfähig sind, also dein Image nicht funktioniert. Für multiboot-Kernel ist der einfachste Bootloader allerdings in Qemu integriert (qemu -kernel kernel.bin), der kann auch multiboot-Module.

Für Images gibt es verschiedene Möglichkeiten, wobei Grub am flexibelsten einsetzbar ist. Persönlich finde ich Syslinux (FAT) und Isolinux (CDs) allerdings einfacher zu handhaben, wobei für das alles ein Windows-Host insgesamt nicht unbedingt optimal ist.

Gruß,
Svenska
Ich hab jetzt versuch den Kernel mit
Zitat
qemu -d int -kernel kernel.bin
zu starten. Gleiches Ergebnis...
Log von qemu ist im Anhang. Wenn das Image nicht bootfähig ist, warum läuft es dann auf dem limbo-emulator  :?

EDIT: hab grade ein Eintrag in der stderr.txt gefunden:
Zitat
Could not open option rom 'multiboot.bin': No such file or directory
In \optionrom\ liegt aber eine multiboot.bin!

EDIT2: hab jetzt die multiboot.bin in das gleiche verzeichniss wie qemu gelegt. Jetzt ist der Error weg, trotzdem kommt ein schwarzer bildschirm. Anscheinend versucht er immer wieder neu den kernel zu laden. Sieht man auch am log. Der log wird zugemüllt und alles wiederholt sich!
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: Svenska am 08. September 2013, 13:05
Klingt spontan nach Triple-Fault (=Reset) im Kernel.
Zeig mal Code.
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: lolxdfly am 08. September 2013, 13:56
Habe den Code von dem oben genannten TuT genommen. Startup.cpp hab ich von http://www.lowlevel.eu/wiki/C%2B%2B (http://www.lowlevel.eu/wiki/C%2B%2B)

asmKernel.asm:
global loader ; Unser Einsprungspunkt
extern kernelMain ; kernelMain() aus Kernel.cpp
extern initialiseConstructors ; aus Startup.cpp
 
FLAGS    equ 0
MAGIC    equ 0x1BADB002 ; Magicnumber - Erkennungsmerkmal für GRUB
CHECKSUM equ -(MAGIC + FLAGS) ; Checksum
 
section .text
align 4
MultiBootHeader:
  dd MAGIC        ; Magic number
  dd FLAGS        ; Flags
  dd CHECKSUM    ; Checksum
 
loader:
  mov esp,0x200000 ; Stack an die 2MB-Grenze platzieren
  push eax          ; Multiboot-Magicnumber auf den Stack legen
  push ebx          ; Adresse der Multiboot-Structure auf den Stack legen
  call initialiseConstructors    ; Konstruktoren aufrufen
  call kernelMain      ; kernelMain aufrufen
 
stop:
  jmp stop

Kernel.cpp:
// Einbinden unseres Header
#include "Video.h"
#include "Multiboot.h"
 
extern "C" void kernelMain(const Multiboot& multiboot_structur,
                           uint32_t multiboot_magic);
 
void kernelMain(const Multiboot& multiboot_structur,
                uint32_t multiboot_magic)
{
  if (multiboot_magic != MULTIBOOT_MAGIC)
  {
    // Fehler!
    screen << background(color::red) << color::white << "Fehler: Nicht von einem multibootfaehigem Bootloader geladen!";
    return;
  }
 
  // Textausgabe
  screen << background(color::light_gray) << color::blue << "Willkommen im C++-TestKernel!";
}

Multiboot.h:
#ifndef MULTIBOOT_H
#define MULTIBOOT_H
 
#include "types.h"
 
#define MULTIBOOT_MAGIC 0x2BADB002
 
struct Multiboot
{
  uint32_t flags;
  uint32_t mem_lower;
  uint32_t mem_upper;
  uint32_t bootdevce;
  uint32_t cmdline;
  uint32_t module_count;
  uint32_t module_address;
  /* etc... */
} PACKED;
 
#endif

Startup.cpp:
typedef void (*constructor)();
 
// Im Linkerskript definiert
extern "C" constructor start_ctors;
extern "C" constructor end_ctors;
 
extern "C" void initialiseConstructors();
 
// Ruft die Konstruktoren für globale/statische Objekte auf
void initialiseConstructors()
{
  for (constructor* i = &start_ctors;i != &end_ctors;++i)
    (*i)();
}

types.h:
#ifndef TYPES_H
#define TYPES_H
 
/* Garantiert, dass ein Typ nicht gepaddet wird und somit exakt die Größe seiner Member hat */
#define PACKED __attribute__((packed))
 
typedef unsigned char  uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int   uint32_t;
 
#endif

Video.cpp:
#include "Video.h"
 
Video screen;
 
Video::Video()
  : m_videomem((uint16_t*) 0xb8000), m_off(0), m_pos(0), m_color(0x0700)
{
  //Bildschirm leeren
  clear();
}
 
Video::~Video(){
}
 
void Video::clear(){
  // Füllen des Bildschirms mit Leerzeichen
  for(int i = 0;i < (80*25);i++)
    m_videomem[i] = (unsigned char)' ' | m_color;
 
  // Zurücksetzen der Textausgabe nach links oben
  m_pos = 0;
  m_off = 0;
}
 
Video& Video::operator << (const char* s){
  // Für jedes einzelne Zeichen wird put() aufgerufen
  while (*s != '\0')
    put(*s++);
 
  return *this;
}
 
Video& Video::operator << (color::type color){
  m_color = (static_cast<uint16_t>(color) << 8) | (m_color & 0xF000);
  return *this;
}
 
Video& Video::operator << (const background& color){
  m_color = (static_cast<uint16_t>(color.m_color) << 12) | (m_color & 0x0F00);
  return *this;
}
 
void Video::put(char c){
  // Wenn die Textausgabe den rechten...
  if(m_pos >= 80){
    m_pos = 0;
    m_off += 80;
  }
 
  // ...oder den unteren Bildschirmrand erreicht, gibt es
  // einen Umbruch bzw. es wird aufgeräumt.
  if(m_off >= (80*25))
    clear();
 
  // Setzen des Zeichens und der Farbe in den Videospeicher
  m_videomem[m_off + m_pos] = (uint16_t)c | m_color;
  m_pos++;
}

Video.h:
#ifndef VIDEO_H
#define VIDEO_H
 
#include "types.h"
 
namespace color
{
  enum type
  {
    black         = 0x00,
    blue          = 0x01,
    green         = 0x02,
    cyan          = 0x03,
    red           = 0x04,
    magenta       = 0x05,
    brown         = 0x06,
    light_gray    = 0x07,
    dark_gray     = 0x08,
    light_blue    = 0x09,
    light_green   = 0x0A,
    light_cyan    = 0x0B,
    light_red     = 0x0C,
    light_magenta = 0x0D,
    yellow        = 0x0E,
    white         = 0x0F
  };
}
 
struct background
{
  inline background(color::type color)
    : m_color(color){}
 
  color::type m_color;
};
 
class Video
{
  public:
    // Konstruktor
    Video();
 
    // Destruktor
    ~Video();
 
    // Leeren des Bildschirms, die Größe beträgt 80x25 Zeichen
    void clear();
 
    // Textausgabe
    Video& operator << (const char* s);
 
    // Vordergrundfarbe setzen
    Video& operator << (color::type color);
 
    // Hintergrundfarbe setzen
    Video& operator << (const background& color);
 
    // Ausgabe eines einzelnen Zeichens
    void put(char c);
 
  private:
    // Zeiger auf den Videospeicher
    uint16_t* m_videomem;
 
    // Y-Position der Textausgabe, je volle Zeile +80
    unsigned int m_off;
 
    // X-Position der Textausgabe, ab Zeilenanfang
    unsigned int m_pos;
 
    // FB/BG-Farbe
    uint16_t m_color;
};
 
// Globale Instanz der Video-Klasse, Definition in Video.cpp
extern Video screen;
 
#endif
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: Svenska am 08. September 2013, 15:17
Hallo,

in deiner Video-Klasse definierst du Farben mit je 16 Bit, eigentlich sollten es nur 8 Bit sein (Code- und Attribut sind jeweils nur 1 Byte). Die Standardtypen uint{8,16,32}_t sind in <stdint.h> bereits definiert, dafür brauchst du keinen eigenen Header.

Ansonsten bekommt deine main-Funktion ein "const Multiboot&" übergeben, was aber eigentlich nur ein Pointer auf deine Multiboot-Struktur ist; in C wäre das "struct multiboot *mb" Ob das aber ein Problem ist, kann ich nicht einschätzen, weil meine C++-Kenntnisse (so sie jemals nennenswert vorhanden waren) nur dürftig sind.

In diesem Stadium sind Endlosschleifen als Debugmittel ganz gut geeignet. Setz mal eine direkt vor deinen Konstrukturaufruf und schaue, ob es immernoch ständig resettet. Und so weiter.

Gruß,
Svenska
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: lolxdfly am 08. September 2013, 17:58
Hi,
das würde ja heißen, dass das TuT aus dem wiki Fehler hat  :-o
Naja egal. Wie ändere ich die 16-Bit Farben in 8-Bit?
Soll ich einfach   m_color = (static_cast<uint16_t>(color) << 8) | (m_color & 0xF000); in   m_color = (static_cast<uint8_t>(color) << 8) | (m_color & 0xF000); umändern?
Falls ja hat es nix genützt. Ich benutze jetzt die <stdint.h>. Ein paar einträge mit long musst ich enfernen, weil sie Fehler verursacht haben.

Zu:
Ansonsten bekommt deine main-Funktion ein "const Multiboot&" übergeben, was aber eigentlich nur ein Pointer auf deine Multiboot-Struktur ist; in C wäre das "struct multiboot *mb" Ob das aber ein Problem ist, kann ich nicht einschätzen, weil meine C++-Kenntnisse (so sie jemals nennenswert vorhanden waren) nur dürftig sind.
Da hab ich so genau auch keine Ahnung. Bei Compilen sagt er da etwas davon:
Zitat
Kernel.cpp:8:6: Warnung: unbenutzter Parameter >>multiboot_structur<< [-Wunused-parameter]

In diesem Stadium sind Endlosschleifen als Debugmittel ganz gut geeignet. Setz mal eine direkt vor deinen Konstrukturaufruf und schaue, ob es immernoch ständig resettet. Und so weiter.
Meinst du diesen?: Video screen; Wie will ich den in eine Endlosschleife packen? O.o

PS: Ich werde wohl ein paar Kapitel in C++ nachholen müssen...
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: Svenska am 08. September 2013, 19:53
das würde ja heißen, dass das TuT aus dem wiki Fehler hat  :-o
Wäre durchaus möglich. Im Normalfall baut man den Kernel ja auch in C zusammen - und die Tutorialreihe dafür ist gut getestet.

Naja egal. Wie ändere ich die 16-Bit Farben in 8-Bit?
In "Video.h" den Typ von uint16_t nach uint8_t ändern und sicherstellen, dass das mit der neuen Definition auch überall so funktioniert, wie das vorgesehen ist...

Falls ja hat es nix genützt.
Gegen den Absturz hätte das auch sicherlich nicht geholfen. :-) Es ist mir nur nebenbei eingefallen.

In diesem Stadium sind Endlosschleifen als Debugmittel ganz gut geeignet. [...]
Meinst du diesen?: Video screen; Wie will ich den in eine Endlosschleife packen? O.o
In welcher Datei rufst du den Konstruktor auf? Richtig, in der Assemblerdatei. :-D Da kannst du schauen, ob es (a) vor den Konstruktoren (b) nach den Konstruktoren (c) nach kernelMain() resettet. Dann musst du rausfinden, in welcher Reihenfolge die Klassen initialisiert werden und kannst einfach in jeden Konstruktor eine Endlosschleife hängen. Anschließend eine in kernelMain().

PS: Ich werde wohl ein paar Kapitel in C++ nachholen müssen...
Oder du fängst erstmal mit C an und baust einen Prototypen, damit du die Mechanik lernst. Wenn du das verstanden hast, baut sich eine vernünftige Abstraktionsebene auch besser.

Gruß,
Svenska
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: lolxdfly am 08. September 2013, 20:42
Ich habe jetzt an verschiedenen Stellen Endlosschleifen gesetzt. Z.B.:
global loader ; Unser Einsprungspunkt
ENDLOSSCHLEIFE:
extern kernelMain ; kernelMain() aus Kernel.cpp
jmp ENDLOSSCHLEIFE
extern initialiseConstructors ; aus Startup.cpp
...
Hoffe mal das war so richtig  :-D
Hat leider nichts ergeben :( Immer noch ein schwarzer flackender Bildschirm. Manchmal ein kurzes aufleuchten von hellblauer Schrift, aber das war vorher auch schon...
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: Jidder am 08. September 2013, 21:51
Setz die mal unter die Zeile loader:

loader:
  endlosschleife
  jmp endlosschleife

Wenn das funktioniert (d.h. der Emulator macht nach dem Booten nichts mehr), entfern sie wieder und füg eine hier ein:

  push ebx          ; Adresse der Multiboot-Structure auf den Stack legen
  call initialiseConstructors    ; Konstruktoren aufrufen
  endlosschleife
  jmp endlosschleife

Wenn der Emulator jetzt abstürzt, weißt du, dass es an der Funktion initialiseConstructors (bzw. in einem der Konstruktoren) liegt.
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: lolxdfly am 08. September 2013, 22:13
Ahh da musst man das also setzen.
Bei
loader:
  endlosschleife
  jmp endlosschleife
läuft es!!!

Bei
  push ebx          ; Adresse der Multiboot-Structure auf den Stack legen
  call initialiseConstructors    ; Konstruktoren aufrufen
  call kernelMain      ; kernelMain aufrufen
  endlosschleife
  jmp endlosschleife
läuft es nicht.

Und bei
  push ebx          ; Adresse der Multiboot-Structure auf den Stack legen
  call initialiseConstructors    ; Konstruktoren aufrufen
  endlosschleife
  jmp endlosschleife
  call kernelMain      ; kernelMain aufrufen
läuft es nicht.

Also hat die Startup.cpp einen Fehler!!
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: Jidder am 08. September 2013, 22:51
Also hat die Startup.cpp einen Fehler!!

Ja entweder das, oder was im Linkerskript, oder bei den Linker-/Compilerflags ist falsch/passt nicht zusammen.
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: lolxdfly am 08. September 2013, 23:17
Hmmm Ist denn meine Startup.cpp richtig?? Als linkerscript hab ich ja den älteren genommen. Kann es daran liegen? Bei dem älteren TuT, wo der linkerscript her kommt hat sich aber nichts am anderen Code geändert. Wenn das TuT korrekt ist, müsste es also am StartupCode liegen. Den hab ich ja von einem anderen Thread... Dort wurde der Code von http://www.lowlevel.eu/wiki/C%2B%2B#globale.2Fstatische_Objekte (http://www.lowlevel.eu/wiki/C%2B%2B#globale.2Fstatische_Objekte) entnommen.
Titel: Re: GRUB4DOS C++Kernel
Beitrag von: lolxdfly am 09. September 2013, 16:21
ES FUNKTIONIERT!!!!  :-)

Ich kann nicht genau sagen, woran es gelegen hat Höchstwahrscheinlich haben sich MinGW-sachen mit dem CrossCompiler vermischt. Nachdem ich alles neu gemacht hatte hats gefunzt.
Trotzdem Danke