aboutsummaryrefslogtreecommitdiff
path: root/src/core/paging.c
blob: 243ed0ba4e9df6e6eafd9983c6a2f81bd923b4a0 (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
135
136
137
#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");
}

int *paging_allocate(int p){
    // ----- Populate kernel adresses (to be able to execute interrupts codes)
    int *page_dir=(int*)paging_allocate_next_page();
    int *k_page_table=(int*)paging_allocate_next_page();
    // Kernel is located in the first 4Mb (page dir entry 0)
    page_dir[0]=(int)k_page_table|3;
    int addr_offset=0;
    for(int i=0;i<1024;i++){
        k_page_table[i]=addr_offset;
        k_page_table[i]|=3; // Permissions
        addr_offset+=PAGING_PAGE_SIZE; // 4Ko pages
    }
  
    // ----- Populate task adresses
    int *u_page_table=(int)paging_allocate_next_page();
    page_dir[1]=(int)u_page_table|7;
    int dir_entry=1; // Entry point is at 1024*4096=4194304 (page dir entry 1 and page table entry 0)
    int pt_entry=0;
    int p_current=max(1,p); // Allocate at least 1 page
    p_current++; // Allocated one more page for the kernel stack (one per task)
    while(p_current!=0){
        u_page_table[pt_entry]=(int)paging_allocate_next_page();
        if(p_current==1) // Kernel stack is the last page
            u_page_table[pt_entry]|=3;
        else
            u_page_table[pt_entry]|=7;
        p_current--;
        pt_entry++;
        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;
            if(p_current==1) // Kernel stack is the last page (and might be in the last page directory entry)
                 page_dir[dir_entry]|=3;
            else
                 page_dir[dir_entry]|=7;
        }
    }
    return page_dir;
}

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