AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
fdt.c
Go to the documentation of this file.
1
16
17#include <core/system.h>
18#include <core/string.h>
19#include <boot/boot.h>
20#include <mm/mm.h>
21
22/* The FDT's magic number, and its structure's tokens. */
23#define FDT_MAGIC 0xD00DFEED
24#define FDT_BEGIN_NODE 1
25#define FDT_END_NODE 2
26#define FDT_PROP 3
27#define FDT_NOP 4
28#define FDT_END 9
29
43
45static inline uint32_t be32(const void *p)
46{
47 const uint8_t *b = p;
48 return (uint32_t) b[0] << 24 | (uint32_t) b[1] << 16 | (uint32_t) b[2] << 8 | b[3];
49}
50
52static uint64_t cells(const void *p, int cells)
53{
54 uint64_t v = 0;
55
56 for (int i = 0; i < cells; ++i)
57 v = v << 32 | be32((const uint8_t *) p + 4 * i);
58
59 return v;
60}
61
62/* The most memory regions that are kept. */
63#define MMAP_MAX 16
64
65/* What the devicetree says, in the kernel's form. */
66static struct boot boot;
68static module_t modules[1];
69static char cmdline[1024];
70
79{
80 const struct fdt_header *h = PHYS2VIRT(dtb);
81
83 boot.mmap = mmap;
85
86 if (be32(&h->magic) != FDT_MAGIC) {
87 printk("fdt: no devicetree at %p\n", (void *) dtb);
88 return &boot;
89 }
90
91 const uint8_t *structs = (const uint8_t *) h + be32(&h->off_dt_struct);
92 const char *strings = (const char *) h + be32(&h->off_dt_strings);
93
94 int addr_cells = 2, size_cells = 2, depth = 0;
95 int in_memory = 0, in_chosen = 0;
96 uint64_t initrd_start = 0, initrd_end = 0;
97
98 for (const uint8_t *p = structs;;) {
99 uint32_t token = be32(p);
100 p += 4;
101
102 if (token == FDT_BEGIN_NODE) {
103 const char *name = (const char *) p;
104 size_t len = strlen(name);
105 p += (len + 1 + 3) & ~3;
106 ++depth;
107
108 /* /memory or /memory@40000000, and /chosen */
109 in_memory = depth == 2 && !strncmp(name, "memory", 6) && (name[6] == '@' || !name[6]);
110 in_chosen = depth == 2 && !strcmp(name, "chosen");
111 } else if (token == FDT_END_NODE) {
112 --depth;
113 in_memory = in_chosen = 0;
114 } else if (token == FDT_PROP) {
115 uint32_t len = be32(p), nameoff = be32(p + 4);
116 const uint8_t *val = p + 8;
117 const char *name = strings + nameoff;
118 p += 8 + ((len + 3) & ~3);
119
120 if (depth == 1 && !strcmp(name, "#address-cells"))
121 addr_cells = be32(val);
122 else if (depth == 1 && !strcmp(name, "#size-cells"))
123 size_cells = be32(val);
124 else if (in_memory && !strcmp(name, "reg")) {
125 size_t entry = 4 * (addr_cells + size_cells);
126
127 for (size_t off = 0; off + entry <= len && boot.mmap_count < MMAP_MAX; off += entry) {
128 uint64_t start = cells(val + off, addr_cells);
129 uint64_t size = cells(val + off + 4 * addr_cells, size_cells);
130
131 mmap[boot.mmap_count++] = (mmap_t) {
132 .type = MMAP_USABLE,
133 .start = start,
134 .end = start + size,
135 };
136
137 boot.total_mem += size / 1024;
138 }
139 } else if (in_chosen && !strcmp(name, "bootargs")) {
140 size_t n = MIN(len, sizeof(cmdline) - 1);
141 memcpy(cmdline, val, n);
142 cmdline[n] = 0;
143 } else if (in_chosen && !strcmp(name, "linux,initrd-start")) {
144 initrd_start = cells(val, len / 4);
145 } else if (in_chosen && !strcmp(name, "linux,initrd-end")) {
146 initrd_end = cells(val, len / 4);
147 }
148 } else if (token == FDT_NOP) {
149 continue;
150 } else {
151 break; /* FDT_END, or a token it doesn't know */
152 }
153 }
154
155 /* the initrd is the one module, as Multiboot's first one is */
156 if (initrd_end > initrd_start) {
157 modules[0] = (module_t) {
158 .paddr = initrd_start,
159 .size = initrd_end - initrd_start,
160 .cmdline = "",
161 };
162
164 }
165
166 return &boot;
167}
struct boot * fdt_boot(uintptr_t dtb)
Reads the boot loader's devicetree into a struct boot.
Definition fdt.c:78
#define PHYS2VIRT(paddr)
Definition mm.h:26
static module_t modules[1]
Definition fdt.c:68
static mmap_t mmap[MMAP_MAX]
Definition fdt.c:67
#define FDT_PROP
Definition fdt.c:26
#define MMAP_MAX
Definition fdt.c:63
#define FDT_MAGIC
Definition fdt.c:23
#define FDT_BEGIN_NODE
Definition fdt.c:24
#define FDT_NOP
Definition fdt.c:27
#define FDT_END_NODE
Definition fdt.c:25
static uint32_t be32(const void *p)
Reads a big-endian 32-bit number.
Definition fdt.c:45
static uint64_t cells(const void *p, int cells)
Reads cells big-endian 32-bit cells at p as one number.
Definition fdt.c:52
static char cmdline[1024]
Definition fdt.c:69
@ MMAP_USABLE
Definition boot.h:23
#define MIN(a, b)
Definition system.h:11
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
Definition printk.c:249
__SIZE_TYPE__ uintptr_t
Definition stddef.h:12
unsigned int uint32_t
Definition stddef.h:22
unsigned char uint8_t
Definition stddef.h:20
unsigned long long int uint64_t
Definition stddef.h:23
Definition boot.h:35
int mmap_count
Definition boot.h:40
char * cmdline
Definition boot.h:36
module_t * modules
Definition boot.h:41
uintptr_t total_mem
Definition boot.h:37
mmap_t * mmap
Definition boot.h:42
int modules_count
Definition boot.h:39
The FDT's header (big-endian).
Definition fdt.c:31
uint32_t size_dt_strings
Definition fdt.c:40
uint32_t off_dt_strings
Definition fdt.c:35
uint32_t magic
Definition fdt.c:32
uint32_t size_dt_struct
Definition fdt.c:41
uint32_t last_comp_version
Definition fdt.c:38
uint32_t off_dt_struct
Definition fdt.c:34
uint32_t off_mem_rsvmap
Definition fdt.c:36
uint32_t version
Definition fdt.c:37
uint32_t totalsize
Definition fdt.c:33
uint32_t boot_cpuid_phys
Definition fdt.c:39
Definition boot.h:28