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
|
#include <asm/system.h>
#include <kernel/con.h>
#include <kernel/memory.h>
#include <kernel/sched.h>
#include <string.h>
#include <sys/types.h>
#define USRSTART ((void*) 0x40000000)
#define pages(n) \
((n / 4096) + 1)
#define tables(n) \
((n / 1024) + 1)
#define getpage(name, p) ({\
void **_next; \
_next = map_page(p); \
name = p; \
p = *_next; \
})
extern char _usrbin_start;
extern char _usrbin_size;
struct task_struct *ctask;
static struct task_struct task;
static inline void empty_table(void *t) {
int i;
for(i = 0; i < PGENT; i++)
((uint32_t*) t)[i] = 0;
}
void userspace_init(void) {
int i, j;
int c;
size_t totpages, npages, ntables;
void *p, *page, *tab, *map;
void *pdir, *stackt, *stackp;
size_t usrsize = (size_t) &_usrbin_size;
npages = pages(usrsize);
ntables = tables(pages(usrsize));
totpages = npages + ntables + 3;
/* here we allocate pages to setup the process'
* address space. in addition to the pages that
* will hold the binary image, the following
* pages are allocated:
* - page directory (1 page)
* - page tables
* - stack page (1 page)
* - stack table (1 page)
*/
p = alloc_physical_pages(totpages);
printf("Allocating %x pages for userspace process\n", totpages);
if(p == NULL) {
printf("Failed to allocate memory for userspace!\n");
return;
}
getpage(pdir, p);
getpage(stackt, p);
getpage(stackp, p);
printf(" Page directory: 0x%08x\n", (uint32_t) pdir);
printf(" Stack table: 0x%08x\n", (uint32_t) stackt);
printf(" Stack page: 0x%08x\n", (uint32_t) stackp);
printf(" Page tables:\n");
/* populate the page directory */
c = npages;
map = map_page(pdir);
empty_table(map);
for(i = 0; i < ntables; i++) {
/* add the table entry to the directory */
getpage(tab, p);
printf(" 0x%08x\n", (uint32_t) tab);
map = map_page(pdir);
((uint32_t*) map)[i + (PGENT / 4)] = (uint32_t) tab | 0x007;
/* populate the page table */
map = map_page(tab);
for(j = 0; j < PGENT; j++) {
((uint32_t*) map)[j] = 0;
if(c <= 0)
continue;
getpage(page, p);
map = map_page(tab);
((uint32_t*) map)[j] = (uint32_t) page | 0x007;
c--;
}
}
/* populate the stack table */
map = map_page(stackt);
empty_table(map);
((uint32_t*) map)[PGENT - 1] = (uint32_t) stackp | 0x007;
/* add the stack page table to the directory */
map = map_page(pdir);
((uint32_t*) map)[PGENT - 1] = (uint32_t) stackt | 0x007;
/* add the kernel's page table to the directory */
((uint32_t*) map)[0] = (uint32_t) ktab | 0x003;
__asm__ volatile ("mov %%eax, %%cr3" :: "a" (pdir));
memcpy(USRSTART, &_usrbin_start, usrsize);
/*
* here we initialize the task struct.
* currently, we only setup state information
* necessary to begin execution.
*/
memset(&task, 0, sizeof(task));
task.state.cs = 0x1B;
task.state.ss = 0x23;
task.state.eip = (uint32_t) USRSTART;
task.state.esp = 0xFFFFFFFF;
__asm__ (
"pushf\n" \
"pop %%eax" \
: "=a" (task.state.eflags) \
::);
switch_to(&task, &task.state);
}
|