process.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. #include <memory>
  2. #include <queue>
  3. #include <utility>
  4. #include <assert.h>
  5. #include <bits/alltypes.h>
  6. #include <stdint.h>
  7. #include <stdio.h>
  8. #include <sys/mount.h>
  9. #include <sys/wait.h>
  10. #include <types/allocator.hpp>
  11. #include <types/cplusplus.hpp>
  12. #include <types/elf.hpp>
  13. #include <types/types.h>
  14. #include <kernel/async/lock.hpp>
  15. #include <kernel/log.hpp>
  16. #include <kernel/mem/paging.hpp>
  17. #include <kernel/module.hpp>
  18. #include <kernel/process.hpp>
  19. #include <kernel/signal.hpp>
  20. #include <kernel/task/readyqueue.hpp>
  21. #include <kernel/task/thread.hpp>
  22. #include <kernel/user/thread_local.hpp>
  23. #include <kernel/vfs.hpp>
  24. #include <kernel/vfs/dentry.hpp>
  25. process::process(const process& parent, pid_t pid)
  26. : mms{parent.mms}
  27. , attr{parent.attr}
  28. , files{parent.files.copy()}
  29. , umask{parent.umask}
  30. , pid{pid}
  31. , ppid{parent.pid}
  32. , pgid{parent.pgid}
  33. , sid{parent.sid}
  34. , control_tty{parent.control_tty} {
  35. if (parent.cwd)
  36. cwd = fs::d_get(parent.cwd);
  37. if (parent.fs_context.root)
  38. fs_context.root = fs::d_get(parent.fs_context.root);
  39. }
  40. process::process(pid_t pid, pid_t ppid)
  41. : attr{.system = true}, files{&fs_context}, pid{pid}, ppid{ppid} {
  42. bool inserted;
  43. std::tie(std::ignore, inserted) = thds.emplace("", pid);
  44. assert(inserted);
  45. }
  46. using signo_type = kernel::signal_list::signo_type;
  47. void process::send_signal(signo_type signal) {
  48. for (auto& thd : thds)
  49. thd.send_signal(signal);
  50. }
  51. void kernel_threadd_main(void) {
  52. kmsg("[kernel] kthread daemon started");
  53. // TODO: create new kthread
  54. for (;;)
  55. asm volatile("hlt");
  56. }
  57. static inline void __spawn(kernel::task::thread& thd, uintptr_t entry) {
  58. auto prev_sp = thd.kstack.sp;
  59. // return(start) address
  60. thd.kstack.pushq(entry);
  61. thd.kstack.pushq(0x200); // flags
  62. thd.kstack.pushq(0); // r15
  63. thd.kstack.pushq(0); // r14
  64. thd.kstack.pushq(0); // r13
  65. thd.kstack.pushq(0); // r12
  66. thd.kstack.pushq(0); // rbp
  67. thd.kstack.pushq(0); // rbx
  68. thd.kstack.pushq(0); // 0 for alignment
  69. thd.kstack.pushq(prev_sp); // previous sp
  70. }
  71. SECTION(".text.kinit")
  72. proclist::proclist() {
  73. // init process has no parent
  74. auto& init = real_emplace(1, 0);
  75. assert(init.pid == 1 && init.ppid == 0);
  76. auto thd = init.thds.begin();
  77. thd->name.assign("[kernel init]");
  78. current_process = &init;
  79. current_thread = &thd;
  80. kernel::task::dispatcher::enqueue(current_thread);
  81. current_thread->kstack.load_interrupt_stack();
  82. current_process->mms.switch_pd();
  83. if (1) {
  84. // pid 0 is kernel thread daemon
  85. auto& proc = real_emplace(0, 0);
  86. assert(proc.pid == 0 && proc.ppid == 0);
  87. // create thread
  88. auto thd = proc.thds.begin();
  89. thd->name.assign("[kernel thread daemon]");
  90. __spawn(*thd, (uintptr_t)kernel_threadd_main);
  91. kernel::task::dispatcher::setup_idle(&thd);
  92. }
  93. }
  94. process& proclist::real_emplace(pid_t pid, pid_t ppid) {
  95. auto [iter, inserted] = m_procs.try_emplace(pid, pid, ppid);
  96. assert(inserted);
  97. return iter->second;
  98. }
  99. void proclist::kill(pid_t pid, int exit_code) {
  100. auto& proc = this->find(pid);
  101. // init should never exit
  102. if (proc.ppid == 0) {
  103. kmsg("kernel panic: init exited!");
  104. freeze();
  105. }
  106. kernel::async::preempt_disable();
  107. // put all threads into sleep
  108. for (auto& thd : proc.thds)
  109. thd.set_attr(kernel::task::thread::ZOMBIE);
  110. // TODO: CHANGE THIS
  111. // files should only be closed when this is the last thread
  112. //
  113. // write back mmap'ped files and close them
  114. proc.files.clear();
  115. // unmap all user memory areas
  116. proc.mms.clear();
  117. // free cwd and fs_context dentry
  118. proc.cwd.reset();
  119. proc.fs_context.root.reset();
  120. // make child processes orphans (children of init)
  121. this->make_children_orphans(pid);
  122. proc.attr.zombie = 1;
  123. // notify parent process and init
  124. auto& parent = this->find(proc.ppid);
  125. auto& init = this->find(1);
  126. using kernel::async::lock_guard;
  127. bool flag = false;
  128. if (1) {
  129. lock_guard lck(init.mtx_waitprocs);
  130. if (1) {
  131. lock_guard lck(proc.mtx_waitprocs);
  132. for (const auto& item : proc.waitprocs) {
  133. if (WIFSTOPPED(item.code) || WIFCONTINUED(item.code))
  134. continue;
  135. init.waitprocs.push_back(item);
  136. flag = true;
  137. }
  138. proc.waitprocs.clear();
  139. }
  140. }
  141. if (flag)
  142. init.waitlist.notify_all();
  143. if (1) {
  144. lock_guard lck(parent.mtx_waitprocs);
  145. parent.waitprocs.push_back({pid, exit_code});
  146. }
  147. parent.waitlist.notify_all();
  148. kernel::async::preempt_enable();
  149. }
  150. static void release_kinit() {
  151. // free .kinit
  152. using namespace kernel::mem::paging;
  153. extern uintptr_t volatile KINIT_START_ADDR, KINIT_END_ADDR, KINIT_PAGES;
  154. std::size_t pages = KINIT_PAGES;
  155. auto range = vaddr_range{KERNEL_PAGE_TABLE_ADDR, KINIT_START_ADDR,
  156. KINIT_END_ADDR, true};
  157. for (auto pte : range)
  158. pte.clear();
  159. create_zone(0x2000, 0x2000 + 0x1000 * pages);
  160. }
  161. extern "C" void (*const late_init_start[])();
  162. extern "C" void late_init_rust();
  163. void NORETURN _kernel_init(kernel::mem::paging::pfn_t kernel_stack_pfn) {
  164. kernel::mem::paging::free_pages(kernel_stack_pfn, 9);
  165. release_kinit();
  166. kernel::kmod::load_internal_modules();
  167. late_init_rust();
  168. asm volatile("sti");
  169. // mount rootfs
  170. fs::vfs* rootfs;
  171. if (1) {
  172. int ret;
  173. std::tie(rootfs, ret) =
  174. fs::vfs::create("none", "tmpfs", MS_NOATIME, nullptr);
  175. assert(ret == 0);
  176. }
  177. current_process->fs_context.root = d_get(rootfs->root());
  178. current_process->cwd = d_get(rootfs->root());
  179. // ------------------------------------------
  180. // interrupt enabled
  181. // ------------------------------------------
  182. for (auto* init = late_init_start; *init; ++init)
  183. (*init)();
  184. const auto& context = current_process->fs_context;
  185. // mount fat32 /mnt directory
  186. // TODO: parse kernel parameters
  187. if (1) {
  188. auto [mnt, status] = fs::open(context, context.root.get(), "/mnt");
  189. assert(mnt && status == -ENOENT);
  190. if (int ret = fs::mkdir(mnt.get(), 0755); 1)
  191. assert(ret == 0 && mnt->flags & fs::D_PRESENT);
  192. int ret = rootfs->mount(mnt.get(), "/dev/sda", "/mnt", "fat32",
  193. MS_RDONLY | MS_NOATIME | MS_NODEV | MS_NOSUID,
  194. "ro,nodev");
  195. assert(ret == 0);
  196. }
  197. current_process->attr.system = 0;
  198. current_thread->attr &= ~kernel::task::thread::SYSTEM;
  199. types::elf::elf32_load_data d{
  200. .exec_dent{},
  201. .argv{"/mnt/busybox", "sh", "/mnt/initsh"},
  202. .envp{"LANG=C", "HOME=/root", "PATH=/mnt", "PWD=/"},
  203. .ip{},
  204. .sp{}};
  205. auto [exec, ret] = fs::open(context, context.root.get(), d.argv[0]);
  206. if (!exec || ret) {
  207. kmsg("kernel panic: init not found!");
  208. freeze();
  209. }
  210. d.exec_dent = exec.get();
  211. if (int ret = types::elf::elf32_load(d); 1)
  212. assert(ret == 0);
  213. exec.reset();
  214. int ds = 0x33, cs = 0x2b;
  215. asm volatile(
  216. "mov %0, %%rax\n"
  217. "mov %%ax, %%ds\n"
  218. "mov %%ax, %%es\n"
  219. "mov %%ax, %%fs\n"
  220. "mov %%ax, %%gs\n"
  221. "push %%rax\n"
  222. "push %2\n"
  223. "push $0x200\n"
  224. "push %1\n"
  225. "push %3\n"
  226. "iretq\n"
  227. :
  228. : "g"(ds), "g"(cs), "g"(d.sp), "g"(d.ip)
  229. : "eax", "memory");
  230. freeze();
  231. }
  232. SECTION(".text.kinit")
  233. void NORETURN init_scheduler(kernel::mem::paging::pfn_t kernel_stack_pfn) {
  234. procs = new proclist;
  235. asm volatile(
  236. "mov %2, %%rdi\n"
  237. "mov %0, %%rsp\n"
  238. "sub $24, %%rsp\n"
  239. "mov %=f, %%rbx\n"
  240. "mov %%rbx, (%%rsp)\n" // return address
  241. "mov %%rbx, 16(%%rsp)\n" // previous frame return address
  242. "xor %%rbx, %%rbx\n"
  243. "mov %%rbx, 8(%%rsp)\n" // previous frame rbp
  244. "mov %%rsp, %%rbp\n" // current frame rbp
  245. "push %1\n"
  246. "mov $0x10, %%ax\n"
  247. "mov %%ax, %%ss\n"
  248. "mov %%ax, %%ds\n"
  249. "mov %%ax, %%es\n"
  250. "mov %%ax, %%fs\n"
  251. "mov %%ax, %%gs\n"
  252. "push $0x0\n"
  253. "popf\n"
  254. "ret\n"
  255. "%=:\n"
  256. "ud2"
  257. :
  258. : "a"(current_thread->kstack.sp), "c"(_kernel_init),
  259. "g"(kernel_stack_pfn)
  260. : "memory");
  261. freeze();
  262. }
  263. extern "C" void asm_ctx_switch(uintptr_t* curr_sp, uintptr_t* next_sp);
  264. extern "C" void after_ctx_switch() {
  265. current_thread->kstack.load_interrupt_stack();
  266. current_thread->load_thread_area32();
  267. }
  268. bool _schedule() {
  269. auto* next_thd = kernel::task::dispatcher::next();
  270. if (current_thread != next_thd) {
  271. auto* proc = &procs->find(next_thd->owner);
  272. if (current_process != proc) {
  273. proc->mms.switch_pd();
  274. current_process = proc;
  275. }
  276. auto* curr_thd = current_thread;
  277. current_thread = next_thd;
  278. asm_ctx_switch(&curr_thd->kstack.sp, &next_thd->kstack.sp);
  279. }
  280. return current_thread->signals.pending_signal() == 0;
  281. }
  282. bool schedule() {
  283. if (kernel::async::preempt_count() != 0)
  284. return true;
  285. return _schedule();
  286. }
  287. void NORETURN schedule_noreturn(void) {
  288. _schedule();
  289. freeze();
  290. }
  291. void NORETURN freeze(void) {
  292. for (;;)
  293. asm volatile("cli\n\thlt");
  294. }
  295. void NORETURN kill_current(int signo) {
  296. procs->kill(current_process->pid, (signo + 128) << 8 | (signo & 0xff));
  297. schedule_noreturn();
  298. }