X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/34f6af4f61e0eec9c96113e07f140b609b4113c8..3164991854344469bc3a9e8afd41ffd90f11a93f:/lunaix-os/arch/generic/kremap.c diff --git a/lunaix-os/arch/generic/kremap.c b/lunaix-os/arch/generic/kremap.c new file mode 100644 index 0000000..3cd6fa7 --- /dev/null +++ b/lunaix-os/arch/generic/kremap.c @@ -0,0 +1,147 @@ +#include +#include + +#include +#include +#include + +ptr_t boot_text +kpt_alloc_table(struct pt_alloc* alloc) +{ + if (alloc->index >= alloc->total) { + return 0; + } + + ptr_t next; + + next = alloc->base + alloc->index * PAGE_SIZE; + alloc->index++; + + return next; +} + +static bool boot_text +__walk(struct ptw_state* state, ptr_t addr, + unsigned long level_size, bool create) +{ + pte_t pte, *pt; + int level, pt_index; + unsigned long lsize; + ptr_t next_level; + + pt = state->root; + level = 0; + + do { + lsize = lnt_page_size(level); + pt_index = va_level_index(addr, lsize); + + pte = pt[pt_index]; + if (!pte_isnull(pte)) { + next_level = pte_paddr(pte); + goto cont; + } + + if (pt_last_level(level) || lsize == level_size) { + break; + } + + if (!create) { + goto fail; + } + + next_level = kpt_alloc_table(state->alloc); + if (!next_level) { + state->lntp = NULL; + goto fail; + } + + pte = mkpte(next_level, KERNEL_PGTAB); + pt[pt_index] = pte; + + cont: + pt = (pte_t*) next_level; + level++; + } + while (lsize > level_size); + + state->lntp = pt; + state->level = level; + state->tab_index = pt_index; + + return true; + +fail: + state->lntp = NULL; + return false; +} + +unsigned int boot_text +kpt_set_ptes_flatten(struct ptw_state* state, ptr_t addr, + pte_t pte, unsigned long lsize, unsigned int nr) +{ + unsigned int tab_i, _n; + pte_t *lntp; + + _n = 0; + addr = addr & ~(lsize - 1); + + do { + if (!__walk(state, addr, lsize, true)) { + break; + } + + lntp = state->lntp; + tab_i = state->tab_index; + while (_n < nr && tab_i < LEVEL_SIZE) { + lntp[tab_i++] = pte; + pte = pte_advance(pte, lsize); + + addr += lsize; + _n++; + } + } + while (_n < nr); + + return _n; +} + +#define ksection_maps autogen_name(ksecmap) +#define PF_X 0x1 +#define PF_W 0x2 + +extern_autogen(ksecmap); + +bridge_farsym(__kexec_text_start); +bridge_farsym(ksection_maps); + +void boot_text +kpt_migrate_highmem(struct ptw_state* state) +{ + pte_t pte; + struct ksecmap* maps; + struct ksection* section; + pfn_t pgs; + + maps = (struct ksecmap*)to_kphysical(__far(ksection_maps)); + + for (unsigned int i = 0; i < maps->num; i++) + { + section = &maps->secs[i]; + + if (section->va < KERNEL_RESIDENT) { + continue; + } + + pte = mkpte(section->pa, KERNEL_RDONLY); + if ((section->flags & PF_X)) { + pte = pte_mkexec(pte); + } + if ((section->flags & PF_W)) { + pte = pte_mkwritable(pte); + } + + pgs = leaf_count(section->size); + kpt_set_ptes(state, section->va, pte, LFT_SIZE, pgs); + } +} \ No newline at end of file