1/*
2 * Copyright 2007, François Revol, revol@free.fr.
3 * Distributed under the terms of the MIT License.
4 *
5 * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de.
6 * Distributed under the terms of the MIT License.
7 *
8 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
9 * Distributed under the terms of the NewOS License.
10 */
11
12
13#include <KernelExport.h>
14
15#include <arch_platform.h>
16#include <arch_thread.h>
17#include <arch/cpu.h>
18#include <boot/kernel_args.h>
19#include <commpage.h>
20#include <elf.h>
21
22extern struct m68k_cpu_ops cpu_ops_030;
23extern struct m68k_cpu_ops cpu_ops_040;
24extern struct m68k_cpu_ops cpu_ops_060;
25
26struct m68k_cpu_ops cpu_ops;
27
28int arch_cpu_type;
29int arch_fpu_type;
30int arch_mmu_type;
31int arch_platform;
32
33status_t
34arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu)
35{
36	// enable FPU
37	//ppc:set_msr(get_msr() | MSR_FP_AVAILABLE);
38
39	// The current thread must be NULL for all CPUs till we have threads.
40	// Some boot code relies on this.
41	arch_thread_set_current_thread(NULL);
42
43	return B_OK;
44}
45
46
47status_t
48arch_cpu_init_percpu(kernel_args *args, int curr_cpu)
49{
50	//detect_cpu(curr_cpu);
51
52	// we only support one anyway...
53	return 0;
54}
55
56
57status_t
58arch_cpu_init(kernel_args *args)
59{
60	arch_cpu_type = args->arch_args.cpu_type;
61	arch_fpu_type = args->arch_args.fpu_type;
62	arch_mmu_type = args->arch_args.mmu_type;
63	arch_platform = args->arch_args.platform;
64	arch_platform = args->arch_args.machine;
65
66	switch (arch_cpu_type) {
67		case 68020:
68		case 68030:
69			memcpy(&cpu_ops, &cpu_ops_030, sizeof(cpu_ops));
70			break;
71
72		case 68040:
73			memcpy(&cpu_ops, &cpu_ops_040, sizeof(cpu_ops));
74			break;
75
76#ifdef SUPPORTS_060
77		case 68060:
78			memcpy(&cpu_ops, &cpu_ops_060, sizeof(cpu_ops));
79			break;
80#endif
81		default:
82			panic("unknown cpu_type %d\n", arch_cpu_type);
83	}
84
85	return B_OK;
86}
87
88
89status_t
90arch_cpu_init_post_vm(kernel_args *args)
91{
92	return B_OK;
93}
94
95status_t
96arch_cpu_init_post_modules(kernel_args *args)
97{
98	// add the functions to the commpage image
99	image_id image = get_commpage_image();
100
101	return B_OK;
102}
103
104
105void
106arch_cpu_sync_icache(void *address, size_t len)
107{
108	cpu_ops.flush_icache((addr_t)address, len);
109}
110
111
112void
113arch_cpu_memory_read_barrier(void)
114{
115	asm volatile ("nop;" : : : "memory");
116#warning M68k: check arch_cpu_memory_read_barrier (FNOP ?)
117}
118
119
120void
121arch_cpu_memory_write_barrier(void)
122{
123	asm volatile ("nop;" : : : "memory");
124#warning M68k: check arch_cpu_memory_write_barrier (FNOP ?)
125}
126
127
128void
129arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
130{
131	int32 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE;
132	cpu_ops.flush_insn_pipeline();
133	while (num_pages-- >= 0) {
134		cpu_ops.flush_atc_addr(start);
135		cpu_ops.flush_insn_pipeline();
136		start += B_PAGE_SIZE;
137	}
138	cpu_ops.flush_insn_pipeline();
139}
140
141
142void
143arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
144{
145	int i;
146
147	cpu_ops.flush_insn_pipeline();
148	for (i = 0; i < num_pages; i++) {
149		cpu_ops.flush_atc_addr(pages[i]);
150		cpu_ops.flush_insn_pipeline();
151	}
152	cpu_ops.flush_insn_pipeline();
153}
154
155
156void
157arch_cpu_global_TLB_invalidate(void)
158{
159	cpu_ops.flush_insn_pipeline();
160	cpu_ops.flush_atc_all();
161	cpu_ops.flush_insn_pipeline();
162}
163
164
165void
166arch_cpu_user_TLB_invalidate(void)
167{
168	cpu_ops.flush_insn_pipeline();
169	cpu_ops.flush_atc_user();
170	cpu_ops.flush_insn_pipeline();
171}
172
173
174status_t
175arch_cpu_shutdown(bool reboot)
176{
177	M68KPlatform::Default()->ShutDown(reboot);
178	return B_ERROR;
179}
180
181
182// The purpose of this function is to trick the compiler. When setting the
183// page_handler to a label that is obviously (to the compiler) never used,
184// it may reorganize the control flow, so that the labeled part is optimized
185// away.
186// By invoking the function like this
187//
188//	if (m68k_set_fault_handler(faultHandler, (addr_t)&&error))
189//		goto error;
190//
191// the compiler has to keep the labeled code, since it can't guess the return
192// value of this (non-inlinable) function. At least in my tests it worked that
193// way, and I hope it will continue to work like this in the future.
194//
195bool
196m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler)
197{
198// TODO: This doesn't work correctly with gcc 4 anymore!
199	*handlerLocation = handler;
200	return false;
201}
202