Compare commits
4 commits
main
...
basic_pagi
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b4e4afd43 | |||
| 6261af8e3a | |||
| e1369902f7 | |||
|
|
20357559c1 |
20 changed files with 466 additions and 139 deletions
|
|
@ -3,4 +3,3 @@
|
||||||
i686-elf-gdb build/ukern.elf \
|
i686-elf-gdb build/ukern.elf \
|
||||||
-ex "target remote localhost:1234" \
|
-ex "target remote localhost:1234" \
|
||||||
-ex "break start" \
|
-ex "break start" \
|
||||||
-ex "continue"
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,32 @@
|
||||||
/* asm.h
|
/**
|
||||||
* Assembly wrappers
|
* @file asm.h
|
||||||
*
|
* @brief Assembly wrappers
|
||||||
* Wrapper functions for using assembly files.
|
* @author Jake "lordtet" Holtham
|
||||||
*/
|
* @date 2025
|
||||||
|
* Wrapper functions for using assembly files.
|
||||||
|
*/
|
||||||
#ifndef ASM_H
|
#ifndef ASM_H
|
||||||
#define ASM_H
|
#define ASM_H
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define COM1 0x3F8
|
/**
|
||||||
#define COM2 0x2F8
|
* @brief Wrapper for asm instruction `out` that feeds a byte.
|
||||||
|
* @param port I/O Address for the port to send to
|
||||||
|
* @param data Data to send
|
||||||
|
*/
|
||||||
void outb(uint16_t port, uint8_t data);
|
void outb(uint16_t port, uint8_t data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wrapper for asm instruction "in" that receives bytewise.
|
||||||
|
* @param port I/O Address for the port to listen from
|
||||||
|
* @return (uint8_t) The received byte.
|
||||||
|
*/
|
||||||
uint8_t inb(uint16_t port);
|
uint8_t inb(uint16_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Refresh the CR3 register.
|
||||||
|
* Moves CR3 into a scratch register and back into CR3. Usually used to nuke the TLB.
|
||||||
|
*/
|
||||||
|
void cr3_reload();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,62 @@
|
||||||
/* IDT.h
|
/**
|
||||||
* Interrupt Descriptor Table
|
* @file idt.h
|
||||||
*
|
* @brief Interrupt Descriptor Table
|
||||||
* IDT related structures, globals and functions
|
* @author Jake "lordtet" Holtham
|
||||||
*/
|
* @date 2025
|
||||||
|
* IDT related structures, globals and functions
|
||||||
|
*/
|
||||||
#ifndef IDT_H
|
#ifndef IDT_H
|
||||||
#define IDT_H
|
#define IDT_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IDT Entry
|
||||||
|
*/
|
||||||
typedef struct InterruptDescriptor_s {
|
typedef struct InterruptDescriptor_s {
|
||||||
uint16_t offset_lo;
|
uint16_t offset_lo; /**< Lower 16 bits of ISR ptr */
|
||||||
uint16_t selector;
|
uint16_t selector; /**< */
|
||||||
uint8_t reserved;
|
uint8_t reserved; /**< Nothing */
|
||||||
uint8_t attributes;
|
uint8_t attributes; /**< */
|
||||||
uint16_t offset_hi;
|
uint16_t offset_hi; /**< Upper 16 bits of ISR ptr */
|
||||||
} InterruptDescriptor_t;
|
} InterruptDescriptor_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
typedef struct IDTR_s {
|
typedef struct IDTR_s {
|
||||||
uint16_t size;
|
uint16_t size; /**< IDT Length */
|
||||||
InterruptDescriptor_t* IDT;
|
InterruptDescriptor_t* IDT; /**< Pointer to the IDT Entry array */
|
||||||
} __attribute__((packed)) IDTR_t;
|
} __attribute__((packed)) IDTR_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The IDTR in memory.
|
||||||
|
*/
|
||||||
extern IDTR_t idtr;
|
extern IDTR_t idtr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief First IDT Entry
|
||||||
|
*/
|
||||||
extern InterruptDescriptor_t idt_start;
|
extern InterruptDescriptor_t idt_start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Amount of ISRs implemented
|
||||||
|
*/
|
||||||
extern unsigned char num_interrupts;
|
extern unsigned char num_interrupts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Call setup and write to construct and load the IDT.
|
||||||
|
*/
|
||||||
void setup_idt();
|
void setup_idt();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write the IDT and IDTR
|
||||||
|
*/
|
||||||
void write_descriptors();
|
void write_descriptors();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LIDT call
|
||||||
|
*/
|
||||||
extern void load_idt();
|
extern void load_idt();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,31 @@
|
||||||
/* interrupt_handlers.h
|
/**
|
||||||
* Interrupt Handlers
|
* @file interrupt_handlers.h
|
||||||
*
|
* @brief Interrupt Handlers
|
||||||
* Functions and structs for the C side of handling interrupts.
|
* @details Functions and structs for the C side of handling interrupts.
|
||||||
*/
|
*/
|
||||||
#ifndef INTERRUPTHANDLERS_H
|
#ifndef INTERRUPTHANDLERS_H
|
||||||
#define INTERRUPTHANDLERS_H
|
#define INTERRUPTHANDLERS_H
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
extern void (*isr_ptrs[])(void);
|
extern void (*isr_ptrs[])(void);
|
||||||
|
|
||||||
//Struct is built "backwards" since it is pushed in this order.
|
/**
|
||||||
|
* @brief
|
||||||
|
* @details Struct is built "backwards" since it is pushed in this order.
|
||||||
|
*/
|
||||||
typedef struct StateSnapshot_s {
|
typedef struct StateSnapshot_s {
|
||||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
|
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; /**< @brief */
|
||||||
uint32_t interrupt_id, error_code;
|
uint32_t interrupt_id, error_code; /**< @brief */
|
||||||
uint32_t eip, cs, eflags;
|
uint32_t eip, cs, eflags; /**< @brief */
|
||||||
} StateSnapshot_t;
|
} StateSnapshot_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @param cpu_state
|
||||||
|
*/
|
||||||
void generic_isr_handler(StateSnapshot_t* cpu_state);
|
void generic_isr_handler(StateSnapshot_t* cpu_state);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
68
include/io.h
68
include/io.h
|
|
@ -1,26 +1,78 @@
|
||||||
/* io.h
|
/**
|
||||||
* In/Out
|
* @file io.h
|
||||||
*
|
* @brief In/Out
|
||||||
* Common library for handling user i/o. Aims to be mechanic agnostic, and instead
|
* @details Common library for handling user i/o. Aims to be mechanic agnostic, and instead
|
||||||
* focus on implementing generic functions to format and manipulate data.
|
* focus on implementing generic functions to format and manipulate data.
|
||||||
*/
|
*/
|
||||||
#ifndef IO_H
|
#ifndef IO_H
|
||||||
#define IO_H
|
#define IO_H
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
typedef struct char_writer_s char_writer_t;
|
typedef struct char_writer_s char_writer_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
struct char_writer_s {
|
struct char_writer_s {
|
||||||
int (*putChar)(void* ctx, char out);
|
int (*putChar)(void* ctx, char out); /**< @brief */
|
||||||
void* ctx;
|
void* ctx; /**< @brief */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
extern char_writer_t* default_output;
|
extern char_writer_t* default_output;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @param
|
||||||
|
* @param
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
int putc(char_writer_t*, char);
|
int putc(char_writer_t*, char);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @param
|
||||||
|
* @param
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
int print(char_writer_t*, const char*);
|
int print(char_writer_t*, const char*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @param
|
||||||
|
* @param
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
int println(char_writer_t*, const char*);
|
int println(char_writer_t*, const char*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @param
|
||||||
|
* @param
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
int printhex(char_writer_t*, uint64_t);
|
int printhex(char_writer_t*, uint64_t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @param
|
||||||
|
* @param out
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
int prindec(char_writer_t*, uint64_t out);
|
int prindec(char_writer_t*, uint64_t out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @param
|
||||||
|
* @param fmt
|
||||||
|
* @param ...
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
int printf(char_writer_t*, const char* fmt, ...);
|
int printf(char_writer_t*, const char* fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,47 @@
|
||||||
/* kmultiboot.h
|
/**
|
||||||
* Kernel Multiboot
|
* @file kmultiboot.h
|
||||||
*
|
* @brief Kernel Multiboot
|
||||||
* Data needed for multiboot compatibility.
|
* @details Data needed for multiboot compatibility.
|
||||||
*/
|
*/
|
||||||
#ifndef KMULTIBOOT_H
|
#ifndef KMULTIBOOT_H
|
||||||
#define KMULTIBOOT_H
|
#define KMULTIBOOT_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
typedef struct multiboot_mmap_entry {
|
typedef struct multiboot_mmap_entry {
|
||||||
uint32_t entry_size; //size of this struct entry
|
uint32_t entry_size; /**< @brief size of this struct entry */
|
||||||
uint64_t addr; //physical location of memory
|
uint64_t addr; /**< @brief physical location of memory */
|
||||||
uint64_t mem_size; //size of the memory block
|
uint64_t mem_size; /**< @brief size of the memory block */
|
||||||
uint32_t type;
|
uint32_t type; /**< @brief */
|
||||||
} __attribute__((packed)) mb_mmap_entry_t;
|
} __attribute__((packed)) mb_mmap_entry_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
typedef struct mb_info_s {
|
typedef struct mb_info_s {
|
||||||
uint32_t flags;
|
uint32_t flags; /**< @brief */
|
||||||
uint32_t mem_lower;
|
uint32_t mem_lower; /**< @brief */
|
||||||
uint32_t mem_upper;
|
uint32_t mem_upper; /**< @brief */
|
||||||
uint32_t boot_device;
|
uint32_t boot_device; /**< @brief */
|
||||||
uint32_t cmdline;
|
uint32_t cmdline; /**< @brief */
|
||||||
uint32_t mods_count;
|
uint32_t mods_count; /**< @brief */
|
||||||
uint32_t mods_addr;
|
uint32_t mods_addr; /**< @brief */
|
||||||
uint32_t syms[4];
|
uint32_t syms[4]; /**< @brief */
|
||||||
uint32_t mmap_length;
|
uint32_t mmap_length; /**< @brief */
|
||||||
uint32_t mmap_addr;
|
uint32_t mmap_addr; /**< @brief */
|
||||||
} mb_info_t;
|
} mb_info_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
extern uint8_t _kernel_start;
|
extern uint8_t _kernel_start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
extern uint8_t _kernel_end;
|
extern uint8_t _kernel_end;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/* kttools.h
|
/**
|
||||||
* Kernel Type Tools
|
* @file kttools.h
|
||||||
*
|
* @brief Kernel Type Tools
|
||||||
* Library for converting types and transcribing data.
|
* @details Library for converting types and transcribing data.
|
||||||
*/
|
*/
|
||||||
#ifndef KTTOOLS_H
|
#ifndef KTTOOLS_H
|
||||||
#define KTTOOLS_H
|
#define KTTOOLS_H
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,29 @@
|
||||||
|
/**
|
||||||
|
* @file physmem.h
|
||||||
|
* @brief
|
||||||
|
* @details
|
||||||
|
*/
|
||||||
#ifndef PHYSMEM_H
|
#ifndef PHYSMEM_H
|
||||||
#define PHYSMEM_H
|
#define PHYSMEM_H
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "kmultiboot.h"
|
#include "kmultiboot.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
#define PAGE_SIZE 0x1000
|
#define PAGE_SIZE 0x1000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
extern uint8_t* pmem_bitmap;
|
extern uint8_t* pmem_bitmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @param mmap
|
||||||
|
* @param mmap_size
|
||||||
|
* @return unsigned int
|
||||||
|
*/
|
||||||
unsigned int build_bitmap(mb_mmap_entry_t* mmap, int mmap_size);
|
unsigned int build_bitmap(mb_mmap_entry_t* mmap, int mmap_size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,11 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define COM1 0x3F8
|
||||||
|
#define COM2 0x2F8
|
||||||
|
|
||||||
typedef struct serial_ctx_s {
|
typedef struct serial_ctx_s {
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
} serial_ctx_t;
|
} serial_ctx_t;
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,64 @@
|
||||||
/* tss.h
|
/**
|
||||||
* Task State Segment
|
* @file tss.h
|
||||||
*
|
* @brief Task State Segment (TSS) definitions and structures
|
||||||
* Structure definitions for the TSS
|
* @author Jake Holtham
|
||||||
|
* @date 2025
|
||||||
|
*
|
||||||
|
* This header file contains the structure definitions for the x86 Task State Segment (TSS).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TSS_H
|
#ifndef TSS_H
|
||||||
#define TSS_H
|
#define TSS_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// TSS
|
/**
|
||||||
|
* @brief Task State Segment structure
|
||||||
|
*
|
||||||
|
* Data structure that contains information about a task,
|
||||||
|
* including the state of the processor registers, stack pointers, and other task-specific
|
||||||
|
* information. It is used by the x86 architecture for task switching and interrupt handling.
|
||||||
|
*
|
||||||
|
* Packed to make sure it's aligned and the correct size.
|
||||||
|
*
|
||||||
|
* @note This structure must be aligned on a 4byte boundary
|
||||||
|
*/
|
||||||
typedef struct tss_s {
|
typedef struct tss_s {
|
||||||
uint32_t LINK;
|
uint32_t LINK; /**< Previous TSS selector*/
|
||||||
uint32_t ESP0;
|
uint32_t ESP0; /**< Stack pointer for privilege level0*/
|
||||||
uint32_t SS0;
|
uint32_t SS0; /**< Stack segment for privilege level0*/
|
||||||
uint32_t ESP1;
|
uint32_t ESP1; /**< Stack pointer for privilege level1*/
|
||||||
uint32_t SS1;
|
uint32_t SS1; /**< Stack segment for privilege level1*/
|
||||||
uint32_t ESP2;
|
uint32_t ESP2; /**< Stack pointer for privilege level2*/
|
||||||
uint32_t SS2;
|
uint32_t SS2; /**< Stack segment for privilege level2*/
|
||||||
uint32_t CR3;
|
uint32_t CR3; /**< Page Directory register */
|
||||||
uint32_t EIP;
|
uint32_t EIP; /**< Instruction pointer */
|
||||||
uint32_t EFLAGS;
|
uint32_t EFLAGS; /**< Flags register */
|
||||||
uint32_t EAX;
|
uint32_t EAX; /**< General purpose */
|
||||||
uint32_t ECX;
|
uint32_t ECX; /**< General purpose */
|
||||||
uint32_t EDX;
|
uint32_t EDX; /**< General purpose */
|
||||||
uint32_t EBX;
|
uint32_t EBX; /**< General purpose */
|
||||||
uint32_t ESP;
|
uint32_t ESP; /**< Stack pointer */
|
||||||
uint32_t ESI;
|
uint32_t ESI; /**< Source index register */
|
||||||
uint32_t EDI;
|
uint32_t EDI; /**< Destination index register */
|
||||||
uint32_t ES;
|
uint32_t ES; /**< Extra segment register */
|
||||||
uint32_t CS;
|
uint32_t CS; /**< Code segment register */
|
||||||
uint32_t SS;
|
uint32_t SS; /**< Stack segment register */
|
||||||
uint32_t DS;
|
uint32_t DS; /**< Data segment register */
|
||||||
uint32_t FS;
|
uint32_t FS; /**< Extra segment register FS */
|
||||||
uint32_t GS;
|
uint32_t GS; /**< Extra segment register GS */
|
||||||
uint32_t LDTR;
|
uint32_t LDTR; /**< Local descriptor table register */
|
||||||
uint32_t IOPB;
|
uint32_t IOPB; /**< I/O permission bitmap offset */
|
||||||
uint32_t SSP;
|
uint32_t SSP; /**< Stack segment pointer */
|
||||||
} __attribute__((packed)) tss_t;
|
} __attribute__((packed)) tss_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Global TSS instance
|
||||||
|
*
|
||||||
|
* This is the main TSS instance used by the kernel for task management.
|
||||||
|
* It contains the current task's state information.
|
||||||
|
* Defined in assembly.
|
||||||
|
*/
|
||||||
extern tss_t tss;
|
extern tss_t tss;
|
||||||
|
|
||||||
|
#endif /* TSS_H */
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,71 @@
|
||||||
/* vga.h
|
/**
|
||||||
* VGA
|
* @file vga.h
|
||||||
*
|
* @brief VGA
|
||||||
* Responsible for VGA buffer control.
|
* @details Responsible for VGA buffer control.
|
||||||
*/
|
*/
|
||||||
#ifndef VGA_H
|
#ifndef VGA_H
|
||||||
#define VGA_H
|
#define VGA_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
#define VGA_GRID_COLS 80
|
#define VGA_GRID_COLS 80
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
#define VGA_GRID_ROWS 25
|
#define VGA_GRID_ROWS 25
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
#define DEFAULT_ATTRIBUTES 0x0F00
|
#define DEFAULT_ATTRIBUTES 0x0F00
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
/*
|
|
||||||
* CONSTANTS AND VARIABLES
|
|
||||||
*/
|
|
||||||
|
|
||||||
//Information on the VGA buffer
|
/**
|
||||||
|
* @brief Information on the VGA buffer
|
||||||
|
*/
|
||||||
extern volatile uint16_t* const vga_buffer;
|
extern volatile uint16_t* const vga_buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
typedef struct vga_ctx_s {
|
typedef struct vga_ctx_s {
|
||||||
int cursor_col;
|
int cursor_col; /**< @brief */
|
||||||
int cursor_row;
|
int cursor_row; /**< @brief */
|
||||||
uint16_t attributes;
|
uint16_t attributes; /**< @brief */
|
||||||
} vga_ctx_t;
|
} vga_ctx_t;
|
||||||
|
|
||||||
//grid is top left origin. This is our cursor!
|
/**
|
||||||
extern uint16_t vga_attributes; // Black background, White foreground
|
* @brief grid is top left origin. This is our cursor! Black background, White foreground
|
||||||
|
*/
|
||||||
|
extern uint16_t vga_attributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
extern char_writer_t* default_vga;
|
extern char_writer_t* default_vga;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Functions
|
* @brief Clear the VGA buffer, context optional
|
||||||
|
* @param ctx
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//Clear the VGA buffer, context optional
|
|
||||||
void vga_clear_ctx(vga_ctx_t* ctx);
|
void vga_clear_ctx(vga_ctx_t* ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
void vga_clear();
|
void vga_clear();
|
||||||
//Write character c to cursor
|
|
||||||
//Implements IO generic ASCII output
|
/**
|
||||||
|
* @brief Write character c to cursor. Implements IO generic ASCII output
|
||||||
|
* @param ctx
|
||||||
|
* @param c
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
int vga_out(void* ctx, char c);
|
int vga_out(void* ctx, char c);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
40
include/virtmem.h
Normal file
40
include/virtmem.h
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* @file virtmem.h
|
||||||
|
* @brief
|
||||||
|
* @details
|
||||||
|
*/
|
||||||
|
#ifndef VIRTMEM_H
|
||||||
|
#define VIRTMEM_H
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
|
extern uint32_t global_page_dir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
|
extern uint32_t kernel_pagetable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @param page_dir
|
||||||
|
* @param phys_loc
|
||||||
|
* @param virtual_loc
|
||||||
|
* @param page_opts
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
int map(uint32_t* page_dir, uint32_t phys_loc, uint32_t virtual_loc, uint8_t page_opts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @param phys_loc
|
||||||
|
* @param virtual_loc
|
||||||
|
* @param page_opts
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
int kmap(uint32_t phys_loc, uint32_t virtual_loc, uint8_t page_opts);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
26
linker.ld
26
linker.ld
|
|
@ -6,19 +6,31 @@ SECTIONS
|
||||||
/*start me at 1Mb because below that is x86 essential stuff, which we dont want to be written on top of.*/
|
/*start me at 1Mb because below that is x86 essential stuff, which we dont want to be written on top of.*/
|
||||||
. = 1M;
|
. = 1M;
|
||||||
|
|
||||||
_kernel_start = .;
|
|
||||||
|
|
||||||
/* we're going to maintain 4K alignment - apparently useful for paging, and i'm not complaining about the lost space anyway. */
|
/* we're going to maintain 4K alignment - apparently useful for paging, and i'm not complaining about the lost space anyway. */
|
||||||
/*our multiboot header from start.s - has to go at the beginning of the executable so the bootloader knows we're loadable.*/
|
/*our multiboot header from start.s - has to go at the beginning of the executable so the bootloader knows we're loadable.*/
|
||||||
/*executable section*/
|
/*executable section*/
|
||||||
.text BLOCK(4K) : ALIGN(4K)
|
.mb_sect :
|
||||||
{
|
{
|
||||||
*(.multiboot)
|
*(.multiboot)
|
||||||
|
}
|
||||||
|
|
||||||
|
.lower_text :
|
||||||
|
{
|
||||||
|
*(.lower_text)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Higher half addressing! We'll have to also specify that we want to be physically placed at 1MB.*/
|
||||||
|
. += 0xC0000000;
|
||||||
|
|
||||||
|
_kernel_start = .;
|
||||||
|
.text ALIGN (4K) : AT (ADDR (.text) - 0xC0000000)
|
||||||
|
{
|
||||||
*(.text)
|
*(.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*general read only data*/
|
/*general read only data*/
|
||||||
.rodata BLOCK(4K) : ALIGN(4K)
|
.rodata ALIGN (4K) : AT(ADDR(.rodata) - 0xC0000000)
|
||||||
{
|
{
|
||||||
*(.rodata*)
|
*(.rodata*)
|
||||||
*(.gdt_sect)
|
*(.gdt_sect)
|
||||||
|
|
@ -26,16 +38,18 @@ SECTIONS
|
||||||
}
|
}
|
||||||
|
|
||||||
/*initialized rw data. */
|
/*initialized rw data. */
|
||||||
.data BLOCK(4K) : ALIGN(4K)
|
.data ALIGN (4K) : AT(ADDR(.data) - 0xC0000000)
|
||||||
{
|
{
|
||||||
*(.data)
|
*(.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*uninitialized data, and our stack as defined in start.s*/
|
/*uninitialized data, and our stack as defined in start.s*/
|
||||||
.bss BLOCK(4K) : ALIGN(4K)
|
.bss ALIGN(4K) : AT(ADDR(.bss) - 0xC0000000)
|
||||||
{
|
{
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
|
*(.bootstrap_tables)
|
||||||
|
*(.tss)
|
||||||
*(.idt)
|
*(.idt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
global outb, inb
|
global outb, inb, invlpg
|
||||||
section .text
|
section .text
|
||||||
outb:
|
outb:
|
||||||
mov dx, [esp+4]
|
mov dx, [esp+4]
|
||||||
|
|
@ -11,3 +11,8 @@ section .text
|
||||||
mov dx, [esp+4]
|
mov dx, [esp+4]
|
||||||
in al, dx
|
in al, dx
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
cr3_reload:
|
||||||
|
mov eax, cr3
|
||||||
|
mov cr3, eax
|
||||||
|
ret
|
||||||
|
|
|
||||||
|
|
@ -55,5 +55,5 @@ section .gdt_sect
|
||||||
;size of the gdt
|
;size of the gdt
|
||||||
dw gdt_end - gdt - 1
|
dw gdt_end - gdt - 1
|
||||||
;location of the gdt
|
;location of the gdt
|
||||||
dd gdt
|
dd gdt - 0xC0000000
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "physmem.h"
|
#include "physmem.h"
|
||||||
|
|
||||||
|
|
||||||
void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
|
void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
|
||||||
{
|
{
|
||||||
//Hello C! Let's get to work in cleaning up our environment a bit and creating some safety.
|
//Hello C! Let's get to work in cleaning up our environment a bit and creating some safety.
|
||||||
|
|
@ -38,6 +40,8 @@ void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
|
||||||
//AND OUR DEFAULT OUTPUT IS:
|
//AND OUR DEFAULT OUTPUT IS:
|
||||||
default_output = default_COM;
|
default_output = default_COM;
|
||||||
|
|
||||||
|
printf(default_output, "Output schemes loaded!\n");
|
||||||
|
printf(default_output, "currently executing in kern_main() at %X\n",kern_main);
|
||||||
printf(default_output, "Entry eax:%X\n", multiboot_magic);
|
printf(default_output, "Entry eax:%X\n", multiboot_magic);
|
||||||
if(multiboot_magic != 0x2BADB002) {
|
if(multiboot_magic != 0x2BADB002) {
|
||||||
println(default_output, "Bootloader not multiboot1 compliant! Needed for mmap, etc. Can't work without it, kthxbye!");
|
println(default_output, "Bootloader not multiboot1 compliant! Needed for mmap, etc. Can't work without it, kthxbye!");
|
||||||
|
|
@ -56,10 +60,8 @@ void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int pages_allocated = build_bitmap((mb_mmap_entry_t*)multiboot_info->mmap_addr, multiboot_info->mmap_length);
|
unsigned int pages_allocated = build_bitmap((mb_mmap_entry_t*)multiboot_info->mmap_addr, multiboot_info->mmap_length);
|
||||||
printf(default_output, "Available mem:%d Pages | %dK", pages_allocated, pages_allocated * 4);
|
printf(default_output, "Available mem:%d Pages | %dK", pages_allocated, pages_allocated * 4);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,13 @@ void free_page(void* addr) {
|
||||||
|
|
||||||
unsigned int build_bitmap(mb_mmap_entry_t* mmap, int mmap_size) {
|
unsigned int build_bitmap(mb_mmap_entry_t* mmap, int mmap_size) {
|
||||||
//rather important global pointer to the bitmap
|
//rather important global pointer to the bitmap
|
||||||
pmem_bitmap = &_kernel_end;
|
pmem_bitmap = (&_kernel_end);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//some variables
|
//some variables
|
||||||
int mmap_end = (uint32_t)mmap + mmap_size;
|
int mmap_end = (uint32_t)mmap + mmap_size;
|
||||||
unsigned int pages_allocated = 0;
|
unsigned int pages_allocated = 0;
|
||||||
uint32_t max_memory = 0;
|
uint32_t max_memory = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//How much memory do we even have? Find the highest usable mmap region, and that'll be our bitmap size.
|
//How much memory do we even have? Find the highest usable mmap region, and that'll be our bitmap size.
|
||||||
for(mb_mmap_entry_t* mmap_walk = mmap;
|
for(mb_mmap_entry_t* mmap_walk = mmap;
|
||||||
(int)mmap_walk < mmap_end;
|
(int)mmap_walk < mmap_end;
|
||||||
|
|
|
||||||
81
src/start.s
81
src/start.s
|
|
@ -5,6 +5,8 @@ bits 32
|
||||||
;Some symbols we'll need from other files...
|
;Some symbols we'll need from other files...
|
||||||
extern kern_main
|
extern kern_main
|
||||||
extern gdtr
|
extern gdtr
|
||||||
|
extern _kernel_start
|
||||||
|
extern _kernel_end
|
||||||
;This will be our entrypoint function name - gotta initialize it now as global so the linker knows later.
|
;This will be our entrypoint function name - gotta initialize it now as global so the linker knows later.
|
||||||
global start
|
global start
|
||||||
|
|
||||||
|
|
@ -17,21 +19,28 @@ section .bss align=16
|
||||||
;Therefore, we put a label here to represent the top of our stack for later.
|
;Therefore, we put a label here to represent the top of our stack for later.
|
||||||
stack_top:
|
stack_top:
|
||||||
;We're gonna throw the TSS here too.
|
;We're gonna throw the TSS here too.
|
||||||
|
|
||||||
|
section .tss align=16 nobits
|
||||||
tss:
|
tss:
|
||||||
resb 104
|
resb 104
|
||||||
|
|
||||||
|
section .bootstrap_tables nobits align=4096
|
||||||
|
global_page_dir:
|
||||||
|
resb 4096
|
||||||
|
kernel_pagetable:
|
||||||
|
resb 4096
|
||||||
|
|
||||||
;Actual code. Entry point goes here!
|
;Actual code. Entry point goes here!
|
||||||
section .text
|
section .lower_text exec
|
||||||
;Here it is!
|
;Here it is!
|
||||||
start:
|
start:
|
||||||
;We made a GDT! Let's use it!
|
;We made a GDT! Let's use it!
|
||||||
lgdt [gdtr]
|
lgdt [gdtr - 0xC0000000]
|
||||||
;Now we start by setting the code segment (CS) with a far jump...
|
;Now we start by setting the code segment (CS) with a far jump...
|
||||||
jmp 0x08:segment_be_gone
|
jmp 0x08:gdt_load
|
||||||
|
|
||||||
|
|
||||||
segment_be_gone:
|
gdt_load:
|
||||||
;Now we go ahead and dump our kernel mode data segment (0x10) into the rest of our segments.
|
;Now we go ahead and dump our kernel mode data segment (0x10) into the rest of our segments.
|
||||||
;Also preserving eax because it has the bootloader's multiboot magic in it and I want to check it in main.
|
;Also preserving eax because it has the bootloader's multiboot magic in it and I want to check it in main.
|
||||||
mov cx, 0x10
|
mov cx, 0x10
|
||||||
|
|
@ -40,7 +49,67 @@ section .text
|
||||||
mov ss, cx
|
mov ss, cx
|
||||||
mov fs, cx
|
mov fs, cx
|
||||||
mov gs, cx
|
mov gs, cx
|
||||||
;Lets set up the stack. Stack grows downward on x86. We did the work earlier of defining where the top of the stack is, so just tell esp.
|
|
||||||
|
;So, we want to set up a page table and page directory. Let's take inventory.
|
||||||
|
;eax - preserve, mb_magic
|
||||||
|
;ebx - preserve, mb_info
|
||||||
|
;ecx,edx,esi - can use
|
||||||
|
;Can technically use esp as the stack is set to stack_top later.
|
||||||
|
|
||||||
|
;ecx = our current indexing for pages, this is a 4K-aligned address
|
||||||
|
mov ecx, 0x0
|
||||||
|
;edi = our pointer to the current page table entry. Array of 4byte entries. It's at, of course, where we put it earlier.
|
||||||
|
;Worth noting that it's actually physically at ~1M with the kernel. The pointer, however, is virtually inclined. So we need to adjust.
|
||||||
|
mov edi, kernel_pagetable - 0xC0000000
|
||||||
|
|
||||||
|
page_alloc_loop:
|
||||||
|
;If we're lower than our kernel, skip this page. If we've passed our kernel, we're done mapping.
|
||||||
|
cmp ecx, _kernel_start
|
||||||
|
jl next_page
|
||||||
|
cmp ecx, _kernel_end - 0xC0000000
|
||||||
|
jge page_alloc_done
|
||||||
|
|
||||||
|
;Okay, we're in kernel zone. Let's map this one.
|
||||||
|
;Let's make a page table entry in edx.
|
||||||
|
;The top bits for the page table entry are just the upper bits of the address, so we dont need to touch it.
|
||||||
|
mov edx, ecx
|
||||||
|
;Set last two bits, "present" and "writeable". Later on we'll make a proper page table with proper permissions, but we're bootstrapping here.
|
||||||
|
or edx, 0x003
|
||||||
|
;edi holds a pointer to the page table entry, so dereference it and throw our new entry (in edx) to it. Done!
|
||||||
|
mov [edi], edx
|
||||||
|
|
||||||
|
next_page:
|
||||||
|
;address page + 1
|
||||||
|
add ecx, 0x1000
|
||||||
|
;page table entry + 1
|
||||||
|
add edi, 4
|
||||||
|
jmp page_alloc_loop
|
||||||
|
|
||||||
|
page_alloc_done:
|
||||||
|
;By now we've mapped the kernel in a page table! Let's map VGA too, we'll need that address later.
|
||||||
|
mov dword [kernel_pagetable - 0xC0000000 + 1023 * 4], 0x000B8000 | 0x27
|
||||||
|
|
||||||
|
;We have our page tables mapped to the phys addr of kernel + VGA. Time to add them to our page directory!
|
||||||
|
;First identity maps, second maps to higher half.
|
||||||
|
mov dword [global_page_dir - 0xC0000000], kernel_pagetable - 0xC0000000 + 0x003
|
||||||
|
mov dword [global_page_dir - 0xC0000000 + 4 * (0xC0000000 >> 22)], kernel_pagetable - 0xC0000000 + 0x003
|
||||||
|
|
||||||
|
;Let's set it! You do this with cr3.
|
||||||
|
mov ecx, global_page_dir - 0xC0000000
|
||||||
|
mov cr3, ecx
|
||||||
|
|
||||||
|
;Enable paging in cr0
|
||||||
|
mov ecx, cr0
|
||||||
|
or ecx, 0x80010000
|
||||||
|
mov cr0, ecx
|
||||||
|
;Done! Leave to the higher half!
|
||||||
|
lea ecx, setup_c_env
|
||||||
|
jmp ecx
|
||||||
|
|
||||||
|
section .text
|
||||||
|
|
||||||
|
setup_c_env:
|
||||||
|
;set up the stack. Stack grows downward on x86. We did the work earlier of defining where the top of the stack is, so just tell esp.
|
||||||
mov esp, stack_top ;set the stack pointer
|
mov esp, stack_top ;set the stack pointer
|
||||||
push ebx
|
push ebx
|
||||||
push eax
|
push eax
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
* VARS
|
* VARS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
volatile uint16_t* const vga_buffer = (uint16_t*)0xB8000;
|
volatile uint16_t* const vga_buffer = (uint16_t*)0xC03FF000;
|
||||||
char_writer_t* default_vga = 0;
|
char_writer_t* default_vga = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
10
src/virtmem.c
Normal file
10
src/virtmem.c
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include "virtmem.h"
|
||||||
|
|
||||||
|
|
||||||
|
int map(uint32_t* page_dir, uint32_t phys_loc, uint32_t virtual_loc, uint8_t page_opts) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int kmap(uint32_t phys_loc, uint32_t virtual_loc, uint8_t page_opts){
|
||||||
|
return map(&global_page_dir, phys_loc, virtual_loc, page_opts);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue