From b836a372648b84c58ab175e5da4b300f08a4616d Mon Sep 17 00:00:00 2001 From: Ruslan Isaev Date: Mon, 14 Apr 2025 19:19:03 +0300 Subject: [PATCH] some test things --- Makefile | 7 +- link.ld | 42 +++++++++-- src/boot.asm | 176 +++++++++++++++++++++++++++-------------------- src/kernel/gdt.c | 171 +++++++++++++++++++++++++++++++++++++++++++++ src/mm/paging.c | 67 ++++++++++++++++++ 5 files changed, 379 insertions(+), 84 deletions(-) create mode 100644 src/kernel/gdt.c diff --git a/Makefile b/Makefile index 8b66f97..f7028a7 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ OBJS = bin/boot.o bin/kernel.o bin/idt.o bin/isr.o bin/screen.o \ bin/utils.o bin/string.o bin/stdio.o bin/disk.o bin/pic.o bin/pit.o \ bin/keyboard.o bin/paging.o bin/heap.o bin/page_alloc.o bin/page_tables.o \ - bin/fat.o bin/task.o bin/switch.o bin/sys_exit.o + bin/fat.o bin/task.o bin/switch.o bin/sys_exit.o bin/gdt.o # Define the compiler and assembler CC = gcc -D__is_katauos @@ -48,7 +48,7 @@ image: sudo losetup -D test: - qemu-system-i386 -drive file=boot.iso,media=disk,format=raw -m 512M -d int + qemu-system-i386 -drive file=boot.iso,media=disk,format=raw -m 4096M -d int #qemu-system-i386 -s -S -kernel myos.bin debug: @@ -120,6 +120,9 @@ bin/task.o: src/tasking/task.c bin/sys_exit.o: src/tasking/sys_exit.asm $(AS) $(ASFLAGS) $< -o $@ +bin/gdt.o: src/kernel/gdt.c + $(CC) $(CFLAGS) -c $< -o $@ + clean: rm -rf bin/ rm -f $(OUTPUT) diff --git a/link.ld b/link.ld index 2fe7329..b68a930 100644 --- a/link.ld +++ b/link.ld @@ -1,17 +1,45 @@ OUTPUT_FORMAT(elf32-i386) ENTRY(start) + +vaddr = 0xC0000000; /* virtual start address */ +paddr = 0x100000; /* physical address at 1MB */ + SECTIONS { . = 0x100000; + + .setup ALIGN(4096) : + { + *(.setup) + } + + . += vaddr; + .text BLOCK(4K) : ALIGN(4K) { - *(.multiboot) *(.text) } - .rodata BLOCK(4K) : ALIGN(4K) { *(.rodata) } - .data BLOCK(4K) : ALIGN(4K) { *(.data) } - .bss BLOCK(4K) : ALIGN(4K) { - *(.COMMON) - *(.bss) + _etext = .; + + .data ALIGN(4096) : AT(ADDR(.data) - vaddr) + { + *(.data) + *(.rodata*) } - kernel_end = .; + _edata = .; + + /* uninitialized data */ + .bss ALIGN(4096) : AT(ADDR(.bss) - vaddr) + { + *(COMMON*) + *(.bss*) + } + _end = .; + +/DISCARD/ : + { + *(.comment) + *(.eh_frame) + *(.note*) + } + } diff --git a/src/boot.asm b/src/boot.asm index 2ca9b5b..c115b94 100644 --- a/src/boot.asm +++ b/src/boot.asm @@ -1,96 +1,122 @@ bits 32 -section .multiboot - align 4 - dd 0x1BADB002 - dd 0x00 - dd - (0x1BADB002+0x00) +%define CR0_MP 0x00000002 /* bit 01 -> enable monitor coprocessor */ +%define CR0_NE 0x00000020 /* bit 05 -> enable native x87 FPU mode */ +%define CR0_WP 0x00010000 /* bit 16 -> enable write protect (for CoW) */ +%define CR0_AM 0x00040000 /* bit 18 -> enable alignment checking */ +%define CR0_PG 0x80000000 /* bit 31 -> enable paging */ -section .data +%define PAGE_OFFSET 0xC0000000 +%define GDT_BASE (0xFFFFFFFF - (PAGE_OFFSET - 1)) + +section .setup align 4 -multiboot_info: - dd 0 - dd 0 - dd 0 - dd 0 - dd 0 - dd 0 - dd 0 +tmp_gdtr: + dw ((3 * 8) - 1) +tmp_gdta: + dd tmp_gdt -global tss -global tss_end align 4 -tss: - dd 0 ; 0-3 - dd stack_top ; 4-7 - dd DATA_SEG ; 8-11 - dd 0 ; 12-15 - dd 0 ; 16-19 - dd 0 ; 20-23 - dd 0 ; 24-27 - dd 0 ; 28-31 - dd 0 ; 32-35 - dd 0 ; 36-39 - dd 0 ; 40-43 - dd 0 ; 44-47 - dd 0 ; 48-51 - dd 0 ; 52-55 - dd 0 ; 56-59 - dd 0 ; 60-63 - dd 0 ; 64-67 - dd 0 ; 68-71 - dd DATA_SEG ; 72-75 - dd CODE_SEG ; 76-79 - dd DATA_SEG ; 80-83 - dd DATA_SEG ; 84-87 - dd DATA_SEG ; 88-91 - dd DATA_SEG ; 92-95 - dd 0 ; 96-99 - dw 0 ; 100-101 - dw 104 ; 102-103 -tss_end: +tmp_gdt: + ; null entry + dw 0x0000 + dw 0x0000 + dw 0x0000 + dw 0x0000 -section .bss -stack_bottom: -resb 16384 -stack_top: + ; /* KERNEL CODE */ + dw 0xFFFF ; /* segment limit 15-00 */ + dw 0x0000 ; /* base address 15-00 */ + db 0x00 ; /* base address 23-16 */ + db 0x9A ; /* P=1 DPL=00 S=1 TYPE=1010 (exec/read) */ + db 0xCF ; /* G=1 DB=1 0=0 AVL=0 SEGLIM=1111 */ + db GDT_BASE >> 24 ; /* base address 31-24 */ + ; /* KERNEL DATA */ + dw 0xFFFF ; /* segment limit 15-00 */ + dw 0x0000 ; /* base address 15-00 */ + db 0x00 ; /* base address 23-16 */ + db 0x92 ; /* P=1 DPL=00 S=1 TYPE=0010 (read/write) */ + db 0xCF ; /* G=1 DB=1 0=0 AVL=0 SEGLIM=1111 */ + db GDT_BASE >> 24 ; /* base address 31-24 */ -section .gdt -%include "src/gdt.asm" +align 4 +multiboot_header: + dd 0x1BADB002 + dd 0x00 + dd - (0x1BADB002 + 0x00) -section .text + dd 0 + dd 0 + dd 0 + dd 0 + dd 0 + dd 0 + dd 0 + dd 0 + dd 0 + +; section .text global start:function (start.end - start) extern kmain ; this function is gonna be located in our c code(kernel.c) +extern get_last_boot_addr +extern gdt_init +extern bss_init +extern setup_tmp_pgdir +align 4 start: - mov esp, stack_top +; mov esp, stack_top cli - push ebx ; Сохраняем оригинальный ebx (указатель Multiboot) + ; push ebx ; Сохраняем оригинальный ebx (указатель Multiboot) - lgdt [gdt] + ;lgdt [gdt] + lgdt [tmp_gdtr] - ; Заполняем адрес TSS в дескрипторе GDT - mov eax, tss ; Получаем 32-битный адрес tss - mov ebx, gdt_tss ; Адрес дескриптора TSS в GDT - mov [ebx + 2], ax ; Нижние 16 бит адреса TSS - shr eax, 16 ; Сдвигаем для доступа к старшим битам - mov [ebx + 4], al ; Средние 8 бит адреса TSS - mov [ebx + 7], ah ; Верхние 8 бит адреса TSS + mov cx, 0x10 ; data segment + mov ds, cx + mov es, cx + mov fs, cx + mov gs, cx + mov ss, cx + jmp 0x8:.huita ; 0x8 - code segment - mov ax, DATA_SEG - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - jmp CODE_SEG:.huita +.text +align 4 .huita: - mov ax, TSS_SEG - ltr ax - pop ebx ; Восстанавливаем оригинальный ebx - push ebx ; Передаем его в kmain - call kmain - hlt + mov esp, PAGE_OFFSET + 0x10000 ; default stack address + push 0 + popf ; reset EFLAGS + + push ebx ; save Multiboot info structure + push eax ; save Multiboot magic value + + call setup_tmp_pgdir + mov cr3, eax + + mov eax, cr0 + and eax, 0x00000011 ; disable all, preserve ET & PE (GRUB) + or eax, 0x80000000 ; CR0_PG ; enable PG + or eax, 0x40000 ; CR0_AM ; enable AM + or eax, 0x10000 ; CR0_WP ; enable WP + or eax, 0x20 ; CR0_NE ; enable NE + or eax, 0x2 ; CR0_MP ; enable MP + mov cr0, eax + + call bss_init ; initialize BSS segment + call gdt_init ; setup and load definitive GDT + call get_last_boot_addr + + pop ecx ; restore Multiboot magic value + pop ebx ; restore Multiboot info structure + + push eax ; save last boot address + push ebx ; save Multiboot info structure + push ecx ; save Multiboot magic value + + pop ebx ; Восстанавливаем оригинальный ebx + push ebx ; Передаем его в kmain + call kmain + hlt .end: diff --git a/src/kernel/gdt.c b/src/kernel/gdt.c new file mode 100644 index 0000000..b49522d --- /dev/null +++ b/src/kernel/gdt.c @@ -0,0 +1,171 @@ +//#include "../include/gdt.h" +#include +#include "../include/string.h" + +struct desc_r { + uint16_t limit; + uint32_t base_addr; +} __attribute__((packed)); + +struct seg_desc { + unsigned sd_lolimit : 16; /* segment limit 0-15 bits */ + unsigned sd_lobase : 24; /* base address 0-23 bits */ + unsigned sd_loflags : 8; /* flags (P, DPL, S and TYPE) */ + unsigned sd_hilimit : 4; /* segment limit 16-19 bits */ + unsigned sd_hiflags : 4; /* flags (G, DB, 0 and AVL) */ + unsigned sd_hibase : 8; /* base address 24-31 bits */ +} __attribute__((packed)); + +struct gate_desc { + unsigned gd_looffset: 16; /* offset 0-15 bits */ + unsigned gd_selector: 16; /* segment selector */ + unsigned gd_flags : 16; /* flags (P, DPL, TYPE, 0 and NULL) */ + unsigned gd_hioffset: 16; /* offset 16-31 bits */ +} __attribute__((packed)); + +extern char _end[], _edata[]; + +#define KERNEL_CS 0x08 /* kernel code segment */ +#define KERNEL_DS 0x10 /* kernel data segment */ +#define USER_CS 0x18 /* user code segment */ +#define USER_DS 0x20 /* user data segment */ +#define TSS 0x28 /* TSS segment */ + + +void load_gdt(uint32_t gdt_ptr) { + asm volatile ( + "lgdt (%0)\n\t" + "movw %1, %%ax\n\t" + "movw %%ax, %%ds\n\t" + "movw %%ax, %%es\n\t" + "movw %%ax, %%fs\n\t" + "movw %%ax, %%gs\n\t" + "movw %%ax, %%ss\n\t" + "ljmp %2, $1f\n\t" + "1:\n\t" + : + : "r" (gdt_ptr), "i" (KERNEL_DS), "i" (KERNEL_CS) + : "eax" + ); +} + +#define PAGE_SIZE 4096 +#define PAGE_SHIFT 0x0C + +#define PAGE_MASK ~(PAGE_SIZE - 1) /* 0xFFFFF000 */ +#define PAGE_ALIGN(addr) (((addr) + (PAGE_SIZE - 1)) & PAGE_MASK) + +#define KERNEL_BSS_SIZE ((int)_end - (int)_edata) + +#define NR_GDT_ENTRIES 6 /* entries in GDT descriptor */ +#define NR_IDT_ENTRIES 256 /* entries in IDT descriptor */ + +/* low flags of Segment Descriptors */ +#define SD_CODE 0x0A /* CODE Exec/Read */ +#define SD_DATA 0x02 /* DATA Read/Write */ + +#define SD_32INTRGATE 0x0E /* 32-bit Interrupt Gate (0D110) */ +#define SD_32TRAPGATE 0x0F /* 32-bit Trap Gate (0D111) */ + +#define SD_CD 0x10 /* 0 = system / 1 = code/data */ +#define SD_DPL0 0x00 /* priority level 0 (kernel) */ +#define SD_DPL3 0x60 /* priority level 3 (user) */ +#define SD_PRESENT 0x80 /* segment present or valid */ + +/* high flags Segment Descriptors */ +#define SD_OPSIZE32 0x04 /* 32-bit code and data segments */ +#define SD_PAGE4KB 0x08 /* page granularity (4KB) */ + +/* low flags of the TSS Descriptors */ +#define SD_TSSPRESENT 0x89 /* TSS present and not busy flag */ + +/* EFLAGS */ +#define EF_IOPL 12 /* IOPL bit */ + +#define KERNEL_CS 0x08 /* kernel code segment */ +#define KERNEL_DS 0x10 /* kernel data segment */ +#define USER_CS 0x18 /* user code segment */ +#define USER_DS 0x20 /* user data segment */ +#define TSS 0x28 /* TSS segment */ + + +struct tss_entry_struct { + uint32_t prev_tss; // The previous TSS - with hardware task switching these form a kind of backward linked list. + uint32_t esp0; // The stack pointer to load when changing to kernel mode. + uint32_t ss0; // The stack segment to load when changing to kernel mode. + // Everything below here is unused. + uint32_t esp1; // esp and ss 1 and 2 would be used when switching to rings 1 or 2. + uint32_t ss1; + uint32_t esp2; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t fs; + uint32_t gs; + uint32_t ldt; + uint16_t trap; + uint16_t iomap_base; +} __packed; + +void bss_init() +{ + memset((void *)((int)_edata), 0, KERNEL_BSS_SIZE); +} + +uint32_t get_last_boot_addr() +{ + return ((unsigned int)_end & PAGE_MASK) + PAGE_SIZE; +} + +struct seg_desc gdt[NR_GDT_ENTRIES]; + +struct desc_r gdtr = { + sizeof(gdt) - 1, + (unsigned int)&gdt +}; + +static void gdt_set_entry(int num, unsigned int base_addr, unsigned int limit, char loflags, char hiflags) +{ + num /= sizeof(struct seg_desc); + gdt[num].sd_lolimit = limit & 0xFFFF; + gdt[num].sd_lobase = base_addr & 0xFFFFFF; + gdt[num].sd_loflags = loflags; + gdt[num].sd_hilimit = (limit >> 16) & 0x0F; + gdt[num].sd_hiflags = hiflags; + gdt[num].sd_hibase = (base_addr >> 24) & 0xFF; +} + +void gdt_init(void) +{ + unsigned char loflags; + + gdt_set_entry(0, 0, 0, 0, 0); /* null descriptor */ + + loflags = SD_CODE | SD_CD | SD_DPL0 | SD_PRESENT; + gdt_set_entry(KERNEL_CS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB); + loflags = SD_DATA | SD_CD | SD_DPL0 | SD_PRESENT; + gdt_set_entry(KERNEL_DS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB); + + loflags = SD_CODE | SD_CD | SD_DPL3 | SD_PRESENT; + gdt_set_entry(USER_CS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB); + loflags = SD_DATA | SD_CD | SD_DPL3 | SD_PRESENT; + gdt_set_entry(USER_DS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB); + + loflags = SD_TSSPRESENT; + gdt_set_entry(TSS, 0, sizeof(struct tss_entry_struct), loflags, SD_OPSIZE32); + + load_gdt((unsigned int)&gdtr); +} diff --git a/src/mm/paging.c b/src/mm/paging.c index 4eb0764..0fad5af 100644 --- a/src/mm/paging.c +++ b/src/mm/paging.c @@ -1,10 +1,77 @@ #include "../include/paging.h" #include +#include "../include/multiboot.h" +#include "../include/string.h" uint32_t kernel_page_directory[1024] __attribute__((aligned(4096))); uint32_t kernel_page_table[1024] __attribute__((aligned(4096))); uint32_t user_page_table[1024] __attribute__((aligned(4096))); +#define PAGE_OFFSET 0xC0000000 +#define PAGE_SIZE 4096 + +#define PAGE_PRESENT 0x1 +#define PAGE_RW 0x002 /* Read/Write */ +#define PAGE_USER 0x004 /* User */ +#define PAGE_NOALLOC 0x200 /* No Page Allocated (OS managed) */ + +#define PAGE_SHIFT 0x0C +#define PAGE_MASK ~(PAGE_SIZE - 1) /* 0xFFFFF000 */ + +#define GDT_BASE (0xFFFFFFFF - (PAGE_OFFSET - 1)) + +#define GET_PGDIR(address) ((unsigned int)((address) >> 22) & 0x3FF) +#define GET_PGTBL(address) ((unsigned int)((address) >> 12) & 0x3FF) + +#define PAGE_ALIGN(addr) (((addr) + (PAGE_SIZE - 1)) & PAGE_MASK) + +unsigned int *kpage_dir; + +unsigned int setup_tmp_pgdir(unsigned int magic, unsigned int info) +{ + int n, pd; + unsigned int addr, memksize; + unsigned int *pgtbl; + struct multiboot_info *mbi; + + if(magic != MULTIBOOT_BOOTLOADER_MAGIC) { + /* 4MB of memory assumed */ + memksize = 4096; + } else { + mbi = (struct multiboot_info *)(PAGE_OFFSET + info); + if(!(mbi->flags & MULTIBOOT_INFO_MEMORY)) { + /* 4MB of memory assumed */ + memksize = 4096; + } else { + /* we need to add the first 1MB to memksize */ + memksize = (unsigned int)mbi->mem_upper + 1024; + /* CONFIG_VM_SPLIT22 marks the maximum physical memory supported */ + if(memksize > ((0xFFFFFFFF - PAGE_OFFSET) / 1024)) { + memksize = (0xFFFFFFFF - PAGE_OFFSET) / 1024; + } + } + } + + addr = PAGE_OFFSET + (memksize * 1024) - memksize; + addr = PAGE_ALIGN(addr); + + kpage_dir = (unsigned int *)addr; + memset(kpage_dir, 0, PAGE_SIZE); + + addr += PAGE_SIZE; + pgtbl = (unsigned int *)addr; + memset(pgtbl, 0, memksize); + + for(n = 0; n < memksize / sizeof(unsigned int); n++) { + pgtbl[n] = (n << PAGE_SHIFT) | PAGE_PRESENT | PAGE_RW; + if(!(n % 1024)) { + pd = n / 1024; + kpage_dir[pd] = (unsigned int)(addr + (PAGE_SIZE * pd) + GDT_BASE) | PAGE_PRESENT | PAGE_RW; + kpage_dir[GET_PGDIR(PAGE_OFFSET) + pd] = (unsigned int)(addr + (PAGE_SIZE * pd) + GDT_BASE) | PAGE_PRESENT | PAGE_RW; + } + } + return (unsigned int)kpage_dir - PAGE_OFFSET; +} void enablePaging() { asm volatile (