Remove everything

This commit is contained in:
Mark 2019-10-04 16:23:18 +03:00
parent d0c709f772
commit 71eeb5d282
109 changed files with 64 additions and 9658 deletions

View File

@ -1,8 +0,0 @@
#pragma once
#include <stdint.h>
typedef struct hpet acpi_hpet_t;
//extern acpi_hpet_t *volatile hpet;
void acpi_hpet_set_base(uintptr_t v);
int acpi_hpet_init(void);

View File

@ -1,116 +0,0 @@
#pragma once
#include <stdint.h>
struct acpi_gas {
char space_id;
char reg_bit_width;
char reg_bit_offset;
char res;
uint64_t pointer;
} __attribute__((packed));
struct acpi_rsdp {
char signature[8];
char checksum;
char oemid[6];
char rev;
uint32_t rsdt_addr;
};
struct acpi_rsdp_extended {
struct acpi_rsdp rsdp;
uint32_t length;
uint64_t xsdt_addr;
char checksum2;
char res[3];
};
struct acpi_sdt_header {
char signature[4];
uint32_t length;
char rev;
char checksum;
char oemid[6];
char oemtableid[8];
uint32_t oemrev;
uint32_t creatorid;
uint32_t creatorrev;
};
struct acpi_rsdt {
struct acpi_sdt_header header;
uint32_t entries[1];
};
struct acpi_xsdt {
struct acpi_sdt_header header;
uint64_t entries[1];
};
struct acpi_fadt {
struct acpi_sdt_header header;
uint32_t firmware_ctrl;
uint32_t dsdt;
char res0;
char preferred_pm_profile;
uint16_t sci_int;
uint32_t smi_cmd;
char acpi_enable;
char acpi_disable;
char s4bios_req;
char pstate_cnt;
uint32_t pm1a_evt_blk;
uint32_t pm1b_evt_blk;
uint32_t pm1a_cnt_blk;
uint32_t pm1b_cnt_blk;
uint32_t pm2_cnt_blk;
uint32_t pm_tmr_blk;
uint32_t gpe0_blk;
uint32_t gpe1_blk;
char pm1_evt_len;
char pm1_cnt_len;
char pm2_cnt_len;
char pm_tmr_len;
char gpe0_blk_len;
char gpe1_blk_len;
char gpe1_base;
char cst_cnt;
uint16_t p_lvl2_lat;
uint16_t p_lvl3_lat;
uint16_t flush_size;
uint16_t flush_stride;
char duty_offset;
char duty_width;
char day_alrm;
char mon_alrm;
char century;
uint16_t ipac_boot_arch;
char res1;
uint32_t flags;
char reset_reg[12];
char reset_value;
uint16_t arm_boot_arch;
char fadt_minor_version;
// ...
};
struct acpi_hpet {
struct acpi_sdt_header header;
uint32_t event_timer_blk_id;
struct acpi_gas base_address;
char hpet_number;
// ...
} __attribute__((packed));
enum acpi_table_type {
ACPI_FADT,
ACPI_APIC,
ACPI_HPET,
ACPI_TABLE_TYPE_COUNT
};
////
extern uintptr_t acpi_tables[ACPI_TABLE_TYPE_COUNT];
int acpi_tables_init(void);

View File

@ -1,37 +0,0 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
typedef struct {
uint16_t limit_lo;
uint16_t base_lo;
uint8_t base_mi;
uint8_t access;
uint8_t flags;
uint8_t base_hi;
} amd64_gdt_entry_t;
typedef struct {
uint32_t __res0;
uint64_t rsp0;
uint64_t rsp1;
uint64_t rsp2;
uint64_t __res1;
uint64_t ist1;
uint64_t ist2;
uint64_t ist3;
uint64_t ist4;
uint64_t ist5;
uint64_t ist6;
uint64_t ist7;
uint64_t __res2;
uint16_t __res3;
uint16_t iopb_base;
}__attribute__((packed)) amd64_tss_t;
typedef struct {
uint16_t size;
uintptr_t offset;
} __attribute__((packed)) amd64_gdt_ptr_t;
void amd64_gdt_init(void);

View File

@ -1,74 +0,0 @@
// vi:syntax=asm
.macro __int_push_ctx
// pushal for amd64 world
pushq %rax
pushq %rcx
pushq %rdx
pushq %rbx
pushq %rsp
pushq %rbp
pushq %rsi
pushq %rdi
// r8-r15
pushq %r8
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r14
pushq %r15
// cr3
mov %cr3, %rax
pushq %rax
// segments
mov %gs, %rax
pushq %rax
mov %fs, %rax
pushq %rax
mov %es, %rax
pushq %rax
mov %ds, %rax
pushq %rax
.endm
.macro __int_pop_ctx
// segments
popq %rax
mov %rax, %ds
popq %rax
mov %rax, %es
popq %rax
popq %rax
xor %rax, %rax
mov %rax, %fs
mov %rax, %gs
// cr3
popq %rax
mov %rax, %cr3
// r15-r8
pop %r15
pop %r14
pop %r13
pop %r12
pop %r11
pop %r10
pop %r9
pop %r8
// popal
pop %rdi
pop %rsi
pop %rbp
pop %rax // Ignore rsp
pop %rbx
pop %rdx
pop %rcx
pop %rax
.endm

View File

@ -1,3 +0,0 @@
#pragma once
void amd64_idt_init(void);

View File

@ -1,28 +0,0 @@
#pragma once
#include <stdint.h>
static inline void outb(uint16_t addr, uint8_t v) {
asm volatile("outb %0, %1"::"a"(v), "Nd"(addr));
}
static inline uint8_t inb(uint16_t addr) {
uint8_t v;
asm volatile("inb %1, %0":"=a"(v):"Nd"(addr));
return v;
}
static inline void outl(uint16_t addr, uint32_t v) {
asm volatile("outl %0, %1"::"a"(v), "Nd"(addr));
}
static inline uint32_t inl(uint16_t addr) {
uint32_t v;
asm volatile("inl %1, %0":"=a"(v):"Nd"(addr));
return v;
}
static inline void io_wait(void) {
asm volatile("jmp 1f\n\t"
"1:jmp 2f\n\t"
"2:" );
}

View File

@ -1,4 +0,0 @@
#pragma once
#define IRQ_BASE 32
void pic8259_init(void);

View File

@ -1,3 +0,0 @@
#pragma once
void amd64_irq1(void);

View File

@ -1,8 +0,0 @@
#pragma once
#include <stdint.h>
#define RS232_COM0 0x3F8
void rs232_init(uint16_t port);
void rs232_send(uint16_t port, char c);
char rs232_recv(uint16_t port);

View File

@ -1,8 +0,0 @@
// For now, the timer driver only has support for 8253 PIT
#pragma once
#include <stdint.h>
extern uint64_t amd64_timer_ticks;
extern void (*amd64_timer_tick)(void);
void amd64_timer_configure(void);

View File

@ -1,10 +0,0 @@
#pragma once
#include <stdint.h>
struct amd64_loader_data {
uint32_t multiboot_info_ptr;
uint32_t initrd_ptr;
uint32_t initrd_len;
// Just in case
uint8_t checksum;
} __attribute__((packed));

View File

@ -1,443 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI_LINUX_ELF_H
#define _UAPI_LINUX_ELF_H
#include <stdint.h>
/* 32-bit ELF base types. */
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off;
typedef uint32_t Elf32_Sword;
typedef uint32_t Elf32_Word;
/* 64-bit ELF base types. */
typedef uint64_t Elf64_Addr;
typedef uint16_t Elf64_Half;
typedef uint16_t Elf64_SHalf;
typedef uint64_t Elf64_Off;
typedef uint32_t Elf64_Sword;
typedef uint32_t Elf64_Word;
typedef uint64_t Elf64_Xword;
typedef uint64_t Elf64_Sxword;
/* These constants are for the segment types stored in the image headers */
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_TLS 7 /* Thread local storage segment */
#define PT_LOOS 0x60000000 /* OS-specific */
#define PT_HIOS 0x6fffffff /* OS-specific */
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
#define PT_GNU_EH_FRAME 0x6474e550
#define PT_GNU_STACK (PT_LOOS + 0x474e551)
/*
* Extended Numbering
*
* If the real number of program header table entries is larger than
* or equal to PN_XNUM(0xffff), it is set to sh_info field of the
* section header at index 0, and PN_XNUM is set to e_phnum
* field. Otherwise, the section header at index 0 is zero
* initialized, if it exists.
*
* Specifications are available in:
*
* - Oracle: Linker and Libraries.
* Part No: 817198419, August 2011.
* http://docs.oracle.com/cd/E18752_01/pdf/817-1984.pdf
*
* - System V ABI AMD64 Architecture Processor Supplement
* Draft Version 0.99.4,
* January 13, 2010.
* http://www.cs.washington.edu/education/courses/cse351/12wi/supp-docs/abi.pdf
*/
#define PN_XNUM 0xffff
/* These constants define the different elf file types */
#define ET_NONE 0
#define ET_REL 1
#define ET_EXEC 2
#define ET_DYN 3
#define ET_CORE 4
#define ET_LOPROC 0xff00
#define ET_HIPROC 0xffff
/* This is the info that is needed to parse the dynamic section of the file */
#define DT_NULL 0
#define DT_NEEDED 1
#define DT_PLTRELSZ 2
#define DT_PLTGOT 3
#define DT_HASH 4
#define DT_STRTAB 5
#define DT_SYMTAB 6
#define DT_RELA 7
#define DT_RELASZ 8
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
#define DT_INIT 12
#define DT_FINI 13
#define DT_SONAME 14
#define DT_RPATH 15
#define DT_SYMBOLIC 16
#define DT_REL 17
#define DT_RELSZ 18
#define DT_RELENT 19
#define DT_PLTREL 20
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23
#define DT_ENCODING 32
#define OLD_DT_LOOS 0x60000000
#define DT_LOOS 0x6000000d
#define DT_HIOS 0x6ffff000
#define DT_VALRNGLO 0x6ffffd00
#define DT_VALRNGHI 0x6ffffdff
#define DT_ADDRRNGLO 0x6ffffe00
#define DT_ADDRRNGHI 0x6ffffeff
#define DT_VERSYM 0x6ffffff0
#define DT_RELACOUNT 0x6ffffff9
#define DT_RELCOUNT 0x6ffffffa
#define DT_FLAGS_1 0x6ffffffb
#define DT_VERDEF 0x6ffffffc
#define DT_VERDEFNUM 0x6ffffffd
#define DT_VERNEED 0x6ffffffe
#define DT_VERNEEDNUM 0x6fffffff
#define OLD_DT_HIOS 0x6fffffff
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7fffffff
/* This info is needed when parsing the symbol table */
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define STT_COMMON 5
#define STT_TLS 6
#define ELF_ST_BIND(x) ((x) >> 4)
#define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf)
#define ELF32_ST_BIND(x) ELF_ST_BIND(x)
#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x)
#define ELF64_ST_BIND(x) ELF_ST_BIND(x)
#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x)
typedef struct dynamic{
Elf32_Sword d_tag;
union{
Elf32_Sword d_val;
Elf32_Addr d_ptr;
} d_un;
} Elf32_Dyn;
typedef struct {
Elf64_Sxword d_tag; /* entry tag value */
union {
Elf64_Xword d_val;
Elf64_Addr d_ptr;
} d_un;
} Elf64_Dyn;
/* The following are used with relocations */
#define ELF32_R_SYM(x) ((x) >> 8)
#define ELF32_R_TYPE(x) ((x) & 0xff)
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
typedef struct elf32_rel {
Elf32_Addr r_offset;
Elf32_Word r_info;
} Elf32_Rel;
typedef struct elf64_rel {
Elf64_Addr r_offset; /* Location at which to apply the action */
Elf64_Xword r_info; /* index and type of relocation */
} Elf64_Rel;
typedef struct elf32_rela{
Elf32_Addr r_offset;
Elf32_Word r_info;
Elf32_Sword r_addend;
} Elf32_Rela;
typedef struct elf64_rela {
Elf64_Addr r_offset; /* Location at which to apply the action */
Elf64_Xword r_info; /* index and type of relocation */
Elf64_Sxword r_addend; /* Constant addend used to compute value */
} Elf64_Rela;
typedef struct elf32_sym{
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
typedef struct elf64_sym {
Elf64_Word st_name; /* Symbol name, index in string tbl */
unsigned char st_info; /* Type and binding attributes */
unsigned char st_other; /* No defined meaning, 0 */
Elf64_Half st_shndx; /* Associated section index */
Elf64_Addr st_value; /* Value of the symbol */
Elf64_Xword st_size; /* Associated symbol size */
} Elf64_Sym;
#define EI_NIDENT 16
typedef struct elf32_hdr{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry; /* Entry point */
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
typedef struct elf64_hdr {
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx;
} Elf64_Ehdr;
/* These constants define the permissions on sections in the program
header, p_flags. */
#define PF_R 0x4
#define PF_W 0x2
#define PF_X 0x1
typedef struct elf32_phdr{
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
typedef struct elf64_phdr {
Elf64_Word p_type;
Elf64_Word p_flags;
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment, file & memory */
} Elf64_Phdr;
/* sh_type */
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_NUM 12
#define SHT_LOPROC 0x70000000
#define SHT_HIPROC 0x7fffffff
#define SHT_LOUSER 0x80000000
#define SHT_HIUSER 0xffffffff
/* sh_flags */
#define SHF_WRITE 0x1
#define SHF_ALLOC 0x2
#define SHF_EXECINSTR 0x4
#define SHF_RELA_LIVEPATCH 0x00100000
#define SHF_RO_AFTER_INIT 0x00200000
#define SHF_MASKPROC 0xf0000000
/* special section indexes */
#define SHN_UNDEF 0
#define SHN_LORESERVE 0xff00
#define SHN_LOPROC 0xff00
#define SHN_HIPROC 0xff1f
#define SHN_LIVEPATCH 0xff20
#define SHN_ABS 0xfff1
#define SHN_COMMON 0xfff2
#define SHN_HIRESERVE 0xffff
typedef struct elf32_shdr {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
typedef struct elf64_shdr {
Elf64_Word sh_name; /* Section name, index in string tbl */
Elf64_Word sh_type; /* Type of section */
Elf64_Xword sh_flags; /* Miscellaneous section attributes */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Size of section in bytes */
Elf64_Word sh_link; /* Index of another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
#define EI_MAG0 0 /* e_ident[] indexes */
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_OSABI 7
#define EI_PAD 8
#define ELFMAG0 0x7f /* EI_MAG */
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
#define ELFMAG "\177ELF"
#define SELFMAG 4
#define ELFCLASSNONE 0 /* EI_CLASS */
#define ELFCLASS32 1
#define ELFCLASS64 2
#define ELFCLASSNUM 3
#define ELFDATANONE 0 /* e_ident[EI_DATA] */
#define ELFDATA2LSB 1
#define ELFDATA2MSB 2
#define EV_NONE 0 /* e_version, EI_VERSION */
#define EV_CURRENT 1
#define EV_NUM 2
#define ELFOSABI_NONE 0
#define ELFOSABI_LINUX 3
#ifndef ELF_OSABI
#define ELF_OSABI ELFOSABI_NONE
#endif
/*
* Notes used in ET_CORE. Architectures export some of the arch register sets
* using the corresponding note types via the PTRACE_GETREGSET and
* PTRACE_SETREGSET requests.
*/
#define NT_PRSTATUS 1
#define NT_PRFPREG 2
#define NT_PRPSINFO 3
#define NT_TASKSTRUCT 4
#define NT_AUXV 6
/*
* Note to userspace developers: size of NT_SIGINFO note may increase
* in the future to accomodate more fields, don't assume it is fixed!
*/
#define NT_SIGINFO 0x53494749
#define NT_FILE 0x46494c45
#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */
#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
#define NT_PPC_TAR 0x103 /* Target Address Register */
#define NT_PPC_PPR 0x104 /* Program Priority Register */
#define NT_PPC_DSCR 0x105 /* Data Stream Control Register */
#define NT_PPC_EBB 0x106 /* Event Based Branch Registers */
#define NT_PPC_PMU 0x107 /* Performance Monitor Registers */
#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */
#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */
#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */
#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */
#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */
#define NT_PPC_TM_CTAR 0x10d /* TM checkpointed Target Address Register */
#define NT_PPC_TM_CPPR 0x10e /* TM checkpointed Program Priority Register */
#define NT_PPC_TM_CDSCR 0x10f /* TM checkpointed Data Stream Control Register */
#define NT_PPC_PKEY 0x110 /* Memory Protection Keys registers */
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */
#define NT_S390_TIMER 0x301 /* s390 timer register */
#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */
#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */
#define NT_S390_CTRS 0x304 /* s390 control registers */
#define NT_S390_PREFIX 0x305 /* s390 prefix register */
#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */
#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */
#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */
#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 upper half */
#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */
#define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */
#define NT_S390_GS_BC 0x30c /* s390 guarded storage broadcast control block */
#define NT_S390_RI_CB 0x30d /* s390 runtime instrumentation */
#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
#define NT_ARM_TLS 0x401 /* ARM TLS register */
#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */
#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension registers */
#define NT_ARM_PAC_MASK 0x406 /* ARM pointer authentication code masks */
#define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */
#define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */
#define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */
#define NT_MIPS_FP_MODE 0x801 /* MIPS floating-point mode */
#define NT_MIPS_MSA 0x802 /* MIPS SIMD registers */
/* Note header in a PT_NOTE section */
typedef struct elf32_note {
Elf32_Word n_namesz; /* Name size */
Elf32_Word n_descsz; /* Content size */
Elf32_Word n_type; /* Content type */
} Elf32_Nhdr;
/* Note header in a PT_NOTE section */
typedef struct elf64_note {
Elf64_Word n_namesz; /* Name size */
Elf64_Word n_descsz; /* Content size */
Elf64_Word n_type; /* Content type */
} Elf64_Nhdr;
#endif /* _UAPI_LINUX_ELF_H */

View File

@ -1,274 +0,0 @@
/* multiboot.h - Multiboot header file. */
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MULTIBOOT_HEADER
#define MULTIBOOT_HEADER 1
/* How many bytes from the start of the file we search for the header. */
#define MULTIBOOT_SEARCH 8192
#define MULTIBOOT_HEADER_ALIGN 4
/* The magic field should contain this. */
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
/* This should be in %eax. */
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
/* Alignment of multiboot modules. */
#define MULTIBOOT_MOD_ALIGN 0x00001000
/* Alignment of the multiboot info structure. */
#define MULTIBOOT_INFO_ALIGN 0x00000004
/* Flags set in the 'flags' member of the multiboot header. */
/* Align all boot modules on i386 page (4KB) boundaries. */
#define MULTIBOOT_PAGE_ALIGN 0x00000001
/* Must pass memory information to OS. */
#define MULTIBOOT_MEMORY_INFO 0x00000002
/* Must pass video information to OS. */
#define MULTIBOOT_VIDEO_MODE 0x00000004
/* This flag indicates the use of the address fields in the header. */
#define MULTIBOOT_AOUT_KLUDGE 0x00010000
/* Flags to be set in the 'flags' member of the multiboot info structure. */
/* is there basic lower/upper memory information? */
#define MULTIBOOT_INFO_MEMORY 0x00000001
/* is there a boot device set? */
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
/* is the command-line defined? */
#define MULTIBOOT_INFO_CMDLINE 0x00000004
/* are there modules to do something with? */
#define MULTIBOOT_INFO_MODS 0x00000008
/* These next two are mutually exclusive */
/* is there a symbol table loaded? */
#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
/* is there an ELF section header table? */
#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
/* is there a full memory map? */
#define MULTIBOOT_INFO_MEM_MAP 0x00000040
/* Is there drive info? */
#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
/* Is there a config table? */
#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
/* Is there a boot loader name? */
#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
/* Is there a APM table? */
#define MULTIBOOT_INFO_APM_TABLE 0x00000400
/* Is there video information? */
#define MULTIBOOT_INFO_VBE_INFO 0x00000800
#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000
#ifndef ASM_FILE
typedef unsigned char multiboot_uint8_t;
typedef unsigned short multiboot_uint16_t;
typedef unsigned int multiboot_uint32_t;
typedef unsigned long long multiboot_uint64_t;
struct multiboot_header
{
/* Must be MULTIBOOT_MAGIC - see above. */
multiboot_uint32_t magic;
/* Feature flags. */
multiboot_uint32_t flags;
/* The above fields plus this one must equal 0 mod 2^32. */
multiboot_uint32_t checksum;
/* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
multiboot_uint32_t header_addr;
multiboot_uint32_t load_addr;
multiboot_uint32_t load_end_addr;
multiboot_uint32_t bss_end_addr;
multiboot_uint32_t entry_addr;
/* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
multiboot_uint32_t mode_type;
multiboot_uint32_t width;
multiboot_uint32_t height;
multiboot_uint32_t depth;
};
/* The symbol table for a.out. */
struct multiboot_aout_symbol_table
{
multiboot_uint32_t tabsize;
multiboot_uint32_t strsize;
multiboot_uint32_t addr;
multiboot_uint32_t reserved;
};
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
/* The section header table for ELF. */
struct multiboot_elf_section_header_table
{
multiboot_uint32_t num;
multiboot_uint32_t size;
multiboot_uint32_t addr;
multiboot_uint32_t shndx;
};
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
struct multiboot_info
{
/* Multiboot info version number */
multiboot_uint32_t flags;
/* Available memory from BIOS */
multiboot_uint32_t mem_lower;
multiboot_uint32_t mem_upper;
/* "root" partition */
multiboot_uint32_t boot_device;
/* Kernel command line */
multiboot_uint32_t cmdline;
/* Boot-Module list */
multiboot_uint32_t mods_count;
multiboot_uint32_t mods_addr;
union
{
multiboot_aout_symbol_table_t aout_sym;
multiboot_elf_section_header_table_t elf_sec;
} u;
/* Memory Mapping buffer */
multiboot_uint32_t mmap_length;
multiboot_uint32_t mmap_addr;
/* Drive Info buffer */
multiboot_uint32_t drives_length;
multiboot_uint32_t drives_addr;
/* ROM configuration table */
multiboot_uint32_t config_table;
/* Boot Loader Name */
multiboot_uint32_t boot_loader_name;
/* APM table */
multiboot_uint32_t apm_table;
/* Video */
multiboot_uint32_t vbe_control_info;
multiboot_uint32_t vbe_mode_info;
multiboot_uint16_t vbe_mode;
multiboot_uint16_t vbe_interface_seg;
multiboot_uint16_t vbe_interface_off;
multiboot_uint16_t vbe_interface_len;
multiboot_uint64_t framebuffer_addr;
multiboot_uint32_t framebuffer_pitch;
multiboot_uint32_t framebuffer_width;
multiboot_uint32_t framebuffer_height;
multiboot_uint8_t framebuffer_bpp;
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
multiboot_uint8_t framebuffer_type;
union
{
struct
{
multiboot_uint32_t framebuffer_palette_addr;
multiboot_uint16_t framebuffer_palette_num_colors;
};
struct
{
multiboot_uint8_t framebuffer_red_field_position;
multiboot_uint8_t framebuffer_red_mask_size;
multiboot_uint8_t framebuffer_green_field_position;
multiboot_uint8_t framebuffer_green_mask_size;
multiboot_uint8_t framebuffer_blue_field_position;
multiboot_uint8_t framebuffer_blue_mask_size;
};
};
};
typedef struct multiboot_info multiboot_info_t;
struct multiboot_color
{
multiboot_uint8_t red;
multiboot_uint8_t green;
multiboot_uint8_t blue;
};
struct multiboot_mmap_entry
{
multiboot_uint32_t size;
multiboot_uint64_t addr;
multiboot_uint64_t len;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
#define MULTIBOOT_MEMORY_NVS 4
#define MULTIBOOT_MEMORY_BADRAM 5
multiboot_uint32_t type;
} __attribute__((packed));
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
struct multiboot_mod_list
{
/* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
multiboot_uint32_t mod_start;
multiboot_uint32_t mod_end;
/* Module command line */
multiboot_uint32_t cmdline;
/* padding to take it to 16 bytes (must be zero) */
multiboot_uint32_t pad;
};
typedef struct multiboot_mod_list multiboot_module_t;
/* APM BIOS info. */
struct multiboot_apm_info
{
multiboot_uint16_t version;
multiboot_uint16_t cseg;
multiboot_uint32_t offset;
multiboot_uint16_t cseg_16;
multiboot_uint16_t dseg;
multiboot_uint16_t flags;
multiboot_uint16_t cseg_len;
multiboot_uint16_t cseg_16_len;
multiboot_uint16_t dseg_len;
};
#endif /* ! ASM_FILE */
#endif /* ! MULTIBOOT_HEADER */

View File

@ -1,15 +0,0 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
// General utils
void *memset(void *blk, int v, size_t sz);
void *memcpy(void *dst, const void *src, size_t sz);
int strcmp(const char *a, const char *b);
int strncmp(const char *a, const char *b, size_t lim);
// Debug utils
void panic(const char *s);
void puts(const char *s);
void putx(uint64_t v);
void putc(char c);

View File

@ -1,34 +0,0 @@
/* vim: set ft=cpp.doxygen : */
#pragma once
#include <stdint.h>
#include "sys/amd64/loader/data.h"
/// The place where the kernel pages are virtually mapped to
#define KERNEL_VIRT_BASE 0xFFFFFF0000000000
/// amd64 standard states that addresses' upper bits are copies of the 47th bit, so these need to be
/// stripped down to only 48 bits
#define AMD64_MM_STRIPSX(a) ((uintptr_t) (a) & 0xFFFFFFFFFFFF)
#define AMD64_MM_ADDRSX(a) (((uintptr_t) (a) & (1ULL << 47)) ? \
(0xFFFFFF0000000000 | ((uintptr_t) (a))) : \
((uintptr_t) (a)))
#define MM_VIRTUALIZE(a) ((uintptr_t) (a) + 0xFFFFFF0000000000)
#define MM_PHYS(a) ((uintptr_t) (a) - 0xFFFFFF0000000000)
/// Page map level 4
typedef uint64_t *mm_pml4_t;
/// Page directory pointer table
typedef uint64_t *mm_pdpt_t;
/// Page directory
typedef uint64_t *mm_pagedir_t;
/// Page table
typedef uint64_t *mm_pagetab_t;
/// Virtual memory space
typedef mm_pml4_t mm_space_t;
/// Kernel memory space
extern mm_space_t mm_kernel;
void amd64_mm_init(struct amd64_loader_data *data);

View File

@ -1,30 +0,0 @@
// vim: set ft=cpp.doxygen :
#pragma once
#include "sys/heap.h"
#include <stdint.h>
#define KERNEL_HEAP (16 * 1024 * 1024)
/**
* @brief Initialize heap instance of size `sz' at `phys_base'
* @param heap Heap instance
* @param phys_base Physical address of the first byte of the heap
* @param sz Count of bytes available for heap usage
* @note Physical addresses are used internally for heap because this
* allows heap to just MM_VIRTUALIZE allocated pointers no matter
* where the kernel heap actually resides, which could be the
* problem if we created a separate mapping for kernel heap
* memory.
*/
void amd64_heap_init(heap_t *heap, uintptr_t phys_base, size_t sz);
// Debug info
/**
* @return Number of blocks in heap
*/
size_t amd64_heap_blocks(const heap_t *heap);
/**
* @brief Print kernel heap block list to debug output
*/
void amd64_heap_dump(const heap_t *heap);

View File

@ -1,49 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file arch/amd64/mm/map.h
* @brief amd64-specific virtual memory space functions
*/
#pragma once
#include "sys/types.h"
#include "sys/mm.h"
/// Splits userspace mappings and kernelspace ones
#define AMD64_PML4I_USER_END 255
/**
* @brief Translate a virtual address in `space' to its physical mapping (if one exists).
* May optionally return access flags in `flags' if non-NULL
* @param space Virtual memory space
* @param vaddr Virtual address
* @param flags Access flags storage pointer or NULL
* @return Physical address corresponding to `vaddr' in `space' if mapping exists,
* MM_NADDR otherwise.
*/
uintptr_t amd64_map_get(const mm_space_t space, uintptr_t vaddr, uint64_t *flags);
/**
* @brief Remove a virtual address mapping from memory space, optionally checking if it
* is of a specific page size.
* @param space Virtual memory space
* @param vaddr Virtual address
* @param size Expected page size:
* * 1 for 4KiB
* * 2 for 2MiB
* * 3 for 1GiB
* * 0 for any size
* @return Physical address of the unmapped page (in case it has to be freed),
* MM_NADDR in case the mapping does not exist or the size does not match.
*/
uintptr_t amd64_map_umap(mm_space_t space, uintptr_t vaddr, uint32_t size);
/**
* @brief Add a single page mapping to `pml4'
* @param pml4 Virtual memory space
* @param virt_addr Source virtual address
* @param phys Destination physical address
* @param flags Access flags:
* * TODO: size-specific
* * AMD64_MAP_WRITE
* * AMD64_MAP_USER
* @return 0 on success, -1 otherwise
*/
int amd64_map_single(mm_space_t pml4, uintptr_t virt_addr, uintptr_t phys, uint32_t flags);

View File

@ -1,10 +0,0 @@
#pragma once
#include "sys/amd64/loader/multiboot.h"
#include "sys/types.h"
#include <stdint.h>
void amd64_phys_memory_map(const multiboot_memory_map_t *mmap, size_t length);
void amd64_phys_free(uintptr_t page);
uintptr_t amd64_phys_alloc_page(void);
uintptr_t amd64_phys_alloc_contiguous(size_t count);

View File

@ -1,15 +0,0 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
// 8192 page tables
#define MM_POOL_SIZE (8192 * 0x1000)
/// Initialize the paging structure allocation pool
void amd64_mm_pool_init(uintptr_t base, size_t size);
/// Allocate a paging structure (returns virtual addresses)
uint64_t *amd64_mm_pool_alloc(void);
/// Free a paging structure (obj is a virtual pointer)
void amd64_mm_pool_free(uint64_t *obj);

View File

@ -1,31 +0,0 @@
#pragma once
#include <stdint.h>
typedef struct {
uint64_t rip;
uint64_t cs;
uint64_t rflags;
uint64_t rsp;
uint64_t ss;
} amd64_iret_regs_t;
typedef struct {
uint64_t ds;
uint64_t es;
uint64_t fs;
uint64_t gs;
} amd64_seg_regs_t;
typedef struct {
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
uint64_t rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax;
} amd64_gp_regs_t;
typedef struct {
amd64_seg_regs_t segs;
uint64_t cr3;
amd64_gp_regs_t gp;
amd64_iret_regs_t iret;
} amd64_ctx_regs_t;
void amd64_ctx_dump(int level, const amd64_ctx_regs_t *regs);

View File

@ -1,37 +0,0 @@
/** vim:set ft=cpp.doxygen :
* @file arch/amd64/sys/thread.h
* @brief amd64 implementation of thread control structs/context storage
*/
#pragma once
#include "sys/thread.h"
#define thread_next(t) ((t)->next)
#define thread_get(t) (&(t)->info)
/**
* @brief amd64 task kernel stack/context storage
*/
typedef struct {
uint64_t seg[4];
uint64_t cr3;
uint64_t r[8];
uint64_t rdi, rsi, rbp, __rsp;
uint64_t rbx, rdx, rcx, rax;
uint64_t rip, cs, rflags, rsp, ss;
}__attribute__((packed)) amd64_thread_context_t;
/**
* @brief amd64-specific thread implementation
*/
struct thread {
uintptr_t kstack_ptr;
uintptr_t kstack_base;
size_t kstack_size;
uintptr_t ustack_base;
size_t ustack_size;
thread_info_t info;
thread_t *next;
};

View File

@ -1,10 +0,0 @@
#pragma once
#include "sys/panic.h"
#define assert(c, m, ...) \
if (!(c)) \
panic(m, ##__VA_ARGS__);
#define _assert(c) \
if (!(c)) \
panic("Assertion failed: " #c);

View File

@ -1,8 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file sys/attr.h
* @brief Storage/function attributes for clarification or
* compiler hints
*/
#pragma once
#define __weak __attribute__((weak))

View File

@ -1,4 +0,0 @@
#pragma once
#include "sys/thread.h"
int elf_load(thread_t *thr, const void *eptr);

View File

@ -1,15 +0,0 @@
#pragma once
#include <stdint.h>
#include <sys/types.h>
struct blkdev {
void *dev_data;
ssize_t (*read) (struct blkdev *blk, void *buf, size_t off, size_t count);
ssize_t (*write) (struct blkdev *blk, const void *buf, size_t off, size_t count);
void (*destroy) (struct blkdev *blk);
};
ssize_t blk_read(struct blkdev *blk, void *buf, size_t off, size_t count);
ssize_t blk_write(struct blkdev *blk, const void *buf, size_t off, size_t count);

View File

@ -1,6 +0,0 @@
#pragma once
#include "sys/blk.h"
extern struct blkdev *ramblk0;
void ramblk_init(uintptr_t at, size_t len);

View File

@ -1,14 +0,0 @@
#pragma once
#include "sys/types.h"
struct chrdev {
char name[64];
void *dev_data;
// TODO: maybe something like flush()
ssize_t (*write) (struct chrdev *chr, const void *buf, size_t pos, size_t lim);
ssize_t (*read) (struct chrdev *chr, void *buf, size_t pos, size_t lim);
};
ssize_t chr_write(struct chrdev *chr, const void *buf, size_t pos, size_t lim);
ssize_t chr_read(struct chrdev *chr, void *buf, size_t pos, size_t lim);

View File

@ -1,447 +0,0 @@
// Copied this from linux/elf.h, changed typenames
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI_LINUX_ELF_H
#define _UAPI_LINUX_ELF_H
#include "sys/types.h"
/* 32-bit ELF base types. */
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off;
typedef int32_t Elf32_Sword;
typedef uint32_t Elf32_Word;
/* 64-bit ELF base types. */
typedef uint64_t Elf64_Addr;
typedef uint16_t Elf64_Half;
typedef int16_t Elf64_SHalf;
typedef uint64_t Elf64_Off;
typedef uint32_t Elf64_Sword;
typedef uint32_t Elf64_Word;
typedef uint64_t Elf64_Xword;
typedef int64_t Elf64_Sxword;
/* These constants are for the segment types stored in the image headers */
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_TLS 7 /* Thread local storage segment */
#define PT_LOOS 0x60000000 /* OS-specific */
#define PT_HIOS 0x6fffffff /* OS-specific */
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
#define PT_GNU_EH_FRAME 0x6474e550
#define PT_GNU_STACK (PT_LOOS + 0x474e551)
/*
* Extended Numbering
*
* If the real number of program header table entries is larger than
* or equal to PN_XNUM(0xffff), it is set to sh_info field of the
* section header at index 0, and PN_XNUM is set to e_phnum
* field. Otherwise, the section header at index 0 is zero
* initialized, if it exists.
*
* Specifications are available in:
*
* - Oracle: Linker and Libraries.
* Part No: 817198419, August 2011.
* http://docs.oracle.com/cd/E18752_01/pdf/817-1984.pdf
*
* - System V ABI AMD64 Architecture Processor Supplement
* Draft Version 0.99.4,
* January 13, 2010.
* http://www.cs.washington.edu/education/courses/cse351/12wi/supp-docs/abi.pdf
*/
#define PN_XNUM 0xffff
/* These constants define the different elf file types */
#define ET_NONE 0
#define ET_REL 1
#define ET_EXEC 2
#define ET_DYN 3
#define ET_CORE 4
#define ET_LOPROC 0xff00
#define ET_HIPROC 0xffff
/* This is the info that is needed to parse the dynamic section of the file */
#define DT_NULL 0
#define DT_NEEDED 1
#define DT_PLTRELSZ 2
#define DT_PLTGOT 3
#define DT_HASH 4
#define DT_STRTAB 5
#define DT_SYMTAB 6
#define DT_RELA 7
#define DT_RELASZ 8
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
#define DT_INIT 12
#define DT_FINI 13
#define DT_SONAME 14
#define DT_RPATH 15
#define DT_SYMBOLIC 16
#define DT_REL 17
#define DT_RELSZ 18
#define DT_RELENT 19
#define DT_PLTREL 20
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23
#define DT_ENCODING 32
#define OLD_DT_LOOS 0x60000000
#define DT_LOOS 0x6000000d
#define DT_HIOS 0x6ffff000
#define DT_VALRNGLO 0x6ffffd00
#define DT_VALRNGHI 0x6ffffdff
#define DT_ADDRRNGLO 0x6ffffe00
#define DT_ADDRRNGHI 0x6ffffeff
#define DT_VERSYM 0x6ffffff0
#define DT_RELACOUNT 0x6ffffff9
#define DT_RELCOUNT 0x6ffffffa
#define DT_FLAGS_1 0x6ffffffb
#define DT_VERDEF 0x6ffffffc
#define DT_VERDEFNUM 0x6ffffffd
#define DT_VERNEED 0x6ffffffe
#define DT_VERNEEDNUM 0x6fffffff
#define OLD_DT_HIOS 0x6fffffff
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7fffffff
/* This info is needed when parsing the symbol table */
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define STT_COMMON 5
#define STT_TLS 6
#define ELF_ST_BIND(x) ((x) >> 4)
#define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf)
#define ELF32_ST_BIND(x) ELF_ST_BIND(x)
#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x)
#define ELF64_ST_BIND(x) ELF_ST_BIND(x)
#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x)
typedef struct dynamic{
Elf32_Sword d_tag;
union{
Elf32_Sword d_val;
Elf32_Addr d_ptr;
} d_un;
} Elf32_Dyn;
typedef struct {
Elf64_Sxword d_tag; /* entry tag value */
union {
Elf64_Xword d_val;
Elf64_Addr d_ptr;
} d_un;
} Elf64_Dyn;
/* The following are used with relocations */
#define ELF32_R_SYM(x) ((x) >> 8)
#define ELF32_R_TYPE(x) ((x) & 0xff)
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
typedef struct elf32_rel {
Elf32_Addr r_offset;
Elf32_Word r_info;
} Elf32_Rel;
typedef struct elf64_rel {
Elf64_Addr r_offset; /* Location at which to apply the action */
Elf64_Xword r_info; /* index and type of relocation */
} Elf64_Rel;
typedef struct elf32_rela{
Elf32_Addr r_offset;
Elf32_Word r_info;
Elf32_Sword r_addend;
} Elf32_Rela;
typedef struct elf64_rela {
Elf64_Addr r_offset; /* Location at which to apply the action */
Elf64_Xword r_info; /* index and type of relocation */
Elf64_Sxword r_addend; /* Constant addend used to compute value */
} Elf64_Rela;
typedef struct elf32_sym{
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
typedef struct elf64_sym {
Elf64_Word st_name; /* Symbol name, index in string tbl */
unsigned char st_info; /* Type and binding attributes */
unsigned char st_other; /* No defined meaning, 0 */
Elf64_Half st_shndx; /* Associated section index */
Elf64_Addr st_value; /* Value of the symbol */
Elf64_Xword st_size; /* Associated symbol size */
} Elf64_Sym;
#define EI_NIDENT 16
typedef struct elf32_hdr{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry; /* Entry point */
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
typedef struct elf64_hdr {
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx;
} Elf64_Ehdr;
/* These constants define the permissions on sections in the program
header, p_flags. */
#define PF_R 0x4
#define PF_W 0x2
#define PF_X 0x1
typedef struct elf32_phdr{
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
typedef struct elf64_phdr {
Elf64_Word p_type;
Elf64_Word p_flags;
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment, file & memory */
} Elf64_Phdr;
/* sh_type */
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_NUM 12
#define SHT_LOPROC 0x70000000
#define SHT_HIPROC 0x7fffffff
#define SHT_LOUSER 0x80000000
#define SHT_HIUSER 0xffffffff
/* sh_flags */
#define SHF_WRITE 0x1
#define SHF_ALLOC 0x2
#define SHF_EXECINSTR 0x4
#define SHF_RELA_LIVEPATCH 0x00100000
#define SHF_RO_AFTER_INIT 0x00200000
#define SHF_MASKPROC 0xf0000000
/* special section indexes */
#define SHN_UNDEF 0
#define SHN_LORESERVE 0xff00
#define SHN_LOPROC 0xff00
#define SHN_HIPROC 0xff1f
#define SHN_LIVEPATCH 0xff20
#define SHN_ABS 0xfff1
#define SHN_COMMON 0xfff2
#define SHN_HIRESERVE 0xffff
typedef struct elf32_shdr {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
typedef struct elf64_shdr {
Elf64_Word sh_name; /* Section name, index in string tbl */
Elf64_Word sh_type; /* Type of section */
Elf64_Xword sh_flags; /* Miscellaneous section attributes */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Size of section in bytes */
Elf64_Word sh_link; /* Index of another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
#define EI_MAG0 0 /* e_ident[] indexes */
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_OSABI 7
#define EI_PAD 8
#define ELFMAG0 0x7f /* EI_MAG */
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
#define ELFMAG "\177ELF"
#define SELFMAG 4
#define ELFCLASSNONE 0 /* EI_CLASS */
#define ELFCLASS32 1
#define ELFCLASS64 2
#define ELFCLASSNUM 3
#define ELFDATANONE 0 /* e_ident[EI_DATA] */
#define ELFDATA2LSB 1
#define ELFDATA2MSB 2
#define EV_NONE 0 /* e_version, EI_VERSION */
#define EV_CURRENT 1
#define EV_NUM 2
#define ELFOSABI_NONE 0
#define ELFOSABI_LINUX 3
#ifndef ELF_OSABI
#define ELF_OSABI ELFOSABI_NONE
#endif
/*
* Notes used in ET_CORE. Architectures export some of the arch register sets
* using the corresponding note types via the PTRACE_GETREGSET and
* PTRACE_SETREGSET requests.
*/
#define NT_PRSTATUS 1
#define NT_PRFPREG 2
#define NT_PRPSINFO 3
#define NT_TASKSTRUCT 4
#define NT_AUXV 6
/*
* Note to userspace developers: size of NT_SIGINFO note may increase
* in the future to accomodate more fields, don't assume it is fixed!
*/
#define NT_SIGINFO 0x53494749
#define NT_FILE 0x46494c45
#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */
#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
#define NT_PPC_TAR 0x103 /* Target Address Register */
#define NT_PPC_PPR 0x104 /* Program Priority Register */
#define NT_PPC_DSCR 0x105 /* Data Stream Control Register */
#define NT_PPC_EBB 0x106 /* Event Based Branch Registers */
#define NT_PPC_PMU 0x107 /* Performance Monitor Registers */
#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */
#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */
#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */
#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */
#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */
#define NT_PPC_TM_CTAR 0x10d /* TM checkpointed Target Address Register */
#define NT_PPC_TM_CPPR 0x10e /* TM checkpointed Program Priority Register */
#define NT_PPC_TM_CDSCR 0x10f /* TM checkpointed Data Stream Control Register */
#define NT_PPC_PKEY 0x110 /* Memory Protection Keys registers */
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */
#define NT_S390_TIMER 0x301 /* s390 timer register */
#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */
#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */
#define NT_S390_CTRS 0x304 /* s390 control registers */
#define NT_S390_PREFIX 0x305 /* s390 prefix register */
#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */
#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */
#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */
#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 upper half */
#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */
#define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */
#define NT_S390_GS_BC 0x30c /* s390 guarded storage broadcast control block */
#define NT_S390_RI_CB 0x30d /* s390 runtime instrumentation */
#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
#define NT_ARM_TLS 0x401 /* ARM TLS register */
#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */
#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension registers */
#define NT_ARM_PAC_MASK 0x406 /* ARM pointer authentication code masks */
#define NT_ARM_PACA_KEYS 0x407 /* ARM pointer authentication address keys */
#define NT_ARM_PACG_KEYS 0x408 /* ARM pointer authentication generic key */
#define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */
#define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */
#define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */
#define NT_MIPS_FP_MODE 0x801 /* MIPS floating-point mode */
#define NT_MIPS_MSA 0x802 /* MIPS SIMD registers */
/* Note header in a PT_NOTE section */
typedef struct elf32_note {
Elf32_Word n_namesz; /* Name size */
Elf32_Word n_descsz; /* Content size */
Elf32_Word n_type; /* Content type */
} Elf32_Nhdr;
/* Note header in a PT_NOTE section */
typedef struct elf64_note {
Elf64_Word n_namesz; /* Name size */
Elf64_Word n_descsz; /* Content size */
Elf64_Word n_type; /* Content type */
} Elf64_Nhdr;
#endif /* _UAPI_LINUX_ELF_H */

View File

@ -1,10 +0,0 @@
#pragma once
#include <stdint.h>
struct dirent {
uint32_t d_ino;
uint32_t d_off;
uint16_t d_reclen;
uint8_t d_type;
char d_name[];
};

View File

@ -1,147 +0,0 @@
#pragma once
#include <stdint.h>
#include "fs.h"
#define EXT2_MAGIC ((uint16_t) 0xEF53)
#define EXT2_SBSIZ 1024
#define EXT2_SBOFF 1024
#define EXT2_ROOTINO 2
#define EXT2_GOOD ((uint16_t) 1)
#define EXT2_BAD ((uint16_t) 2)
#define EXT2_EACT_IGN ((uint16_t) 1)
#define EXT2_EACT_REM ((uint16_t) 2)
#define EXT2_EACT_PAN ((uint16_t) 3)
#define EXT2_TYPE_REG ((uint16_t) 0x8000)
#define EXT2_TYPE_DIR ((uint16_t) 0x4000)
#define EXT2_TYPE_LNK ((uint16_t) 0xA000)
struct ext2_sb {
uint32_t inode_count;
uint32_t block_count;
uint32_t su_reserved;
uint32_t free_block_count;
uint32_t free_inode_count;
uint32_t sb_block_number;
uint32_t block_size_log;
uint32_t frag_size_log;
uint32_t block_group_size_blocks;
uint32_t block_group_size_frags;
uint32_t block_group_size_inodes;
uint32_t last_mount_time;
uint32_t last_mtime;
uint16_t mount_count_since_fsck;
uint16_t mount_max_before_fsck;
uint16_t magic;
uint16_t fs_state;
uint16_t error_action;
uint16_t version_minor;
uint32_t last_fsck_time;
uint32_t os_id;
uint32_t version_major;
uint16_t su_uid;
uint16_t su_gid;
} __attribute__((packed));
struct ext2_extsb {
struct ext2_sb sb;
uint32_t first_non_reserved;
uint16_t inode_struct_size;
uint16_t backup_group_number;
uint32_t optional_features;
uint32_t required_features;
uint32_t ro_required_features;
char fsid[16];
char volname[16];
char last_mount_path[64];
uint32_t compression;
uint8_t prealloc_file_block_number;
uint8_t prealloc_dir_block_number;
uint16_t __un0;
char journal_id[16];
uint32_t journal_inode;
uint32_t journal_dev;
uint32_t orphan_inode_head;
// driver-specific info
uint32_t block_size;
uint32_t block_group_count;
uint32_t block_group_descriptor_table_block;
uint32_t block_group_descriptor_table_size_blocks;
struct ext2_grp_desc *block_group_descriptor_table;
} __attribute__((packed));
struct ext2_grp_desc {
uint32_t block_usage_bitmap_block;
uint32_t inode_usage_bitmap_block;
uint32_t inode_table_block;
uint16_t free_blocks;
uint16_t free_inodes;
uint16_t dir_count;
char __pad[14];
} __attribute__((packed));
struct ext2_inode {
uint16_t type_perm;
uint16_t uid;
uint32_t size_lower;
uint32_t atime;
uint32_t ctime;
uint32_t mtime;
uint32_t dtime;
uint16_t gid;
uint16_t hard_link_count;
uint32_t disk_sector_count;
uint32_t flags;
uint32_t os_value_1;
uint32_t direct_blocks[12];
uint32_t l1_indirect_block;
uint32_t l2_indirect_block;
uint32_t l3_indirect_block;
uint32_t gen_number;
uint32_t acl;
union {
uint32_t dir_acl;
uint32_t size_upper;
};
uint32_t frag_block_addr;
char os_value_2[12];
} __attribute__((packed));
struct ext2_dirent {
uint32_t ino;
uint16_t len;
uint8_t name_len;
uint8_t type_ind;
char name[];
} __attribute__((packed));
void ext2_class_init(void);
enum vnode_type ext2_inode_type(struct ext2_inode *i);
// Implemented in ext2blk.c
int ext2_write_superblock(fs_t *ext2);
int ext2_read_block(fs_t *ext2, uint32_t block_no, void *buf);
int ext2_write_block(fs_t *ext2, uint32_t block_no, const void *buf);
int ext2_read_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index, void *buf);
int ext2_write_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index, const void *buf);
int ext2_read_inode(fs_t *ext2, struct ext2_inode *inode, uint32_t ino);
int ext2_write_inode(fs_t *ext2, const struct ext2_inode *inode, uint32_t ino);
// Implemented in ext2alloc.c
int ext2_alloc_block(fs_t *ext2, uint32_t *block_no);
int ext2_free_block(fs_t *ext2, uint32_t block_no);
int ext2_inode_alloc_block(fs_t *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index);
int ext2_free_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index);
int ext2_free_inode(fs_t *ext2, uint32_t ino);
int ext2_alloc_inode(fs_t *ext2, uint32_t *ino);
// Implemented in ext2dir.c
int ext2_dir_add_inode(fs_t *ext2, vnode_t *dir, const char *name, uint32_t ino);
int ext2_dir_remove_inode(fs_t *ext2, vnode_t *dir, const char *name, uint32_t ino);
extern struct vnode_operations ext2_vnode_ops;

View File

@ -1,31 +0,0 @@
#pragma once
#define R_OK 4
#define W_OK 2
#define X_OK 1
#define F_OK 0
// O_EXEC is a special one for opening a node for
// execution
#define O_EXEC (1 << 2)
#define O_ACCMODE 00000003
#define O_RDONLY 00000000
#define O_WRONLY 00000001
#define O_RDWR 00000002
#define O_CREAT 00000100
// #define O_EXCL 00000200
// #define O_NOCTTY 00000400
#define O_TRUNC 00001000
#define O_APPEND 00002000
// #define O_NONBLOCK 00004000
// #define O_DSYNC 00010000
// #define FASYNC 00020000
// #define O_DIRECT 00040000
// #define O_LARGEFILE 00100000
#define O_DIRECTORY 00200000
// #define O_NOFOLLOW 00400000
// #define O_NOATIME 01000000
// #define O_CLOEXEC 02000000

View File

@ -1,47 +0,0 @@
#pragma once
#include "sys/fs/node.h"
#include "sys/blk.h"
// Means that the filesystem has a weird way of storing hierarchical
// nodes and employs a custom mapping algorithm. This ensures that
// at mount time the whole node tree for the filesystem is mapped
// to the VFS tree and the nodes do not get deallocated until the
// FS is unmounted.
// Note: when this flag is on, get_root is not used, as the filesystem
// produces the VFS tree all by itself.
#define FS_NODE_MAPPER (1 << 0)
struct statvfs;
struct vfs_node;
struct fs_class {
char name[256];
int opt;
vnode_t *(*get_root) (fs_t *fs);
int (*mount) (fs_t *fs, const char *opt);
int (*umount) (fs_t *fs);
int (*statvfs) (fs_t *fs, struct statvfs *st);
int (*mapper) (fs_t *fs, struct vfs_node **root);
};
// The actual filesystem instance,
// one per each mount
struct fs {
// Mount details here
vnode_t *mnt_at;
// Block device on which the filesystem resides
struct blkdev *blk;
// Private data structure per-mount
void *fs_private;
struct fs_class *cls;
};
struct fs *fs_create(struct fs_class *cls, struct blkdev *blk, vnode_t *mnt_at);
void fs_release(struct fs *fs);
struct fs_class *fs_class_by_name(const char *name);
int fs_class_register(struct fs_class *cls);

View File

@ -1,34 +0,0 @@
#pragma once
#include <sys/types.h>
#include <stdint.h>
typedef struct hash_entry {
uint64_t key;
void *value;
struct hash_entry *next;
} hash_entry_t;
typedef struct {
int (*keycmp) (uint64_t, uint64_t);
uint64_t (*keyhsh) (uint64_t);
uint64_t (*keydup) (uint64_t);
void (*keyfree) (uint64_t);
void (*valfree) (void *);
size_t bucket_count;
size_t item_count;
hash_entry_t **buckets;
} hash_t;
void hash_init(hash_t *h, int nb);
void hash_walk(hash_t *h, int (*wlkfn) (hash_entry_t *));
void hash_clear(hash_t *h);
void hash_put(hash_t *h, uint64_t key, void *value);
int hash_del(hash_t *h, uint64_t key);
int hash_get(hash_t *h, uint64_t key, void **value);
// Helper functions
int hash_u64_keycmp(uint64_t v0, uint64_t v1);
uint64_t hash_u64_keyhsh(uint64_t v0);

View File

@ -1,7 +0,0 @@
#pragma once
typedef struct list_simple {
void *car;
struct list_simple *cdr;
} list_simple_t;

View File

@ -1,80 +0,0 @@
/** vim: ft=c.doxygen
* @file node.h
* @brief vnode
*/
#pragma once
#include <stdint.h>
#include "sys/types.h"
#include "dirent.h"
#include "stat.h"
struct ofile;
struct vfs_ioctx;
typedef struct vnode vnode_t;
typedef struct fs fs_t;
enum vnode_type {
VN_REG,
VN_DIR,
VN_BLK,
VN_CHR,
VN_LNK
};
/**
* @brief Set of functions implemented by filesystem driver
*/
struct vnode_operations {
// File tree traversal, node instance operations
int (*find) (vnode_t *node, const char *path, vnode_t **res);
void (*destroy) (vnode_t *node);
// Symlink
int (*readlink) (vnode_t *node, char *path);
int (*symlink) (vnode_t *at, struct vfs_ioctx *ctx, const char *name, const char *dst);
// File entry operations
int (*access) (vnode_t *node, uid_t *uid, gid_t *gid, mode_t *mode);
int (*creat) (vnode_t *node, struct vfs_ioctx *ctx, const char *name, mode_t mode, int opt, vnode_t **res);
int (*mkdir) (vnode_t *at, const char *name, mode_t mode);
int (*unlink) (vnode_t *at, vnode_t *vn, const char *name);
int (*stat) (vnode_t *node, struct stat *st);
int (*chmod) (vnode_t *node, mode_t mode);
int (*chown) (vnode_t *node, uid_t uid, gid_t gid);
// Directory access
int (*opendir) (vnode_t *node, int opt);
int (*readdir) (struct ofile *fd);
// File access
int (*open) (vnode_t *node, int opt);
void (*close) (struct ofile *fd);
ssize_t (*read) (struct ofile *fd, void *buf, size_t count);
ssize_t (*write) (struct ofile *fd, const void *buf, size_t count);
int (*truncate) (struct ofile *fd, size_t length);
};
struct vnode {
enum vnode_type type;
uint32_t refcount;
fs_t *fs;
// Private filesystem-specific data (like inode struct)
void *fs_data;
// Private filesystem-specific number (like inode number)
uint32_t fs_number;
/*
* (struct blkdev *) if type == VN_BLK
* (struct chrdev *) if type == VN_CHR
*/
void *dev;
void *tree_node;
struct vnode_operations *op;
};
void vnode_ref(vnode_t *vn);
void vnode_unref(vnode_t *vn);
void vnode_free(vnode_t *vn);

View File

@ -1,11 +0,0 @@
#pragma once
#include "node.h"
#include <sys/types.h>
struct ofile {
int flags;
vnode_t *vnode;
size_t pos;
// Dirent buffer
char dirent_buf[512];
};

View File

@ -1,59 +0,0 @@
/** vi: ft=c.doxygen :
* @file stat.h
* @brief File status structure
*/
#pragma once
#include <stdint.h>
#include "sys/types.h"
#define S_IFMT 0170000
#define S_IFSOCK 0140000
#define S_IFLNK 0120000
#define S_IFREG 0100000
#define S_IFBLK 0060000
#define S_IFDIR 0040000
#define S_IFCHR 0020000
#define S_IFIFO 0010000
#define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK)
#define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
#define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
#define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK)
#define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
#define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR)
#define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO)
#define S_ISUID 04000
#define S_ISGID 02000
#define S_ISVTX 01000
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
struct stat {
uint32_t st_dev;
uint32_t st_ino;
mode_t st_mode;
uint32_t st_nlink;
uid_t st_uid;
gid_t st_gid;
uint32_t st_rdev;
uint32_t st_size;
uint32_t st_blksize;
uint32_t st_blocks;
uint32_t st_atime;
uint32_t st_mtime;
uint32_t st_ctime;
};

View File

@ -1,22 +0,0 @@
/** vi: ft=c.doxygen :
* @file statvfs.h
* @brief Filesystem status information
*/
#pragma once
#include <stdint.h>
typedef uint64_t fsblkcnt_t;
struct statvfs {
uint64_t f_bsize;
uint64_t f_frsize;
fsblkcnt_t f_blocks;
fsblkcnt_t f_bfree;
fsblkcnt_t f_bavail;
fsblkcnt_t f_files;
fsblkcnt_t f_ffree;
fsblkcnt_t f_favail;
uint64_t f_fsid;
uint64_t f_flag;
uint64_t f_namemax;
};

View File

@ -1,4 +0,0 @@
#pragma once
#include "sys/fs/fs.h"
void tarfs_init(void);

View File

@ -1,8 +0,0 @@
#pragma once
#include "list.h"
typedef struct tree {
void *value;
struct tree *parent;
list_simple_t *children;
} tree_t;

View File

@ -1,150 +0,0 @@
/** vi: ft=c.doxygen :
* @file vfs.h
* @brief Virtual filesystem (VFS) core functions
*/
#pragma once
#include "tree.h"
#include "node.h"
#include "ofile.h"
#include "stat.h"
#include "statvfs.h"
/**
* @brief Internal VFS tree node.
* As the actual vnodes are not associated
* with any location in the filesystem tree,
* we use this struct to keep things in order.
*/
struct vfs_node {
char name[256];
// Current vnode unless mnt, otherwise the root node of
// the mounted filesystem
vnode_t *vnode;
// Real vnode if mountpoint
vnode_t *real_vnode;
// Is 1 when node is a mountpoint
int ismount;
// Parent ref
struct vfs_node *parent;
// Linked list of children
struct vfs_node *child;
struct vfs_node *cdr;
};
/**
* @brief Process-specific I/O context details
* @note This will be moved to other headers once
* I integrate the VFS project into my kernel.
*/
struct vfs_ioctx {
// Process' current working directory
vnode_t *cwd_vnode;
uid_t uid;
gid_t gid;
};
/**
* @brief Set process' current working directory
* @param ctx I/O context
* @param cwd New CWD
* @return 0 on success, negative values on error
*/
int vfs_setcwd(struct vfs_ioctx *ctx, const char *cwd);
/**
* @brief Set process' working directory relative to the
* current one.
* @param ctx I/O context
* @param cwd_rel Relative/absolute path
* @return 0 on success, negative values on error
*/
int vfs_chdir(struct vfs_ioctx *ctx, const char *cwd_rel);
/**
* @brief Initialize the VFS
*/
void vfs_init(void);
/**
* @brief Dump the internal filesystem representation
*/
void vfs_dump_tree(void);
/**
* @brief Get a string representation of a path
* inside a filesystem tree.
* @param path The result path
* @param vn vnode
*/
void vfs_vnode_path(char *path, vnode_t *vn);
// Tree node ops
/**
* @brief Free internal VFS node struct
* @param n Tree node
*/
void vfs_node_free(struct vfs_node *n);
/**
* @brief Allocate a new node and associate it with
* a vnode
* @param name Name to be given to the tree node
* @param vn The vnode to bind it to
* @return Non-NULL (struct vfs_node *) on success, NULL otherwise
*/
struct vfs_node *vfs_node_create(const char *name, vnode_t *vn);
/**
* @brief Create a mountpoint in a filesystem tree so that
* a "source" directory actually refers to the root
* node of a "target" filesystem.
* @param ctx I/O context
* @param at Path to create mountpoint at
* @param blk Block device on which a filesystem shall be mounted
* @param fs_name Filesystem name
* @param fs_opt Filesystem mounting options
* @return 0 on success,
* -EACCES if the caller context's UID is not zero,
* -EBUSY if trying to create a mountpoint at a
* directory which is not empty,
* -ENOENT if the directory does not exist
*/
int vfs_mount(struct vfs_ioctx *ctx, const char *at, void *blk, const char *fs_name, const char *fs_opt);
/**
* @brief Destroy a mountpoint in a filesystem tree
* @param ctx I/O context
* @param target Path to unmount
* @return 0 on success,
* -EBUSY if there are any used filesystem objects inside
* the mountpoint,
* -EACCES if the caller context's UID is not zero,
* -ENOENT if the directory does not exist
*/
int vfs_umount(struct vfs_ioctx *ctx, const char *target);
/**
* @brief Read symlink's destination path into a buffer
* @param ctx I/O context
* @param path
*/
int vfs_readlink(struct vfs_ioctx *ctx, const char *path, char *buf);
int vfs_readlinkat(struct vfs_ioctx *ctx, vnode_t *at, const char *path, char *buf);
int vfs_symlink(struct vfs_ioctx *ctx, const char *target, const char *linkpath);
// File ops
int vfs_truncate(struct vfs_ioctx *ctx, struct ofile *fd, size_t length);
int vfs_creat(struct vfs_ioctx *ctx, struct ofile *fd, const char *path, int mode, int opt);
int vfs_open(struct vfs_ioctx *ctx, struct ofile *fd, const char *path, int mode, int opt);
int vfs_open_node(struct vfs_ioctx *ctx, struct ofile *fd, vnode_t *vn, int opt);
void vfs_close(struct vfs_ioctx *ctx, struct ofile *fd);
ssize_t vfs_read(struct vfs_ioctx *ctx, struct ofile *fd, void *buf, size_t count);
ssize_t vfs_write(struct vfs_ioctx *ctx, struct ofile *fd, const void *buf, size_t count);
int vfs_unlink(struct vfs_ioctx *ctx, const char *path);
int vfs_stat(struct vfs_ioctx *ctx, const char *path, struct stat *st);
int vfs_statat(struct vfs_ioctx *ctx, vnode_t *at, const char *path, struct stat *st);
int vfs_chmod(struct vfs_ioctx *ctx, const char *path, mode_t mode);
int vfs_chown(struct vfs_ioctx *ctx, const char *path, uid_t uid, gid_t gid);
int vfs_access(struct vfs_ioctx *ctx, const char *path, int mode);
// Directroy ops
int vfs_mkdir(struct vfs_ioctx *ctx, const char *path, mode_t mode);
struct dirent *vfs_readdir(struct vfs_ioctx *ctx, struct ofile *fd);
int vfs_statvfs(struct vfs_ioctx *ctx, const char *path, struct statvfs *st);

View File

@ -1,53 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file sys/heap.h
* @brief Kernel heap memory managament functions
*/
#pragma once
#include "sys/types.h"
/**
* @brief Common kernel heap alloc
* @see heap_alloc
*/
#define kmalloc(sz) heap_alloc(heap_global, sz)
/**
* @brief Common kernel heap free
* @see heal_free
*/
#define kfree(p) heap_free(heap_global, p)
/// Opaque type for kernel heap usage
typedef struct kernel_heap heap_t;
/// Implementations provide at least global heap
extern heap_t *heap_global;
/**
* @brief Allocate `count' bytes
* @param heap Heap instance
* @param count Number of bytes to allocate
* @return Virtual address of the block on success,
* NULL otherwise
*/
void *heap_alloc(heap_t *heap, size_t count);
/**
* @brief Make memory block at `ptr' usable again if `ptr' is non-NULL
* @param heap Heap instance
* @param ptr Pointer to a heap block or NULL
* @warning ptr must be a valid pointer allocated from the heap, otherwise
* kernel panic is raised
*/
void heap_free(heap_t *heap, void *ptr);
/**
* @brief Estimate heap free memory size
* @param heap Heap instance
* @return Approximate number of usable bytes
*/
size_t heap_info_free(heap_t *heap);
#if defined(ARCH_AMD64)
#include "sys/amd64/mm/heap.h"
#endif

View File

@ -1,10 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file sys/kidle.h
* @brief Kernel idle process
*/
#pragma once
/**
* @brief Sets up [kidle] process and adds it to sched
*/
void kidle_init(void);

View File

@ -1,10 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file sys/mem.h
* @brief Generic memory operations
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
void *memset(void *blk, int v, size_t sz);
void *memcpy(void *dst, const void *src, size_t sz);

View File

@ -1,141 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file sys/mm.h
* @brief Virtual memory space management functions
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
#if defined(ARCH_AMD64)
#include "sys/amd64/mm.h"
#endif
/// An invalid address analogous to NULL
#define MM_NADDR ((uintptr_t) -1)
#define MM_CLONE_FLG_KERNEL (1 << 0)
#define MM_CLONE_FLG_USER (1 << 1)
#define userspace
/**
* @brief Creates a virtual memory space with underlying data structures specific to current
* platform
*/
mm_space_t mm_space_create(void);
/**
* @brief Copies the mappings from one memory space to another preserving the original physical
* pages
* @param dst - Destination space
* @param src - Source space
* @param flags - Flags:
* * MM_CLONE_FLG_KERNEL - clone kernel-region mappings
* * MM_CLONE_FLG_USER - clone userspace mappings
* @return 0 on success
* @return Non-zero values in case of error
*/
int mm_space_clone(mm_space_t dst, const mm_space_t src, uint32_t flags);
/**
* @brief Performs a "fork" of a memory space: copies the original mappings to the destination space
* and optionally replaces userspace mappings with cloned physical pages
* @param dst - Destination space
* @param src - Source space
* @param flags - Flags:
* * MM_CLONE_FLG_KERNEL - clone kernel-region mappings
* * MM_CLONE_FLG_USER - clone userspace mappings and underlying physical pages
* @return 0 on success
* @return Non-zero values in case of error
*/
int mm_space_fork(mm_space_t dst, const mm_space_t src, uint32_t flags);
/**
* @brief Destroy the virtual memory space and free used resources
* @param pd - Virtual memory space
*/
void mm_space_free(mm_space_t pd);
/**
* @brief Dump debug information about the memory space
* @param pd - Virtual memory space
*/
void mm_describe(const mm_space_t pd);
/**
* @brief Map a contiguous physical memory region to a contiguous virtual memory region
* @param pd - Memory space
* @param virt_base - Beginning of the virtual memory range
* @param phys_base - Beginning of the physical memory range
* @param count - Count of pages to be mapped
* @param flags - Flags:
* * MM_FLG_WR - Writable
* * MM_FLG_US - Available for userspace
* @return 0 on success
* @return Non-zero values in case of error
*/
int mm_map_pages_contiguous(mm_space_t pd, uintptr_t virt_base, uintptr_t phys_base, size_t count, uint32_t flags);
/**
* @brief Map a set of physical pages to a virtual memory region
* @param pd - Memory space
* @param virt_base - Beginning of the virtual memory range
* @param pages - Array of physical pages to be mapped
* @param count - Count of pages to be mapped
* @param flags - Flags:
* * MM_FLG_WR - Writable
* * MM_FLG_US - Available for userspace
* @return 0 on success
* @return Non-zero values in case of error
*/
int mm_map_range_pages(mm_space_t pd, uintptr_t virt_base, uintptr_t *pages, size_t count, uint32_t flags);
/**
* @brief Remove virtual memory mappings for the specified region, optionally de-allocating the
* underlying physical memory pages
* @param pd - Memory space
* @param virt_base - Beginning of the virtual memory range
* @param count - Count of pages to unmap
* @param flags - Flags:
* * MM_FLG_NOPHYS - Don't de-allocate the physical pages used by the mappings
* @return 0 on success
* @return Non-zero values in case of error
*/
int mm_umap_range(mm_space_t pd, uintptr_t virt_base, size_t count, uint32_t flags);
/**
* @brief Translate a virtual memory address to its physical counterpart
* @param pd - Memory space
* @param virt - Virtual address
* @param rflags - (output, nullable) variable to store the mapping's flags:
* * MM_FLG_WR
* * MM_FLG_US
* @return Physical address if the mapping is present
* @return MM_NADDR if the mapping is not present
*/
uintptr_t mm_translate(mm_space_t pd, uintptr_t virt, uint32_t *rflags);
/**
* @brief Copy data from kernel memory space to user
* @param pd - Memory space
* @param dst - Destination address
* @param src - Source address
* @param count - Number of bytes to transfer
* @return Number of bytes copied on success
* @return -1 on error
*/
int mm_memcpy_kernel_to_user(mm_space_t pd, userspace void *dst, const void *src, size_t count);
/**
* @brief Copy data from user memory space to kernel
* @param pd - Memory space
* @param dst - Destination address
* @param src - Source address
* @param count - Number of bytes to transfer
* @return Number of bytes copied on success
* @return -1 on error
*/
int mm_memcpy_user_to_kernel(mm_space_t pd, void *dst, const userspace void *src, size_t count);

View File

@ -1,17 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file sys/panic.h
* @brief Kernel assertion-testing and critical failure functions
*/
#pragma once
#include <stdarg.h>
#include <stdint.h>
#define panic(f, ...) panicf("[%s] " f, __func__, ##__VA_ARGS__)
#if defined(ARCH_AMD64)
#define __idle_halt() asm volatile ("cli; hlt")
#endif
#define panic_hlt() do { __idle_halt(); } while (1)
void panicf(const char *fmt, ...) __attribute__((noreturn));

View File

@ -1,14 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file sys/sched.h
* @brief Multitasking scheduler control and process management
*/
#pragma once
#include "sys/thread.h"
/**
* @brief Add a thread to process queue
* @param t Thread
* @returns Assigned PID of the newly added thread on success,
* -1 on failure
*/
pid_t sched_add(thread_t *t);

View File

@ -1,17 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file sys/string.h
* @brief Generic string operations
*/
#pragma once
#include "sys/types.h"
void *memcpy(void *restrict dst, const void *restrict src, size_t cnt);
void *memmove(void *dst, const void *src, size_t cnt);
size_t strlen(const char *s);
int strncmp(const char *a, const char *b, size_t lim);
int strcmp(const char *a, const char *b);
char *strchr(const char *a, int c);
char *strrchr(const char *a, int c);
char *strcpy(char *dst, const char *src);
char *strncpy(char *dst, const char *src, size_t lim);

View File

@ -1,14 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file sys/syscall.h
* @brief System call interface definitions
*/
#pragma once
#include "sys/types.h"
// Defined here so no need to include mm.h
#define userspace
// System call numbers
#define SYS_NR_READ 0
#define SYS_NR_WRITE 1

View File

@ -1,94 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file sys/thread.h
* @brief Multithreading and thread context manipulation functions
* @note For now, let's define `thread' the same as `process'
*/
#pragma once
#include "sys/fs/ofile.h"
#include "sys/fs/vfs.h"
#include "sys/types.h"
#include "sys/mm.h"
#define THREAD_KERNEL (1 << 0)
/**
* @brief Process ID type (Thread ID, too)
*/
typedef int32_t pid_t;
/**
* @brief Opaque type for thread, details are platform-specific
*/
typedef struct thread thread_t;
/**
* @brief Generic thread information
* @note Platform-specific implementations provide thread_get(t) macro
* to extract this.
*/
typedef struct thread_info {
pid_t pid;
pid_t parent;
uint32_t flags;
uint32_t status;
struct ofile fds[8];
struct vfs_ioctx ioctx;
mm_space_t space;
} thread_info_t;
#if defined(ARCH_AMD64)
#include "sys/amd64/sys/thread.h"
#endif
////////
/**
* @brief Current thread context
*/
extern thread_t *sched_current;
/**
* @brief Initialize thread information struct
* @param info Thread info struct
*/
int thread_info_init(thread_info_t *info);
////////
/**
* @brief Setup thread data structures
* @param t Thread
*/
int thread_init(thread_t *t,
mm_space_t space,
uintptr_t ip,
uintptr_t kstack_base,
size_t kstack_size,
uintptr_t ustack_base,
size_t ustack_size,
uint32_t flags);
/**
* @brief Set thread instruction pointer
* @param t Thread
* @param ip Address of entry point
* @note In order for this function to handle kernel threads properly,
* set THREAD_KERNEL flag @b before calling this one.
*/
void thread_set_ip(thread_t *t, uintptr_t ip);
/**
* @brief Set thread memory space
* @param t Thread
* @param pd Virtual memory space
*/
void thread_set_space(thread_t *t, mm_space_t pd);
/**
* @brief Set thread userspace stack
* @param t Thread
* @param bottom Start address of the stack
* @param size Size of the user stack in bytes
* @warning Will panic if thread is kernel-space
*/
void thread_set_ustack(thread_t *t, uintptr_t bottom, size_t size);

View File

@ -1,16 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file sys/time.h
* @brief Kernel timer values
*/
#pragma once
#include <stdint.h>
/**
* @brief Desired resolution of systick timer in Hz
*/
#define SYSTICK_RES 1000
/**
* @brief Kernel timer tick counter
*/
extern volatile uint64_t systick;

View File

@ -1,7 +0,0 @@
#pragma once
#include "sys/fs/node.h"
extern vnode_t *tty0;
void tty_buffer_write(int n, char c);
void tty_init(void);

View File

@ -1,13 +0,0 @@
#pragma once
#include <stdint.h>
#ifndef NULL
#define NULL ((void *) 0)
#endif
typedef uintptr_t size_t;
typedef intptr_t ssize_t;
typedef uint32_t mode_t;
typedef uint32_t uid_t;
typedef uint32_t gid_t;

View File

@ -1,46 +0,0 @@
/** vim: set ft=cpp.doxygen :
* @file sys/vmalloc.h
* @brief Contiguous virtual memory range management functions
*/
#pragma once
#include "sys/mm.h"
#define VM_ALLOC_USER (1 << 0)
#define VM_ALLOC_WRITE (1 << 1)
/**
* @brief Find a free contiguous memory range inside a given one
* in a virtual memory space.
* @param pd Virtual memory space
* @param from Start of the range to allocate from
* @param to End of the range to allocate from
* @param npages Size of the needed range in 4K pages
* @return Address of the resulting range on success,
* MM_NADDR if such range cannot be allocated
*/
uintptr_t vmfind(const mm_space_t pd, uintptr_t from, uintptr_t to, size_t npages);
/**
* @brief Allocate a contiguous virtual memory range in a space
* within `from'..`to' limits and map it to a set of
* physical pages (which may not be contiguous).
* @param pd Virtual memory space
* @param from Start of the range to allocate from
* @param to End of the range to allocate from
* @param npages Count of 4K pages to allocate
* @param flags:
* * VM_ALLOC_USER - The range is available for userspace
* * VM_ALLOC_WRITE - The range is writable
* @return Virtual address of the resulting range on success,
* MM_NADDR otherwise
*/
uintptr_t vmalloc(mm_space_t pd, uintptr_t from, uintptr_t to, size_t npages, int flags);
/**
* @brief Deallocate a virtual memory range and physical pages
* it's mapped to.
* @param pd Virtual memory space
* @param addr Address of the beginning of the range
* @param npages Size of the range in 4K pages
*/
void vmfree(mm_space_t pd, uintptr_t addr, size_t npages);

View File

@ -1,82 +0,0 @@
#include "sys/amd64/acpi/hpet.h"
#include "sys/amd64/acpi/tables.h"
#include "sys/amd64/hw/timer.h"
#include "sys/assert.h"
#include "sys/panic.h"
#include "sys/debug.h"
#include "sys/time.h"
#include "sys/mm.h"
#define HPET_ENABLE_CNF (1 << 0)
#define HPET_LEG_RT_CNF (1 << 1)
#define HPET_Tn_INT_TYPE_CNF (1 << 1)
#define HPET_Tn_INT_ENB_CNF (1 << 2)
#define HPET_Tn_TYPE_CNF (1 << 3)
#define HPET_Tn_PER_INT_CAP (1 << 4)
#define HPET_Tn_SIZE_CAP (1 << 5)
#define HPET_Tn_VAL_SET_CNF (1 << 6)
#define HPET_Tn_32MODE_CNF (1 << 8)
#define HPET_Tn_INT_ROUTE_OFF (9)
#define HPET_Tn_FSB_EN_CNF (1 << 14)
#define HPET_Tn_FSB_INT_DEL_CAP (1 << 15)
struct hpet_timer_block {
uint64_t ctrl;
uint64_t value;
uint64_t fsb_int_rt;
uint64_t res;
};
struct hpet {
uint64_t caps;
uint64_t res0;
uint64_t ctrl;
uint64_t res1;
uint64_t intr;
char res2[200];
uint64_t count;
uint64_t res3;
struct hpet_timer_block timers[2];
};
static uint64_t hpet_freq;
static uint64_t hpet_last;
static uint64_t hpet_systick_res;
static uintptr_t hpet_base = 0;
static struct hpet *volatile hpet;
void acpi_hpet_set_base(uintptr_t v) {
hpet_base = v;
}
static void acpi_hpet_tick(void) {
uint64_t hpet_count = hpet->count;
systick += (hpet_count - hpet_last) / hpet_systick_res;
hpet_last = hpet_count;
hpet->intr |= 1;
}
int acpi_hpet_init(void) {
if (!hpet_base) {
return -1;
}
hpet = (struct hpet *) MM_VIRTUALIZE(hpet_base);
kdebug("HPET = %p\n", hpet);
uint64_t hpet_clk = (hpet->caps >> 32) & 0xFFFFFFFF;
assert(hpet_clk != 0, "HPET does not work correctly\n");
hpet_freq = 1000000000000000ULL / hpet_clk;
assert(hpet->timers[0].ctrl & HPET_Tn_PER_INT_CAP, "HPET does not support periodic interrupts\n");
hpet->ctrl |= HPET_ENABLE_CNF | HPET_LEG_RT_CNF;
hpet->timers[0].ctrl = HPET_Tn_INT_ENB_CNF | HPET_Tn_VAL_SET_CNF | HPET_Tn_TYPE_CNF;
hpet->timers[0].value = hpet->count + hpet_freq / SYSTICK_RES;
hpet_last = hpet->count;
hpet_systick_res = hpet_freq / SYSTICK_RES;
amd64_timer_tick = acpi_hpet_tick;
return 0;
}

View File

@ -1,130 +0,0 @@
#include "sys/amd64/acpi/tables.h"
#include "sys/amd64/acpi/hpet.h"
#include "sys/string.h"
#include "sys/assert.h"
#include "sys/panic.h"
#include "sys/debug.h"
#include "sys/mem.h"
#include "sys/mm.h"
#define ACPI_SIGN_RSDP "RSD PTR "
#define ACPI_SIGN_FADT "FACP"
#define ACPI_SIGN_APIC "APIC"
#define ACPI_SIGN_HPET "HPET"
static const char *acpi_table_type_name[ACPI_TABLE_TYPE_COUNT] = {
ACPI_SIGN_FADT,
ACPI_SIGN_APIC,
ACPI_SIGN_HPET
};
uintptr_t acpi_tables[ACPI_TABLE_TYPE_COUNT];
static char acpi_checksum(const void *block, size_t count) {
char r = 0;
for (size_t i = 0; i < count; ++i) {
r += ((const char *) block)[i];
}
return r;
}
static int acpi_xsdp_read(const struct acpi_rsdp_extended *xsdp) {
panic("Not yet implemented\n");
return 0;
}
static int acpi_rsdp_read(const struct acpi_rsdp *rsdp) {
struct acpi_rsdt *rsdt = (struct acpi_rsdt *) MM_VIRTUALIZE(rsdp->rsdt_addr);
assert(!strncmp(rsdt->header.signature, "RSDT", 4), "RSDP does not point to a valid RSDT\n");
assert(acpi_checksum(rsdt, rsdt->header.length) == 0, "RSDT checksum is invalid\n");
uint32_t nentr = (rsdt->header.length - sizeof(struct acpi_sdt_header)) / 4;
kdebug("RSDT contains %u entries\n", nentr);
// Dump entries
for (uint32_t i = 0; i < nentr; ++i) {
struct acpi_sdt_header *header = (struct acpi_sdt_header *) MM_VIRTUALIZE(rsdt->entries[i]);
// Find out the type of the table
for (size_t j = 0; j < ACPI_TABLE_TYPE_COUNT; ++j) {
if (!strncmp(header->signature, acpi_table_type_name[j], 4)) {
kdebug("%u: %s @ %p\n", i, acpi_table_type_name[j], header);
assert(acpi_checksum(header, header->length) == 0, "Table is invalid: %s\n", acpi_table_type_name[j]);
acpi_tables[j] = (uintptr_t) header;
continue;
}
}
// Ignore the table otherwise - it's unknown to us
}
// Must have FADT table
assert(acpi_tables[ACPI_FADT] != MM_NADDR, "RSDT is missing FADT\n");
return 0;
}
int acpi_tables_init(void) {
memset(acpi_tables, 0xFF, sizeof(acpi_tables));
kdebug("Trying to locate ACPI tables\n");
struct acpi_rsdp *rsdp = (struct acpi_rsdp *) MM_NADDR;
struct acpi_rsdp_extended *xsdp = (struct acpi_rsdp_extended *) MM_NADDR;
// 1. Try locating in EBDA
uintptr_t ebda_base = ((uintptr_t) (*((uint16_t *) MM_VIRTUALIZE(0x040E)))) << 4;
ebda_base = MM_VIRTUALIZE(ebda_base);
kdebug("Possible EBDA location: %p\n", ebda_base);
for (uintptr_t addr = ebda_base & ~0xF; addr < ebda_base + 1024; ++addr) {
if (!strncmp((const char *) addr, ACPI_SIGN_RSDP, 8)) {
rsdp = (struct acpi_rsdp *) addr;
if (acpi_checksum(rsdp, sizeof(struct acpi_rsdp))) {
rsdp = (struct acpi_rsdp *) MM_NADDR;
continue;
}
kdebug("Found RSDP in EBDA @ %p\n", addr);
break;
}
}
// 2. Try searching in 0xE0000 - 0xFFFFF
for (uintptr_t addr = MM_VIRTUALIZE(0xE0000); addr < MM_VIRTUALIZE(0xFFFFF); ++addr) {
if (!strncmp((const char *) addr, ACPI_SIGN_RSDP, 8)) {
rsdp = (struct acpi_rsdp *) addr;
if (acpi_checksum(rsdp, sizeof(struct acpi_rsdp))) {
rsdp = (struct acpi_rsdp *) MM_NADDR;
continue;
}
kdebug("Found RSDP in BIOS romem @ %p\n", addr);
break;
}
}
if (rsdp == (struct acpi_rsdp *) MM_NADDR) {
return -1;
}
kdebug("RSDP revision is %d\n", rsdp->rev);
// Check if RSDP is an extended one
if (rsdp->rev == 2) {
xsdp = (struct acpi_rsdp_extended *) rsdp;
if (acpi_xsdp_read(xsdp) != 0) {
return -1;
}
} else {
kdebug("Falling back to ACPI 1.0\n");
if (acpi_rsdp_read(rsdp) != 0) {
return -1;
}
}
// Extract HPET
if (acpi_tables[ACPI_HPET] != MM_NADDR) {
struct acpi_hpet *hpet_table = (struct acpi_hpet *) acpi_tables[ACPI_HPET];
assert(hpet_table->base_address.space_id == 0, "HPET is not memory-mapped (what?)\n");
acpi_hpet_set_base(hpet_table->base_address.pointer);
}
return 0;
}

View File

@ -3,32 +3,8 @@ include sys/amd64/compiler.mk
all:
### Kernel build
DEFINES+=-DARCH_AMD64
OBJS+=$(O)/sys/amd64/kernel.o \
$(O)/sys/amd64/mm/pool.o \
$(O)/sys/amd64/mm/mm.o \
$(O)/sys/amd64/hw/rs232.o \
$(O)/sys/amd64/hw/gdt.o \
$(O)/sys/amd64/hw/gdt_s.o \
$(O)/sys/amd64/hw/idt.o \
$(O)/sys/amd64/hw/ints.o \
$(O)/sys/amd64/hw/exc.o \
$(O)/sys/amd64/hw/regs.o \
$(O)/sys/amd64/hw/irq0.o \
$(O)/sys/amd64/hw/pic8259.o \
$(O)/sys/amd64/hw/irqs.o \
$(O)/sys/amd64/mm/map.o \
$(O)/sys/amd64/hw/timer.o \
$(O)/sys/amd64/acpi/tables.o \
$(O)/sys/amd64/acpi/hpet.o \
$(O)/sys/amd64/mm/phys.o \
$(O)/sys/amd64/mm/heap.o \
$(O)/sys/amd64/mm/vmalloc.o \
$(O)/sys/amd64/sys/thread.o \
$(O)/sys/amd64/sys/syscall.o \
$(O)/sys/amd64/sys/syscall_s.o \
$(O)/sys/amd64/sys/kidle.o \
$(O)/sys/amd64/hw/irq.o \
$(O)/sys/amd64/hw/ps2.o
OBJS+=$(O)/sys/amd64/hw/rs232.o \
$(O)/sys/amd64/string.o
kernel_OBJS=$(O)/sys/amd64/entry.o \
$(OBJS)
kernel_LINKER=sys/amd64/link.ld
@ -56,11 +32,8 @@ kernel_CFLAGS=-ffreestanding \
-mno-sse \
-mno-sse2 \
-z max-page-size=0x1000
DIRS+=$(O)/sys/amd64/mm \
$(O)/sys/amd64/hw \
$(O)/sys/amd64/acpi \
$(O)/sys/amd64/sys \
$(O)/sys/amd64/image/boot/grub
DIRS+=$(O)/sys/amd64/image/boot/grub \
$(O)/sys/amd64/hw
# add .inc includes for asm
HEADERS+=$(shell find include -name "*.inc")

View File

@ -6,13 +6,19 @@ _start:
cli
movabsq $kernel_stack_top, %rsp
call kernel_main
leaq _msg_entry(%rip), %rsi
xorq %rdi, %rdi
call debugf
1:
cli
hlt
jmp 1b
.section .rodata
_msg_entry:
.string "Entered kernel\n"
.section .bss
kernel_stack_bottom:
.skip 65536

View File

@ -1,52 +0,0 @@
#include "sys/amd64/hw/ints.h"
#include "sys/amd64/mm/map.h"
#include "sys/amd64/regs.h"
#include "sys/debug.h"
uint64_t amd64_err_num, amd64_err_code;
void amd64_exc_handler(amd64_ctx_regs_t *regs) {
kfatal("Unhandled exception #%d\n", amd64_err_num);
amd64_ctx_dump(DEBUG_FATAL, regs);
if (amd64_err_num == 14) {
mm_space_t pml4 = (mm_space_t) MM_VIRTUALIZE(regs->cr3);
kfatal("This is a page fault\n");
uintptr_t cr2;
asm volatile ("movq %%cr2, %0":"=a"(cr2));
kfatal("cr2 = %p\n", cr2);
uint64_t flags;
uintptr_t paddr = amd64_map_get(pml4, cr2, &flags);
if (paddr == MM_NADDR) {
kfatal("Requested page is not present\n");
} else {
kfatal("Requested page physical address is %p\n", paddr);
}
kfatal("Error code: %p\n", amd64_err_code);
if (amd64_err_code & (1 << 0)) {
kfatal("[Present]\n");
}
if (amd64_err_code & (1 << 1)) {
kfatal("[Write]\n");
}
if (amd64_err_code & (1 << 2)) {
kfatal("[User]\n");
kfatal("Page \"user\" flag is %d\n", !!(flags & (1 << 2)));
}
if (amd64_err_code & (1 << 3)) {
kfatal("[Reserved Write]\n");
}
if (amd64_err_code & (1 << 4)) {
kfatal("[Instruction Fetch]\n");
}
}
while (1) {
asm volatile ("cli; hlt");
}
}

View File

@ -1,62 +0,0 @@
#include "sys/amd64/hw/gdt.h"
#include "sys/mem.h"
extern void amd64_reload_segs(void);
#define AMD64_GDT_SIZE 7
#define GDT_ACC_AC (1 << 0)
#define GDT_ACC_RW (1 << 1)
#define GDT_ACC_DC (1 << 2)
#define GDT_ACC_EX (1 << 3)
#define GDT_ACC_S (1 << 4)
#define GDT_ACC_R0 (0 << 5)
#define GDT_ACC_R1 (1 << 5)
#define GDT_ACC_R2 (2 << 5)
#define GDT_ACC_R3 (3 << 5)
#define GDT_ACC_PR (1 << 7)
#define GDT_FLG_LONG (1 << 5)
#define GDT_FLG_SZ (1 << 6)
#define GDT_FLG_GR (1 << 7)
amd64_tss_t amd64_tss;
static amd64_gdt_entry_t gdt[AMD64_GDT_SIZE];
static amd64_gdt_ptr_t gdtr;
static void amd64_gdt_set(int idx, uint32_t base, uint32_t limit, uint8_t flags, uint8_t access) {
gdt[idx].base_lo = base & 0xFFFF;
gdt[idx].base_mi = (base >> 16) & 0xFF;
gdt[idx].base_hi = (base >> 24) & 0xFF;
gdt[idx].access = access;
gdt[idx].flags = (flags & 0xF0) | ((limit >> 16) & 0xF);
gdt[idx].limit_lo = limit & 0xFFFF;
}
static void amd64_tss_setup(void) {
memset(&amd64_tss, 0, sizeof(amd64_tss));
}
void amd64_gdt_init(void) {
gdtr.size = sizeof(gdt) - 1;
gdtr.offset = (uintptr_t) gdt;
amd64_tss_setup();
amd64_gdt_set(0, 0, 0, 0, 0); // 0x00
amd64_gdt_set(1, 0, 0, GDT_FLG_LONG,
GDT_ACC_PR | GDT_ACC_R0 | GDT_ACC_EX | GDT_ACC_S | GDT_ACC_RW); // 0x08
amd64_gdt_set(2, 0, 0, 0,
GDT_ACC_PR | GDT_ACC_R0 | GDT_ACC_S | GDT_ACC_RW); // 0x10
amd64_gdt_set(4, 0, 0, GDT_FLG_LONG,
GDT_ACC_PR | GDT_ACC_R3 | GDT_ACC_EX | GDT_ACC_S | GDT_ACC_RW); // 0x18
amd64_gdt_set(3, 0, 0, 0,
GDT_ACC_PR | GDT_ACC_R3 | GDT_ACC_S | GDT_ACC_RW); // 0x20
amd64_gdt_set(5, ((uintptr_t) &amd64_tss) & 0xFFFFFFFF, sizeof(amd64_tss) - 1, GDT_FLG_LONG,
GDT_ACC_PR | GDT_ACC_AC | GDT_ACC_EX);
((uint64_t *) gdt)[6] = ((uintptr_t) &amd64_tss) >> 32;
asm volatile ("lea gdtr(%rip), %rax; lgdt (%rax)");
amd64_reload_segs();
asm volatile ("mov $0x28, %ax; ltr %ax");
}

View File

@ -1,21 +0,0 @@
.section .text
.global amd64_reload_segs
amd64_reload_segs:
cli
movabsq $.jmpbuf, %rax
rex.w ljmp *(%rax)
.reload_data:
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
ret
.jmpbuf:
.quad .reload_data
.word 0x08

View File

@ -1,161 +0,0 @@
#include "sys/amd64/hw/ints.h"
#include "sys/amd64/hw/pic8259.h"
#include "sys/mem.h"
#include <stdint.h>
#include <stddef.h>
#define ignore(x) if (0) {x = x;}
#define IDT_NENTR 256
#define IDT_FLG_TASK32 0x5
#define IDT_FLG_INT16 0x6
#define IDT_FLG_TRAP16 0x7
#define IDT_FLG_INT32 0xE
#define IDT_FLG_TRAP32 0xF
#define IDT_FLG_SS (1 << 4)
#define IDT_FLG_R0 (0 << 5)
#define IDT_FLG_R1 (1 << 5)
#define IDT_FLG_R2 (2 << 5)
#define IDT_FLG_R3 (3 << 5)
#define IDT_FLG_P (1 << 7)
extern void amd64_isr_0();
extern void amd64_isr_1();
extern void amd64_isr_2();
extern void amd64_isr_3();
extern void amd64_isr_4();
extern void amd64_isr_5();
extern void amd64_isr_6();
extern void amd64_isr_7();
extern void amd64_isr_8();
extern void amd64_isr_9();
extern void amd64_isr_10();
extern void amd64_isr_11();
extern void amd64_isr_12();
extern void amd64_isr_13();
extern void amd64_isr_14();
extern void amd64_isr_15();
extern void amd64_isr_16();
extern void amd64_isr_17();
extern void amd64_isr_18();
extern void amd64_isr_19();
extern void amd64_isr_20();
extern void amd64_isr_21();
extern void amd64_isr_22();
extern void amd64_isr_23();
extern void amd64_isr_24();
extern void amd64_isr_25();
extern void amd64_isr_26();
extern void amd64_isr_27();
extern void amd64_isr_28();
extern void amd64_isr_29();
extern void amd64_isr_30();
extern void amd64_isr_31();
extern void amd64_isr_syscall();
// 8259 PIC IRQs
extern void amd64_irq_0(); // Timer
extern void amd64_irq_1(); // TODO
extern void amd64_irq_2(); // TODO
extern void amd64_irq_3(); // TODO
extern void amd64_irq_4(); // TODO
extern void amd64_irq_5(); // TODO
extern void amd64_irq_6(); // TODO
extern void amd64_irq_7(); // TODO
extern void amd64_irq_8(); // TODO
extern void amd64_irq_9(); // TODO
extern void amd64_irq_10(); // TODO
extern void amd64_irq_11(); // TODO
extern void amd64_irq_12(); // TODO
extern void amd64_irq_13(); // TODO
extern void amd64_irq_14(); // TODO
extern void amd64_irq_15(); // TODO
typedef struct {
uint16_t base_lo;
uint16_t selector;
uint8_t zero;
uint8_t flags;
uint16_t base_hi;
uint32_t base_ex;
uint32_t zero1;
} amd64_idt_entry_t;
typedef struct {
uint16_t size;
uintptr_t offset;
} __attribute__((packed)) amd64_idt_ptr_t;
static amd64_idt_entry_t idt[IDT_NENTR];
static amd64_idt_ptr_t idtr;
void amd64_idt_set(int idx, uintptr_t base, uint16_t selector, uint8_t flags) {
idt[idx].base_lo = base & 0xFFFF;
idt[idx].base_hi = (base >> 16) & 0xFFFF;
idt[idx].base_ex = (base >> 32) & 0xFFFFFFFF;
idt[idx].selector = selector;
idt[idx].flags = flags;
idt[idx].zero = 0;
}
void amd64_idt_init(void) {
idtr.offset = (uintptr_t) idt;
idtr.size = sizeof(idt) - 1;
memset(idt, 0, sizeof(idt));
// Exceptions
amd64_idt_set(0 , (uintptr_t) amd64_isr_0 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(1 , (uintptr_t) amd64_isr_1 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(2 , (uintptr_t) amd64_isr_2 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(3 , (uintptr_t) amd64_isr_3 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(4 , (uintptr_t) amd64_isr_4 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(5 , (uintptr_t) amd64_isr_5 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(6 , (uintptr_t) amd64_isr_6 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(7 , (uintptr_t) amd64_isr_7 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(8 , (uintptr_t) amd64_isr_8 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(9 , (uintptr_t) amd64_isr_9 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(10, (uintptr_t) amd64_isr_10, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(11, (uintptr_t) amd64_isr_11, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(12, (uintptr_t) amd64_isr_12, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(13, (uintptr_t) amd64_isr_13, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(14, (uintptr_t) amd64_isr_14, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(15, (uintptr_t) amd64_isr_15, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(16, (uintptr_t) amd64_isr_16, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(17, (uintptr_t) amd64_isr_17, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(18, (uintptr_t) amd64_isr_18, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(19, (uintptr_t) amd64_isr_19, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(20, (uintptr_t) amd64_isr_20, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(21, (uintptr_t) amd64_isr_21, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(22, (uintptr_t) amd64_isr_22, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(23, (uintptr_t) amd64_isr_23, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(24, (uintptr_t) amd64_isr_24, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(25, (uintptr_t) amd64_isr_25, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(26, (uintptr_t) amd64_isr_26, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(27, (uintptr_t) amd64_isr_27, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(28, (uintptr_t) amd64_isr_28, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(29, (uintptr_t) amd64_isr_29, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(30, (uintptr_t) amd64_isr_30, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(31, (uintptr_t) amd64_isr_31, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 0 , (uintptr_t) amd64_irq_0 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 1 , (uintptr_t) amd64_irq_1 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 2 , (uintptr_t) amd64_irq_2 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 3 , (uintptr_t) amd64_irq_3 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 4 , (uintptr_t) amd64_irq_4 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 5 , (uintptr_t) amd64_irq_5 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 6 , (uintptr_t) amd64_irq_6 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 7 , (uintptr_t) amd64_irq_7 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 8 , (uintptr_t) amd64_irq_8 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 9 , (uintptr_t) amd64_irq_9 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 10, (uintptr_t) amd64_irq_10, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 11, (uintptr_t) amd64_irq_11, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 12, (uintptr_t) amd64_irq_12, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 13, (uintptr_t) amd64_irq_13, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 14, (uintptr_t) amd64_irq_14, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
amd64_idt_set(IRQ_BASE + 15, (uintptr_t) amd64_irq_15, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
asm volatile ("lea idtr(%%rip), %%rax; lidt (%%rax)":::"memory");
}

View File

@ -1,77 +0,0 @@
#include "sys/amd64/hw/int_macros.inc"
.section .text
.extern amd64_err_num
// For legacy system call interface (via int $0x80)
.global amd64_isr_syscall
__isr_generic:
cli
// TODO: preserve error codes
pushq %rax
mov 8(%rsp), %rax
mov %rax, amd64_err_num(%rip)
mov 16(%rsp), %rax
mov %rax, amd64_err_code(%rip)
popq %rax
add $16, %rsp
__int_push_ctx
movq %rsp, %rdi
call amd64_exc_handler
// TODO: allow handling and returning from an exception ISR
1:
hlt
jmp 1b
// ISR with error code
.macro __isr_yerr n
.global amd64_isr_\n
amd64_isr_\n:
pushq $\n
jmp __isr_generic
.endm
// ISR with no error code
.macro __isr_nerr n
.global amd64_isr_\n
amd64_isr_\n:
pushq $0
pushq $\n
jmp __isr_generic
.endm
__isr_nerr 0
__isr_nerr 1
__isr_nerr 2
__isr_nerr 3
__isr_nerr 4
__isr_nerr 5
__isr_nerr 6
__isr_nerr 7
__isr_yerr 8
__isr_nerr 9
__isr_yerr 10
__isr_yerr 11
__isr_yerr 12
__isr_yerr 13
__isr_yerr 14
__isr_nerr 15
__isr_nerr 16
__isr_yerr 17
__isr_nerr 18
__isr_nerr 19
__isr_nerr 20
__isr_nerr 21
__isr_nerr 22
__isr_nerr 23
__isr_nerr 24
__isr_nerr 25
__isr_nerr 26
__isr_nerr 27
__isr_nerr 28
__isr_nerr 29
__isr_yerr 30
__isr_nerr 31

View File

@ -1,17 +0,0 @@
#include "sys/amd64/regs.h"
#include "sys/debug.h"
#include "sys/panic.h"
#include "sys/amd64/hw/io.h"
#include "sys/amd64/hw/ps2.h"
void amd64_irq_handler(uint64_t n) {
if (n == 1) {
amd64_irq1();
}
// EOI
if (n > 8) {
panic("I forgot how to cascaded IRQs\n");
}
outb(0x20, 0x20);
}

View File

@ -1,45 +0,0 @@
#include "sys/amd64/hw/int_macros.inc"
.section .text
.global amd64_irq_0
.extern amd64_tss
amd64_irq_0:
cli
__int_push_ctx
// Store current RSP
movq sched_current(%rip), %rdi
test %rdi, %rdi
jz 1f
movq %rsp, (%rdi)
1:
movq amd64_timer_tick(%rip), %rax
callq *%rax
callq sched
test %rax, %rax
jnz __no_switch
// Load next task's RSP
movq sched_current(%rip), %rsi
test %rsi, %rsi
jz __no_switch
movq (%rsi), %rsp
movq %rsp, %rax
addq $((8 + 8 + 5 + 5) * 8), %rax
leaq amd64_tss(%rip), %rdi
movq %rax, 4(%rdi)
// TODO: TSS here
__no_switch:
// EOI
mov $0x20, %dx
mov $0x20, %al
outb %al, %dx
__int_pop_ctx
iretq

View File

@ -1,52 +0,0 @@
#include "sys/amd64/hw/int_macros.inc"
.section .text
.extern panicf
amd64_irq_nyi_msg:
.string "IRQ handler not implemented: %d\n"
.macro __irq_nyi_stub n
.global amd64_irq_\n
amd64_irq_\n:
cli
__int_push_ctx
// Store current RSP
movq sched_current(%rip), %rdi
test %rdi, %rdi
jz 1f
movq %rsp, (%rdi)
movq $\n, %rdi
call amd64_irq_handler
// Load next task's RSP
movq sched_current(%rip), %rsi
test %rsi, %rsi
jz 1f
movq (%rsi), %rsp
movq %rsp, %rax
addq $((8 + 8 + 5 + 5) * 8), %rax
leaq amd64_tss(%rip), %rdi
movq %rax, 4(%rdi)
1:
__int_pop_ctx
iretq
.endm
__irq_nyi_stub 1
__irq_nyi_stub 2
__irq_nyi_stub 3
__irq_nyi_stub 4
__irq_nyi_stub 5
__irq_nyi_stub 6
__irq_nyi_stub 7
__irq_nyi_stub 8
__irq_nyi_stub 9
__irq_nyi_stub 10
__irq_nyi_stub 11
__irq_nyi_stub 12
__irq_nyi_stub 13
__irq_nyi_stub 14
__irq_nyi_stub 15

View File

@ -1,62 +0,0 @@
#include "sys/amd64/hw/pic8259.h"
#include "sys/amd64/hw/io.h"
#define PIC_MCMD 0x20
#define PIC_MDAT 0x21
#define PIC_SCMD 0xA0
#define PIC_SDAT 0xA1
#define PIC_EOI 0x20
#define PIC_ICW1_ICW4 0x01
#define PIC_ICW1_SINGLE 0x02
#define PIC_ICW1_INTERVAL4 0x04
#define PIC_ICW1_LEVEL 0x08
#define PIC_ICW1_INIT 0x10
#define PIC_ICW4_8086 0x01
#define PIC_ICW4_AUTO 0x02
#define PIC_ICW4_BUF_SLAVE 0x08
#define PIC_ICW4_BUF_MASTER 0x0C
#define PIC_ICW4_SFNM 0x10
void pic8259_clear_mask(uint8_t line) {
uint16_t port;
uint8_t value;
if (line < 8) {
port = PIC_MDAT;
} else {
port = PIC_SDAT;
line -= 8;
}
value = inb(port) & ~(1 << line);
outb(port, value);
}
void pic8259_init(void) {
uint8_t a1, a2;
a1 = inb(PIC_MDAT);
a2 = inb(PIC_SDAT);
outb(PIC_MCMD, PIC_ICW1_INIT | PIC_ICW1_ICW4);
io_wait();
outb(PIC_SCMD, PIC_ICW1_INIT | PIC_ICW1_ICW4);
io_wait();
outb(PIC_MDAT, IRQ_BASE);
io_wait();
outb(PIC_SDAT, IRQ_BASE + 8);
io_wait();
outb(PIC_MDAT, 4);
io_wait();
outb(PIC_SDAT, 2);
io_wait();
outb(PIC_MDAT, PIC_ICW4_8086);
io_wait();
outb(PIC_SDAT, PIC_ICW4_8086);
io_wait();
outb(PIC_MDAT, a1);
outb(PIC_SDAT, a2);
}

View File

@ -1,29 +0,0 @@
#include "sys/tty.h"
#include "sys/amd64/hw/io.h"
#include "sys/debug.h"
static char _ps2_table0[] = {
[0x00] = 0, [0x01] = '\x033',
[0x02] = '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
[0x0C] = '-', '=', '\b', '\t',
[0x10] = 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',
[0x1A] = '[', ']', '\n', 0,
[0x1E] = 'a', 's', 'd', 'f', 'h', 'j', 'k', 'l',
[0x27] = ';', '\'', '`', 0, '\\',
[0x2C] = 'z', 'x', 'c', 'v', 'b', 'n', 'm',
[0x33] = ',', '.', '/', 0, '*', 0, ' ', 0,
[0xFF] = 0
};
void amd64_irq1(void) {
// Pop event from keyboard buffer
uint8_t ev = inb(0x60);
if (ev < 0x80) {
char sym = _ps2_table0[ev];
if (sym != 0) {
tty_buffer_write(0, sym);
}
}
}

View File

@ -1,37 +0,0 @@
#include "sys/amd64/regs.h"
#include "sys/mm.h"
#include "sys/debug.h"
void amd64_ctx_dump(int level, const amd64_ctx_regs_t *regs) {
if (regs->cr3 == MM_PHYS(mm_kernel)) {
kprint(level, "(CR3 points to kernel PML4)\n");
}
kprint(level, "rax = %p (%ld)\n", regs->gp.rax, regs->gp.rax);
kprint(level, "rcx = %p (%ld)\n", regs->gp.rcx, regs->gp.rcx);
kprint(level, "rdx = %p (%ld)\n", regs->gp.rdx, regs->gp.rdx);
kprint(level, "rbx = %p (%ld)\n", regs->gp.rbx, regs->gp.rbx);
kprint(level, "r8 = %p (%ld)\n", regs->gp.r8, regs->gp.r8);
kprint(level, "r9 = %p (%ld)\n", regs->gp.r9, regs->gp.r9);
kprint(level, "r10 = %p (%ld)\n", regs->gp.r10, regs->gp.r10);
kprint(level, "r11 = %p (%ld)\n", regs->gp.r11, regs->gp.r11);
kprint(level, "r12 = %p (%ld)\n", regs->gp.r12, regs->gp.r12);
kprint(level, "r13 = %p (%ld)\n", regs->gp.r13, regs->gp.r13);
kprint(level, "r14 = %p (%ld)\n", regs->gp.r14, regs->gp.r14);
kprint(level, "r15 = %p (%ld)\n", regs->gp.r15, regs->gp.r15);
if (regs->iret.cs == 0x08) {
// Print stack pointer before the exception occurred
kprint(level, "rsp = %p\n", regs->gp.rsp + sizeof(amd64_ctx_regs_t));
}
kprint(level, "rbp = %p\n", regs->gp.rbp);
kprint(level, "rsi = %p\n", regs->gp.rsi);
kprint(level, "rdi = %p\n", regs->gp.rdi);
kprint(level, "pc: %02x:%p\n", regs->iret.cs, regs->iret.rip);
if (regs->iret.cs != 0x08) {
kprint(level, "stack: %02x:%p\n", regs->iret.ss, regs->iret.rsp);
}
}

11
sys/amd64/hw/rs232.S Normal file
View File

@ -0,0 +1,11 @@
.section .text
.global rs232_send
rs232_send:
// %rdi - port
// %rsi - sym
movw %si, %ax
movw %di, %dx
outb %al, %dx
ret

View File

@ -1,11 +0,0 @@
#include "sys/amd64/hw/rs232.h"
#include "sys/amd64/hw/io.h"
void rs232_init(uint16_t port) {
// Do nothing yet
}
void rs232_send(uint16_t port, char v) {
while (!(inb(port + 5) & 0x20)) {}
outb(port, v);
}

View File

@ -1,56 +0,0 @@
#include "sys/amd64/hw/timer.h"
#include "sys/amd64/hw/io.h"
#include "sys/amd64/acpi/hpet.h"
#include "sys/debug.h"
// IO ports
#define PIT_CH0 0x40
#define PIT_CMD 0x43
// Select channel
#define PIT_BIT_CH0 (0x0 << 6)
#define PIT_BIT_CH1 (0x1 << 6)
#define PIT_BIT_CH2 (0x2 << 6)
// Access flags
#define PIT_ACC_LATCH (0x0 << 4)
#define PIT_ACC_LOW (0x1 << 4)
#define PIT_ACC_HIGH (0x2 << 4)
#define PIT_ACC_16 (0x3 << 4)
// Operation mode
#define PIT_MODE_CDOWN (0x0 << 1)
#define PIT_MODE_ONESH (0x1 << 1)
#define PIT_MODE_RATEG (0x2 << 1)
#define PIT_MODE_SQWAV (0x3 << 1)
#define PIT_MODE_SWSTR (0x4 << 1)
#define PIT_MODE_HWSTR (0x5 << 1)
// BCD/Binary mode
#define PIT_BCD_NO (0 << 0)
#define PIT_BCD_YES (0 << 1)
#define PIT_FREQ_BASE 1193182
uint64_t amd64_timer_ticks = 0;
void (*amd64_timer_tick) (void) = NULL;
static void pit8253_init(void) {
uint32_t div = PIT_FREQ_BASE / 1000;
outb(PIT_CMD, PIT_CH0 | PIT_BCD_NO | PIT_ACC_16 | PIT_MODE_RATEG);
outb(PIT_CH0, div & 0xFF);
outb(PIT_CH0, (div >> 8) & 0xFF);
}
static void pit8253_tick(void) {
++amd64_timer_ticks;
}
void amd64_timer_configure(void) {
if (acpi_hpet_init() != 0) {
kdebug("HPET is not available, falling back to PIT\n");
amd64_timer_tick = pit8253_tick;
pit8253_init();
}
}

View File

@ -1,188 +0,0 @@
#include "sys/mm.h"
#include "sys/debug.h"
#include "sys/panic.h"
#include "sys/amd64/hw/gdt.h"
#include "sys/amd64/hw/pic8259.h"
#include "sys/amd64/hw/ints.h"
#include "sys/amd64/hw/timer.h"
#include "sys/amd64/loader/data.h"
#include "sys/amd64/loader/multiboot.h"
#include "sys/amd64/mm/phys.h"
#include "sys/amd64/acpi/tables.h"
#include "sys/amd64/mm/pool.h"
#include "sys/sched.h"
#include "sys/string.h"
#include "sys/assert.h"
#include "sys/heap.h"
#include "sys/fs/tar.h"
#include "sys/fs/vfs.h"
#include "sys/errno.h"
#include "sys/fs/fcntl.h"
#include "sys/blk/ram.h"
#include "sys/thread.h"
#include "sys/binfmt_elf.h"
#include "sys/tty.h"
#include "sys/kidle.h"
// TODO: move to some util header
#define __wfe() asm volatile ("sti; hlt")
// For the sake of log readability
#define kernel_startup_section(text) \
kdebug("\n"); \
kdebug("====== " text "\n"); \
kdebug("\n")
static struct amd64_loader_data *loader_data = 0;
static multiboot_info_t *multiboot_info;
static struct vfs_ioctx kernel_ioctx = { NULL, 0, 0 };
static uint8_t amd64_loader_data_checksum(const struct amd64_loader_data *ld) {
uint8_t chk = 0;
for (size_t i = 0; i < sizeof(struct amd64_loader_data); ++i) {
chk += ((uint8_t *) ld)[i];
}
return chk;
}
static void amd64_loader_data_process(void) {
// Virtualize pointer locations, as the loader has passed their
// physical locations
multiboot_info = (multiboot_info_t *) MM_VIRTUALIZE(loader_data->multiboot_info_ptr);
}
static int init_start(void) {
struct stat st;
int res;
if ((res = vfs_stat(&kernel_ioctx, "/etc/init", &st)) < 0) {
return res;
}
if ((st.st_mode & S_IFMT) != S_IFREG) {
kerror("/etc/init: not a regular file\n");
return -EINVAL;
}
if (!(st.st_mode & 0111)) {
kerror("/etc/init: no one can execute this\n");
return -EINVAL;
}
kdebug("/etc/init is %S\n", st.st_size);
// That seems to be a weird way of loading binaries, whatever
void *exec_buf = kmalloc(st.st_size);
_assert(exec_buf);
struct ofile fd;
char buf[512];
size_t pos = 0;
ssize_t bread;
if ((res = vfs_open(&kernel_ioctx, &fd, "/etc/init", 0, O_RDONLY)) < 0) {
return res;
}
while ((bread = vfs_read(&kernel_ioctx, &fd, buf, 512)) > 0) {
memcpy((void *) ((uintptr_t) exec_buf + pos), buf, bread);
pos += bread;
}
vfs_close(&kernel_ioctx, &fd);
kdebug("Successfully read init file\n");
thread_t *init_thread = (thread_t *) kmalloc(sizeof(thread_t));
_assert(init_thread);
mm_space_t thread_space = amd64_mm_pool_alloc();
_assert(thread_space);
mm_space_clone(thread_space, mm_kernel, MM_CLONE_FLG_KERNEL);
if (thread_init(init_thread, thread_space, 0, 0, 0, 0, 0, 0) < 0) {
panic("Failed to set init up\n");
}
if ((res = elf_load(init_thread, exec_buf)) < 0) {
return res;
}
// Setup stdout file descriptor
struct thread_info *tinfo = thread_get(init_thread);
tinfo->fds[0].flags = O_RDONLY;
tinfo->fds[0].pos = 0;
tinfo->fds[0].vnode = tty0;
tinfo->fds[1].flags = O_WRONLY;
tinfo->fds[1].pos = 0;
tinfo->fds[1].vnode = tty0;
sched_add(init_thread);
return 0;
}
void kernel_main(uintptr_t loader_info_phys_ptr) {
kdebug("Booting\n");
#if defined(KERNEL_TEST_MODE)
kdebug("Kernel testing mode enabled\n");
#endif
// Obtain boot information from loader
loader_data = (struct amd64_loader_data *) MM_VIRTUALIZE(loader_info_phys_ptr);
if (amd64_loader_data_checksum(loader_data)) {
panic("Loader data checksum is invalid\n");
}
// Process loader data
amd64_loader_data_process();
// Memory management
kernel_startup_section("Memory management");
amd64_phys_memory_map((multiboot_memory_map_t *) MM_VIRTUALIZE(multiboot_info->mmap_addr), multiboot_info->mmap_length);
amd64_mm_init(loader_data);
kernel_startup_section("Basic hardware");
amd64_gdt_init();
pic8259_init();
acpi_tables_init();
amd64_timer_configure();
amd64_idt_init();
#if defined(KERNEL_TEST_MODE)
kernel_startup_section("Test dumps");
mm_describe(mm_kernel);
#endif
extern void amd64_setup_syscall(void);
amd64_setup_syscall();
// Setup /dev/ram0
// As we don't yet support booting with rootfs on disk
if (!loader_data->initrd_len) {
panic("Failed to init /dev/ram0: no initrd\n");
}
kdebug("initrd: %p, %S\n", loader_data->initrd_ptr, loader_data->initrd_len);
ramblk_init(MM_VIRTUALIZE(loader_data->initrd_ptr), loader_data->initrd_len);
// Setup tarfs class
tarfs_init();
// Mount tarfs@ram0 as root
if (vfs_mount(&kernel_ioctx, "/", ramblk0, "ustar", NULL) < 0) {
panic("Failed to mount root\n");
}
// Try to execute an ELF binary from initrd
int res;
if ((res = init_start()) < 0) {
kerror("Failed to execute init: %s\n", kstrerror(res));
}
kidle_init();
// Wait until entering [kidle]
while (1) {
__wfe();
}
}

View File

@ -1,123 +0,0 @@
#include "sys/amd64/mm/heap.h"
#include "sys/assert.h"
#include "sys/panic.h"
#include "sys/debug.h"
#include "sys/mm.h"
#define HEAP_MAGIC 0x1BAD83A0
typedef struct heap_block {
uint32_t magic;
uint32_t size;
struct heap_block *prev, *next;
} heap_block_t;
static struct kernel_heap {
uintptr_t phys_base;
size_t limit;
} amd64_global_heap;
heap_t *heap_global = &amd64_global_heap;
void amd64_heap_init(heap_t *heap, uintptr_t phys_base, size_t sz) {
heap->phys_base = phys_base;
heap->limit = sz;
// Create a single whole-heap block
heap_block_t *block = (heap_block_t *) MM_VIRTUALIZE(heap->phys_base);
block->magic = HEAP_MAGIC;
block->next = NULL;
block->prev = NULL;
block->size = sz - sizeof(heap_block_t);
}
// Heap interface implementation
void *heap_alloc(heap_t *heap, size_t count) {
heap_block_t *begin = (heap_block_t *) MM_VIRTUALIZE(heap->phys_base);
for (heap_block_t *block = begin; block; block = block->next) {
if (block->magic & 1) {
continue;
}
if (count == block->size) {
block->magic |= 1;
return (void *) &block[1];
} else if (count <= block->size + sizeof(heap_block_t)) {
// Insert new block after this one
heap_block_t *new_block = (heap_block_t *) (((uintptr_t) block) + sizeof(heap_block_t) + count);
new_block->next = block->next;
new_block->prev = block;
new_block->size = block->size - sizeof(heap_block_t) - count;
new_block->magic = HEAP_MAGIC;
block->next = new_block;
block->size = count;
block->magic |= 1;
return (void *) &block[1];
}
}
return NULL;
}
void heap_free(heap_t *heap, void *ptr) {
if (!ptr) {
return;
}
// Check if the pointer belongs to the heap
if (((uintptr_t) ptr) < MM_VIRTUALIZE(heap->phys_base) ||
((uintptr_t) ptr) > (MM_VIRTUALIZE(heap->phys_base) + heap->limit)) {
panic("Tried to free a pointer from outside a heap\n");
}
// Check if ptr is in a valid block
heap_block_t *block = (heap_block_t *) (((uintptr_t) ptr) - sizeof(heap_block_t));
assert((block->magic & HEAP_MAGIC) == HEAP_MAGIC, "Corrupted heap block magic\n");
assert(block->magic & 1, "Double free error (kheap): %p\n", ptr);
block->magic = HEAP_MAGIC;
kdebug("%p is free\n", block);
heap_block_t *prev = block->prev;
heap_block_t *next = block->next;
if (prev && !(prev->magic & 1)) {
prev->next = next;
if (next) {
next->prev = prev;
}
prev->size += sizeof(heap_block_t) + block->size;
block->magic = 0;
block = prev;
}
if (next && !(next->magic & 1)) {
block->next = next->next;
if (next->next) {
next->next->prev = block;
}
next->magic = 0;
block->size += sizeof(heap_block_t) + next->size;
}
}
// amd64-specific
size_t amd64_heap_blocks(const heap_t *heap) {
size_t c = 0;
for (const heap_block_t *block = (heap_block_t *) MM_VIRTUALIZE(heap->phys_base);
block; block = block->next) {
assert((block->magic & HEAP_MAGIC) == HEAP_MAGIC, "Corrupted heap block magic\n");
++c;
}
return c;
}
void amd64_heap_dump(const heap_t *heap) {
for (const heap_block_t *block = (heap_block_t *) MM_VIRTUALIZE(heap->phys_base);
block; block = block->next) {
assert((block->magic & HEAP_MAGIC) == HEAP_MAGIC, "Corrupted heap block magic\n");
kdebug("%p: %S %s%s\n", block, block->size, (block->magic & 1 ? "USED" : "FREE"), (block->next ? " -> " : ""));
}
}

View File

@ -1,283 +0,0 @@
#include "sys/mm.h"
#include "sys/debug.h"
#include "sys/panic.h"
#include "sys/assert.h"
#include "sys/mem.h"
#include "sys/amd64/mm/map.h"
#include "sys/amd64/mm/pool.h"
uintptr_t amd64_map_get(const mm_space_t pml4, uintptr_t vaddr, uint64_t *flags) {
vaddr = AMD64_MM_STRIPSX(vaddr);
size_t pml4i = (vaddr >> 39) & 0x1FF;
size_t pdpti = (vaddr >> 30) & 0x1FF;
size_t pdi = (vaddr >> 21) & 0x1FF;
size_t pti = (vaddr >> 12) & 0x1FF;
mm_pdpt_t pdpt;
mm_pagedir_t pd;
mm_pagetab_t pt;
if (!(pml4[pml4i] & 1)) {
return MM_NADDR;
}
if (pml4[pml4i] & (1 << 7)) {
panic("NYI\n");
}
pdpt = (mm_pdpt_t) MM_VIRTUALIZE(pml4[pml4i] & ~0xFFF);
if (!(pdpt[pdpti] & 1)) {
return MM_NADDR;
}
if (pdpt[pdpti] & (1 << 7)) {
if (flags) {
*flags = 2;
}
return (pdpt[pdpti] & ~0xFFF) | (vaddr & ((1 << 30) - 1));
}
pd = (mm_pagedir_t) MM_VIRTUALIZE(pdpt[pdpti] & ~0xFFF);
if (!(pd[pdi] & 1)) {
return MM_NADDR;
}
if (pd[pdi] & (1 << 7)) {
if (flags) {
*flags = 1;
}
return (pd[pti] & ~0xFFF) | (vaddr & ((1 << 21) - 1));
}
pt = (mm_pagetab_t) MM_VIRTUALIZE(pd[pdi] & ~0xFFF);
if (!(pt[pti] & 1)) {
return MM_NADDR;
}
if (flags) {
*flags = 0;
}
return (pt[pti] & ~0xFFF) | (vaddr & 0xFFF);
}
uintptr_t amd64_map_umap(mm_space_t pml4, uintptr_t vaddr, uint32_t size) {
vaddr = AMD64_MM_STRIPSX(vaddr);
// TODO: support page sizes other than 4KiB
// (Though I can't think of any reason to use it)
size_t pml4i = (vaddr >> 39) & 0x1FF;
size_t pdpti = (vaddr >> 30) & 0x1FF;
size_t pdi = (vaddr >> 21) & 0x1FF;
size_t pti = (vaddr >> 12) & 0x1FF;
mm_pdpt_t pdpt;
mm_pagedir_t pd;
mm_pagetab_t pt;
if (!(pml4[pml4i] & 1)) {
return MM_NADDR;
}
if (pml4[pml4i] & (1 << 7)) {
panic("NYI\n");
}
pdpt = (mm_pdpt_t) MM_VIRTUALIZE(pml4[pml4i] & ~0xFFF);
if (!(pdpt[pdpti] & 1)) {
return MM_NADDR;
}
if (pdpt[pdpti] & (1 << 7)) {
panic("NYI\n");
}
pd = (mm_pagedir_t) MM_VIRTUALIZE(pdpt[pdpti] & ~0xFFF);
if (!(pd[pdi] & 1)) {
return MM_NADDR;
}
if (pd[pdi] & (1 << 7)) {
panic("NYI\n");
}
pt = (mm_pagetab_t) MM_VIRTUALIZE(pd[pdi] & ~0xFFF);
if (!(pt[pti] & 1)) {
return MM_NADDR;
}
uint64_t old = pt[pti] & ~0xFFF;
pt[pti] = 0;
asm volatile("invlpg (%0)"::"a"(vaddr):"memory");
return old;
}
int amd64_map_single(mm_space_t pml4, uintptr_t virt_addr, uintptr_t phys, uint32_t flags) {
virt_addr = AMD64_MM_STRIPSX(virt_addr);
// TODO: support page sizes other than 4KiB
// (Though I can't think of any reason to use it)
size_t pml4i = (virt_addr >> 39) & 0x1FF;
size_t pdpti = (virt_addr >> 30) & 0x1FF;
size_t pdi = (virt_addr >> 21) & 0x1FF;
size_t pti = (virt_addr >> 12) & 0x1FF;
mm_pdpt_t pdpt;
mm_pagedir_t pd;
mm_pagetab_t pt;
if (!(pml4[pml4i] & 1)) {
// Allocate PDPT
pdpt = (mm_pdpt_t) amd64_mm_pool_alloc();
assert(pdpt, "PDPT alloc failed\n");
kdebug("Allocated PDPT = %p\n", pdpt);
pml4[pml4i] = MM_PHYS(pdpt) | (1 << 2) | (1 << 1) | 1;
} else {
pdpt = (mm_pdpt_t) MM_VIRTUALIZE(pml4[pml4i] & ~0xFFF);
}
if (!(pdpt[pdpti] & 1)) {
// Allocate PD
pd = (mm_pagedir_t) amd64_mm_pool_alloc();
assert(pd, "PD alloc failed\n");
kdebug("Allocated PD = %p\n", pd);
pdpt[pdpti] = MM_PHYS(pd) | (1 << 2) | (1 << 1) | 1;
} else {
pd = (mm_pagedir_t) MM_VIRTUALIZE(pdpt[pdpti] & ~0xFFF);
}
if (!(pd[pdi] & 1)) {
// Allocate PT
pt = (mm_pagetab_t) amd64_mm_pool_alloc();
assert(pt, "PT alloc failed\n");
kdebug("Allocated PT = %p\n", pt);
pd[pdi] = MM_PHYS(pt) | (1 << 2) | (1 << 1) | 1;
} else {
pt = (mm_pagetab_t) MM_VIRTUALIZE(pd[pdi] & ~0xFFF);
}
if (!(flags & (1 << 31))) {
assert(!(pt[pti] & 1), "Entry already present for %p\n", virt_addr);
}
#if defined(KERNEL_TEST_MODE)
kdebug("map %p -> %p\n", virt_addr, phys);
#endif
pt[pti] = (phys & ~0xFFF) | (flags & 0xFFF) | 1;
asm volatile("invlpg (%0)"::"a"(virt_addr):"memory");
return 0;
}
int mm_map_pages_contiguous(mm_space_t pml4, uintptr_t virt_base, uintptr_t phys_base, size_t count, uint32_t flags) {
for (size_t i = 0; i < count; ++i) {
uintptr_t virt_addr = virt_base + (i << 12);
if (amd64_map_single(pml4, virt_addr, phys_base + (i << 12), flags) != 0) {
return -1;
}
}
return 0;
}
int mm_space_clone(mm_space_t dst_pml4, const mm_space_t src_pml4, uint32_t flags) {
if ((flags & MM_CLONE_FLG_USER)) {
panic("NYI\n");
}
if ((flags & MM_CLONE_FLG_KERNEL)) {
// Kernel table references may be cloned verbatim, as they're guarannteed to be
// shared across all the spaces.
// This allows to save some resources on allocating the actual PDPT/PD/PTs
for (size_t i = AMD64_PML4I_USER_END; i < 512; ++i) {
dst_pml4[i] = src_pml4[i];
}
}
return 0;
}
static void amd64_mm_describe_range(const mm_space_t pml4, uintptr_t start_addr, uintptr_t end_addr) {
uintptr_t addr = AMD64_MM_STRIPSX(start_addr);
size_t range_length = 0;
uintptr_t virt_range_begin = MM_NADDR;
uint32_t range_flags = 0;
mm_pdpt_t pdpt;
while (addr < AMD64_MM_STRIPSX(end_addr)) {
size_t pml4i = (addr >> 39) & 0x1FF;
size_t pdpti = (addr >> 30) & 0x1FF;
size_t pdi = (addr >> 21) & 0x1FF;
size_t pti = (addr >> 12) & 0x1FF;
size_t page_size = 1ULL << 39;
if (pml4[pml4i] & 1) {
if (pml4[pml4i] & (1 << 7)) {
panic("Found a huge page in PML4 (shouldn't be possible): %p\n", AMD64_MM_ADDRSX(addr));
}
page_size = 1ULL << 30;
pdpt = (mm_pdpt_t) MM_VIRTUALIZE(pml4[pml4i] & ~0xFFF);
if (pdpt[pdpti] & 1) {
if (pdpt[pdpti] & (1 << 7)) {
if (virt_range_begin == MM_NADDR) {
virt_range_begin = addr;
range_length = 0;
range_flags = pdpt[pdpti] & 5;
}
goto found;
}
panic("TODO: implement smaller page description\n");
}
}
if (virt_range_begin != MM_NADDR) {
kdebug("Range %p .. %p (%c%c) %S\n",
virt_range_begin,
virt_range_begin + range_length,
(range_flags & (1 << 2) ? 'u' : '-'),
(range_flags & (1 << 1) ? 'w' : '-'),
range_length);
}
found:
addr += page_size;
range_length += page_size;
}
if (virt_range_begin != MM_NADDR) {
kdebug("Range %p .. %p (%c%c) %S\n",
virt_range_begin,
virt_range_begin + range_length,
(range_flags & (1 << 2) ? 'u' : '-'),
(range_flags & (1 << 1) ? 'w' : '-'),
range_length);
}
}
void mm_describe(const mm_space_t pml4) {
kdebug("Memory space V:%p:\n", pml4);
mm_pdpt_t pdpt;
mm_pagedir_t pd;
mm_pagetab_t pt;
// Dump everything except kernel-space mappings
kdebug("- Userspace:\n");
amd64_mm_describe_range(pml4, 0, 0xFFFFFF0000000000);
kdebug("- Kernelspace:\n");
amd64_mm_describe_range(pml4, 0xFFFFFF0000000000, 0xFFFFFF00FFFFFFFF);
}

View File

@ -1,52 +0,0 @@
#include "sys/amd64/mm/pool.h"
#include "sys/amd64/mm/phys.h"
#include "sys/vmalloc.h"
#include "sys/assert.h"
#include "sys/debug.h"
#include "sys/panic.h"
#include "sys/heap.h"
#include "sys/mem.h"
#include "sys/mm.h"
mm_space_t mm_kernel;
extern int _kernel_end;
void amd64_mm_init(struct amd64_loader_data *data) {
kdebug("Memory manager init\n");
// Physical memory at this point:
// 0x000000 - 0x400000 - Used by kernel and info passed from the loader
// Virtual memory:
// Lower 1GiB mapped to itself for loader access
// 0xFFFFFF0000000000 (1GiB) is mapped to 0 for kernel access
// XXX: assuming nothing important is there
uint64_t *pml4 = (uint64_t *) (0x200000 - 0x1000);
uint64_t *pdpt = (uint64_t *) (0x200000 - 0x2000);
memset((void *) (0x200000 - 2 * 0x1000), 0, 0x1000 * 2);
// 0xFFFFFF0000000000 -> 0 (512GiB) mapping
pml4[AMD64_MM_STRIPSX(KERNEL_VIRT_BASE) >> 39] = ((uintptr_t) pdpt) | 1 | 2 | 4;
for (uint64_t i = 0; i < 4; ++i) {
kdebug("Mapping %p -> %p\n", KERNEL_VIRT_BASE | (i << 30), i << 30);
pdpt[((AMD64_MM_STRIPSX(KERNEL_VIRT_BASE) >> 30) + i) & 0x1FF] = (i << 30) | 1 | 2 | 4 | (1 << 7);
}
// Load the new table
asm volatile ("mov %0, %%cr3"::"a"(pml4):"memory");
// Create a pool located right after kernel image
amd64_mm_pool_init((uintptr_t) &_kernel_end, MM_POOL_SIZE);
mm_kernel = (mm_space_t) (MM_VIRTUALIZE(pml4));
// Allocate some pages for kernel heap (base size: 16MiB)
uintptr_t heap_base_phys = amd64_phys_alloc_contiguous(KERNEL_HEAP >> 12);
assert(heap_base_phys != MM_NADDR, "Could not allocate %S of memory for kernel heap\n", KERNEL_HEAP);
kdebug("Setting up kernel heap of %S @ %p\n", KERNEL_HEAP, heap_base_phys);
amd64_heap_init(heap_global, heap_base_phys, KERNEL_HEAP);
amd64_heap_dump(heap_global);
}

View File

@ -1,137 +0,0 @@
#include "sys/amd64/mm/phys.h"
#include "sys/amd64/mm/pool.h"
#include "sys/assert.h"
#include "sys/panic.h"
#include "sys/debug.h"
#include "sys/mem.h"
#include "sys/mm.h"
extern int _kernel_end_phys;
// Roughly 36MiB of lower memory is occupied by kernel so far:
// The rest is available for both kernel and user allocation
#define PHYS_ALLOWED_BEGIN ((((uintptr_t) &_kernel_end_phys + MM_POOL_SIZE) + 0xFFF) & ~0xFFF)
// TODO: move to sys/util.h
#define MAX(x, y) ((x) > (y) ? (x) : (y))
// TODO: this could be a better allocator
// + Support more memory
// 1 index is 64 pages - 256KiB
#define PHYS_MAX_INDEX 16384 // Gives exactly 4GiB available for allocation
#define PHYS_TRACK_INDEX(page) ((page) >> 18)
#define PHYS_TRACK_BIT(page) (((page) >> 12) & 0x3F)
static uint64_t amd64_phys_memory_track[PHYS_MAX_INDEX];
static uint64_t amd64_phys_last_index = 0;
// Allocate a single 4K page
uintptr_t amd64_phys_alloc_page(void) {
for (uint64_t i = amd64_phys_last_index; i < PHYS_MAX_INDEX; ++i) {
for (uint64_t j = 0; j < 64; ++j) {
if (!(amd64_phys_memory_track[i] & (1ULL << j))) {
amd64_phys_memory_track[i] |= (1ULL << j);
amd64_phys_last_index = i;
return PHYS_ALLOWED_BEGIN + ((i << 18) | (j << 12));
}
}
}
for (uint64_t i = 0; i < amd64_phys_last_index; ++i) {
for (uint64_t j = 0; j < 64; ++j) {
if (!(amd64_phys_memory_track[i] & (1ULL << j))) {
amd64_phys_memory_track[i] |= (1ULL << j);
amd64_phys_last_index = i;
return PHYS_ALLOWED_BEGIN + ((i << 18) | (j << 12));
}
}
}
return MM_NADDR;
}
void amd64_phys_free(uintptr_t page) {
// Address is too low
assert(page >= PHYS_ALLOWED_BEGIN, "The page is outside the physical range: %p\n", page);
page -= PHYS_ALLOWED_BEGIN;
// Address is too high
assert(PHYS_TRACK_INDEX(page) < PHYS_MAX_INDEX, "The page is outside the physical range: %p\n", page + PHYS_ALLOWED_BEGIN);
uint64_t bit = 1ULL << PHYS_TRACK_BIT(page);
uint64_t index = PHYS_TRACK_INDEX(page);
// Double free error
assert(amd64_phys_memory_track[index] & bit, "Double free error (phys): %p\n", page + PHYS_ALLOWED_BEGIN);
amd64_phys_memory_track[index] &= ~bit;
}
// XXX: very slow impl.
uintptr_t amd64_phys_alloc_contiguous(size_t count) {
uintptr_t addr = 0;
kdebug("Requested %S\n", count << 12);
if (count >= (PHYS_MAX_INDEX << 6)) {
// The requested range is too large
return MM_NADDR;
}
while (addr < (((uint64_t) (PHYS_MAX_INDEX - (count >> 6) - 1)) << 18)) {
// Check if we can allocate these pages
for (size_t i = 0; i < count; ++i) {
uintptr_t page = (i << 12) + addr;
if (amd64_phys_memory_track[PHYS_TRACK_INDEX(page)] & (1ULL << PHYS_TRACK_BIT(page))) {
// When reaching unavailable page, just start searching beyond its address
addr = page + 0x1000;
goto no_match;
}
}
// All pages are available
for (size_t i = 0; i < count; ++i) {
uintptr_t page = (i << 12) + addr;
amd64_phys_memory_track[PHYS_TRACK_INDEX(page)] |= (1ULL << PHYS_TRACK_BIT(page));
}
kdebug("== %p\n", addr + PHYS_ALLOWED_BEGIN);
return PHYS_ALLOWED_BEGIN + addr;
// Found unavailable page in the range, continue searching
no_match:
continue;
}
return MM_NADDR;
}
void amd64_phys_memory_map(const multiboot_memory_map_t *mmap, size_t length) {
kdebug("Kernel table pool ends @ %p\n", PHYS_ALLOWED_BEGIN);
kdebug("Memory map @ %p\n", mmap);
memset(amd64_phys_memory_track, 0xFF, sizeof(amd64_phys_memory_track));
uintptr_t curr_item = (uintptr_t) mmap;
uintptr_t mmap_end = length + curr_item;
size_t total_phys = 0;
// Collect usable physical memory information
while (curr_item < mmap_end) {
const multiboot_memory_map_t *entry = (const multiboot_memory_map_t *) (curr_item);
uintptr_t page_aligned_begin = MAX((entry->addr + 0xFFF) & ~0xFFF, PHYS_ALLOWED_BEGIN);
uintptr_t page_aligned_end = (entry->addr + entry->len) & ~0xFFF;
if (entry->type == 1 && page_aligned_end > page_aligned_begin) {
kdebug("+++ %S @ %p\n", page_aligned_end - page_aligned_begin, page_aligned_begin);
for (uintptr_t addr = page_aligned_begin - PHYS_ALLOWED_BEGIN;
addr < (page_aligned_end - PHYS_ALLOWED_BEGIN); addr += 0x1000) {
uintptr_t index = PHYS_TRACK_INDEX(addr);
if (index >= PHYS_MAX_INDEX) {
kdebug("Too high: %p\n", addr);
break;
}
amd64_phys_memory_track[index] &= ~(1ULL << PHYS_TRACK_BIT(addr));
++total_phys;
}
}
curr_item += entry->size + sizeof(uint32_t);
}
kdebug("%S available\n", total_phys << 12);
}

View File

@ -1,66 +0,0 @@
#include "sys/amd64/mm/pool.h"
#include "sys/amd64/mm.h"
#include "sys/assert.h"
#include "sys/debug.h"
#include "sys/panic.h"
#include "sys/mem.h"
static struct {
uint64_t track[512];
uintptr_t start;
uintptr_t index_last;
size_t size;
} amd64_mm_pool;
uint64_t *amd64_mm_pool_alloc(void) {
uint64_t *r = NULL;
for (size_t i = amd64_mm_pool.index_last; i < amd64_mm_pool.size >> 18; ++i) {
for (size_t j = amd64_mm_pool.index_last; j < 64; ++j) {
if (!(amd64_mm_pool.track[i] & (1ULL << j))) {
r = (uint64_t *) (amd64_mm_pool.start + ((i << 18) + (j << 12)));
amd64_mm_pool.track[i] |= (1ULL << j);
amd64_mm_pool.index_last = i;
memset(r, 0, 4096);
return r;
}
}
}
for (size_t i = 0; i < amd64_mm_pool.index_last; ++i) {
for (size_t j = amd64_mm_pool.index_last; j < 64; ++j) {
if (!(amd64_mm_pool.track[i] & (1ULL << j))) {
r = (uint64_t *) (amd64_mm_pool.start + ((i << 18) + (j << 12)));
amd64_mm_pool.track[i] |= (1ULL << j);
amd64_mm_pool.index_last = i;
memset(r, 0, 4096);
return r;
}
}
}
return NULL;
}
void amd64_mm_pool_free(uint64_t *page) {
uintptr_t a = (uintptr_t) page;
if (a < amd64_mm_pool.start || a >= (amd64_mm_pool.start + amd64_mm_pool.size)) {
panic("The page does not belong to the pool: %p\n", a);
}
a -= amd64_mm_pool.start;
size_t i = (a >> 18) & 0x1FF;
size_t j = (a >> 12) & 0x3F;
assert(amd64_mm_pool.track[i] & (1ULL << j), "Double free error (pool): %p\n", page);
amd64_mm_pool.track[i] &= ~(1ULL << j);
}
void amd64_mm_pool_init(uintptr_t begin, size_t size) {
amd64_mm_pool.start = begin;
amd64_mm_pool.size = size;
memset(amd64_mm_pool.track, 0, 512 * sizeof(uint64_t));
}

View File

@ -1,80 +0,0 @@
#include "sys/amd64/mm/phys.h"
#include "sys/amd64/mm/map.h"
#include "sys/assert.h"
#include "sys/vmalloc.h"
#include "sys/debug.h"
#include "sys/panic.h"
uintptr_t vmfind(const mm_space_t pml4, uintptr_t from, uintptr_t to, size_t npages) {
// XXX: The slowest approach I could think of
// Though the easiest one
size_t page_index = from >> 12;
while ((page_index + npages) <= (to >> 12)) {
for (size_t i = 0; i < npages; ++i) {
if (amd64_map_get(pml4, (page_index + i) << 12, 0) != MM_NADDR) {
goto no_match;
}
}
return page_index << 12;
no_match:
++page_index;
continue;
}
return MM_NADDR;
}
uintptr_t vmalloc(mm_space_t pml4, uintptr_t from, uintptr_t to, size_t npages, int flags) {
uintptr_t addr = vmfind(pml4, from, to, npages);
uintptr_t virt_page, phys_page;
uint32_t rflags = 0;
if (flags & VM_ALLOC_WRITE) {
rflags |= 1 << 1;
}
if (flags & VM_ALLOC_USER) {
rflags |= 1 << 2;
}
if (addr == MM_NADDR) {
return MM_NADDR;
}
for (size_t i = 0; i < npages; ++i) {
virt_page = addr + (i << 12);
phys_page = amd64_phys_alloc_page();
// Allocation of physical page failed, clean up
if (phys_page == MM_NADDR) {
// Unmap previously allocated pages
for (size_t j = 0; j < i; ++j) {
virt_page = addr + (j << 12);
// Deallocate physical pages that've already been mapped
// We've mapped only 4KiB pages, so expect to unmap only
// 4KiB pages
assert((phys_page = amd64_map_umap(pml4, virt_page, 1)) != MM_NADDR,
"Failed to deallocate page when cleaning up botched alloc: %p\n", virt_page);
amd64_phys_free(phys_page);
}
return MM_NADDR;
}
// Succeeded, map the page
assert(amd64_map_single(pml4, virt_page, phys_page, 0) == 0, "Failed to map page: %p\n", virt_page);
}
return addr;
}
void vmfree(mm_space_t pml4, uintptr_t addr, size_t npages) {
uintptr_t phys;
for (size_t i = 0; i < npages; ++i) {
if ((phys = amd64_map_umap(pml4, addr + (i << 12), 1)) == MM_NADDR) {
panic("Double vmfree error: %p is not an allocated page\n", addr + (i << 12));
}
amd64_phys_free(phys);
}
}

14
sys/amd64/string.S Normal file
View File

@ -0,0 +1,14 @@
.section .text
.global strlen
strlen:
// %rdi - str
xorq %rax, %rax
1:
cmpq $0, (%rdi)
je 1f
incq %rax
incq %rdi
jmp 1b
1:
ret

View File

@ -1,28 +0,0 @@
#include "sys/thread.h"
#include "sys/assert.h"
#include "sys/sched.h"
#include "sys/kidle.h"
#include "sys/debug.h"
#include "sys/time.h"
static char kidle_kstack[8192];
static thread_t kidle_thread;
static void kidle(void) {
while (1) {
asm volatile ("sti; hlt");
}
}
void kidle_init(void) {
assert(thread_init(&kidle_thread,
mm_kernel,
(uintptr_t) kidle,
(uintptr_t) kidle_kstack,
sizeof(kidle_kstack),
0,
0,
THREAD_KERNEL) == 0,
"Failed to set kidle up\n");
sched_add(&kidle_thread);
}

View File

@ -1,49 +0,0 @@
#include "sys/thread.h"
#include "sys/debug.h"
#include "sys/syscall.h"
#include "sys/thread.h"
#include "sys/assert.h"
#include "sys/sched.h"
#include "sys/errno.h"
static ssize_t sys_write(int fd, const userspace void *buf, size_t lim);
static ssize_t sys_read(int fd, userspace void *buf, size_t lim);
uint64_t amd64_syscall(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t no) {
switch (no) {
case SYS_NR_READ:
return sys_read(a0, (void *) a1, a2);
case SYS_NR_WRITE:
return sys_write(a0, (const void *) a1, a2);
default:
return -EINVAL;
}
}
static ssize_t sys_write(int fd, const userspace void *buf, size_t lim) {
struct thread_info *tinfo = thread_get(sched_current);
_assert(tinfo);
if (fd < 0 || (size_t) fd >= sizeof(tinfo->fds) / sizeof(tinfo->fds[0])) {
return -EBADF;
}
struct ofile *of = &tinfo->fds[fd];
if (of->vnode == NULL) {
return -EBADF;
}
return vfs_write(&tinfo->ioctx, of, buf, lim);
}
static ssize_t sys_read(int fd, userspace void *buf, size_t lim) {
struct thread_info *tinfo = thread_get(sched_current);
_assert(tinfo);
if (fd < 0 || (size_t) fd >= sizeof(tinfo->fds) / sizeof(tinfo->fds[0])) {
return -EBADF;
}
struct ofile *of = &tinfo->fds[fd];
if (of->vnode == NULL) {
return -EBADF;
}
return vfs_read(&tinfo->ioctx, of, buf, lim);
}

View File

@ -1,79 +0,0 @@
.set AMD64_MSR_EFER, 0xC0000080
.set AMD64_MSR_STAR, 0xC0000081
.set AMD64_MSR_LSTAR, 0xC0000082
.set AMD64_MSR_SFMASK, 0xC0000084
.extern amd64_syscall
.global amd64_setup_syscall
amd64_setup_syscall:
// Load STAR = 0x08 << 32
// Needed:
// userCS = 0x23
// userSS = 0x1B
// SYSRET.CS = SYSRET.SS + 8 = X + 16 = 0x13 + 16
// Needed:
// kernCS = 0x08
// kernSS = 0x10
// SYSCALL.SS = SYSCALL.CS + 8 = 0x08 + 8
movl $0x130008, %edx
xorl %eax, %eax
movl $AMD64_MSR_STAR, %ecx
wrmsr
// Load LSTAR = RIP of syscall entry
leaq amd64_syscall_entry(%rip), %rdx
movl %edx, %eax
shrq $32, %rdx
movl $AMD64_MSR_LSTAR, %ecx
wrmsr
movl $0x0200, %eax
movl $0x0, %edx
movl $AMD64_MSR_SFMASK, %ecx
wrmsr
// Set EFER.SCE = 1
movl $AMD64_MSR_EFER, %ecx
rdmsr
or $1, %eax
wrmsr
retq
amd64_syscall_entry:
// R11 = RFLAGS
// RCX = userRIP
// RSP = userRSP
// Args:
// %rdi, %rsi, %rdx, %r10, %r8, %r9
// Preserved:
// %r12-%r15, %rbx
// Result:
// %rax
// 1. Load kernRSP from amd64_thread_current->kstack_ptr,
// userRSP is stored in %rax before being pushed
movq %rsp, %r9
movq sched_current(%rip), %rsp
movq (%rsp), %rsp
// syscall handlers may mess up this in SysV amd64 ABI, store
// these on stack
pushq %r9
pushq %r11
pushq %rcx
// Move arguments
movq %r10, %rcx
movq %rax, %r9
// Args:
// %rdi %rsi, %rdx, %rcx
call amd64_syscall
popq %rcx
popq %r11
popq %rsp
rex.w sysret

View File

@ -1,113 +0,0 @@
#include "sys/thread.h"
#include "sys/panic.h"
#include "sys/assert.h"
#include "sys/debug.h"
#include "sys/heap.h"
#include "sys/amd64/mm/phys.h"
#include "sys/amd64/mm/map.h"
#define AMD64_DEFAULT_KSTACK_SIZE 0x4000
#define ctx0(t) ((amd64_thread_context_t *) (t->kstack_ptr))
int thread_init(thread_t *t,
mm_space_t space,
uintptr_t ip,
uintptr_t kstack_base,
size_t kstack_size,
uintptr_t ustack_base,
size_t ustack_size,
uint32_t flags
) {
if (thread_info_init(&t->info) != 0) {
return -1;
}
t->info.flags = flags;
// Mandatory for both kernel and user threads
if (!kstack_base) {
kstack_base = (uintptr_t) kmalloc(AMD64_DEFAULT_KSTACK_SIZE);
kstack_size = AMD64_DEFAULT_KSTACK_SIZE;
if (!kstack_base) {
panic("Failed to allocate thread kstack\n");
}
}
t->kstack_base = kstack_base;
t->kstack_size = kstack_size;
t->kstack_ptr = t->kstack_base + t->kstack_size - sizeof(amd64_thread_context_t);
kdebug("KSTACK %p\n", t->kstack_ptr);
// If we're not kernel, additionally set the ustack
if (!(flags & THREAD_KERNEL)) {
if (ustack_base == 0) {
// Allocate an ustack
uintptr_t ustack_base_phys = amd64_phys_alloc_page();
if (ustack_base_phys == MM_NADDR) {
panic("Failed to allocate thread ustack\n");
}
ustack_size = 0x1000;
ustack_base = 0x80000000;
if (amd64_map_single(space, ustack_base, ustack_base_phys, (1 << 2) | (1 << 1)) < 0) {
panic("Failed to map thread ustack\n");
}
}
t->ustack_size = ustack_size;
t->ustack_base = ustack_base;
}
// Set CS:RIP
if (flags & THREAD_KERNEL) {
ctx0(t)->cs = 0x08;
ctx0(t)->ss = 0x10;
ctx0(t)->rsp = t->kstack_ptr;
ctx0(t)->rflags = 0x248;
ctx0(t)->rip = ip;
} else {
ctx0(t)->cs = 0x23;
ctx0(t)->ss = 0x1B;
ctx0(t)->rsp = t->ustack_size + t->ustack_base;
ctx0(t)->rflags = 0x248;
ctx0(t)->rip = ip;
}
assert(((uintptr_t) space) > 0xFFFFFF0000000000,
"Invalid PML4 address provided: %p\n", space);
// Set task space
t->info.space = space;
ctx0(t)->cr3 = ((uintptr_t) space) - 0xFFFFFF0000000000;
t->next = NULL;
return 0;
}
void thread_set_ip(thread_t *t, uintptr_t ip) {
if (t->info.flags & THREAD_KERNEL) {
ctx0(t)->cs = 0x08;
ctx0(t)->ss = 0x10;
ctx0(t)->rsp = t->kstack_ptr;
ctx0(t)->rflags = 0x248;
ctx0(t)->rip = ip;
} else {
ctx0(t)->cs = 0x23;
ctx0(t)->ss = 0x1B;
ctx0(t)->rsp = t->ustack_size + t->ustack_base;
ctx0(t)->rflags = 0x248;
ctx0(t)->rip = ip;
}
}
void thread_set_space(thread_t *t, mm_space_t pd) {
assert(((uintptr_t) pd) > 0xFFFFFF0000000000, "Invalid PML4 address provided: %p\n", pd);
t->info.space = pd;
ctx0(t)->cr3 = ((uintptr_t) pd) - 0xFFFFFF0000000000;
}
void thread_set_ustack(thread_t *t, uintptr_t base, size_t size) {
panic("NYI\n");
}

View File

@ -1,101 +0,0 @@
#include "sys/binfmt_elf.h"
#include "sys/debug.h"
#include "sys/mem.h"
#include "sys/string.h"
#include "sys/panic.h"
#include "sys/amd64/mm/phys.h"
#include "sys/amd64/mm/map.h"
#include "sys/errno.h"
#include "sys/elf.h"
#define ELF_ADDR_MIN 0x400000
int elf_load(thread_t *thr, const void *from) {
struct thread_info *thri = thread_get(thr);
Elf64_Ehdr *ehdr = (Elf64_Ehdr *) from;
// Check magic
if (strncmp((const char *) ehdr->e_ident, "\x7F""ELF", 4) != 0) {
kerror("elf: magic mismatch\n");
return -EINVAL;
}
if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
kerror("elf: object was not intended for 64-bit\n");
return -EINVAL;
}
Elf64_Shdr *shdrs = (Elf64_Shdr *) (ehdr->e_shoff + (uintptr_t) from);
const char *shstrtabd = (const char *) (shdrs[ehdr->e_shstrndx].sh_offset + (uintptr_t) from);
// Load the sections
for (size_t i = 0; i < ehdr->e_shnum; ++i) {
Elf64_Shdr *shdr = &shdrs[i];
const char *name = &shstrtabd[shdr->sh_name];
if (shdr->sh_flags & SHF_ALLOC) {
if (!strncmp(name, ".note", 5)) {
// Fuck you, gcc
continue;
}
if (!strncmp(name, ".gnu", 4)) {
// Fuck you, gcc
continue;
}
kdebug("Loading %s\n", name);
// If the section is below what is allowed
if (shdr->sh_addr < ELF_ADDR_MIN) {
kerror("elf: section address is below allowed\n");
return -EINVAL;
}
// Allocate memory for the section
size_t sec_pages = (shdr->sh_size + 0xFFF) / 0x1000;
kdebug("%s needs %u pages\n", name, sec_pages);
if (sec_pages > 1) {
panic("elf: I was too lazy to implement this yet\n");
}
uintptr_t page_virt = shdr->sh_addr & ~0xFFF;
uintptr_t page_offset = shdr->sh_addr & 0xFFF;
kdebug("%s base page is VMA %p\n", name, page_virt);
uintptr_t page_phys;
if ((page_phys = amd64_map_get(thri->space, page_virt, NULL)) == MM_NADDR) {
page_phys = amd64_phys_alloc_page();
if (page_phys == MM_NADDR) {
panic("elf: out of memory\n");
}
if (amd64_map_single(thri->space, page_virt, page_phys, (1 << 1) | (1 << 2)) != 0) {
panic("elf: map failed\n");
}
} else {
kdebug("Not mapping\n");
}
if (shdr->sh_type == SHT_PROGBITS) {
kdebug("elf: memcpy %p <- %p %S\n", MM_VIRTUALIZE(page_phys) + page_offset,
(uintptr_t) from + shdr->sh_offset,
shdr->sh_size);
memcpy((void *) (MM_VIRTUALIZE(page_phys) + page_offset),
(const void *) ((uintptr_t) from + shdr->sh_offset),
shdr->sh_size);
} else if (shdr->sh_type == SHT_NOBITS) {
kdebug("elf: memset 0 %p %S\n", MM_VIRTUALIZE(page_phys) + page_offset,
shdr->sh_size);
memset((void *) (MM_VIRTUALIZE(page_phys) + page_offset),
0, shdr->sh_size);
}
}
}
thread_set_ip(thr, ehdr->e_entry);
return 0;
}

View File

@ -1,23 +0,0 @@
#include "sys/blk.h"
#include "sys/assert.h"
#include "sys/errno.h"
ssize_t blk_read(struct blkdev *blk, void *buf, size_t off, size_t lim) {
_assert(blk);
if (blk->read) {
return blk->read(blk, buf, off, lim);
} else {
return -EINVAL;
}
}
ssize_t blk_write(struct blkdev *blk, const void *buf, size_t off, size_t lim) {
_assert(blk);
if (blk->write) {
return blk->write(blk, buf, off, lim);
} else {
return -EINVAL;
}
}

View File

@ -1,31 +0,0 @@
#include "sys/blk/ram.h"
#include "sys/string.h"
#define MIN(x, y) ((x) < (y) ? (x) : (y))
static struct ram_priv {
uintptr_t begin;
size_t lim;
} ram_priv;
static ssize_t ramblk_read(struct blkdev *blk, void *buf, size_t off, size_t len) {
if (off > ram_priv.lim) {
return -1;
}
size_t r = MIN(len, ram_priv.lim - off);
memcpy(buf, (void *) (ram_priv.begin + off), r);
return r;
}
static struct blkdev _ramblk0 = {
.dev_data = &ram_priv,
.read = ramblk_read,
.write = NULL
};
struct blkdev *ramblk0 = &_ramblk0;
void ramblk_init(uintptr_t at, size_t len) {
ram_priv.begin = at;
ram_priv.lim = len;
}

View File

@ -1,22 +0,0 @@
#include "sys/chr.h"
#include "sys/errno.h"
ssize_t chr_write(struct chrdev *chr, const void *buf, size_t off, size_t count) {
if (!chr) {
return -ENODEV;
}
if (!chr->write) {
return -EROFS;
}
return chr->write(chr, buf, off, count);
}
ssize_t chr_read(struct chrdev *chr, void *buf, size_t off, size_t count) {
if (!chr) {
return -ENODEV;
}
if (!chr->read) {
return -EINVAL;
}
return chr->read(chr, buf, off, count);
}

View File

@ -15,29 +15,31 @@ ifdef KERNEL_TEST_MODE
CFLAGS+=-DKERNEL_TEST_MODE
endif
DIRS+=$(O)/sys \
$(O)/sys/vfs \
$(O)/sys/vfs/ext2 \
$(O)/sys/blk
OBJS+=$(O)/sys/mem.o \
$(O)/sys/string.o \
$(O)/sys/debug.o \
$(O)/sys/panic.o \
$(O)/sys/thread.o \
$(O)/sys/sched.o \
$(O)/sys/time.o \
$(O)/sys/blk.o \
$(O)/sys/vfs/node.o \
$(O)/sys/vfs/vfs.o \
$(O)/sys/vfs/fs_class.o \
$(O)/sys/vfs/ext2/ext2.o \
$(O)/sys/vfs/ext2/ext2blk.o \
$(O)/sys/vfs/ext2/ext2alloc.o \
$(O)/sys/vfs/ext2/ext2vnop.o \
$(O)/sys/vfs/ext2/ext2dir.o \
$(O)/sys/blk/ram.o \
$(O)/sys/vfs/tar.o \
$(O)/sys/binfmt_elf.o \
$(O)/sys/errno.o \
$(O)/sys/tty.o \
$(O)/sys/chr.o
# DIRS+=$(O)/sys \
# $(O)/sys/vfs \
# $(O)/sys/vfs/ext2 \
# $(O)/sys/blk
# OBJS+=$(O)/sys/mem.o \
# $(O)/sys/string.o \
# $(O)/sys/debug.o \
# $(O)/sys/panic.o \
# $(O)/sys/thread.o \
# $(O)/sys/sched.o \
# $(O)/sys/time.o \
# $(O)/sys/blk.o \
# $(O)/sys/vfs/node.o \
# $(O)/sys/vfs/vfs.o \
# $(O)/sys/vfs/fs_class.o \
# $(O)/sys/vfs/ext2/ext2.o \
# $(O)/sys/vfs/ext2/ext2blk.o \
# $(O)/sys/vfs/ext2/ext2alloc.o \
# $(O)/sys/vfs/ext2/ext2vnop.o \
# $(O)/sys/vfs/ext2/ext2dir.o \
# $(O)/sys/blk/ram.o \
# $(O)/sys/vfs/tar.o \
# $(O)/sys/binfmt_elf.o \
# $(O)/sys/errno.o \
# $(O)/sys/tty.o \
# $(O)/sys/chr.o
OBJS+=$(O)/sys/debug.o

View File

@ -1,12 +0,0 @@
#include "sys/errno.h"
const char *kstrerror(int e) {
switch (e) {
case -ENOENT:
return "No such file or directory";
case -EINVAL:
return "Invalid argument";
default:
return "Unknown error";
}
}

View File

@ -1,38 +0,0 @@
#pragma once
#define EPERM 1
#define ENOENT 2
#define ESRCH 3
#define EINTR 4
#define EIO 5
#define ENXIO 6
#define E2BIG 7
#define ENOEXEC 8
#define EBADF 9
#define ECHILD 10
#define EAGAIN 11
#define ENOMEM 12
#define EACCES 13
#define EFAULT 14
#define ENOTBLK 15
#define EBUSY 16
#define EEXIST 17
#define EXDEV 18
#define ENODEV 19
#define ENOTDIR 20
#define EISDIR 21
#define EINVAL 22
#define ENFILE 23
#define EMFILE 24
#define ENOTTY 25
#define ETXTBSY 26
#define EFBIG 27
#define ENOSPC 28
#define ESPIPE 29
#define EROFS 30
#define EMLINK 31
#define EPIPE 32
#define EDOM 33
#define ERANGE 34
const char *kstrerror(int e);

View File

@ -1,15 +0,0 @@
#include "sys/mem.h"
void *memset(void *blk, int v, size_t sz) {
for (size_t i = 0; i < sz; ++i) {
((char *) blk)[i] = v;
}
return blk;
}
void *memcpy(void *dst, const void *src, size_t sz) {
for (size_t i = 0; i < sz; ++i) {
((char *) dst)[i] = ((const char *) src)[i];
}
return dst;
}

View File

@ -1,16 +0,0 @@
#include "sys/panic.h"
#include "sys/debug.h"
void panicf(const char *fmt, ...) {
asm volatile ("cli");
va_list args;
kfatal("--- Panic ---\n");
va_start(args, fmt);
debugfv(DEBUG_FATAL, fmt, args);
va_end(args);
kfatal("--- Panic ---\n");
panic_hlt();
}

View File

@ -1,50 +0,0 @@
#include "sys/thread.h"
#include "sys/debug.h"
thread_t *sched_current = NULL;
static thread_t *sched_first = NULL, *sched_last = NULL;
static pid_t sched_pid_counter = 0;
pid_t sched_add(thread_t *t) {
pid_t pid;
if (thread_get(t)->flags & THREAD_KERNEL) {
pid = 0;
} else {
pid = ++sched_pid_counter;
}
thread_get(t)->pid = pid;
if (sched_first) {
sched_last->next = t;
} else {
sched_first = t;
}
sched_last = t;
return pid;
}
int sched(void) {
if (!sched_current) {
sched_current = sched_first;
if (!sched_current) {
return -1;
}
return 0;
}
// Plain round-robin scheduler
thread_t *from = sched_current;
thread_t *to = thread_next(from);
if (to == NULL) {
to = sched_first;
}
if (to == from) {
return -1;
}
sched_current = to;
return 0;
}

View File

@ -1,129 +0,0 @@
#include "sys/string.h"
size_t strlen(const char *a) {
size_t s = 0;
while (*a++) {
++s;
}
return s;
}
int strncmp(const char *a, const char *b, size_t n) {
size_t c = 0;
for (; c < n && (*a || *b); ++c, ++a, ++b) {
if (*a != *b) {
return -1;
}
}
return 0;
}
int strcmp(const char *a, const char *b) {
if (a == b) {
return 0;
}
if (a == NULL || b == NULL) {
return -1;
}
for (; *a || *b; ++a, ++b) {
if (*a != *b) {
return 1;
}
}
return 0;
}
char *strcpy(char *dst, const char *src) {
size_t i;
for (i = 0; src[i]; ++i) {
dst[i] = src[i];
}
dst[i] = 0;
return dst;
}
char *strncpy(char *dst, const char *src, size_t lim) {
size_t i = 0;
while (i < lim) {
if (!src[i]) {
dst[i] = 0;
return dst;
}
dst[i] = src[i];
++i;
}
return dst;
}
char *strchr(const char *s, int c) {
while (*s) {
if (*s == (char) c) {
return (char *) s;
}
++s;
}
return NULL;
}
char *strrchr(const char *s, int c) {
ssize_t l = (ssize_t) strlen(s);
if (!l) {
return NULL;
}
while (l >= 0) {
if (s[l] == (char) c) {
return (char *) &s[l];
}
--l;
}
return NULL;
}
void *memmove(void *dest, const void *src, size_t n) {
char *d = dest;
const char *s = src;
if (d == s) {
return d;
}
if ((s + n) <= d || (d + n) <= s) {
return memcpy(d, s, n);
}
if (d < s) {
if (((uintptr_t) s) % sizeof(size_t) == ((uintptr_t) d) % sizeof(size_t)) {
while (((uintptr_t) d) % sizeof(size_t)) {
if (!n--) {
return dest;
}
*d++ = *s++;
}
for (; n >= sizeof(size_t); n -= sizeof(size_t), d += sizeof(size_t), s += sizeof(size_t)) {
*((size_t *) d) = *((size_t *) s);
}
}
for (; n; n--) {
*d++ = *s++;
}
} else {
if (((uintptr_t) s) % sizeof(size_t) == ((uintptr_t) d) % sizeof(size_t)) {
while (((uintptr_t) (d + n)) % sizeof(size_t)) {
if (!n--) {
return dest;
}
d[n] = s[n];
}
while (n >= sizeof(size_t)) {
n -= sizeof(size_t);
*((size_t *) (d + n)) = *((size_t *) (s + n));
}
}
while (n) {
n--;
d[n] = s[n];
}
}
return dest;
}

View File

@ -1,18 +0,0 @@
#include "sys/thread.h"
#include "sys/mem.h"
int thread_info_init(thread_info_t *info) {
info->flags = 0;
info->parent = 0;
info->pid = 0;
info->space = 0;
info->status = 0;
memset(info->fds, 0, sizeof(info->fds));
info->ioctx.cwd_vnode = NULL;
info->ioctx.uid = 0;
info->ioctx.gid = 0;
return 0;
}

View File

@ -1,3 +0,0 @@
#include "sys/time.h"
volatile uint64_t systick;

107
sys/tty.c
View File

@ -1,107 +0,0 @@
#include "sys/tty.h"
#include "sys/chr.h"
#include "sys/errno.h"
#include "sys/debug.h"
#include "sys/panic.h"
#include "sys/mem.h"
#define DEV_TTY(n) (n ## ULL)
#define DEV_DATA_TTY(n) ((void *) n ## ULL)
#define DEV_DATA_GETTTY(d) ((uint64_t) (d)->dev_data)
static ssize_t tty_write(struct chrdev *tty, const void *buf, size_t pos, size_t lim);
static ssize_t tty_read(struct chrdev *tty, void *buf, size_t pos, size_t lim);
static struct chrdev _dev_tty0 = {
.name = "tty0",
.dev_data = DEV_DATA_TTY(0),
.write = tty_write,
.read = tty_read
};
static vnode_t _tty0 = {
.type = VN_CHR,
.dev = &_dev_tty0
};
vnode_t *tty0 = &_tty0;
// TODO: this seems very ugly
static char *_tty0_reading_now = NULL;
static size_t _tty0_left = 0;
// This function receives keystrokes from keyboard drivers
void tty_buffer_write(int tty_no, char c) {
asm volatile ("cli");
if (tty_no != 0) {
panic("Not implemented\n");
}
if (!_tty0_left) {
// Ignore keystrokes sent while we're not reading
// This is bad and should be reimplemented by
// storing key data inside a ring buffer
return;
}
// No safety
*_tty0_reading_now++ = c;
--_tty0_left;
}
void tty_init(void) {
}
// TODO: multiple ttys
static ssize_t tty_write(struct chrdev *tty, const void *buf, size_t pos, size_t lim) {
uint64_t tty_no = DEV_DATA_GETTTY(tty);
if (tty_no != DEV_TTY(0)) {
return -EINVAL;
}
// TODO: buffer sanity checks
for (size_t i = 0; i < lim; ++i) {
debugc(DEBUG_INFO, ((const char *) buf)[i]);
}
return lim;
}
static ssize_t tty_read(struct chrdev *tty, void *buf, size_t pos, size_t lim) {
uint64_t tty_no = DEV_DATA_GETTTY(tty);
char ibuf[16];
if (tty_no != DEV_TTY(0)) {
return -EINVAL;
}
if (lim == 0) {
return 0;
}
#define MIN(x, y) ((x) < (y) ? (x) : (y))
size_t read = 0;
while (lim > 0) {
// XXX: This is very ugly
// Better just send the task to some kind of "busy"
// state and then wait
size_t read_now = MIN(16, lim);
_tty0_left = read_now;
_tty0_reading_now = ibuf;
while (1) {
asm volatile ("cli");
if (_tty0_left == 0) {
break;
}
asm volatile ("sti; hlt");
}
// Read 16 byte block
lim -= read_now;
// TODO: memcpy_kernel_to_user
memcpy((void *) ((uintptr_t) buf + read), ibuf, read_now);
read += read_now;
}
return 16;
}

View File

@ -1,152 +0,0 @@
#include "sys/fs/ext2.h"
#include "sys/fs/vfs.h"
#include "sys/debug.h"
#include "sys/panic.h"
#include "sys/errno.h"
#include "sys/heap.h"
enum vnode_type ext2_inode_type(struct ext2_inode *i) {
uint16_t v = i->type_perm & 0xF000;
switch (v) {
case EXT2_TYPE_DIR:
return VN_DIR;
case EXT2_TYPE_REG:
return VN_REG;
case EXT2_TYPE_LNK:
return VN_LNK;
default:
// fprintf(stderr, "Unknown file type: %x\n", v);
// abort();
panic("Unknown file type: %x\n", v);
return 0;
}
}
static int ext2_fs_mount(fs_t *fs, const char *opt) {
int res;
kdebug("ext2_fs_mount()\n");
struct ext2_extsb *sb;
// ext2's private data is its superblock structure
sb = (struct ext2_extsb *) kmalloc(EXT2_SBSIZ);
fs->fs_private = sb;
// Read the superblock from blkdev
if ((res = blk_read(fs->blk, sb, EXT2_SBOFF, EXT2_SBSIZ)) != EXT2_SBSIZ) {
kfree(fs->fs_private);
kerror("ext2: superblock read failed\n");
return -EINVAL;
}
// Check if superblock is ext2
if (sb->sb.magic != EXT2_MAGIC) {
kfree(sb);
kdebug("ext2: magic mismatch\n");
return -EINVAL;
}
// Check if we have an extended ext2 sb
if (sb->sb.version_major == 0) {
// Initialize params which are missing in non-extended sbs
sb->inode_struct_size = 128;
sb->first_non_reserved = 11;
}
sb->block_size = 1024 << sb->sb.block_size_log;
// Load block group descriptor table
// Get descriptor table size
uint32_t block_group_descriptor_table_length = sb->sb.block_count / sb->sb.block_group_size_blocks;
if (block_group_descriptor_table_length * sb->sb.block_group_size_blocks < sb->sb.block_count) {
++block_group_descriptor_table_length;
}
sb->block_group_count = block_group_descriptor_table_length;
uint32_t block_group_descriptor_table_size_blocks = 32 * block_group_descriptor_table_length /
sb->block_size + 1;
uint32_t block_group_descriptor_table_block = 2;
if (sb->block_size > 1024) {
block_group_descriptor_table_block = 1;
}
sb->block_group_descriptor_table_block = block_group_descriptor_table_block;
sb->block_group_descriptor_table_size_blocks = block_group_descriptor_table_size_blocks;
// Load all block group descriptors into memory
kdebug("Allocating %u bytes for BGDT\n", sb->block_group_descriptor_table_size_blocks * sb->block_size);
sb->block_group_descriptor_table = (struct ext2_grp_desc *) kmalloc(sb->block_group_descriptor_table_size_blocks * sb->block_size);
for (size_t i = 0; i < sb->block_group_descriptor_table_size_blocks; ++i) {
ext2_read_block(fs, i + sb->block_group_descriptor_table_block,
(void *) (((uintptr_t) sb->block_group_descriptor_table) + i * sb->block_size));
}
return 0;
}
static int ext2_fs_umount(fs_t *fs) {
struct ext2_extsb *sb = (struct ext2_extsb *) fs->fs_private;
// Free block group descriptor table
kfree(sb->block_group_descriptor_table);
// Free superblock
kfree(sb);
return 0;
}
static vnode_t *ext2_fs_get_root(fs_t *fs) {
struct ext2_extsb *sb = fs->fs_private;
kdebug("ext2_fs_get_root()\n");
struct ext2_inode *inode = (struct ext2_inode *) kmalloc(sb->inode_struct_size);
// Read root inode (2)
if (ext2_read_inode(fs, inode, EXT2_ROOTINO) != 0) {
kfree(inode);
return NULL;
}
vnode_t *res = (vnode_t *) kmalloc(sizeof(vnode_t));
res->fs = fs;
res->fs_data = inode;
res->fs_number = EXT2_ROOTINO;
res->op = &ext2_vnode_ops;
res->type = ext2_inode_type(inode);
return res;
}
static int ext2_fs_statvfs(fs_t *fs, struct statvfs *st) {
struct ext2_extsb *sb = fs->fs_private;
st->f_blocks = sb->sb.block_count;
st->f_bfree = sb->sb.free_block_count;
st->f_bavail = sb->sb.block_count - sb->sb.su_reserved;
st->f_files = sb->sb.inode_count;
st->f_ffree = sb->sb.free_inode_count;
st->f_favail = sb->sb.inode_count - sb->first_non_reserved + 1;
st->f_bsize = sb->block_size;
st->f_frsize = sb->block_size;
// XXX: put something here
st->f_fsid = 0;
st->f_flag = 0;
st->f_namemax = 256;
return 0;
}
static struct fs_class ext2_class = {
.name = "ext2",
.get_root = ext2_fs_get_root,
.mount = ext2_fs_mount,
.umount = ext2_fs_umount,
.statvfs = ext2_fs_statvfs
};
void ext2_class_init(void) {
fs_class_register(&ext2_class);
}

View File

@ -1,319 +0,0 @@
// ext2fs block/inode alloc/free
#include "sys/fs/ext2.h"
#include "sys/string.h"
#include "sys/assert.h"
#include "sys/debug.h"
#include "sys/errno.h"
// #include <assert.h>
// #include <stdlib.h>
// #include <errno.h>
// #include <stdio.h>
int ext2_alloc_block(fs_t *ext2, uint32_t *block_no) {
struct ext2_extsb *sb = (struct ext2_extsb *) ext2->fs_private;
char block_buffer[sb->block_size];
uint32_t res_block_no = 0;
uint32_t res_group_no = 0;
uint32_t res_block_no_in_group = 0;
int found = 0;
int res;
for (size_t i = 0; i < sb->block_group_count; ++i) {
if (sb->block_group_descriptor_table[i].free_blocks > 0) {
// Found a free block here
kdebug("Allocating a block in group #%zu\n", i);
if ((res = ext2_read_block(ext2,
sb->block_group_descriptor_table[i].block_usage_bitmap_block,
block_buffer)) < 0) {
return res;
}
for (size_t j = 0; j < sb->block_size / sizeof(uint64_t); ++j) {
uint64_t qw = ((uint64_t *) block_buffer)[j];
if (qw != (uint64_t) -1) {
for (size_t k = 0; k < 64; ++k) {
if (!(qw & (1 << k))) {
res_block_no_in_group = k + j * 64;
res_group_no = i;
// XXX: had to increment the resulting block_no
// because for some reason linux's ext2
// impl hasn't marked #531 as used in one
// case, but it was actually a L1-indirect
// block. So I just had to make it allocate
// #532 instead as a workaround (though
// block numbering should start with 0)
res_block_no = res_block_no_in_group + i * sb->sb.block_group_size_blocks + 1;
found = 1;
break;
}
}
if (found) {
break;
}
}
}
if (found) {
break;
}
}
}
if (!found) {
return -ENOSPC;
}
// Write block usage bitmap
((uint64_t *) block_buffer)[res_block_no_in_group / 64] |= (1 << (res_block_no_in_group % 64));
if ((res = ext2_write_block(ext2,
sb->block_group_descriptor_table[res_group_no].block_usage_bitmap_block,
block_buffer)) < 0) {
return res;
}
// Update BGDT
--sb->block_group_descriptor_table[res_group_no].free_blocks;
for (size_t i = 0; i < sb->block_group_descriptor_table_size_blocks; ++i) {
void *blk_ptr = (void *) (((uintptr_t) sb->block_group_descriptor_table) + i * sb->block_size);
if ((res = ext2_write_block(ext2, sb->block_group_descriptor_table_block + i, blk_ptr)) < 0) {
return res;
}
}
// Update global block count and flush superblock
--sb->sb.free_block_count;
if ((res = ext2_write_superblock(ext2)) < 0) {
return res;
}
*block_no = res_block_no;
kdebug("Allocated block #%u\n", res_block_no);
return 0;
}
int ext2_free_block(fs_t *ext2, uint32_t block_no) {
_assert(block_no);
struct ext2_extsb *sb = (struct ext2_extsb *) ext2->fs_private;
char block_buffer[sb->block_size];
int res;
uint32_t block_group_no = (block_no - 1) / sb->sb.block_group_size_blocks;
uint32_t block_no_in_group = (block_no - 1) % sb->sb.block_group_size_blocks;
// Read block ussge bitmap block
if ((res = ext2_read_block(ext2,
sb->block_group_descriptor_table[block_group_no].block_usage_bitmap_block,
block_buffer)) < 0) {
return res;
}
// Update the bitmap
_assert(((uint64_t *) block_buffer)[block_no_in_group / 64] & (1 << (block_no_in_group % 64)));
((uint64_t *) block_buffer)[block_no_in_group / 64] &= ~(1 << (block_no_in_group % 64));
if ((res = ext2_write_block(ext2,
sb->block_group_descriptor_table[block_group_no].block_usage_bitmap_block,
block_buffer)) < 0) {
return res;
}
// Update BGDT
++sb->block_group_descriptor_table[block_group_no].free_blocks;
for (size_t i = 0; i < sb->block_group_descriptor_table_size_blocks; ++i) {
void *blk_ptr = (void *) (((uintptr_t) sb->block_group_descriptor_table) + i * sb->block_size);
if ((res = ext2_write_block(ext2, sb->block_group_descriptor_table_block + i, blk_ptr)) < 0) {
return res;
}
}
// Update global block count
++sb->sb.free_block_count;
if ((res = ext2_write_superblock(ext2)) < 0) {
return res;
}
kdebug("Freed block #%u\n", block_no);
return 0;
}
int ext2_inode_alloc_block(fs_t *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index) {
if (index >= 12) {
panic("Not implemented\n");
}
int res;
uint32_t block_no;
// Allocate the block itself
if ((res = ext2_alloc_block(ext2, &block_no)) < 0) {
return res;
}
// Write direct block list entry
inode->direct_blocks[index] = block_no;
// Flush changes to the device
return ext2_write_inode(ext2, inode, ino);
}
int ext2_free_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index) {
if (index >= 12) {
panic("Not implemented\n");
}
// All sanity checks regarding whether the block is present
// at all are left to the caller
int res;
uint32_t block_no;
// Get block number
block_no = inode->direct_blocks[index];
// Free the block
if ((res = ext2_free_block(ext2, block_no)) < 0) {
return res;
}
// Write updated inode
inode->direct_blocks[index] = 0;
return ext2_write_inode(ext2, inode, ino);
}
int ext2_free_inode(fs_t *ext2, uint32_t ino) {
_assert(ino);
struct ext2_extsb *sb = (struct ext2_extsb *) ext2->fs_private;
char block_buffer[sb->block_size];
uint32_t ino_block_group_number = (ino - 1) / sb->sb.block_group_size_inodes;
uint32_t ino_inode_index_in_group = (ino - 1) % sb->sb.block_group_size_inodes;
int res;
// Read inode usage block
if ((res = ext2_read_block(ext2,
sb->block_group_descriptor_table[ino_block_group_number].inode_usage_bitmap_block,
block_buffer)) < 0) {
return res;
}
// Remove usage bit
_assert(((uint64_t *) block_buffer)[ino_inode_index_in_group / 64] & (1 << (ino_inode_index_in_group % 64)));
((uint64_t *) block_buffer)[ino_inode_index_in_group / 64] &= ~(1 << (ino_inode_index_in_group % 64));
// Write modified bitmap back
if ((res = ext2_write_block(ext2,
sb->block_group_descriptor_table[ino_block_group_number].inode_usage_bitmap_block,
block_buffer)) < 0) {
return res;
}
// Increment free inode count in BGDT entry and write it back
// TODO: this code is repetitive and maybe should be moved to
// ext2_bgdt_inode_inc/_dec()
++sb->block_group_descriptor_table[ino_block_group_number].free_inodes;
for (size_t i = 0; i < sb->block_group_descriptor_table_size_blocks; ++i) {
void *blk_ptr = (void *) (((uintptr_t) sb->block_group_descriptor_table) + i * sb->block_size);
if ((res = ext2_write_block(ext2, sb->block_group_descriptor_table_block + i, blk_ptr)) < 0) {
return res;
}
}
// Update global inode count
++sb->sb.free_inode_count;
if ((res = ext2_write_superblock(ext2)) < 0) {
return res;
}
kdebug("Freed inode #%u\n", ino);
return 0;
}
int ext2_alloc_inode(fs_t *ext2, uint32_t *ino) {
struct ext2_extsb *sb = (struct ext2_extsb *) ext2->fs_private;
char block_buffer[sb->block_size];
uint32_t res_ino = 0;
uint32_t res_group_no = 0;
uint32_t res_ino_number_in_group = 0;
int res;
// Look through BGDT to find any block groups with free inodes
for (size_t i = 0; i < sb->block_group_count; ++i) {
if (sb->block_group_descriptor_table[i].free_inodes > 0) {
// Found a block group with free inodes
kdebug("Allocating an inode inside block group #%zu\n", i);
// Read inode usage bitmap
if ((res = ext2_read_block(ext2,
sb->block_group_descriptor_table[i].inode_usage_bitmap_block,
block_buffer)) < 0) {
return res;
}
// Find a free bit
// Think this should be fine on amd64
for (size_t j = 0; j < sb->block_size / sizeof(uint64_t); ++j) {
// Get bitmap qword
uint64_t qw = ((uint64_t *) block_buffer)[j];
// If not all bits are set in this qword, find exactly which one
if (qw != ((uint64_t) -1)) {
for (size_t k = 0; k < 64; ++k) {
if (!(qw & (1 << k))) {
res_ino_number_in_group = k + j * 64;
res_group_no = i;
res_ino = res_ino_number_in_group + i * sb->sb.block_group_size_inodes + 1;
break;
}
}
if (res_ino) {
break;
}
}
if (res_ino) {
break;
}
}
}
if (res_ino) {
break;
}
}
if (res_ino == 0) {
return -ENOSPC;
}
// Write updated bitmap
((uint64_t *) block_buffer)[res_ino_number_in_group / 64] |= (1 << (res_ino_number_in_group % 64));
if ((res = ext2_write_block(ext2,
sb->block_group_descriptor_table[res_group_no].inode_usage_bitmap_block,
block_buffer)) < 0) {
return res;
}
// Write updated BGDT
--sb->block_group_descriptor_table[res_group_no].free_inodes;
for (size_t i = 0; i < sb->block_group_descriptor_table_size_blocks; ++i) {
void *blk_ptr = (void *) (((uintptr_t) sb->block_group_descriptor_table) + i * sb->block_size);
if ((res = ext2_write_block(ext2, sb->block_group_descriptor_table_block + i, blk_ptr)) < 0) {
return res;
}
}
// Update global inode count and flush superblock
--sb->sb.free_inode_count;
if ((res = ext2_write_superblock(ext2)) < 0) {
return res;
}
*ino = res_ino;
return 0;
}

Some files were not shown because too many files have changed in this diff Show More