Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

179 initialize user mode #181

Merged
merged 18 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 31 additions & 18 deletions src/asm/boot.s
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ global p2_table
global p4_table
global p3_table
global p3_table_hh
%if SMALL_PAGES == 1
%if SMALL_PAGES == 1
global pt_tables
%endif
global end_of_mapped_memory ;this variable will contain the virtual address of the last address mapped after bootstrap
Expand All @@ -29,6 +29,10 @@ global multiboot_mmap_data
global multiboot_basic_meminfo
global multiboot_acpi_info
global read_multiboot
global gdt64
global stack

extern kernel_tss
extern kernel_start

[bits 32]
Expand All @@ -38,7 +42,7 @@ start:
mov esi, eax ; Magic number

mov esp, stack.top - KERNEL_VIRTUAL_ADDR

mov eax, p3_table - KERNEL_VIRTUAL_ADDR; Copy p3_table address in eax
or eax, PRESENT_BIT | WRITE_BIT ; set writable and present bits to 1
mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 0], eax ; Copy eax content into the entry 0 of p4 table
Expand Down Expand Up @@ -77,7 +81,7 @@ start:
.map_p2_table:
mov eax, PAGE_SIZE ; Size of the page
mul ecx ; Multiply by counter
or eax, PAGE_TABLE_ENTRY ; We set: huge page bit (if on 2M pages), writable and present
or eax, PAGE_TABLE_ENTRY ; We set: huge page bit (if on 2M pages), writable and present

; Moving the computed value into p2_table entry defined by ecx * 8
; ecx is the counter, 8 is the size of a single entry
Expand All @@ -95,7 +99,7 @@ start:
; when small pages enabled: two tables are adjacent in memory
; they are mapped in the pdir during the map_pd_table cycle
; this is why the loop is up to 1024

jne .map_p2_table ; if ecx < 512 then loop


Expand All @@ -112,7 +116,7 @@ start:
mov eax, cr4
or eax, 1 << 5 ; Physical address extension bit
mov cr4, eax

; Now set up the long mode bit
mov ecx, 0xC0000080
; rdmsr is to read a a model specific register (msr)
Expand All @@ -121,21 +125,21 @@ start:
or eax, 1 << 8
; write back the value
wrmsr

; Now is time to enable paging
mov eax, cr0 ;cr0 contains the values we want to change
or eax, 1 << 31 ; Paging bit
or eax, 1 << 16 ; Write protect, cpu can't write to read-only pages when
; privilege level is 0
mov cr0, eax ; write back cr0
; load gdt
; load gdt
lgdt [gdt64.pointer_low - KERNEL_VIRTUAL_ADDR]
jmp (0x8):(kernel_jumper - KERNEL_VIRTUAL_ADDR)
bits 64

section .text
kernel_jumper:
bits 64
bits 64

%if SMALL_PAGES == 0
mov qword[(end_of_mapped_memory - KERNEL_VIRTUAL_ADDR)], (511 << 39) | (510 << 30) | (511 << 21)
Expand All @@ -149,9 +153,9 @@ kernel_jumper:
mov es, ax ; extra segment register
mov fs, ax ; extra segment register
mov gs, ax ; extra segment register

lea rax, [rdi+8]

;.bss section should be already 0 at least on unix and windows systems
;no need to initialize

Expand Down Expand Up @@ -192,7 +196,7 @@ read_multiboot:
inc rcx
cmp rcx, 512
jne .map_fb
;mov qword [p2_table + 8 * 488],
;mov qword [p2_table + 8 * 488],
%endif
jmp .item_not_needed
.mmap_tag_item:
Expand All @@ -211,7 +215,7 @@ read_multiboot:
;Padded with 0 until the first byte aligned with 8bytes
add rax, 7
and rax, ~7
;Check if the tag is the end tag
;Check if the tag is the end tag
;Type: 0 Size: 8
;multiboot_tag.type == 0?
cmp dword [rax + multiboot_tag.type], MULTIBOOT_TAG_TYPE_END
Expand All @@ -229,7 +233,7 @@ higher_half:
lgdt [gdt64.pointer]

; The two lines below are needed to un map the kernel in the lower half
; But i'll leave them commented for now because the code in the kernel need
; But i'll leave them commented for now because the code in the kernel need
; to be changed and some addresses need to be updated (i.e. multiboot stuff)
mov eax, 0x0
mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 0], eax
Expand All @@ -245,7 +249,7 @@ p4_table: ;PML4
p3_table: ;PDPR
resb 4096
p3_table_hh: ;PDPR
resb 4096
resb 4096
p2_table: ;PDP
resb 4096

Expand Down Expand Up @@ -275,23 +279,32 @@ stack:
resb 16384
.top:

section .rodata

section .data
; gdt table needs at least 3 entries:
; the first entry is always null
; the other two are data segment and code segment.
; the last two are data and code segments for user mode.
gdt64:
dq 0 ;first entry = 0
.code equ $ - gdt64
; equ tells the compiler to set the address of the variable at given address ($ - gdt64). $ is the current position.
; set the following values:
; descriptor type: bit 44 has to be 1 for code and data segments
; present: bit 47 has to be 1 if the entry is valid
; read/write: bit 41 1 means that is readable
; executable: bit 43 it has to be 1 for code segments
; 64bit: bit 53 1 if this is a 64bit gdt
dq (1 <<44) | (1 << 47) | (1 << 41) | (1 << 43) | (1 << 53) ;second entry=code=8
dq (1 <<44) | (1 << 47) | (1 << 41) | (1 << 43) | (1 << 53) ;second entry=code=0x8
.data equ $ - gdt64
dq (1 << 44) | (1 << 47) | (1 << 41) ;third entry = data = 10
dq (1 << 44) | (1 << 47) | (1 << 41) ;third entry = data = 0x10
.ucode equ $ - gdt64
dq (1 <<44) | (1 << 47) | (1 << 41) | (1 << 43) | (1 << 53) | (3 << 45) ;fourth entry=code=0x18
.udata equ $ - gdt64
dq (1 << 44) | (1 << 47) | (1 << 41) | (3 << 45) ;fifth entry = data = 0x20
.tss_low equ $ - gdt64 ;sixth entry placeholder for TSS entry lower part
dq 0
.tss_high equ $ - gdt64 ; seventh entry placeholder for TSS entry higher part
dq 0

.pointer:
dw .pointer - gdt64 - 1
Expand Down
3 changes: 2 additions & 1 deletion src/include/kernel/scheduling/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ typedef enum {

typedef struct thread_t thread_t;

#include <task.h>
#include <task.h>

struct thread_t {
uint16_t tid;
Expand All @@ -35,6 +35,7 @@ struct thread_t {
size_t wakeup_time;
thread_t* next_sibling;
thread_t* next;
uint64_t* rsp0;
};


Expand Down
42 changes: 42 additions & 0 deletions src/include/kernel/x86_64/tss.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef __TSS_H__
#define __TSS_H__

#include <stdint.h>
#include <stddef.h>

#define TSS_ENTRY_LOW 5
#define TSS_ENTRY_HIGH 6

/** This structure is copied from OSDev Notes, Part 6: Userspace.
* https://github.com/dreamos82/Osdev-Notes/blob/master/06_Userspace/03_Handling_Interrupts.md
*/
typedef struct tss
{
uint32_t reserved0;
uint64_t rsp0;
uint64_t rsp1;
uint64_t rsp2;
uint64_t reserved1;
uint64_t reserved2;
uint64_t ist1;
uint64_t ist2;
uint64_t ist3;
uint64_t ist4;
uint64_t ist5;
uint64_t ist6;
uint64_t ist7;
uint64_t reserved3;
uint16_t reserved4;
uint16_t io_bitmap_offset;
}__attribute__((__packed__)) tss_t;

//typedef struct tss tss_t;

extern tss_t kernel_tss;

extern void _load_task_register();

void initialize_tss();
void load_tss();

#endif
9 changes: 9 additions & 0 deletions src/kernel/arch/x86_64/cpu/load_tr.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
section .text

; This function just load the tss selecto in the task _load_task_register
; it should be called only once during kernel initialization.
global _load_task_register
_load_task_register:
mov rax, 0x28
ltr ax
ret
72 changes: 72 additions & 0 deletions src/kernel/arch/x86_64/cpu/tss.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include <logging.h>
#include <tss.h>

extern uint64_t gdt64[];
extern uint64_t stack[];

tss_t kernel_tss;

void initialize_tss(){

loglinef(Verbose, "(%s) Initializing tss", __FUNCTION__);

// These fields are reserved and must be set to 0
kernel_tss.reserved0 = 0x00;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that this is all explicit, but it'd be more efficient to use memset() to zero the whole tss and then set the fields you want afterwards.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, i totally agree, but i haven't implemented memset yet XD

kernel_tss.reserved1 = 0x00;
kernel_tss.reserved2 = 0x00;
kernel_tss.reserved3 = 0x00;
kernel_tss.reserved4 = 0x00;

// The rspX are used when there is a privilege change from a lower to a higher privilege
// Rsp contain the stack for that privilege level.
// We use only privilege level 0 and 3, so rsp1 and rsp2 can be left as 0
// Every thread will have it's own rsp0 pointer
kernel_tss.rsp0 = (uint64_t)stack + 16384;
kernel_tss.rsp1 = 0x0;
kernel_tss.rsp2 = 0x0;
// istX are the Interrup stack table, unless some specific cases they can be left as 0
// See intel manual chapter 5
kernel_tss.ist1 = 0x0;
kernel_tss.ist2 = 0x0;
kernel_tss.ist3 = 0x0;
kernel_tss.ist4 = 0x0;
kernel_tss.ist5 = 0x0;
kernel_tss.ist6 = 0x0;
kernel_tss.ist7 = 0x0;
// Can be left as 0 for now
kernel_tss.io_bitmap_offset = 0x0;
}

void load_tss() {
// Fields explanation (each entry is 64bit)
// TYPE: 1001 (64Bit TSS Available)
// BASE_ADDRESS: kernel_tss
// LIMIT 16:19 0 DPL: 0 P: 1 G:0

gdt64[TSS_ENTRY_LOW] = 0x00;
gdt64[TSS_ENTRY_HIGH] = 0x00;

// TSS_ENTRY_LOW:
uint16_t limit_low = (uint16_t) sizeof(kernel_tss); // 0:15 -> Limit (first 15 bits) should be 0xFFFF
uint16_t tss_entry_base_1 = (((uint64_t)&kernel_tss & 0xFFFF)); // 16:31 -> First 16 bits of kernel_tss address
uint8_t tss_entry_base_2 = (((uint64_t)&kernel_tss >> 16) & 0xFF); // 32:39 -> Next 8 bits of kernel_tss address
uint8_t flags_1 = 0x89; // 40:47 -> Type 4 bits in our case is 1001, 0, DPL should be 0 , P = 1
uint8_t flags_2 = 0; // 48:55 -> Limit (last 4 bits) can be 0, AVL=available to OS we leave it as 0, 53:54 are 0, 55 G (Granularity)
uint8_t tss_entry_base_3 = (((uint64_t)&kernel_tss >> 24) & 0xFF); // 55:63 -> Bits 25:31 of the kernel_tss base address

// TSS_ENTRY_HIGH
uint32_t tss_entry_base_4 = (((uint64_t) &kernel_tss>>32)& 0xFFFFFFFF); // 0:31 -> kernel_tss bits 32:63
uint32_t reserved_part = 0; // 32:63 -> Reserved / 0

uint64_t entry_low = (uint64_t) tss_entry_base_3 << 56 | (uint64_t) flags_2 << 48 | (uint64_t) flags_1 << 40 | (uint64_t) tss_entry_base_2 << 32| (uint64_t)tss_entry_base_1 << 16 | (uint64_t) limit_low;
uint64_t entry_high = reserved_part | tss_entry_base_4;


gdt64[TSS_ENTRY_LOW] = entry_low;
gdt64[TSS_ENTRY_HIGH] = entry_high;
loglinef(Verbose, "(%s) Loading TSS Register", __FUNCTION__);
loglinef(Verbose, "(%s) kernel_tss address = 0x%x", __FUNCTION__, &kernel_tss);
loglinef(Verbose, "(%s) gdt64[4] = 0x%x", __FUNCTION__, (uint64_t)gdt64[TSS_ENTRY_LOW]);
loglinef(Verbose, "(%s) gdt64[5] = 0x%x", __FUNCTION__, (uint64_t)gdt64[TSS_ENTRY_HIGH]);
_load_task_register();
}
17 changes: 5 additions & 12 deletions src/kernel/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <vfs.h>
#include <fcntl.h>
#include <unistd.h>
#include <tss.h>
//#include <runtime_tests.h>

extern uint32_t FRAMEBUFFER_MEMORY_SIZE;
Expand Down Expand Up @@ -134,13 +135,12 @@ void kernel_start(unsigned long addr, unsigned long magic){
} else {
PSF_font *font = (PSF_font*)&_binary_fonts_default_psf_start;
logline(Verbose, "(kernel_start): PSF v2 found");
loglinef(Verbose, "(kernel_start): Version: 0x%x - Magic: 0x%x", font->magic, font->version);
loglinef(Verbose, "(kernel_start): Version: 0x%x - Magic: 0x%x", font->version, font->magic);
loglinef(Verbose, "(kernel_start): Number of glyphs: 0x%x - Bytes per glyphs: 0x%x", font->numglyph, font->bytesperglyph);
loglinef(Verbose, "(kernel_start): Header size: 0x%x - flags: 0x%x", font->headersize, font->flags);
loglinef(Verbose, "(kernel_start): Width: 0x%x - Height: 0x%x", font->width, font->height);
}

loglinef(Verbose, "(kernel_start): PSF stored version: %d", psf_font_version);
uint32_t pw, ph, cw, ch;
get_framebuffer_mode(&pw, &ph, &cw, &ch);
loglinef(Verbose, "(kernel_start): Number of lines: %d", ch);
Expand All @@ -153,12 +153,6 @@ void kernel_start(unsigned long addr, unsigned long magic){
draw_logo(0, 400);
#endif

/*char *cpuid_model = _cpuid_model();
loglinef(Verbose, "(kernel_start): Cpuid model: %s", cpuid_model);

uint32_t cpu_info = 0;
cpu_info = _cpuid_feature_apic();
loglinef(Verbose, "(kernel_start): Cpu info result: 0x%x", cpu_info);*/
init_apic();
_mmap_setup();
vmm_init(VMM_LEVEL_SUPERVISOR, NULL);
Expand All @@ -176,14 +170,15 @@ void kernel_start(unsigned long addr, unsigned long magic){
init_keyboard();
set_irq(KEYBOARD_IRQ, IOREDTBL1, 0x21, 0, 0, false);
set_irq(PIT_IRQ, IOREDTBL2, 0x22, 0, 0, true);
initialize_tss();
load_tss();
asm("sti");

uint32_t apic_ticks = calibrate_apic();
kernel_settings.apic_timer.timer_ticks_base = apic_ticks;
loglinef(Verbose, "(kernel_main) Calibrated apic value: %u", apic_ticks);
loglinef(Verbose, "(kernel_main) (END of Mapped memory: 0x%x)", end_of_mapped_memory);
vfs_init();
logline(Info, "(kernel_main) Init end!! Starting infinite loop");
uint64_t unix_timestamp = read_rtc_time();
#if USE_FRAMEBUFFER == 1
_fb_printStrAndNumber("Epoch time: ", unix_timestamp, 0, 5, 0xf5c4f1, 0x000000);
Expand All @@ -195,7 +190,6 @@ void kernel_start(unsigned long addr, unsigned long magic){
char d = 'd';
task_t* idle_task = create_task("idle", noop, &a);
idle_thread = idle_task->threads;
//idle_thread = create_thread("idle", noop, &a, NULL);
task_t* eldi_task = create_task("eldi", noop2, &b);
create_thread("ledi", noop2, &c, eldi_task);
create_task("sleeper", noop3, &d);
Expand All @@ -208,12 +202,11 @@ void kernel_start(unsigned long addr, unsigned long magic){
int result = close(fd_id);
loglinef(Verbose, "(kernel_main) Closing file with id: %d", result);
//execute_runtime_tests();
//test_get_task();
start_apic_timer(kernel_settings.apic_timer.timer_ticks_base, APIC_TIMER_SET_PERIODIC, kernel_settings.apic_timer.timer_divisor);
loglinef(Verbose, "(kernel_main) (END of Mapped memory: 0x%x)", end_of_mapped_memory);
loglinef(Verbose, "(kernel_main) init_basic_system: Memory lower (in kb): %d - upper (in kb): %d", tagmem->mem_lower, tagmem->mem_upper);
struct multiboot_tag_basic_meminfo *virt_phys_addr = (struct multiboot_tag_basic_meminfo *) vmm_get_variable_from_direct_map ( (size_t) multiboot_basic_meminfo );
loglinef(Verbose, "(kernel_main) init_basic_system: Memory lower (in kb): %d - upper (in kb): %d", virt_phys_addr->mem_lower, virt_phys_addr->mem_upper);
logline(Info, "(kernel_main) Init end!! Starting infinite loop");
while(1);
}

Loading
Loading