OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [alpha/] [mm/] [init.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.