From 47990aac566ab53dd4e1b9f6c5e383311659c6e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Krzy=C5=BCanowski?= Date: Fri, 3 Nov 2023 14:13:33 +0100 Subject: [PATCH] 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. --- boot.s | 56 +++++++------------------- kernel.c | 120 ++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 102 insertions(+), 74 deletions(-) diff --git a/boot.s b/boot.s index 467845a..fdf0b03 100644 --- a/boot.s +++ b/boot.s @@ -29,17 +29,14 @@ .section .bss .align 16 +.global stack_top +.global stack_bottom stack_bottom: /* Stos o wielkości 16 KB */ -.skip 16834 +.skip 16384 stack_top: .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! @@ -48,48 +45,23 @@ gdtb: .long 0x400000 .global _start .type _start, @function _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 */ mov $stack_top, %esp -/* Tutaj jakieś ustawienia inicjalizacyjne trzeba zrobić normalnie */ -//mov $69, %esi -//mov $_start, %edi - /* Wywołanie kernela */ 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 */ cli 1: hlt diff --git a/kernel.c b/kernel.c index b0f2b00..fbde3b0 100644 --- a/kernel.c +++ b/kernel.c @@ -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"; - size_t size = 0; + int size = 0; char numChars[32]; - while (number != 0) + if (number == 0) { - uint64_t rest = number / base; - uint64_t digit = number % base; + numChars[31] = '0'; + size = 1; + } + else + { + while (number != 0) + { + uint64_t rest = number / base; + uint64_t digit = number % base; - numChars[31 - size++] = digits[digit]; - number = rest; + numChars[31 - size++] = digits[digit]; + 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); } +void terminal_writenum(uint64_t number, int base) +{ + terminal_writenumpad(number, base, 0); +} + void terminal_writestring(const char *data) { terminal_write(data, strlen(data)); @@ -230,7 +251,7 @@ struct gdt_entry { #define KERNEL_SEGMENT 0 #define USER_SEGMENT 1 #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, 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 - uint64_t gdt_entry_encode(struct gdt_entry entry) { + entry.base = entry.base << 12; + uint64_t gdt_encoded = 0; // Insert base - gdt_encoded |= ((uint64_t) (entry.base & 0xFF000000) << 32); - gdt_encoded |= ((uint64_t) (entry.base & 0x00FFFFFF) << 16); + gdt_encoded |= ((((uint64_t) entry.base) & 0xFF000000) << 32); + gdt_encoded |= ((((uint64_t) entry.base) & 0x00FFFFFF) << 16); // Insert limit 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; // Insert access byte - gdt_encoded |= (access_byte << 20); + gdt_encoded |= (access_byte << 40); return gdt_encoded; } -struct gdt_table { - uint16_t entries_count; - uint32_t *dest_pointer; +struct __attribute__((__packed__)) gdt_table +{ + uint16_t size_in_bytes; + uint64_t *dest_pointer; struct gdt_entry entries[16]; }; @@ -323,26 +347,19 @@ void apply_table(struct gdt_table table) uint64_t null_entry_encoded = 0; *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]); - uint32_t *dest_address = table.dest_pointer + (i + 1) * 8; + uint64_t *dest_address = table.dest_pointer + i + 1; *dest_address = entry_encoded; } __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 ("Witam i pozdrawiam, MK\nTest wielolinijkowosci\n"); @@ -374,11 +391,50 @@ void kernel_main(void) size_t human_readable = start_point / (1024 * 1024); terminal_writenum(human_readable, 10); terminal_writestring(" MiB\n"); - - terminal_writestring("Test wpisu GDT:\n"); - struct gdt_entry entry = - gdt_entry_create(0, 0x400, KERNEL_SEGMENT, CODE_SEGMENT); - uint64_t entry_encoded = gdt_entry_encode(entry); - terminal_writenum(entry_encoded, 16); - terminal_newline(); +} + +void gdt_setup() +{ + struct gdt_entry kernel_code_entry = + gdt_entry_create(0, 0x400, KERNEL_SEGMENT, CODE_SEGMENT); + 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(); }