/* * Copyright 2019-2021 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Alexander von Gluck IV */ #include #include #include #include #include extern "C" { #include } #include "dtb.h" uint32 gBootHart = 0; static uint64 sTimerFrequency = 10000000; static addr_range sPlic = {0}; static addr_range sClint = {0}; void arch_handle_fdt(const void* fdt, int node) { const char* deviceType = (const char*)fdt_getprop(fdt, node, "device_type", NULL); const char* name = fdt_get_name(fdt, node, NULL); if (strcmp(name, "chosen") == 0) { if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "boot-hartid", NULL)) gBootHart = fdt32_to_cpu(*prop); } else if (strcmp(name, "cpus") == 0) { if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "timebase-frequency", NULL)) sTimerFrequency = fdt32_to_cpu(*prop); } if (deviceType != NULL) { if (strcmp(deviceType, "cpu") == 0) { // TODO: improve incompatible CPU detection if (!(fdt_getprop(fdt, node, "mmu-type", NULL) != NULL)) return; platform_cpu_info* info; arch_smp_register_cpu(&info); if (info == NULL) return; info->id = fdt32_to_cpu(*(uint32*)fdt_getprop(fdt, node, "reg", NULL)); dprintf("cpu\n"); dprintf(" id: %" B_PRIu32 "\n", info->id); int subNode = fdt_subnode_offset(fdt, node, "interrupt-controller"); if (subNode < 0) { dprintf(" [!] no interrupt controller\n"); } else { info->phandle = fdt_get_phandle(fdt, subNode); dprintf(" phandle: %" B_PRIu32 "\n", info->phandle); } } } int compatibleLen; const char* compatible = (const char*)fdt_getprop(fdt, node, "compatible", &compatibleLen); if (compatible == NULL) return; if (dtb_has_fdt_string(compatible, compatibleLen, "riscv,clint0")) { dtb_get_reg(fdt, node, 0, sClint); return; } if (dtb_has_fdt_string(compatible, compatibleLen, "riscv,plic0") || dtb_has_fdt_string(compatible, compatibleLen, "sifive,plic-1.0.0")) { dtb_get_reg(fdt, node, 0, sPlic); int propSize; if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts-extended", &propSize)) { dprintf("PLIC contexts\n"); uint32 contextId = 0; for (uint32 *it = prop; (uint8_t*)it - (uint8_t*)prop < propSize; it += 2) { uint32 phandle = fdt32_to_cpu(*it); uint32 interrupt = fdt32_to_cpu(*(it + 1)); if (interrupt == sExternInt) { platform_cpu_info* cpuInfo = arch_smp_find_cpu(phandle); dprintf(" context %" B_PRIu32 ": %" B_PRIu32 "\n", contextId, phandle); if (cpuInfo != NULL) { cpuInfo->plicContext = contextId; dprintf(" cpu id: %" B_PRIu32 "\n", cpuInfo->id); } } contextId++; } } return; } } void arch_dtb_set_kernel_args(void) { dprintf("bootHart: %" B_PRIu32 "\n", gBootHart); dprintf("timerFrequency: %" B_PRIu64 "\n", sTimerFrequency); gKernelArgs.arch_args.timerFrequency = sTimerFrequency; // gKernelArgs.arch_args.htif = {.start = 0x40008000, .size = 0x10}; gKernelArgs.arch_args.htif = {.start = 0, .size = 0}; gKernelArgs.arch_args.plic = sPlic; gKernelArgs.arch_args.clint = sClint; }