146 lines
4.6 KiB
C
146 lines
4.6 KiB
C
/* SPDX-License-Identifier: AGPL-3.0-or-later */
|
|
/* Copyright (C) 2026 David (Corey) Herrera */
|
|
/**
|
|
* @file ft_tt_program_directory.c
|
|
* @brief Implementation of the on-disk program loader for the Phase 2 follow-up tests.
|
|
*
|
|
* @status Runs on the p150a test card.
|
|
* @issues None
|
|
* @todo None
|
|
*/
|
|
|
|
#ifndef _POSIX_C_SOURCE
|
|
#define _POSIX_C_SOURCE 200809L
|
|
#endif
|
|
|
|
#include "ft_tt_program_directory.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "ft_tt_device.h"
|
|
|
|
/** Kernel ELF names build_tensix_program.sh writes, indexed by FT_TT_PROC_*. */
|
|
static const char *const k_kernel_file_names[FT_TT_PROC_COUNT] = {
|
|
"brisc.elf", "ncrisc.elf", "trisc0.elf", "trisc1.elf", "trisc2.elf"
|
|
};
|
|
|
|
/** Read a whole file into a fresh buffer. */
|
|
static int read_whole_file(const char *path, unsigned char **out_data, size_t *out_size)
|
|
{
|
|
FILE *file = fopen(path, "rb");
|
|
unsigned char *buffer = NULL;
|
|
long size;
|
|
|
|
if (!file) {
|
|
ft_tt_log_error("program dir: cannot open %s", path);
|
|
return FT_TT_EIO;
|
|
}
|
|
if (fseek(file, 0, SEEK_END) != 0 || (size = ftell(file)) < 0 ||
|
|
fseek(file, 0, SEEK_SET) != 0) {
|
|
fclose(file);
|
|
return FT_TT_EIO;
|
|
}
|
|
buffer = malloc((size_t)size);
|
|
if (!buffer) {
|
|
fclose(file);
|
|
return FT_TT_ENOMEM;
|
|
}
|
|
if (fread(buffer, 1, (size_t)size, file) != (size_t)size) {
|
|
ft_tt_log_error("program dir: short read on %s", path);
|
|
free(buffer);
|
|
fclose(file);
|
|
return FT_TT_EIO;
|
|
}
|
|
fclose(file);
|
|
*out_data = buffer;
|
|
*out_size = (size_t)size;
|
|
return FT_TT_OK;
|
|
}
|
|
|
|
/** Copy the `.src` sidecar's first line into `out`, or the ELF name if there is none. */
|
|
static void read_source_name(const char *directory, unsigned processor, char *out, size_t out_bytes)
|
|
{
|
|
char path[512];
|
|
FILE *file;
|
|
size_t length;
|
|
|
|
snprintf(out, out_bytes, "%s", k_kernel_file_names[processor]);
|
|
if (snprintf(path, sizeof(path), "%s/%s.src", directory,
|
|
k_kernel_file_names[processor]) >= (int)sizeof(path))
|
|
return;
|
|
file = fopen(path, "r");
|
|
if (!file)
|
|
return;
|
|
if (fgets(out, (int)out_bytes, file)) {
|
|
length = strlen(out);
|
|
while (length > 0u && (out[length - 1u] == '\n' || out[length - 1u] == '\r'))
|
|
out[--length] = '\0';
|
|
}
|
|
fclose(file);
|
|
}
|
|
|
|
int ft_tt_program_directory_load(const char *directory, uint32_t processor_mask,
|
|
ft_tt_program_directory *out_loaded)
|
|
{
|
|
unsigned processor;
|
|
unsigned image_count = 0;
|
|
const char *last_separator;
|
|
|
|
if (!directory || !out_loaded || processor_mask == 0u ||
|
|
processor_mask >= (1u << FT_TT_PROC_COUNT))
|
|
return FT_TT_EINVAL;
|
|
memset(out_loaded, 0, sizeof(*out_loaded));
|
|
|
|
last_separator = strrchr(directory, '/');
|
|
snprintf(out_loaded->name, sizeof(out_loaded->name), "%s",
|
|
last_separator ? last_separator + 1 : directory);
|
|
|
|
for (processor = 0; processor < FT_TT_PROC_COUNT; processor++) {
|
|
char path[512];
|
|
int rc;
|
|
|
|
if ((processor_mask & (1u << processor)) == 0u)
|
|
continue;
|
|
if (snprintf(path, sizeof(path), "%s/%s", directory,
|
|
k_kernel_file_names[processor]) >= (int)sizeof(path)) {
|
|
ft_tt_program_directory_release(out_loaded);
|
|
return FT_TT_EINVAL;
|
|
}
|
|
rc = read_whole_file(path, &out_loaded->elf_data[processor],
|
|
&out_loaded->images[image_count].elf_size);
|
|
if (rc != FT_TT_OK) {
|
|
ft_tt_program_directory_release(out_loaded);
|
|
return rc;
|
|
}
|
|
read_source_name(directory, processor, out_loaded->source_names[processor],
|
|
sizeof(out_loaded->source_names[processor]));
|
|
|
|
out_loaded->images[image_count].processor = processor;
|
|
out_loaded->images[image_count].elf_data = out_loaded->elf_data[processor];
|
|
out_loaded->images[image_count].source_name = out_loaded->source_names[processor];
|
|
image_count++;
|
|
}
|
|
|
|
out_loaded->program.name = out_loaded->name;
|
|
out_loaded->program.toolchain = "on-disk build";
|
|
out_loaded->program.compile_time_args = "see the build log beside the directory";
|
|
out_loaded->program.images = out_loaded->images;
|
|
out_loaded->program.image_count = image_count;
|
|
return FT_TT_OK;
|
|
}
|
|
|
|
void ft_tt_program_directory_release(ft_tt_program_directory *loaded)
|
|
{
|
|
unsigned processor;
|
|
|
|
if (!loaded)
|
|
return;
|
|
for (processor = 0; processor < FT_TT_PROC_COUNT; processor++) {
|
|
free(loaded->elf_data[processor]);
|
|
loaded->elf_data[processor] = NULL;
|
|
}
|
|
memset(&loaded->program, 0, sizeof(loaded->program));
|
|
}
|