mirror of
https://github.com/gbowne1/ClassicOS.git
synced 2025-11-16 22:35:26 -08:00
119 lines
3.1 KiB
C
119 lines
3.1 KiB
C
#include <stdint.h>
|
|
|
|
// ELF Ident indexes
|
|
#define EI_NIDENT 16
|
|
|
|
// Program header types
|
|
#define PT_NULL 0
|
|
#define PT_LOAD 1
|
|
|
|
// ELF Header (32-bit)
|
|
typedef struct {
|
|
uint8_t e_ident[EI_NIDENT];
|
|
uint16_t e_type;
|
|
uint16_t e_machine;
|
|
uint32_t e_version;
|
|
uint32_t e_entry; // Entry point
|
|
uint32_t e_phoff; // Program header table offset
|
|
uint32_t e_shoff; // Section header table offset
|
|
uint32_t e_flags;
|
|
uint16_t e_ehsize;
|
|
uint16_t e_phentsize;
|
|
uint16_t e_phnum;
|
|
uint16_t e_shentsize;
|
|
uint16_t e_shnum;
|
|
uint16_t e_shstrndx;
|
|
} __attribute__((packed)) Elf32_Ehdr;
|
|
|
|
// Program Header (32-bit)
|
|
typedef struct {
|
|
uint32_t p_type;
|
|
uint32_t p_offset;
|
|
uint32_t p_vaddr;
|
|
uint32_t p_paddr;
|
|
uint32_t p_filesz;
|
|
uint32_t p_memsz;
|
|
uint32_t p_flags;
|
|
uint32_t p_align;
|
|
} __attribute__((packed)) Elf32_Phdr;
|
|
|
|
// Load an ELF executable into memory.
|
|
static int elf_load(const void* data, void (*load_segment)(uint8_t *vaddr, uint32_t src, uint32_t size)) {
|
|
const Elf32_Ehdr* header = (const Elf32_Ehdr*)data;
|
|
const Elf32_Phdr* ph = (const Elf32_Phdr*)((uint8_t*)data + header->e_phoff);
|
|
|
|
for (int i = 0; i < header->e_phnum; i++) {
|
|
if (ph[i].p_type != PT_LOAD)
|
|
continue;
|
|
|
|
uint32_t offset = ph[i].p_offset;
|
|
uint32_t vaddr = ph[i].p_vaddr;
|
|
uint32_t filesz = ph[i].p_filesz;
|
|
uint32_t memsz = ph[i].p_memsz;
|
|
|
|
// Copy data segment
|
|
//load_segment((uint8_t *)vaddr, offset, filesz);
|
|
load_segment((uint8_t *)vaddr, offset, filesz);
|
|
|
|
// Zero remaining BSS (if any)
|
|
if (memsz > filesz) {
|
|
uint8_t* bss_start = (uint8_t*)(vaddr + filesz);
|
|
for (uint32_t j = 0; j < memsz - filesz; j++) {
|
|
bss_start[j] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return header->e_entry;
|
|
}
|
|
|
|
#define KERN_START_SECT 5
|
|
#define MAX(a, b) ((a)>(b) ? (a) : (b))
|
|
|
|
extern void ata_lba_read(uint32_t lba, uint8_t nsect, void *addr);
|
|
extern uint8_t read_buf[];
|
|
|
|
static uint32_t
|
|
total_header_size(const Elf32_Ehdr *header) {
|
|
uint32_t phend = header->e_phoff + header->e_phentsize*header->e_phnum;
|
|
|
|
// Align to 512
|
|
return (phend + 511) & ~511;
|
|
}
|
|
|
|
static void read_sectors(uint8_t *vaddr, uint32_t offset, uint32_t size) {
|
|
// # of sectors to read
|
|
uint32_t rem_nsect = ((size + 511) & ~511) / 512;
|
|
|
|
// Current lba address, offset by the first sector already read
|
|
uint32_t lba = KERN_START_SECT + offset / 512;
|
|
|
|
// Max 255 sectors at a time
|
|
while (rem_nsect) {
|
|
uint8_t nsect = rem_nsect > 255 ? 255 : rem_nsect;
|
|
ata_lba_read(lba, nsect, vaddr);
|
|
|
|
vaddr += nsect * 512;
|
|
rem_nsect -= nsect;
|
|
lba += nsect;
|
|
}
|
|
}
|
|
|
|
void *load_kernel(void) {
|
|
// Read the first sector
|
|
ata_lba_read(KERN_START_SECT, 1, read_buf);
|
|
|
|
const Elf32_Ehdr* header = (const Elf32_Ehdr*)read_buf;
|
|
|
|
// Remaining data size, subtract the first 512B already read
|
|
uint32_t rem = total_header_size(header) - 512;
|
|
|
|
// Read the rest if necessary
|
|
if (rem)
|
|
read_sectors(read_buf+512, 512, rem);
|
|
|
|
elf_load(read_buf, read_sectors);
|
|
|
|
return (void *)header->e_entry;
|
|
}
|