diff --git a/arch/i386/boot.S b/arch/i386/boot.S index c28621b..13d29fd 100755 --- a/arch/i386/boot.S +++ b/arch/i386/boot.S @@ -6,25 +6,93 @@ .set CHECKSUM, -(MAGIC + FLAGS) # checksum to prove we're multiboot # Declare header for multiboot - .section .multiboot + .section .multiboot.data, "aw" .align 4 .long MAGIC .long FLAGS .long CHECKSUM # Reserve stack for initial thread - .section .bss - .align 16 + .section .bootstrap_stack, "aw", @nobits stack_bottom: .skip 16384 # 16K stack_top: + # Preallocate pages for paging + .section .bss, "aw", @nobits + .align 4096 +boot_page_directory: + .skip 4096 +boot_page_table1: + .skip 4096 + # May need additional page for kernel > 3 MiB + # Kernel entry - .section .text + .section .multiboot.text, "a" .global _start .type _start, @function _start: - movl $stack_top, %esp + # Physical address of boot_page_table 1 + movl $(boot_page_table1 - 0xC0000000), %edi + # Map address 0 + movl $0, %esi + # Map first 1023 pages + movl $1023, %ecx + +1: + # Only map the kernel + cmpl $_kernel_start, %esi + jl 2f + cmpl $(_kernel_end - 0xC0000000), %esi + jge 3f + + # Map physical address as "present, writable" + # TODO: map .text and .rodata as non-writable + movl %esi, %edx + orl $0x003, %edx + movl %edx, (%edi) + +2: + # Size of page is 4KiB + addl $4096, %esi + # Size of entries in boot_page_table1 is 4 bytes + addl $4, %edi + # Loop to next if not done + loop 1b + +3: + # Map VGA memory to 0xC03FF000 as "present, writable" + movl $(0x000B8000 | 0x003), boot_page_table1 - 0xC0000000 + 1023 * 4 + + # Map page table to 0x0 and 0xC0000000 + movl $(boot_page_table1 - 0xC0000000 + 0x003), boot_page_directory - 0xC0000000 + 0 + movl $(boot_page_table1 - 0xC0000000 + 0x003), boot_page_directory - 0xC0000000 + 768 * 4 + + # Set cr3 to address of boot page directory + movl $(boot_page_directory - 0xC0000000), %ecx + movl %ecx, %cr3 + + # Enable paging and write-protect + movl %cr0, %ecx + orl $0x80010000, %ecx + movl %ecx, %cr0 + + # Jump to higher half + lea 4f, %ecx + jmp *%ecx + + .section .text + +4: + # Unmap identity mapping + movl $0, boot_page_directory + 0 + + # Reload cr3 to force TLB flush + movl %cr3, %ecx + movl %ecx, %cr3 + + # Set up stack + mov $stack_top, %esp # Call global constructors call _init @@ -36,4 +104,3 @@ _start: cli 1: hlt jmp 1b - .size _start, . - _start diff --git a/arch/i386/init.c b/arch/i386/init.c index 7645b57..5e88ff3 100755 --- a/arch/i386/init.c +++ b/arch/i386/init.c @@ -3,6 +3,7 @@ #include #include #include "gdt.h" +#include "ps2_kbd.h" int tss[16][2]; @@ -42,11 +43,84 @@ void setup_gdt(void) { extern void enter_pmode(void); +int initialize_ps2_kbd() { + /* Should really make sure PS/2 controller exists here: */ + + /* Disable devices */ + outb(0xAD, 0x64); + outb(0xA7, 0xAD); + + /* Flush output buffer */ + get_ps2_inbyte(); + + /* Set config byte */ + outb(0x20, 0x64); + unsigned char config_byte = get_ps2_inbyte(); + int is_dual_ch = (config_byte & 020) != 0 ? 1 : 0; + config_byte &= 0274; + outb(0x60, 0x64); + outb(config_byte, 0x60); + + /* Quick self-test */ + outb(0xAA, 0x64); + unsigned char test_response = get_ps2_inbyte(); + if(test_response != 0x55) { + printf("error: PS/2 self-test failed\n"); + return 1; + } + outb(0x60, 0x64); + outb(config_byte, 0x60); + + /* Double check dual channel stuff */ + if(is_dual_ch) { + outb(0xA8, 0x64); + outb(0x20, 0x64); + unsigned char new_config_byte = get_ps2_inbyte(); + is_dual_ch = (new_config_byte & 020) == 0 ? 1 : 0; + if(is_dual_ch) { + outb(0xA7, 0x64); + } + } + + /* Interface tests */ + outb(0xAB, 0x64); + test_response = get_ps2_inbyte(); + int working_ports = test_response == 0x00 ? 01 : 00; + if(test_response != 0x00 && !is_dual_ch) { + printf("error: could not initialize PS/2 device\n"); + return 2; + } + if(is_dual_ch) { + outb(0xA9, 0x64); + test_response = get_ps2_inbyte(); + working_ports |= test_response == 0x00 ? 02 : 00; + if(test_response != 0x00 && working_ports != 01) { + printf("error: could not initialize PS/2 device\n"); + return 2; + } + } + + /* Enable devices */ + if(working_ports & 01) { + outb(0xAE, 0x64); + config_byte |= 01; + } + if(working_ports & 02) { + outb(0xA8, 0x64); + config_byte |= 02; + } + outb(0x60, 0x64); + outb(config_byte, 0x60); + + return 0; +} + int init(void) { printf("Setting up GDT...\n"); setup_gdt(); printf("Enabling interrupts...\n"); idt_init(); - printf("Fenix Dev Pre-release v0.0.3\n"); + printf("Initializing PS/2 controller...\n"); + initialize_ps2_kbd(); return 0; } diff --git a/arch/i386/inter.s b/arch/i386/inter.s index 155a262..597b3c3 100644 --- a/arch/i386/inter.s +++ b/arch/i386/inter.s @@ -69,99 +69,100 @@ .extern irq15_handler irq0: - pusha + pushal call irq0_handler - popa + popal iret irq1: - pusha + pushal + cld call irq1_handler - popa + popal iret irq2: - pusha + pushal call irq2_handler - popa + popal iret irq3: - pusha + pushal call irq3_handler - popa + popal iret irq4: - pusha + pushal call irq4_handler - popa + popal iret irq5: - pusha + pushal call irq5_handler - popa + popal iret irq6: - pusha + pushal call irq6_handler - popa + popal iret irq7: - pusha + pushal call irq7_handler - popa + popal iret irq8: - pusha + pushal call irq8_handler - popa + popal iret irq9: - pusha + pushal call irq9_handler - popa + popal iret irq10: - pusha + pushal call irq10_handler - popa + popal iret irq11: - pusha + pushal call irq11_handler - popa + popal iret irq12: - pusha + pushal call irq12_handler - popa + popal iret irq13: - pusha + pushal call irq13_handler - popa + popal iret irq14: - pusha + pushal call irq14_handler - popa + popal iret irq15: - pusha + pushal call irq15_handler - popa + popal iret load_idt: diff --git a/arch/i386/interrupt.c b/arch/i386/interrupt.c index 98ce0e0..3100731 100644 --- a/arch/i386/interrupt.c +++ b/arch/i386/interrupt.c @@ -1,5 +1,7 @@ #include #include +#include +#include "ps2_kbd.h" void idt_init(void) { extern int load_idt(); @@ -192,6 +194,7 @@ void irq0_handler(void) { /* Keyboard Interrupt */ void irq1_handler(void) { + printf("owo\n"); outb(0x20, 0x20); } diff --git a/arch/i386/linker.ld b/arch/i386/linker.ld index d766d45..9a020c5 100755 --- a/arch/i386/linker.ld +++ b/arch/i386/linker.ld @@ -4,21 +4,33 @@ SECTIONS { . = 1M; - .text BLOCK (4K) : ALIGN (4K) { - *(.multiboot) - *(.text) + _kernel_start = .; + .multiboot.data : { + *(.multiboot.data) + } + + .multiboot.text : { + *(.multiboot.text) + } + + . += 0xC0000000; + + .text ALIGN (4K) : AT (ADDR (.text) - 0xC0000000) { + *(.text) } - .rodata BLOCK (4K) : ALIGN (4K) { + .rodata ALIGN (4K) : AT (ADDR (.rodata) - 0xC0000000) { *(.rodata) } - .data BLOCK (4K) : ALIGN (4K) { - *(.data) + .data ALIGN (4K) : AT (ADDR(.data) - 0xC0000000) { + *(.data) } - .bss BLOCK (4K) : ALIGN (4K) { - *(COMMON) + .bss ALIGN (4K) : AT (ADDR (.bss) - 0xC0000000) { + *(COMMON) *(.bss) + *(.bootstrap_stack) } + _kernel_end = .; } diff --git a/arch/i386/make.config b/arch/i386/make.config index 558cf5d..b0913be 100755 --- a/arch/i386/make.config +++ b/arch/i386/make.config @@ -10,4 +10,6 @@ $(ARCHDIR)/cmos.o \ $(ARCHDIR)/gdt.o \ $(ARCHDIR)/gdt_load.o \ $(ARCHDIR)/interrupt.o \ -$(ARCHDIR)/inter.o \ No newline at end of file +$(ARCHDIR)/inter.o \ +$(ARCHDIR)/ps2_kbd.o \ +$(ARCHDIR)/syscall_uname.o \ No newline at end of file diff --git a/arch/i386/ps2_kbd.c b/arch/i386/ps2_kbd.c new file mode 100644 index 0000000..2aaf774 --- /dev/null +++ b/arch/i386/ps2_kbd.c @@ -0,0 +1,15 @@ +#include "ps2_kbd.h" +#include + +unsigned char get_ps2_inbyte() { + return inb(0x60); +} + +unsigned char* identify_device() { + unsigned char ret_val[2]; int j = 0; + outb(0xF2, 0x64); + for(unsigned char i; i != 0xFA; i = inb(0x60)) { + ret_val[j++] = i; + } + return ret_val; +} \ No newline at end of file diff --git a/arch/i386/ps2_kbd.h b/arch/i386/ps2_kbd.h new file mode 100644 index 0000000..45826c5 --- /dev/null +++ b/arch/i386/ps2_kbd.h @@ -0,0 +1,10 @@ +#ifndef _ARCH_I386_PS2_KBD_H +#define _ARCH_I386_PS2_KBD_H + +int scan_set; + +unsigned char get_ps2_inbyte(); + +unsigned char* identify_device(); + +#endif \ No newline at end of file diff --git a/arch/i386/syscall_uname.c b/arch/i386/syscall_uname.c new file mode 100644 index 0000000..cdc3f00 --- /dev/null +++ b/arch/i386/syscall_uname.c @@ -0,0 +1,13 @@ +#include +#include + +#define PTR ((struct utsname *) v) + +int __syscall_uname(void * v) { + strcpy(PTR->sysname, "FENIX"); + strcpy(PTR->release, "PRE-ALPHA"); + strcpy(PTR->version, "20220726_1700"); + strcpy(PTR->machine, "i386"); + + return 0; +} \ No newline at end of file diff --git a/arch/i386/tty.c b/arch/i386/tty.c index 8e017bb..a6e28fe 100755 --- a/arch/i386/tty.c +++ b/arch/i386/tty.c @@ -9,7 +9,7 @@ static const size_t VGA_WIDTH = 80; static const size_t VGA_HEIGHT = 24; -static uint16_t* const VGA_MEMORY = (uint16_t*) 0xB8000 ; +static uint16_t* const VGA_MEMORY = (uint16_t*) 0xC03FF000 ; static size_t term_row; static size_t term_col; diff --git a/include/kernel/cmos.h b/include/kernel/cmos.h index cecc2d0..731156a 100644 --- a/include/kernel/cmos.h +++ b/include/kernel/cmos.h @@ -2,7 +2,7 @@ #define _KERNEL_CMOS /* This is kinda important, and has to be changed each year. */ -#define RELEASE_YEAR 2020 +#define RELEASE_YEAR 2022 struct _rtc_val { unsigned char second; diff --git a/include/kernel/interrupt.h b/include/kernel/interrupt.h index 781a599..caf6d9c 100644 --- a/include/kernel/interrupt.h +++ b/include/kernel/interrupt.h @@ -1,6 +1,15 @@ #ifndef _KERNEL_INTERRUPT #define _KERNEL_INTERRUPT +#ifdef __GNUC__ +struct IDT_entry { + unsigned short int offset_lowerbits; + unsigned short int selector; + unsigned char zero; + unsigned char type_attr; + unsigned short int offset_higherbits; +} __attribute__((packed)); +#else struct IDT_entry { unsigned short int offset_lowerbits; unsigned short int selector; @@ -8,7 +17,11 @@ struct IDT_entry { unsigned char type_attr; unsigned short int offset_higherbits; }; +#endif +#ifdef __GNUC__ +__attribute((aligned(0x10))) +#endif struct IDT_entry IDT[256]; void idt_init(void); diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h new file mode 100644 index 0000000..3df2ae1 --- /dev/null +++ b/include/kernel/syscall.h @@ -0,0 +1,6 @@ +#ifndef _KERNEL_SYSCALL +#define _KERNEL_SYSCALL + +int __syscall_uname(void *); + +#endif \ No newline at end of file diff --git a/kernel/kernel.c b/kernel/kernel.c index 3895fa7..1aaafbc 100755 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -1,7 +1,12 @@ #include #include +#include +#include void kern_main(void) { term_init(); - init(); + init(); + struct utsname u; + uname(&u); + printf("%s %s %s\n", u.sysname, u.release, u.machine); }