File Index
Files and directories
Sign in
FILE

init.c

File preview with syntax highlighting.

linux-6.19.14/arch/alpha/mm/init.c C
  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 <andrea@suse.de> */
  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
 38static struct pcb_struct original_pcb;
 39
 40pgd_t *
 41pgd_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
 63static inline unsigned long
 64load_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
 73static inline void
 74switch_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
114int callback_init_done;
115
116void * __init
117callback_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 */
214void __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)
233void
234srm_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
249static 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};
269DECLARE_VM_GET_PAGE_PROT
~/ Read-only file preview.