source: mainline/boot/arch/sparc64/src/main.c@ d7f7a4a

Last change on this file since d7f7a4a was d7f7a4a, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 4 years ago

Replace some license headers with SPDX identifier

Headers are replaced using tools/transorm-copyright.sh only
when it can be matched verbatim with the license header used
throughout most of the codebase.

  • Property mode set to 100644
File size: 6.8 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2005 Martin Decky
3 * SPDX-FileCopyrightText: 2006 Jakub Jermar
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8#include <arch/main.h>
9#include <arch/arch.h>
10#include <arch/asm.h>
11#include <arch/ofw.h>
12#include <genarch/ofw.h>
13#include <genarch/ofw_tree.h>
14#include <halt.h>
15#include <printf.h>
16#include <memstr.h>
17#include <version.h>
18#include <macros.h>
19#include <align.h>
20#include <str.h>
21#include <errno.h>
22#include <payload.h>
23#include <kernel.h>
24
25/* The lowest ID (read from the VER register) of some US3 CPU model */
26#define FIRST_US3_CPU 0x14
27
28/* The greatest ID (read from the VER register) of some US3 CPU model */
29#define LAST_US3_CPU 0x19
30
31/* UltraSPARC IIIi processor implementation code */
32#define US_IIIi_CODE 0x15
33
34#define OBP_BIAS 0x400000
35
36#define BALLOC_MAX_SIZE 131072
37
38#define TOP2ADDR(top) (((void *) KERNEL_ADDRESS) + (top))
39
40/** UltraSPARC architecture */
41static uint8_t arch;
42
43/** UltraSPARC subarchitecture */
44static uint8_t subarch;
45
46/** Mask of the MID field inside the ICBUS_CONFIG register
47 *
48 * Shifted by MID_SHIFT bits to the right
49 *
50 */
51static uint16_t mid_mask;
52
53static bootinfo_t bootinfo;
54
55/** Detect the UltraSPARC architecture
56 *
57 * Detection is done by inspecting the property called "compatible"
58 * in the OBP root node. Currently sun4u and sun4v are supported.
59 * Set global variable "arch" to the correct value.
60 *
61 */
62static void arch_detect(void)
63{
64 phandle root = ofw_find_device("/");
65 char compatible[OFW_TREE_PROPERTY_MAX_VALUELEN];
66
67 if (ofw_get_property(root, "compatible", compatible,
68 OFW_TREE_PROPERTY_MAX_VALUELEN) <= 0) {
69 printf("Warning: Unable to determine architecture, assuming sun4u.\n");
70 arch = ARCH_SUN4U;
71 return;
72 }
73
74 if (str_cmp(compatible, "sun4v") != 0) {
75 /*
76 * As not all sun4u machines have "sun4u" in their "compatible"
77 * OBP property (e.g. Serengeti's OBP "compatible" property is
78 * "SUNW,Serengeti"), we will by default fallback to sun4u if
79 * an unknown value of the "compatible" property is encountered.
80 */
81 if (str_cmp(compatible, "sun4u") != 0)
82 printf("Warning: Unknown architecture, assuming sun4u.\n");
83 arch = ARCH_SUN4U;
84 } else
85 arch = ARCH_SUN4V;
86}
87
88/** Detect the subarchitecture (US, US3) of sun4u
89 *
90 * Set the global variables "subarch" and "mid_mask" to
91 * correct values.
92 *
93 */
94static void sun4u_subarch_detect(void)
95{
96 uint64_t ver;
97 asm volatile (
98 "rdpr %%ver, %[ver]\n"
99 : [ver] "=r" (ver)
100 );
101
102 ver = (ver << 16) >> 48;
103
104 if ((ver >= FIRST_US3_CPU) && (ver <= LAST_US3_CPU)) {
105 subarch = SUBARCH_US3;
106
107 if (ver == US_IIIi_CODE)
108 mid_mask = (1 << 5) - 1;
109 else
110 mid_mask = (1 << 10) - 1;
111
112 } else if (ver < FIRST_US3_CPU) {
113 subarch = SUBARCH_US;
114 mid_mask = (1 << 5) - 1;
115 } else {
116 printf("Warning: This CPU is not supported.");
117 subarch = SUBARCH_UNKNOWN;
118 }
119}
120
121/** Perform sun4u-specific SMP initialization.
122 *
123 */
124static void sun4u_smp(void)
125{
126#ifdef CONFIG_AP
127 printf("Checking for secondary processors ...\n");
128 ofw_cpu(mid_mask, bootinfo.physmem_start);
129#endif
130}
131
132/** Perform sun4v-specific fixups.
133 *
134 */
135static void sun4v_fixups(void)
136{
137 /*
138 * When SILO booted, the OBP had established a virtual to physical
139 * memory mapping. This mapping is not an identity since the
140 * physical memory starts at non-zero address.
141 *
142 * However, the mapping even does not map virtual address 0
143 * onto the starting address of the physical memory, but onto an
144 * address which is 0x400000 (OBP_BIAS) bytes higher.
145 *
146 * The reason is that the OBP had already used the memory just
147 * at the beginning of the physical memory. Thus that memory cannot
148 * be used by SILO (nor the bootloader).
149 *
150 * So far, we solve it by a nasty workaround:
151 *
152 * We pretend that the physical memory starts 0x400000 (OBP_BIAS)
153 * bytes further than it actually does (and hence pretend that the
154 * physical memory is 0x400000 bytes smaller). Of course, the value
155 * 0x400000 will most probably depend on the machine and OBP version
156 * (the workaround works on Simics).
157 *
158 * A proper solution would be to inspect the "available" property
159 * of the "/memory" node to find out which parts of memory
160 * are used by OBP and redesign the algorithm of copying
161 * kernel/init tasks/ramdisk from the bootable image to memory.
162 */
163 bootinfo.physmem_start += OBP_BIAS;
164 bootinfo.memmap.zones[0].start += OBP_BIAS;
165 bootinfo.memmap.zones[0].size -= OBP_BIAS;
166 bootinfo.memmap.total -= OBP_BIAS;
167}
168
169void bootstrap(void)
170{
171 version_print();
172
173 arch_detect();
174 if (arch == ARCH_SUN4U)
175 sun4u_subarch_detect();
176 else
177 subarch = SUBARCH_UNKNOWN;
178
179 bootinfo.physmem_start = ofw_get_physmem_start();
180 ofw_memmap(&bootinfo.memmap);
181
182 if (arch == ARCH_SUN4V)
183 sun4v_fixups();
184
185 void *bootinfo_pa = ofw_translate(&bootinfo);
186 void *kernel_address_pa = ofw_translate((void *) KERNEL_ADDRESS);
187 void *loader_address_pa = ofw_translate((void *) LOADER_ADDRESS);
188
189 printf("\nMemory statistics (total %" PRIu64 " MB, starting at %p)\n",
190 bootinfo.memmap.total >> 20, (void *) bootinfo.physmem_start);
191 printf(" %p|%p: boot info structure\n", &bootinfo, (void *) bootinfo_pa);
192 printf(" %p|%p: kernel entry point\n",
193 (void *) KERNEL_ADDRESS, (void *) kernel_address_pa);
194 printf(" %p|%p: loader entry point\n",
195 (void *) LOADER_ADDRESS, (void *) loader_address_pa);
196
197 /*
198 * At this point, we claim and map the physical memory that we
199 * are going to use. We should be safe in case of the virtual
200 * address space because the OpenFirmware, according to its
201 * SPARC binding, should restrict its use of virtual memory to
202 * addresses from [0xffd00000; 0xffefffff] and [0xfe000000;
203 * 0xfeffffff].
204 */
205
206 size_t sz = ALIGN_UP(payload_unpacked_size(), PAGE_SIZE);
207 ofw_claim_phys((void *) (bootinfo.physmem_start + KERNEL_ADDRESS), sz);
208 ofw_map((void *) (bootinfo.physmem_start + KERNEL_ADDRESS),
209 (void *) KERNEL_ADDRESS, sz, -1);
210
211 /* Extract components. */
212
213 // TODO: Cache-coherence callback?
214 extract_payload(&bootinfo.taskmap, (void *) KERNEL_ADDRESS,
215 (void *) KERNEL_ADDRESS + sz, KERNEL_ADDRESS, NULL);
216
217 /*
218 * Claim and map the physical memory for the boot allocator.
219 * Initialize the boot allocator.
220 */
221 printf("Setting up boot allocator ...\n");
222 void *balloc_base = (void *) KERNEL_ADDRESS + sz;
223 ofw_claim_phys(bootinfo.physmem_start + balloc_base, BALLOC_MAX_SIZE);
224 ofw_map(bootinfo.physmem_start + balloc_base, balloc_base,
225 BALLOC_MAX_SIZE, -1);
226 balloc_init(&bootinfo.ballocs, balloc_base, (uintptr_t) balloc_base,
227 BALLOC_MAX_SIZE);
228
229 printf("Setting up screens ...\n");
230 ofw_setup_screens();
231
232 printf("Canonizing OpenFirmware device tree ...\n");
233 bootinfo.ofw_root = ofw_tree_build();
234
235 if (arch == ARCH_SUN4U)
236 sun4u_smp();
237
238 uintptr_t entry = check_kernel((void *) KERNEL_ADDRESS);
239
240 printf("Booting the kernel ...\n");
241 jump_to_kernel(bootinfo.physmem_start | BSP_PROCESSOR, &bootinfo,
242 subarch, (void *) entry);
243}
Note: See TracBrowser for help on using the repository browser.