From 79f2fa136f26a0b87917336e089485712ee49bd6 Mon Sep 17 00:00:00 2001
From: Marvin Borner
Date: Fri, 7 Aug 2020 21:14:20 +0200
Subject: Dual-tasking works.

I don't know why triple-tasking doesn't though...
---
 src/Makefile          |  1 +
 src/entry.asm         | 29 ++++++++---------------------
 src/features/load.c   |  1 +
 src/features/proc.asm | 25 +++++++++++++++++++++++++
 src/features/proc.c   | 36 +++++++++++++++++++++---------------
 src/inc/proc.h        |  4 ++--
 6 files changed, 58 insertions(+), 38 deletions(-)
 create mode 100644 src/features/proc.asm

(limited to 'src')

diff --git a/src/Makefile b/src/Makefile
index d568901..e917981 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -14,6 +14,7 @@ COBJS = main.o \
 		features/gui.o \
 		features/load.o \
 		features/proc.o \
+		features/proc_asm.o \
 		features/syscall.o \
 		lib/str.o \
 		lib/mem.o \
diff --git a/src/entry.asm b/src/entry.asm
index 67b5ffd..ac70091 100644
--- a/src/entry.asm
+++ b/src/entry.asm
@@ -4,14 +4,17 @@
 
 ; Definitions
 
-%define LOCATION 0x7c00 ; Bootloader location
-
 ; General configurations
 ; TODO: Find out why 2560x1600 doesn't work
 %define VIDEO_WIDTH 1920
 %define VIDEO_HEIGHT 1200
 %define VIDEO_BPP 4
 
+; Boot constants
+%define LOCATION 0x7c00 ; Bootloader location
+%define SECTOR_END 0xaa55 ; Bootsector end signature
+%define SECTOR_SIZE 510 ; 512 bytes minus signature
+
 ; Interrupts
 %define VIDEO_INT 0x10 ; Video BIOS Interrupt
 %define DISK_INT 0x13 ; Disk BIOS Interrupt
@@ -158,8 +161,6 @@ lba_error:
 
 ; Video map routine
 video_map:
-	xor eax, eax
-	mov es, ax
 	mov bx, VESA_START ; Set load address
 	mov di, bx
 	mov ax, VESA_GET_MODES ; Get video modes
@@ -187,7 +188,6 @@ video_map:
 	cmp ax, VESA_SUCCESS_SIG ; Check if call succeeded
 	jne .error ; Nope, jump to error!
 
-	xor ax, ax
 	mov ax, [es:di + VESA_FRAMEBUFFER_OFFSET] ; Save framebuffer
 	mov [.framebuffer], ax ; Move fb address to struct
 
@@ -209,7 +209,6 @@ video_map:
 	lea ax, [es:di - 0x100]
 	mov [vid_info.array], ax
 .set_mode:
-	xor ax, ax
 	mov ax, VESA_SET_MODE ; Set VBE mode
 	mov bx, [.mode] ; Set mode address
 	mov [vid_info], bx ; Move mode information to array
@@ -257,8 +256,8 @@ lba:
 	dd 0 ; More storage bytes
 
 ; End of boot sector
-times 510 - ($ - $$) db 0
-dw 0xAA55
+times SECTOR_SIZE - ($ - $$) db 0
+dw SECTOR_END
 
 ; This is the second stage. It tries to load the kernel (inode 5) into memory.
 ; To do this, it first checks the integrity of the ext2 fs. Then it has to find
@@ -297,9 +296,6 @@ stage_two:
 	jmp protected_mode_enter
 
 kernel_load:
-	xor ax, ax ; Clear ax
-	mov dx, ax ; Clear dx
-
 	; TODO: Add singly pointer support (until ~12KiB)
 	;cmp cx, EXT2_DIRECT_POINTER_COUNT ; Indirect pointer needed?
 	;jge .indirect ; Singly indirect pointer
@@ -316,8 +312,6 @@ kernel_load:
 ;	push bx
 ;	push cx
 ;
-;	xor ebx, ebx
-;
 ;	; Read singly indirect pointer
 ;	mov bx, EXT2_GET_ADDRESS(EXT2_KERNEL_INODE) ; First block
 ;	lea di, [bx + EXT2_IND_POINTER_OFFSET] ; Address of singly indirect pointer
@@ -363,13 +357,6 @@ protected_mode_enter:
 	out A20_GATE, al
 	.a20_enabled:
 
-	; Clear registers
-	xor ax, ax
-	mov ds, ax
-	mov es, ax
-	mov fs, ax
-	mov gs, ax
-
 	lgdt [gdt_desc] ; Load GDT
 
 	; Set protected mode via cr0
@@ -390,7 +377,7 @@ protected_mode:
 
 	mov esp, STACK_POINTER ; Move stack pointer
 
-	mov ax, gdt_tss - gdt ; Load TSS
+	mov ax, (gdt_tss - gdt) | 0b11 ; Load TSS in ring 3
 	ltr ax
 
 	mov eax, vid_info ; Pass VBE struct to kernel
diff --git a/src/features/load.c b/src/features/load.c
index 5382c77..cc1a094 100644
--- a/src/features/load.c
+++ b/src/features/load.c
@@ -14,5 +14,6 @@ void bin_load(char *path, struct proc *proc)
 
 	proc->regs.ebp = (u32)stack;
 	proc->regs.esp = (u32)stack;
+	proc->regs.useresp = (u32)stack;
 	proc->regs.eip = (u32)data;
 }
diff --git a/src/features/proc.asm b/src/features/proc.asm
new file mode 100644
index 0000000..3d6bbc4
--- /dev/null
+++ b/src/features/proc.asm
@@ -0,0 +1,25 @@
+%define USER_CODE_SEGMENT 0x18
+%define USER_DATA_SEGMENT 0x20
+%define RING3_MASK 0b11
+
+global proc_jump_userspace
+extern _esp
+extern _eip
+proc_jump_userspace:
+	mov ax, USER_DATA_SEGMENT | RING3_MASK
+	mov ds, ax
+	mov es, ax
+	mov fs, ax
+	mov gs, ax
+
+	mov eax, dword [_esp]
+	push USER_DATA_SEGMENT | RING3_MASK
+	push eax
+	pushf
+
+	sti
+
+	push USER_CODE_SEGMENT | RING3_MASK
+	push dword [_eip]
+
+	iret
diff --git a/src/features/proc.c b/src/features/proc.c
index 46b55fb..a14aaea 100644
--- a/src/features/proc.c
+++ b/src/features/proc.c
@@ -16,10 +16,8 @@ struct proc *last;
 
 void scheduler(struct regs *regs)
 {
-	if (current) {
-		printf("%d", current->pid);
+	if (current)
 		memcpy(&current->regs, regs, sizeof(struct regs));
-	}
 
 	timer_handler();
 
@@ -34,7 +32,19 @@ void scheduler(struct regs *regs)
 		else
 			current = current->next;
 
+	/* proc_print(); */
 	memcpy(regs, &current->regs, sizeof(struct regs));
+
+	if (regs->cs != GDT_USER_CODE_OFFSET) {
+		regs->gs = GDT_USER_DATA_OFFSET;
+		regs->fs = GDT_USER_DATA_OFFSET;
+		regs->es = GDT_USER_DATA_OFFSET;
+		regs->ds = GDT_USER_DATA_OFFSET;
+		regs->ss = GDT_USER_DATA_OFFSET;
+		regs->cs = GDT_USER_CODE_OFFSET;
+		regs->eflags = EFLAGS_ALWAYS | EFLAGS_INTERRUPTS;
+	}
+	printf("%d", current->pid);
 }
 
 void proc_print()
@@ -64,19 +74,10 @@ void proc_attach(struct proc *proc)
 
 struct proc *proc_make()
 {
-	/* if (current) */
-	/* 	current->state = PROC_ASLEEP; */
 	struct proc *proc = malloc(sizeof(*proc));
 	proc->pid = pid++;
 	proc->state = PROC_RUNNING;
-
-	// Configure registers (default data)
-	proc->regs.ds = GDT_DATA_OFFSET;
-	proc->regs.es = GDT_DATA_OFFSET;
-	proc->regs.fs = GDT_DATA_OFFSET;
-	proc->regs.gs = GDT_DATA_OFFSET;
-	proc->regs.cs = GDT_CODE_OFFSET;
-	proc->regs.eflags = EFLAGS_ALWAYS | EFLAGS_INTERRUPTS;
+	proc->next = NULL;
 
 	if (current)
 		proc_attach(proc);
@@ -84,6 +85,9 @@ struct proc *proc_make()
 	return proc;
 }
 
+extern void proc_jump_userspace();
+
+u32 _esp, _eip;
 void proc_init()
 {
 	cli();
@@ -93,6 +97,8 @@ void proc_init()
 	bin_load("/init", root);
 	strcpy(root->name, "root");
 	proc_print();
-	sti();
-	hlt();
+
+	_eip = root->regs.eip;
+	_esp = root->regs.esp;
+	proc_jump_userspace();
 }
diff --git a/src/inc/proc.h b/src/inc/proc.h
index 8231810..39ba704 100644
--- a/src/inc/proc.h
+++ b/src/inc/proc.h
@@ -9,8 +9,8 @@
 #define EFLAGS_ALWAYS 0x2 // Always one
 #define EFLAGS_INTERRUPTS 0x200 // Enable interrupts
 
-#define GDT_DATA_OFFSET 0x10 // Data segment offset in GDT
-#define GDT_CODE_OFFSET 0x8 // Code segment offset in GDT
+#define GDT_USER_CODE_OFFSET 0x1b // User code segment offset in GDT (with ring3 mask)
+#define GDT_USER_DATA_OFFSET 0x23 // User data segment offset in GDT (with ring3 mask)
 
 enum state { PROC_RUNNING, PROC_ASLEEP };
 
-- 
cgit v1.2.3