xref: /haiku/src/system/boot/arch/arm/arch_cpu.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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 	TRACE(("%s: implementor=0x%x('%c'), arch=%d, variant=0x%x, part=0x%x, revision=0x%x\n",
85 		__func__, implementor, implementor, arch, variant, part, revision));
86 
87 	return (arch < ARCH_ARM_v5) ? B_ERROR : B_OK;
88 }
89 
90 
91 extern "C" status_t
92 boot_arch_cpu_init(void)
93 {
94 	status_t err = check_cpu_features();
95 	if (err != B_OK) {
96 		panic("Retire your old Acorn and get something modern to boot!\n");
97 		return err;
98 	}
99 
100 	return B_OK;
101 }
102 
103 
104 extern "C" void
105 arch_ucode_load(BootVolume& volume)
106 {
107 	// NOP on arm currently
108 }
109 
110 
111 extern "C" bigtime_t
112 system_time()
113 {
114 	#warning Implement system_time in ARM bootloader!
115 	return 0;
116 }
117 
118 
119 extern "C" void
120 spin(bigtime_t microseconds)
121 {
122 	#warning Implment spin in ARM bootloader!
123 	//bigtime_t time = system_time();
124 	//while ((system_time() - time) < microseconds)
125 	//	asm volatile ("nop;");
126 }
127