xref: /haiku/src/system/boot/arch/arm/arch_cpu.cpp (revision 52f7c9389475e19fc21487b38064b4390eeb6fea)
1 /*
2  * Copyright 2012-2022, 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 <boot/arch/arm/arch_cpu.h>
10 #include <kernel/arch/arm/arch_cpu.h>
11 
12 #include <OS.h>
13 #include <boot/platform.h>
14 #include <boot/stdio.h>
15 #include <boot/kernel_args.h>
16 #include <boot/stage2.h>
17 #include <arch/cpu.h>
18 #include <arch_kernel.h>
19 #include <arch_system_info.h>
20 #include <string.h>
21 
22 
23 #define TRACE_CPU
24 #ifdef TRACE_CPU
25 #	define TRACE(x...) dprintf(x)
26 #else
27 #	define TRACE(x...) ;
28 #endif
29 
30 
31 /*! Detect ARM core version and features.
32     Please note the fact that ARM7 and ARMv7 are two different things ;)
33     ARMx is a specific ARM CPU core instance, while ARMvX refers to the
34     ARM architecture specification version....
35 
36     Most of the architecture versions we're detecting here we will probably
37     never run on, just included for completeness sake... ARMv5 and up are
38     the likely ones for us to support (as they all have some kind of MMU).
39 */
40 static status_t
41 check_cpu_features()
42 {
43 	uint32 result = 0;
44 	int arch = 0;
45 	int variant = 0;
46 	int part = 0;
47 	int revision = 0;
48 	int implementor = 0;
49 
50 	asm volatile("MRC p15, 0, %[c1out], c0, c0, 0":[c1out] "=r" (result));
51 
52 	implementor = (result >> 24) & 0xff;
53 
54 	switch ((result >> 12) & 0xf) {
55 		case 0:	/* early ARMv3 or even older */
56 			arch = ARCH_ARM_PRE_ARM7;
57 			break;
58 
59 		case 7:	/* ARM7 processor */
60 			arch = (result & (1 << 23)) ? ARCH_ARM_v4T : ARCH_ARM_v3;
61 			variant = (result >> 16) & 0x7f;
62 			part = (result >> 4) & 0xfff;
63 			revision = result & 0xf;
64 			break;
65 
66 		default:
67 			revision = result & 0xf;
68 			part = (result >> 4) & 0xfff;
69 			switch((result >> 16) & 0xf) {
70 				case 1: arch = ARCH_ARM_v4; break;
71 				case 2: arch = ARCH_ARM_v4T; break;
72 				case 3: arch = ARCH_ARM_v5; break;
73 				case 4: arch = ARCH_ARM_v5T; break;
74 				case 5: arch = ARCH_ARM_v5TE; break;
75 				case 6: arch = ARCH_ARM_v5TEJ; break;
76 				case 7: arch = ARCH_ARM_v6; break;
77 				case 0xf:
78 					arch = ARCH_ARM_v7;
79 					// TODO ... or later. We apparently need to scan the
80 					// CPUID registers to decide.
81 					break;
82 			}
83 			variant = (result >> 20) & 0xf;
84 			break;
85 	}
86 
87 	TRACE("%s: implementor=0x%x('%c'), arch=%d, variant=0x%x, part=0x%x, revision=0x%x\n",
88 		__func__, implementor, implementor, arch, variant, part, revision);
89 
90 	return (arch < ARCH_ARM_v5) ? B_ERROR : B_OK;
91 }
92 
93 
94 status_t
95 boot_arch_cpu_init(void)
96 {
97 	status_t err = check_cpu_features();
98 	if (err != B_OK) {
99 		panic("Retire your old Acorn and get something modern to boot!\n");
100 		return err;
101 	}
102 
103 	return B_OK;
104 }
105 
106 
107 void
108 arch_ucode_load(BootVolume& volume)
109 {
110 	// NOP on arm currently
111 }
112