Beiträge anzeigen

Diese Sektion erlaubt es dir alle Beiträge dieses Mitglieds zu sehen. Beachte, dass du nur solche Beiträge sehen kannst, zu denen du auch Zugriffsrechte hast.


Themen - ChristianF

Seiten: [1] 2
1
Lowlevel-Coding / 64 bit kernel mit grub 2 booten
« am: 25. June 2013, 08:57 »
Hallo,
lange ist es her, dass ich mich damit beschäftigt habe. Allerdings juckt es mich in den Fingern mal wieder was zu machen. Da ich mich mal mit was anderem als vorher 32-bit beschäftigen wollte, habe ich mich an einen 64-bit Feldversuch gehalten. Dabei habe ich folgendes Tutorial gelesen und versucht mein eigenes Ding zu machen: http://wiki.osdev.org/64-bit_Higher_Half_Kernel_with_GRUB_2
 
Zum kompilieren und linken des codes habe ich mir unter mingw einen cross-compiler nach der Anleitung im Wiki kompiliert.
 
Beim zwischendurch erstellen des Kernels wird immer folgender Fehler von ld ausgespuckt:
./obj/bootstrap.S.o: In function `asmKernelStartupGdt':
src/arch/x86-64/bootstrap.S:(.boot+0x86): relocation truncated to fit: R_X86_64_32 against `.text'

Jetzt bin ich mir allerdings nicht so sicher, ob das ganze so funktioniert/funktionieren kann, wie ich es gerne hätte. Ich würde gerne den assembler startup code in eine einzige Datei packen. Zuerst kommt also der 32-Bit Code, der eine temporäre GDT anlegt und das Paging für den 64-bit Modus aktiviert. Dann sollte zum 64-bit Startup-Code gesprungen werden, der in der gleichen Datei liegt, und schließlich die initKernel vom C-Code aufruft.
 
Kann ich das überhaupt so machen? Oder muss ich die Dateien doch auftrennen? Oder läuft da bei mir generell etwas schief? Ich bin, was die Fehlermeldung von ld angeht dezent ratlos.
 
Mein momentaner startup-code sieht wie folgt aus:
[BITS 32]

; just an own section for multiboot header in cause of a may
; be very large kernel at the future!
[SECTION .multiboot]

; some defines needed for multiboot header start
MULTIBOOT2_HEADER_MAGIC equ 0xe85250d6
GRUB_MULTIBOOT_ARCHITECTURE_I386 equ 0
MULTIBOOT_HEADER_TAG_FRAMEBUFFER equ 8
MULTIBOOT_HEADER_TAG_OPTIONAL equ 1
MULTIBOOT_HEADER_TAG_END equ 0

; align 64 bits boundary
ALIGN 8
; multiboot header
multibootHeaderStart:
; magic number for grub2
dd MULTIBOOT2_HEADER_MAGIC
; architecture: i386
dd GRUB_MULTIBOOT_ARCHITECTURE_I386
; Header length
dd multibootHeaderEnd - multibootHeaderStart
; Grub2 checksum
dd -(MULTIBOOT2_HEADER_MAGIC + GRUB_MULTIBOOT_ARCHITECTURE_I386 + (multibootHeaderEnd - multibootHeaderStart))

; enable vbe framebuffer (1024 * 768)
framebufferTagStart:
dw MULTIBOOT_HEADER_TAG_FRAMEBUFFER
dw MULTIBOOT_HEADER_TAG_OPTIONAL
dd framebufferTagEnd - framebufferTagStart
dd 1024
dd 768
dd 32
framebufferTagEnd:
dw MULTIBOOT_HEADER_TAG_END
dw 0
dd 8
multibootHeaderEnd:

; just an own section for startup code
[SECTION .boot]

; global declaration needed for linking
[GLOBAL asmKernelStartup]

; variables for holding the multiboot informations
[EXTERN varMultibootHeaderMagic]
[EXTERN varMultibootHeaderAddress]
[EXTERN varBootstrapStack]
[EXTERN varBootsrapPml4]
[EXTERN varBootstrapPdt]
[EXTERN varBootstrapPd]

; Initialise simple paging, initialise gdt and jump to 64 bit code
asmKernelStartup:

; disable interrupts
cli

; save multiboot header and address for longmode entry later
mov [varMultibootHeaderMagic], eax
mov [varMultibootHeaderAddress], ebx

; load initial gdt
lgdt [Gdtr1]
jmp 0x08:asmKernelStartupGdt

asmKernelStartupGdt:

; reset eflags
push dword 0
popf

; set registers after loading gdt
mov eax, 0x10
mov ds, ax
mov ss, ax

; initialise bootstrap stack
mov esp, varBootstrapStack

; check for available cpuid
pushfd ; Store the FLAGS-register.
pop eax ; Restore the A-register.
mov ecx, eax ; Set the C-register to the A-register.
xor eax, 1 << 21 ; Flip the ID-bit, which is bit 21.
push eax ; Store the A-register.
popfd ; Restore the FLAGS-register.
pushfd ; Store the FLAGS-register.
pop eax ; Restore the A-register.
push ecx ; Store the C-register.
popfd ; Restore the FLAGS-register.
xor eax, ecx ; Do a XOR-operation on the A-register and the C-register.
jz .noCpuid ; The zero flag is set => no CPUID!

; check for extended cpuid functions
mov eax, 0x80000000 ; Set the A-register to 0x80000000.
cpuid ; CPU identification.
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001.
jb .noLongmodeSupport ; It is less => there is no long mode support!

; check for longmode available
mov eax, 0x80000001 ; Set the A-register to 0x80000001.
cpuid ; CPU identification.
test eax, 1 << 29 ; Test if the LM-bit, which is bit 29, is set in the D-register.
jz .noLongmodeSupport ; They aren't => there is no long mode support!

; check for page address extension
mov eax, 0x80000001 ; Set the A-register to 0x80000001.
cpuid ; CPU identification.
test edx, 1 << 6 ; Test if the PAE-bit, which is bit 6, is set in the D-register.
jz .noLongmodeSupport ; They aren't => there is no long mode support!

; check for page size extension
mov eax, 0x80000001 ; Set the A-Register
cpuid ; CPU identification
test edx, 1 << 3 ; Test if the PSE-bit, which is bit 3, is set in the D-register
jz .noLongmodeSupport ; They aren't => there is no long mode support!

; set up initial paging!
call setupInitialPaging

mov eax, Gdtr2
lgdt [eax]

; jump to long mode entry point!
jmp 0x08:asmLongmodeEntry

.noLongmodeSupport:
; TODO: print error message
jmp .errorEndlessLoop

.noCpuid:
; TODO: print error message
jmp .errorEndlessLoop

.errorEndlessLoop:
jmp .errorEndlessLoop

setupInitialPaging:
ret

; Some error messages for previous checks!
msgNoCpuid: db 'cpuid is not supported',13,10,0
msgNoLongmodeSupport: db 'long mode (64bit) is not supported',13,10,0

TmpGdt:
DQ 0x0000000000000000
DQ 0x00CF9A000000FFFF
DQ 0x00CF92000000FFFF
DQ 0x0000000000000000
DQ 0x00A09A0000000000
DQ 0x00A0920000000000

Gdtr1:
DW 23
DD TmpGdt

Gdtr2:
DW 23
DD TmpGdt + 24
DD 0

[BITS 64]
[SECTION .text]

; kernel startup c-code
[EXTERN initKernel]

; long mode kernel startup initialises stack and calls c-code
asmLongmodeEntry:

; initialise new kernel stack
mov rsp, kernelStack

; push multiboot data
mov rax, [varMultibootHeaderAddress]
mov rbx, [varMultibootHeaderMagic]

push rax
push rbx

; call c kernel
mov rax, initKernel
call [rax]

; disable interrupts and jump to never ending loop when initKernel returns
cli
jmp .longmodeEntryHalt

; hang within endless loop!
.longmodeEntryHalt:
jmp .longmodeEntryHalt

[SECTION .bss]
resb 8192
kernelStack:

Mein linker script sieht wie folgt aus:
OUTPUT_FORMAT(elf64-x86-64)
OUTPUT_ARCH(i386:x86-64)
ENTRY(asmKernelStartup)

KERNEL_PHYSICAL_BASE = 0x0000000000100000;
KERNEL_VIRTUAL_BASE = 0xFFFFFFFF80000000;
KERNEL_VIRTUAL_TO_PHYSICAL = KERNEL_VIRTUAL_BASE - KERNEL_PHYSICAL_BASE;

SECTIONS
{
. = KERNEL_PHYSICAL_BASE;

/* define variables for kernels start address */
kernelVirtualStartAddress = . + KERNEL_VIRTUAL_TO_PHYSICAL;
kernelPhysicalStartAddress = .;

/* kernels virtual base */
kernelVirtualBase = KERNEL_VIRTUAL_BASE;

/* the multiboot header MUST come early enough in the output object file */
    .boot :
{
*(.multiboot*)
*(.boot*)
. = ALIGN(0x1000);
varMultibootHeaderMagic = .;
. += 0x0020;
varMultibootHeaderAddress = .;
. += 0x0020;
. = ALIGN(0x1000);
varBootsrapPml4 = .;
. += 0x1000;
varBootstrapPdt = .;
. += 0x1000;
varBootstrapPd = .;
. += 0x1000;
. += 0x8000;
varBootstrapStack = .;
}

. += KERNEL_VIRTUAL_TO_PHYSICAL;

/* code section and read only data (e.g. strings within c-part) */
.text ALIGN(0x1000) : AT(ADDR(.text) - KERNEL_VIRTUAL_TO_PHYSICAL)
{
*(.text*)
*(.gnu.linkonce.t*)
}

/* Initialised data - should be page aligned */
.data ALIGN(0x1000) : AT(ADDR(.data) - KERNEL_VIRTUAL_TO_PHYSICAL)
{
*(.data*)
*(.gnu.linkonce.d*)
}

/* Read only data - should be page aligned too */
.rodata ALIGN(0x1000) : AT(ADDR(.rodata) - KERNEL_VIRTUAL_TO_PHYSICAL)
{
*(.rodata*)
*(.gnu.linkonce.r*)
}

/* Uninitialised data */
.bss : AT(ADDR(.bss) - KERNEL_VIRTUAL_TO_PHYSICAL)
{
*(.bss)
*(COMMON)
*(.gnu.linkonce.b*)
}

/* define variable for kernels end address */
kernelVirtualEndAddress = .;
kernelPhysicalEndAddress = . - KERNEL_VIRTUAL_TO_PHYSICAL;

/* discard comment sections */
/DISCARD/ :
{
*(.comment)
*(.eh_frame*)
}
}
2
Softwareentwicklung / Bit geschiebe mit Java
« am: 16. June 2011, 09:34 »
Moin moin,

ich sitze hier vor einem Problem und komme einfach nicht zur Lösung. Und zwar habe ich folgendes Problem:

Ich habe 4 Werte (Helligkeit, Rot, Grün und Blau), z.B. so: 0, 234, 12, 67. Binär sieht das ganze ja so aus (es werden von 32 Bit immer nur die ersten 8 genutzt):
0000 0000 -> 0
1110 1010 -> 234
0000 1100 -> 12
0100 0011 -> 67

Nun muss ich das ganze Bit für Bit durchgehen (angefangen beim höchsten) und das immer nach unten hin gruppieren, damit dann die folgende Bitfolge daraus wird:
0100 0101 0100 0000 0110 0010 0101 0001
Mein bisheriger Ansatz sah wie folgt aus:
  • Ich laufe von 7 ab runter bis einschließlich 0
  • Zusammenschieben der Bitfolge anhand des aktuellen Durchlaufs
for(int i = 7; i >= 0; i--)
{
int brightness, red, green, blue;
int pos = 0;

// get values
brightness = 0;
red = 234;
green = 12;
blue = 67;

// Bit abhängig von der aktuellen Position holen
// - Bit um i Stellen nach vorne schieben (>> i)
// - Bit ganz nach vorne schieben (>> (7 - i))
// - Überflüssige Daten wegschmeißen (&0x01)
// - Bit an die korrekte Position schieben.
pos |= ((((brightness >> i) >> (7 - i)) & 0x01) << 3);
pos |= ((((red >> i) >> (7 - i)) & 0x01) << 2);
pos |= ((((green >> i)>> (7 - i)) & 0x01) << 1);
pos |= ((((blue >> i) >> (7 - i)) & 0x01) << 0);

// Weitere basteleien mit der Position
}

Wenn meine Beispielwerte nicht gänzlich falsch sind, sollte ja beim 2. Durchlauf (i = 6) pos den Wert 5 haben, allerdings ist dem nicht so.
 
Ich bin das ganze auch schon mit dem Debugger durchgegangen, und deswegen weiß ich, dass das letzte Bit (blau) irgendwie verloren geht.
 
Könnt ihr mir da vielleicht weiter helfen?

Grüße Christian
3
Lowlevel-Coding / Frage zur .data-Sektion
« am: 24. October 2010, 15:58 »
Moin moin...
ich beschäftige mich seit längerem mal wieder mit dem Thema und habe direkt ein Problem, bzw. eine Frage... :roll:
 
Wie sieht es mit der Sektion .data aus? Muss diese immer da sein? Könnte das nicht existieren der Sektion .data eventuell auch mit einem Fehler im Linkerscript zusammen hängen?
 
mein objdump sieht nämlich so aus, und das hat mich doch etwas verwirrt, da nur .text und .bss vorhanden sind:
kernel.elf:     file format elf32-i386
kernel.elf
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0010000c

Program Header:
    LOAD off    0x00001000 vaddr 0x00100000 paddr 0x00100000 align 2**12
         filesz 0x0000002c memsz 0x00002030 flags rwx
   STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2
         filesz 0x00000000 memsz 0x00000000 flags rwx

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000002c  00100000  00100000  00001000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .bss          00002004  0010002c  0010002c  0000102c  2**2
                  ALLOC
SYMBOL TABLE:
00100000 l    d  .text  00000000 .text
0010002c l    d  .bss   00000000 .bss
0010202c l       .bss   00000000 _sys_stack
00100019 l       .text  00000000 stop
00000000 l    df *ABS*  00000000 init.c
00100000 g       *ABS*  00000000 kernel_phys_start_address
0010002c g       .bss   00000000 _sbss
00102030 g       *ABS*  00000000 kernel_end_address
00102030 g       .bss   00000000 _ebss
00100000 g       *ABS*  00000000 KERNEL_VMA
00000000 g       *ABS*  00000000 KERNEL_VOFFSET
00002030 g       *ABS*  00000000 kernel_size
00100000 g       *ABS*  00000000 kernel_start_address
00100000 g       *ABS*  00000000 KERNEL_LMA
0010202c g     O .bss   00000004 globalData
0010000c g       .text  00000000 loader
00102030 g       *ABS*  00000000 kernel_phys_end_address
0010001c g     F .text  00000010 vKernelInit

Viel ist nicht da. Es gibt eine C-Funktion, die nichts macht außer einer Endlosschleife und einen Startup-Code, der diese C-Funktion lädt...
 
Grüße Christian
4
Offtopic / Problem mit Kubuntu und dem Netzwerk
« am: 28. June 2010, 12:04 »
Moin,
ich habe schon seit geraumer Zeit ein Problem mit meinem installierten Kubuntu. Und zwar habe ich vor einiger Zeit "Maßnahmen" ergriffen, um so Dingen wie ARP Poisoning vorzubeugen. Das war letzten Endes ein totaler Fehlschlag. So habe ich nun irgendwo ein "arp -s ..." samt "dhclient ..." rein geschrieben, damit das beim Starten des Systems ausgeführt wird. Dies war nie der Fall... :roll:
Allerdings ist seit dem beim starten nie eine Netzwerkverbindung vorhanden, was heißt, dass ich diese immer per Hand einrichten muss. Zu beginn hat mich das nicht weiter gestört, weshalb ich meine Änderungen auch nicht rückgängig gemacht habe. Mittlerweile geht mir das ganze aber ziemlich aufn Kecks und ich weiß nicht mehr, wo ich das reingeschrieben habe.  :cry:
 
Gibt es irgendeine Möglichkeit alle Dateien nach einer bestimmten Zeichenfolge zu durchsuchen? Oder weiß evtl. jemand von euch, wo man solche Konfigurationsdateien für gewöhnlich ablegt?
 
Gruß Christian
5
Offtopic / Mikrokontrollertechnik
« am: 09. March 2010, 10:16 »
Moin moin,
ich möchte mich mal auf einem anderen Feld des Lowlevel beschäftigen, und habe mir dafür die Mikrokontrollertechnik, wie das bei mir in der Schule genannt wurde herausgesucht.
 
Was ich gerne machen möchte:
Ein kleines Gerät bauen, dass ein analoges Signal (z.B. von einer Gitarre) in ein digitales umwandelt, dieses irgendwie modifiziert (sollte hörbar sein :roll:), wieder in ein analoges umwandeln und an eine Box, einen Lautsprecher, schicken.
 
Nun ist es doch ein oder zwei Jahre her, als ich mich das letzte Mal mit so etwas beschäftigt habe. Ich müsste mich also wieder einlesen...  :roll:
Gibt es hier jemanden, der sich mit ähnlichen Themen beschäftigt hat? Könnt ihr mir eventuell etwas Literatur empfehlen, das die Grundlagen der Mikrokontrollertechnik abdeckt?
 
Gruß Christian
 
PS: So etwas kann man auch als Vertiefung zum Studiengang "Elektro- und Informationstechnik" studieren (evtl. ja ein Thema für mich nach meinem Zivi)  :evil:
 
EDIT:
Kann ich hier auf einen Mikroprozessor zurückgreifen, oder sollte ich mich besser mit FPGAs beschäftigen?
6
Offtopic / CSS Spaß und der IE
« am: 01. March 2010, 14:18 »
Moin moin,
ich ärgere mich gerade mal wieder mit dem Internet Explorer herum...
 
Und zwar sollen der Inhalt einer Tabelle scrollbar sein. im Firefox war das schnell gemacht:
tbody {
     overflow: scroll;
     overflow-x: hidden;
     height: 250px;
}
Da das aber anscheinend noch nie im IE funktioniert hat, habe ich angefangen, den Tabellenkopf absolut über der Tabelle zu positionieren:
.tableContainer thead {
position: absolute; /* throws the header out of the table */
top: 0px;
left: 0px;

width: 100%
}
Damit bin ich der Lösung schon recht nahe gekommen, da der Kopf nun fest über dem Inhalt ist. Allerdings habe ich noch ein kleines Problem: Und zwar hat der Inhalt der Tabelle eine Breite von 100%, was auch korrekt dargestellt wird. Durch die absolute Positionierung des Kopfes passiert dies allerdings nicht mit dem Tabellenkopf. Ist das ein Bug vom IE und wenn ja, wie kann ich das beheben?
 
 
Solltet ihr den kompletten Code zum experimentieren brauchen, stelle ich diesen gerne zur Verfügung.
7
Offtopic / Shellscript
« am: 11. February 2010, 11:42 »
Hallo,
 
ich habe mich daran gemacht, ein kleines Shellscript zu bauen. Nun frage ich mittels "Dialog" ab, für welche Architektur der Kernel gebaut werden soll, welcher compiler genutzt werden soll (momentan nur gcc) und wo der Kernel abgelegt werden soll.
 
Nun muss ich prüfen, ob der Compiler auch installiert ist. Wie macht man das am besten? Bisher bin ich nur darauf gekommen, 'gcc -v' aufzurufen und die Ausgabe entsprechend auszuwerten... kann man das nicht auch irgendwie anders (schöner) machen?
 
Gruß Christian
8
OS-Design / Kernelparts in Modulen unterbringen
« am: 22. January 2010, 08:53 »
Hallo Lowlevel-Community,
mir ist soeben eine fix Idee gekommen.
 
Und zwar möchte ich die Kernelaufgaben meines Microkernels in mehrere Module aufteilen. So hätte ich dann z.B. ein HAL-Modul, in dem Paging usw. definiert wird. Des Weiteren hätte ich noch eine Reihe von Einzelmodulen, wie z.B. eines für die physikalische Speicherverwaltung.
 
Ist so etwas praktikabel, oder sollte man das besser im Kernel belassen?
 
Gruß Christian
9
Lowlevel-Coding / Größe des Kernels
« am: 02. November 2009, 19:23 »
Hallo Leute,
ich bin seit einiger Zeit dabei, mein Projekt aufzuräumen, bzw. neu zu schreiben, und habe nun alles schön in Unterordner gepackt, damit eine spätere Portierung leichter fällt. Das ist zumindest das Ziel...
 
Nun hat der Kernel nur eine GDT, IDT, ISRs und ein paar zusätzliche Funktionen, wie z.B. outb oder video_puts. Da das ja nicht sonderlich viel ist, verwundert es mich, dass der Kernel doch bereits jetzt eine Größe von 38 KB hat.
Könnte das an den vielen Unterordnern liegen? Der alte Kernel war nämlich nur ein bissel größer, wenn nicht sogar gleich groß, und konnte wesentlich mehr (Multitasking, System Calls).
 
Muss ich da noch Optimierungsoptionen setzen, oder kann ich auch Optionen weglassen? Die Optionen, die gcc mitgegeben werden, sehen momentan wie folgt aus: -m32 -Wall -Wextra -O3 -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-stack-protector -fno-builtin -I./src/kernel/include -I./src/kernel/include/arch/$(ARCH) -D PAE=$(PAE) -D APIC=$(APIC) -c -o
10
Lowlevel-Coding / Endlosschleife nach Initialisieren der GDT
« am: 09. September 2009, 09:05 »
Guten Morgen,
 
und noch ein neuer Thread  :-D
Ich bin momentan dabei, alles rauszuschmeißen und neuzuschreiben, was aus Tutorials übernommen wurde, bzw. den kompletten Kernel neuzuschreiben.
Leider leider hänge ich schon bei der GDT :cry:
 
Und zwar initialisiere ich diese und nach dem Sprung, um die GDT neuzuladen, hängt Bochs in einer endlosschleife. Hier erst einmal die Ausgaben des Debuggers, die wichtig sein sollten:
(0) [0x00100129] 0008:0000000000100129 (unk. ctxt): lgdt ss:[esp+0x1e]        ; 0f0154241e
(0) [0x0010012e] 0008:000000000010012e (unk. ctxt): mov ax, 0x0010            ; 66b81000
(0) [0x00100132] 0008:0000000000100132 (unk. ctxt): mov ds, ax                ; 8ed8
(0) [0x00100134] 0008:0000000000100134 (unk. ctxt): mov es, ax                ; 8ec0
(0) [0x00100136] 0008:0000000000100136 (unk. ctxt): mov fs, ax                ; 8ee0
(0) [0x00100138] 0008:0000000000100138 (unk. ctxt): mov gs, ax                ; 8ee8
(0) [0x0010013a] 0008:000000000010013a (unk. ctxt): mov ss, ax                ; 8ed0
(0) [0x0010013c] 0008:000000000010013c (unk. ctxt): jmp far 0008:00100143     ; ea430110000800
(0) [0x00110142] 0008:0000000000100143 (unk. ctxt): add byte ptr ds:[eax], al ; 0000
(0) [0x00110144] 0008:0000000000100145 (unk. ctxt): add byte ptr ds:[eax], al ; 0000
(0) [0x00110146] 0008:0000000000100147 (unk. ctxt): add byte ptr ds:[eax], al ; 0000
(0) [0x00110148] 0008:0000000000100149 (unk. ctxt): add byte ptr ds:[eax], al ; 0000
(0) [0x0011014a] 0008:000000000010014b (unk. ctxt): add byte ptr ds:[eax], al ; 0000
(0) [0x0011014c] 0008:000000000010014d (unk. ctxt): add byte ptr ds:[eax], al ; 0000
....

Nun zu meinem geschriebenen unrat. Meine Struktur für die Einträge habe ich so angelegt, wie es in den Intel Dokumenten steht. Damit GCC nix optimiert, habe ich das auch noch gepackt:
struct segment_descriptor
{
unsigned short base_low;
unsigned short limit_low;
unsigned char base_mid;
unsigned char access;
unsigned char granularity;
unsigned char base_high;
} __attribute__((packed));
Meine Funktion zum setzen eines Eintrags ist auch nicht unähnlich der, die im Tutorial genutzt wurde, allerdings selbst geschrieben:
void gdt_set_descriptor(unsigned int num, unsigned int base, unsigned int limit, unsigned char access, unsigned char granularity)
{
// sollte nicht passieren ;)
if(num >= GDT_NUM_MAX_ENTRIES)
return;

// basis adresse
kgdt[num].base_low = (base & 0xFFFF);
kgdt[num].base_mid = ((base >> 16) & 0xFF);
kgdt[num].base_high = ((base >> 24)); // sollte man weglassen können: & 0xFF

// limit
kgdt[num].limit_low = (limit & 0xFFFF);
kgdt[num].granularity = ((limit >> 16) & 0x0F);

// der rest
kgdt[num].access = access;
kgdt[num].granularity |= (granularity & 0xF0);
}

Für das Initialisieren der GDT rufe ich einfach oben die aufgeführte Funktion 5 mal auf (0, Kernelcode, Kerneldata, Usercode, Userdata (später 6 mal, da noch die TSS hinzu kommt)).
Nun habe ich die Informationen für das Register GDTR nur lokal in der Funktion abgelegt, da es ja eigentlich nur einmal gebraucht wird. Und da ich auf zusätzliche Funktionen verzichten wollte, habe ich den Wechsel auch gleich in inline assembler geschrieben.  Das ganze sieht dann wie folgt aus:
void gdt_install(void)
{
// gdtr
struct {
unsigned short limit;
unsigned int base;
}__attribute__((packed)) gp = {
.limit = (sizeof(struct segment_descriptor) * GDT_NUM_MAX_ENTRIES) - 1,
.base = (unsigned int)kgdt
};

// NULL-Segment
gdt_set_descriptor(0, 0, 0, 0, 0);
// kernel code
gdt_set_descriptor(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
// kernel data
gdt_set_descriptor(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
// user code
gdt_set_descriptor(3, 0, 0xFFFFFFFF, 0xFA, 0xCF);
// user data
gdt_set_descriptor(4, 0, 0xFFFFFFFF, 0xF2, 0xCF);
// task state segment
//gdt_set_descriptor(5, &..., sizeof(...), 0x89, 0x4F);

asm("lgdt %0\n\t"
"mov $0x10, %%ax\n\t"
"mov %%ax, %%ds\n\t"
"mov %%ax, %%es\n\t"
"mov %%ax, %%fs\n\t"
"mov %%ax, %%gs\n\t"
"mov %%ax, %%ss\n\t"
"ljmp $0x08,$1f\n\t"
"1:\n\t"
: : "m"(gp) : "ax");
}

 
Da der Code nicht funktioniert, muss ich irgendwo einen Fehler haben, doch wo? Ich sehe hier keine Unstimmigkeiten. Wenn ich nun aus ax eax mache, passiert auch nichts anderes... :(
Was kann ich hier machen?
11
Lowlevel-Coding / Verständnisfragen
« am: 04. September 2009, 11:06 »
Moin,
ich möchte nun endlich mal einige Dinge geklärt haben, die bisher ungeklärt waren. Ich hatte die ganze Zeit ein Skript für "ld" aus einem Tutorial genutzt. Nun möchte ich dieses aber auch verstehen und nach dem Lesen des Manuals sind noch ein paar Dinge offen.
 
Die einzelnen Sektionen sind mir soweit klar. Nur frage ich mich, warum die Sektionen nach .text (.data und .bss) bei mir und in vielen Tutorials ein ALIGN(0x1000) haben.
Laut Manual heißt dass, das diese Sektionen dann an Page-Aligned werden. Das heißt also, dass .bss an 0x00101000 liegt (laut objdump). Aber was bringt das für Vorteile?
.data ALIGN(0x1000) : { /*...*/ }

Des Weiteren gibt es laut Manual die bss-Sektion für uninitialisierte Daten. Hier gibt es *(.bss) und *(COMMON). Das Manual sagt folgendes:
Zitat
A special notation is needed for common symbols, because in many object file formats common symbols do not have a particular input section.
...
Was sind denn "common symbols"? Ein kleines Beispiel würde ausreichen...
Weiterhin habe ich in verschiedenen Tutorials immer wieder _sbss und _ebss in der Sektion .bss gesehen. Geben diese start und ende der uninitialisierten Daten an, oder wozu werden diese Angaben benötigt?
 
 
Gruß Christian
 
PS: Ich hoffe meine Sätze sind nicht ganz so wirr, wie sie mir gerade erscheinen, und meine Fragen verständlich :P
 
 
EDIT
Noch eine kleine Frage. Allerdings diesmal nicht zu ld...
Und zwar habe ich im Assemblerstub für GRUB folgenden Abschnitt:
[SECTION .bss]
ALIGN 32
stack:
resb OS_STACK_SIZE
Dieser Abschnitt reserviert Daten für den Stack (16 KiB). Die Sektion BSS deswegen, weil es sich ja um uninitialisierte Daten handelt. Nun verstehe ich allerdings nicht, warum darüber ein "ALIGN 32" steht.
12
OS-Design / Speicher > 4GB
« am: 27. August 2009, 11:37 »
Hallo Leute,
mir ist da etwas unklar...
Wenn ich eine 32-Bit Maschine mit sagen wir mal 16GB Arbeitsspeicher habe, muss ich ja die Page Address Extension aktivieren, um alles nutzen zu können.
 
Was passiert allerdings, wenn ein Prozess mehr als 4GB Speicher benötigt (unwahrscheinlich aber möglich)? Der Adressraum von 4GB bleibt ja bestehen, muss ich dann einen solchen Prozess terminieren oder kann man hier über Umwege auch mehr als 4GB zur Verfügung stellen?
 
Gruß Christian
13
Lowlevel-Coding / Bochs und der Debugger
« am: 21. August 2009, 09:33 »
Hallo Leute,
ich bin ja momentan dabei, den Code fürs Paging zu überarbeiten. Nun wird nicht merh von 0 bis zum ende des Kernels gemappt, sondern nur der Kernel, VGA Part, usw.
Nun nutze ich den Debugger von Bochs, um zu schauen, wie das ganze gemappt wurde, wo folgende Ausgabe hervorgegangen ist:
0x000b8000-0x000b8fff -> 0x000b8000-0x000b8fff
0x00100000-0x0010ffff -> 0x00100000-0x0010ffff
0x00112000-0x0011bfff -> 0x00112000-0x0011bfff
0xa0000000-0xa0000fff -> 0x00002000-0x00002fff
0xa0001000-0xa009bfff -> 0x00004000-0x0009efff
0xa009c000-0xa00b2fff -> 0x000a1000-0x000b7fff
0xa00b3000-0xa00e1fff -> 0x000b9000-0x000e7fff
0xa00e2000-0xa00e3fff -> 0x00110000-0x00111fff
0xa00e4000-0xa0100fff -> 0x0011c000-0x00138fff
Ich vermute ja mal, dass die verkorkste Ausgabe deswegen ist, da die physikalischen Speicherseiten nicht aneinanderliegen (die des Heaps, also ab 0xa0000000)... Sollte behoben sein, wenn ich die Speicherseiten nehme, die hinter dem Kernel liegen
 
Meine Frage ist nun folgende:
Gibt es die Möglichkeit, den Bochs Debugger so zu nutzen wie den "Debugger" von qemu? Dort habe ich die Möflichkeit, zu egal welcher Laufzeit mir die mappings oder die Register anzeigen zu lassen. Kann man dies irgendwie über die Konfigurationsdatei, die Bochs benötigt einstellen? Es ist nämlich mühselig, immer ein PANIC einzubauen und das dann per lb als Haltepunkt anzugeben.
14
OS-Design / Planung der Kernelentwicklung
« am: 13. August 2009, 14:46 »
Hallo Leute,
ich bin ja momentan damit beschäftigt, ein kleines Betriebssystem in Assembler zu schreiben, das von GRUB geladen wird. Das Laden passt und auch Text wird ausgegeben, was sicherlich noch verbessert werden muss.
Nun möchte ich allerdings nicht wieder den Fehler begehen und einfach drauf los zu schreiben, da ich deswegen immer wieder etliche Parts neu schreiben musste.
 
Ich frage mich nun, in wie weit ich dieses Projekt planen kann. Meine ersten Vorgabe sind einfach nur, dass es auf einem 32Bit Prozessor (i386-kompatibel) laufen muss und dass es ein Mikrokernel werden soll. Wie habt ihr die Projekte geplant? Überhaupt nicht, etwas, ...
Habt ihr da, falls geplant wurde, das ganze als normalen Text einfach geschrieben, wo die ganzen Vorgaben drinne standen/stehen (z.B. i386, Paging, Hardware Multitasking, ...) oder wie wurde das gemacht?
 
Gruß Christian
 
PS: Ich bin für jede Antwort dankbar.
15
Lowlevel-Coding / Kleiner Assembler Thread
« am: 13. August 2009, 08:40 »
Moin Moin,
da ich für diese Frage keinen passenden existierenden Thread gefunden habe, der halbwegs aktuell ist, erstelle ich mal wieder einen neuen.  :evil: Deswegen werde ich auch weitere Fragen dann hier stellen :)
 
Und zwar beschäftige ich mich einfach mal so etwas mehr mit Assembler, was heißt, ich habe meinen GRUB Assembler-Part, damit der Kernel überhaupt geladen wird, übernommen und bin dabei einen kleinen Kernel in reinem Assembler zu schreiben.
 
Das erste Hindernis hat aber leider nicht lange auf sich warten lassen.  :cry:
So sieht das momentan aus (klein und noch übersichtlich):
[SECTION .text]
global kernel_main
kernel_main:
push dword string ; parameter 1 der String
call video_write_string

ret

[SECTION .data]
string db "Hello World, From AsmOS",10,0

Wie man sieht, schiebe ich den String "string" als Parameter auf den Stack und rufe die Funktion auf. Hier versuche ich dann wie folgt den übergebenen String auszugeben:
video_write_string:
push ebp
;push edi
mov ebp, esp

mov esi, [ebp+8]
mov edi, 0xB8000
.printloop:
lodsb

test al, al
jz .printdone

stosb

mov al, 0x0F
stosb

jmp .printloop
.printdone:

mov esp, ebp
;pop edi
pop ebp
ret

Allerdings funktioniert dies nicht richtig. Der Ablauf ist, dass der string und danach einige kryptische Zeichen ausgegeben werden und dann anscheinend ein triple fault ausgelöst wird, da bochs neugestartet wird. Was habe ich hier falsch gemacht?  :?
 
Gruß Christian
16
Lowlevel-Coding / Kurze Frage zu GRUB
« am: 12. August 2009, 10:29 »
Guten Morgen,
ich habe eine kurze Frage zu GRUB, die mich schon länger plagt und auf die ich bisher keine Antwort finden konnte.
 
Und zwar macht Grub ja einige Ausgaben auf dem Bildschirm, wie z.B. die Adresse, wo der Kernel hingeladen wurde, usw.
Ich möchte nun mit den Textausgaben des Kernels an diese Ausgaben anschließen, also nicht wie zuvor erst den Bildschirm leeren und dann Text ausgeben. Ist das möglich? Kann ich die zuletzt beschriebene Adresse auslesen, oder wird diese von GRUB eventuell sogar mitgegeben?
 
Gruß Christian
17
Hallo,
ich bin mittlerweile so weit, dass mein Projekt Betriebssystem einfache Programme ausführen kann, die über System Calls Text ausgeben, Ports und Speicherbereiche anfordern können.
Die Anforderung von Speicherbereichen mappt den gewünschten Speicher, z.B. 0xa0000 einfach in den Usermode, ohne überhaupt zu prüfen, man könnte also den Kernel komplett in den Usermode mappen und dann überschreiben, was ja nicht sonderlich sicher ist. *g*
 
Wie macht ihr das?
Welche Ports werden einfach so dem Task zur verfügung gestellt und welche nicht?
Wie sieht das aus, wenn jetzt z.B. ein Grafiktreiber den Bereich 0xa0000 anfordert, werden da noch spezielle Prüfungen durchgeführt, damit nicht aus Versehen Bereiche des Kernels in den Usermode gemappt werden?

Gruß Christian
18
Lowlevel-Coding / TAR-Format im Kernel auslesen
« am: 24. July 2009, 08:18 »
Hallo Community,
ich habe mich dazu entschieden, meine initial ramdisk im TAR-Format abzulegen, was das ganze beim Zusammenbauen des Abbilds etwas einfacher macht, da ich nicht noch extra ein Programm schreiben muss.
 
Nun habe ich mir den Aufbau des Headers angeschaut und bei TAR wird alles als ASCII abgelegt, was so momentan ein Problem für mich ist. Und zwar habe ich als erstes eine Datei liegen, 8804 Byte groß ist (sagt 7-Zip und das Konsolenprogramm tar).
Nun ist im Header die Größe der Datei auch als char-Array angegeben und zwar mit 12 Feldern, quasi "char size[12];". Wie wandelt man dies um in einen Integer, damit ich weiß, wie groß die Datei ist?
Die Funktion "atoi" kann ich da leider nicht nutzen, da Sie bei meinem Test unter Windows 21144 zurückgegeben hat. In der Spezifikation steht allerdings, dass dieses Array die größe in Bytes enthält, was also dann nicht mittels atoi umgewandelt werden kann. Wie rechnet man das um?
 
Hier die Seite mit der Info über den Header: http://www.gnu.org/software/automake/manual/tar/Standard.html
19
Lowlevel-Coding / Multitasking - Frage zum Taskwechsel
« am: 01. July 2009, 09:52 »
Hallo,
ich habe da noch eine Frage zum Taskwechsel.
Ich pushe den kompletten Stack und rufe den Interrupt-Handler auf. Dieser ruft dann die Funktion zum Taskwechsel auf und übergibt den gepushten Stack. Also wie folgt:
u32int_t new_esp = multitasking_schedule(context);Wenn ich vom einen zum nächsten Prozess wechsle, speichere ich den Stack wie folgt:
// context needs to be saved when Multitasking is going around
// not directly after initialising it
if(current != NULL)
{
printf("0x%x - 0x%x - ", ((struct regs*)context)->esp, context);
current->kernel_stack = ((struct regs*)context)->esp;
//current->kernel_stack = context;
}


Meine Frage ist nun, muss ich esp des contexts speichern oder komplett den context?
 
 
Gruß Christian
20
OS-Design / Klassendesign
« am: 09. February 2009, 14:43 »
Hallo,
ich habe mir vor kurzem meinen Quellcode angesehen und da ist mir aufgefallen, dass viele Klassen totaler müll sind.  :roll:
 
Aufgrund dessen habe ich erst einmal alles entfernt, bis auf die Klassen für die GDT, IDT und ISRs, denn diese sind vom Aufbau her soweit okay. Nun habe ich mich also mal mit dem PIC beschäftigt und mir dazu eine Klasse ausgedacht.
Diese hat den folgenden Aufbau:
namespace kernel
{
class pic
{
DEF_SINGLETON(pic)

private:
/* method send a Initialisation Command Word
* [Param1]: specifies the art (data (1) or command (0))
* [Param2]: value for master pic
* [Param3]: value for slave pic
*/
void send_icw(unsigned int art, unsigned int value_mpic, unsigned int value_spic);

/* mehtod send an Operation Command Word
* [Param1]: specifies the art (data (1) or command (0))
* [Param2]: value for master pic
* [Param3]: value for slave pic
*/
void send_ocw(unsigned int art, unsigned int value_mpic, unsigned int value_spic);

/* method waits for an interrupt */
void io_wait(void);
public:
/* method initialises PIC and set the IDT entries */
void initialise(void);

/* mehtod send an "End of Interrupt" Signal
* [Param1]: handled interruptnumber
*/
void send_eoi(unsigned int irq);

/* method initialises PIC with the given start-interrupts of master and slave
* and disable all IRQs
* [Param1]: Interruptnumber where the master pic starts
* [Param2]: Interruptnumber where the slave pic starts
*/
void remap(unsigned int masterpic, unsigned int slavepic);

/* method masks (activates) an IRQ
* [Param1]: Interruptnumber which should be activated
*/
void mask_irq(unsigned int irq);

/* method unmasks (deactivates) an IRQ
* [Param1]: Interruptnumber which should be deactivated
*/
void unmask_irq(unsigned int irq);
};
}
Meine Frage nun an euch, was haltet ihr von diesem Aufbau? Habe ich vielleicht irgend etwas vergessen oder ist etwas in der Klasse, was nicht hinein gehört?
 
 
Gruß
Christian
Seiten: [1] 2

Einloggen