|  | @@ -6,6 +6,7 @@
 | 
	
		
			
				|  |  |  #include <kernel/tty.h>
 | 
	
		
			
				|  |  |  #include <kernel_main.h>
 | 
	
		
			
				|  |  |  #include <types/types.h>
 | 
	
		
			
				|  |  | +#include <types/lock.h>
 | 
	
		
			
				|  |  |  #include <hello-world.res>
 | 
	
		
			
				|  |  |  #include <interrupt-test.res>
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -13,15 +14,13 @@ extern "C" void NORETURN go_user_space(void* eip);
 | 
	
		
			
				|  |  |  extern "C" void NORETURN to_kernel(interrupt_stack* ret_stack);
 | 
	
		
			
				|  |  |  extern "C" void NORETURN to_user(interrupt_stack* ret_stack);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static inline void* align_down_to_16byte(void* addr)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    return (void*)((uint32_t)addr & 0xfffffff0);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  static bool is_scheduler_ready;
 | 
	
		
			
				|  |  |  static types::list<process>* processes;
 | 
	
		
			
				|  |  |  static types::list<thread*>* ready_thds;
 | 
	
		
			
				|  |  |  static pid_t max_pid = 1;
 | 
	
		
			
				|  |  | +void (* volatile kthreadd_new_thd_func)(void*);
 | 
	
		
			
				|  |  | +void  * volatile kthreadd_new_thd_data;
 | 
	
		
			
				|  |  | +uint32_t kthreadd_lock = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  thread* current_thread;
 | 
	
		
			
				|  |  |  process* current_process;
 | 
	
	
		
			
				|  | @@ -49,13 +48,15 @@ process::process(const process& val, const thread& main_thd)
 | 
	
		
			
				|  |  |      , attr { .system = val.attr.system }
 | 
	
		
			
				|  |  |      , pid { max_pid++ }
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    k_esp = (char*)k_malloc(THREAD_KERNEL_STACK_SIZE);
 | 
	
		
			
				|  |  | -    memset((char*)k_esp, 0x00, THREAD_KERNEL_STACK_SIZE);
 | 
	
		
			
				|  |  | -    k_esp = align_down_to_16byte((char*)k_esp + THREAD_KERNEL_STACK_SIZE);
 | 
	
		
			
				|  |  |      auto iter_thd = thds.emplace_back(main_thd);
 | 
	
		
			
				|  |  |      iter_thd->owner = this;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (!val.attr.system) {
 | 
	
		
			
				|  |  | +        // TODO: allocate low mem
 | 
	
		
			
				|  |  | +        k_esp = (void*)page_to_phys_addr(alloc_n_raw_pages(2));
 | 
	
		
			
				|  |  | +        memset((char*)k_esp, 0x00, THREAD_KERNEL_STACK_SIZE);
 | 
	
		
			
				|  |  | +        k_esp = (char*)k_esp + THREAD_KERNEL_STACK_SIZE;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          page_directory_entry* pd = alloc_pd();
 | 
	
		
			
				|  |  |          memcpy(pd, mms_get_pd(kernel_mms), PAGE_SIZE);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -72,6 +73,19 @@ process::process(const process& val, const thread& main_thd)
 | 
	
		
			
				|  |  |                          iter_src->attr.system,
 | 
	
		
			
				|  |  |                          1);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        // TODO: allocate low mem
 | 
	
		
			
				|  |  | +        k_esp = (void*)page_to_phys_addr(alloc_n_raw_pages(2));
 | 
	
		
			
				|  |  | +        memcpy(k_esp, main_thd.owner->k_esp, THREAD_KERNEL_STACK_SIZE);
 | 
	
		
			
				|  |  | +        k_esp = (char*)k_esp + THREAD_KERNEL_STACK_SIZE;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        auto orig_k_esp = (uint32_t)main_thd.owner->k_esp;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        iter_thd->regs.ebp -= orig_k_esp;
 | 
	
		
			
				|  |  | +        iter_thd->regs.ebp += (uint32_t)k_esp;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        iter_thd->regs.esp -= orig_k_esp;
 | 
	
		
			
				|  |  | +        iter_thd->regs.esp += (uint32_t)k_esp;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -81,9 +95,10 @@ process::process(void* start_eip, uint8_t* image, size_t image_size, bool system
 | 
	
		
			
				|  |  |      , attr { .system = system }
 | 
	
		
			
				|  |  |      , pid { max_pid++ }
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    k_esp = (char*)k_malloc(THREAD_KERNEL_STACK_SIZE);
 | 
	
		
			
				|  |  | +    // TODO: allocate low mem
 | 
	
		
			
				|  |  | +    k_esp = (void*)page_to_phys_addr(alloc_n_raw_pages(2));
 | 
	
		
			
				|  |  |      memset((char*)k_esp, 0x00, THREAD_KERNEL_STACK_SIZE);
 | 
	
		
			
				|  |  | -    k_esp = align_down_to_16byte((char*)k_esp + THREAD_KERNEL_STACK_SIZE);
 | 
	
		
			
				|  |  | +    k_esp = (char*)k_esp + THREAD_KERNEL_STACK_SIZE;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      auto thd = thds.emplace_back(thread {
 | 
	
		
			
				|  |  |          .eip = start_eip,
 | 
	
	
		
			
				|  | @@ -137,11 +152,46 @@ process::process(void* start_eip, uint8_t* image, size_t image_size, bool system
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +void _example_io_thread(void* _d)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const char* data = reinterpret_cast<const char*>(_d);
 | 
	
		
			
				|  |  | +    tty_print(console, data);
 | 
	
		
			
				|  |  | +    // syscall_sleep
 | 
	
		
			
				|  |  | +    asm volatile("movl $0x02, %%eax\nint $0x80":::"eax");
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  void kernel_threadd_main(void)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      tty_print(console, "kernel thread daemon started\n");
 | 
	
		
			
				|  |  | -    for (;;)
 | 
	
		
			
				|  |  | +    kthreadd_new_thd_func = _example_io_thread;
 | 
	
		
			
				|  |  | +    kthreadd_new_thd_data = (void*)"data in io thread\n";
 | 
	
		
			
				|  |  | +    for (;;) {
 | 
	
		
			
				|  |  | +        spin_lock(&kthreadd_lock);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (kthreadd_new_thd_func) {
 | 
	
		
			
				|  |  | +            int return_value = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            void (*func)(void*) = kthreadd_new_thd_func;
 | 
	
		
			
				|  |  | +            void* data = kthreadd_new_thd_data;
 | 
	
		
			
				|  |  | +            kthreadd_new_thd_func = nullptr;
 | 
	
		
			
				|  |  | +            kthreadd_new_thd_data = nullptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            spin_unlock(&kthreadd_lock);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // syscall_fork
 | 
	
		
			
				|  |  | +            asm volatile("movl $0x00, %%eax\nint $0x80\nmovl %%eax, %0": "=a" (return_value): :);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (return_value != 0) {
 | 
	
		
			
				|  |  | +                // child
 | 
	
		
			
				|  |  | +                func(data);
 | 
	
		
			
				|  |  | +                for (;;) asm_hlt();
 | 
	
		
			
				|  |  | +                // TODO: syscall_exit()
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            spin_unlock(&kthreadd_lock);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |          asm_hlt();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void NORETURN init_scheduler()
 | 
	
	
		
			
				|  | @@ -212,9 +262,9 @@ void add_to_ready_list(thread* thd)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static inline void next_task(const types::list<thread*>::iterator_type& iter_to_remove, thread* cur_thd)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -        ready_thds->erase(iter_to_remove);
 | 
	
		
			
				|  |  | -        if (cur_thd->attr.ready)
 | 
	
		
			
				|  |  | -            ready_thds->push_back(cur_thd);
 | 
	
		
			
				|  |  | +    ready_thds->erase(iter_to_remove);
 | 
	
		
			
				|  |  | +    if (cur_thd->attr.ready)
 | 
	
		
			
				|  |  | +        ready_thds->push_back(cur_thd);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void do_scheduling(interrupt_stack* intrpt_data)
 |