• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <andrea@suse.de> */
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/uaccess.h>
26 #include <asm/pgtable.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 extern void die_if_kernel(char *,struct pt_regs *,long);
37 
38 static struct pcb_struct original_pcb;
39 
40 pgd_t *
pgd_alloc(struct mm_struct * mm)41 pgd_alloc(struct mm_struct *mm)
42 {
43 	pgd_t *ret, *init;
44 
45 	ret = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
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 /*
64  * BAD_PAGE is the page that is used for page faults when linux
65  * is out-of-memory. Older versions of linux just did a
66  * do_exit(), but using this instead means there is less risk
67  * for a process dying in kernel mode, possibly leaving an inode
68  * unused etc..
69  *
70  * BAD_PAGETABLE is the accompanying page-table: it is initialized
71  * to point to BAD_PAGE entries.
72  *
73  * ZERO_PAGE is a special page that is used for zero-initialized
74  * data and COW.
75  */
76 pmd_t *
__bad_pagetable(void)77 __bad_pagetable(void)
78 {
79 	memset((void *) EMPTY_PGT, 0, PAGE_SIZE);
80 	return (pmd_t *) EMPTY_PGT;
81 }
82 
83 pte_t
__bad_page(void)84 __bad_page(void)
85 {
86 	memset((void *) EMPTY_PGE, 0, PAGE_SIZE);
87 	return pte_mkdirty(mk_pte(virt_to_page(EMPTY_PGE), PAGE_SHARED));
88 }
89 
90 static inline unsigned long
load_PCB(struct pcb_struct * pcb)91 load_PCB(struct pcb_struct *pcb)
92 {
93 	register unsigned long sp __asm__("$30");
94 	pcb->ksp = sp;
95 	return __reload_thread(pcb);
96 }
97 
98 /* Set up initial PCB, VPTB, and other such nicities.  */
99 
100 static inline void
switch_to_system_map(void)101 switch_to_system_map(void)
102 {
103 	unsigned long newptbr;
104 	unsigned long original_pcb_ptr;
105 
106 	/* Initialize the kernel's page tables.  Linux puts the vptb in
107 	   the last slot of the L1 page table.  */
108 	memset(swapper_pg_dir, 0, PAGE_SIZE);
109 	newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT;
110 	pgd_val(swapper_pg_dir[1023]) =
111 		(newptbr << 32) | pgprot_val(PAGE_KERNEL);
112 
113 	/* Set the vptb.  This is often done by the bootloader, but
114 	   shouldn't be required.  */
115 	if (hwrpb->vptb != 0xfffffffe00000000UL) {
116 		wrvptptr(0xfffffffe00000000UL);
117 		hwrpb->vptb = 0xfffffffe00000000UL;
118 		hwrpb_update_checksum(hwrpb);
119 	}
120 
121 	/* Also set up the real kernel PCB while we're at it.  */
122 	init_thread_info.pcb.ptbr = newptbr;
123 	init_thread_info.pcb.flags = 1;	/* set FEN, clear everything else */
124 	original_pcb_ptr = load_PCB(&init_thread_info.pcb);
125 	tbia();
126 
127 	/* Save off the contents of the original PCB so that we can
128 	   restore the original console's page tables for a clean reboot.
129 
130 	   Note that the PCB is supposed to be a physical address, but
131 	   since KSEG values also happen to work, folks get confused.
132 	   Check this here.  */
133 
134 	if (original_pcb_ptr < PAGE_OFFSET) {
135 		original_pcb_ptr = (unsigned long)
136 			phys_to_virt(original_pcb_ptr);
137 	}
138 	original_pcb = *(struct pcb_struct *) original_pcb_ptr;
139 }
140 
141 int callback_init_done;
142 
143 void * __init
callback_init(void * kernel_end)144 callback_init(void * kernel_end)
145 {
146 	struct crb_struct * crb;
147 	pgd_t *pgd;
148 	pmd_t *pmd;
149 	void *two_pages;
150 
151 	/* Starting at the HWRPB, locate the CRB. */
152 	crb = (struct crb_struct *)((char *)hwrpb + hwrpb->crb_offset);
153 
154 	if (alpha_using_srm) {
155 		/* Tell the console whither it is to be remapped. */
156 		if (srm_fixup(VMALLOC_START, (unsigned long)hwrpb))
157 			__halt();		/* "We're boned."  --Bender */
158 
159 		/* Edit the procedure descriptors for DISPATCH and FIXUP. */
160 		crb->dispatch_va = (struct procdesc_struct *)
161 			(VMALLOC_START + (unsigned long)crb->dispatch_va
162 			 - crb->map[0].va);
163 		crb->fixup_va = (struct procdesc_struct *)
164 			(VMALLOC_START + (unsigned long)crb->fixup_va
165 			 - crb->map[0].va);
166 	}
167 
168 	switch_to_system_map();
169 
170 	/* Allocate one PGD and one PMD.  In the case of SRM, we'll need
171 	   these to actually remap the console.  There is an assumption
172 	   here that only one of each is needed, and this allows for 8MB.
173 	   On systems with larger consoles, additional pages will be
174 	   allocated as needed during the mapping process.
175 
176 	   In the case of not SRM, but not CONFIG_ALPHA_LARGE_VMALLOC,
177 	   we need to allocate the PGD we use for vmalloc before we start
178 	   forking other tasks.  */
179 
180 	two_pages = (void *)
181 	  (((unsigned long)kernel_end + ~PAGE_MASK) & PAGE_MASK);
182 	kernel_end = two_pages + 2*PAGE_SIZE;
183 	memset(two_pages, 0, 2*PAGE_SIZE);
184 
185 	pgd = pgd_offset_k(VMALLOC_START);
186 	pgd_set(pgd, (pmd_t *)two_pages);
187 	pmd = pmd_offset(pgd, VMALLOC_START);
188 	pmd_set(pmd, (pte_t *)(two_pages + PAGE_SIZE));
189 
190 	if (alpha_using_srm) {
191 		static struct vm_struct console_remap_vm;
192 		unsigned long nr_pages = 0;
193 		unsigned long vaddr;
194 		unsigned long i, j;
195 
196 		/* calculate needed size */
197 		for (i = 0; i < crb->map_entries; ++i)
198 			nr_pages += crb->map[i].count;
199 
200 		/* register the vm area */
201 		console_remap_vm.flags = VM_ALLOC;
202 		console_remap_vm.size = nr_pages << PAGE_SHIFT;
203 		vm_area_register_early(&console_remap_vm, PAGE_SIZE);
204 
205 		vaddr = (unsigned long)console_remap_vm.addr;
206 
207 		/* Set up the third level PTEs and update the virtual
208 		   addresses of the CRB entries.  */
209 		for (i = 0; i < crb->map_entries; ++i) {
210 			unsigned long pfn = crb->map[i].pa >> PAGE_SHIFT;
211 			crb->map[i].va = vaddr;
212 			for (j = 0; j < crb->map[i].count; ++j) {
213 				/* Newer consoles (especially on larger
214 				   systems) may require more pages of
215 				   PTEs. Grab additional pages as needed. */
216 				if (pmd != pmd_offset(pgd, vaddr)) {
217 					memset(kernel_end, 0, PAGE_SIZE);
218 					pmd = pmd_offset(pgd, vaddr);
219 					pmd_set(pmd, (pte_t *)kernel_end);
220 					kernel_end += PAGE_SIZE;
221 				}
222 				set_pte(pte_offset_kernel(pmd, vaddr),
223 					pfn_pte(pfn, PAGE_KERNEL));
224 				pfn++;
225 				vaddr += PAGE_SIZE;
226 			}
227 		}
228 	}
229 
230 	callback_init_done = 1;
231 	return kernel_end;
232 }
233 
234 
235 #ifndef CONFIG_DISCONTIGMEM
236 /*
237  * paging_init() sets up the memory map.
238  */
paging_init(void)239 void __init paging_init(void)
240 {
241 	unsigned long zones_size[MAX_NR_ZONES] = {0, };
242 	unsigned long dma_pfn, high_pfn;
243 
244 	dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
245 	high_pfn = max_pfn = max_low_pfn;
246 
247 	if (dma_pfn >= high_pfn)
248 		zones_size[ZONE_DMA] = high_pfn;
249 	else {
250 		zones_size[ZONE_DMA] = dma_pfn;
251 		zones_size[ZONE_NORMAL] = high_pfn - dma_pfn;
252 	}
253 
254 	/* Initialize mem_map[].  */
255 	free_area_init(zones_size);
256 
257 	/* Initialize the kernel's ZERO_PGE. */
258 	memset((void *)ZERO_PGE, 0, PAGE_SIZE);
259 }
260 #endif /* CONFIG_DISCONTIGMEM */
261 
262 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
263 void
srm_paging_stop(void)264 srm_paging_stop (void)
265 {
266 	/* Move the vptb back to where the SRM console expects it.  */
267 	swapper_pg_dir[1] = swapper_pg_dir[1023];
268 	tbia();
269 	wrvptptr(0x200000000UL);
270 	hwrpb->vptb = 0x200000000UL;
271 	hwrpb_update_checksum(hwrpb);
272 
273 	/* Reload the page tables that the console had in use.  */
274 	load_PCB(&original_pcb);
275 	tbia();
276 }
277 #endif
278 
279 void __init
mem_init(void)280 mem_init(void)
281 {
282 	set_max_mapnr(max_low_pfn);
283 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
284 	free_all_bootmem();
285 	mem_init_print_info(NULL);
286 }
287 
288 void
free_initmem(void)289 free_initmem(void)
290 {
291 	free_initmem_default(-1);
292 }
293 
294 #ifdef CONFIG_BLK_DEV_INITRD
295 void
free_initrd_mem(unsigned long start,unsigned long end)296 free_initrd_mem(unsigned long start, unsigned long end)
297 {
298 	free_reserved_area((void *)start, (void *)end, -1, "initrd");
299 }
300 #endif
301