Skip to content

Commit 76d2a04

Browse files
RISC-V: Init and Halt Code
This contains the various __init C functions, the initial assembly kernel entry point, and the code to reset the system. When a file was init-related this patch contains the entire file. Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 8caea50 commit 76d2a04

File tree

15 files changed

+1524
-0
lines changed

15 files changed

+1524
-0
lines changed

arch/riscv/include/asm/bug.h

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright (C) 2012 Regents of the University of California
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation, version 2.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
14+
#ifndef _ASM_RISCV_BUG_H
15+
#define _ASM_RISCV_BUG_H
16+
17+
#include <linux/compiler.h>
18+
#include <linux/const.h>
19+
#include <linux/types.h>
20+
21+
#include <asm/asm.h>
22+
23+
#ifdef CONFIG_GENERIC_BUG
24+
#define __BUG_INSN _AC(0x00100073, UL) /* ebreak */
25+
26+
#ifndef __ASSEMBLY__
27+
typedef u32 bug_insn_t;
28+
29+
#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
30+
#define __BUG_ENTRY_ADDR INT " 1b - 2b"
31+
#define __BUG_ENTRY_FILE INT " %0 - 2b"
32+
#else
33+
#define __BUG_ENTRY_ADDR RISCV_PTR " 1b"
34+
#define __BUG_ENTRY_FILE RISCV_PTR " %0"
35+
#endif
36+
37+
#ifdef CONFIG_DEBUG_BUGVERBOSE
38+
#define __BUG_ENTRY \
39+
__BUG_ENTRY_ADDR "\n\t" \
40+
__BUG_ENTRY_FILE "\n\t" \
41+
SHORT " %1"
42+
#else
43+
#define __BUG_ENTRY \
44+
__BUG_ENTRY_ADDR
45+
#endif
46+
47+
#define BUG() \
48+
do { \
49+
__asm__ __volatile__ ( \
50+
"1:\n\t" \
51+
"ebreak\n" \
52+
".pushsection __bug_table,\"a\"\n\t" \
53+
"2:\n\t" \
54+
__BUG_ENTRY "\n\t" \
55+
".org 2b + %2\n\t" \
56+
".popsection" \
57+
: \
58+
: "i" (__FILE__), "i" (__LINE__), \
59+
"i" (sizeof(struct bug_entry))); \
60+
unreachable(); \
61+
} while (0)
62+
#endif /* !__ASSEMBLY__ */
63+
#else /* CONFIG_GENERIC_BUG */
64+
#ifndef __ASSEMBLY__
65+
#define BUG() \
66+
do { \
67+
__asm__ __volatile__ ("ebreak\n"); \
68+
unreachable(); \
69+
} while (0)
70+
#endif /* !__ASSEMBLY__ */
71+
#endif /* CONFIG_GENERIC_BUG */
72+
73+
#define HAVE_ARCH_BUG
74+
75+
#include <asm-generic/bug.h>
76+
77+
#ifndef __ASSEMBLY__
78+
79+
struct pt_regs;
80+
struct task_struct;
81+
82+
extern void die(struct pt_regs *regs, const char *str);
83+
extern void do_trap(struct pt_regs *regs, int signo, int code,
84+
unsigned long addr, struct task_struct *tsk);
85+
86+
#endif /* !__ASSEMBLY__ */
87+
88+
#endif /* _ASM_RISCV_BUG_H */

arch/riscv/include/asm/cache.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (C) 2017 Chen Liqin <[email protected]>
3+
* Copyright (C) 2012 Regents of the University of California
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU General Public License
7+
* as published by the Free Software Foundation, version 2.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*/
14+
15+
#ifndef _ASM_RISCV_CACHE_H
16+
#define _ASM_RISCV_CACHE_H
17+
18+
#define L1_CACHE_SHIFT 6
19+
20+
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
21+
22+
#endif /* _ASM_RISCV_CACHE_H */

arch/riscv/include/asm/smp.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (C) 2012 Regents of the University of California
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation, version 2.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
14+
#ifndef _ASM_RISCV_SMP_H
15+
#define _ASM_RISCV_SMP_H
16+
17+
/* This both needs asm-offsets.h and is used when generating it. */
18+
#ifndef GENERATING_ASM_OFFSETS
19+
#include <asm/asm-offsets.h>
20+
#endif
21+
22+
#include <linux/cpumask.h>
23+
#include <linux/irqreturn.h>
24+
25+
#ifdef CONFIG_SMP
26+
27+
/* SMP initialization hook for setup_arch */
28+
void __init init_clockevent(void);
29+
30+
/* SMP initialization hook for setup_arch */
31+
void __init setup_smp(void);
32+
33+
/* Hook for the generic smp_call_function_many() routine. */
34+
void arch_send_call_function_ipi_mask(struct cpumask *mask);
35+
36+
/* Hook for the generic smp_call_function_single() routine. */
37+
void arch_send_call_function_single_ipi(int cpu);
38+
39+
/*
40+
* This is particularly ugly: it appears we can't actually get the definition
41+
* of task_struct here, but we need access to the CPU this task is running on.
42+
* Instead of using C we're using asm-offsets.h to get the current processor
43+
* ID.
44+
*/
45+
#define raw_smp_processor_id() (*((int*)((char*)get_current() + TASK_TI_CPU)))
46+
47+
/* Interprocessor interrupt handler */
48+
irqreturn_t handle_ipi(void);
49+
50+
#endif /* CONFIG_SMP */
51+
52+
#endif /* _ASM_RISCV_SMP_H */

arch/riscv/kernel/cacheinfo.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright (C) 2017 SiFive
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation, version 2.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
14+
#include <linux/cacheinfo.h>
15+
#include <linux/cpu.h>
16+
#include <linux/of.h>
17+
#include <linux/of_device.h>
18+
19+
static void ci_leaf_init(struct cacheinfo *this_leaf,
20+
struct device_node *node,
21+
enum cache_type type, unsigned int level)
22+
{
23+
this_leaf->of_node = node;
24+
this_leaf->level = level;
25+
this_leaf->type = type;
26+
/* not a sector cache */
27+
this_leaf->physical_line_partition = 1;
28+
/* TODO: Add to DTS */
29+
this_leaf->attributes =
30+
CACHE_WRITE_BACK
31+
| CACHE_READ_ALLOCATE
32+
| CACHE_WRITE_ALLOCATE;
33+
}
34+
35+
static int __init_cache_level(unsigned int cpu)
36+
{
37+
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
38+
struct device_node *np = of_cpu_device_node_get(cpu);
39+
int levels = 0, leaves = 0, level;
40+
41+
if (of_property_read_bool(np, "cache-size"))
42+
++leaves;
43+
if (of_property_read_bool(np, "i-cache-size"))
44+
++leaves;
45+
if (of_property_read_bool(np, "d-cache-size"))
46+
++leaves;
47+
if (leaves > 0)
48+
levels = 1;
49+
50+
while ((np = of_find_next_cache_node(np))) {
51+
if (!of_device_is_compatible(np, "cache"))
52+
break;
53+
if (of_property_read_u32(np, "cache-level", &level))
54+
break;
55+
if (level <= levels)
56+
break;
57+
if (of_property_read_bool(np, "cache-size"))
58+
++leaves;
59+
if (of_property_read_bool(np, "i-cache-size"))
60+
++leaves;
61+
if (of_property_read_bool(np, "d-cache-size"))
62+
++leaves;
63+
levels = level;
64+
}
65+
66+
this_cpu_ci->num_levels = levels;
67+
this_cpu_ci->num_leaves = leaves;
68+
return 0;
69+
}
70+
71+
static int __populate_cache_leaves(unsigned int cpu)
72+
{
73+
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
74+
struct cacheinfo *this_leaf = this_cpu_ci->info_list;
75+
struct device_node *np = of_cpu_device_node_get(cpu);
76+
int levels = 1, level = 1;
77+
78+
if (of_property_read_bool(np, "cache-size"))
79+
ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level);
80+
if (of_property_read_bool(np, "i-cache-size"))
81+
ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level);
82+
if (of_property_read_bool(np, "d-cache-size"))
83+
ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level);
84+
85+
while ((np = of_find_next_cache_node(np))) {
86+
if (!of_device_is_compatible(np, "cache"))
87+
break;
88+
if (of_property_read_u32(np, "cache-level", &level))
89+
break;
90+
if (level <= levels)
91+
break;
92+
if (of_property_read_bool(np, "cache-size"))
93+
ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level);
94+
if (of_property_read_bool(np, "i-cache-size"))
95+
ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level);
96+
if (of_property_read_bool(np, "d-cache-size"))
97+
ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level);
98+
levels = level;
99+
}
100+
101+
return 0;
102+
}
103+
104+
DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
105+
DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)

arch/riscv/kernel/cpu.c

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright (C) 2012 Regents of the University of California
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation, version 2.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
14+
#include <linux/init.h>
15+
#include <linux/seq_file.h>
16+
#include <linux/of.h>
17+
18+
/* Return -1 if not a valid hart */
19+
int riscv_of_processor_hart(struct device_node *node)
20+
{
21+
const char *isa, *status;
22+
u32 hart;
23+
24+
if (!of_device_is_compatible(node, "riscv")) {
25+
pr_warn("Found incompatible CPU\n");
26+
return -(ENODEV);
27+
}
28+
29+
if (of_property_read_u32(node, "reg", &hart)) {
30+
pr_warn("Found CPU without hart ID\n");
31+
return -(ENODEV);
32+
}
33+
if (hart >= NR_CPUS) {
34+
pr_info("Found hart ID %d, which is above NR_CPUs. Disabling this hart\n", hart);
35+
return -(ENODEV);
36+
}
37+
38+
if (of_property_read_string(node, "status", &status)) {
39+
pr_warn("CPU with hartid=%d has no \"status\" property\n", hart);
40+
return -(ENODEV);
41+
}
42+
if (strcmp(status, "okay")) {
43+
pr_info("CPU with hartid=%d has a non-okay status of \"%s\"\n", hart, status);
44+
return -(ENODEV);
45+
}
46+
47+
if (of_property_read_string(node, "riscv,isa", &isa)) {
48+
pr_warn("CPU with hartid=%d has no \"riscv,isa\" property\n", hart);
49+
return -(ENODEV);
50+
}
51+
if (isa[0] != 'r' || isa[1] != 'v') {
52+
pr_warn("CPU with hartid=%d has an invalid ISA of \"%s\"\n", hart, isa);
53+
return -(ENODEV);
54+
}
55+
56+
return hart;
57+
}
58+
59+
#ifdef CONFIG_PROC_FS
60+
61+
static void *c_start(struct seq_file *m, loff_t *pos)
62+
{
63+
*pos = cpumask_next(*pos - 1, cpu_online_mask);
64+
if ((*pos) < nr_cpu_ids)
65+
return (void *)(uintptr_t)(1 + *pos);
66+
return NULL;
67+
}
68+
69+
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
70+
{
71+
(*pos)++;
72+
return c_start(m, pos);
73+
}
74+
75+
static void c_stop(struct seq_file *m, void *v)
76+
{
77+
}
78+
79+
static int c_show(struct seq_file *m, void *v)
80+
{
81+
unsigned long hart_id = (unsigned long)v - 1;
82+
struct device_node *node = of_get_cpu_node(hart_id, NULL);
83+
const char *compat, *isa, *mmu;
84+
85+
seq_printf(m, "hart\t: %lu\n", hart_id);
86+
if (!of_property_read_string(node, "riscv,isa", &isa)
87+
&& isa[0] == 'r'
88+
&& isa[1] == 'v')
89+
seq_printf(m, "isa\t: %s\n", isa);
90+
if (!of_property_read_string(node, "mmu-type", &mmu)
91+
&& !strncmp(mmu, "riscv,", 6))
92+
seq_printf(m, "mmu\t: %s\n", mmu+6);
93+
if (!of_property_read_string(node, "compatible", &compat)
94+
&& strcmp(compat, "riscv"))
95+
seq_printf(m, "uarch\t: %s\n", compat);
96+
seq_puts(m, "\n");
97+
98+
return 0;
99+
}
100+
101+
const struct seq_operations cpuinfo_op = {
102+
.start = c_start,
103+
.next = c_next,
104+
.stop = c_stop,
105+
.show = c_show
106+
};
107+
108+
#endif /* CONFIG_PROC_FS */

0 commit comments

Comments
 (0)