Kernel: We can create basic userspace processes
These are still allocated on the kernel memory
This commit is contained in:
		
							parent
							
								
									34358b8471
								
							
						
					
					
						commit
						8ee63f8264
					
				|  | @ -26,3 +26,22 @@ continue_thread: | ||||||
| 	movl 4(%esp), %esp | 	movl 4(%esp), %esp | ||||||
| 	movl $0, %eax | 	movl $0, %eax | ||||||
| 	jmp *%ecx | 	jmp *%ecx | ||||||
|  | 
 | ||||||
|  | # void thread_jump_userspace(uint32_t rsp, uint32_t rip) | ||||||
|  | .global thread_jump_userspace
 | ||||||
|  | thread_jump_userspace: | ||||||
|  | 	movl $0x23, %eax | ||||||
|  | 	movw %ax, %ds | ||||||
|  | 	movw %ax, %es | ||||||
|  | 	movw %ax, %fs | ||||||
|  | 	movw %ax, %gs | ||||||
|  | 
 | ||||||
|  | 	movl 8(%esp), %ecx | ||||||
|  | 	movl 4(%esp), %esp | ||||||
|  | 
 | ||||||
|  | 	pushl $0x23 | ||||||
|  | 	pushl %esp | ||||||
|  | 	pushfl | ||||||
|  | 	pushl $0x1B | ||||||
|  | 	pushl %ecx | ||||||
|  | 	iret | ||||||
|  |  | ||||||
|  | @ -24,3 +24,13 @@ continue_thread: | ||||||
| 	movq %rdi, %rsp | 	movq %rdi, %rsp | ||||||
| 	movq $0, %rax | 	movq $0, %rax | ||||||
| 	jmp *%rsi | 	jmp *%rsi | ||||||
|  | 
 | ||||||
|  | # void thread_jump_userspace(uint64_t rsp, uint64_t rip) | ||||||
|  | .global thread_jump_userspace
 | ||||||
|  | thread_jump_userspace: | ||||||
|  | 	pushq $0x23 | ||||||
|  | 	pushq %rdi | ||||||
|  | 	pushfq | ||||||
|  | 	pushq $0x1B | ||||||
|  | 	pushq %rsi | ||||||
|  | 	iretq | ||||||
|  |  | ||||||
|  | @ -23,9 +23,10 @@ namespace Kernel | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
| 		static BAN::ErrorOr<BAN::RefPtr<Process>> create_kernel(entry_t, void*); | 		static BAN::ErrorOr<BAN::RefPtr<Process>> create_kernel(entry_t, void*); | ||||||
|  | 		static BAN::ErrorOr<BAN::RefPtr<Process>> create_userspace(void(*)()); | ||||||
| 		~Process(); | 		~Process(); | ||||||
| 
 | 
 | ||||||
| 		void exit(); | 		[[noreturn]] void exit(); | ||||||
| 
 | 
 | ||||||
| 		BAN::ErrorOr<Thread*> add_thread(entry_t, void*); | 		BAN::ErrorOr<Thread*> add_thread(entry_t, void*); | ||||||
| 		void on_thread_exit(Thread&); | 		void on_thread_exit(Thread&); | ||||||
|  |  | ||||||
|  | @ -1,4 +1,20 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #define SYS_TEST 0 | #define SYS_EXIT 1 | ||||||
| #define SYS_PUTC 1 | #define SYS_READ 2 | ||||||
|  | #define SYS_WRITE 3 | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | namespace Kernel | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | 	template<typename T1 = void*, typename T2 = void*, typename T3 = void*> | ||||||
|  | 	inline int syscall(int syscall, T1 arg1 = nullptr, T2 arg2 = nullptr, T3 arg3 = nullptr) | ||||||
|  | 	{ | ||||||
|  | 		int ret; | ||||||
|  | 		asm volatile("int $0x80" : "=a"(ret) : "a"(syscall), "b"((uintptr_t)arg1), "c"((uintptr_t)arg2), "d"((uintptr_t)arg3) : "memory"); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -29,6 +29,8 @@ namespace Kernel | ||||||
| 		static BAN::ErrorOr<Thread*> create(entry_t, void* = nullptr, BAN::RefPtr<Process> = nullptr); | 		static BAN::ErrorOr<Thread*> create(entry_t, void* = nullptr, BAN::RefPtr<Process> = nullptr); | ||||||
| 		~Thread(); | 		~Thread(); | ||||||
| 
 | 
 | ||||||
|  | 		void jump_userspace(uintptr_t rip); | ||||||
|  | 
 | ||||||
| 		pid_t tid() const { return m_tid; } | 		pid_t tid() const { return m_tid; } | ||||||
| 
 | 
 | ||||||
| 		void set_rsp(uintptr_t rsp) { m_rsp = rsp; } | 		void set_rsp(uintptr_t rsp) { m_rsp = rsp; } | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| #include <kernel/CriticalScope.h> | #include <kernel/CriticalScope.h> | ||||||
| #include <kernel/FS/VirtualFileSystem.h> | #include <kernel/FS/VirtualFileSystem.h> | ||||||
| #include <kernel/LockGuard.h> | #include <kernel/LockGuard.h> | ||||||
|  | #include <kernel/MMU.h> | ||||||
| #include <kernel/Process.h> | #include <kernel/Process.h> | ||||||
| #include <kernel/Scheduler.h> | #include <kernel/Scheduler.h> | ||||||
| 
 | 
 | ||||||
|  | @ -20,6 +21,25 @@ namespace Kernel | ||||||
| 		return process; | 		return process; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	BAN::ErrorOr<BAN::RefPtr<Process>> Process::create_userspace(void(*entry)()) | ||||||
|  | 	{ | ||||||
|  | 		auto process = TRY(BAN::RefPtr<Process>::create(s_next_pid++)); | ||||||
|  | 		TRY(process->m_working_directory.push_back('/')); | ||||||
|  | 		TRY(process->init_stdio()); | ||||||
|  | 
 | ||||||
|  | 		TRY(process->add_thread( | ||||||
|  | 			[](void* entry_func) | ||||||
|  | 			{ | ||||||
|  | 				Thread& current = Thread::current(); | ||||||
|  | 				MMU::get().allocate_range(current.stack_base(), current.stack_size(), MMU::Flags::UserSupervisor | MMU::Flags::ReadWrite | MMU::Flags::Present); | ||||||
|  | 				current.jump_userspace((uintptr_t)entry_func); | ||||||
|  | 				ASSERT_NOT_REACHED(); | ||||||
|  | 			}, (void*)entry | ||||||
|  | 		)); | ||||||
|  | 
 | ||||||
|  | 		return process; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	Process::Process(pid_t pid) | 	Process::Process(pid_t pid) | ||||||
| 		: m_pid(pid) | 		: m_pid(pid) | ||||||
| 		, m_tty(TTY::current()) | 		, m_tty(TTY::current()) | ||||||
|  |  | ||||||
|  | @ -1,19 +1,28 @@ | ||||||
| #include <kernel/Debug.h> | #include <kernel/Debug.h> | ||||||
| #include <kernel/kprint.h> | #include <kernel/Process.h> | ||||||
| #include <kernel/Syscall.h> | #include <kernel/Syscall.h> | ||||||
| 
 | 
 | ||||||
| namespace Kernel | namespace Kernel | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| 	int sys_test() | 	void sys_exit() | ||||||
| 	{ | 	{ | ||||||
| 		dprintln("hello"); | 		Process::current()->exit(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	int sys_read(int fd, void* buffer, size_t size) | ||||||
|  | 	{ | ||||||
|  | 		auto res = Process::current()->read(fd, buffer, size); | ||||||
|  | 		if (res.is_error()) | ||||||
|  | 			return res.error().get_error_code(); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	int sys_putc(void* ch) | 	int sys_write(int fd, const void* buffer, size_t size) | ||||||
| 	{ | 	{ | ||||||
| 		kprint("{}", (char)(uintptr_t)ch); | 		auto res = Process::current()->write(fd, buffer, size); | ||||||
|  | 		if (res.is_error()) | ||||||
|  | 			return res.error().get_error_code(); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -23,14 +32,17 @@ namespace Kernel | ||||||
| 		(void)arg2; | 		(void)arg2; | ||||||
| 		(void)arg3; | 		(void)arg3; | ||||||
| 
 | 
 | ||||||
| 		int ret; | 		int ret = 0; | ||||||
| 		switch (syscall) | 		switch (syscall) | ||||||
| 		{ | 		{ | ||||||
| 		case SYS_TEST: | 		case SYS_EXIT: | ||||||
| 			ret = sys_test(); | 			sys_exit(); | ||||||
| 			break; | 			break; | ||||||
| 		case SYS_PUTC: | 		case SYS_READ: | ||||||
| 			ret = sys_putc(arg1); | 			ret = sys_read((int)(uintptr_t)arg1, arg2, (size_t)(uintptr_t)arg3); | ||||||
|  | 			break; | ||||||
|  | 		case SYS_WRITE: | ||||||
|  | 			ret = sys_write((int)(uintptr_t)arg1, arg2, (size_t)(uintptr_t)arg3); | ||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			ret = -1; | 			ret = -1; | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ | ||||||
| namespace Kernel | namespace Kernel | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
|  | 	extern "C" void thread_jump_userspace(uintptr_t rsp, uintptr_t rip); | ||||||
| 
 | 
 | ||||||
| 	template<size_t size, typename T> | 	template<size_t size, typename T> | ||||||
| 	static void write_to_stack(uintptr_t& rsp, const T& value) | 	static void write_to_stack(uintptr_t& rsp, const T& value) | ||||||
|  | @ -63,6 +64,11 @@ namespace Kernel | ||||||
| 		kfree(m_stack_base); | 		kfree(m_stack_base); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	void Thread::jump_userspace(uintptr_t rip) | ||||||
|  | 	{ | ||||||
|  | 		thread_jump_userspace(rsp(), rip); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	void Thread::on_exit() | 	void Thread::on_exit() | ||||||
| 	{ | 	{ | ||||||
| 		if (m_process) | 		if (m_process) | ||||||
|  |  | ||||||
|  | @ -103,6 +103,7 @@ extern "C" uintptr_t g_userspace_start; | ||||||
| extern "C" uintptr_t g_userspace_end; | extern "C" uintptr_t g_userspace_end; | ||||||
| 
 | 
 | ||||||
| extern void userspace_entry(); | extern void userspace_entry(); | ||||||
|  | static void jump_userspace(); | ||||||
| 
 | 
 | ||||||
| static void init2(void*); | static void init2(void*); | ||||||
| 
 | 
 | ||||||
|  | @ -154,54 +155,10 @@ extern "C" void kernel_main() | ||||||
| 
 | 
 | ||||||
| 	MUST(Scheduler::initialize()); | 	MUST(Scheduler::initialize()); | ||||||
| 	Scheduler& scheduler = Scheduler::get(); | 	Scheduler& scheduler = Scheduler::get(); | ||||||
| #if 0 
 |  | ||||||
| 	MUST(scheduler.add_thread(MUST(Thread::create( |  | ||||||
| 		[] (void*) |  | ||||||
| 		{ |  | ||||||
| 			MMU::get().allocate_range((uintptr_t)&g_userspace_start, (uintptr_t)&g_userspace_end - (uintptr_t)&g_userspace_start, MMU::Flags::UserSupervisor | MMU::Flags::Present); |  | ||||||
| 			MMU::get().allocate_range((uintptr_t)&g_rodata_start,    (uintptr_t)&g_rodata_end    - (uintptr_t)&g_rodata_start,    MMU::Flags::UserSupervisor | MMU::Flags::Present); |  | ||||||
| 
 |  | ||||||
| 			void* userspace_stack = kmalloc(4096, 4096); |  | ||||||
| 			ASSERT(userspace_stack); |  | ||||||
| 			MMU::get().allocate_page((uintptr_t)userspace_stack, MMU::Flags::UserSupervisor | MMU::Flags::ReadWrite | MMU::Flags::Present); |  | ||||||
| 
 |  | ||||||
| 			BOCHS_BREAK(); |  | ||||||
| 
 |  | ||||||
| #if ARCH(x86_64) |  | ||||||
| 			asm volatile( |  | ||||||
| 				"pushq %0;" |  | ||||||
| 				"pushq %1;" |  | ||||||
| 				"pushfq;" |  | ||||||
| 				"pushq %2;" |  | ||||||
| 				"pushq %3;" |  | ||||||
| 				"iretq;" |  | ||||||
| 				:: "r"((uintptr_t)0x20 | 3), "r"((uintptr_t)userspace_stack + 4096), "r"((uintptr_t)0x18 | 3), "r"(userspace_entry) |  | ||||||
| 			); |  | ||||||
| #else |  | ||||||
| 			asm volatile( |  | ||||||
| 				"movl %0, %%eax;" |  | ||||||
| 				"movw %%ax, %%ds;" |  | ||||||
| 				"movw %%ax, %%es;" |  | ||||||
| 				"movw %%ax, %%fs;" |  | ||||||
| 				"movw %%ax, %%gs;" |  | ||||||
| 
 |  | ||||||
| 				"movl %1, %%esp;" |  | ||||||
| 				"pushl %0;" |  | ||||||
| 				"pushl %1;" |  | ||||||
| 				"pushfl;" |  | ||||||
| 				"pushl %2;" |  | ||||||
| 				"pushl %3;" |  | ||||||
| 				"iret;" |  | ||||||
| 				:: "r"((uintptr_t)0x20 | 3), "r"((uintptr_t)userspace_stack + 4096), "r"((uintptr_t)0x18 | 3), "r"(userspace_entry) |  | ||||||
| 			); |  | ||||||
| #endif |  | ||||||
| 		} |  | ||||||
| 	)))); |  | ||||||
| #else |  | ||||||
| 	MUST(scheduler.add_thread(MUST(Thread::create(init2, terminal_driver)))); | 	MUST(scheduler.add_thread(MUST(Thread::create(init2, terminal_driver)))); | ||||||
| #endif |  | ||||||
| 	scheduler.start(); | 	scheduler.start(); | ||||||
| 	ASSERT(false); | 
 | ||||||
|  | 	ASSERT_NOT_REACHED(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void init2(void* terminal_driver) | static void init2(void* terminal_driver) | ||||||
|  | @ -220,6 +177,8 @@ static void init2(void* terminal_driver) | ||||||
| 	ASSERT(tty1); | 	ASSERT(tty1); | ||||||
| 	DeviceManager::get().add_device(tty1); | 	DeviceManager::get().add_device(tty1); | ||||||
| 
 | 
 | ||||||
|  | 	return jump_userspace(); | ||||||
|  | 
 | ||||||
| 	MUST(Process::create_kernel( | 	MUST(Process::create_kernel( | ||||||
| 		[](void*)  | 		[](void*)  | ||||||
| 		{ | 		{ | ||||||
|  | @ -230,3 +189,13 @@ static void init2(void* terminal_driver) | ||||||
| 		}, nullptr | 		}, nullptr | ||||||
| 	)); | 	)); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | static void jump_userspace() | ||||||
|  | { | ||||||
|  | 	using namespace Kernel; | ||||||
|  | 
 | ||||||
|  | 	MMU::get().allocate_range((uintptr_t)&g_userspace_start, (uintptr_t)&g_userspace_end - (uintptr_t)&g_userspace_start, MMU::Flags::UserSupervisor | MMU::Flags::Present); | ||||||
|  | 	MMU::get().allocate_range((uintptr_t)&g_rodata_start,    (uintptr_t)&g_rodata_end    - (uintptr_t)&g_rodata_start,    MMU::Flags::UserSupervisor | MMU::Flags::Present); | ||||||
|  | 
 | ||||||
|  | 	MUST(Process::create_userspace(userspace_entry)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1,28 +1,12 @@ | ||||||
| #include <BAN/Formatter.h> | #include <BAN/Formatter.h> | ||||||
| #include <kernel/Syscall.h> | #include <kernel/Syscall.h> | ||||||
| 
 | 
 | ||||||
|  | #include <unistd.h> | ||||||
|  | 
 | ||||||
| #define USERSPACE __attribute__((section(".userspace"))) | #define USERSPACE __attribute__((section(".userspace"))) | ||||||
| 
 | 
 | ||||||
| USERSPACE int syscall(int syscall, void* arg1 = nullptr, void* arg2 = nullptr, void* arg3 = nullptr) |  | ||||||
| { |  | ||||||
| 	int ret; |  | ||||||
| 	asm volatile("int $0x80" : "=a"(ret) : "a"(syscall), "b"(arg1), "c"(arg2), "d"(arg3) : "memory"); |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| USERSPACE void user_putc(char ch) |  | ||||||
| { |  | ||||||
| 	syscall(SYS_PUTC, (void*)(uintptr_t)ch); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| USERSPACE void print(const char* str) |  | ||||||
| { |  | ||||||
| 	while (*str) |  | ||||||
| 		user_putc(*str++); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| USERSPACE void userspace_entry() | USERSPACE void userspace_entry() | ||||||
| { | { | ||||||
| 	BAN::Formatter::println(user_putc, "Hello {}!", "World"); | 	Kernel::syscall(SYS_WRITE, STDOUT_FILENO, "Hello World!", 12); | ||||||
| 	for (;;); | 	Kernel::syscall(SYS_EXIT); | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue