Initial import from mbr_asm project
This commit is contained in:
commit
2c251fa51c
43
Makefile
Normal file
43
Makefile
Normal file
@ -0,0 +1,43 @@
|
||||
# Used to generated .d file that deal with header dependencies
|
||||
CPPFLAGS = -MMD
|
||||
AS=nasm
|
||||
ASFLAGS += -f elf32
|
||||
LDFLAGS += -m32 -nostdlib -static -fno-common -fno-use-cxa-atexit -fno-exceptions -fno-non-call-exceptions -fno-weak -fno-rtti -fno-stack-protector
|
||||
CFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-pie -fno-stack-protector
|
||||
CXXFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-rtti -fno-pie
|
||||
|
||||
SUBDIRS := core drivers
|
||||
|
||||
CPPFLAGS += $(foreach dir, $(SUBDIRS), -I$(dir))
|
||||
|
||||
asmsrc=$(wildcard *.asm)
|
||||
asmobj=$(asmsrc:%.asm=%.o)
|
||||
csrc=$(shell find $(SUBDIRS) -type f -name "*.c")# $(wildcard *.c)
|
||||
cobj=$(csrc:%.c=%.o)
|
||||
deps = $(csrc:%.c=%.d)
|
||||
|
||||
kernel:$(asmobj) $(cobj) linker.ld
|
||||
$(CXX) $(LDFLAGS) $(cobj) $(asmobj) -o $@ -T linker.ld
|
||||
|
||||
fd.img: kernel
|
||||
dd if=/dev/zero of=$@ bs=512 count=2880
|
||||
dd if=$< of=$@ conv=notrunc
|
||||
|
||||
#https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#x86-Function-Attributes
|
||||
core/exception_handler.o:core/exception_handler.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -mgeneral-regs-only -c $< -o $@
|
||||
core/irq_handler.o:core/irq_handler.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -mgeneral-regs-only -c $< -o $@
|
||||
|
||||
%.o:%.asm
|
||||
$(AS) $(ASFLAGS) -o $@ $<
|
||||
|
||||
test:kernel
|
||||
qemu-system-x86_64 -fda $<
|
||||
|
||||
clean:
|
||||
$(RM) kernel $(asmobj) $(cobj) $(deps)
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(deps)
|
||||
endif
|
24
core/exception.c
Normal file
24
core/exception.c
Normal file
@ -0,0 +1,24 @@
|
||||
#include "exception.h"
|
||||
#include "idt.h"
|
||||
#include "interrupt.h"
|
||||
#include "irq.h"
|
||||
|
||||
exception_handler exception_handler_array[EXCEPTION_NUM] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
int exceptionSetRoutine(int exception, exception_handler handler)
|
||||
{
|
||||
uint32_t flags;
|
||||
if ((exception < 0) || exception >= EXCEPTION_NUM)
|
||||
return -1;
|
||||
|
||||
disable_IRQs(flags);
|
||||
|
||||
exception_handler_array[exception] = handler;
|
||||
|
||||
idt_set_handler(EXCEPTION_INTERRUPT_BASE_ADDRESS + exception, (unsigned int)handler,
|
||||
0);
|
||||
restore_IRQs(flags);
|
||||
return 0;
|
||||
}
|
46
core/exception.h
Normal file
46
core/exception.h
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#include "interrupt.h"
|
||||
#include "types.h"
|
||||
|
||||
#define EXCEPTION_INTERRUPT_BASE_ADDRESS 0
|
||||
|
||||
// list and description https://wiki.osdev.org/Exceptions
|
||||
|
||||
#define EXCEPTION_DIVIDE_ZERO 0
|
||||
#define EXCEPTION_DEBUG 1
|
||||
#define EXCEPTION_NMI 2
|
||||
#define EXCEPTION_BREAKPOINT 3
|
||||
#define EXCEPTION_OVERFLOW 4
|
||||
#define EXCEPTION_BOUND_RANGE_EXCEEDED 5
|
||||
#define EXCEPTION_INVALID_OPCODE 6
|
||||
#define EXCEPTION_DEVICE_NOT_AVAILABLE 7
|
||||
#define EXCEPTION_DOUBLE_FAULT 8
|
||||
#define EXCEPTION_COPRO_OVERRUN 9
|
||||
#define EXCEPTION_INVALID_TSS 10
|
||||
#define EXCEPTION_SEGMENT_NOT_PRESENT 11
|
||||
#define EXCEPTION_STACK_SEGMENT_FAULT 12
|
||||
#define EXCEPTION_GENERAL_PROTECTION_FAULT 13
|
||||
#define EXCEPTION_PAGE_FAULT 14
|
||||
#define EXCEPTION_RESERVED_1 15
|
||||
#define EXCEPTION_X87_FP_EXCEPTION 16
|
||||
#define EXCEPTION_ALIGNMENT_CHECK 17
|
||||
#define EXCEPTION_MACHINE_CHECK 18
|
||||
#define EXCEPTION_SIMD_FP 19
|
||||
#define EXCEPTION_VIRTUALIZATION 20
|
||||
#define EXCEPTION_RESERVED_2 21
|
||||
#define EXCEPTION_RESERVED_3 22
|
||||
#define EXCEPTION_RESERVED_4 23
|
||||
#define EXCEPTION_RESERVED_5 24
|
||||
#define EXCEPTION_RESERVED_6 25
|
||||
#define EXCEPTION_RESERVED_7 26
|
||||
#define EXCEPTION_RESERVED_8 27
|
||||
#define EXCEPTION_RESERVED_9 28
|
||||
#define EXCEPTION_RESERVED_10 29
|
||||
#define EXCEPTION_SECURITY 30
|
||||
#define EXCEPTION_RESERVED_11 31
|
||||
|
||||
#define EXCEPTION_NUM 32
|
||||
|
||||
typedef void (*exception_handler) (struct interrupt_frame *frame, ulong error_code);
|
||||
int exceptionSetRoutine(int exception, exception_handler handler);
|
||||
|
12
core/exception_handler.c
Normal file
12
core/exception_handler.c
Normal file
@ -0,0 +1,12 @@
|
||||
#include "exception.h"
|
||||
#include "vga.h"
|
||||
|
||||
// Need GCC > 6
|
||||
__attribute__((interrupt)) void print_handler(struct interrupt_frame *frame, ulong error_code)
|
||||
{
|
||||
|
||||
printStringDetails("EXCEPTION", RED, BLACK, 0, VGA_HEIGHT - 1);
|
||||
printIntDetails(error_code, RED, BLACK, 11, VGA_HEIGHT - 1);
|
||||
(void)frame;
|
||||
(void)error_code;
|
||||
}
|
147
core/gdt.c
Normal file
147
core/gdt.c
Normal file
@ -0,0 +1,147 @@
|
||||
/* Copyright (C) 2004 David Decotigny
|
||||
Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
USA.
|
||||
*/
|
||||
#include "segment.h"
|
||||
|
||||
#include "gdt.h"
|
||||
|
||||
/**
|
||||
* The sructure of a segment descriptor.
|
||||
*
|
||||
* @see Intel x86 doc, Vol 3, section 3.4.3, figure 3-8. For segment
|
||||
* types, see section 3.5
|
||||
*/
|
||||
struct x86_segment_descriptor {
|
||||
/* Lowest dword */
|
||||
uint16_t limit_15_0; /* Segment limit, bits 15..0 */
|
||||
uint16_t base_paged_addr_15_0; /* Base address, bits 15..0 */
|
||||
|
||||
/* Highest dword */
|
||||
uint8_t base_paged_addr_23_16; /* Base address bits 23..16 */
|
||||
uint8_t segment_type : 4; /* Section 3.4.3.1 (code/data)
|
||||
and 3.5 (system) of Intel x86 vol 3 */
|
||||
uint8_t descriptor_type : 1; /* 0=system, 1=Code/Data */
|
||||
uint8_t dpl : 2;
|
||||
uint8_t present : 1;
|
||||
|
||||
uint8_t limit_19_16 : 4; /* Segment limit, bits 19..16 */
|
||||
uint8_t custom : 1;
|
||||
uint8_t zero : 1;
|
||||
uint8_t op_size : 1; /* 0=16bits instructions, 1=32bits */
|
||||
uint8_t granularity : 1; /* 0=limit in bytes, 1=limit in pages */
|
||||
|
||||
uint8_t base_paged_addr_31_24; /* Base address bits 31..24 */
|
||||
} __attribute__((packed, aligned(8)));
|
||||
|
||||
/**
|
||||
* The GDT register, which stores the address and size of the
|
||||
* GDT.
|
||||
*
|
||||
* @see Intel x86 doc vol 3, section 2.4, figure 2-4; and section
|
||||
* 3.5.1
|
||||
*/
|
||||
struct x86_gdt_register {
|
||||
/* The maximum GDT offset allowed to access an entry in the GDT */
|
||||
uint16_t limit;
|
||||
|
||||
/* This is not exactly a "virtual" address, ie an adddress such as
|
||||
those of instructions and data; this is a "linear" address, ie an
|
||||
address in the paged memory. However, in SOS we configure the
|
||||
segmented memory as a "flat" space: the 0-4GB segment-based (ie
|
||||
"virtual") addresses directly map to the 0-4GB paged memory (ie
|
||||
"linear"), so that the "linear" addresses are numerically equal
|
||||
to the "virtual" addresses: this base_addr will thus be the same
|
||||
as the address of the gdt array */
|
||||
uint32_t base_addr;
|
||||
} __attribute__((packed, aligned(8)));
|
||||
|
||||
/**
|
||||
* Helper macro that builds a Segment descriptor for the virtual
|
||||
* 0..4GB addresses to be mapped to the linear 0..4GB linear
|
||||
* addresses.
|
||||
*/
|
||||
#define BUILD_GDTE(descr_privilege_level, is_code) \
|
||||
((struct x86_segment_descriptor){ \
|
||||
.limit_15_0 = 0xffff, \
|
||||
.base_paged_addr_15_0 = 0, \
|
||||
.base_paged_addr_23_16 = 0, \
|
||||
.segment_type = \
|
||||
((is_code) ? 0xb : 0x3), /* With descriptor_type (below) = 1 (code/data), \
|
||||
* see Figure 3-1 of section 3.4.3.1 in Intel \
|
||||
* x86 vol 3: \
|
||||
* - Code (bit 3 = 1): \
|
||||
* bit 0: 1=Accessed \
|
||||
* bit 1: 1=Readable \
|
||||
* bit 2: 0=Non-Conforming \
|
||||
* - Data (bit 3 = 0): \
|
||||
* bit 0: 1=Accessed \
|
||||
* bit 1: 1=Writable \
|
||||
* bit 2: 0=Expand up (stack-related) \
|
||||
* For Conforming/non conforming segments, see \
|
||||
* Intel x86 Vol 3 section 4.8.1.1 \
|
||||
*/ \
|
||||
.descriptor_type = 1, /* 1=Code/Data */ \
|
||||
.dpl = ((descr_privilege_level)&0x3), \
|
||||
.present = 1, \
|
||||
.limit_19_16 = 0xf, \
|
||||
.custom = 0, \
|
||||
.op_size = 1, /* 32 bits instr/data */ \
|
||||
.granularity = 1 /* limit is in 4kB Pages */ \
|
||||
})
|
||||
|
||||
/** The actual GDT */
|
||||
static struct x86_segment_descriptor gdt[] = {
|
||||
[SOS_SEG_NULL] =
|
||||
(struct x86_segment_descriptor){
|
||||
0,
|
||||
},
|
||||
[SOS_SEG_KCODE] = BUILD_GDTE(0, 1),
|
||||
[SOS_SEG_KDATA] = BUILD_GDTE(0, 0),
|
||||
};
|
||||
|
||||
int gdtSetup(void)
|
||||
{
|
||||
struct x86_gdt_register gdtr;
|
||||
|
||||
/* Address of the GDT */
|
||||
gdtr.base_addr = (uint32_t)gdt;
|
||||
|
||||
/* The limit is the maximum offset in bytes from the base address of
|
||||
the GDT */
|
||||
gdtr.limit = sizeof(gdt) - 1;
|
||||
|
||||
/* Commit the GDT into the CPU, and update the segment
|
||||
registers. The CS register may only be updated with a long jump
|
||||
to an absolute address in the given segment (see Intel x86 doc
|
||||
vol 3, section 4.8.1). */
|
||||
asm volatile("lgdt %0 \n\
|
||||
ljmp %1,$1f \n\
|
||||
1: \n\
|
||||
movw %2, %%ax \n\
|
||||
movw %%ax, %%ss \n\
|
||||
movw %%ax, %%ds \n\
|
||||
movw %%ax, %%es \n\
|
||||
movw %%ax, %%fs \n\
|
||||
movw %%ax, %%gs"
|
||||
:
|
||||
: "m"(gdtr), "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE)),
|
||||
"i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA))
|
||||
: "memory", "eax");
|
||||
|
||||
return 0;
|
||||
}
|
39
core/gdt.h
Normal file
39
core/gdt.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* Copyright (C) 2004 David Decotigny
|
||||
Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
USA.
|
||||
*/
|
||||
#ifndef _SOS_GDT_H_
|
||||
#define _SOS_GDT_H_
|
||||
|
||||
/**
|
||||
* @file gdt.h
|
||||
*
|
||||
* The routines that manage the GDT, the table that maps the virtual
|
||||
* addresses (data/instructions, segment-relative), to "linear"
|
||||
* addresses (ie paged-memory). In SOS/x86, we use a "flat" virtual
|
||||
* space, ie the virtual and linear spaces are equivalent.
|
||||
*
|
||||
* @see Intel x86 doc vol 3, chapter 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Configure the virtual space as a direct mapping to the linear
|
||||
* address space (ie "flat" virtual space).
|
||||
*/
|
||||
int gdtSetup(void);
|
||||
|
||||
#endif /* _SOS_GDT_H_ */
|
68
core/idt.c
Normal file
68
core/idt.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include "idt.h"
|
||||
static struct idtEntry idt[IDT_NUM];
|
||||
|
||||
int idtSetup()
|
||||
{
|
||||
struct idtRegister idtr;
|
||||
|
||||
for (int i = 0; i < IDT_NUM; i++) {
|
||||
struct idtEntry *idte = idt + i;
|
||||
|
||||
/* Setup an empty IDTE interrupt gate, see figure 5-2 in Intel
|
||||
x86 doc, vol 3 */
|
||||
idte->seg_sel = BUILD_SEGMENT_SELECTOR(RING_0, 0, SEGMENT_IDX_CODE);
|
||||
idte->reserved = 0;
|
||||
idte->flags = 0;
|
||||
idte->type = 0x6; /* Interrupt gate (110b) */
|
||||
idte->op_size = 1; /* 32bits instructions */
|
||||
|
||||
/* Disabled it for now */
|
||||
idte->zero = 0;
|
||||
idte->offset_low = 0;
|
||||
idte->offset_high = 0;
|
||||
idte->dpl = 0;
|
||||
idte->present = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the IDT register, see Intel x86 doc vol 3, section 5.8.
|
||||
*/
|
||||
|
||||
/* Address of the IDT */
|
||||
idtr.base_addr = (uint32_t)idt;
|
||||
|
||||
/* The limit is the maximum offset in bytes from the base address of
|
||||
the IDT */
|
||||
idtr.limit = sizeof(idt) - 1;
|
||||
|
||||
/* Commit the IDT into the CPU */
|
||||
asm volatile("lidt %0\n" ::"m"(idtr) : "memory");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int idt_set_handler(int index, unsigned int addr, int priviledge)
|
||||
{
|
||||
struct idtEntry *idte;
|
||||
|
||||
if (index < 0 || index >= IDT_NUM)
|
||||
return -1;
|
||||
if ((priviledge < 0) || priviledge > 3)
|
||||
return -1;
|
||||
|
||||
idte = idt + index;
|
||||
|
||||
if (addr != (unsigned int)NULL) {
|
||||
idte->offset_low = addr & 0xffff;
|
||||
idte->offset_high = (addr >> 16) & 0xffff;
|
||||
idte->dpl = priviledge;
|
||||
idte->present = 1;
|
||||
} else {
|
||||
idte->offset_low = 0;
|
||||
idte->offset_high = 0;
|
||||
idte->dpl = 0;
|
||||
idte->present = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
45
core/idt.h
Normal file
45
core/idt.h
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
#define IDT_NUM 256
|
||||
|
||||
#define RING_0 0
|
||||
#define RING_1 1
|
||||
#define RING_2 2
|
||||
#define RING_3 3
|
||||
|
||||
#define SEGMENT_IDX_NULL 0
|
||||
#define SEGMENT_IDX_CODE 1
|
||||
#define SEGMENT_IDX_DATA 2
|
||||
|
||||
struct idtEntry {
|
||||
uint16_t offset_low;
|
||||
uint16_t seg_sel;
|
||||
uint8_t reserved : 5;
|
||||
uint8_t flags : 3;
|
||||
uint8_t type : 3;
|
||||
uint8_t op_size : 1;
|
||||
uint8_t zero : 1;
|
||||
uint8_t dpl : 2;
|
||||
uint8_t present : 1;
|
||||
uint16_t offset_high;
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* The IDT register, which stores the address and size of the
|
||||
* IDT.
|
||||
*
|
||||
* @see Intel x86 doc vol 3, section 2.4, figure 2-4
|
||||
*/
|
||||
struct idtRegister {
|
||||
uint16_t limit;
|
||||
uint32_t base_addr;
|
||||
} __attribute__((packed, aligned(8)));
|
||||
|
||||
/* Build segment http://wiki.osdev.org/Selector*/
|
||||
#define BUILD_SEGMENT_SELECTOR(desc_privilege, in_ldt, index) \
|
||||
((((desc_privilege)&0x3) << 0) | (((in_ldt) ? 1 : 0) << 2) | \
|
||||
((index) << 3))
|
||||
|
||||
int idtSetup();
|
||||
int idt_set_handler(int index, unsigned int addr, int priviledge);
|
11
core/interrupt.h
Normal file
11
core/interrupt.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
struct interrupt_frame;
|
||||
|
||||
//Exception
|
||||
void print_handler(struct interrupt_frame *frame, ulong error_code);
|
||||
|
||||
//IRQ
|
||||
void keyboard_handler(struct interrupt_frame *frame);
|
||||
void timer_handler(struct interrupt_frame *frame);
|
21
core/io.h
Normal file
21
core/io.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
// NIH http://wiki.osdev.org/Inline_Assembly/Examples#I.2FO_access
|
||||
static inline void outb(uint16_t port, uint8_t val)
|
||||
{
|
||||
asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
|
||||
/* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint).
|
||||
* Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint).
|
||||
* The outb %al, %dx encoding is the only option for all other cases.
|
||||
* %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */
|
||||
}
|
||||
|
||||
static inline uint8_t inb(uint16_t port)
|
||||
{
|
||||
uint8_t ret;
|
||||
asm volatile ( "inb %1, %0"
|
||||
: "=a"(ret)
|
||||
: "Nd"(port) );
|
||||
return ret;
|
||||
}
|
32
core/irq.c
Normal file
32
core/irq.c
Normal file
@ -0,0 +1,32 @@
|
||||
#include "irq.h"
|
||||
#include "idt.h"
|
||||
#include "pic.h"
|
||||
#include "types.h"
|
||||
|
||||
int irqSetup()
|
||||
{
|
||||
initPic();
|
||||
return 0;
|
||||
}
|
||||
|
||||
irq_handler irq_handler_array[IRQ_NUM] = {NULL, };
|
||||
|
||||
int irqSetRoutine(int irq, irq_handler handler)
|
||||
{
|
||||
uint32_t flags;
|
||||
if ((irq < 0) || irq >= IRQ_NUM)
|
||||
return -1;
|
||||
|
||||
disable_IRQs(flags);
|
||||
|
||||
irq_handler_array[irq] = handler;
|
||||
|
||||
if (handler != NULL) {
|
||||
int ret =
|
||||
idt_set_handler(IRQ_INTERRUPT_BASE_ADDRESS + irq, (unsigned int)irq_handler_array[irq], 0);
|
||||
if (!ret)
|
||||
enableIrq(irq);
|
||||
}
|
||||
restore_IRQs(flags);
|
||||
return 0;
|
||||
}
|
40
core/irq.h
Normal file
40
core/irq.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#include "interrupt.h"
|
||||
|
||||
#define save_flags(flags) asm volatile("pushfl ; popl %0" : "=g"(flags)::"memory")
|
||||
#define restore_flags(flags) asm volatile("push %0; popfl" ::"g"(flags) : "memory")
|
||||
|
||||
#define disable_IRQs(flags) \
|
||||
({ \
|
||||
save_flags(flags); \
|
||||
asm("cli\n"); \
|
||||
})
|
||||
#define restore_IRQs(flags) restore_flags(flags)
|
||||
|
||||
|
||||
#define IRQ_TIMER 0 // MASTER IRQ
|
||||
#define IRQ_KEYBOARD 1
|
||||
#define IRQ_SLAVE_PIC 2
|
||||
#define IRQ_COM2 3
|
||||
#define IRQ_COM1 4
|
||||
#define IRQ_LPT2 5
|
||||
#define IRQ_FLOPPY 6
|
||||
#define IRQ_LPT1 7
|
||||
#define IRQ_8_NOT_DEFINED 8 // SLAVE
|
||||
#define IRQ_RESERVED_1 9 // SLAVE IRQ
|
||||
#define IRQ_RESERVED_2 10
|
||||
#define IRQ_RESERVED_3 11
|
||||
#define IRQ_RESERVED_4 12
|
||||
#define IRQ_COPROCESSOR 13
|
||||
#define IRQ_HARDDISK 14
|
||||
#define IRQ_RESERVED_5 15
|
||||
|
||||
#define IRQ_INTERRUPT_BASE_ADDRESS 0x20
|
||||
#define IRQ_NUM 16
|
||||
|
||||
// An handler should finish by the iret opcode -> https://wiki.osdev.org/Interrupt_Service_Routines
|
||||
// That's why we use wrapper around them or the gcc interrupt attribut
|
||||
// __attribute__((interrupt)) void (*irq_handler)(int irq);
|
||||
typedef void (*irq_handler)(struct interrupt_frame *frame);
|
||||
int irqSetup();
|
||||
int irqSetRoutine(int irq, irq_handler handler);
|
22
core/irq_handler.c
Normal file
22
core/irq_handler.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include "interrupt.h"
|
||||
#include "io.h"
|
||||
#include "irq.h"
|
||||
#include "keyboard.h"
|
||||
#include "pic.h"
|
||||
#include "vga.h"
|
||||
|
||||
// Need GCC > 6
|
||||
__attribute__((interrupt)) void keyboard_handler(struct interrupt_frame *frame)
|
||||
{
|
||||
EOIIrq(IRQ_KEYBOARD);
|
||||
keyboard_do_irq();
|
||||
(void)frame;
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void timer_handler(struct interrupt_frame *frame)
|
||||
{
|
||||
static int timeCnt = 0;
|
||||
EOIIrq(IRQ_TIMER);
|
||||
printIntDetails(timeCnt++, RED, BLACK, 20, VGA_HEIGHT - 1);
|
||||
(void)frame;
|
||||
}
|
11
core/klibc.c
Normal file
11
core/klibc.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include "klibc.h"
|
||||
|
||||
void *memcpy(void *dst, const void *src, size_t n)
|
||||
{
|
||||
char *dstChar = dst;
|
||||
const char *srcChar = src;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
*(dstChar++) = *(srcChar++);
|
||||
}
|
||||
return dst;
|
||||
}
|
4
core/klibc.h
Normal file
4
core/klibc.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n );
|
37
core/main.c
Normal file
37
core/main.c
Normal file
@ -0,0 +1,37 @@
|
||||
#include "exception.h"
|
||||
#include "gdt.h"
|
||||
#include "idt.h"
|
||||
#include "interrupt.h"
|
||||
#include "io.h"
|
||||
#include "irq.h"
|
||||
#include "pit.h"
|
||||
#include "types.h"
|
||||
#include "vga.h"
|
||||
|
||||
void cpuid(int code, uint32_t *a, uint32_t *d)
|
||||
{
|
||||
asm volatile("cpuid" : "=a"(*a), "=d"(*d) : "0"(code) : "ebx", "ecx");
|
||||
}
|
||||
|
||||
void kmain()
|
||||
{
|
||||
initVGA(BLACK, GREEN);
|
||||
printString("Setting up IDT\n");
|
||||
gdtSetup();
|
||||
idtSetup();
|
||||
irqSetup();
|
||||
initPit(100);
|
||||
|
||||
printString("Setting up IRQ handlers\n");
|
||||
irqSetRoutine(IRQ_KEYBOARD, keyboard_handler);
|
||||
irqSetRoutine(IRQ_TIMER, timer_handler);
|
||||
printString("Enabling HW interrupts\n");
|
||||
exceptionSetRoutine(EXCEPTION_DOUBLE_FAULT, print_handler);
|
||||
// Enabling the HW interrupts
|
||||
asm volatile("sti\n");
|
||||
int count = 0;
|
||||
while (1) {
|
||||
printIntDetails(count++, GREEN, BLACK, 0, VGA_HEIGHT - 1);
|
||||
}
|
||||
printString("exiting\n");
|
||||
}
|
59
core/segment.h
Normal file
59
core/segment.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* Copyright (C) 2004 The SOS Team
|
||||
Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
USA.
|
||||
*/
|
||||
#ifndef _SOS_HWSEGS_H_
|
||||
#define _SOS_HWSEGS_H_
|
||||
|
||||
/**
|
||||
* @file segments.h
|
||||
*
|
||||
* Global and local (GDT/LDT) segment descriptor definition and
|
||||
* structure. These segments map virtual addresses (ie
|
||||
* data/instruction addresses, relative to these segment descriptors)
|
||||
* to linear addresses (ie addresses in the paged-memory space).
|
||||
*
|
||||
* @see Intel x86 doc, vol 3 chapter 3.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/*
|
||||
* Global segment selectors (GDT) for SOS/x86.
|
||||
*
|
||||
* @see gdt.h
|
||||
*/
|
||||
#define SOS_SEG_NULL 0 /* NULL segment, unused by the procesor */
|
||||
#define SOS_SEG_KCODE 1 /* Kernel code segment */
|
||||
#define SOS_SEG_KDATA 2 /* Kernel data segment */
|
||||
|
||||
|
||||
/**
|
||||
* Helper macro that builds a segment register's value
|
||||
*/
|
||||
#define SOS_BUILD_SEGMENT_REG_VALUE(desc_privilege,in_ldt,seg_index) \
|
||||
( (((desc_privilege) & 0x3) << 0) \
|
||||
| (((in_ldt)?1:0) << 2) \
|
||||
| ((seg_index) << 3) )
|
||||
|
||||
|
||||
/*
|
||||
* Local segment selectors (LDT) for SOS/x86
|
||||
*/
|
||||
/* None */
|
||||
|
||||
#endif /* _SOS_HWSEGS_H_ */
|
47
core/types.h
Normal file
47
core/types.h
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
typedef __signed__ char __s8;
|
||||
typedef unsigned char __u8;
|
||||
|
||||
typedef __signed__ short __s16;
|
||||
typedef unsigned short __u16;
|
||||
|
||||
typedef __signed__ int __s32;
|
||||
typedef unsigned int __u32;
|
||||
|
||||
#ifdef __GNUC__
|
||||
__extension__ typedef __signed__ long long __s64;
|
||||
__extension__ typedef unsigned long long __u64;
|
||||
#else
|
||||
typedef __signed__ long long __s64;
|
||||
typedef unsigned long long __u64;
|
||||
#endif
|
||||
|
||||
/* sysv */
|
||||
typedef unsigned char unchar;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
typedef __s8 int8_t;
|
||||
typedef __s16 int16_t;
|
||||
typedef __s32 int32_t;
|
||||
|
||||
typedef __u8 uint8_t;
|
||||
typedef __u16 uint16_t;
|
||||
typedef __u32 uint32_t;
|
||||
|
||||
typedef __u64 uint64_t;
|
||||
typedef __u64 u_int64_t;
|
||||
typedef __s64 int64_t;
|
||||
|
||||
typedef enum { FALSE=0, TRUE } bool_t;
|
||||
#define NULL ((void*)0)
|
||||
|
||||
#if __x86_64__
|
||||
typedef unsigned long size_t;
|
||||
typedef long ssize_t;
|
||||
#else
|
||||
typedef unsigned int size_t;
|
||||
typedef int ssize_t;
|
||||
#endif
|
301
drivers/keyboard.c
Normal file
301
drivers/keyboard.c
Normal file
@ -0,0 +1,301 @@
|
||||
#include "keyboard.h"
|
||||
#include "io.h"
|
||||
#include "vga.h"
|
||||
|
||||
const char *scancode[128] = {
|
||||
/* 0 */ 0,
|
||||
/* 1 */ "\e", /* escape */
|
||||
/* 2 */ "&",
|
||||
/* 3 */ "é",
|
||||
/* 4 */ "\"",
|
||||
/* 5 */ "'",
|
||||
/* 6 */ "(",
|
||||
/* 7 */ "-",
|
||||
/* 8 */ "è",
|
||||
/* 9 */ "_",
|
||||
/* 10 */ "ç",
|
||||
/* 11 */ "à",
|
||||
/* 12 */ ")",
|
||||
/* 13 */ "=",
|
||||
/* 14 */ "\b", /* Backspace */
|
||||
/* 15 */ "\t", /* Tab */
|
||||
/* 16 */ "a",
|
||||
/* 17 */ "z",
|
||||
/* 18 */ "e",
|
||||
/* 19 */ "r",
|
||||
/* 20 */ "t",
|
||||
/* 21 */ "y",
|
||||
/* 22 */ "u",
|
||||
/* 23 */ "i",
|
||||
/* 24 */ "o",
|
||||
/* 25 */ "p",
|
||||
/* 26 */ "^",
|
||||
/* 27 */ "$",
|
||||
/* 28 */ "\n",
|
||||
/* 29 */ 0, /* left control */
|
||||
/* 30 */ "q",
|
||||
/* 31 */ "s",
|
||||
/* 32 */ "d",
|
||||
/* 33 */ "f",
|
||||
/* 34 */ "g",
|
||||
/* 35 */ "h",
|
||||
/* 36 */ "j",
|
||||
/* 37 */ "k",
|
||||
/* 38 */ "l",
|
||||
/* 39 */ "m",
|
||||
/* 40 */ "ù",
|
||||
/* 41 */ 0, /*²*/
|
||||
/* 42 */ 0, /* left shift */
|
||||
/* 43 */ "*",
|
||||
/* 44 */ "w",
|
||||
/* 45 */ "x",
|
||||
/* 46 */ "c",
|
||||
/* 47 */ "v",
|
||||
/* 48 */ "b",
|
||||
/* 49 */ "n",
|
||||
/* 50 */ ",",
|
||||
/* 51 */ ";",
|
||||
/* 52 */ ":",
|
||||
/* 53 */ "!",
|
||||
/* 54 */ 0, /* right shift*/
|
||||
/* 55 */ 0,
|
||||
/* 56 */ 0, /* left alt*/
|
||||
/* 57 */ " ",
|
||||
/* 58 */ 0,
|
||||
/* 59 */ "\eOP", /* F1 */
|
||||
/* 60 */ "\eOQ", /* F2 */
|
||||
/* 61 */ "\eOR", /* F3 */
|
||||
/* 62 */ "\eOS", /* F4 */
|
||||
/* 63 */ "\e[15~", /* F5 */
|
||||
/* 64 */ "\e[17~", /* F6 */
|
||||
/* 65 */ "\e[18~", /* F7 */
|
||||
/* 66 */ "\e[19~", /* F8 */
|
||||
/* 67 */ "\e[20~", /* F9 */
|
||||
/* 68 */ "\e[21~", /* F10 */
|
||||
/* 69 */ 0,
|
||||
/* 70 */ 0,
|
||||
/* 71 */ 0,
|
||||
/* 72 */ 0,
|
||||
/* 73 */ 0,
|
||||
/* 74 */ 0,
|
||||
/* 75 */ 0,
|
||||
/* 76 */ 0,
|
||||
/* 77 */ 0,
|
||||
/* 78 */ 0,
|
||||
/* 79 */ 0,
|
||||
/* 80 */ 0,
|
||||
/* 81 */ 0,
|
||||
/* 82 */ 0,
|
||||
/* 83 */ 0,
|
||||
/* 84 */ 0,
|
||||
/* 85 */ 0,
|
||||
/* 86 */ "<",
|
||||
/* 87 */ "\e[23~", /* F11 */
|
||||
/* 88 */ "\e[24~", /* F12 */
|
||||
/* 89 */ 0,
|
||||
/* 90 */ 0,
|
||||
/* 91 */ 0,
|
||||
/* 92 */ 0,
|
||||
/* 93 */ 0,
|
||||
/* 94 */ 0,
|
||||
/* 95 */ 0,
|
||||
/* 96 */ 0,
|
||||
/* 97 */ 0,
|
||||
/* 98 */ 0,
|
||||
/* 99 */ 0,
|
||||
/* 100 */ 0,
|
||||
/* 101 */ 0,
|
||||
/* 102 */ 0,
|
||||
/* 103 */ 0,
|
||||
/* 104 */ 0,
|
||||
/* 105 */ 0,
|
||||
/* 106 */ 0,
|
||||
/* 107 */ 0,
|
||||
/* 108 */ 0,
|
||||
/* 109 */ 0,
|
||||
/* 110 */ 0,
|
||||
/* 111 */ 0,
|
||||
/* 112 */ 0,
|
||||
/* 113 */ 0,
|
||||
/* 114 */ 0,
|
||||
/* 115 */ 0,
|
||||
/* 116 */ 0,
|
||||
/* 117 */ 0,
|
||||
/* 118 */ 0,
|
||||
/* 119 */ 0,
|
||||
/* 120 */ 0,
|
||||
/* 121 */ 0,
|
||||
/* 122 */ 0,
|
||||
/* 123 */ 0,
|
||||
/* 124 */ 0,
|
||||
/* 125 */ 0,
|
||||
/* 126 */ 0,
|
||||
/* 127 */ 0};
|
||||
|
||||
const char *scancode_shift[128] = {
|
||||
/* 0 */ 0,
|
||||
/* 1 */ "\e",
|
||||
/* 2 */ "1",
|
||||
/* 3 */ "2",
|
||||
/* 4 */ "3",
|
||||
/* 5 */ "4",
|
||||
/* 6 */ "5",
|
||||
/* 7 */ "6",
|
||||
/* 8 */ "7",
|
||||
/* 9 */ "8",
|
||||
/* 10 */ "9",
|
||||
/* 11 */ "0",
|
||||
/* 12 */ "°",
|
||||
/* 13 */ "+",
|
||||
/* 14 */ "\b", /* Shift-Backspace */
|
||||
/* 15 */ "\e[Z", /* Shift-Tab */
|
||||
/* 16 */ "A",
|
||||
/* 17 */ "Z",
|
||||
/* 18 */ "E",
|
||||
/* 19 */ "R",
|
||||
/* 20 */ "T",
|
||||
/* 21 */ "Y",
|
||||
/* 22 */ "U",
|
||||
/* 23 */ "I",
|
||||
/* 24 */ "O",
|
||||
/* 25 */ "P",
|
||||
/* 26 */ "\"",
|
||||
/* 27 */ "£",
|
||||
/* 28 */ "\n",
|
||||
/* 29 */ 0, /* left control */
|
||||
/* 30 */ "Q",
|
||||
/* 31 */ "S",
|
||||
/* 32 */ "D",
|
||||
/* 33 */ "F",
|
||||
/* 34 */ "G",
|
||||
/* 35 */ "H",
|
||||
/* 36 */ "J",
|
||||
/* 37 */ "K",
|
||||
/* 38 */ "L",
|
||||
/* 39 */ "M",
|
||||
/* 40 */ "%",
|
||||
/* 41 */ 0,
|
||||
/* 42 */ 0,
|
||||
/* 43 */ "µ",
|
||||
/* 44 */ "W",
|
||||
/* 45 */ "X",
|
||||
/* 46 */ "C",
|
||||
/* 47 */ "V",
|
||||
/* 48 */ "B",
|
||||
/* 49 */ "N",
|
||||
/* 50 */ "?",
|
||||
/* 51 */ ".",
|
||||
/* 52 */ "/",
|
||||
/* 53 */ "§",
|
||||
/* 54 */ 0,
|
||||
/* 55 */ 0,
|
||||
/* 56 */ 0,
|
||||
/* 57 */ 0,
|
||||
/* 58 */ 0,
|
||||
/* 59 */ "\eOP", /* Shift-F1 */
|
||||
/* 60 */ "\eOQ", /* Shift-F2 */
|
||||
/* 61 */ "\eOR", /* Shift-F3 */
|
||||
/* 62 */ "\eOS", /* Shift-F4 */
|
||||
/* 63 */ "\e[15;2~", /* Shift-F5 */
|
||||
/* 64 */ "\e[17;2~", /* Shift-F6 */
|
||||
/* 65 */ "\e[18;2~", /* Shift-F7 */
|
||||
/* 66 */ "\e[19;2~", /* Shift-F8 */
|
||||
/* 67 */ "\e[20:2~", /* Shift-F9 */
|
||||
/* 68 */ "\e[21:2~", /* Shift-F10 */
|
||||
/* 69 */ 0,
|
||||
/* 70 */ 0,
|
||||
/* 71 */ 0,
|
||||
/* 72 */ 0,
|
||||
/* 73 */ 0,
|
||||
/* 74 */ 0,
|
||||
/* 75 */ 0,
|
||||
/* 76 */ 0,
|
||||
/* 77 */ 0,
|
||||
/* 78 */ 0,
|
||||
/* 79 */ 0,
|
||||
/* 80 */ 0,
|
||||
/* 81 */ 0,
|
||||
/* 82 */ 0,
|
||||
/* 83 */ 0,
|
||||
/* 84 */ 0,
|
||||
/* 85 */ 0,
|
||||
/* 86 */ ">",
|
||||
/* 87 */ "\e[23;2~", /* Shift-F11 */
|
||||
/* 88 */ "\e[24;2~", /* Shift-F12 */
|
||||
/* 89 */ 0,
|
||||
/* 90 */ 0,
|
||||
/* 91 */ 0,
|
||||
/* 92 */ 0,
|
||||
/* 93 */ 0,
|
||||
/* 94 */ 0,
|
||||
/* 95 */ 0,
|
||||
/* 96 */ 0,
|
||||
/* 97 */ 0,
|
||||
/* 98 */ 0,
|
||||
/* 99 */ 0,
|
||||
/* 100 */ 0,
|
||||
/* 101 */ 0,
|
||||
/* 102 */ 0,
|
||||
/* 103 */ 0,
|
||||
/* 104 */ 0,
|
||||
/* 105 */ 0,
|
||||
/* 106 */ 0,
|
||||
/* 107 */ 0,
|
||||
/* 108 */ 0,
|
||||
/* 109 */ 0,
|
||||
/* 110 */ 0,
|
||||
/* 111 */ 0,
|
||||
/* 112 */ 0,
|
||||
/* 113 */ 0,
|
||||
/* 114 */ 0,
|
||||
/* 115 */ 0,
|
||||
/* 116 */ 0,
|
||||
/* 117 */ 0,
|
||||
/* 118 */ 0,
|
||||
/* 119 */ 0,
|
||||
/* 120 */ 0,
|
||||
/* 121 */ 0,
|
||||
/* 122 */ 0,
|
||||
/* 123 */ 0,
|
||||
/* 124 */ 0,
|
||||
/* 125 */ 0,
|
||||
/* 126 */ 0,
|
||||
/* 127 */ 0};
|
||||
|
||||
void keyboard_do_irq()
|
||||
{
|
||||
static int lshift = 0;
|
||||
static int rshift = 0;
|
||||
unsigned char c = 0;
|
||||
if (inb(0x60) != c) {
|
||||
c = inb(0x60);
|
||||
if (c > 0) {
|
||||
if (c < BREAK_CODE) {
|
||||
switch (c) {
|
||||
case 42:
|
||||
lshift = 1;
|
||||
break;
|
||||
case 54:
|
||||
rshift = 1;
|
||||
break;
|
||||
default:
|
||||
if (lshift || rshift)
|
||||
printString(scancode_shift[(int)c]);
|
||||
else
|
||||
printString(scancode[(int)c]);
|
||||
}
|
||||
}else {
|
||||
c = c - BREAK_CODE;
|
||||
switch (c) {
|
||||
case 42:
|
||||
lshift = 0;
|
||||
break;
|
||||
case 54:
|
||||
rshift = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
6
drivers/keyboard.h
Normal file
6
drivers/keyboard.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// Pushing generate MAKE_CODE (<0x80)
|
||||
// Releasing generate BREAK_CODE (break_code = make_code + 0x80)
|
||||
#define BREAK_CODE 0x80
|
||||
void keyboard_do_irq();
|
73
drivers/pic.c
Normal file
73
drivers/pic.c
Normal file
@ -0,0 +1,73 @@
|
||||
#include "pic.h"
|
||||
#include "io.h"
|
||||
#include "irq.h"
|
||||
|
||||
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
|
||||
#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 - required! */
|
||||
|
||||
#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) */
|
||||
|
||||
void initPic(void)
|
||||
{
|
||||
/* Send CMD: Init + sequence in 4 DATA */
|
||||
outb(PIC_MASTER_CMD, ICW1_INIT + ICW1_ICW4);
|
||||
outb(PIC_SLAVE_CMD, ICW1_INIT + ICW1_ICW4);
|
||||
|
||||
/* Send ICW2: ctrl base address. Remap IRQ from interupt range 0x0-0xF to 0x20-0x2F as
|
||||
* intel
|
||||
* reserve interupt 0x0-0x1F in protected mode (e.g. 0-7 are CPU exception) */
|
||||
outb(PIC_MASTER_DATA, IRQ_INTERRUPT_BASE_ADDRESS);
|
||||
outb(PIC_SLAVE_DATA, IRQ_INTERRUPT_BASE_ADDRESS + 8);
|
||||
|
||||
/* Send ICW3 master: mask where slaves are connected */
|
||||
outb(PIC_MASTER_DATA, 0x4);
|
||||
/* Send ICW3 slave: index where the slave is connected on master */
|
||||
outb(PIC_SLAVE_DATA, 0x2);
|
||||
|
||||
/* Send ICW4: 8086 mode, fully nested, not buffered, no implicit EOI */
|
||||
outb(PIC_MASTER_DATA, ICW4_8086);
|
||||
outb(PIC_SLAVE_DATA, ICW4_8086);
|
||||
|
||||
/* Send OCW1:
|
||||
* Closing all IRQs : waiting for a correct handler The only IRQ
|
||||
* enabled is the cascade (that's why we use 0xFB for the master) */
|
||||
outb(PIC_MASTER_DATA, 0xFB);
|
||||
outb(PIC_SLAVE_DATA, 0xFF);
|
||||
}
|
||||
|
||||
void EOIIrq(int irq)
|
||||
{
|
||||
if (irq >= 8)
|
||||
outb(PIC_SLAVE_CMD, PIC_EOI);
|
||||
|
||||
outb(PIC_MASTER_CMD, PIC_EOI);
|
||||
}
|
||||
|
||||
void disableIrq(int irq)
|
||||
{
|
||||
if (irq < 8) {
|
||||
uint8_t status = inb(PIC_MASTER_DATA);
|
||||
outb(PIC_MASTER_DATA, (status | (1 << irq)));
|
||||
} else {
|
||||
uint8_t status = inb(PIC_SLAVE_DATA);
|
||||
outb(PIC_SLAVE_DATA, (status | (1 << (irq - 8))));
|
||||
}
|
||||
}
|
||||
|
||||
void enableIrq(int irq)
|
||||
{
|
||||
if (irq < 8) {
|
||||
uint8_t status = inb(PIC_MASTER_DATA);
|
||||
outb(PIC_MASTER_DATA, (status & ~(1 << irq)));
|
||||
} else {
|
||||
uint8_t status = inb(PIC_SLAVE_DATA);
|
||||
outb(PIC_SLAVE_DATA, (status & ~(1 << (irq - 8))));
|
||||
}
|
||||
}
|
21
drivers/pic.h
Normal file
21
drivers/pic.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
// 2 PIC 8259 are available on x86
|
||||
//
|
||||
// Master - command: 0x20, data: 0x21
|
||||
// Slave - command: 0xA0, data: 0xA1
|
||||
//
|
||||
// http://www.jamesmolloy.co.uk/tutorial_html/5.-IRQs%20and%20the%20PIT.html
|
||||
// SimpleOS art2
|
||||
// http://wiki.osdev.org/PIC
|
||||
|
||||
#define PIC_MASTER_CMD 0x20
|
||||
#define PIC_SLAVE_CMD 0xa0
|
||||
#define PIC_MASTER_DATA 0x21
|
||||
#define PIC_SLAVE_DATA 0xa1
|
||||
#define PIC_EOI 0x20 /* End-of-interrupt command code */
|
||||
|
||||
|
||||
void EOIIrq(int irq);
|
||||
void initPic(void);
|
||||
void enableIrq(int irq);
|
||||
void disableIrq(int irq);
|
14
drivers/pit.c
Normal file
14
drivers/pit.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include "pit.h"
|
||||
#include "io.h"
|
||||
|
||||
int initPit(unsigned int freq)
|
||||
{
|
||||
unsigned int divisor = PIT_FREQ / freq;
|
||||
if (divisor > 65535)
|
||||
divisor = 0; // Used to represent 35536
|
||||
outb(PIT_CMD, 0x34); // chan 0; low then high; mode 2
|
||||
outb(PIT_CHAN_0, divisor & 0xFF);
|
||||
outb(PIT_CHAN_0, divisor >> 8u);
|
||||
|
||||
return 0;
|
||||
}
|
16
drivers/pit.h
Normal file
16
drivers/pit.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
// C.f https://wiki.osdev.org/PIT
|
||||
|
||||
#define PIT_FREQ 1193182
|
||||
#define PIT_CHAN_0 0x40 // IRQ0
|
||||
#define PIT_CHAN_1 0x41 // Used for DRAM refresh. Not used anymore
|
||||
#define PIT_CHAN_2 0x42 // PC Speaker
|
||||
#define PIT_CMD 0x43
|
||||
// Cmd are
|
||||
// 7-6: select channel. 0 ->chan0, 1 -> chan1, 2 -> chan 2, 3 -> read back
|
||||
// 5-4: access mode. 0 -> latch count; 1 -> low value only; 2 -> high value only;
|
||||
// 3 -> low then high 3-1: mode. See https://wiki.osdev.org/PIT
|
||||
|
||||
int initPit(unsigned int freq);
|
||||
|
142
drivers/vga.c
Normal file
142
drivers/vga.c
Normal file
@ -0,0 +1,142 @@
|
||||
#include "vga.h"
|
||||
#include "io.h"
|
||||
#include "klibc.h"
|
||||
|
||||
static uint vgaBgColor;
|
||||
static uint vgaColor;
|
||||
static int line, col;
|
||||
|
||||
int initVGA(uint bgColor, uint color)
|
||||
{
|
||||
vgaBgColor = bgColor;
|
||||
vgaColor = color;
|
||||
clearScreen(bgColor);
|
||||
line = 0;
|
||||
col = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clearScreen(uint bgColor)
|
||||
{
|
||||
volatile short *vga = (short *)VGA_ADDR;
|
||||
long int colorAttr = bgColor << 12;
|
||||
for (int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++) {
|
||||
vga[i] = colorAttr;
|
||||
}
|
||||
}
|
||||
|
||||
void printInt(int integer)
|
||||
{
|
||||
char num[sizeof(int) *
|
||||
3]; // int max is 2^(sizeof(int)*8) which is (2^3)^(sizeof(int)*8/3) =
|
||||
// 8^(sizeof(int)*8/3) ~ 10^(sizeof(int)*8/3)
|
||||
int i = 0, k = 0;
|
||||
if (integer < 0) {
|
||||
printChar('-');
|
||||
}
|
||||
while (integer != 0) {
|
||||
int digit = integer % 10;
|
||||
num[i++] = (digit > 0) ? digit : -digit;
|
||||
integer = integer / 10;
|
||||
}
|
||||
for (k = i - 1; k >= 0; k--) {
|
||||
printChar(num[k] + '0');
|
||||
}
|
||||
}
|
||||
|
||||
void printIntDetails(int integer, uint color, uint bgColor, int startX, int startY)
|
||||
{
|
||||
char num[sizeof(int) *
|
||||
3]; // int max is 2^(sizeof(int)*8) which is (2^3)^(sizeof(int)*8/3) =
|
||||
// 8^(sizeof(int)*8/3) ~ 10^(sizeof(int)*8/3)
|
||||
int x = startX;
|
||||
int i = 0, k = 0;
|
||||
if (integer < 0) {
|
||||
printCharDetails('-', color, bgColor, x++, startY);
|
||||
}
|
||||
while (integer != 0) {
|
||||
int digit = integer % 10;
|
||||
num[i++] = (digit > 0) ? digit : -digit;
|
||||
integer = integer / 10;
|
||||
}
|
||||
for (k = i - 1; k >= 0; k--) {
|
||||
printCharDetails(num[k] + '0', color, bgColor, x++, startY);
|
||||
}
|
||||
}
|
||||
|
||||
void printCharDetails(const char str, uint color, uint bgColor, int startX, int startY)
|
||||
{
|
||||
volatile short *vga = (short *)VGA_ADDR;
|
||||
long int colorAttr = (bgColor << 4 | (color & 0x0f)) << 8;
|
||||
vga[VGA_WIDTH * startY + startX] = colorAttr | str;
|
||||
}
|
||||
|
||||
void vgaScrollUp(void)
|
||||
{
|
||||
long int colorAttr = vgaBgColor << 12;
|
||||
volatile short *vga = (short *)VGA_ADDR;
|
||||
for (int i = 1; i < VGA_HEIGHT - 2;
|
||||
i++) { // last line is status line. Do not scroll it
|
||||
memcpy((void *)&vga[VGA_WIDTH * (i - 1)], (void *)&vga[VGA_WIDTH * i],
|
||||
VGA_WIDTH * sizeof(short));
|
||||
}
|
||||
for (int i = 0; i < VGA_WIDTH; i++) {
|
||||
vga[(VGA_HEIGHT - 2) * VGA_WIDTH + i] = colorAttr;
|
||||
}
|
||||
}
|
||||
|
||||
void printString(const char *str)
|
||||
{
|
||||
while (*str) {
|
||||
printChar(*(str++));
|
||||
}
|
||||
}
|
||||
|
||||
void printChar(const char str)
|
||||
{
|
||||
if (str == '\n') {
|
||||
line++;
|
||||
col = 0;
|
||||
if (line >= VGA_HEIGHT - 1) {
|
||||
vgaScrollUp();
|
||||
line--;
|
||||
}
|
||||
}
|
||||
else if(str == '\r')
|
||||
{
|
||||
col = 0;
|
||||
}
|
||||
else if(str == '\b')
|
||||
{
|
||||
col--;
|
||||
if (col < 0) {
|
||||
col = VGA_WIDTH - 1;
|
||||
line--;
|
||||
}
|
||||
printCharDetails(' ', vgaColor, vgaBgColor, col, line);
|
||||
}
|
||||
else
|
||||
{
|
||||
printCharDetails(str, vgaColor, vgaBgColor, col++, line);
|
||||
if (col == VGA_WIDTH) {
|
||||
col = 0;
|
||||
line++;
|
||||
}
|
||||
if (line >= VGA_HEIGHT - 1) {
|
||||
vgaScrollUp();
|
||||
line--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void printStringDetails(const char *str, uint color, uint bgColor, int startX, int startY)
|
||||
{
|
||||
volatile short *vga = (short *)VGA_ADDR;
|
||||
int i = 0;
|
||||
long int colorAttr = (bgColor << 4 | (color & 0x0f)) << 8;
|
||||
while (*str) {
|
||||
vga[VGA_WIDTH * startY + startX + i] = colorAttr | *str;
|
||||
str++;
|
||||
i++;
|
||||
}
|
||||
}
|
27
drivers/vga.h
Normal file
27
drivers/vga.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
// https://wiki.osdev.org/Text_UI
|
||||
#define BLACK 0x00
|
||||
#define BLUE 0x01
|
||||
#define GREEN 0x02
|
||||
#define CYAN 0x03
|
||||
#define RED 0x04
|
||||
#define MAGENTA 0x05
|
||||
#define BROWN 0x06
|
||||
#define GREY 0x07
|
||||
#define WHITE 0x0F
|
||||
|
||||
#define VGA_ADDR 0xB8000
|
||||
#define VGA_WIDTH 80
|
||||
#define VGA_HEIGHT 25
|
||||
|
||||
int initVGA(uint bgColor, uint color);
|
||||
void clearScreen(uint bgColor);
|
||||
void printInt(int integer);
|
||||
void printIntDetails(int integer, uint color, uint bgColor, int startX, int startY);
|
||||
void printCharDetails(char str, uint color, uint bgColor, int startX, int startY);
|
||||
void printStringDetails(const char *str, uint color, uint bgColor, int startX, int startY);
|
||||
void printString(const char *str);
|
||||
void printChar(const char str);
|
||||
void vgaScrollUp(void);
|
26
linker.ld
Normal file
26
linker.ld
Normal file
@ -0,0 +1,26 @@
|
||||
ENTRY(boot)
|
||||
OUTPUT_FORMAT("binary")
|
||||
SECTIONS {
|
||||
. = 0x7c00;
|
||||
.text :
|
||||
{
|
||||
*(.boot)
|
||||
*(.text)
|
||||
}
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
*(.bss)
|
||||
}
|
||||
}
|
||||
|
161
mbr.asm
Normal file
161
mbr.asm
Normal file
@ -0,0 +1,161 @@
|
||||
section .boot
|
||||
bits 16
|
||||
global boot
|
||||
boot:
|
||||
jmp main
|
||||
|
||||
display_enable:
|
||||
push bp
|
||||
mov bp, sp
|
||||
mov ah, 0h ; 00h Set Video Mode
|
||||
mov al, 07h ; Txt, monochrome, 80x25
|
||||
|
||||
int 10h
|
||||
|
||||
mov sp, bp
|
||||
pop bp
|
||||
ret
|
||||
|
||||
print:
|
||||
push bp
|
||||
mov bp, sp
|
||||
mov si, [bp + 4]; put first function arg in si. sp is stask pointer
|
||||
.loop:
|
||||
lodsb ; load si content into al then inc si
|
||||
cmp al, 0;
|
||||
je .end
|
||||
|
||||
mov ah, 0eh
|
||||
mov bx, 0
|
||||
int 10h
|
||||
|
||||
jmp .loop
|
||||
|
||||
.end:
|
||||
mov sp, bp
|
||||
pop bp
|
||||
ret
|
||||
|
||||
println:
|
||||
push bp
|
||||
mov bp, sp
|
||||
push word [bp + 4]
|
||||
call print
|
||||
add sp, 2
|
||||
|
||||
mov ah, 03h ; read cursor position
|
||||
int 10h ; row number in dh. Col in dl
|
||||
|
||||
inc dh ; goto next line
|
||||
mov dl, 0
|
||||
|
||||
mov ah, 02h ; Set Cursor Position
|
||||
int 10h
|
||||
mov sp, bp
|
||||
pop bp
|
||||
ret
|
||||
|
||||
hello db 'Booting matOs', 0
|
||||
|
||||
main:
|
||||
sti ; enable virtual interupts
|
||||
mov [disk],dl ; save disk used to boot by bios
|
||||
|
||||
call display_enable
|
||||
|
||||
push hello
|
||||
call println
|
||||
add sp, 2
|
||||
|
||||
; Switch in 32bits Protected mode
|
||||
|
||||
; Activate A20 http://wiki.osdev.org/A20_Line to be able to access more than 1Mb memory
|
||||
mov ah, 0h
|
||||
mov ax, 0x2401
|
||||
int 0x15
|
||||
|
||||
; Change video mode to display VGA
|
||||
mov ax, 0x3
|
||||
int 0x10
|
||||
|
||||
; http://www.ctyme.com/intr/rb-0607.htm
|
||||
; Bios read first 512 bytes, read next disk sector
|
||||
mov ah, 0x2 ;read sectors
|
||||
mov al, 15 ;sectors to read
|
||||
mov ch, 0 ;cylinder idx
|
||||
mov dh, 0 ;head idx
|
||||
mov cl, 2 ;sector idx
|
||||
mov dl, [disk] ;disk idx
|
||||
mov bx, copy_target;target pointer
|
||||
int 0x13
|
||||
|
||||
cli ; disable interruption when setting GDT
|
||||
|
||||
; switch in 32 bits
|
||||
lgdt [gdt_pointer] ; switch in 32bits here
|
||||
mov eax, cr0
|
||||
or eax,0x1; set the protected mode bit on special CPU reg cr0
|
||||
mov cr0, eax
|
||||
jmp CODE_SEG:boot2 ; In protected mode we need to add the segment selector
|
||||
|
||||
; GDT table desciption could be found http://wiki.osdev.org/Global_Descriptor_Table
|
||||
; here we define the 3 64bits segment needed: null segment, code segment and data segment
|
||||
gdt_start: ;null segment
|
||||
dq 0x0
|
||||
gdt_code: ;code segment
|
||||
dw 0xFFFF ; limit [0:15]
|
||||
dw 0x0 ; base [0:15]
|
||||
db 0x0 ; base [16:23]
|
||||
db 10011010b ; access byte: Present(1)| Priv(2) 0 ->kernel 3->userspace | 1 | Executable(1) | Direction/Conformity (1) | RW(1) | Accessed(1)
|
||||
db 11001111b ; Granularity(1) | Size (1) 0-> 16bit mode 1->32protected mode | 0 | 0 | Limit [16:19]
|
||||
db 0x0 ; base [24:31]
|
||||
gdt_data:
|
||||
dw 0xFFFF
|
||||
dw 0x0
|
||||
db 0x0
|
||||
db 10010010b
|
||||
db 11001111b
|
||||
db 0x0
|
||||
gdt_end:
|
||||
gdt_pointer:
|
||||
dw gdt_end - gdt_start
|
||||
dd gdt_start
|
||||
disk:
|
||||
db 0x0
|
||||
CODE_SEG equ gdt_code - gdt_start
|
||||
DATA_SEG equ gdt_data - gdt_start
|
||||
|
||||
times 510 - ($-$$) db 0
|
||||
dw 0xaa55
|
||||
copy_target:
|
||||
bits 32
|
||||
boot2:
|
||||
mov ax, DATA_SEG ; set all segments to point to DATA_SEG https://en.wikipedia.org/wiki/X86_memory_segmentation
|
||||
mov ds, ax ; Data segment
|
||||
mov es, ax ; Extra Segment (for string operation)
|
||||
mov fs, ax ; No Specific use
|
||||
mov gs, ax ; No Specific use
|
||||
mov ss, ax ; stack segment
|
||||
mov esi,hello32
|
||||
mov ebx,0xb8000 ; Cannot use BIOS anymore, use VGA Text buffer instead
|
||||
|
||||
.loop32:
|
||||
lodsb
|
||||
or al,al
|
||||
jz halt
|
||||
or eax,0x0100 ; blue bg
|
||||
mov word [ebx], ax
|
||||
add ebx,2
|
||||
jmp .loop32
|
||||
halt:
|
||||
mov esp,kernel_stack_top
|
||||
extern kmain
|
||||
call kmain
|
||||
cli
|
||||
hlt
|
||||
hello32: db "Hello 32 bits world!",0
|
||||
section .bss
|
||||
align 4
|
||||
kernel_stack_bottom: equ $
|
||||
resb 16384 ; 16 KB
|
||||
kernel_stack_top:
|
Loading…
Reference in New Issue
Block a user