#pragma once

#include <stdint.h>
#include <limine.h>
#include <stddef.h>
#include <mp/spinlock.h>
#include <stdbool.h>
#include <stdint.h>

#define PAGE_SIZE 4096ULL

extern volatile struct limine_hhdm_request hhdm_request;

#define MEM_PHYS_OFFSET (hhdm_request.response->offset)


extern volatile struct limine_executable_address_request kernel_address_request;

#define INVALID_PHYS 0xffffffffffffffffULL

#define PAGE_READ     (1ULL << 0)
#define PAGE_WRITE    (1ULL << 1)
#define PAGE_USER     (1ULL << 2)
#define PAGE_NO_EXECUTE (1ULL << 63)

struct pagemap {
    spinlock_t lock;
    uint64_t *top_level;
};

extern struct pagemap *kernel_pagemap;

enum page_size { Size4KiB, Size2MiB };

void vmm_init(struct limine_memmap_entry **memmap, size_t memmap_entries);
void vmm_switch_pagemap(struct pagemap *pagemap);
bool vmm_map_page(struct pagemap *pagemap, uint64_t virt, uint64_t phys,
                  uint64_t flags, enum page_size pg_size);
uint64_t vmm_virt_to_phys(struct pagemap *pagemap, uint64_t virt);