Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/alpha/mm/init.c
29269 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* linux/arch/alpha/mm/init.c
4
*
5
* Copyright (C) 1995 Linus Torvalds
6
*/
7
8
/* 2.3.x zone allocator, 1999 Andrea Arcangeli <[email protected]> */
9
10
#include <linux/pagemap.h>
11
#include <linux/signal.h>
12
#include <linux/sched.h>
13
#include <linux/kernel.h>
14
#include <linux/errno.h>
15
#include <linux/string.h>
16
#include <linux/types.h>
17
#include <linux/ptrace.h>
18
#include <linux/mman.h>
19
#include <linux/mm.h>
20
#include <linux/swap.h>
21
#include <linux/init.h>
22
#include <linux/memblock.h> /* max_low_pfn */
23
#include <linux/vmalloc.h>
24
#include <linux/gfp.h>
25
26
#include <linux/uaccess.h>
27
#include <asm/pgalloc.h>
28
#include <asm/hwrpb.h>
29
#include <asm/dma.h>
30
#include <asm/mmu_context.h>
31
#include <asm/console.h>
32
#include <asm/tlb.h>
33
#include <asm/setup.h>
34
#include <asm/sections.h>
35
36
#include "../kernel/proto.h"
37
38
static struct pcb_struct original_pcb;
39
40
pgd_t *
41
pgd_alloc(struct mm_struct *mm)
42
{
43
pgd_t *ret, *init;
44
45
ret = __pgd_alloc(mm, 0);
46
init = pgd_offset(&init_mm, 0UL);
47
if (ret) {
48
#ifdef CONFIG_ALPHA_LARGE_VMALLOC
49
memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
50
(PTRS_PER_PGD - USER_PTRS_PER_PGD - 1)*sizeof(pgd_t));
51
#else
52
pgd_val(ret[PTRS_PER_PGD-2]) = pgd_val(init[PTRS_PER_PGD-2]);
53
#endif
54
55
/* The last PGD entry is the VPTB self-map. */
56
pgd_val(ret[PTRS_PER_PGD-1])
57
= pte_val(mk_pte(virt_to_page(ret), PAGE_KERNEL));
58
}
59
return ret;
60
}
61
62
63
static inline unsigned long
64
load_PCB(struct pcb_struct *pcb)
65
{
66
register unsigned long sp __asm__("$30");
67
pcb->ksp = sp;
68
return __reload_thread(pcb);
69
}
70
71
/* Set up initial PCB, VPTB, and other such nicities. */
72
73
static inline void
74
switch_to_system_map(void)
75
{
76
unsigned long newptbr;
77
unsigned long original_pcb_ptr;
78
79
/* Initialize the kernel's page tables. Linux puts the vptb in
80
the last slot of the L1 page table. */
81
memset(swapper_pg_dir, 0, PAGE_SIZE);
82
newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT;
83
pgd_val(swapper_pg_dir[1023]) =
84
(newptbr << 32) | pgprot_val(PAGE_KERNEL);
85
86
/* Set the vptb. This is often done by the bootloader, but
87
shouldn't be required. */
88
if (hwrpb->vptb != 0xfffffffe00000000UL) {
89
wrvptptr(0xfffffffe00000000UL);
90
hwrpb->vptb = 0xfffffffe00000000UL;
91
hwrpb_update_checksum(hwrpb);
92
}
93
94
/* Also set up the real kernel PCB while we're at it. */
95
init_thread_info.pcb.ptbr = newptbr;
96
init_thread_info.pcb.flags = 1; /* set FEN, clear everything else */
97
original_pcb_ptr = load_PCB(&init_thread_info.pcb);
98
tbia();
99
100
/* Save off the contents of the original PCB so that we can
101
restore the original console's page tables for a clean reboot.
102
103
Note that the PCB is supposed to be a physical address, but
104
since KSEG values also happen to work, folks get confused.
105
Check this here. */
106
107
if (original_pcb_ptr < PAGE_OFFSET) {
108
original_pcb_ptr = (unsigned long)
109
phys_to_virt(original_pcb_ptr);
110
}
111
original_pcb = *(struct pcb_struct *) original_pcb_ptr;
112
}
113
114
int callback_init_done;
115
116
void * __init
117
callback_init(void * kernel_end)
118
{
119
struct crb_struct * crb;
120
pgd_t *pgd;
121
p4d_t *p4d;
122
pud_t *pud;
123
pmd_t *pmd;
124
void *two_pages;
125
126
/* Starting at the HWRPB, locate the CRB. */
127
crb = (struct crb_struct *)((char *)hwrpb + hwrpb->crb_offset);
128
129
if (alpha_using_srm) {
130
/* Tell the console whither it is to be remapped. */
131
if (srm_fixup(VMALLOC_START, (unsigned long)hwrpb))
132
__halt(); /* "We're boned." --Bender */
133
134
/* Edit the procedure descriptors for DISPATCH and FIXUP. */
135
crb->dispatch_va = (struct procdesc_struct *)
136
(VMALLOC_START + (unsigned long)crb->dispatch_va
137
- crb->map[0].va);
138
crb->fixup_va = (struct procdesc_struct *)
139
(VMALLOC_START + (unsigned long)crb->fixup_va
140
- crb->map[0].va);
141
}
142
143
switch_to_system_map();
144
145
/* Allocate one PGD and one PMD. In the case of SRM, we'll need
146
these to actually remap the console. There is an assumption
147
here that only one of each is needed, and this allows for 8MB.
148
On systems with larger consoles, additional pages will be
149
allocated as needed during the mapping process.
150
151
In the case of not SRM, but not CONFIG_ALPHA_LARGE_VMALLOC,
152
we need to allocate the PGD we use for vmalloc before we start
153
forking other tasks. */
154
155
two_pages = (void *)
156
(((unsigned long)kernel_end + ~PAGE_MASK) & PAGE_MASK);
157
kernel_end = two_pages + 2*PAGE_SIZE;
158
memset(two_pages, 0, 2*PAGE_SIZE);
159
160
pgd = pgd_offset_k(VMALLOC_START);
161
p4d = p4d_offset(pgd, VMALLOC_START);
162
pud = pud_offset(p4d, VMALLOC_START);
163
pud_set(pud, (pmd_t *)two_pages);
164
pmd = pmd_offset(pud, VMALLOC_START);
165
pmd_set(pmd, (pte_t *)(two_pages + PAGE_SIZE));
166
167
if (alpha_using_srm) {
168
static struct vm_struct console_remap_vm;
169
unsigned long nr_pages = 0;
170
unsigned long vaddr;
171
unsigned long i, j;
172
173
/* calculate needed size */
174
for (i = 0; i < crb->map_entries; ++i)
175
nr_pages += crb->map[i].count;
176
177
/* register the vm area */
178
console_remap_vm.flags = VM_ALLOC;
179
console_remap_vm.size = nr_pages << PAGE_SHIFT;
180
vm_area_register_early(&console_remap_vm, PAGE_SIZE);
181
182
vaddr = (unsigned long)console_remap_vm.addr;
183
184
/* Set up the third level PTEs and update the virtual
185
addresses of the CRB entries. */
186
for (i = 0; i < crb->map_entries; ++i) {
187
unsigned long pfn = crb->map[i].pa >> PAGE_SHIFT;
188
crb->map[i].va = vaddr;
189
for (j = 0; j < crb->map[i].count; ++j) {
190
/* Newer consoles (especially on larger
191
systems) may require more pages of
192
PTEs. Grab additional pages as needed. */
193
if (pmd != pmd_offset(pud, vaddr)) {
194
memset(kernel_end, 0, PAGE_SIZE);
195
pmd = pmd_offset(pud, vaddr);
196
pmd_set(pmd, (pte_t *)kernel_end);
197
kernel_end += PAGE_SIZE;
198
}
199
set_pte(pte_offset_kernel(pmd, vaddr),
200
pfn_pte(pfn, PAGE_KERNEL));
201
pfn++;
202
vaddr += PAGE_SIZE;
203
}
204
}
205
}
206
207
callback_init_done = 1;
208
return kernel_end;
209
}
210
211
/*
212
* paging_init() sets up the memory map.
213
*/
214
void __init paging_init(void)
215
{
216
unsigned long max_zone_pfn[MAX_NR_ZONES] = {0, };
217
unsigned long dma_pfn;
218
219
dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
220
max_pfn = max_low_pfn;
221
222
max_zone_pfn[ZONE_DMA] = dma_pfn;
223
max_zone_pfn[ZONE_NORMAL] = max_pfn;
224
225
/* Initialize mem_map[]. */
226
free_area_init(max_zone_pfn);
227
228
/* Initialize the kernel's ZERO_PGE. */
229
memset(absolute_pointer(ZERO_PGE), 0, PAGE_SIZE);
230
}
231
232
#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
233
void
234
srm_paging_stop (void)
235
{
236
/* Move the vptb back to where the SRM console expects it. */
237
swapper_pg_dir[1] = swapper_pg_dir[1023];
238
tbia();
239
wrvptptr(0x200000000UL);
240
hwrpb->vptb = 0x200000000UL;
241
hwrpb_update_checksum(hwrpb);
242
243
/* Reload the page tables that the console had in use. */
244
load_PCB(&original_pcb);
245
tbia();
246
}
247
#endif
248
249
static const pgprot_t protection_map[16] = {
250
[VM_NONE] = _PAGE_P(_PAGE_FOE | _PAGE_FOW |
251
_PAGE_FOR),
252
[VM_READ] = _PAGE_P(_PAGE_FOE | _PAGE_FOW),
253
[VM_WRITE] = _PAGE_P(_PAGE_FOE),
254
[VM_WRITE | VM_READ] = _PAGE_P(_PAGE_FOE),
255
[VM_EXEC] = _PAGE_P(_PAGE_FOW | _PAGE_FOR),
256
[VM_EXEC | VM_READ] = _PAGE_P(_PAGE_FOW),
257
[VM_EXEC | VM_WRITE] = _PAGE_P(0),
258
[VM_EXEC | VM_WRITE | VM_READ] = _PAGE_P(0),
259
[VM_SHARED] = _PAGE_S(_PAGE_FOE | _PAGE_FOW |
260
_PAGE_FOR),
261
[VM_SHARED | VM_READ] = _PAGE_S(_PAGE_FOE | _PAGE_FOW),
262
[VM_SHARED | VM_WRITE] = _PAGE_S(_PAGE_FOE),
263
[VM_SHARED | VM_WRITE | VM_READ] = _PAGE_S(_PAGE_FOE),
264
[VM_SHARED | VM_EXEC] = _PAGE_S(_PAGE_FOW | _PAGE_FOR),
265
[VM_SHARED | VM_EXEC | VM_READ] = _PAGE_S(_PAGE_FOW),
266
[VM_SHARED | VM_EXEC | VM_WRITE] = _PAGE_S(0),
267
[VM_SHARED | VM_EXEC | VM_WRITE | VM_READ] = _PAGE_S(0)
268
};
269
DECLARE_VM_GET_PAGE_PROT
270
271