100 lines
3.2 KiB
C
100 lines
3.2 KiB
C
/**
|
|
* fdt implementation of Asagiri
|
|
* Copyright (C) 2023 Asagiri contributors
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <fdt.h>
|
|
#include <string.h>
|
|
|
|
fdt_header* fdt;
|
|
|
|
void fdt_init() {
|
|
fdt = (fdt_header*)(*(uint32_t*)0x1337);
|
|
}
|
|
|
|
fdt_prop fdt_get_prop(uint32_t* addr) {
|
|
return (fdt_prop){
|
|
SWAP_UINT32(*addr),
|
|
SWAP_UINT32(*(addr+1)),
|
|
addr+2
|
|
};
|
|
}
|
|
|
|
uint32_t* fdt_get_addr(const char* path) {
|
|
const char* fdt_strings = (uint32_t)fdt + SWAP_UINT32(fdt->off_dt_strings);
|
|
uint32_t* fdt_struct = (uint32_t)fdt + SWAP_UINT32(fdt->off_dt_struct);
|
|
const uint32_t struct_size = SWAP_UINT32(fdt->size_dt_struct);
|
|
|
|
uint32_t* struct_ptr = fdt_struct;
|
|
uint32_t name_length = 0;
|
|
uint32_t prop_length = 0;
|
|
uint32_t prop_name_off = 0;
|
|
uint32_t* lastaddr = 0;
|
|
|
|
char path_copy[strlen(path)+1];
|
|
strcpy(path_copy, path);
|
|
char* name = strtok(path_copy, "/");
|
|
|
|
while(name && struct_ptr < fdt_struct + struct_size) {
|
|
// Read token
|
|
const uint32_t token = SWAP_UINT32(*struct_ptr);
|
|
switch(token) {
|
|
// The beginning node is followed immediately by its name
|
|
case FDT_BEGIN_NODE:
|
|
// Advance pointer
|
|
struct_ptr++;
|
|
|
|
// check if we are in the token we want
|
|
if(!strcmp((char*)struct_ptr, name)) {
|
|
name = strtok(0, "/");
|
|
lastaddr = struct_ptr;
|
|
}
|
|
|
|
// Calculate the size of the node name
|
|
name_length = strlen((char*)struct_ptr);
|
|
// Advance pointer by size of node name aligned to 4 bytes
|
|
struct_ptr += name_length / 4;
|
|
break;
|
|
|
|
// Property
|
|
case FDT_PROP:
|
|
// Advance pointer
|
|
prop_length = *++struct_ptr;
|
|
prop_name_off = *++struct_ptr;
|
|
|
|
// check if we are in the token we want
|
|
if(!strcmp(fdt_strings + SWAP_UINT32(prop_name_off), name)) {
|
|
return struct_ptr-1;
|
|
}
|
|
// Advance pointer
|
|
struct_ptr += SWAP_UINT32(prop_length) / 4;
|
|
break;
|
|
|
|
// End is followed immediately by next token
|
|
case FDT_END_NODE:
|
|
case FDT_NOP:
|
|
break;
|
|
|
|
// There can be only one FDT_END which marks the
|
|
// end of FDT
|
|
case FDT_END:
|
|
return 0;
|
|
}
|
|
// Advance pointer
|
|
struct_ptr++;
|
|
}
|
|
return lastaddr;
|
|
} |