linux/arch/riscv/kernel/setup.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
   3 *  Chen Liqin <liqin.chen@sunplusct.com>
   4 *  Lennox Wu <lennox.wu@sunplusct.com>
   5 * Copyright (C) 2012 Regents of the University of California
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, see the file COPYING, or write
  19 * to the Free Software Foundation, Inc.,
  20 */
  21
  22#include <linux/init.h>
  23#include <linux/mm.h>
  24#include <linux/memblock.h>
  25#include <linux/sched.h>
  26#include <linux/initrd.h>
  27#include <linux/console.h>
  28#include <linux/screen_info.h>
  29#include <linux/of_fdt.h>
  30#include <linux/of_platform.h>
  31#include <linux/sched/task.h>
  32
  33#include <asm/setup.h>
  34#include <asm/sections.h>
  35#include <asm/pgtable.h>
  36#include <asm/smp.h>
  37#include <asm/sbi.h>
  38#include <asm/tlbflush.h>
  39#include <asm/thread_info.h>
  40
  41#ifdef CONFIG_DUMMY_CONSOLE
  42struct screen_info screen_info = {
  43        .orig_video_lines       = 30,
  44        .orig_video_cols        = 80,
  45        .orig_video_mode        = 0,
  46        .orig_video_ega_bx      = 0,
  47        .orig_video_isVGA       = 1,
  48        .orig_video_points      = 8
  49};
  50#endif
  51
  52unsigned long va_pa_offset;
  53EXPORT_SYMBOL(va_pa_offset);
  54unsigned long pfn_base;
  55EXPORT_SYMBOL(pfn_base);
  56
  57unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss;
  58EXPORT_SYMBOL(empty_zero_page);
  59
  60/* The lucky hart to first increment this variable will boot the other cores */
  61atomic_t hart_lottery;
  62
  63#ifdef CONFIG_BLK_DEV_INITRD
  64static void __init setup_initrd(void)
  65{
  66        extern char __initramfs_start[];
  67        extern unsigned long __initramfs_size;
  68        unsigned long size;
  69
  70        if (__initramfs_size > 0) {
  71                initrd_start = (unsigned long)(&__initramfs_start);
  72                initrd_end = initrd_start + __initramfs_size;
  73        }
  74
  75        if (initrd_start >= initrd_end) {
  76                printk(KERN_INFO "initrd not found or empty");
  77                goto disable;
  78        }
  79        if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) {
  80                printk(KERN_ERR "initrd extends beyond end of memory");
  81                goto disable;
  82        }
  83
  84        size =  initrd_end - initrd_start;
  85        memblock_reserve(__pa(initrd_start), size);
  86        initrd_below_start_ok = 1;
  87
  88        printk(KERN_INFO "Initial ramdisk at: 0x%p (%lu bytes)\n",
  89                (void *)(initrd_start), size);
  90        return;
  91disable:
  92        pr_cont(" - disabling initrd\n");
  93        initrd_start = 0;
  94        initrd_end = 0;
  95}
  96#endif /* CONFIG_BLK_DEV_INITRD */
  97
  98pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
  99pgd_t trampoline_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
 100
 101#ifndef __PAGETABLE_PMD_FOLDED
 102#define NUM_SWAPPER_PMDS ((uintptr_t)-PAGE_OFFSET >> PGDIR_SHIFT)
 103pmd_t swapper_pmd[PTRS_PER_PMD*((-PAGE_OFFSET)/PGDIR_SIZE)] __page_aligned_bss;
 104pmd_t trampoline_pmd[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
 105#endif
 106
 107asmlinkage void __init setup_vm(void)
 108{
 109        extern char _start;
 110        uintptr_t i;
 111        uintptr_t pa = (uintptr_t) &_start;
 112        pgprot_t prot = __pgprot(pgprot_val(PAGE_KERNEL) | _PAGE_EXEC);
 113
 114        va_pa_offset = PAGE_OFFSET - pa;
 115        pfn_base = PFN_DOWN(pa);
 116
 117        /* Sanity check alignment and size */
 118        BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0);
 119        BUG_ON((pa % (PAGE_SIZE * PTRS_PER_PTE)) != 0);
 120
 121#ifndef __PAGETABLE_PMD_FOLDED
 122        trampoline_pg_dir[(PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD] =
 123                pfn_pgd(PFN_DOWN((uintptr_t)trampoline_pmd),
 124                        __pgprot(_PAGE_TABLE));
 125        trampoline_pmd[0] = pfn_pmd(PFN_DOWN(pa), prot);
 126
 127        for (i = 0; i < (-PAGE_OFFSET)/PGDIR_SIZE; ++i) {
 128                size_t o = (PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD + i;
 129                swapper_pg_dir[o] =
 130                        pfn_pgd(PFN_DOWN((uintptr_t)swapper_pmd) + i,
 131                                __pgprot(_PAGE_TABLE));
 132        }
 133        for (i = 0; i < ARRAY_SIZE(swapper_pmd); i++)
 134                swapper_pmd[i] = pfn_pmd(PFN_DOWN(pa + i * PMD_SIZE), prot);
 135#else
 136        trampoline_pg_dir[(PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD] =
 137                pfn_pgd(PFN_DOWN(pa), prot);
 138
 139        for (i = 0; i < (-PAGE_OFFSET)/PGDIR_SIZE; ++i) {
 140                size_t o = (PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD + i;
 141                swapper_pg_dir[o] =
 142                        pfn_pgd(PFN_DOWN(pa + i * PGDIR_SIZE), prot);
 143        }
 144#endif
 145}
 146
 147void __init parse_dtb(unsigned int hartid, void *dtb)
 148{
 149        early_init_dt_scan(__va(dtb));
 150}
 151
 152static void __init setup_bootmem(void)
 153{
 154        struct memblock_region *reg;
 155        phys_addr_t mem_size = 0;
 156
 157        /* Find the memory region containing the kernel */
 158        for_each_memblock(memory, reg) {
 159                phys_addr_t vmlinux_end = __pa(_end);
 160                phys_addr_t end = reg->base + reg->size;
 161
 162                if (reg->base <= vmlinux_end && vmlinux_end <= end) {
 163                        /*
 164                         * Reserve from the start of the region to the end of
 165                         * the kernel
 166                         */
 167                        memblock_reserve(reg->base, vmlinux_end - reg->base);
 168                        mem_size = min(reg->size, (phys_addr_t)-PAGE_OFFSET);
 169                }
 170        }
 171        BUG_ON(mem_size == 0);
 172
 173        set_max_mapnr(PFN_DOWN(mem_size));
 174        max_low_pfn = pfn_base + PFN_DOWN(mem_size);
 175
 176#ifdef CONFIG_BLK_DEV_INITRD
 177        setup_initrd();
 178#endif /* CONFIG_BLK_DEV_INITRD */
 179
 180        early_init_fdt_reserve_self();
 181        early_init_fdt_scan_reserved_mem();
 182        memblock_allow_resize();
 183        memblock_dump_all();
 184
 185        for_each_memblock(memory, reg) {
 186                unsigned long start_pfn = memblock_region_memory_base_pfn(reg);
 187                unsigned long end_pfn = memblock_region_memory_end_pfn(reg);
 188
 189                memblock_set_node(PFN_PHYS(start_pfn),
 190                                  PFN_PHYS(end_pfn - start_pfn),
 191                                  &memblock.memory, 0);
 192        }
 193}
 194
 195void __init setup_arch(char **cmdline_p)
 196{
 197        *cmdline_p = boot_command_line;
 198
 199        parse_early_param();
 200
 201        init_mm.start_code = (unsigned long) _stext;
 202        init_mm.end_code   = (unsigned long) _etext;
 203        init_mm.end_data   = (unsigned long) _edata;
 204        init_mm.brk        = (unsigned long) _end;
 205
 206        setup_bootmem();
 207        paging_init();
 208        unflatten_device_tree();
 209
 210#ifdef CONFIG_SMP
 211        setup_smp();
 212#endif
 213
 214#ifdef CONFIG_DUMMY_CONSOLE
 215        conswitchp = &dummy_con;
 216#endif
 217
 218        riscv_fill_hwcap();
 219}
 220
 221static int __init riscv_device_init(void)
 222{
 223        return of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 224}
 225subsys_initcall_sync(riscv_device_init);
 226