Lowlevel
Lowlevel => Softwareentwicklung => Thema gestartet 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
-
Versuch es mal mit der Taste "c", damit solltest du in die Grub-Konsole kommen. Da dann deinen Kernel laden und booten.
-
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?
-
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.
-
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 boot
bootet man ihn. :-D
EDIT: hab mit 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??
-
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.
-
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^^
-
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...
-
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)
-
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
-
Außerdem ist der .bxrc zu entnehmen, dass gar kein Image geladen werden soll.
-
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 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:
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!
-
Klingt spontan nach Triple-Fault (=Reset) im Kernel.
Zeig mal Code.
-
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
-
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
-
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:
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...
-
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
-
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...
-
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.
-
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!!
-
Also hat die Startup.cpp einen Fehler!!
Ja entweder das, oder was im Linkerskript, oder bei den Linker-/Compilerflags ist falsch/passt nicht zusammen.
-
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.
-
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