Compare commits
23 Commits
1e1a28e23d
...
main
Author | SHA1 | Date | |
---|---|---|---|
3fd818395d | |||
8a18cf5633 | |||
88921f024e | |||
ed2c0a3568 | |||
2ec3e259d8 | |||
99a842df7e | |||
af596cd43a | |||
779680987f | |||
45c167568c | |||
a009462c72 | |||
7669ea32a4 | |||
98f8a0dc88 | |||
f216c32f22 | |||
03aecd514f | |||
920d0b01e1 | |||
83b6a9eaf2 | |||
f1515ad7b5 | |||
a776376403 | |||
ac3dc4d48a | |||
c6cc318c69 | |||
f9c2ea2f2b | |||
378f7ef23d | |||
a0749400f5 |
6
README.md
Normal file
6
README.md
Normal file
@ -0,0 +1,6 @@
|
||||
## What is this?
|
||||
|
||||
A research Operating System.. i guess
|
||||
idk. im trying my hand at OS dev because I want to be better at low level programming
|
||||
|
||||
Its fun, and terrible, but mostly fun
|
11
REFERENCES.md
Normal file
11
REFERENCES.md
Normal file
@ -0,0 +1,11 @@
|
||||
Websites:
|
||||
OSDev Wiki - https://wiki.osdev.org/
|
||||
bona fide os developer - http://osdever.net/
|
||||
LittleOSBook - https://littleosbook.github.io/
|
||||
http://www.brokenthorn.com/Resources/OSDevIndex.html
|
||||
|
||||
References:
|
||||
NASM quick reference - https://www.posix.nl/linuxassembly/nasmdochtml/nasmdoca.html
|
||||
ELF Reference - https://flint.cs.yale.edu/cs422/doc/ELF_Format.pdf
|
||||
Anatomy of a program in memory - https://manybutfinite.com/post/anatomy-of-a-program-in-memory/
|
||||
Linux Buddy System Paging - https://lwn.net/Articles/253361/
|
50
TODO.md
50
TODO.md
@ -1,33 +1,43 @@
|
||||
## What do I need to do?
|
||||
|
||||
- Unit testing
|
||||
(https://wiki.osdev.org/Unit_Testing)
|
||||
(https://wiki.osdev.org/Troubleshooting#Showing_the_stack_content)
|
||||
lets implmeent some better testing functions aswell
|
||||
- Paging & virtual memory
|
||||
- Get GRUB to show memory map - DONE
|
||||
- Write a page allocator - DONE
|
||||
- Setup paging
|
||||
- Setup virtual memory
|
||||
- Setup higher half kernel
|
||||
- Heap allocator (malloc)
|
||||
- after this, implment some data structures? cleanup queue?
|
||||
|
||||
After the above is done, i want to clean up the code and restructure some stuff
|
||||
clean up the headers so that we're not exposing kernel functions to the entire c library
|
||||
and also only make required functions be exposed to the header
|
||||
|
||||
Drivers:
|
||||
|
||||
PIC - Done
|
||||
PIT - Done
|
||||
- Need sleep and timers implemented, ACPI can help with this
|
||||
- Lets also maybe set up a hardware abstraction for timing interfaces?
|
||||
|
||||
ACPI (use ACPICA?)
|
||||
PCI, PCIE (i think qemue and bochs dont have legacy PCI, so lets try for PCIE)
|
||||
PS/2 controller
|
||||
-> need to setup some timing device, probably PIT
|
||||
-> need to setup the USB controller first, so i can disable Legacy USB bios shit
|
||||
-> need to configure ACPI so i can actually detect for the PS/2 controller
|
||||
-> then we can start configuring the PS/2
|
||||
|
||||
-> to properly send data to PS/2 controllers, we need some sort of timing interface,
|
||||
this way we can timeout if we're being hanged on sending commands to a ps/2 device
|
||||
|
||||
|
||||
|
||||
|
||||
PIT timer, or some sort of timer interface
|
||||
|
||||
perhaps maybe some more things off of the PIC? im not sure
|
||||
|
||||
really after that I want to do more to work towards userspace, so that I can start creating things
|
||||
|
||||
scheduler?
|
||||
multi processing? threads?
|
||||
etc
|
||||
Proper KEYB driver
|
||||
|
||||
From here, determine whats needed next for pushing into userspace.
|
||||
Ideally I would like a shell, and then create some essential userspace posix tools (gnutils?)
|
||||
|
||||
POSIX compliant?
|
||||
|
||||
### Features I want
|
||||
|
||||
- A kernel bus
|
||||
- some kind of driver where I can send messages that can eventually be accessed globally by other drives / applications
|
||||
- modularity in terms of drivers:
|
||||
- I want drivers to be optional and to not limit functionality
|
||||
- perhaps this means providing every thing as a hardware abstraction layer, so that when its absent we can have some sort of virtual replacement
|
||||
|
@ -3,7 +3,7 @@
|
||||
; We set up some parameters and then pass the execution to our kmain
|
||||
|
||||
global loader ; entry symbol for ELF
|
||||
extern kmain
|
||||
extern _main
|
||||
|
||||
MAGIC_NUMBER equ 0x1BADB002 ; magic number constant
|
||||
FLAGS equ 0x3
|
||||
@ -30,7 +30,10 @@ section .text
|
||||
loader:
|
||||
mov esp, kernel_stack + KERNEL_STACK_SIZE ; move the top of the stack into esp
|
||||
|
||||
call kmain ; pass execution over to our kmain function, where all of the real stuff is done
|
||||
push eax
|
||||
push ebx
|
||||
|
||||
call _main ; pass execution over to our _main function, where all of the real stuff is done
|
||||
|
||||
; Should the system exit, we clear the interrupt flag
|
||||
; and do an infinite loop of nothing
|
||||
|
@ -1,8 +1,8 @@
|
||||
gdtr DW 0 ; limit store
|
||||
DD 0 ; base storage
|
||||
|
||||
global setGdt
|
||||
setGdt:
|
||||
global set_gdt
|
||||
set_gdt:
|
||||
mov ax, [esp + 4]
|
||||
mov [gdtr], ax
|
||||
mov eax, [esp + 8]
|
||||
@ -10,8 +10,8 @@ setGdt:
|
||||
lgdt [gdtr]
|
||||
ret
|
||||
|
||||
global reloadSegments
|
||||
reloadSegments:
|
||||
global reload_segments
|
||||
reload_segments:
|
||||
jmp 0x08:.reload_CS ; 0x08 is a stand in for the code segment
|
||||
.reload_CS:
|
||||
mov ax, 0x10 ; stand in for the data segment
|
||||
|
@ -26,8 +26,58 @@
|
||||
* etc, by going through the CPU permission system (RING 0 - 3)
|
||||
*/
|
||||
|
||||
#define GDT_SIZE 5
|
||||
|
||||
// Each define here is for a specific flag in the descriptor.
|
||||
// Refer to the intel documentation for a description of what each one does.
|
||||
#define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data)
|
||||
#define SEG_PRES(x) ((x) << 0x07) // Present
|
||||
#define SEG_SAVL(x) ((x) << 0x0C) // Available for system use
|
||||
#define SEG_LONG(x) ((x) << 0x0D) // Long mode
|
||||
#define SEG_SIZE(x) ((x) << 0x0E) // Size (0 for 16-bit, 1 for 32)
|
||||
#define SEG_GRAN(x) ((x) << 0x0F) // Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB)
|
||||
#define SEG_PRIV(x) (((x) & 0x03) << 0x05) // Set privilege level (0 - 3)
|
||||
|
||||
#define SEG_DATA_RD 0x00 // Read-Only
|
||||
#define SEG_DATA_RDA 0x01 // Read-Only, accessed
|
||||
#define SEG_DATA_RDWR 0x02 // Read/Write
|
||||
#define SEG_DATA_RDWRA 0x03 // Read/Write, accessed
|
||||
#define SEG_DATA_RDEXPD 0x04 // Read-Only, expand-down
|
||||
#define SEG_DATA_RDEXPDA 0x05 // Read-Only, expand-down, accessed
|
||||
#define SEG_DATA_RDWREXPD 0x06 // Read/Write, expand-down
|
||||
#define SEG_DATA_RDWREXPDA 0x07 // Read/Write, expand-down, accessed
|
||||
#define SEG_CODE_EX 0x08 // Execute-Only
|
||||
#define SEG_CODE_EXA 0x09 // Execute-Only, accessed
|
||||
#define SEG_CODE_EXRD 0x0A // Execute/Read
|
||||
#define SEG_CODE_EXRDA 0x0B // Execute/Read, accessed
|
||||
#define SEG_CODE_EXC 0x0C // Execute-Only, conforming
|
||||
#define SEG_CODE_EXCA 0x0D // Execute-Only, conforming, accessed
|
||||
#define SEG_CODE_EXRDC 0x0E // Execute/Read, conforming
|
||||
#define SEG_CODE_EXRDCA 0x0F // Execute/Read, conforming, accessed
|
||||
|
||||
#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(0) | SEG_CODE_EXRD
|
||||
|
||||
#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(0) | SEG_DATA_RDWR
|
||||
|
||||
#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(3) | SEG_CODE_EXRD
|
||||
|
||||
#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(3) | SEG_DATA_RDWR
|
||||
|
||||
|
||||
|
||||
uint64_t gdt[GDT_SIZE];
|
||||
|
||||
void set_gdt(unsigned short limit, uint64_t* base);
|
||||
void reload_segments(void);
|
||||
|
||||
uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag)
|
||||
{
|
||||
uint64_t descriptor;
|
||||
@ -63,11 +113,11 @@ void gdt_init(void)
|
||||
gdt[0] = create_descriptor(0, 0, 0); // null
|
||||
gdt[1] = create_descriptor(0, 0x000FFFFF, (GDT_CODE_PL0)); // kernel code
|
||||
gdt[2] = create_descriptor(0, 0x000FFFFF, (GDT_DATA_PL0)); // kernel data
|
||||
//gdt[3] = create_descriptor(0, 0x000FFFFF, (GDT_CODE_PL3)); // user code
|
||||
//gdt[4] = create_descriptor(0, 0x000FFFFF, (GDT_DATA_PL3)); // user data
|
||||
gdt[3] = create_descriptor(0, 0x000FFFFF, (GDT_CODE_PL3)); // user code
|
||||
gdt[4] = create_descriptor(0, 0x000FFFFF, (GDT_DATA_PL3)); // user data
|
||||
|
||||
setGdt((sizeof(uint64_t) * GDT_SIZE) - 1, &(gdt[0])); // limit, base
|
||||
reloadSegments();
|
||||
set_gdt((sizeof(uint64_t) * GDT_SIZE) - 1, &(gdt[0])); // limit, base
|
||||
reload_segments();
|
||||
#ifdef __TESTING__
|
||||
kinfo("Initialized the GDT");
|
||||
#endif
|
||||
@ -76,4 +126,31 @@ void gdt_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#undef SEG_DESCTYPE
|
||||
#undef SEG_PRES
|
||||
#undef SEG_SAVL
|
||||
#undef SEG_LONG
|
||||
#undef SEG_SIZE
|
||||
#undef SEG_GRAN
|
||||
#undef SEG_PRIV
|
||||
#undef SEG_DATA_RD
|
||||
#undef SEG_DATA_RDA
|
||||
#undef SEG_DATA_RDWR
|
||||
#undef SEG_DATA_RDWRA
|
||||
#undef SEG_DATA_RDEXPD
|
||||
#undef SEG_DATA_RDEXPDA
|
||||
#undef SEG_DATA_RDWREXPD
|
||||
#undef SEG_DATA_RDWREXPDA
|
||||
#undef SEG_CODE_EX
|
||||
#undef SEG_CODE_EXA
|
||||
#undef SEG_CODE_EXRD
|
||||
#undef SEG_CODE_EXRDA
|
||||
#undef SEG_CODE_EXC
|
||||
#undef SEG_CODE_EXCA
|
||||
#undef SEG_CODE_EXRDC
|
||||
#undef SEG_CODE_EXRDCA
|
||||
#undef GDT_CODE_PL0
|
||||
#undef GDT_DATA_PL0
|
||||
#undef GDT_CODE_PL3
|
||||
#undef GDT_DATA_PL3
|
||||
#undef GDT_SIZE
|
||||
|
@ -6,26 +6,39 @@
|
||||
#include <kernel/_kernel.h>
|
||||
#include <kernel/x86/idt.h>
|
||||
#include <kernel/x86/pic.h>
|
||||
#include <kernel/x86/pit.h>
|
||||
#include <kernel/x86/io.h>
|
||||
#include <kernel/x86/keyb.h>
|
||||
|
||||
#define IDT_MAX_DESCRIPTORS 48 // number of entries in the idt table
|
||||
|
||||
typedef struct {
|
||||
uint16_t isr_low; // The lower 16 bits of the ISR's address
|
||||
uint16_t kernel_cs; // The GDT segment selector that the CPU will load into CS before calling the ISR
|
||||
uint8_t reserved; // set to zero
|
||||
uint8_t attributes; // Type and attributes
|
||||
uint16_t isr_high; // The higher 16 bits of the ISR's address
|
||||
} __attribute__((packed)) idt_entry_t;
|
||||
|
||||
__attribute__((aligned(0x10)))
|
||||
static idt_entry_t idt[256];
|
||||
|
||||
typedef struct {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
} __attribute__((packed)) idtr_t;
|
||||
|
||||
static idtr_t idtr;
|
||||
|
||||
|
||||
static bool vectors[IDT_MAX_DESCRIPTORS];
|
||||
|
||||
extern struct keyboard_state keyb_state;
|
||||
|
||||
extern struct pit_state pit;
|
||||
|
||||
#define EXTERNAL_BIT (0x1)
|
||||
|
||||
#define TBL_GDT (0x0)
|
||||
#define TBL_LDT (0x2)
|
||||
#define TBL_IDT (0x1)
|
||||
#define TBL_IDT_TWO (0x3)
|
||||
|
||||
static void examine_selector(uint32_t selector)
|
||||
{
|
||||
printf("The interrupt arised %s.\n", (selector & EXTERNAL_BIT) == EXTERNAL_BIT ? "externally" : "internally");
|
||||
@ -44,11 +57,11 @@ static void examine_selector(uint32_t selector)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#undef TBL_GDT
|
||||
#undef TBL_LDT
|
||||
#undef TBL_IDT
|
||||
#undef TBL_IDT_TWO
|
||||
#undef EXTERNAL_BIT
|
||||
|
||||
#define PF_P (1 << 0)
|
||||
#define PF_W (1 << 1)
|
||||
@ -108,8 +121,40 @@ static void examine_page_fault(uint32_t error_code)
|
||||
#undef PF_SS
|
||||
#undef PF_SGX
|
||||
|
||||
#define EXCEPTION_LOCATION() printf("Exception occurred at 0x%2\n", stack.eip)
|
||||
static void dump_cpu_state(struct cpu_state cpu, struct stack_state stack)
|
||||
{
|
||||
kinfo("DUMPING CPU STATE");
|
||||
printf("eax: %2\nebx: %2\necx: %2\nedx: %2\nesi: %2\nedi: %22\nebp: %2\n",
|
||||
cpu.eax, cpu.ebx, cpu.ecx, cpu.edx, cpu.esi, cpu.edi, cpu.ebp);
|
||||
kinfo("DUMPING STACK STATE FOR INTERRUPT");
|
||||
printf("eip: %2\ncs: %2\neflags: %2\n",
|
||||
stack.eip, stack.cs, stack.eflags);
|
||||
}
|
||||
|
||||
#define EXCEPTION_LOCATION() printf("Exception occurred at 0x%2\n", stack.eip)
|
||||
#define EXCEPT_DIV_ERR 0
|
||||
#define EXCEPT_DEBUG 1
|
||||
#define EXCEPT_NMI 2
|
||||
#define EXCEPT_BREAKPOINT 3
|
||||
#define EXCEPT_OVERFLOW 4
|
||||
#define EXCEPT_BOUND_RANGE_EXCEEDED 5
|
||||
#define EXCEPT_INVALID_OPCODE 6
|
||||
#define EXCEPT_DEVICE_NOT_AVAILABLE 7
|
||||
#define EXCEPT_DOUBLE_FAULT 8
|
||||
#define EXCEPT_INVALID_TSS 10
|
||||
#define EXCEPT_SEG_NOT_PRESENT 11
|
||||
#define EXCEPT_STACK_SEG_FAULT 12
|
||||
#define EXCEPT_GENERAL_PROTECTION 13
|
||||
#define EXCEPT_PAGE_FAULT 14
|
||||
#define EXCEPT_FLOATING_POINT_ERR_FPU 16
|
||||
#define EXCEPT_ALIGNMENT_CHECK 17
|
||||
#define EXCEPT_MACHINE_CHECK 18
|
||||
#define EXCEPT_FLOATING_POINT_ERR_SIMD 19
|
||||
#define EXCEPT_VIRT 20
|
||||
#define EXCEPT_CTRL_PROT 21
|
||||
#define EXCEPT_HYPERVISOR_INJECTION 28
|
||||
#define EXCEPT_VMM_COMMUNICATION 29
|
||||
#define EXCEPT_SECURITY_EXCEPTION 30
|
||||
void exception_handler(struct cpu_state __attribute__((unused)) cpu, uint32_t interrupt, struct stack_state stack)
|
||||
{
|
||||
uint32_t inbyte;
|
||||
@ -147,8 +192,8 @@ void exception_handler(struct cpu_state __attribute__((unused)) cpu, uint32_t in
|
||||
break;
|
||||
case EXCEPT_DOUBLE_FAULT:
|
||||
kerror("EXCEPTION: DOUBLE FAULT");
|
||||
__asm__ volatile ("cli; hlt"); // boned
|
||||
break;
|
||||
__asm__ volatile ("cli; hlt"); // boned break;
|
||||
break; // don't need t his but -Werror lol
|
||||
case EXCEPT_INVALID_TSS:
|
||||
kerror("EXCEPTION: INVALID TSS");
|
||||
examine_selector(stack.error_code);
|
||||
@ -219,6 +264,10 @@ void exception_handler(struct cpu_state __attribute__((unused)) cpu, uint32_t in
|
||||
/** EXCEPTIONS END **/
|
||||
|
||||
/** PIC BEGIN **/
|
||||
case PIC_PIT:
|
||||
pit.interrupts++;
|
||||
PIC_sendEOI(0);
|
||||
break;
|
||||
case PIC_KEYB:
|
||||
inbyte = inb(0x60);
|
||||
do_keypress(decode_scancode(inbyte));
|
||||
@ -229,9 +278,36 @@ void exception_handler(struct cpu_state __attribute__((unused)) cpu, uint32_t in
|
||||
default:
|
||||
kerror("EXCEPTION: UNHANDLED EXCEPTION OR INTERRUPT");
|
||||
printf("Error code: 0x%2\n", stack.error_code);
|
||||
dump_cpu_state(cpu, stack);
|
||||
|
||||
// TODO i would love to track spurious interrupts as well, would be useful to dump their state and specify that its spurious (if possible)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#undef EXCEPT_DIV_ERR
|
||||
#undef EXCEPT_DEBUG
|
||||
#undef EXCEPT_NMI
|
||||
#undef EXCEPT_BREAKPOINT
|
||||
#undef EXCEPT_OVERFLOW
|
||||
#undef EXCEPT_BOUND_RANGE_EXCEEDED
|
||||
#undef EXCEPT_INVALID_OPCODE
|
||||
#undef EXCEPT_DEVICE_NOT_AVAILABLE
|
||||
#undef EXCEPT_DOUBLE_FAULT
|
||||
#undef EXCEPT_INVALID_TSS
|
||||
#undef EXCEPT_SEG_NOT_PRESENT
|
||||
#undef EXCEPT_STACK_SEG_FAULT
|
||||
#undef EXCEPT_GENERAL_PROTECTION
|
||||
#undef EXCEPT_PAGE_FAULT
|
||||
#undef EXCEPT_FLOATING_POINT_ERR_FPU
|
||||
#undef EXCEPT_ALIGNMENT_CHECK
|
||||
#undef EXCEPT_MACHINE_CHECK
|
||||
#undef EXCEPT_FLOATING_POINT_ERR_SIMD
|
||||
#undef EXCEPT_VIRT
|
||||
#undef EXCEPT_CTRL_PROT
|
||||
#undef EXCEPT_HYPERVISOR_INJECTION
|
||||
#undef EXCEPT_VMM_COMMUNICATION
|
||||
#undef EXCEPT_SECURITY_EXCEPTION
|
||||
#undef EXCEPTION_LOCATION
|
||||
|
||||
void idt_set_descriptor(uint8_t vector, void *isr, uint8_t flags)
|
||||
{
|
||||
@ -263,6 +339,7 @@ void idt_init(void)
|
||||
|
||||
PIC_remap(0x20, 0x28);
|
||||
pic_disable(); // mask everything
|
||||
IRQ_clear_mask(0);
|
||||
IRQ_clear_mask(1);
|
||||
|
||||
__asm__ volatile("sti"); // set the interrupt flag
|
||||
@ -270,3 +347,5 @@ void idt_init(void)
|
||||
kinfo("Initialized the IDT");
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef IDT_MAX_DESCRIPTORS
|
||||
|
@ -9,8 +9,25 @@ outb:
|
||||
out dx, al ; send the data to the I/O port
|
||||
ret ; return to the calling function
|
||||
|
||||
|
||||
global outb_16 ; TODO these are probably wrong, eh, the stack might need more bcs the variables are bigger? im not sure
|
||||
outb_16:
|
||||
mov ax, [esp + 8]
|
||||
mov dx, [esp + 4]
|
||||
out dx, ax
|
||||
ret
|
||||
|
||||
|
||||
|
||||
global outb_32
|
||||
outb_32:
|
||||
mov eax, [esp + 8]
|
||||
mov dx, [esp + 4]
|
||||
out dx, eax
|
||||
ret
|
||||
|
||||
global inb
|
||||
; inb - returns a byte from the given I/O port
|
||||
; inb - returns a byte from the given I/O porot
|
||||
; stack: [esp + 4] The address of the I/O port
|
||||
; [esp ] The return address
|
||||
inb:
|
||||
@ -18,9 +35,24 @@ inb:
|
||||
in al, dx ; read a byte from the I/O port and store it in the al register
|
||||
ret ; return the read byte
|
||||
|
||||
global inb_16
|
||||
inb_16:
|
||||
mov dx, [esp + 4]
|
||||
in ax, dx
|
||||
ret
|
||||
|
||||
global inb_32
|
||||
inb_32:
|
||||
mov dx, [esp + 4]
|
||||
in eax, dx
|
||||
ret
|
||||
|
||||
|
||||
global io_wait
|
||||
io_wait:
|
||||
mov al, 0x0
|
||||
out 0x80, al
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
@ -1,3 +1,75 @@
|
||||
#include <math.h>
|
||||
|
||||
#include <kernel/x86/pit.h>
|
||||
#include <kernel/x86/io.h>
|
||||
|
||||
struct pit_state pit;
|
||||
|
||||
uint32_t normalize_divisor(uint32_t divisor)
|
||||
{
|
||||
if (divisor == 0)
|
||||
return 65536;
|
||||
return clamp_u32(divisor, 0, 65535);
|
||||
}
|
||||
|
||||
double get_time_from_divisor(uint32_t divisor)
|
||||
{
|
||||
uint32_t _divisor = normalize_divisor(divisor);
|
||||
|
||||
double clock_rate = 3579545.0 / 3.0; // This is for a bit more precision in the hz rate
|
||||
|
||||
return (_divisor / (clock_rate)) * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Im worried about an overflow
|
||||
*
|
||||
*
|
||||
* What i want to do is
|
||||
*
|
||||
* Every time we get the Timer intterupt, i want to increment a variable, just the amount of times its fired
|
||||
* and then we can use the time rate above to get total time elapsed, which we can use for sleep and stuff
|
||||
*
|
||||
* Im worried about overflows, but i can add something that will automatically flip it over? or do uints already roll over? they already rollover!!! WOOOO!!!
|
||||
* just need to be aware that only a maximum of 52ms * 32int max (64 int max) can be tracked before it rolls over!
|
||||
*/
|
||||
|
||||
|
||||
uint16_t read_pit_count(uint8_t channel) // Only in lobyte/hibyte mode
|
||||
|
||||
{
|
||||
uint16_t count = 0;
|
||||
|
||||
__asm__ volatile ("cli");
|
||||
|
||||
|
||||
outb(PIT_CMD_REG, (channel << 6)); // xx000000 where x is the channel
|
||||
|
||||
count = inb(channel);
|
||||
count |= inb(channel) << 8;
|
||||
|
||||
return count; // TODO make sure to enable interrupts after this
|
||||
}
|
||||
|
||||
void set_pit_count(uint8_t channel, uint16_t count) // Only in lobyte/hibyte mode
|
||||
{
|
||||
__asm__ volatile ("cli");
|
||||
|
||||
outb(channel, count & 0xFF); // low byte
|
||||
outb(channel, (count & 0xFF00) >> 8); // high byte
|
||||
|
||||
// TODO: make sure to set interrupts
|
||||
}
|
||||
|
||||
void init_pit(uint8_t init_command, uint8_t channel, uint32_t divisor)
|
||||
{
|
||||
uint32_t normalized_div = normalize_divisor(divisor);
|
||||
|
||||
pit.divisor = normalized_div;
|
||||
pit.interrupts = 0;
|
||||
|
||||
outb(PIT_CMD_REG, init_command); // access mode must be lobyte/hibyte
|
||||
|
||||
outb(channel, normalized_div & 0xFF);
|
||||
outb(channel, (normalized_div & 0xFF00) >> 8);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ SECTIONS
|
||||
*/
|
||||
.text BLOCK(4K) : ALIGN(4K) /* The first section we want is the text section, this is where most code is */
|
||||
{
|
||||
text_start = .;
|
||||
*(.multiboot) /* Multiboot needs to be early in the file, required by grub */
|
||||
*(.text) /* The text section */
|
||||
}
|
||||
@ -33,12 +34,16 @@ SECTIONS
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.data)
|
||||
end_data = .;
|
||||
}
|
||||
|
||||
/* BSS */
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
sbss = .;
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
ebss = .;
|
||||
endkernel = .;
|
||||
}
|
||||
}
|
||||
|
86
kernel/arch/paging/paging.h
Normal file
86
kernel/arch/paging/paging.h
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* The page direcotry and the page table have very specific
|
||||
* entry formats.
|
||||
*
|
||||
* They will be defined here, and constants will be properly allocated.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Page directory
|
||||
* containes 1024 4 byte entries, making them 4KiB each.
|
||||
*
|
||||
* In the page directory, each entry points to a page table.
|
||||
*
|
||||
*
|
||||
* Page Directory Entry
|
||||
*
|
||||
* (this is following the page size of 0, or 4KiB)
|
||||
* bits:
|
||||
* 31 - 12 : Bits 31-12 of address
|
||||
* 11 - 8 : AVL
|
||||
* 7 : PS
|
||||
* 6 : AVL
|
||||
* 5 : A
|
||||
* 4 : PCD
|
||||
* 3 : PWT
|
||||
* 2 : U/S
|
||||
* 1 : R/W
|
||||
* 0 : P
|
||||
*
|
||||
*
|
||||
* The address field represnets the physical address of the page table that manages the four megabytes at that point.
|
||||
* It is very important that this address by 4KiB aligned. As the remainder of bytes are overwritten by access bits and such.
|
||||
*
|
||||
* P: Present
|
||||
* If the bit is set, the page is actually in physical memory at the moment. For example, when a page is swapped out, it is not in physical memory and therefor not 'Present'.
|
||||
* If a page is called, but not present, a page fault will occur, and the OS should handle it.
|
||||
* R/W: Read/Write
|
||||
* If the big is set, the page is read/write. Otherwise, it is read-only. The WP bit in CR0 determines if this is only applied to userland, always giving the kernel write access (the default)
|
||||
* or both userland and the kernel. (see Intel Manuals 3A 2-20)
|
||||
* U/S: User/Supervisor
|
||||
* Controls access to the page based on privelege level. If the bit is set, then the page may be accessed by all; if the bit is not set, however,
|
||||
* only the supervisor can access it. For ap age directory entry, the user bit controls access to all the pages referenced by the page directory entry.
|
||||
* Therefore if you wish to make a page a user page, you must set the bit in the releveant page directory, as well as the page table entry.
|
||||
* PWT: Write-through
|
||||
* Controls Write-through abilities of the page. If the bit is set, write-through caching is enabled.
|
||||
* If not, then write-back is enabled instead.
|
||||
* PCD: Cache Disable
|
||||
* Cache disable bit, if the bit is set, the page will not be cached. Otherwise, it will be.
|
||||
* A: Accessed
|
||||
* Accessed is used to discover whether a PDE or PTE was read during virtual address translation. If it has, then the bit is set, otherwise it is not.
|
||||
* Note that, this bit will not be cleared by the CPU, so that burden falls on the OS (if its needed at all).
|
||||
* D: Dirty
|
||||
* Dirty is used to determine wether a page has been written to.
|
||||
* PS: Page Size (always 0, since we're using 4KiB pages)
|
||||
* Stores the page size for that specific entry. If the bit is set, then the PDE maps a page that is 4MiB in size. Otherwise, it maps to a 4KiB page table.
|
||||
* AVL: Available
|
||||
* These bits are unused and are free for the OS to use for accounting information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Page Table
|
||||
*
|
||||
* In each page table, as it is, there are also 1024 entries. Each entry points to a 4KiB physical page frame.
|
||||
*
|
||||
* These are called page table entries, and are very similar to the entries described above.
|
||||
*
|
||||
* The first item is a 4KiB aligned physical address. However, these point to a 4KiB block of physical memory, which si then mapped to that location in the page table and driectory.
|
||||
*
|
||||
* 31 - 12 : Bits 31-12 of address
|
||||
* 11 - 9 : AVL
|
||||
* 8 : G
|
||||
* 7 : PAT
|
||||
* 6 : D
|
||||
* 5 : A
|
||||
* 4 : PCD
|
||||
* 3 : PWT
|
||||
* 2 : U/S
|
||||
* 1 : R/W
|
||||
* 0 : P
|
||||
*
|
||||
* G: Global
|
||||
* Tells the processor not to invalidate the TLB entry corresponding to the page upon a MOV to CR3 instruction.
|
||||
* Bit 7 (PGE) in CR4 must be set to enable global pages.
|
||||
* PAT: Page Attribute Table
|
||||
* If PAT is supported, then PAT along with PCD and PWT shall indicate the memory caching type. Otherwise, it is reserved and must be set to 0.
|
||||
*/
|
42
kernel/arch/pic/pci.c
Normal file
42
kernel/arch/pic/pci.c
Normal file
@ -0,0 +1,42 @@
|
||||
#include <kernel/x86/io.h>
|
||||
#include <kernel/x86/pci.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* None of this is working. I'm assuming that QEMU (and bochs) are using pcie purely memory mapped, without legacy PCI support
|
||||
*
|
||||
* so we'll need to setup ACPI first :)
|
||||
*/
|
||||
|
||||
uint16_t pci_config_read_word(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset)
|
||||
{
|
||||
uint32_t address;
|
||||
uint32_t lbus = (uint32_t) bus;
|
||||
uint32_t lslot = (uint32_t) slot;
|
||||
uint32_t lfunc = (uint32_t) func;
|
||||
uint16_t tmp = 0;
|
||||
|
||||
|
||||
address = (uint32_t) ((lbus << 16) | (lslot << 11) |
|
||||
(lfunc << 8) | (offset & 0xFC) | ((uint32_t) 0x80000000));
|
||||
|
||||
printf("%b\n", address);
|
||||
|
||||
outb_32(PCI_CONFIG_ADDRESS, address);
|
||||
|
||||
tmp = (uint16_t)((inb(PCI_CONFIG_DATA) >> ((offset & 2) * 8)) & 0xFFFF);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
uint16_t pci_check_vendor(uint8_t bus, uint8_t slot, uint8_t func)
|
||||
{
|
||||
uint16_t vendor, device;
|
||||
|
||||
if ((vendor = pci_config_read_word(bus, slot, func, 0)) != 0xFFFF) {
|
||||
device = pci_config_read_word(bus, slot, func, 2);
|
||||
// we'll do something here, store all the pcis in memory or something
|
||||
device++;
|
||||
}
|
||||
return vendor;
|
||||
}
|
@ -5,6 +5,33 @@
|
||||
#include <kernel/x86/io.h>
|
||||
#include <kernel/x86/pic.h>
|
||||
|
||||
/** PIC I/O ports **/
|
||||
#define PIC1 0x20 /** Master PIC **/
|
||||
#define PIC2 0xA0 /** Slave PIC **/
|
||||
|
||||
/** PIC helper defines **/
|
||||
#define PIC1_COMMAND (PIC1)
|
||||
#define PIC1_DATA (PIC1 + 1)
|
||||
#define PIC2_COMMAND (PIC2)
|
||||
#define PIC2_DATA (PIC2 + 1)
|
||||
|
||||
/** PIC Commands **/
|
||||
#define ICW1_ICW4 0x01 /** Indicates ICW4 will be present **/
|
||||
#define ICW1_SINGLE 0x02 /** Single (cascade mode) **/
|
||||
#define ICW1_INTERVAL4 0x04 /** Call address interval 4 (8) **/
|
||||
#define ICW1_LEVEL 0x08 /** Level triggered (edge) mode **/
|
||||
#define ICW1_INIT 0x10 /** Initialization **/
|
||||
|
||||
#define ICW4_8086 0x01 /** 8086/88 (MCS-80/85) mode **/
|
||||
#define ICW4_AUTO 0x02 /** Auto (normal) EOI **/
|
||||
#define ICW4_BUF_SLAVE 0x08 /** Buffered mode/slave **/
|
||||
#define ICW4_BUF_MASTER 0x0C /** Buffered mode/master **/
|
||||
#define ICW4_SFNM 0x10 /** Special fully nested (not) **/
|
||||
|
||||
#define PIC_EOI 0x20 /** End-of-interrupt command code **/
|
||||
#define PIC_READ_IRR 0x0a /** OCW3 irq ready next CMD read **/
|
||||
#define PIC_READ_ISR 0x0b /** OCW3 irq service next CMD read **/
|
||||
|
||||
void PIC_sendEOI(uint8_t irq)
|
||||
{
|
||||
if (irq >= 8) // if we're over the PIC1 limit
|
||||
@ -123,3 +150,22 @@ uint16_t pic_get_isr(void)
|
||||
return __pic_get_irq_reg(PIC_READ_ISR);
|
||||
}
|
||||
|
||||
#undef PIC1
|
||||
#undef PIC2
|
||||
#undef PIC1_COMMAND
|
||||
#undef PIC1_DATA
|
||||
#undef PIC2_COMMAND
|
||||
#undef PIC2_DATA
|
||||
#undef ICW1_ICW4
|
||||
#undef ICW1_SINGLE
|
||||
#undef ICW1_INTERVAL4
|
||||
#undef ICW1_LEVEL
|
||||
#undef ICW1_INIT
|
||||
#undef ICW4_8086
|
||||
#undef ICW4_AUTO
|
||||
#undef ICW4_BUF_SLAVE
|
||||
#undef ICW4_BUF_MASTER
|
||||
#undef ICW4_SFNM
|
||||
#undef PIC_EOI
|
||||
#undef PIC_READ_IRR
|
||||
#undef PIC_READ_ISR
|
||||
|
211
kernel/arch/pmm/pmm.c
Normal file
211
kernel/arch/pmm/pmm.c
Normal file
@ -0,0 +1,211 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <kernel/_kernel.h>
|
||||
#include <kernel/pmm.h>
|
||||
|
||||
/**
|
||||
* What i want to do is create a linked list of all the memory structures
|
||||
*
|
||||
* Theres one at the very start of the memory
|
||||
*
|
||||
* one at 1MB
|
||||
*
|
||||
* and then one provided by ram.
|
||||
*
|
||||
*
|
||||
* So the idea is to create a way to access memory through this such that,
|
||||
* when you give a bit block number, it'll go through the first item in the linked list, if the block is out of that range, it
|
||||
* traverses to the next node, tries to find it there, and then continues until it either runs out of memory, or finds a location
|
||||
*/
|
||||
|
||||
#define PMM_PAGE_SIZE 4096
|
||||
#define PMM_BLOCKS_PER_BYTE 8
|
||||
|
||||
struct pmm_mem_info {
|
||||
uint32_t startaddr;
|
||||
uint32_t len; // in kb
|
||||
uint32_t* bitmap;
|
||||
|
||||
uint32_t max_blocks;
|
||||
uint32_t free_blocks;
|
||||
uint32_t used_blocks;
|
||||
};
|
||||
|
||||
#define PMM_GET_MEM_BLOCKS(x) x.len / PMM_PAGE_SIZE
|
||||
|
||||
struct pmm_mem_info main_mem;
|
||||
|
||||
void pmm_set(uint32_t bit);
|
||||
void pmm_unset(uint32_t bit);
|
||||
bool pmm_test(uint32_t bit);
|
||||
int pmm_first_free(void);
|
||||
void pmm_init(void);
|
||||
void* pmm_alloc_block(void);
|
||||
void pmm_free_block(void* p);
|
||||
|
||||
void pmm_panic(const char* str)
|
||||
{
|
||||
printf("PMM: ");
|
||||
panic(str);
|
||||
}
|
||||
|
||||
void __pmm_set(uint32_t bit, struct pmm_mem_info* mem_block)
|
||||
{
|
||||
(mem_block->bitmap)[bit / 32] |= (1 << (bit % 32));
|
||||
mem_block->used_blocks++;
|
||||
mem_block->free_blocks--;
|
||||
}
|
||||
|
||||
void __pmm_unset(uint32_t bit, struct pmm_mem_info* mem_block)
|
||||
{
|
||||
(mem_block->bitmap)[bit / 32] &= ~(1 << (bit % 32));
|
||||
mem_block->used_blocks--;
|
||||
mem_block->free_blocks++;
|
||||
}
|
||||
|
||||
bool __pmm_test(uint32_t bit, struct pmm_mem_info* mem_block)
|
||||
{
|
||||
return (mem_block->bitmap)[bit / 32] & (1 << (bit % 32));
|
||||
}
|
||||
|
||||
int __pmm_first_free(struct pmm_mem_info* mem_block)
|
||||
{
|
||||
for (uint32_t i = 0; i < PMM_GET_MEM_BLOCKS((*mem_block)) / 32; i++) {
|
||||
if (mem_block->bitmap[i] == 0xFFFFFFFF) // this segment is full
|
||||
continue;
|
||||
for (int j = 0; j < 32; j++) {
|
||||
if (mem_block->bitmap[i] & (1 << j))
|
||||
continue; // this page is used
|
||||
return (i * 32) + j; // i * 32 is the chunk of 32, plus j to get to the page in the chunk
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void __pmm_add_mem_block(uint32_t addr, int32_t len, struct pmm_mem_info* mem_block)
|
||||
{
|
||||
mem_block->startaddr = addr;
|
||||
mem_block->len = len;
|
||||
mem_block->bitmap = 0;
|
||||
}
|
||||
|
||||
void __pmm_init(struct pmm_mem_info* mem_block)
|
||||
{
|
||||
// TODO same as above
|
||||
mem_block->used_blocks = 0;
|
||||
mem_block->max_blocks = PMM_GET_MEM_BLOCKS(main_mem);
|
||||
mem_block->free_blocks = mem_block->max_blocks;
|
||||
|
||||
memset(mem_block->bitmap, 0x0, PMM_GET_MEM_BLOCKS((*mem_block)) / PMM_BLOCKS_PER_BYTE); // declare all memory available
|
||||
|
||||
#ifdef __TESTING__
|
||||
printf("Initialized %1 blocks of memory (%1KiB available)\n", mem_block->max_blocks, mem_block->free_blocks * 4096);
|
||||
#endif
|
||||
__pmm_set(0, mem_block); // first block must always be set
|
||||
}
|
||||
|
||||
void* __pmm_alloc_block(struct pmm_mem_info* mem_block)
|
||||
{
|
||||
if (mem_block->free_blocks == 0) {
|
||||
kerror("OUT OF MEMORY");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int block_in_map = pmm_first_free();
|
||||
if (block_in_map == -1) {
|
||||
kerror("OUT OF MEMORY");
|
||||
return 0;
|
||||
}
|
||||
|
||||
__pmm_set(block_in_map, mem_block);
|
||||
|
||||
return (void*) (mem_block->startaddr + (block_in_map * PMM_PAGE_SIZE));
|
||||
}
|
||||
|
||||
void __pmm_free_block(void* p, struct pmm_mem_info* mem_block)
|
||||
{
|
||||
uint64_t* addr = (uint64_t*) &p;
|
||||
uint32_t idx = ((*addr) - mem_block->startaddr) / PMM_PAGE_SIZE;
|
||||
|
||||
// TODO this might still be a little flaky
|
||||
// should we be able to free any pointer? or just ones that we've given out?
|
||||
if (idx == 0)
|
||||
pmm_panic("Trying to free reserved memory!");
|
||||
|
||||
if (pmm_test(idx) == 0)
|
||||
pmm_panic("Trying to free a block that was already free!");
|
||||
|
||||
__pmm_unset(idx, mem_block);
|
||||
}
|
||||
|
||||
void pmm_set(uint32_t bit)
|
||||
{
|
||||
/**
|
||||
* Here we want to calculate if the bit is over the length
|
||||
* subtract the length and bit amount so that we compensate for the bit map
|
||||
*
|
||||
* i.e. (length / 4096) == amount of blocks in that specific mem region
|
||||
* if (bit > amt of blocks),
|
||||
* go to next node, subtract amt of blocks from bit, and pass that
|
||||
*
|
||||
* below is merely a temporary solution
|
||||
*/
|
||||
__pmm_set(bit, &main_mem);
|
||||
}
|
||||
|
||||
void pmm_unset(uint32_t bit)
|
||||
{
|
||||
// TODO: same as above
|
||||
__pmm_unset(bit, &main_mem);
|
||||
}
|
||||
|
||||
bool pmm_test(uint32_t bit)
|
||||
{
|
||||
// TODO: same as above
|
||||
return __pmm_test(bit, &main_mem);
|
||||
}
|
||||
|
||||
int pmm_first_free(void) //TODO implement a free_s where it finds a series of free pages
|
||||
{
|
||||
// TODO: same as above
|
||||
int ret = __pmm_first_free(&main_mem);
|
||||
if (ret == -1)
|
||||
kerror("OUT OF MEMORY");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void pmm_init(void)
|
||||
{
|
||||
// TODO same as above
|
||||
__pmm_init(&main_mem);
|
||||
}
|
||||
|
||||
void* pmm_alloc_block(void)
|
||||
{
|
||||
return __pmm_alloc_block(&main_mem);
|
||||
}
|
||||
|
||||
void pmm_free_block(void* p)
|
||||
{
|
||||
__pmm_free_block(p, &main_mem);
|
||||
}
|
||||
|
||||
void pmm_add_mem_block(uint32_t addr, uint32_t len)
|
||||
{
|
||||
// TODO: make this add to a linked list
|
||||
__pmm_add_mem_block(addr, len, &main_mem);
|
||||
}
|
||||
|
||||
#ifdef __TESTING__
|
||||
void print_main_mem()
|
||||
{
|
||||
printf("Available blocks: %1\nUsed blocks: %1\nMax blocks: %1\n",
|
||||
main_mem.free_blocks, main_mem.used_blocks, main_mem.max_blocks);
|
||||
}
|
||||
#endif
|
||||
|
@ -7,6 +7,5 @@ void kwarn(const char*);
|
||||
|
||||
void kinfo(const char*);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
6
kernel/include/kernel/paging.h
Normal file
6
kernel/include/kernel/paging.h
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef ARCH_PAGING_H
|
||||
#define ARCH_PAGING_H
|
||||
|
||||
#endif
|
15
kernel/include/kernel/pmm.h
Normal file
15
kernel/include/kernel/pmm.h
Normal file
@ -0,0 +1,15 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef ARCH_PMM_H
|
||||
#define ARCH_PMM_H
|
||||
|
||||
void pmm_init(void);
|
||||
void* pmm_alloc_block(void);
|
||||
void pmm_free_block(void* p);
|
||||
void pmm_add_mem_block(uint32_t addr, uint32_t len);
|
||||
|
||||
#ifdef __TESTING__
|
||||
void print_main_mem();
|
||||
#endif
|
||||
|
||||
#endif
|
@ -3,59 +3,6 @@
|
||||
#ifndef ARCH_I386_GDT_H
|
||||
#define ARCH_I386_GDT_H
|
||||
|
||||
// Each define here is for a specific flag in the descriptor.
|
||||
// Refer to the intel documentation for a description of what each one does.
|
||||
#define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data)
|
||||
#define SEG_PRES(x) ((x) << 0x07) // Present
|
||||
#define SEG_SAVL(x) ((x) << 0x0C) // Available for system use
|
||||
#define SEG_LONG(x) ((x) << 0x0D) // Long mode
|
||||
#define SEG_SIZE(x) ((x) << 0x0E) // Size (0 for 16-bit, 1 for 32)
|
||||
#define SEG_GRAN(x) ((x) << 0x0F) // Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB)
|
||||
#define SEG_PRIV(x) (((x) & 0x03) << 0x05) // Set privilege level (0 - 3)
|
||||
|
||||
#define SEG_DATA_RD 0x00 // Read-Only
|
||||
#define SEG_DATA_RDA 0x01 // Read-Only, accessed
|
||||
#define SEG_DATA_RDWR 0x02 // Read/Write
|
||||
#define SEG_DATA_RDWRA 0x03 // Read/Write, accessed
|
||||
#define SEG_DATA_RDEXPD 0x04 // Read-Only, expand-down
|
||||
#define SEG_DATA_RDEXPDA 0x05 // Read-Only, expand-down, accessed
|
||||
#define SEG_DATA_RDWREXPD 0x06 // Read/Write, expand-down
|
||||
#define SEG_DATA_RDWREXPDA 0x07 // Read/Write, expand-down, accessed
|
||||
#define SEG_CODE_EX 0x08 // Execute-Only
|
||||
#define SEG_CODE_EXA 0x09 // Execute-Only, accessed
|
||||
#define SEG_CODE_EXRD 0x0A // Execute/Read
|
||||
#define SEG_CODE_EXRDA 0x0B // Execute/Read, accessed
|
||||
#define SEG_CODE_EXC 0x0C // Execute-Only, conforming
|
||||
#define SEG_CODE_EXCA 0x0D // Execute-Only, conforming, accessed
|
||||
#define SEG_CODE_EXRDC 0x0E // Execute/Read, conforming
|
||||
#define SEG_CODE_EXRDCA 0x0F // Execute/Read, conforming, accessed
|
||||
|
||||
#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(0) | SEG_CODE_EXRD
|
||||
|
||||
#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(0) | SEG_DATA_RDWR
|
||||
|
||||
#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(3) | SEG_CODE_EXRD
|
||||
|
||||
#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(3) | SEG_DATA_RDWR
|
||||
|
||||
|
||||
#define GDT_SIZE 3
|
||||
|
||||
|
||||
void setGdt(unsigned short limit, uint64_t* base);
|
||||
|
||||
void reloadSegments();
|
||||
|
||||
uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag);
|
||||
|
||||
void gdt_init(void);
|
||||
|
||||
#endif
|
||||
|
@ -3,33 +3,6 @@
|
||||
#ifndef ARCH_IDT_H
|
||||
#define ARCH_IDT_H
|
||||
|
||||
#define IDT_MAX_DESCRIPTORS 48 // number of entries in the idt table
|
||||
|
||||
|
||||
#define EXCEPT_DIV_ERR 0
|
||||
#define EXCEPT_DEBUG 1
|
||||
#define EXCEPT_NMI 2
|
||||
#define EXCEPT_BREAKPOINT 3
|
||||
#define EXCEPT_OVERFLOW 4
|
||||
#define EXCEPT_BOUND_RANGE_EXCEEDED 5
|
||||
#define EXCEPT_INVALID_OPCODE 6
|
||||
#define EXCEPT_DEVICE_NOT_AVAILABLE 7
|
||||
#define EXCEPT_DOUBLE_FAULT 8
|
||||
#define EXCEPT_INVALID_TSS 10
|
||||
#define EXCEPT_SEG_NOT_PRESENT 11
|
||||
#define EXCEPT_STACK_SEG_FAULT 12
|
||||
#define EXCEPT_GENERAL_PROTECTION 13
|
||||
#define EXCEPT_PAGE_FAULT 14
|
||||
#define EXCEPT_FLOATING_POINT_ERR_FPU 16
|
||||
#define EXCEPT_ALIGNMENT_CHECK 17
|
||||
#define EXCEPT_MACHINE_CHECK 18
|
||||
#define EXCEPT_FLOATING_POINT_ERR_SIMD 19
|
||||
#define EXCEPT_VIRT 20
|
||||
#define EXCEPT_CTRL_PROT 21
|
||||
#define EXCEPT_HYPERVISOR_INJECTION 28
|
||||
#define EXCEPT_VMM_COMMUNICATION 29
|
||||
#define EXCEPT_SECURITY_EXCEPTION 30
|
||||
|
||||
struct cpu_state {
|
||||
uint32_t eax;
|
||||
uint32_t ebx;
|
||||
@ -49,20 +22,6 @@ struct stack_state {
|
||||
|
||||
void exception_handler(struct cpu_state cpu, uint32_t interrupt, struct stack_state stack);
|
||||
|
||||
typedef struct {
|
||||
uint16_t isr_low; // The lower 16 bits of the ISR's address
|
||||
uint16_t kernel_cs; // The GDT segment selector that the CPU will load into CS before calling the ISR
|
||||
uint8_t reserved; // set to zero
|
||||
uint8_t attributes; // Type and attributes
|
||||
uint16_t isr_high; // The higher 16 bits of the ISR's address
|
||||
} __attribute__((packed)) idt_entry_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
} __attribute__((packed)) idtr_t;
|
||||
|
||||
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags);
|
||||
void idt_init(void);
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,5 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef ARCH_IO_H
|
||||
#define ARCH_IO_H
|
||||
|
||||
@ -8,7 +10,9 @@
|
||||
* @param port The I/O port to send the data to
|
||||
* @param data The data to send to the I/O port
|
||||
*/
|
||||
void outb(unsigned short port, unsigned char data);
|
||||
void outb(unsigned short port, uint8_t data);
|
||||
void outb_16(unsigned short port, uint16_t data);
|
||||
void outb_32(unsigned short port, uint32_t data);
|
||||
|
||||
/**
|
||||
* inb:
|
||||
@ -17,7 +21,9 @@ void outb(unsigned short port, unsigned char data);
|
||||
* @param port The address of the I/O port
|
||||
* @return The read byte
|
||||
*/
|
||||
unsigned char inb(unsigned short port);
|
||||
uint8_t inb(unsigned short port);
|
||||
uint16_t inb_16(unsigned short port);
|
||||
uint32_t inb_32(unsigned short port);
|
||||
|
||||
/**
|
||||
* io_wait:
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef ARCH_KEYB_H
|
||||
#define ARCH_KEYB_H
|
||||
|
16
kernel/include/kernel/x86/pci.h
Normal file
16
kernel/include/kernel/x86/pci.h
Normal file
@ -0,0 +1,16 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef ARCH_PCI_H
|
||||
#define ARCH_PCI_H
|
||||
|
||||
#define PCI_CONFIG_ADDRESS (0xCF8)
|
||||
#define PCI_CONFIG_DATA (0xCFC)
|
||||
|
||||
uint16_t pci_config_read_word(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);
|
||||
|
||||
uint16_t pci_check_vendor(uint8_t bus, uint8_t slot, uint8_t func);
|
||||
|
||||
void check_all_busses(void);
|
||||
|
||||
|
||||
#endif
|
@ -3,34 +3,6 @@
|
||||
#ifndef ARCH_PIC_H
|
||||
#define ARCH_PIC_H
|
||||
|
||||
/** PIC I/O ports **/
|
||||
#define PIC1 0x20 /** Master PIC **/
|
||||
#define PIC2 0xA0 /** Slave PIC **/
|
||||
|
||||
/** PIC helper defines **/
|
||||
#define PIC1_COMMAND (PIC1)
|
||||
#define PIC1_DATA (PIC1 + 1)
|
||||
#define PIC2_COMMAND (PIC2)
|
||||
#define PIC2_DATA (PIC2 + 1)
|
||||
|
||||
/** PIC Commands **/
|
||||
#define ICW1_ICW4 0x01 /** Indicates ICW4 will be present **/
|
||||
#define ICW1_SINGLE 0x02 /** Single (cascade mode) **/
|
||||
#define ICW1_INTERVAL4 0x04 /** Call address interval 4 (8) **/
|
||||
#define ICW1_LEVEL 0x08 /** Level triggered (edge) mode **/
|
||||
#define ICW1_INIT 0x10 /** Initialization **/
|
||||
|
||||
#define ICW4_8086 0x01 /** 8086/88 (MCS-80/85) mode **/
|
||||
#define ICW4_AUTO 0x02 /** Auto (normal) EOI **/
|
||||
#define ICW4_BUF_SLAVE 0x08 /** Buffered mode/slave **/
|
||||
#define ICW4_BUF_MASTER 0x0C /** Buffered mode/master **/
|
||||
#define ICW4_SFNM 0x10 /** Special fully nested (not) **/
|
||||
|
||||
#define PIC_EOI 0x20 /** End-of-interrupt command code **/
|
||||
#define PIC_READ_IRR 0x0a /** OCW3 irq ready next CMD read **/
|
||||
#define PIC_READ_ISR 0x0b /** OCW3 irq service next CMD read **/
|
||||
|
||||
|
||||
#define PIC_PIT 32
|
||||
#define PIC_KEYB 33
|
||||
#define PIC_CASCADE 34 // never raised
|
||||
@ -63,11 +35,6 @@ void pic_disable(void);
|
||||
void IRQ_set_mask(uint8_t IRQline);
|
||||
void IRQ_clear_mask(uint8_t IRQline);
|
||||
|
||||
/** Returns the combined value of the cascaded PICs irq request register **/
|
||||
uint16_t pic_get_irr(void);
|
||||
/** Returns the combined value of the cascaded PICs in-service register **/
|
||||
uint16_t pic_get_isr(void);
|
||||
|
||||
/**
|
||||
* TODO: implement handling for Spurious IRQs
|
||||
* https://wiki.osdev.org/8259_PIC#Spurious_IRQs
|
||||
|
@ -1,3 +1,5 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef ARCH_PIT_H
|
||||
#define ARCH_PIT_H
|
||||
|
||||
@ -14,8 +16,29 @@
|
||||
*/
|
||||
enum PIT_CHANNEL {
|
||||
CHANNEL_0 = 0x0,
|
||||
CHANNEL_1,
|
||||
CHANNEL_1, // this channel isn't always here...
|
||||
CHANNEL_2,
|
||||
/**
|
||||
* Isn't supported on 8253 chips, but should be supported on AT and later (except for PS/2).
|
||||
*
|
||||
* Layout goes:
|
||||
* bits:
|
||||
* 76 - Set for READ_BACK
|
||||
* 5 - Latch count flag (0 = latch count, 1 = don't latch count)
|
||||
* 4 - Latch status flag (0 = latch status, 1 = don't latch status) - If this is clear, the next read of the corresponding data port will be a status byte
|
||||
* 3 - Read back timer channel 2 (1 = yes, 0 = no)
|
||||
* 2 - Read back timer channel 1 (..)
|
||||
* 1 - Read back timer channel 0 (..)
|
||||
* 0 - Reserved - set to 0
|
||||
*
|
||||
* Read back status byte:
|
||||
* bits:
|
||||
* 7 - Output pin state
|
||||
* 6 - Null count flags
|
||||
* 54 - Access mode
|
||||
* 321 - Operating mode
|
||||
* 0 BCD/Binary mode
|
||||
*/
|
||||
READ_BACK // 8254 only
|
||||
};
|
||||
|
||||
@ -28,6 +51,13 @@ enum PIT_CHANNEL {
|
||||
* HI AND LOW means that the values will come sequentially through the IO port, lowest followed by highest
|
||||
*/
|
||||
enum PIT_ACCESS_MODE {
|
||||
/*
|
||||
* To prevent the count from being updated, we can use this command to latch the PIT.
|
||||
* This must be xx000000 ( where x is the channel ).
|
||||
* The value for each channel remains latched, until its fully read (or a new CMD has been issued).
|
||||
* Some older/cheap motherboards have an issue with this command being sent a lot, leading to innaccuracies
|
||||
* this command shouldn't be sent a lot anyways.
|
||||
*/
|
||||
LATCH_COUNT_VAL_CMD = 0x0,
|
||||
LO_BYTE_ONLY,
|
||||
HI_BYTE_ONLY,
|
||||
@ -213,5 +243,19 @@ enum PIT_DIGIT_MODE {
|
||||
BCD_MODE // four-digit bcd
|
||||
};
|
||||
|
||||
struct pit_state {
|
||||
uint32_t divisor;
|
||||
// this allows us to track a.. very long time before an overflow... 52ms * INT64MAX = 4.8e20ms = 5.6e12 days = 1.5e7 centuries
|
||||
// TODO: ... handle overflow? :p
|
||||
uint64_t interrupts;
|
||||
} __attribute__((packed));
|
||||
|
||||
void init_pit(uint8_t init_command, uint8_t channel, uint32_t divisor);
|
||||
|
||||
double get_time_from_divisor(uint32_t divisor);
|
||||
|
||||
|
||||
uint16_t read_pit_count(uint8_t channel);
|
||||
void set_pit_count(uint8_t channel, uint16_t count);
|
||||
|
||||
#endif
|
||||
|
@ -29,7 +29,7 @@ void klog(const char* buf, enum log_mode mode)
|
||||
serial_writestring(buf);
|
||||
terminal_writestring(buf);
|
||||
|
||||
serial_writestring("\n");
|
||||
serial_writestring("\n\r");
|
||||
terminal_writestring("\n");
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,61 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <kernel/_kernel.h>
|
||||
#include <kernel/tty.h>
|
||||
#include <kernel/serial.h>
|
||||
#include <kernel/paging.h>
|
||||
#include <kernel/x86/gdt.h>
|
||||
#include <kernel/x86/idt.h>
|
||||
#include <kernel/x86/io.h>
|
||||
#include <kernel/x86/keyb.h>
|
||||
#include <kernel/x86/pit.h>
|
||||
#include <kernel/x86/pci.h>
|
||||
#include <kernel/pmm.h>
|
||||
|
||||
#include "multiboot.h"
|
||||
|
||||
extern struct pmm_mem_info main_mem;
|
||||
|
||||
void kmain(void)
|
||||
void verify_memmap(multiboot_info_t* mbd, uint32_t magic)
|
||||
{
|
||||
if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
|
||||
panic("Invalid magic number!");
|
||||
|
||||
if (!(mbd->flags >> 6 & 0x1))
|
||||
panic("Invalid memory map given by GRUB bootloader!");
|
||||
|
||||
if (!(mbd->flags & (1 << 0)))
|
||||
panic("Memory info not passed to kernel!");
|
||||
|
||||
puts("Printing available memory map...");
|
||||
uint32_t i;
|
||||
for (i = 0; i < mbd->mmap_length; i += sizeof(multiboot_memory_map_t)) {
|
||||
multiboot_memory_map_t* mmmt = (multiboot_memory_map_t*) (mbd->mmap_addr + i);
|
||||
|
||||
printf("Start Addr: %4 | Length: %4 | Size: %2 | Type: %d\n",
|
||||
mmmt->addr, mmmt->len, mmmt->size, mmmt->type);
|
||||
|
||||
// This is pretty flaky, we want to actually create a linked list,
|
||||
// where each block of available memory gets its own mem_block
|
||||
// not just this main one
|
||||
// TODO
|
||||
if (mmmt->addr == 0x100000) {
|
||||
pmm_add_mem_block((uint32_t) mmmt->addr, (uint32_t) mmmt->len);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void _main(multiboot_info_t* mbd, uint32_t magic)
|
||||
{
|
||||
#ifdef __TESTING__ // important components should be declared first, but if we're testing we want to log all of that
|
||||
terminal_initialize();
|
||||
serial_initialize();
|
||||
#endif
|
||||
verify_memmap(mbd, magic);
|
||||
|
||||
gdt_init();
|
||||
idt_init();
|
||||
|
||||
@ -24,9 +63,15 @@ void kmain(void)
|
||||
terminal_initialize();
|
||||
serial_initialize();
|
||||
#endif
|
||||
|
||||
|
||||
pmm_init();
|
||||
|
||||
//setup_paging();
|
||||
|
||||
init_kb();
|
||||
|
||||
init_pit(0x36, PIT_CHANNEL_0, 0);
|
||||
|
||||
printf("Entering loop...\n");
|
||||
while (1) {
|
||||
|
||||
|
274
kernel/multiboot.h
Normal file
274
kernel/multiboot.h
Normal file
@ -0,0 +1,274 @@
|
||||
/* 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 */
|
13
libc/include/math.h
Normal file
13
libc/include/math.h
Normal file
@ -0,0 +1,13 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef MATH_H
|
||||
#define MATH_H
|
||||
|
||||
int pow(int base, int exp);
|
||||
|
||||
uint8_t clamp_u8(uint8_t val, uint8_t min, uint8_t max);
|
||||
uint16_t clamp_u16(uint16_t val, uint16_t min, uint16_t max);
|
||||
uint32_t clamp_u32(uint32_t val, uint32_t min, uint32_t max);
|
||||
uint64_t clamp_u64(uint64_t val, uint64_t min, uint64_t max);
|
||||
|
||||
#endif
|
@ -8,6 +8,8 @@
|
||||
__attribute__((__noreturn__))
|
||||
void abort(void);
|
||||
|
||||
void panic(const char* str);
|
||||
|
||||
char* s64toa(int64_t num, char* buf, int base);
|
||||
char* u64toa(uint64_t num, char* buf, int base);
|
||||
char* s32toa(int32_t num, char* buf, int base);
|
||||
@ -20,5 +22,7 @@ char* u8toa(uint8_t num, char* buf, int base);
|
||||
char* itoa(int num, char* buf, int base);
|
||||
char* utoa(unsigned int num, char* buf, int base);
|
||||
|
||||
char* dtoa(double n, char* buf, int afterpoint);
|
||||
|
||||
|
||||
#endif
|
||||
|
39
libc/math/clamp.c
Normal file
39
libc/math/clamp.c
Normal file
@ -0,0 +1,39 @@
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
uint8_t clamp_u8(uint8_t val, uint8_t min, uint8_t max)
|
||||
{
|
||||
if (val > max)
|
||||
return max;
|
||||
if (val < min)
|
||||
return min;
|
||||
return val;
|
||||
}
|
||||
|
||||
uint16_t clamp_u16(uint16_t val, uint16_t min, uint16_t max)
|
||||
{
|
||||
if (val > max)
|
||||
return max;
|
||||
if (val < min)
|
||||
return min;
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t clamp_u32(uint32_t val, uint32_t min, uint32_t max)
|
||||
{
|
||||
if (val > max)
|
||||
return max;
|
||||
if (val < min)
|
||||
return min;
|
||||
return val;
|
||||
|
||||
}
|
||||
|
||||
uint64_t clamp_u64(uint64_t val, uint64_t min, uint64_t max)
|
||||
{
|
||||
if (val > max)
|
||||
return max;
|
||||
if (val < min)
|
||||
return min;
|
||||
return val;
|
||||
}
|
9
libc/math/pow.c
Normal file
9
libc/math/pow.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <math.h>
|
||||
|
||||
int pow(int base, int exp)
|
||||
{
|
||||
int res = base;
|
||||
for (int i = 0; i < exp; i++)
|
||||
res *= base;
|
||||
return res;
|
||||
}
|
@ -16,7 +16,7 @@ void init_queue(queue *q)
|
||||
bool queue_is_empty(queue *q)
|
||||
{
|
||||
bool empty = q->front == q->rear - 1;
|
||||
if (empty)
|
||||
if (empty) // This allows us to continuously reuse the queue when it empties. Ideally i'd like to switch to a heap implementation... TODO
|
||||
init_queue(q);
|
||||
return empty;
|
||||
}
|
||||
|
@ -77,6 +77,18 @@ int printf(const char* restrict format, ...) {
|
||||
if (!print(buffer, len))
|
||||
return -1;
|
||||
written += len;
|
||||
} else if (*format == 'f') {
|
||||
format++;
|
||||
double d = (double) va_arg(parameters, double);
|
||||
dtoa(d, buffer, 5);
|
||||
size_t len = strlen(buffer);
|
||||
if (maxrem < len) {
|
||||
// TODO
|
||||
return -1;
|
||||
}
|
||||
if (!print(buffer, len))
|
||||
return -1;
|
||||
written += len;
|
||||
} else if (*format == 'u') {
|
||||
format++;
|
||||
unsigned int i = (unsigned int) va_arg(parameters, unsigned int);
|
||||
@ -103,8 +115,8 @@ int printf(const char* restrict format, ...) {
|
||||
written += len;
|
||||
} else if (*format == '1') {
|
||||
format++;
|
||||
int32_t i = (int32_t) va_arg(parameters, int32_t);
|
||||
s32toa(i, buffer, 10);
|
||||
int32_t i = (uint32_t) va_arg(parameters, int32_t);
|
||||
u32toa(i, buffer, 10);
|
||||
size_t len = strlen(buffer);
|
||||
if (maxrem < len) {
|
||||
// TODO: Set errno to EOVERFLOW.
|
||||
@ -149,6 +161,17 @@ int printf(const char* restrict format, ...) {
|
||||
if (!print(buffer, len))
|
||||
return -1;
|
||||
written += len;
|
||||
} else if (*format == 'b') {
|
||||
format++;
|
||||
uint32_t i = (uint32_t) va_arg(parameters, uint32_t);
|
||||
u32toa(i, buffer, 2);
|
||||
size_t len = strlen(buffer);
|
||||
if (maxrem < len) {
|
||||
return -1;
|
||||
}
|
||||
if (!print(buffer, len))
|
||||
return -1;
|
||||
written += len;
|
||||
} else {
|
||||
format = format_begun_at;
|
||||
size_t len = strlen(format);
|
||||
|
@ -13,6 +13,10 @@ int putchar(int ic) {
|
||||
terminal_write(&c, sizeof(c));
|
||||
#ifdef __TESTING__
|
||||
serial_write(&c, sizeof(c));
|
||||
if (c == '\n') {
|
||||
char tmp = '\r';
|
||||
serial_write(&tmp, sizeof(tmp));
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
// TODO: Implement stdio and the write system call.
|
||||
|
@ -13,3 +13,9 @@ void abort(void) {
|
||||
while (1) { }
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void panic(const char* str)
|
||||
{
|
||||
printf("%s\n", str);
|
||||
abort();
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
static void reverse(char* buf, int len)
|
||||
{
|
||||
@ -273,3 +275,35 @@ char* utoa(unsigned int num, char* buf, int base)
|
||||
reverse(buf, i); // reverse, since we did it backwards!
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int dbl_to_str(int x, char* buf, int d)
|
||||
{
|
||||
int i = 0;
|
||||
while (x) {
|
||||
buf[i++] = (x % 10) + '0';
|
||||
x = x / 10;
|
||||
}
|
||||
|
||||
while (i < d)
|
||||
buf[i++] = '0';
|
||||
|
||||
reverse(buf, i);
|
||||
buf[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
char* dtoa(double n, char* buf, int afterpoint)
|
||||
{
|
||||
int whole = (int) n;
|
||||
|
||||
double decimals = n - (double) whole;
|
||||
|
||||
int i = dbl_to_str(whole, buf, 0);
|
||||
if (afterpoint != 0) {
|
||||
buf[i] = '.'; // add the decimal
|
||||
|
||||
decimals = decimals * pow(10, afterpoint);
|
||||
dbl_to_str((int) decimals, buf + i + 1, afterpoint + 1);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
@ -8,4 +8,4 @@ log: bochslog.txt
|
||||
clock: sync=realtime, time0=local
|
||||
cpu: count=1, ips=10000000
|
||||
com1: enabled=1, mode=file, dev=com1.out
|
||||
|
||||
usb_uhci: port1=mouse, port2=disk, options2="path:usbstick.img"
|
||||
|
Reference in New Issue
Block a user