1 | /* The system call implemented in this file:
|
---|
2 | * m_type: SYS_VM_MAP
|
---|
3 | *
|
---|
4 | * The parameters for this system call are:
|
---|
5 | * m4_l1: Process that requests map (VM_MAP_ENDPT)
|
---|
6 | * m4_l2: Map (TRUE) or unmap (FALSE) (VM_MAP_MAPUNMAP)
|
---|
7 | * m4_l3: Base address (VM_MAP_BASE)
|
---|
8 | * m4_l4: Size (VM_MAP_SIZE)
|
---|
9 | * m4_l5: Memory address (VM_MAP_ADDR)
|
---|
10 | */
|
---|
11 | #include "../system.h"
|
---|
12 |
|
---|
13 | #include <sys/vm.h>
|
---|
14 |
|
---|
15 | PRIVATE int vm_needs_init= 1;
|
---|
16 | PRIVATE u32_t vm_cr3;
|
---|
17 |
|
---|
18 | FORWARD _PROTOTYPE( void vm_init, (void) );
|
---|
19 | FORWARD _PROTOTYPE( void phys_put32, (phys_bytes addr, u32_t value) );
|
---|
20 | FORWARD _PROTOTYPE( u32_t phys_get32, (phys_bytes addr) );
|
---|
21 | FORWARD _PROTOTYPE( void vm_set_cr3, (u32_t value) );
|
---|
22 | FORWARD _PROTOTYPE( void set_cr3, (void) );
|
---|
23 | FORWARD _PROTOTYPE( void vm_enable_paging, (void) );
|
---|
24 | FORWARD _PROTOTYPE( void map_range, (u32_t base, u32_t size,
|
---|
25 | u32_t offset) );
|
---|
26 |
|
---|
27 | /*===========================================================================*
|
---|
28 | * do_vm_map *
|
---|
29 | *===========================================================================*/
|
---|
30 | PUBLIC int do_vm_map(m_ptr)
|
---|
31 | message *m_ptr; /* pointer to request message */
|
---|
32 | {
|
---|
33 | int proc_nr, do_map;
|
---|
34 | phys_bytes base, size, offset, p_phys;
|
---|
35 | struct proc *pp;
|
---|
36 |
|
---|
37 | /* do_serial_debug= 1; */
|
---|
38 |
|
---|
39 | if (vm_needs_init)
|
---|
40 | {
|
---|
41 | vm_needs_init= 0;
|
---|
42 | vm_init();
|
---|
43 | }
|
---|
44 |
|
---|
45 | if (m_ptr->VM_MAP_ENDPT == SELF) {
|
---|
46 | proc_nr = who_p;
|
---|
47 | } else {
|
---|
48 | if(!isokendpt(m_ptr->VM_MAP_ENDPT, &proc_nr))
|
---|
49 | return EINVAL;
|
---|
50 | }
|
---|
51 |
|
---|
52 | do_map= m_ptr->VM_MAP_MAPUNMAP;
|
---|
53 | base= m_ptr->VM_MAP_BASE;
|
---|
54 | size= m_ptr->VM_MAP_SIZE;
|
---|
55 | offset= m_ptr->VM_MAP_ADDR;
|
---|
56 |
|
---|
57 | pp= proc_addr(proc_nr);
|
---|
58 | p_phys= umap_local(pp, D, base, size);
|
---|
59 | if (p_phys == 0)
|
---|
60 | return EFAULT;
|
---|
61 |
|
---|
62 | if (do_map)
|
---|
63 | {
|
---|
64 | pp->p_misc_flags |= MF_VM;
|
---|
65 |
|
---|
66 | map_range(p_phys, size, offset);
|
---|
67 | }
|
---|
68 | else
|
---|
69 | {
|
---|
70 | map_range(p_phys, size, p_phys);
|
---|
71 | }
|
---|
72 | vm_set_cr3(vm_cr3);
|
---|
73 |
|
---|
74 | return OK;
|
---|
75 | }
|
---|
76 |
|
---|
77 | /*===========================================================================*
|
---|
78 | * vm_map_default *
|
---|
79 | *===========================================================================*/
|
---|
80 | PUBLIC void vm_map_default(pp)
|
---|
81 | struct proc *pp;
|
---|
82 | {
|
---|
83 | phys_bytes base_clicks, size_clicks;
|
---|
84 |
|
---|
85 | if (vm_needs_init)
|
---|
86 | panic("vm_map_default: VM not initialized?", NO_NUM);
|
---|
87 | pp->p_misc_flags &= ~MF_VM;
|
---|
88 | base_clicks= pp->p_memmap[D].mem_phys;
|
---|
89 | size_clicks= pp->p_memmap[S].mem_phys+pp->p_memmap[S].mem_len -
|
---|
90 | base_clicks;
|
---|
91 | map_range(base_clicks << CLICK_SHIFT, size_clicks << CLICK_SHIFT,
|
---|
92 | base_clicks << CLICK_SHIFT);
|
---|
93 | vm_set_cr3(vm_cr3);
|
---|
94 | }
|
---|
95 |
|
---|
96 | PRIVATE void vm_init(void)
|
---|
97 | {
|
---|
98 | int o;
|
---|
99 | phys_bytes p, pt_size;
|
---|
100 | phys_bytes vm_dir_base, vm_pt_base, phys_mem;
|
---|
101 | u32_t entry;
|
---|
102 | unsigned pages;
|
---|
103 |
|
---|
104 | if (!vm_size)
|
---|
105 | panic("vm_init: no space for page tables", NO_NUM);
|
---|
106 |
|
---|
107 | /* Align page directory */
|
---|
108 | o= (vm_base % PAGE_SIZE);
|
---|
109 | if (o != 0)
|
---|
110 | o= PAGE_SIZE-o;
|
---|
111 | vm_dir_base= vm_base+o;
|
---|
112 |
|
---|
113 | /* Page tables start after the page directory */
|
---|
114 | vm_pt_base= vm_dir_base+PAGE_SIZE;
|
---|
115 |
|
---|
116 | pt_size= (vm_base+vm_size)-vm_pt_base;
|
---|
117 | pt_size -= (pt_size % PAGE_SIZE);
|
---|
118 |
|
---|
119 | /* Compute the number of pages based on vm_mem_high */
|
---|
120 | pages= (vm_mem_high-1)/PAGE_SIZE + 1;
|
---|
121 |
|
---|
122 | if (pages * I386_VM_PT_ENT_SIZE > pt_size)
|
---|
123 | panic("vm_init: page table too small", NO_NUM);
|
---|
124 |
|
---|
125 | for (p= 0; p*I386_VM_PT_ENT_SIZE < pt_size; p++)
|
---|
126 | {
|
---|
127 | phys_mem= p*PAGE_SIZE;
|
---|
128 | entry= phys_mem | I386_VM_USER | I386_VM_WRITE |
|
---|
129 | I386_VM_PRESENT;
|
---|
130 | if (phys_mem >= vm_mem_high)
|
---|
131 | entry= 0;
|
---|
132 | phys_put32(vm_pt_base + p*I386_VM_PT_ENT_SIZE, entry);
|
---|
133 | }
|
---|
134 |
|
---|
135 | for (p= 0; p < I386_VM_DIR_ENTRIES; p++)
|
---|
136 | {
|
---|
137 | phys_mem= vm_pt_base + p*PAGE_SIZE;
|
---|
138 | entry= phys_mem | I386_VM_USER | I386_VM_WRITE |
|
---|
139 | I386_VM_PRESENT;
|
---|
140 | if (phys_mem >= vm_pt_base + pt_size)
|
---|
141 | entry= 0;
|
---|
142 | phys_put32(vm_dir_base + p*I386_VM_PT_ENT_SIZE, entry);
|
---|
143 | }
|
---|
144 | vm_set_cr3(vm_dir_base);
|
---|
145 | level0(vm_enable_paging);
|
---|
146 | }
|
---|
147 |
|
---|
148 | PRIVATE void phys_put32(addr, value)
|
---|
149 | phys_bytes addr;
|
---|
150 | u32_t value;
|
---|
151 | {
|
---|
152 | phys_copy(vir2phys((vir_bytes)&value), addr, sizeof(value));
|
---|
153 | }
|
---|
154 |
|
---|
155 | PRIVATE u32_t phys_get32(addr)
|
---|
156 | phys_bytes addr;
|
---|
157 | {
|
---|
158 | u32_t value;
|
---|
159 |
|
---|
160 | phys_copy(addr, vir2phys((vir_bytes)&value), sizeof(value));
|
---|
161 |
|
---|
162 | return value;
|
---|
163 | }
|
---|
164 |
|
---|
165 | PRIVATE void vm_set_cr3(value)
|
---|
166 | u32_t value;
|
---|
167 | {
|
---|
168 | vm_cr3= value;
|
---|
169 | level0(set_cr3);
|
---|
170 | }
|
---|
171 |
|
---|
172 | PRIVATE void set_cr3()
|
---|
173 | {
|
---|
174 | write_cr3(vm_cr3);
|
---|
175 | }
|
---|
176 |
|
---|
177 | PRIVATE void vm_enable_paging(void)
|
---|
178 | {
|
---|
179 | u32_t cr0;
|
---|
180 |
|
---|
181 | cr0= read_cr0();
|
---|
182 | write_cr0(cr0 | I386_CR0_PG);
|
---|
183 | }
|
---|
184 |
|
---|
185 | PRIVATE void map_range(base, size, offset)
|
---|
186 | u32_t base;
|
---|
187 | u32_t size;
|
---|
188 | u32_t offset;
|
---|
189 | {
|
---|
190 | u32_t curr_pt, curr_pt_addr, entry;
|
---|
191 | int dir_ent, pt_ent;
|
---|
192 |
|
---|
193 | if (base % PAGE_SIZE != 0)
|
---|
194 | panic("map_range: bad base", base);
|
---|
195 | if (size % PAGE_SIZE != 0)
|
---|
196 | panic("map_range: bad size", size);
|
---|
197 | if (offset % PAGE_SIZE != 0)
|
---|
198 | panic("map_range: bad offset", offset);
|
---|
199 |
|
---|
200 | curr_pt= -1;
|
---|
201 | curr_pt_addr= 0;
|
---|
202 | while (size != 0)
|
---|
203 | {
|
---|
204 | dir_ent= (base >> I386_VM_DIR_ENT_SHIFT);
|
---|
205 | pt_ent= (base >> I386_VM_PT_ENT_SHIFT) & I386_VM_PT_ENT_MASK;
|
---|
206 | if (dir_ent != curr_pt)
|
---|
207 | {
|
---|
208 | /* Get address of page table */
|
---|
209 | curr_pt= dir_ent;
|
---|
210 | curr_pt_addr= phys_get32(vm_cr3 +
|
---|
211 | dir_ent * I386_VM_PT_ENT_SIZE);
|
---|
212 | curr_pt_addr &= I386_VM_ADDR_MASK;
|
---|
213 | }
|
---|
214 | entry= offset | I386_VM_USER | I386_VM_WRITE |
|
---|
215 | I386_VM_PRESENT;
|
---|
216 | #if 0 /* Do we need this for memory mapped I/O? */
|
---|
217 | entry |= I386_VM_PCD | I386_VM_PWT;
|
---|
218 | #endif
|
---|
219 | phys_put32(curr_pt_addr + pt_ent * I386_VM_PT_ENT_SIZE, entry);
|
---|
220 | offset += PAGE_SIZE;
|
---|
221 | base += PAGE_SIZE;
|
---|
222 | size -= PAGE_SIZE;
|
---|
223 | }
|
---|
224 | }
|
---|