#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
#include "Memory.h"

extern void InitMM(void);
#define	PAGESIZE 	4096
#define	RAM_MAXPAGE	0x10000

#define	VADDR_PD_OFFSET(addr)	((addr) & 0xFFC00000) >> 22
#define	VADDR_PT_OFFSET(addr)	((addr) & 0x003FF000) >> 12
#define	VADDR_PG_OFFSET(addr)	(addr) & 0x00000FFF
#define PAGE(addr)		(addr) >> 12

#define PAGING_FLAG 0x80000000
#define USER_OFFSET 0x40000000
#define USER_STACK  0xE0000000

#ifdef __MM__
uint32_t *pd0;
uint32_t *pt0;
uint8_t mem_bitmap[RAM_MAXPAGE / 8];
#endif

#define	PAGESIZE 	4096
#define	RAM_MAXPAGE	0x10000

#define	VADDR_PD_OFFSET(addr)	((addr) & 0xFFC00000) >> 22
#define	VADDR_PT_OFFSET(addr)	((addr) & 0x003FF000) >> 12
#define	VADDR_PG_OFFSET(addr)	(addr) & 0x00000FFF
#define PAGE(addr)		(addr) >> 12

#define PAGING_FLAG 0x80000000	/* CR0 - bit 31 */
#define USER_OFFSET 0x40000000
#define USER_STACK  0xE0000000

#ifdef __MM__
uint32_t *pd0;
uint32_t *pt0;
uint8_t mem_bitmap[RAM_MAXPAGE / 8];
#else
extern uint8_t mem_bitmap[];
#endif

struct pd_entry {
	uint32_t present:1;
	uint32_t writable:1;
	uint32_t user:1;
	uint32_t pwt:1;
	uint32_t pcd:1;
	uint32_t accessed:1;
	uint32_t _unused:1;
	uint32_t page_size:1;
	uint32_t global:1;
	uint32_t avail:3;

	uint32_t page_table_base:20;
} __attribute__ ((packed));

struct pt_entry {
	uint32_t present:1;
	uint32_t writable:1;
	uint32_t user:1;
	uint32_t pwt:1;
	uint32_t pcd:1;
	uint32_t accessed:1;
	uint32_t dirty:1;
	uint32_t pat:1;
	uint32_t global:1;
	uint32_t avail:3;

	uint32_t page_base:20;
} __attribute__ ((packed));



#define SetPageFrameUsed(page)	mem_bitmap[((uint32_t) page)/8] |= (1 << (((uint32_t) page)%8))
#define ReleasePageFrame(p_addr)	mem_bitmap[((uint32_t) p_addr/PAGESIZE)/8] &= ~(1 << (((uint32_t) p_addr/PAGESIZE)%8))

char *GetPageFrame(void);

void InitMM(void);

uint32_t *PdCreate(uint32_t * code_phys_addr, unsigned int code_size);