1/*
2 * Copyright 2019, Adrien Destugues, pulkomandy@pulkomandy.tk.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <KernelExport.h>
8
9#include <arch/cpu.h>
10#include <boot/kernel_args.h>
11#include <vm/VMAddressSpace.h>
12#include <commpage.h>
13#include <elf.h>
14#include <Htif.h>
15#include <platform/sbi/sbi_syscalls.h>
16
17#include <algorithm>
18
19
20extern "C" void SVec();
21
22extern uint32 gPlatform;
23
24
25status_t
26arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu)
27{
28	// dprintf("arch_cpu_preboot_init_percpu(%" B_PRId32 ")\n", curr_cpu);
29	return B_OK;
30}
31
32
33status_t
34arch_cpu_init_percpu(kernel_args *args, int curr_cpu)
35{
36	SetStvec((uint64)SVec);
37	SstatusReg sstatus{.val = Sstatus()};
38	sstatus.ie = 0;
39	sstatus.fs = extStatusInitial; // enable FPU
40	sstatus.xs = extStatusOff;
41	SetSstatus(sstatus.val);
42	SetBitsSie((1 << sTimerInt) | (1 << sSoftInt) | (1 << sExternInt));
43
44	return B_OK;
45}
46
47
48status_t
49arch_cpu_init(kernel_args *args)
50{
51	for (uint32 curCpu = 0; curCpu < args->num_cpus; curCpu++) {
52		cpu_ent* cpu = &gCPU[curCpu];
53
54		cpu->arch.hartId = args->arch_args.hartIds[curCpu];
55
56		cpu->topology_id[CPU_TOPOLOGY_PACKAGE] = 0;
57		cpu->topology_id[CPU_TOPOLOGY_CORE] = curCpu;
58		cpu->topology_id[CPU_TOPOLOGY_SMT] = 0;
59
60		for (unsigned int i = 0; i < CPU_MAX_CACHE_LEVEL; i++)
61			cpu->cache_id[i] = -1;
62	}
63
64	uint64 conversionFactor
65		= (1LL << 32) * 1000000LL / args->arch_args.timerFrequency;
66
67	__riscv64_setup_system_time(conversionFactor);
68
69	return B_OK;
70}
71
72
73status_t
74arch_cpu_init_post_vm(kernel_args *args)
75{
76	// Set address space ownership to currently running threads
77	for (uint32 i = 0; i < args->num_cpus; i++) {
78		VMAddressSpace::Kernel()->Get();
79	}
80
81	return B_OK;
82}
83
84
85status_t
86arch_cpu_init_post_modules(kernel_args *args)
87{
88	return B_OK;
89}
90
91
92void
93arch_cpu_sync_icache(void *address, size_t len)
94{
95	FenceI();
96
97	if (smp_get_num_cpus() > 1) {
98		memory_full_barrier();
99		sbi_remote_fence_i(0, -1);
100	}
101}
102
103
104void
105arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
106{
107	addr_t kernelStart = std::max<addr_t>(start, KERNEL_BASE);
108	addr_t kernelEnd   = std::min<addr_t>(end,   KERNEL_TOP);
109
110	addr_t userStart = std::max<addr_t>(start, USER_BASE);
111	addr_t userEnd   = std::min<addr_t>(end,   USER_TOP);
112
113	if (kernelStart <= kernelEnd) {
114		int64 numPages = kernelStart / B_PAGE_SIZE - kernelEnd / B_PAGE_SIZE;
115		while (numPages-- >= 0) {
116			FlushTlbPage(start);
117			start += B_PAGE_SIZE;
118		}
119	}
120
121	if (userStart <= userEnd) {
122		int64 numPages = userStart / B_PAGE_SIZE - userEnd / B_PAGE_SIZE;
123		while (numPages-- >= 0) {
124			FlushTlbPageAsid(start, 0);
125			start += B_PAGE_SIZE;
126		}
127	}
128}
129
130
131void
132arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
133{
134	for (int i = 0; i < num_pages; i++) {
135		addr_t page = pages[i];
136		if (IS_KERNEL_ADDRESS(page))
137			FlushTlbPage(page);
138		else
139			FlushTlbPageAsid(page, 0);
140	}
141}
142
143
144void
145arch_cpu_global_TLB_invalidate(void)
146{
147	FlushTlbAll();
148}
149
150
151void
152arch_cpu_user_TLB_invalidate(void)
153{
154	FlushTlbAllAsid(0);
155}
156
157
158status_t
159arch_cpu_shutdown(bool reboot)
160{
161	if (gPlatform == kPlatformSbi) {
162		sbi_system_reset(
163			reboot ? SBI_RESET_TYPE_COLD_REBOOT : SBI_RESET_TYPE_SHUTDOWN,
164			SBI_RESET_REASON_NONE);
165	}
166
167	HtifShutdown();
168	return B_ERROR;
169}
170