From e59104ffb55abe522c82d658f1f285149cca2cb1 Mon Sep 17 00:00:00 2001 From: Loic Guegan Date: Sun, 2 May 2021 14:46:18 +0200 Subject: [PATCH] Debug GDT enable multitasking --- src/Makefile | 2 +- src/boucane.cc | 44 +++++++++++------- src/core/apic.cc | 30 ++++++++----- src/core/apic.hpp | 1 + src/core/gdt.S | 22 +++++---- src/core/idt.cc | 18 ++++++-- src/core/idt.hpp | 1 + src/core/int.S | 80 +++++++++++++++++++++++++++++---- src/core/paging.cc | 12 +++-- src/core/scheduler.cc | 91 +++++++++++++++++++++++++++++++++----- src/core/scheduler.hpp | 28 +++++++----- src/core/scheduler_asm.S | 27 ++++++----- src/core/syscalls.cc | 8 ++++ src/drivers/framebuffer.cc | 4 +- 14 files changed, 283 insertions(+), 85 deletions(-) create mode 100644 src/core/syscalls.cc diff --git a/src/Makefile b/src/Makefile index 0390042..61e6899 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,5 @@ EXEC := boucane -CC := g++ -Wno-write-strings -Wno-int-to-pointer-cast -mcmodel=large -nostdlib -nostdinc -no-pie -fno-builtin -fno-stack-protector -I ./ -I include +CC := g++ -g -Wno-write-strings -Wno-int-to-pointer-cast -mcmodel=large -nostdlib -nostdinc -no-pie -fno-builtin -fno-stack-protector -I ./ -I include LD_SCRIPT := linker.ld # Note that BOOT_OBJ do not match boot.S diff --git a/src/boucane.cc b/src/boucane.cc index caf0b8d..f4d9482 100644 --- a/src/boucane.cc +++ b/src/boucane.cc @@ -28,15 +28,18 @@ extern u64 gdt64_tss; void configure_tss(){ // Get TSS physical address - u64 tss_addr=(u64)PHY(&kvar_tss); + u64 tss_addr=(u64)&kvar_tss; u32 limit=sizeof(TSS); u32 desc1=(tss_addr&0xFFFF)<<16|(limit&0xFFFF); + tss_addr>>=16; u32 desc2=(tss_addr&0xFF); - desc2|=0b1001<<8; // Type - desc2|=0b111<<13; // Permission & present - u32 desc3=((limit>>8)&0xFFFF)|(limit>>24); - + desc2|=0b11101001<<8; // Type, Permission, present + tss_addr>>=8; + desc2|=tss_addr<<24; + tss_addr>>=8; + u32 desc3=tss_addr; + // Configure GDT u32 *gdt_entry=(u32*)&gdt64_tss; gdt_entry[0]=desc1; @@ -46,6 +49,7 @@ void configure_tss(){ // Configure segment kvar_tss.rsp0=(u64)VIRT(kvar_stack_pma); + kvar_tss.iomap_address=0; asm( "mov $0x28, %ax \n\t" "ltr %ax" @@ -53,9 +57,15 @@ void configure_tss(){ } void task1(){ - u64 a=0xEEEEEE; - DUMP(a); - while(1); + while(1){ + asm("mov $1, %rdi;int $0x30"); + } +} + +void task2(){ + while(1){ + asm("mov $2, %rdi;int $0x30"); + } } extern "C" void boucane(u64 mb_info){ @@ -77,7 +87,7 @@ extern "C" void boucane(u64 mb_info){ memtext_init(); idt_enable_interrupt(); apic_enable(); - + // Looking for framebuffer FRAMEBUFFER fb_info; if(mb2_find_framebuffer((u32*)mb_info, &fb_info)){ @@ -97,23 +107,25 @@ extern "C" void boucane(u64 mb_info){ __putchar=vgatext_putchar; } } - + // Booting! printk("Booting Boucane v%d.%d.%d\n",VERSION_MAJOR,VERSION_MINOR, VERSION_PATH); - + printk("System informations -- "); char bootloader[20]; if(mb2_find_bootloader_name((u32*)mb_info,bootloader)){ - printk("System informations -- BOOT:%s ", bootloader); + + printk("BOOT:%s ", bootloader); } - + MEM_INFO mem_infos; if(mb2_find_mem((u32*)mb_info,&mem_infos)){ u64 mem=mem_infos.mem_upper-mem_infos.mem_lower; mem/=1024; printk("RAM:%dMB\n", mem); } - - //create_task((void*)task1, 50); - //scheduler_start(); + show_ticks=1; + create_task((void*)task1, 50); + create_task((void*)task2, 50); + scheduler_start(); while(1); } \ No newline at end of file diff --git a/src/core/apic.cc b/src/core/apic.cc index 6722a3d..aba801a 100644 --- a/src/core/apic.cc +++ b/src/core/apic.cc @@ -17,23 +17,23 @@ u8 lapic_space[4096] __attribute__((aligned(4096))); u8 ioapic_space[4096] __attribute__((aligned(4096))); - +char enable=0; void apic_enable(){ // Memory Allocation - PAGE_MAP(lapic_space,APIC_LAPIC_ADDR, PAGING_OPT_DEFAULTS); - PAGE_MAP(lapic_space,APIC_LAPIC_ADDR,PAGING_OPT_DEFAULTS); - + PAGE_MAP(lapic_space,APIC_LAPIC_ADDR, PAGING_OPT_PCD|PAGING_OPT_DEFAULTS); + PAGE_MAP(ioapic_space,APIC_IOAPIC_ADDR,PAGING_OPT_PCD|PAGING_OPT_DEFAULTS); + // Configure APIC register location and enable it via MSR - u64 lapic_addr=(u64)APIC_LAPIC_ADDR; + /* u64 lapic_addr=(u64)APIC_LAPIC_ADDR; u32 high=lapic_addr>>32; u32 low=((u64)APIC_LAPIC_ADDR&0xFFFFFFFF); low|=0x800; // Enable apic - WRITE_MSR(0x1B,high,low); + WRITE_MSR(0x1B,high,low);*/ // Configure LAPIC device using mmap apic_write(APIC_LAPIC_REG_SPURIOUS, 0x100&apic_read(APIC_LAPIC_REG_SPURIOUS)); - apic_write(APIC_DFR, 0xFFFFFFFF); - apic_write(APIC_PRIOR, 0); + //apic_write(APIC_DFR, 0xFFFFFFFF); + // apic_write(APIC_PRIOR, 0); apic_write(APIC_LAPIC_TIMER_DVD, 1); apic_write(APIC_LAPIC_TIMER_LVT, (1<<17)|61); apic_write(APIC_LAPIC_TIMER_IC, 100000); @@ -43,6 +43,7 @@ void apic_enable(){ *ioapic_reg=0x12; // Select the 0x12 IRQ ioapic_reg=(u32*)(((u64)ioapic_space)+0x10); // Now use the IOREGWIN to write *ioapic_reg=(0x0<<12)|60; // Enable IRQ 1 (0x12) and assign it to the vector 0x3C (index 60 in the IDT) + enable=1; } void apic_write(u32 reg, u32 value){ @@ -55,6 +56,15 @@ u32 apic_read(u32 reg){ return *lapic_reg; } -extern "C" void ack(){ - apic_write(APIC_EOI, 0); +extern "C" void apic_ack(){ + if(enable){ +/* u8 data; + do { + inb(0x64,data); + } + while((data&0x01) == 0); + inb(0x60,data); */ + + apic_write(APIC_EOI, 0); + } } \ No newline at end of file diff --git a/src/core/apic.hpp b/src/core/apic.hpp index c64c509..decb565 100644 --- a/src/core/apic.hpp +++ b/src/core/apic.hpp @@ -4,6 +4,7 @@ #include "boucane.hpp" +extern "C" void apic_ack(); void apic_enable(); void apic_write(u32 reg, u32 value); u32 apic_read(u32 reg); \ No newline at end of file diff --git a/src/core/gdt.S b/src/core/gdt.S index c32db59..d99145e 100644 --- a/src/core/gdt.S +++ b/src/core/gdt.S @@ -3,31 +3,35 @@ gdt64: gdt64_null: - .long 0 - .long 0 + .word 0xFFF + .word 0x0 + .byte 0 + .byte 0 + .byte 1 + .byte 0 gdt64_cs: .long 0 .byte 0 - .byte 0b10011100 - .byte 0b00100000 + .byte 0b10011010 # Present and non-conforming Readable + .byte 0b00100000 # Long mode .byte 0 gdt64_ds: .long 0 .byte 0 - .byte 0b10010010 + .byte 0b10010010 # Present, writable .word 0 gdt64_cs_user: .long 0 .byte 0 - .byte 0b11111100 - .byte 0b00100000 + .byte 0b11111010 # Present, Privilege 3 and non-conforming Readable + .byte 0b00100000 # Long mode .byte 0 gdt64_ds_user: .long 0 .byte 0 - .byte 0b11110010 + .byte 0b11110010 # Present, Privilege 3 and writable .word 0 - gdt64_tss: + gdt64_tss: # Will be setup in the boucane() function .long 0 .long 0 .long 0 diff --git a/src/core/idt.cc b/src/core/idt.cc index 495b332..b8b57c7 100644 --- a/src/core/idt.cc +++ b/src/core/idt.cc @@ -6,7 +6,7 @@ u32 idt[IDT_MAX_ENTRIES][4] __attribute__((aligned(4096)));; IDT_REGISTER IDTR; -extern u64 INT_DEFAULT,INT_0,INT_14,INT_KBD,INT_CLK; +extern u64 INT_DEFAULT,INT_0,INT_10,INT_14,INT_KBD,INT_CLK,INT_SYSCALL; void idt_enable_interrupt(void){ IDTR.base=((u64)idt); @@ -28,6 +28,10 @@ void idt_enable_interrupt(void){ d.offset=(u64)&INT_14; idt_write_descriptor(d, i); } + else if(i==10){ + d.offset=(u64)&INT_10; + idt_write_descriptor(d, i); + } else if(i==60){ // Keyboard d.offset=(u64)&INT_KBD; idt_write_descriptor(d, i); @@ -36,12 +40,20 @@ void idt_enable_interrupt(void){ d.offset=(u64)&INT_CLK; idt_write_descriptor(d, i); } + else if(i==0x30){ // Syscall + IDT_DESCRIPTOR d2; + d2.ign=0; + d2.ist=0; + d2.selector=0x08; + d2.options=IDT_OPT_P|IDT_OPT_PRVL_3|IDT_OPT_TYPE_INT; + d2.offset=(u64)&INT_SYSCALL; + idt_write_descriptor(d2, i); + } else { d.offset=(u64)&INT_DEFAULT; idt_write_descriptor(d, i); } - } - + } // Enable interrupts asm( "lidt (IDTR) \n\t" diff --git a/src/core/idt.hpp b/src/core/idt.hpp index 1133ad1..67b52d9 100644 --- a/src/core/idt.hpp +++ b/src/core/idt.hpp @@ -9,6 +9,7 @@ #define IDT_OPT_P (1 << 15) #define IDT_OPT_TYPE_INT 0xE << 8 +#define IDT_OPT_TYPE_TRAP 0xF << 8 #define IDT_OPT_PRVL_0 0 #define IDT_OPT_PRVL_1 (1 << 13) #define IDT_OPT_PRVL_2 (2 << 13) diff --git a/src/core/int.S b/src/core/int.S index 9505191..2897698 100644 --- a/src/core/int.S +++ b/src/core/int.S @@ -1,50 +1,112 @@ .code64 .extern printk -.extern ack +.extern apic_ack -.macro call_printk msg +.macro CALL_PRINTK msg mov \msg, %rdi mov $0, %eax # Required for variadic functions mov $printk,%rcx call *(%rcx) .endm +.macro SAVE_REGS + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 + push %rax + push %rbx + push %rcx + push %rdx + push %rbp + push %rsi + push %rdi + push %rax + mov $0x10, %ax + mov %ax, %ds + pop %rax +.endm + +.macro RESTORE_REGS + pop %rdi + pop %rsi + pop %rbp + pop %rdx + pop %rcx + pop %rbx + pop %rax + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 +.endm + .globl INT_DEFAULT INT_DEFAULT: + SAVE_REGS + RESTORE_REGS iretq .globl INT_0 INT_0: - call_printk $MSG_INT_0 + CALL_PRINTK $MSG_INT_0 INT_0_INFINITE: jmp INT_0_INFINITE iretq +.globl INT_10 +INT_10: + CALL_PRINTK $MSG_INT_10 + INT_10_INFINITE: + jmp INT_10_INFINITE + iretq + .globl INT_14 INT_14: - call_printk $MSG_INT_14 - mov $0, %eax - call printk + CALL_PRINTK $MSG_INT_14 INT_14_INFINITE: jmp INT_14_INFINITE iretq .globl INT_KBD INT_KBD: - #call_printk $MSG_INT_KBD - call ack + SAVE_REGS + CALL_PRINTK $MSG_INT_KBD + call apic_ack + RESTORE_REGS iretq .globl INT_CLK .extern clock INT_CLK: + SAVE_REGS call clock - call ack + call apic_ack + RESTORE_REGS iretq +.globl INT_SYSCALL +.extern syscall +INT_SYSCALL: + SAVE_REGS + call syscall + RESTORE_REGS + iretq + + MSG_INT_0: .asciz "Zero Division error!" +MSG_INT_10: +.asciz "Invalid TSS!" MSG_INT_14: .asciz "Page fault!" MSG_INT_KBD: diff --git a/src/core/paging.cc b/src/core/paging.cc index 7231352..ebd4f9d 100644 --- a/src/core/paging.cc +++ b/src/core/paging.cc @@ -52,7 +52,7 @@ void paging_enable() { // 4096 bytes stack PAGE_MAP(kvar_kernel_vma-4096, kvar_stack_pma,PAGING_OPT_DEFAULTS); - + // Load new pml4 kpml4=(u64*)((u64)kpages[0]-kvar_kernel_vma); lpml4(kpml4); @@ -190,9 +190,15 @@ void paging_allocate_addr(u64* pml4_table, u64 virt, u64 phy, u16 options, char u64* paging_create_task(int npages){ u64 *pml4=paging_allocate_utable(); - for(int i=0;i>39&0x1FF; diff --git a/src/core/scheduler.cc b/src/core/scheduler.cc index 00741fe..fee5716 100644 --- a/src/core/scheduler.cc +++ b/src/core/scheduler.cc @@ -1,40 +1,107 @@ #include "scheduler.hpp" +#include "boucane.hpp" +#include "core/apic.hpp" -TASK tasks[MAX_TASK]; -u32 ntasks=0; +PROC procs[MAX_TASK]; +u32 nproc=0; char show_ticks=0; +char scheduling=0; +u32 active_process=0; extern "C" void clock(){ if(show_ticks) print("."); + if(scheduling) + schedule(); } void schedule(){ + // First get a pointer to the first process saved register. + // Since this is called by clock(), %rbp contains a pointer + // to the clock() %rbp value and then we access to the registers SAVE_REGS in int.S + u64* stack; + asm("mov %%rbp, %%rax;mov (%%rax), %%rbx; add $16, %%rbx; mov %%rbx,%0": "=m"(stack)::"rax","rbx"); + + // Save current task + PROC *t=&procs[active_process]; + t->registers.r8=stack[0]; + t->registers.r9=stack[1]; + t->registers.r10=stack[2]; + t->registers.r11=stack[3]; + t->registers.r12=stack[4]; + t->registers.r13=stack[5]; + t->registers.r14=stack[6]; + t->registers.r15=stack[7]; + t->registers.rdi=stack[8]; + t->registers.rsi=stack[9]; + t->registers.rbp=stack[10]; + t->registers.rdx=stack[11]; + t->registers.rcx=stack[12]; + t->registers.rbx=stack[13]; + t->registers.rax=stack[14]; + t->registers.rip=stack[15]; + t->registers.cs=stack[16]; + t->registers.eflags=stack[17]; + t->registers.rsp=stack[18]; + t->registers.ds=stack[19]; + // Goto next task + active_process++; + if(active_process>=nproc) + active_process=0; + + t=&procs[active_process]; + kvar_tss.rsp0=t->registers.rsp0; + + // Clock acknownledgement + apic_ack(); + + asm volatile( + "mov %0, %%rdi \n\t" + "jmp switch \n\t" + :: "a" (t) + ); } void create_task(void* task, u32 size){ - if(ntasks>=MAX_TASK){ + if(nproc>=MAX_TASK){ printk("Could not create more tasks."); return; } - TASK *t=&tasks[ntasks]; - t->id=ntasks; - t->pid=ntasks; + PROC *t=&procs[nproc]; + t->id=nproc; + t->pid=nproc; t->size=size; - t->pml4=paging_create_task(size/4096+1); + + u32 npages=size%4096 ? size/4096 + 1 : size/4096; + // Note that paging_create_task() allocate 2 more pages (one for the user stack and + // the other for the kernel stack) + t->pml4=paging_create_task(npages); + t->registers.rsp=TASK_VMA+npages*4096+4096; // User stack + t->registers.rsp0=TASK_VMA+npages*4096+4096*2; // Kernel stack on the last page + + t->registers.rip=TASK_VMA; + t->registers.cs=0x1B; // 0x18 and 0x3 privilege + t->registers.ds=0x23; // 0x20 and 0x3 privilege // Load task using lpml4(t->pml4); memcpy(task, TASK_VMA, size); lpml4(kpml4); - - ntasks++; + + nproc++; } void scheduler_start(){ - TASK *t=&tasks[0]; - lpml4(t->pml4); - asm("jmp switch"); + scheduling=1; + active_process=0; + PROC *t=&procs[active_process]; + kvar_tss.rsp0=t->registers.rsp0; + asm( + "cli \n\t" + "mov %0, %%rdi \n\t" + "jmp switch \n\t" + :: "r" (t) + ); } \ No newline at end of file diff --git a/src/core/scheduler.hpp b/src/core/scheduler.hpp index 15b4caf..17b7f96 100644 --- a/src/core/scheduler.hpp +++ b/src/core/scheduler.hpp @@ -4,24 +4,32 @@ #define MAX_TASK 5 #define TASK_VMA 0x0 +#if (TASK_VMA % 0x7) + #error TASK_VMA value is not 4096 bits aligned! +#endif +// DO NOT CHANGE THE FOLLOWING STRUCTURE WITHOUT CONCIDERING UPDATING +// THE SWITCH FUNCTION INTO scheduler_asm.S typedef struct { - u32 rax, rbx, rcx, rdx; - u32 cs, rip; - u32 ss, rsp, rbp; - u32 rsi, rdi; - u32 ds, es, fs, gs; - u32 eflags; - u32 ss0, rsp0; + u64 rax, rbx, rcx, rdx; + u64 cs, rip; + u64 ss, rsp, rbp; + u64 rsi, rdi; + u64 ds, es, fs, gs; + u64 eflags; + u64 rsp0; + u64 r8,r9,r10,r11,r12,r13,r14,r15; } __attribute__((packed)) REGS; +// DO NOT CHANGE THE FOLLOWING STRUCTURE WITHOUT CONCIDERING UPDATING +// THE SWITCH FUNCTION INTO scheduler_asm.S typedef struct { + u64* pml4; + REGS registers; u32 id; u32 pid; - u64* pml4; u32 size; - REGS registers; -} __attribute__((packed)) TASK; +} __attribute__((packed)) PROC; extern char show_ticks; diff --git a/src/core/scheduler_asm.S b/src/core/scheduler_asm.S index fc8bc50..8f417c4 100644 --- a/src/core/scheduler_asm.S +++ b/src/core/scheduler_asm.S @@ -2,26 +2,33 @@ - +.extern kvar_stack_pma switch: - - mov $0x23, %ax + # TODO: Check if we come from kernel mode (use kernel stack) + # TODO: restore all registers + + mov 96(%rdi), %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs - push $0x23 # - push $0x80 + mov (%rdi), %rax + mov %rax, %cr3 + + push 96(%rdi) + push 64(%rdi) pushf pop %rax - #orl $0x200, %%eax - mov $0xffffbfff, %rbx + or $0x200, %rax # Enable interrupt + mov $0xffffffffbfff, %rbx # NT flag and %rbx, %rax push %rax - push $0x1B - push $0x0 - + push 40(%rdi) + push 48(%rdi) + + + # Perform task switching iretq diff --git a/src/core/syscalls.cc b/src/core/syscalls.cc new file mode 100644 index 0000000..f98e6e3 --- /dev/null +++ b/src/core/syscalls.cc @@ -0,0 +1,8 @@ +#include "boucane.hpp" + +extern "C" void syscall(){ + u64 call_number; + asm volatile("mov %%rdi, %0":"=r"(call_number)); + printk("%d",call_number); + for(int i=0;i<10000000;i++){} +} \ No newline at end of file diff --git a/src/drivers/framebuffer.cc b/src/drivers/framebuffer.cc index ce7790e..33b73d6 100644 --- a/src/drivers/framebuffer.cc +++ b/src/drivers/framebuffer.cc @@ -15,7 +15,7 @@ void framebuffer_init(FB_CFG config){ // Ensure we start writing at the begining of the page since // start is not necessarly 4096 bytes aligned start=PAGE(start); - PAGE_RMAP(start,fb_cfg.location, PAGING_OPT_DEFAULTS,fb_cfg.pitch*fb_cfg.height); + PAGE_RMAP(start,fb_cfg.location, PAGING_OPT_PCD|PAGING_OPT_DEFAULTS,fb_cfg.pitch*fb_cfg.height); fb_cfg.location=start; } @@ -25,7 +25,7 @@ void framebuffer_draw(FB_PIXEL p){ p.y=p.y>(fb_cfg.width)?fb_cfg.width:p.y; p.x=p.x<0?0:p.x; p.y=p.y<0?0:p.y; - + u8 *pixel=(u8*)(fb_cfg.location+p.x*(fb_cfg.depth/8)+p.y*fb_cfg.pitch); pixel[0]=p.r; pixel[1]=p.g;