fix indentation some more
[rpi-open-firmware.git] / arm_chainloader / loader.cc
1 /*=============================================================================
2 Copyright (C) 2016 Kristina Brooks
3 All rights reserved.
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 FILE DESCRIPTION
16 Second stage bootloader.
17
18 =============================================================================*/
19
20 #include <drivers/fatfs/ff.h>
21 #include <chainloader.h>
22 #include <drivers/mailbox.hpp>
23 #include <drivers/block_device.hpp>
24 #include <libfdt.h>
25 #include <memory_map.h>
26
27 #define logf(fmt, ...) printf("[LDR:%s]: " fmt, __FUNCTION__, ##__VA_ARGS__);
28
29 FATFS g_BootVolumeFs;
30
31 #define ROOT_VOLUME_PREFIX "0:"
32 #define DTB_LOAD_ADDRESS 0x20000000
33 #define KERNEL_LOAD_ADDRESS 0x2000000
34
35 extern "C" {
36 void boot_linux(int zero, int machineID, void* dtb, void* kernel);
37 }
38
39 static_assert((MEM_USABLE_START+0x800000) < KERNEL_LOAD_ADDRESS,
40 "memory layout would not allow for kernel to be loaded at KERNEL_LOAD_ADDRESS, please check memory_map.h");
41
42 struct LoaderImpl {
43 inline bool file_exists(const char* path) {
44 return f_stat(path, NULL) == FR_OK;
45 }
46
47 bool read_file(const char* path, uint8_t*& dest, size_t& size, bool should_alloc = true) {
48 /* ensure file exists first */
49 if(!file_exists(path))
50 return false;
51
52 /* read entire file into buffer */
53 FIL fp;
54 f_open(&fp, path, FA_READ);
55
56 unsigned int len = f_size(&fp);
57
58 if(should_alloc) {
59 uint8_t* buffer = new uint8_t[len];
60 dest = buffer;
61 }
62
63 logf("%s: reading %d bytes to 0x%X (allocated=%d) ...\n", path, len, (unsigned int)dest, should_alloc);
64
65 size = len;
66
67 f_read(&fp, dest, len, &len);
68 f_close(&fp);
69
70 return true;
71 }
72
73 inline bool read_file(const char* path, uint8_t*& dest, bool should_alloc = true) {
74 size_t size;
75 return read_file(path, dest, size, should_alloc);
76 }
77
78 uint8_t* load_fdt(const char* filename, uint8_t* cmdline) {
79 /* read device tree blob */
80 uint8_t* fdt = reinterpret_cast<uint8_t*>(DTB_LOAD_ADDRESS);
81 size_t sz;
82
83 if(!read_file(filename, fdt, sz, false)) {
84 panic("error reading fdt");
85 }
86
87 void* v_fdt = reinterpret_cast<void*>(fdt);
88
89 int res;
90
91 if ((res = fdt_check_header(v_fdt)) != 0) {
92 panic("fdt blob invalid, fdt_check_header returned %d", res);
93 }
94
95 /* pass in command line args */
96 res = fdt_open_into(v_fdt, v_fdt, sz + 4096);
97 logf("fdt_open_into(): %d\n", res);
98
99 int node = fdt_path_offset(v_fdt, "/chosen");
100 logf("/chosen node: %d\n", node);
101 if (node < 0)
102 return NULL;
103 res = fdt_setprop(v_fdt, node, "bootargs", cmdline, strlen((char*) cmdline) + 1);
104 logf("fdt_setprop(): %d\n", res);
105
106 /* pass in a memory map, skipping first meg for bootcode */
107 int memory = fdt_path_offset(v_fdt, "/memory");
108 if(memory < 0)
109 return NULL;
110
111 /* start the memory map at 1M/16 and grow continuous for 256M
112 * TODO: does this disrupt I/O? */
113
114 char dtype[] = "memory";
115 //uint32_t memmap[] = { 0x10000, 0x20000000 };
116 //uint8_t memmap[] = { 0x00, 0x00, 0x01, 0x00,
117 // 0x00, 0x00, 0x00, 0x20 };
118 uint8_t memmap[] = { 0x00, 0x00, 0x01, 0x00,
119 0x30, 0x00, 0x00, 0x00 };
120
121 res = fdt_setprop(v_fdt, memory, "reg", (void*) memmap, sizeof(memmap));
122 //res = fdt_setprop(v_fdt, memory, "device_type", dtype, strlen(dtype) + 1);
123 logf("fdt_setprop(): %d\n", res);
124
125 logf("valid fdt loaded at 0x%X\n", (unsigned int)fdt);
126
127 return fdt;
128 }
129
130 void teardown_hardware() {
131 BlockDevice* bd = get_sdhost_device();
132 if (bd)
133 bd->stop();
134 }
135
136 LoaderImpl() {
137 logf("Mounting boot partitiion ...\n");
138 FRESULT r = f_mount(&g_BootVolumeFs, ROOT_VOLUME_PREFIX, 1);
139 if (r != FR_OK) {
140 panic("failed to mount boot partition, error: %d", (int)r);
141 }
142 logf("Boot partition mounted!\n");
143
144 size_t sz;
145
146 /* dump cmdline.txt for test */
147 uint8_t* cmdline;
148
149 if(!read_file("cmdline.txt", cmdline, sz)) {
150 panic("error reading cmdline");
151 }
152
153 /* nul terminate it */
154 cmdline[sz - 1] = 0;
155 logf("kernel cmdline: %s\n", cmdline);
156
157 /* load flat device tree */
158 uint8_t* fdt = load_fdt("rpi.dtb", cmdline);
159 if (!fdt) {
160 panic("fdt pointer is null");
161 }
162
163 /* after load_fdt is done with it, we don't need it anymore */
164 delete[] cmdline;
165
166 /* read the kernel -- necessarily at fixed address */
167 uint8_t* zImage = reinterpret_cast<uint8_t*>(KERNEL_LOAD_ADDRESS);
168
169 if(!read_file("zImage", zImage, sz, false)) {
170 panic("error reading zImage");
171 }
172
173 logf("zImage loaded at 0x%X\n", (unsigned int)zImage);
174
175 logf("First few of zImage.. %X%X%X%X\n", zImage[0], zImage[1], zImage[2], zImage[3]);
176
177 /* flush the cache */
178 logf("Flushing....\n")
179 for (uint8_t* i = zImage; i < zImage + sz; i += 32) {
180 __asm__ __volatile__ ("mcr p15,0,%0,c7,c10,1" : : "r" (i) : "memory");
181 }
182
183 teardown_hardware();
184
185 /* fire away */
186 logf("Jumping to the Linux kernel...\n");
187
188 /* this should never return */
189 logf("FDT loaded at %x\n", reinterpret_cast<uint32_t>(fdt));
190 logf("First few of fdt... %X%X%X%X\n", fdt[0], fdt[1], fdt[2], fdt[3]);
191 boot_linux(0, ~0, fdt, zImage);
192 }
193 };
194
195 static LoaderImpl STATIC_APP g_Loader {};
This page took 0.094625 seconds and 5 git commands to generate.