Remove everything
This commit is contained in:
parent
d0c709f772
commit
71eeb5d282
@ -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);
|
@ -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);
|
@ -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);
|
@ -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
|
@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void amd64_idt_init(void);
|
@ -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:" );
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
#define IRQ_BASE 32
|
||||
|
||||
void pic8259_init(void);
|
@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void amd64_irq1(void);
|
@ -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);
|
@ -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);
|
@ -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));
|
@ -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: 817–1984–19, 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 */
|
@ -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 */
|
@ -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);
|
@ -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);
|
@ -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);
|
@ -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);
|
@ -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);
|
@ -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);
|
@ -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);
|
@ -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;
|
||||
};
|
@ -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);
|
@ -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))
|
@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
#include "sys/thread.h"
|
||||
|
||||
int elf_load(thread_t *thr, const void *eptr);
|
@ -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);
|
@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
#include "sys/blk.h"
|
||||
|
||||
extern struct blkdev *ramblk0;
|
||||
|
||||
void ramblk_init(uintptr_t at, size_t len);
|
@ -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);
|
@ -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: 817–1984–19, 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 */
|
||||
|
@ -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[];
|
||||
};
|
@ -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;
|
@ -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
|
||||
|
@ -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);
|
@ -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);
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct list_simple {
|
||||
void *car;
|
||||
struct list_simple *cdr;
|
||||
} list_simple_t;
|
||||
|
@ -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);
|
@ -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];
|
||||
};
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
#include "sys/fs/fs.h"
|
||||
|
||||
void tarfs_init(void);
|
@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
#include "list.h"
|
||||
|
||||
typedef struct tree {
|
||||
void *value;
|
||||
struct tree *parent;
|
||||
list_simple_t *children;
|
||||
} tree_t;
|
@ -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);
|
@ -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
|
@ -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);
|
@ -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);
|
141
include/sys/mm.h
141
include/sys/mm.h
@ -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);
|
@ -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));
|
@ -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);
|
@ -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);
|
@ -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
|
@ -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);
|
@ -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;
|
@ -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);
|
@ -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;
|
@ -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);
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
@ -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
|
@ -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");
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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
11
sys/amd64/hw/rs232.S
Normal 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
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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 ? " -> " : ""));
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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));
|
||||
}
|
@ -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
14
sys/amd64/string.S
Normal 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
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
@ -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");
|
||||
}
|
101
sys/binfmt_elf.c
101
sys/binfmt_elf.c
@ -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;
|
||||
}
|
23
sys/blk.c
23
sys/blk.c
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
22
sys/chr.c
22
sys/chr.c
@ -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);
|
||||
}
|
54
sys/conf.mk
54
sys/conf.mk
@ -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
|
||||
|
12
sys/errno.c
12
sys/errno.c
@ -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";
|
||||
}
|
||||
}
|
38
sys/errno.h
38
sys/errno.h
@ -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);
|
15
sys/mem.c
15
sys/mem.c
@ -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;
|
||||
}
|
16
sys/panic.c
16
sys/panic.c
@ -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();
|
||||
}
|
50
sys/sched.c
50
sys/sched.c
@ -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;
|
||||
}
|
129
sys/string.c
129
sys/string.c
@ -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;
|
||||
}
|
18
sys/thread.c
18
sys/thread.c
@ -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;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
#include "sys/time.h"
|
||||
|
||||
volatile uint64_t systick;
|
107
sys/tty.c
107
sys/tty.c
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user