Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/alpha/mm/init.c
10817 views
1
/*
2
* linux/arch/alpha/mm/init.c
3
*
4
* Copyright (C) 1995 Linus Torvalds
5
*/
6
7
/* 2.3.x zone allocator, 1999 Andrea Arcangeli <[email protected]> */
8
9
#include <linux/pagemap.h>
10
#include <linux/signal.h>
11
#include <linux/sched.h>
12
#include <linux/kernel.h>
13
#include <linux/errno.h>
14
#include <linux/string.h>
15
#include <linux/types.h>
16
#include <linux/ptrace.h>
17
#include <linux/mman.h>
18
#include <linux/mm.h>
19
#include <linux/swap.h>
20
#include <linux/init.h>
21
#include <linux/bootmem.h> /* max_low_pfn */
22
#include <linux/vmalloc.h>
23
#include <linux/gfp.h>
24
25
#include <asm/system.h>
26
#include <asm/uaccess.h>
27
#include <asm/pgtable.h>
28
#include <asm/pgalloc.h>
29
#include <asm/hwrpb.h>
30
#include <asm/dma.h>
31
#include <asm/mmu_context.h>
32
#include <asm/console.h>
33
#include <asm/tlb.h>
34
35
extern void die_if_kernel(char *,struct pt_regs *,long);
36
37
static struct pcb_struct original_pcb;
38
39
pgd_t *
40
pgd_alloc(struct mm_struct *mm)
41
{
42
pgd_t *ret, *init;
43
44
ret = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
45
init = pgd_offset(&init_mm, 0UL);
46
if (ret) {
47
#ifdef CONFIG_ALPHA_LARGE_VMALLOC
48
memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
49
(PTRS_PER_PGD - USER_PTRS_PER_PGD - 1)*sizeof(pgd_t));
50
#else
51
pgd_val(ret[PTRS_PER_PGD-2]) = pgd_val(init[PTRS_PER_PGD-2]);
52
#endif
53
54
/* The last PGD entry is the VPTB self-map. */
55
pgd_val(ret[PTRS_PER_PGD-1])
56
= pte_val(mk_pte(virt_to_page(ret), PAGE_KERNEL));
57
}
58
return ret;
59
}
60
61
62
/*
63
* BAD_PAGE is the page that is used for page faults when linux
64
* is out-of-memory. Older versions of linux just did a
65
* do_exit(), but using this instead means there is less risk
66
* for a process dying in kernel mode, possibly leaving an inode
67
* unused etc..
68
*
69
* BAD_PAGETABLE is the accompanying page-table: it is initialized
70
* to point to BAD_PAGE entries.
71
*
72
* ZERO_PAGE is a special page that is used for zero-initialized
73
* data and COW.
74
*/
75
pmd_t *
76
__bad_pagetable(void)
77
{
78
memset((void *) EMPTY_PGT, 0, PAGE_SIZE);
79
return (pmd_t *) EMPTY_PGT;
80
}
81
82
pte_t
83
__bad_page(void)
84
{
85
memset((void *) EMPTY_PGE, 0, PAGE_SIZE);
86
return pte_mkdirty(mk_pte(virt_to_page(EMPTY_PGE), PAGE_SHARED));
87
}
88
89
static inline unsigned long
90
load_PCB(struct pcb_struct *pcb)
91
{
92
register unsigned long sp __asm__("$30");
93
pcb->ksp = sp;
94
return __reload_thread(pcb);
95
}
96
97
/* Set up initial PCB, VPTB, and other such nicities. */
98
99
static inline void
100
switch_to_system_map(void)
101
{
102
unsigned long newptbr;
103
unsigned long original_pcb_ptr;
104
105
/* Initialize the kernel's page tables. Linux puts the vptb in
106
the last slot of the L1 page table. */
107
memset(swapper_pg_dir, 0, PAGE_SIZE);
108
newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT;
109
pgd_val(swapper_pg_dir[1023]) =
110
(newptbr << 32) | pgprot_val(PAGE_KERNEL);
111
112
/* Set the vptb. This is often done by the bootloader, but
113
shouldn't be required. */
114
if (hwrpb->vptb != 0xfffffffe00000000UL) {
115
wrvptptr(0xfffffffe00000000UL);
116
hwrpb->vptb = 0xfffffffe00000000UL;
117
hwrpb_update_checksum(hwrpb);
118
}
119
120
/* Also set up the real kernel PCB while we're at it. */
121
init_thread_info.pcb.ptbr = newptbr;
122
init_thread_info.pcb.flags = 1; /* set FEN, clear everything else */
123
original_pcb_ptr = load_PCB(&init_thread_info.pcb);
124
tbia();
125
126
/* Save off the contents of the original PCB so that we can
127
restore the original console's page tables for a clean reboot.
128
129
Note that the PCB is supposed to be a physical address, but
130
since KSEG values also happen to work, folks get confused.
131
Check this here. */
132
133
if (original_pcb_ptr < PAGE_OFFSET) {
134
original_pcb_ptr = (unsigned long)
135
phys_to_virt(original_pcb_ptr);
136
}
137
original_pcb = *(struct pcb_struct *) original_pcb_ptr;
138
}
139
140
int callback_init_done;
141
142
void * __init
143
callback_init(void * kernel_end)
144
{
145
struct crb_struct * crb;
146
pgd_t *pgd;
147
pmd_t *pmd;
148
void *two_pages;
149
150
/* Starting at the HWRPB, locate the CRB. */
151
crb = (struct crb_struct *)((char *)hwrpb + hwrpb->crb_offset);
152
153
if (alpha_using_srm) {
154
/* Tell the console whither it is to be remapped. */
155
if (srm_fixup(VMALLOC_START, (unsigned long)hwrpb))
156
__halt(); /* "We're boned." --Bender */
157
158
/* Edit the procedure descriptors for DISPATCH and FIXUP. */
159
crb->dispatch_va = (struct procdesc_struct *)
160
(VMALLOC_START + (unsigned long)crb->dispatch_va
161
- crb->map[0].va);
162
crb->fixup_va = (struct procdesc_struct *)
163
(VMALLOC_START + (unsigned long)crb->fixup_va
164
- crb->map[0].va);
165
}
166
167
switch_to_system_map();
168
169
/* Allocate one PGD and one PMD. In the case of SRM, we'll need
170
these to actually remap the console. There is an assumption
171
here that only one of each is needed, and this allows for 8MB.
172
On systems with larger consoles, additional pages will be
173
allocated as needed during the mapping process.
174
175
In the case of not SRM, but not CONFIG_ALPHA_LARGE_VMALLOC,
176
we need to allocate the PGD we use for vmalloc before we start
177
forking other tasks. */
178
179
two_pages = (void *)
180
(((unsigned long)kernel_end + ~PAGE_MASK) & PAGE_MASK);
181
kernel_end = two_pages + 2*PAGE_SIZE;
182
memset(two_pages, 0, 2*PAGE_SIZE);
183
184
pgd = pgd_offset_k(VMALLOC_START);
185
pgd_set(pgd, (pmd_t *)two_pages);
186
pmd = pmd_offset(pgd, VMALLOC_START);
187
pmd_set(pmd, (pte_t *)(two_pages + PAGE_SIZE));
188
189
if (alpha_using_srm) {
190
static struct vm_struct console_remap_vm;
191
unsigned long nr_pages = 0;
192
unsigned long vaddr;
193
unsigned long i, j;
194
195
/* calculate needed size */
196
for (i = 0; i < crb->map_entries; ++i)
197
nr_pages += crb->map[i].count;
198
199
/* register the vm area */
200
console_remap_vm.flags = VM_ALLOC;
201
console_remap_vm.size = nr_pages << PAGE_SHIFT;
202
vm_area_register_early(&console_remap_vm, PAGE_SIZE);
203
204
vaddr = (unsigned long)console_remap_vm.addr;
205
206
/* Set up the third level PTEs and update the virtual
207
addresses of the CRB entries. */
208
for (i = 0; i < crb->map_entries; ++i) {
209
unsigned long pfn = crb->map[i].pa >> PAGE_SHIFT;
210
crb->map[i].va = vaddr;
211
for (j = 0; j < crb->map[i].count; ++j) {
212
/* Newer consoles (especially on larger
213
systems) may require more pages of
214
PTEs. Grab additional pages as needed. */
215
if (pmd != pmd_offset(pgd, vaddr)) {
216
memset(kernel_end, 0, PAGE_SIZE);
217
pmd = pmd_offset(pgd, vaddr);
218
pmd_set(pmd, (pte_t *)kernel_end);
219
kernel_end += PAGE_SIZE;
220
}
221
set_pte(pte_offset_kernel(pmd, vaddr),
222
pfn_pte(pfn, PAGE_KERNEL));
223
pfn++;
224
vaddr += PAGE_SIZE;
225
}
226
}
227
}
228
229
callback_init_done = 1;
230
return kernel_end;
231
}
232
233
234
#ifndef CONFIG_DISCONTIGMEM
235
/*
236
* paging_init() sets up the memory map.
237
*/
238
void __init paging_init(void)
239
{
240
unsigned long zones_size[MAX_NR_ZONES] = {0, };
241
unsigned long dma_pfn, high_pfn;
242
243
dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
244
high_pfn = max_pfn = max_low_pfn;
245
246
if (dma_pfn >= high_pfn)
247
zones_size[ZONE_DMA] = high_pfn;
248
else {
249
zones_size[ZONE_DMA] = dma_pfn;
250
zones_size[ZONE_NORMAL] = high_pfn - dma_pfn;
251
}
252
253
/* Initialize mem_map[]. */
254
free_area_init(zones_size);
255
256
/* Initialize the kernel's ZERO_PGE. */
257
memset((void *)ZERO_PGE, 0, PAGE_SIZE);
258
}
259
#endif /* CONFIG_DISCONTIGMEM */
260
261
#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
262
void
263
srm_paging_stop (void)
264
{
265
/* Move the vptb back to where the SRM console expects it. */
266
swapper_pg_dir[1] = swapper_pg_dir[1023];
267
tbia();
268
wrvptptr(0x200000000UL);
269
hwrpb->vptb = 0x200000000UL;
270
hwrpb_update_checksum(hwrpb);
271
272
/* Reload the page tables that the console had in use. */
273
load_PCB(&original_pcb);
274
tbia();
275
}
276
#endif
277
278
#ifndef CONFIG_DISCONTIGMEM
279
static void __init
280
printk_memory_info(void)
281
{
282
unsigned long codesize, reservedpages, datasize, initsize, tmp;
283
extern int page_is_ram(unsigned long) __init;
284
extern char _text, _etext, _data, _edata;
285
extern char __init_begin, __init_end;
286
287
/* printk all informations */
288
reservedpages = 0;
289
for (tmp = 0; tmp < max_low_pfn; tmp++)
290
/*
291
* Only count reserved RAM pages
292
*/
293
if (page_is_ram(tmp) && PageReserved(mem_map+tmp))
294
reservedpages++;
295
296
codesize = (unsigned long) &_etext - (unsigned long) &_text;
297
datasize = (unsigned long) &_edata - (unsigned long) &_data;
298
initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
299
300
printk("Memory: %luk/%luk available (%luk kernel code, %luk reserved, %luk data, %luk init)\n",
301
nr_free_pages() << (PAGE_SHIFT-10),
302
max_mapnr << (PAGE_SHIFT-10),
303
codesize >> 10,
304
reservedpages << (PAGE_SHIFT-10),
305
datasize >> 10,
306
initsize >> 10);
307
}
308
309
void __init
310
mem_init(void)
311
{
312
max_mapnr = num_physpages = max_low_pfn;
313
totalram_pages += free_all_bootmem();
314
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
315
316
printk_memory_info();
317
}
318
#endif /* CONFIG_DISCONTIGMEM */
319
320
void
321
free_reserved_mem(void *start, void *end)
322
{
323
void *__start = start;
324
for (; __start < end; __start += PAGE_SIZE) {
325
ClearPageReserved(virt_to_page(__start));
326
init_page_count(virt_to_page(__start));
327
free_page((long)__start);
328
totalram_pages++;
329
}
330
}
331
332
void
333
free_initmem(void)
334
{
335
extern char __init_begin, __init_end;
336
337
free_reserved_mem(&__init_begin, &__init_end);
338
printk ("Freeing unused kernel memory: %ldk freed\n",
339
(&__init_end - &__init_begin) >> 10);
340
}
341
342
#ifdef CONFIG_BLK_DEV_INITRD
343
void
344
free_initrd_mem(unsigned long start, unsigned long end)
345
{
346
free_reserved_mem((void *)start, (void *)end);
347
printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
348
}
349
#endif
350
351