~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/alpha/mm/init.c

Version: ~ [ linux-5.13-rc5 ] ~ [ linux-5.12.9 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.42 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.124 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.193 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.235 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.271 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.271 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp