Merge pull request #303 from xvanc/trunk
riscv: implement extension detection and support for `Svpbmt`
This commit is contained in:
commit
7326a3dadf
@ -22,6 +22,7 @@
|
||||
#include <drivers/disk.h>
|
||||
#include <sys/lapic.h>
|
||||
#include <lib/readline.h>
|
||||
#include <sys/cpu.h>
|
||||
|
||||
void stage3_common(void);
|
||||
|
||||
@ -130,6 +131,18 @@ noreturn void stage3_common(void) {
|
||||
init_io_apics();
|
||||
#endif
|
||||
|
||||
#if defined (__riscv)
|
||||
#if defined (UEFI)
|
||||
RISCV_EFI_BOOT_PROTOCOL *rv_proto = get_riscv_boot_protocol();
|
||||
if (rv_proto == NULL || rv_proto->GetBootHartId(rv_proto, &bsp_hartid) != EFI_SUCCESS) {
|
||||
panic(false, "failed to get BSP's hartid");
|
||||
}
|
||||
#else
|
||||
#error riscv: only UEFI is supported
|
||||
#endif
|
||||
init_riscv();
|
||||
#endif
|
||||
|
||||
term_notready();
|
||||
|
||||
menu(true);
|
||||
|
@ -103,6 +103,75 @@ struct smbios_entry_point_64 {
|
||||
uint64_t table_address;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct madt {
|
||||
struct sdt header;
|
||||
uint32_t local_controller_addr;
|
||||
uint32_t flags;
|
||||
char madt_entries_begin[];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct madt_header {
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct madt_lapic {
|
||||
struct madt_header header;
|
||||
uint8_t acpi_processor_uid;
|
||||
uint8_t lapic_id;
|
||||
uint32_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct madt_x2apic {
|
||||
struct madt_header header;
|
||||
uint8_t reserved[2];
|
||||
uint32_t x2apic_id;
|
||||
uint32_t flags;
|
||||
uint32_t acpi_processor_uid;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct madt_io_apic {
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
uint8_t apic_id;
|
||||
uint8_t reserved;
|
||||
uint32_t address;
|
||||
uint32_t gsib;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct madt_gicc {
|
||||
struct madt_header header;
|
||||
uint8_t reserved1[2];
|
||||
uint32_t iface_no;
|
||||
uint32_t acpi_uid;
|
||||
uint32_t flags;
|
||||
uint32_t parking_ver;
|
||||
uint32_t perf_gsiv;
|
||||
uint64_t parking_addr;
|
||||
uint64_t gicc_base_addr;
|
||||
uint64_t gicv_base_addr;
|
||||
uint64_t gich_base_addr;
|
||||
uint32_t vgic_maint_gsiv;
|
||||
uint64_t gicr_base_addr;
|
||||
uint64_t mpidr;
|
||||
uint8_t power_eff_class;
|
||||
uint8_t reserved2;
|
||||
uint16_t spe_overflow_gsiv;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Reference: https://github.com/riscv-non-isa/riscv-acpi/issues/15
|
||||
struct madt_riscv_intc {
|
||||
struct madt_header header;
|
||||
uint8_t version;
|
||||
uint8_t reserved;
|
||||
uint32_t flags;
|
||||
uint64_t hartid;
|
||||
uint32_t acpi_processor_uid;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define MADT_RISCV_INTC_ENABLED ((uint32_t)1 << 0)
|
||||
#define MADT_RISCV_INTC_ONLINE_CAPABLE ((uint32_t)1 << 1)
|
||||
|
||||
uint8_t acpi_checksum(void *ptr, size_t size);
|
||||
void *acpi_get_rsdp(void);
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
bool isprint(int c);
|
||||
bool isspace(int c);
|
||||
bool isalpha(int c);
|
||||
bool isdigit(int c);
|
||||
|
||||
int toupper(int c);
|
||||
int tolower(int c);
|
||||
@ -23,6 +25,7 @@ size_t strlen(const char *);
|
||||
int strcmp(const char *, const char *);
|
||||
int strcasecmp(const char *, const char *);
|
||||
int strncmp(const char *, const char *, size_t);
|
||||
int strncasecmp(const char *, const char *, size_t);
|
||||
int inet_pton(const char *src, void *dst);
|
||||
|
||||
#endif
|
||||
|
@ -12,6 +12,14 @@ bool isspace(int c) {
|
||||
return (c >= '\t' && c <= 0xD) || c == ' ';
|
||||
}
|
||||
|
||||
bool isalpha(int c) {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
|
||||
bool isdigit(int c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
int toupper(int c) {
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
return c - 0x20;
|
||||
@ -84,6 +92,18 @@ int strncmp(const char *s1, const char *s2, size_t n) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strncasecmp(const char *s1, const char *s2, size_t n) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char c1 = s1[i], c2 = s2[i];
|
||||
if (tolower(c1) != tolower(c2))
|
||||
return c1 < c2 ? -1 : 1;
|
||||
if (!c1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t strlen(const char *str) {
|
||||
size_t len;
|
||||
|
||||
|
@ -252,6 +252,7 @@ level4:
|
||||
#define PT_FLAG_USER ((uint64_t)1 << 4)
|
||||
#define PT_FLAG_ACCESSED ((uint64_t)1 << 6)
|
||||
#define PT_FLAG_DIRTY ((uint64_t)1 << 7)
|
||||
#define PT_FLAG_PBMT_NC ((uint64_t)1 << 62)
|
||||
#define PT_PADDR_MASK ((uint64_t)0x003ffffffffffc00)
|
||||
|
||||
#define PT_FLAG_RWX (PT_FLAG_READ | PT_FLAG_WRITE | PT_FLAG_EXEC)
|
||||
@ -271,6 +272,8 @@ static uint64_t pt_to_vmm_flags_internal(pt_entry_t entry) {
|
||||
flags |= VMM_FLAG_WRITE;
|
||||
if (!(entry & PT_FLAG_EXEC))
|
||||
flags |= VMM_FLAG_NOEXEC;
|
||||
if (entry & PT_FLAG_PBMT_NC)
|
||||
flags |= VMM_FLAG_FB;
|
||||
|
||||
return flags;
|
||||
}
|
||||
@ -337,11 +340,19 @@ done:
|
||||
return 6 + max_level;
|
||||
}
|
||||
|
||||
static pt_entry_t pbmt_nc = 0;
|
||||
|
||||
pagemap_t new_pagemap(int paging_mode) {
|
||||
pagemap_t pagemap;
|
||||
pagemap.paging_mode = paging_mode;
|
||||
pagemap.max_page_size = paging_mode - 6;
|
||||
pagemap.top_level = ext_mem_alloc(PT_SIZE);
|
||||
|
||||
if (riscv_check_isa_extension("svpbmt", NULL, NULL)) {
|
||||
printv("riscv: Svpbmt extension is supported.\n");
|
||||
pbmt_nc = PT_FLAG_PBMT_NC;
|
||||
}
|
||||
|
||||
return pagemap;
|
||||
}
|
||||
|
||||
@ -357,6 +368,8 @@ void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_
|
||||
ptflags |= PT_FLAG_WRITE;
|
||||
if (!(flags & VMM_FLAG_NOEXEC))
|
||||
ptflags |= PT_FLAG_EXEC;
|
||||
if (flags & VMM_FLAG_FB)
|
||||
ptflags |= pbmt_nc;
|
||||
|
||||
// Start at the highest level.
|
||||
// The values of `enum page_size` map to the level index at which that size is mapped.
|
||||
|
@ -923,19 +923,6 @@ FEAT_END
|
||||
pagemap = build_pagemap(paging_mode, nx_available, ranges, ranges_count,
|
||||
physical_base, virtual_base, direct_map_offset);
|
||||
|
||||
#if defined (__riscv64)
|
||||
// Fetch the BSP's Hart ID before exiting boot services.
|
||||
size_t bsp_hartid;
|
||||
bool have_bsp_hartid = false;
|
||||
|
||||
RISCV_EFI_BOOT_PROTOCOL *riscv_boot_proto = get_riscv_boot_protocol();
|
||||
if (riscv_boot_proto != NULL) {
|
||||
if (riscv_boot_proto->GetBootHartId(riscv_boot_proto, &bsp_hartid) == EFI_SUCCESS) {
|
||||
have_bsp_hartid = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (UEFI)
|
||||
efi_exit_boot_services();
|
||||
#endif
|
||||
@ -962,12 +949,7 @@ FEAT_START
|
||||
pagemap, LIMINE_MAIR(fb_attr), LIMINE_TCR(tsz, pa), LIMINE_SCTLR,
|
||||
direct_map_offset);
|
||||
#elif defined (__riscv64)
|
||||
if (!have_bsp_hartid) {
|
||||
printv("smp: failed to get bsp's hart id\n");
|
||||
break;
|
||||
}
|
||||
|
||||
smp_info = init_smp(&cpu_count, bsp_hartid, pagemap, direct_map_offset);
|
||||
smp_info = init_smp(&cpu_count, pagemap, direct_map_offset);
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
@ -320,6 +320,30 @@ inline uint64_t rdtsc(void) {
|
||||
locked_read__ret; \
|
||||
})
|
||||
|
||||
extern size_t bsp_hartid;
|
||||
|
||||
struct riscv_hart {
|
||||
struct riscv_hart *next;
|
||||
const char *isa_string;
|
||||
size_t hartid;
|
||||
uint32_t acpi_uid;
|
||||
uint8_t mmu_type;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
#define RISCV_HART_COPROC ((uint8_t)1 << 0) // is a coprocessor
|
||||
#define RISCV_HART_HAS_MMU ((uint8_t)1 << 1) // `mmu_type` field is valid
|
||||
|
||||
extern struct riscv_hart *hart_list;
|
||||
|
||||
bool riscv_check_isa_extension_for(size_t hartid, const char *ext, size_t *maj, size_t *min);
|
||||
|
||||
static inline bool riscv_check_isa_extension(const char *ext, size_t *maj, size_t *min) {
|
||||
return riscv_check_isa_extension_for(bsp_hartid, ext, maj, min);
|
||||
}
|
||||
|
||||
void init_riscv(void);
|
||||
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
261
common/sys/cpu_riscv.c
Normal file
261
common/sys/cpu_riscv.c
Normal file
@ -0,0 +1,261 @@
|
||||
|
||||
#if defined(__riscv)
|
||||
|
||||
#include <lib/acpi.h>
|
||||
#include <lib/misc.h>
|
||||
#include <lib/print.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// ACPI RISC-V Hart Capabilities Table
|
||||
struct rhct {
|
||||
struct sdt header;
|
||||
uint32_t flags;
|
||||
uint64_t time_base_frequency;
|
||||
uint32_t nodes_len;
|
||||
uint32_t nodes_offset;
|
||||
uint8_t nodes[];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define RHCT_ISA_STRING 0
|
||||
#define RHCT_CMO 1
|
||||
#define RHCT_MMU 2
|
||||
#define RHCT_HART_INFO 65535
|
||||
|
||||
struct rhct_header {
|
||||
uint16_t type; // node type
|
||||
uint16_t size; // node size (bytes)
|
||||
uint16_t revision; // node revision
|
||||
} __attribute__((packed));
|
||||
|
||||
// One `struct rhct_hart_info` structure exists per hart in the system.
|
||||
// The `offsets` array points to other entries in the RHCT associated with the
|
||||
// hart.
|
||||
struct rhct_hart_info {
|
||||
struct rhct_header header;
|
||||
uint16_t offsets_len;
|
||||
uint32_t acpi_processor_uid;
|
||||
uint32_t offsets[];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct rhct_isa_string {
|
||||
struct rhct_header header;
|
||||
uint16_t isa_string_len;
|
||||
const char isa_string[];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define RISCV_MMU_TYPE_SV39 0
|
||||
#define RISCV_MMU_TYPE_SV48 1
|
||||
#define RISCV_MMU_TYPE_SV57 2
|
||||
|
||||
struct rhct_mmu {
|
||||
struct rhct_header header;
|
||||
uint8_t reserved0;
|
||||
uint8_t mmu_type;
|
||||
} __attribute__((packed));
|
||||
|
||||
size_t bsp_hartid;
|
||||
struct riscv_hart *hart_list;
|
||||
static struct riscv_hart *bsp_hart;
|
||||
|
||||
static struct riscv_hart *riscv_get_hart(size_t hartid) {
|
||||
for (struct riscv_hart *hart = hart_list; hart != NULL; hart = hart->next) {
|
||||
if (hart->hartid == hartid) {
|
||||
return hart;
|
||||
}
|
||||
}
|
||||
panic(false, "no `struct riscv_hart` for hartid %u", hartid);
|
||||
}
|
||||
|
||||
static inline struct rhct_hart_info *rhct_get_hart_info(struct rhct *rhct, uint32_t acpi_uid) {
|
||||
uint32_t offset = rhct->nodes_offset;
|
||||
for (uint32_t i = 0; i < rhct->nodes_len; i++) {
|
||||
struct rhct_hart_info *node = (void *)((uintptr_t)rhct + offset);
|
||||
if (node->header.type == RHCT_HART_INFO && node->acpi_processor_uid == acpi_uid) {
|
||||
return node;
|
||||
}
|
||||
offset += node->header.size;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void init_riscv(void) {
|
||||
struct madt *madt = acpi_get_table("APIC", 0);
|
||||
struct rhct *rhct = acpi_get_table("RHCT", 0);
|
||||
if (madt == NULL || rhct == NULL) {
|
||||
panic(false, "riscv: requires acpi");
|
||||
}
|
||||
|
||||
for (uint8_t *madt_ptr = (uint8_t *)madt->madt_entries_begin;
|
||||
(uintptr_t)madt_ptr < (uintptr_t)madt + madt->header.length; madt_ptr += *(madt_ptr + 1)) {
|
||||
if (*madt_ptr != 0x18) {
|
||||
continue;
|
||||
}
|
||||
struct madt_riscv_intc *intc = (struct madt_riscv_intc *)madt_ptr;
|
||||
|
||||
// Ignore harts we can't do anything with.
|
||||
if (!(intc->flags & MADT_RISCV_INTC_ENABLED ||
|
||||
intc->flags & MADT_RISCV_INTC_ONLINE_CAPABLE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t acpi_uid = intc->acpi_processor_uid;
|
||||
size_t hartid = intc->hartid;
|
||||
|
||||
struct rhct_hart_info *hart_info = rhct_get_hart_info(rhct, acpi_uid);
|
||||
if (hart_info == NULL) {
|
||||
panic(false, "riscv: missing rhct node for hartid %u", hartid);
|
||||
}
|
||||
|
||||
const char *isa_string = NULL;
|
||||
uint8_t mmu_type = 0;
|
||||
uint8_t flags = 0;
|
||||
|
||||
for (uint32_t i = 0; i < hart_info->offsets_len; i++) {
|
||||
const struct rhct_header *node = (void *)((uintptr_t)rhct + hart_info->offsets[i]);
|
||||
switch (node->type) {
|
||||
case RHCT_ISA_STRING:
|
||||
isa_string = ((struct rhct_isa_string *)node)->isa_string;
|
||||
break;
|
||||
case RHCT_MMU:
|
||||
mmu_type = ((struct rhct_mmu *)node)->mmu_type;
|
||||
flags |= RISCV_HART_HAS_MMU;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isa_string == NULL) {
|
||||
print("riscv: missing isa string for hartid %u, skipping.\n", hartid);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp("rv64", isa_string, 4) && strncmp("rv32", isa_string, 4)) {
|
||||
print("riscv: skipping hartid %u with invalid isa string: %s", hartid, isa_string);
|
||||
}
|
||||
|
||||
struct riscv_hart *hart = ext_mem_alloc(sizeof(struct riscv_hart));
|
||||
if (hart == NULL) {
|
||||
panic(false, "out of memory");
|
||||
}
|
||||
|
||||
hart->hartid = hartid;
|
||||
hart->acpi_uid = acpi_uid;
|
||||
hart->isa_string = isa_string;
|
||||
hart->mmu_type = mmu_type;
|
||||
hart->flags = flags;
|
||||
|
||||
hart->next = hart_list;
|
||||
hart_list = hart;
|
||||
|
||||
if (hart->hartid == bsp_hartid) {
|
||||
bsp_hart = hart;
|
||||
}
|
||||
}
|
||||
|
||||
if (bsp_hart == NULL) {
|
||||
panic(false, "riscv: missing `struct riscv_hart` for BSP");
|
||||
}
|
||||
|
||||
if (strncasecmp(bsp_hart->isa_string, "rv64i", 5)) {
|
||||
panic(false, "unsupported cpu: %s", bsp_hart->isa_string);
|
||||
}
|
||||
|
||||
for (struct riscv_hart *hart = hart_list; hart != NULL; hart = hart->next) {
|
||||
if (hart != bsp_hart && strcmp(bsp_hart->isa_string, hart->isa_string)) {
|
||||
hart->flags |= RISCV_HART_COPROC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct isa_extension {
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
uint32_t ver_maj;
|
||||
uint32_t ver_min;
|
||||
};
|
||||
|
||||
// Parse the next sequence of digit characters into an integer.
|
||||
static bool parse_number(const char **s, size_t *_n) {
|
||||
size_t n = 0;
|
||||
bool parsed = false;
|
||||
while (isdigit(**s)) {
|
||||
n *= 10;
|
||||
n += *(*s)++ - '0';
|
||||
parsed = true;
|
||||
}
|
||||
*_n = n;
|
||||
return parsed;
|
||||
}
|
||||
|
||||
// Parse the next extension from an ISA string.
|
||||
static bool parse_extension(const char **s, struct isa_extension *ext) {
|
||||
if (**s == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *name = *s;
|
||||
size_t name_len = 1;
|
||||
if (**s == 's' || **s == 'S' || **s == 'x' || **s == 'X' || **s == 'z' || **s == 'Z') {
|
||||
while (isalpha((*s)[name_len])) {
|
||||
name_len++;
|
||||
}
|
||||
}
|
||||
*s += name_len;
|
||||
|
||||
size_t maj = 0, min = 0;
|
||||
if (parse_number(s, &maj)) {
|
||||
if (**s == 'p') {
|
||||
*s += 1;
|
||||
parse_number(s, &min);
|
||||
}
|
||||
}
|
||||
|
||||
while (**s == '_') {
|
||||
*s += 1;
|
||||
}
|
||||
|
||||
if (ext) {
|
||||
ext->name = name;
|
||||
ext->name_len = name_len;
|
||||
ext->ver_maj = maj;
|
||||
ext->ver_min = min;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool extension_matches(const struct isa_extension *ext, const char *name) {
|
||||
for (size_t i = 0; i < ext->name_len; i++) {
|
||||
const char c1 = tolower(ext->name[i]);
|
||||
const char c2 = tolower(*name++);
|
||||
if (c2 == '\0' || c1 != c2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Make sure `name` is not longer.
|
||||
return *name == '\0';
|
||||
}
|
||||
|
||||
bool riscv_check_isa_extension_for(size_t hartid, const char *name, size_t *maj, size_t *min) {
|
||||
// Skip the `rv{32,64}` prefix so it's not parsed as extensions.
|
||||
const char *isa_string = riscv_get_hart(hartid)->isa_string + 4;
|
||||
|
||||
struct isa_extension ext;
|
||||
while (parse_extension(&isa_string, &ext)) {
|
||||
if (!extension_matches(&ext, name)) {
|
||||
continue;
|
||||
}
|
||||
if (maj) {
|
||||
*maj = ext.ver_maj;
|
||||
}
|
||||
if (min) {
|
||||
*min = ext.ver_min;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
@ -9,22 +9,6 @@
|
||||
#include <lib/acpi.h>
|
||||
#include <mm/pmm.h>
|
||||
|
||||
struct madt {
|
||||
struct sdt header;
|
||||
uint32_t local_controller_addr;
|
||||
uint32_t flags;
|
||||
char madt_entries_begin[];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct madt_io_apic {
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
uint8_t apic_id;
|
||||
uint8_t reserved;
|
||||
uint32_t address;
|
||||
uint32_t gsib;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct dmar {
|
||||
struct sdt header;
|
||||
uint8_t host_address_width;
|
||||
|
158
common/sys/smp.c
158
common/sys/smp.c
@ -17,66 +17,9 @@
|
||||
#include <sys/sbi.h>
|
||||
#endif
|
||||
|
||||
struct madt {
|
||||
struct sdt header;
|
||||
uint32_t local_controller_addr;
|
||||
uint32_t flags;
|
||||
char madt_entries_begin[];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct madt_header {
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct madt_lapic {
|
||||
struct madt_header header;
|
||||
uint8_t acpi_processor_uid;
|
||||
uint8_t lapic_id;
|
||||
uint32_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct madt_x2apic {
|
||||
struct madt_header header;
|
||||
uint8_t reserved[2];
|
||||
uint32_t x2apic_id;
|
||||
uint32_t flags;
|
||||
uint32_t acpi_processor_uid;
|
||||
} __attribute__((packed));
|
||||
|
||||
extern symbol smp_trampoline_start;
|
||||
extern size_t smp_trampoline_size;
|
||||
|
||||
struct madt_gicc {
|
||||
struct madt_header header;
|
||||
uint8_t reserved1[2];
|
||||
uint32_t iface_no;
|
||||
uint32_t acpi_uid;
|
||||
uint32_t flags;
|
||||
uint32_t parking_ver;
|
||||
uint32_t perf_gsiv;
|
||||
uint64_t parking_addr;
|
||||
uint64_t gicc_base_addr;
|
||||
uint64_t gicv_base_addr;
|
||||
uint64_t gich_base_addr;
|
||||
uint32_t vgic_maint_gsiv;
|
||||
uint64_t gicr_base_addr;
|
||||
uint64_t mpidr;
|
||||
uint8_t power_eff_class;
|
||||
uint8_t reserved2;
|
||||
uint16_t spe_overflow_gsiv;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Reference: https://github.com/riscv-non-isa/riscv-acpi/issues/15
|
||||
struct madt_riscv_intc {
|
||||
struct madt_header header;
|
||||
uint8_t version;
|
||||
uint8_t reserved;
|
||||
uint32_t flags;
|
||||
uint64_t hartid;
|
||||
uint32_t acpi_processor_uid;
|
||||
} __attribute__((packed));
|
||||
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
|
||||
struct trampoline_passed_info {
|
||||
@ -608,77 +551,46 @@ static bool smp_start_ap(size_t hartid, size_t satp, struct limine_smp_info *inf
|
||||
return false;
|
||||
}
|
||||
|
||||
struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||
size_t bsp_hartid,
|
||||
pagemap_t pagemap,
|
||||
uint64_t hhdm_offset) {
|
||||
// No RSDP means no ACPI.
|
||||
// Parsing the Device Tree is the only other method for detecting APs.
|
||||
if (acpi_get_rsdp() == NULL) {
|
||||
printv("smp: ACPI is required to detect APs.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct madt *madt = acpi_get_table("APIC", 0);
|
||||
if (madt == NULL)
|
||||
return NULL;
|
||||
|
||||
size_t max_cpus = 0;
|
||||
for (uint8_t *madt_ptr = (uint8_t *)madt->madt_entries_begin;
|
||||
(uintptr_t)madt_ptr < (uintptr_t)madt + madt->header.length;
|
||||
madt_ptr += *(madt_ptr + 1)) {
|
||||
switch (*madt_ptr) {
|
||||
case 0x18: {
|
||||
struct madt_riscv_intc *intc = (void *)madt_ptr;
|
||||
|
||||
// Check if we can actually try to start the AP
|
||||
if ((intc->flags & 1) ^ ((intc->flags >> 1) & 1))
|
||||
max_cpus++;
|
||||
|
||||
continue;
|
||||
}
|
||||
struct limine_smp_info *init_smp(size_t *cpu_count, pagemap_t pagemap, uint64_t hhdm_offset) {
|
||||
size_t num_cpus = 0;
|
||||
for (struct riscv_hart *hart = hart_list; hart != NULL; hart = hart->next) {
|
||||
if (!(hart->flags & RISCV_HART_COPROC)) {
|
||||
num_cpus += 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct limine_smp_info *ret = ext_mem_alloc(max_cpus * sizeof(struct limine_smp_info));
|
||||
struct limine_smp_info *ret = ext_mem_alloc(num_cpus * sizeof(struct limine_smp_info));
|
||||
if (ret == NULL) {
|
||||
panic(false, "out of memory");
|
||||
}
|
||||
|
||||
*cpu_count = 0;
|
||||
|
||||
// Try to start all APs
|
||||
for (uint8_t *madt_ptr = (uint8_t *)madt->madt_entries_begin;
|
||||
(uintptr_t)madt_ptr < (uintptr_t)madt + madt->header.length;
|
||||
madt_ptr += *(madt_ptr + 1)) {
|
||||
switch (*madt_ptr) {
|
||||
case 0x18: {
|
||||
struct madt_riscv_intc *intc = (void *)madt_ptr;
|
||||
|
||||
// Check if we can actually try to start the AP
|
||||
if (!((intc->flags & 1) ^ ((intc->flags >> 1) & 1)))
|
||||
continue;
|
||||
|
||||
struct limine_smp_info *info_struct = &ret[*cpu_count];
|
||||
|
||||
info_struct->processor_id = intc->acpi_processor_uid;
|
||||
info_struct->hartid = intc->hartid;
|
||||
|
||||
// Do not try to restart the BSP
|
||||
if (intc->hartid == bsp_hartid) {
|
||||
(*cpu_count)++;
|
||||
continue;
|
||||
}
|
||||
|
||||
printv("smp: Found candidate AP for bring-up. Hart ID: %u\n", intc->hartid);
|
||||
|
||||
// Try to start the AP.
|
||||
size_t satp = make_satp(pagemap.paging_mode, pagemap.top_level);
|
||||
if (!smp_start_ap(intc->hartid, satp, info_struct, hhdm_offset)) {
|
||||
print("smp: FAILED to bring-up AP\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
(*cpu_count)++;
|
||||
continue;
|
||||
}
|
||||
for (struct riscv_hart *hart = hart_list; hart != NULL; hart = hart->next) {
|
||||
if (hart->flags & RISCV_HART_COPROC) {
|
||||
continue;
|
||||
}
|
||||
struct limine_smp_info *info_struct = &ret[*cpu_count];
|
||||
|
||||
info_struct->hartid = hart->hartid;
|
||||
info_struct->processor_id = hart->acpi_uid;
|
||||
|
||||
// Don't try to start the BSP.
|
||||
if (hart->hartid == bsp_hartid) {
|
||||
*cpu_count += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
printv("smp: Found candidate AP for bring-up. Hart ID: %u\n", hart->hartid);
|
||||
|
||||
// Try to start the AP.
|
||||
size_t satp = make_satp(pagemap.paging_mode, pagemap.top_level);
|
||||
if (!smp_start_ap(hart->hartid, satp, info_struct, hhdm_offset)) {
|
||||
print("smp: FAILED to bring-up AP\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
(*cpu_count)++;
|
||||
continue;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -33,7 +33,6 @@ struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||
#elif defined (__riscv64)
|
||||
|
||||
struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||
uint64_t bsp_hartid,
|
||||
pagemap_t pagemap,
|
||||
uint64_t hhdm_offset);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user