Non-flat segmentation set from C

Playing with non-flat segmentation, but it seems that it won't be
feasible to use it with C programs - implementing paging and flat
segmentation scheme will be neceassary.
This commit is contained in:
Maciej Krzyżanowski 2023-11-03 14:13:33 +01:00
parent 4fc60d7440
commit 47990aac56
2 changed files with 102 additions and 74 deletions

56
boot.s
View File

@ -29,17 +29,14 @@
.section .bss .section .bss
.align 16 .align 16
.global stack_top
.global stack_bottom
stack_bottom: stack_bottom:
/* Stos o wielkości 16 KB */ /* Stos o wielkości 16 KB */
.skip 16834 .skip 16384
stack_top: stack_top:
.section .data .section .data
/* 31, bo będą 4 deskryptory po 8 bajtów, a przekazujemy wielkość - 1*/
// TODO
gdtr: .word 23
/* Na 4 MiB daję bazę dla GDT, czyli tam gdzie zaczynają się dane kernela */
gdtb: .long 0x400000
/* /*
Oznaczenie startu, tu zaczyna się kod kernela! Oznaczenie startu, tu zaczyna się kod kernela!
@ -48,48 +45,23 @@ gdtb: .long 0x400000
.global _start .global _start
.type _start, @function .type _start, @function
_start: _start:
/* Tutaj podobno jest tryb chroniony już, jednak zastanawia czy faktycznie
* bootloader ustawia za nas segmentacje pamięci?
* EDIT: Ustawia, ale pod własne potrzeby, więc i tak trzeba zmienić
* Ustawię zatem najprostszy model segmentacji */
// Domyślne ustawienia z GRUB-a są takie, że pomijają segmentację!
// Dodam w ramach segmentu danych kernela, czyli u mnie 4-8 MiB
mov gdtb, %eax
// 1. Pusty (null) deskryptor
movl $0, (%eax)
movl $0, 4(%eax)
// 2. Deskryptor kodu jądra
movl $0x000003FF, 8(%eax)
movl $0x00c09800, 12(%eax)
// 3. Deskryptor danych jądra
movl $0x000003FF, 16(%eax)
movl $0x00C09240, 20(%eax)
// 4. Deskryptor kodu użytkownika
// 6. Load GDT
lgdt (gdtr)
// 7. Refresh registers
mov %cs, 8(%eax)
mov %ds, 16(%eax)
mov %es, 16(%eax)
mov %fs, 16(%eax)
mov %gs, 16(%eax)
mov %ss, 16(%eax)
// Wpisywane jest i tak pod %ds:64
movb $69, (64)
/* Ustawienie ESP na wierzchołek stosu */ /* Ustawienie ESP na wierzchołek stosu */
mov $stack_top, %esp mov $stack_top, %esp
/* Tutaj jakieś ustawienia inicjalizacyjne trzeba zrobić normalnie */
//mov $69, %esi
//mov $_start, %edi
/* Wywołanie kernela */ /* Wywołanie kernela */
call kernel_main call kernel_main
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
jmp $0x08,$cs_refresh
cs_refresh:
mov $0x4000, %esp
push $5
/* Wieczne oczekiwanie po zakończeniu kodu kernela */ /* Wieczne oczekiwanie po zakończeniu kodu kernela */
cli cli
1: hlt 1: hlt

120
kernel.c
View File

@ -164,24 +164,45 @@ void terminal_write(const char *data, size_t size)
} }
} }
void terminal_writenum(uint64_t number, int base) // Pad length is what number length should be, including padding
void terminal_writenumpad(uint64_t number, int base, int pad_length)
{ {
char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
size_t size = 0; int size = 0;
char numChars[32]; char numChars[32];
while (number != 0) if (number == 0)
{ {
uint64_t rest = number / base; numChars[31] = '0';
uint64_t digit = number % base; size = 1;
}
else
{
while (number != 0)
{
uint64_t rest = number / base;
uint64_t digit = number % base;
numChars[31 - size++] = digits[digit]; numChars[31 - size++] = digits[digit];
number = rest; number = rest;
}
}
// Write pad_length - size of zeros
// If padding won't be needed (number is longer than pad_legnth)
// then loop won't run at all
while (pad_length > size) {
numChars[31 - size++] = digits[0];
} }
terminal_write(numChars + (32 - size), size); terminal_write(numChars + (32 - size), size);
} }
void terminal_writenum(uint64_t number, int base)
{
terminal_writenumpad(number, base, 0);
}
void terminal_writestring(const char *data) void terminal_writestring(const char *data)
{ {
terminal_write(data, strlen(data)); terminal_write(data, strlen(data));
@ -230,7 +251,7 @@ struct gdt_entry {
#define KERNEL_SEGMENT 0 #define KERNEL_SEGMENT 0
#define USER_SEGMENT 1 #define USER_SEGMENT 1
#define CODE_SEGMENT 0 #define CODE_SEGMENT 0
#define USER_SEGMENT 1 #define DATA_SEGMENT 1
struct gdt_entry gdt_entry_create(size_t start_address, size_t pages_size, struct gdt_entry gdt_entry_create(size_t start_address, size_t pages_size,
int kernel_or_user, int code_or_data) int kernel_or_user, int code_or_data)
@ -276,11 +297,13 @@ struct gdt_entry gdt_entry_create(size_t start_address, size_t pages_size,
// F = G DB L - // F = G DB L -
uint64_t gdt_entry_encode(struct gdt_entry entry) uint64_t gdt_entry_encode(struct gdt_entry entry)
{ {
entry.base = entry.base << 12;
uint64_t gdt_encoded = 0; uint64_t gdt_encoded = 0;
// Insert base // Insert base
gdt_encoded |= ((uint64_t) (entry.base & 0xFF000000) << 32); gdt_encoded |= ((((uint64_t) entry.base) & 0xFF000000) << 32);
gdt_encoded |= ((uint64_t) (entry.base & 0x00FFFFFF) << 16); gdt_encoded |= ((((uint64_t) entry.base) & 0x00FFFFFF) << 16);
// Insert limit // Insert limit
gdt_encoded |= ((uint64_t) (entry.limit & 0xF0000) << 32); gdt_encoded |= ((uint64_t) (entry.limit & 0xF0000) << 32);
@ -306,14 +329,15 @@ uint64_t gdt_entry_encode(struct gdt_entry entry)
access_byte |= entry.was_accessed; access_byte |= entry.was_accessed;
// Insert access byte // Insert access byte
gdt_encoded |= (access_byte << 20); gdt_encoded |= (access_byte << 40);
return gdt_encoded; return gdt_encoded;
} }
struct gdt_table { struct __attribute__((__packed__)) gdt_table
uint16_t entries_count; {
uint32_t *dest_pointer; uint16_t size_in_bytes;
uint64_t *dest_pointer;
struct gdt_entry entries[16]; struct gdt_entry entries[16];
}; };
@ -323,26 +347,19 @@ void apply_table(struct gdt_table table)
uint64_t null_entry_encoded = 0; uint64_t null_entry_encoded = 0;
*table.dest_pointer = null_entry_encoded; *table.dest_pointer = null_entry_encoded;
for (int i = 0; i < table.entries_count; i++) int entries_count = (table.size_in_bytes + 1) / 8;
for (int i = 0; i < entries_count; i++)
{ {
uint64_t entry_encoded = gdt_entry_encode(table.entries[i]); uint64_t entry_encoded = gdt_entry_encode(table.entries[i]);
uint32_t *dest_address = table.dest_pointer + (i + 1) * 8; uint64_t *dest_address = table.dest_pointer + i + 1;
*dest_address = entry_encoded; *dest_address = entry_encoded;
} }
__asm__("lgdt (%0)" : : "r" (&table)); __asm__("lgdt (%0)" : : "r" (&table));
} }
void kernel_main(void) void print_texts()
{ {
/*
* Initialize terminal interface
*/
terminal_initialize();
/*
* Newline support is left as an exercise.
*/
terminal_writestring("TEGO NIE POWINNO BYC WIDAC\n"); terminal_writestring("TEGO NIE POWINNO BYC WIDAC\n");
terminal_writestring terminal_writestring
("Witam i pozdrawiam, MK\nTest wielolinijkowosci\n"); ("Witam i pozdrawiam, MK\nTest wielolinijkowosci\n");
@ -374,11 +391,50 @@ void kernel_main(void)
size_t human_readable = start_point / (1024 * 1024); size_t human_readable = start_point / (1024 * 1024);
terminal_writenum(human_readable, 10); terminal_writenum(human_readable, 10);
terminal_writestring(" MiB\n"); terminal_writestring(" MiB\n");
}
terminal_writestring("Test wpisu GDT:\n");
struct gdt_entry entry = void gdt_setup()
gdt_entry_create(0, 0x400, KERNEL_SEGMENT, CODE_SEGMENT); {
uint64_t entry_encoded = gdt_entry_encode(entry); struct gdt_entry kernel_code_entry =
terminal_writenum(entry_encoded, 16); gdt_entry_create(0, 0x400, KERNEL_SEGMENT, CODE_SEGMENT);
terminal_newline(); struct gdt_entry kernel_data_entry =
gdt_entry_create(0x400, 0x400, KERNEL_SEGMENT, DATA_SEGMENT);
struct gdt_entry user_code_entry =
gdt_entry_create(0x800, 0x400, USER_SEGMENT, CODE_SEGMENT);
struct gdt_entry user_data_entry =
gdt_entry_create(0xC00, 0x400, USER_SEGMENT, DATA_SEGMENT);
struct gdt_table gdt_table;
gdt_table.size_in_bytes = 39;
gdt_table.dest_pointer = (uint64_t*)0x400000;
gdt_table.entries[0] = kernel_code_entry;
gdt_table.entries[1] = kernel_data_entry;
gdt_table.entries[2] = user_code_entry;
gdt_table.entries[3] = user_data_entry;
apply_table(gdt_table);
terminal_writestring("GDT table applied\n");
__asm__ volatile(
"mov $stack_bottom, %%esi;"
"mov $0x500000, %%edi;"
"mov $16384, %%ecx;"
"cld;"
"rep movsb;"
:
:
:
"esi","edi","ecx"
);
__asm__(
"xchg %bx, %bx"
);
}
void kernel_main(void)
{
terminal_initialize();
print_texts();
gdt_setup();
} }