xref: /haiku/src/system/boot/arch/arm/arch_cpu.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
1 /*
2  * Copyright 2012-2020, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ithamar R. Adema <ithamar@upgrade-android.com>
7  */
8 
9 #include <OS.h>
10 #include <boot/platform.h>
11 #include <boot/stdio.h>
12 #include <boot/kernel_args.h>
13 #include <boot/stage2.h>
14 #include <arch/cpu.h>
15 #include <arch_kernel.h>
16 #include <arch_system_info.h>
17 #include <string.h>
18 
19 
20 #define TRACE_CPU
21 #ifdef TRACE_CPU
22 #	define TRACE(x) dprintf x
23 #else
24 #	define TRACE(x) ;
25 #endif
26 
27 
28 /*! Detect ARM core version and features.
29     Please note the fact that ARM7 and ARMv7 are two different things ;)
30     ARMx is a specific ARM CPU core instance, while ARMvX refers to the
31     ARM architecture specification version....
32 
33     Most of the architecture versions we're detecting here we will probably
34     never run on, just included for completeness sake... ARMv5 and up are
35     the likely ones for us to support (as they all have some kind of MMU).
36 */
37 static status_t
38 check_cpu_features()
39 {
40 	uint32 result = 0;
41 	int arch = 0;
42 	int variant = 0;
43 	int part = 0;
44 	int revision = 0;
45 	int implementor = 0;
46 
47 	asm volatile("MRC p15, 0, %[c1out], c0, c0, 0":[c1out] "=r" (result));
48 
49 	implementor = (result >> 24) & 0xff;
50 
51 	switch ((result >> 12) & 0xf) {
52 		case 0:	/* early ARMv3 or even older */
53 			arch = ARCH_ARM_PRE_ARM7;
54 			break;
55 
56 		case 7:	/* ARM7 processor */
57 			arch = (result & (1 << 23)) ? ARCH_ARM_v4T : ARCH_ARM_v3;
58 			variant = (result >> 16) & 0x7f;
59 			part = (result >> 4) & 0xfff;
60 			revision = result & 0xf;
61 			break;
62 
63 		default:
64 			revision = result & 0xf;
65 			part = (result >> 4) & 0xfff;
66 			switch((result >> 16) & 0xf) {
67 				case 1: arch = ARCH_ARM_v4; break;
68 				case 2: arch = ARCH_ARM_v4T; break;
69 				case 3: arch = ARCH_ARM_v5; break;
70 				case 4: arch = ARCH_ARM_v5T; break;
71 				case 5: arch = ARCH_ARM_v5TE; break;
72 				case 6: arch = ARCH_ARM_v5TEJ; break;
73 				case 7: arch = ARCH_ARM_v6; break;
74 				case 0xf:
75 					arch = ARCH_ARM_v7;
76 					// TODO ... or later. We apparently need to scan the
77 					// CPUID registers to decide.
78 					break;
79 			}
80 			variant = (result >> 20) & 0xf;
81 			break;
82 	}
83 
84 	// We could check for VFP/NEON support here, but for the moment we only
85 	// really target ARM CPU's with VFP/NEON built-in (cortex-a7+)
86 	if (arch >= ARCH_ARM_v7)
87 	{
88 		// Enable VFP/NEON. We HAVE to do this before the trace call below,
89 		// which is the first time we call vprintf. Otherwise, it will crash
90 		// when trying to push floating point registers on the stack.
91 		asm volatile(
92 		"	MRC p15, #0, r1, c1, c0, #2\n" // r1 = Access Control Register
93 		"	ORR r1, r1, #(0xf << 20)\n" // enable full access for p10,11
94 		"	MCR p15, #0, r1, c1, c0, #2\n" // Access Control Register = r1
95 		"	MOV r1, #0\n"
96 		"	MCR p15, #0, r1, c7, c5, #4\n" // flush prefetch buffer because of
97 			// FMXR below and CP 10 & 11 were only just enabled
98 		"	MOV r0,#0x40000000	\n" // Enable VFP itself
99 		"	FMXR FPEXC, r0" //FPEXC = r0
100 		:::"r0", "r1");
101 	}
102 
103 
104 	TRACE(("%s: implementor=0x%x('%c'), arch=%d, variant=0x%x, part=0x%x, revision=0x%x\n",
105 		__func__, implementor, implementor, arch, variant, part, revision));
106 
107 	return (arch < ARCH_ARM_v5) ? B_ERROR : B_OK;
108 }
109 
110 
111 extern "C" status_t
112 boot_arch_cpu_init(void)
113 {
114 	status_t err = check_cpu_features();
115 	if (err != B_OK) {
116 		panic("Retire your old Acorn and get something modern to boot!\n");
117 		return err;
118 	}
119 
120 	return B_OK;
121 }
122 
123 
124 extern "C" void
125 arch_ucode_load(BootVolume& volume)
126 {
127 	// NOP on arm currently
128 }
129 
130 
131 extern "C" bigtime_t
132 system_time()
133 {
134 	#warning Implement system_time in ARM bootloader!
135 	return 0;
136 }
137 
138 
139 extern "C" void
140 spin(bigtime_t microseconds)
141 {
142 	#warning Implment spin in ARM bootloader!
143 	//bigtime_t time = system_time();
144 	//while ((system_time() - time) < microseconds)
145 	//	asm volatile ("nop;");
146 }
147