aboutsummaryrefslogtreecommitdiff
path: root/src/core/paging.c
blob: 0ab54982e15c67aecedc5eb11f977a6874846d42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "paging.h"
#include "libc/stdio.h"
#include "libc/math.h"

/// Use a bitmap to keep track of allocated pages
char pages_status[PAGING_MAX_PAGES/8];
/// Kernel page directory (ATTENTION need to be 4096)
u32 k_pd[PAGING_MAX_DIR_ENTRY] __attribute__((aligned(4096)));
/// Kernel page table
u32 k_pt[PAGING_MAX_DIR_ENTRY][1024] __attribute__((aligned(4096)));

void paging_enable(){
    // Init pages status
    for(int i=0;i<PAGING_MAX_PAGES/8;i++)
        pages_status[i]=0;

    // Init page directory
    for(int i=0;i<PAGING_MAX_DIR_ENTRY;i++){
        k_pd[i]=0;
    }
    k_pd[0]=((int)&k_pt[0][0]);
    k_pd[0]|=7; // Permissions

    // Init page table 0
    int addr_offset=0;
    for(int i=0;i<1024;i++){
        k_pt[0][i]=addr_offset;
        k_pt[0][i]|=7; // Permission
        paging_set_usage(addr_offset,1); // Mark addr as used
        addr_offset+=PAGING_PAGE_SIZE; // 4Ko pages
    }

    // Allow access to more ram
    for(int i=1;i<PAGING_MAX_DIR_ENTRY;i++){
        k_pd[i]=((int)&k_pt[i][0]);
        k_pd[i]|=7; // Permissions
        for(int j=0;j<1024;j++){
            k_pt[i][j]=addr_offset;
            k_pt[i][j]|=7; // Permission
            addr_offset+=PAGING_PAGE_SIZE; // 4Ko pages
        }
    }

    // Turns on paging
    asm(
        "movl %0, %%eax       \n\t"
        "movl %%eax, %%cr3    \n\t" // Configure page table location
        "movl %%cr0, %%eax    \n\t"
        "orl %1, %%eax        \n\t"
        "movl %%eax, %%cr0    \n\t" // Turn on paging
        :: "b" (k_pd), "i" (PAGING_CR0_BIT)
    );
}
void paging_set_usage(int addr,char state){
    char bytes=pages_status[addr/PAGING_PAGE_SIZE/8];
    char bit=addr/PAGING_PAGE_SIZE%8;
    if(state=0)
        pages_status[addr/PAGING_PAGE_SIZE/8]=~(1<<bit)&bytes;
    else
        pages_status[addr/PAGING_PAGE_SIZE/8]=(1<<bit)|bytes;
}

void paging_dump(int min,int max){
    for(int i=0;i<(PAGING_MAX_PAGES/8);i++){
        for(int j=0;j<8;j++){
            char status=(pages_status[i]>>j)&0x1;
            if((i*8+j)>=min){
                if((i*8+j)<max || max<0)
                    printi(status);
            }
        }
    }
}

char* paging_allocate_next_page(){
    for(int i=0;i<(PAGING_MAX_PAGES/8);i++){
        char bytes=pages_status[i];
        for(int j=0;j<8;j++){
            char state=(bytes>>j)&1;
            if(state!=1){
                int page_id=i*8+j;
                int page_addr=PAGING_PAGE_SIZE*page_id;
                paging_set_usage(page_addr,1);
                return((char*)page_addr);
            }
        }
    }
    print("Could not allocate anymore pages! Stopping...");
    asm("hlt");
}

// TODO: Take p into account
int *paging_allocate(int p){
    // ----- Allow kernel access during interruption
    int *page_dir=(int*)paging_allocate_next_page();
    int *k_page_table=(int*)paging_allocate_next_page();
    // Init page directory
    page_dir[0]=(int)k_page_table|3;
    // Init page table 0
    int addr_offset=0;
    for(int i=0;i<1024;i++){
        k_page_table[i]=addr_offset;
        k_page_table[i]|=3; // Permission
        addr_offset+=PAGING_PAGE_SIZE; // 4Ko pages
    }
  
    // ----- Task table
    int *u_page_table=(int*)paging_allocate_next_page();
    page_dir[1]=(int)u_page_table|7;
    u_page_table[0]=(int)page_dir|7; // Virtual address is 1024*4096/4
    u_page_table[1]=(int)k_page_table|7;
    u_page_table[2]=(int)u_page_table|7;

    int dir_entry=1;
    int pt_entry=3;
    int p_current=max(1,p); // Allocate at least 1 page
    while(p_current!=0){
        if(pt_entry%1024==0){
            dir_entry++;
            pt_entry=0;
            u_page_table=(int*)paging_allocate_next_page();
            page_dir[dir_entry]=(int)u_page_table|7;
        }
        u_page_table[pt_entry]=(int)paging_allocate_next_page()|7;
        p_current--;
    }
    
    return page_dir;
}

void paging_page_fault(){
  print("Page fault!");
  asm("hlt");
}