mem.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. #include <cstddef>
  2. #include <asm/port_io.h>
  3. #include <asm/sys.h>
  4. #include <assert.h>
  5. #include <errno.h>
  6. #include <kernel/mem.h>
  7. #include <kernel/mm.hpp>
  8. #include <kernel/process.hpp>
  9. #include <kernel/task.h>
  10. #include <kernel/vga.hpp>
  11. #include <stdint.h>
  12. #include <stdio.h>
  13. #include <types/allocator.hpp>
  14. #include <types/bitmap.hpp>
  15. #include <types/size.h>
  16. #include <types/status.h>
  17. // constant values
  18. #define EMPTY_PAGE ((page_t)0)
  19. // ---------------------
  20. static size_t mem_size;
  21. static uint8_t _mem_bitmap[1024 * 1024 / 8];
  22. static types::bitmap mem_bitmap(
  23. [](unsigned char*, std::size_t){}, _mem_bitmap,
  24. 1024 * 1024);
  25. // global
  26. segment_descriptor gdt[7];
  27. uint8_t e820_mem_map[1024];
  28. uint32_t e820_mem_map_count;
  29. uint32_t e820_mem_map_entry_size;
  30. struct mem_size_info mem_size_info;
  31. constexpr void mark_addr_len(pptr_t start, size_t n)
  32. {
  33. if (n == 0)
  34. return;
  35. page_t start_page = align_down<12>(start) >> 12;
  36. page_t end_page = align_up<12>(start + n) >> 12;
  37. for (page_t i = start_page; i < end_page; ++i)
  38. mem_bitmap.set(i);
  39. }
  40. constexpr void free_addr_len(pptr_t start, size_t n)
  41. {
  42. if (n == 0)
  43. return;
  44. page_t start_page = align_down<12>(start) >> 12;
  45. page_t end_page = align_up<12>(start + n) >> 12;
  46. for (page_t i = start_page; i < end_page; ++i)
  47. mem_bitmap.clear(i);
  48. }
  49. constexpr void mark_addr_range(pptr_t start, pptr_t end)
  50. {
  51. mark_addr_len(start, end - start);
  52. }
  53. constexpr void free_addr_range(pptr_t start, pptr_t end)
  54. {
  55. free_addr_len(start, end - start);
  56. }
  57. page_t __alloc_raw_page(void)
  58. {
  59. const auto size = mem_bitmap.size();
  60. for (size_t i = 0; i < size; ++i) {
  61. if (mem_bitmap.test(i) == 0) {
  62. mem_bitmap.set(i);
  63. return i;
  64. }
  65. }
  66. return -1;
  67. }
  68. void __free_raw_page(page_t pg)
  69. {
  70. mem_bitmap.clear(pg);
  71. }
  72. page allocate_page(void)
  73. {
  74. return page {
  75. .phys_page_id = __alloc_raw_page(),
  76. .ref_count = types::memory::kinew<size_t>(0),
  77. .pg_pteidx = 0,
  78. .attr = 0,
  79. };
  80. }
  81. void free_page(page* pg)
  82. {
  83. if (*pg->ref_count == 1) {
  84. types::memory::kidelete<size_t>(pg->ref_count);
  85. __free_raw_page(pg->phys_page_id);
  86. } else {
  87. --*pg->ref_count;
  88. }
  89. }
  90. void dealloc_pd(page_t pd)
  91. {
  92. {
  93. kernel::paccess pa(pd);
  94. auto p_pd = (pd_t)pa.ptr();
  95. assert(p_pd);
  96. for (pde_t* ent = (*p_pd); ent < (*p_pd) + 768; ++ent) {
  97. if (!ent->in.p)
  98. continue;
  99. __free_raw_page(ent->in.pt_page);
  100. }
  101. }
  102. __free_raw_page(pd);
  103. }
  104. SECTION(".text.kinit")
  105. static inline void init_mem_layout(void)
  106. {
  107. mem_size = 1024 * mem_size_info.n_1k_blks;
  108. mem_size += 64 * 1024 * mem_size_info.n_64k_blks;
  109. // mark empty page
  110. mark_addr_range(0x00000000, 0x00001000);
  111. // mark kernel page directory
  112. mark_addr_range(0x00001000, 0x00002000);
  113. // mark kernel page table
  114. mark_addr_range(0x00002000, 0x00006000);
  115. // mark kernel early stack
  116. mark_addr_range(0x00006000, 0x00008000);
  117. // mark EBDA and upper memory as allocated
  118. mark_addr_range(0x80000, 0x100000);
  119. extern char __stage1_start[];
  120. extern char __kinit_end[];
  121. extern char __text_start[];
  122. extern char __data_end[];
  123. constexpr pptr_t PHYS_BSS_START = 0x100000;
  124. // mark .stage1 and .kinit
  125. mark_addr_range((pptr_t)__stage1_start, (pptr_t)__kinit_end);
  126. // mark kernel .text to .data
  127. mark_addr_len((pptr_t)__kinit_end, __data_end - __text_start);
  128. // mark kernel .bss
  129. mark_addr_len(PHYS_BSS_START, bss_len);
  130. if (e820_mem_map_entry_size == 20) {
  131. struct e820_mem_map_entry_20* entry = (struct e820_mem_map_entry_20*)e820_mem_map;
  132. for (uint32_t i = 0; i < e820_mem_map_count; ++i, ++entry) {
  133. if (entry->type != 1) {
  134. mark_addr_len(entry->base, entry->len);
  135. }
  136. }
  137. } else {
  138. struct e820_mem_map_entry_24* entry = (struct e820_mem_map_entry_24*)e820_mem_map;
  139. for (uint32_t i = 0; i < e820_mem_map_count; ++i, ++entry) {
  140. if (entry->in.type != 1) {
  141. mark_addr_len(entry->in.base, entry->in.len);
  142. }
  143. }
  144. }
  145. }
  146. using kernel::memory::mm_list;
  147. using kernel::memory::mm;
  148. mm_list::mm_list()
  149. : m_areas(s_kernel_mms->m_areas)
  150. {
  151. m_pd = __alloc_raw_page();
  152. kernel::paccess pdst(m_pd), psrc(s_kernel_mms->m_pd);
  153. auto* dst = pdst.ptr();
  154. auto* src = psrc.ptr();
  155. assert(dst && src);
  156. memcpy(dst, src, PAGE_SIZE);
  157. }
  158. mm_list::mm_list(const mm_list& other)
  159. : mm_list()
  160. {
  161. m_brk = other.m_brk;
  162. for (auto& src : other.m_areas) {
  163. if (src.is_kernel_space() || src.attr.system)
  164. continue;
  165. auto& area = this->addarea(
  166. src.start, src.attr.write, src.attr.system);
  167. if (src.attr.mapped) {
  168. area.attr.mapped = 1;
  169. area.mapped_file = src.mapped_file;
  170. area.file_offset = src.file_offset;
  171. }
  172. paccess pa(m_pd);
  173. pd_t pd = (pd_t)pa.ptr();
  174. for (const auto& pg : *src.pgs) {
  175. area.append_page(pd, pg,
  176. PAGE_COW | (pg.attr & PAGE_MMAP),
  177. src.attr.system);
  178. }
  179. }
  180. }
  181. mm_list::~mm_list()
  182. {
  183. if (!m_pd)
  184. return;
  185. clear_user();
  186. dealloc_pd(m_pd);
  187. }
  188. void mm_list::switch_pd() const
  189. {
  190. asm_switch_pd(m_pd);
  191. }
  192. int mm_list::register_brk(void* addr)
  193. {
  194. if (!is_avail(addr))
  195. return GB_FAILED;
  196. m_brk = &addarea(addr, true, false);
  197. return GB_OK;
  198. }
  199. void* mm_list::set_brk(void* addr)
  200. {
  201. assert(m_brk);
  202. void* curbrk = m_brk->end();
  203. if (addr <= curbrk || !is_avail(curbrk, vptrdiff(addr, curbrk)))
  204. return curbrk;
  205. kernel::paccess pa(m_pd);
  206. pd_t pd = (pd_t)pa.ptr();
  207. while (curbrk < addr) {
  208. m_brk->append_page(pd, empty_page, PAGE_COW, false);
  209. curbrk = (char*)curbrk + PAGE_SIZE;
  210. }
  211. return curbrk;
  212. }
  213. void* mm_list::find_avail(void* hint, size_t len, bool priv) const
  214. {
  215. void* addr = hint;
  216. if (!addr) {
  217. // default value of mmapp'ed area
  218. if (!priv)
  219. addr = (void*)0x40000000;
  220. else
  221. addr = (void*)0xe0000000;
  222. }
  223. while (!is_avail(addr, len)) {
  224. auto iter = m_areas.lower_bound(addr);
  225. if (iter == m_areas.end())
  226. return nullptr;
  227. addr = iter->end();
  228. }
  229. if (!priv && addr >= (void*)0xc0000000)
  230. return nullptr;
  231. return addr;
  232. }
  233. // TODO: write dirty pages to file
  234. int mm_list::unmap(void* start, size_t len, bool system)
  235. {
  236. ptr_t addr = (ptr_t)start;
  237. void* end = vptradd(start, align_up<12>(len));
  238. // standard says that addr and len MUST be
  239. // page-aligned or the call is invalid
  240. if (addr % PAGE_SIZE != 0)
  241. return -EINVAL;
  242. // if doing user mode unmapping, check area privilege
  243. if (!system) {
  244. if (addr >= 0xc0000000 || end > (void*)0xc0000000)
  245. return -EINVAL;
  246. }
  247. auto iter = m_areas.lower_bound(start);
  248. for ( ; iter != m_areas.end() && *iter < end; ) {
  249. if (!(start < *iter) && start != iter->start) {
  250. mm newmm = iter->split(start);
  251. unmap(newmm);
  252. ++iter;
  253. continue;
  254. }
  255. else if (!(*iter < end)) {
  256. mm newmm = iter->split(end);
  257. unmap(*iter);
  258. m_areas.erase(iter);
  259. bool inserted;
  260. std::tie(std::ignore, inserted) = m_areas.emplace(std::move(newmm));
  261. assert(inserted);
  262. break;
  263. }
  264. else {
  265. unmap(*iter);
  266. iter = m_areas.erase(iter);
  267. }
  268. }
  269. return GB_OK;
  270. }
  271. mm& mm_list::add_empty_area(void *start, std::size_t page_count,
  272. uint32_t page_attr, bool w, bool system)
  273. {
  274. auto& area = addarea(start, w, system);
  275. kernel::paccess pa(m_pd);
  276. pd_t pd = (pd_t)pa.ptr();
  277. while (page_count--)
  278. area.append_page(pd, empty_page, page_attr, system);
  279. return area;
  280. }
  281. constexpr void map_raw_page_to_pte(
  282. pte_t* pte, page_t page,
  283. bool present, bool write, bool priv)
  284. {
  285. // set P bit
  286. pte->v = 0;
  287. pte->in.p = present;
  288. pte->in.rw = write;
  289. pte->in.us = !priv;
  290. pte->in.page = page;
  291. }
  292. void mm::append_page(pd_t pd, const page& pg, uint32_t attr, bool priv)
  293. {
  294. assert(pd);
  295. void* addr = this->end();
  296. pde_t* pde = *pd + v_to_pdi(addr);
  297. page_t pt_pg = 0;
  298. pte_t* pte = nullptr;
  299. // page table not exist
  300. if (!pde->in.p) [[unlikely]] {
  301. // allocate a page for the page table
  302. pt_pg = __alloc_raw_page();
  303. pde->in.p = 1;
  304. pde->in.rw = 1;
  305. pde->in.us = 1;
  306. pde->in.pt_page = pt_pg;
  307. auto pt = (pt_t)kernel::pmap(pt_pg);
  308. assert(pt);
  309. pte = *pt;
  310. memset(pt, 0x00, PAGE_SIZE);
  311. } else {
  312. pt_pg = pde->in.pt_page;
  313. auto pt = (pt_t)kernel::pmap(pt_pg);
  314. assert(pt);
  315. pte = *pt;
  316. }
  317. // map the page in the page table
  318. int pti = v_to_pti(addr);
  319. pte += pti;
  320. map_raw_page_to_pte(
  321. pte,
  322. pg.phys_page_id,
  323. !(attr & PAGE_MMAP),
  324. false,
  325. priv);
  326. kernel::pfree(pt_pg);
  327. if (unlikely((attr & PAGE_COW) && !(pg.attr & PAGE_COW))) {
  328. kernel::paccess pa(pg.pg_pteidx >> 12);
  329. auto* pg_pte = (pte_t*)pa.ptr();
  330. assert(pg_pte);
  331. pg_pte += (pg.pg_pteidx & 0xfff);
  332. pg.attr |= PAGE_COW;
  333. pg_pte->in.rw = 0;
  334. pg_pte->in.a = 0;
  335. invalidate_tlb(addr);
  336. }
  337. ++*pg.ref_count;
  338. this->pgs->emplace_back(pg);
  339. auto& emplaced = this->pgs->back();
  340. emplaced.pg_pteidx = (pt_pg << 12) + pti;
  341. emplaced.attr = attr;
  342. }
  343. mm mm::split(void *addr)
  344. {
  345. assert(addr > start && addr < end());
  346. assert((ptr_t)addr % PAGE_SIZE == 0);
  347. size_t this_count = vptrdiff(addr, start) / PAGE_SIZE;
  348. size_t new_count = pgs->size() - this_count;
  349. mm newmm {
  350. .start = addr,
  351. .attr { attr },
  352. .pgs = types::memory::kinew<mm::pages_vector>(),
  353. .mapped_file = mapped_file,
  354. .file_offset = attr.mapped ? file_offset + this_count * PAGE_SIZE : 0,
  355. };
  356. for (size_t i = 0; i < new_count; ++i) {
  357. newmm.pgs->emplace_back(pgs->back());
  358. pgs->pop_back();
  359. }
  360. return newmm;
  361. }
  362. int mmap(
  363. void* hint,
  364. size_t len,
  365. fs::inode* file,
  366. size_t offset,
  367. int write,
  368. int priv)
  369. {
  370. auto& mms = current_process->mms;
  371. if (file && !S_ISREG(file->mode) && !S_ISBLK(file->mode)) [[unlikely]] {
  372. errno = EINVAL;
  373. return GB_FAILED;
  374. }
  375. // TODO: find another address
  376. assert(((uint32_t)hint & 0xfff) == 0);
  377. // TODO: return failed
  378. assert((offset & 0xfff) == 0);
  379. size_t n_pgs = align_up<12>(len) >> 12;
  380. if (!mms.is_avail(hint, len)) {
  381. errno = EEXIST;
  382. return GB_FAILED;
  383. }
  384. if (file) {
  385. auto& mm = mms.add_empty_area(hint, n_pgs, PAGE_MMAP | PAGE_COW, write, priv);
  386. mm.attr.mapped = 1;
  387. mm.mapped_file = file;
  388. mm.file_offset = offset;
  389. }
  390. else {
  391. // private mapping of zero-filled pages
  392. auto& mm = mms.add_empty_area(hint, n_pgs, PAGE_COW, write, priv);
  393. mm.attr.mapped = 0;
  394. }
  395. return GB_OK;
  396. }
  397. SECTION(".text.kinit")
  398. void init_mem(void)
  399. {
  400. init_mem_layout();
  401. // TODO: replace early kernel pd
  402. auto* __kernel_mms = types::memory::kinew<kernel::memory::mm_list>(EARLY_KERNEL_PD_PAGE);
  403. kernel::memory::mm_list::s_kernel_mms = __kernel_mms;
  404. // create empty_page struct
  405. empty_page.attr = 0;
  406. empty_page.phys_page_id = EMPTY_PAGE;
  407. empty_page.ref_count = types::memory::kinew<size_t>(2);
  408. empty_page.pg_pteidx = 0x00002000;
  409. // 0xd0000000 to 0xd4000000 or 3.5GiB, size 64MiB
  410. __kernel_mms->add_empty_area(KERNEL_HEAP_START,
  411. 64 * 1024 * 1024 / PAGE_SIZE, PAGE_COW, true, true);
  412. kernel::kinit::init_kernel_heap(KERNEL_HEAP_START,
  413. vptrdiff(KERNEL_HEAP_LIMIT, KERNEL_HEAP_START));
  414. }
  415. SECTION(".text.kinit")
  416. void create_segment_descriptor(
  417. segment_descriptor* sd,
  418. uint32_t base,
  419. uint32_t limit,
  420. uint32_t flags,
  421. uint32_t access)
  422. {
  423. sd->base_low = base & 0x0000ffff;
  424. sd->base_mid = ((base & 0x00ff0000) >> 16);
  425. sd->base_high = ((base & 0xff000000) >> 24);
  426. sd->limit_low = limit & 0x0000ffff;
  427. sd->limit_high = ((limit & 0x000f0000) >> 16);
  428. sd->access = access;
  429. sd->flags = flags;
  430. }
  431. namespace __physmapper {
  432. struct mapped_area {
  433. size_t ref;
  434. void* ptr;
  435. };
  436. static types::hash_map<page_t, mapped_area,
  437. types::memory::ident_allocator<std::pair<page_t, mapped_area>>>
  438. mapped;
  439. static uint8_t _freebm[0x400 / 8];
  440. static types::bitmap freebm(
  441. [](unsigned char*, std::size_t){}, _freebm, 0x400);
  442. } // namespace __physmapper
  443. void* kernel::pmap(page_t pg, bool cached)
  444. {
  445. auto* const pmap_pt = std::bit_cast<pte_t*>(0xff001000);
  446. auto* const mapped_start = std::bit_cast<void*>(0xff000000);
  447. auto iter = __physmapper::mapped.find(pg);
  448. if (iter) {
  449. auto [ idx, area ] = *iter;
  450. ++area.ref;
  451. return area.ptr;
  452. }
  453. for (int i = 2; i < 0x400; ++i) {
  454. if (__physmapper::freebm.test(i) == 0) {
  455. auto* pte = pmap_pt + i;
  456. if (cached)
  457. pte->v = 0x3;
  458. else
  459. pte->v = 0x13;
  460. pte->in.page = pg;
  461. void* ptr = vptradd(mapped_start, 0x1000 * i);
  462. invalidate_tlb(ptr);
  463. __physmapper::freebm.set(i);
  464. __physmapper::mapped.emplace(pg,
  465. __physmapper::mapped_area { 1, ptr });
  466. return ptr;
  467. }
  468. }
  469. return nullptr;
  470. }
  471. void kernel::pfree(page_t pg)
  472. {
  473. auto* const pmap_pt = std::bit_cast<pte_t*>(0xff001000);
  474. auto* const mapped_start = std::bit_cast<void*>(0xff000000);
  475. auto iter = __physmapper::mapped.find(pg);
  476. if (!iter)
  477. return;
  478. auto& [ ref, ptr ] = iter->second;
  479. if (ref > 1) {
  480. --ref;
  481. return;
  482. }
  483. int i = vptrdiff(ptr, mapped_start);
  484. i /= 0x1000;
  485. auto* pte = pmap_pt + i;
  486. pte->v = 0;
  487. invalidate_tlb(ptr);
  488. __physmapper::freebm.clear(i);
  489. __physmapper::mapped.remove(iter);
  490. }