Hallo Coummunity,
ich habe ein neues Projekt für mich persönlich gestartet. Und zwar möchte ich gerne einen eigenen Mikrokernel haben.
Die Hauptzielplattform ist eigentlich ARM, habe das Projekt aber mal auf x86 gestartet.
Problem habe ich aber mit der GDT. Wenn ich die Werte für Base auf 0x0 und Limit auf 0xFFFFF setze, dann klappt alles wunderbar.
Auszug:
Sobald ich aber aber die Adresse vom .text Segment für Code und .rodata, .data usw. für Daten angebe, dann resetet QEMU.
Hab das ganze vorerst noch nicht auf echter Hardware ausprobiert. Weiß also nicht, ob sich echte Hardware gleich verhält.
Die Adressen von den Segmenten entnehme ich aus dem Linkerscript. Was aber leider nicht klappt:
Die Symbole lese ich mit Funktionen in Assembler ein, z.B.:
Hier ist die Funktion gdt_set_entry():
Ist hier eventuell ein Fehler?
ich habe ein neues Projekt für mich persönlich gestartet. Und zwar möchte ich gerne einen eigenen Mikrokernel haben.
Die Hauptzielplattform ist eigentlich ARM, habe das Projekt aber mal auf x86 gestartet.
Problem habe ich aber mit der GDT. Wenn ich die Werte für Base auf 0x0 und Limit auf 0xFFFFF setze, dann klappt alles wunderbar.
Auszug:
C:
static void gdt_init(void)
{
/* NULL entry */
gdt_set_entry(&gdt[0], 0, 0, 0, 0);
/* Kernel Code */
gdt_set_entry(&gdt[1], 0, 0xFFFFF, GDT_ACCESS_EXEC |
GDT_ACCESS_SEGMENT |
GDT_ACCESS_RING0 |
GDT_ACCESS_PRESENT,
GDT_FLAG_SIZE |
GDT_FLAG_GRAN);
/* Kernel Data */
gdt_set_entry(&gdt[2], 0, 0xFFFFF, GDT_ACCESS_RW |
GDT_ACCESS_SEGMENT |
GDT_ACCESS_RING0 |
GDT_ACCESS_PRESENT,
GDT_FLAG_SIZE |
GDT_FLAG_GRAN);
/* User Code */
gdt_set_entry(&gdt[3], 0, 0xFFFFF, GDT_ACCESS_EXEC |
GDT_ACCESS_SEGMENT |
GDT_ACCESS_RING3 |
GDT_ACCESS_PRESENT,
GDT_FLAG_SIZE |
GDT_FLAG_GRAN);
/* User Data */
gdt_set_entry(&gdt[4], 0, 0xFFFFF, GDT_ACCESS_RW |
GDT_ACCESS_SEGMENT |
GDT_ACCESS_RING3 |
GDT_ACCESS_PRESENT,
GDT_FLAG_SIZE |
GDT_FLAG_GRAN);
gdt_p.ptr = (uint32_t) &gdt[0];
gdt_p.limit = ((sizeof(struct gdt_entry) * GDT_ENTRIES) - 1);
_cpu_gdt_flush((uint32_t) &gdt_p, ((uint32_t )&gdt[2].lo - (uint32_t)&gdt[0].lo));
}
Sobald ich aber aber die Adresse vom .text Segment für Code und .rodata, .data usw. für Daten angebe, dann resetet QEMU.
Hab das ganze vorerst noch nicht auf echter Hardware ausprobiert. Weiß also nicht, ob sich echte Hardware gleich verhält.
Die Adressen von den Segmenten entnehme ich aus dem Linkerscript. Was aber leider nicht klappt:
Code:
ENTRY(_start)
SECTIONS {
. = 1M;
_kern_start = .;
.text ALIGN(4096) : {
_kern_text_start = .;
*(.multiboot)
*(.text)
_kern_text_end = .;
}
.rodata ALIGN(4096) : {
_kern_rodata_start = .;
*(.rodata)
_kern_rodata_end = .;
}
.data ALIGN(4096): {
_kern_data_start = .;
*(.data)
_kern_data_end = .;
}
.bss ALIGN(4096) : {
_kern_bss_start = .;
*(.bss)
_kern_bss_end = .;
}
.stack ALIGN(4096) : {
_kern_stack_start = .;
*(.stack)
_kern_stack_end = .;
}
.heap ALIGN(4096) : {
_kern_heap_start = .;
*(.heap)
_kern_heap_end = .;
}
_kern_end = .;
}
Die Symbole lese ich mit Funktionen in Assembler ein, z.B.:
C-ähnlich:
FUNCTION(_kern_text_get_addr)
pushl %ebp
movl %esp, %ebp
movl $_kern_text_start, %eax
leave
ret
FUNCTION(_kern_text_get_size)
pushl %ebp
movl %esp, %ebp
movl $_kern_text_start, %ebx
movl $_kern_text_end, %eax
sub %ebx, %eax
leave
ret
Hier ist die Funktion gdt_set_entry():
C:
#define GDT_ACCESS_RW 0x02
#define GDT_ACCESS_DIRECTION 0x04
#define GDT_ACCESS_EXEC 0x08
#define GDT_ACCESS_SEGMENT 0x10
#define GDT_ACCESS_RING0 0x00
#define GDT_ACCESS_RING1 0x20
#define GDT_ACCESS_RING2 0x40
#define GDT_ACCESS_RING3 0x60
#define GDT_ACCESS_PRESENT 0x80
#define GDT_FLAG_SIZE 0x04
#define GDT_FLAG_GRAN 0x08
static void gdt_set_entry(struct gdt_entry *entry,
uint32_t base,
uint32_t limit,
uint8_t access,
uint8_t flags)
{
if (!entry)
return;
entry->lo = (limit & 0xFFFF);
entry->lo |= ((base & 0xFFFF) << 16);
entry->hi = ((base & 0xFF0000) >> 16);
entry->hi |= (access << 8);
entry->hi |= (limit & 0xF0000);
entry->hi |= ((flags & 0xF) << 20);
entry->hi |= (base & 0xFF000000);
}
Ist hier eventuell ein Fehler?