Merge branch 'main' of https://github.com/hse-cs-ami/yabloko-public
This commit is contained in:
commit
fd270fc1a0
3
Makefile
3
Makefile
@ -82,7 +82,8 @@ user/%: user/%.o user/crt.o
|
|||||||
image.bin: mbr.bin fs.img
|
image.bin: mbr.bin fs.img
|
||||||
cat $^ >$@
|
cat $^ >$@
|
||||||
|
|
||||||
kernel.bin: kernel.o console.o drivers/vga.o drivers/uart.o
|
kernel.bin: kernel.o console.o drivers/vga.o drivers/uart.o drivers/keyboard.o \
|
||||||
|
cpu/idt.o cpu/vectors.o lib/mem.o
|
||||||
$(LD) $(LDFLAGS) $(LDKERNELFLAGS) -o $@ -Ttext 0x1000 $^
|
$(LD) $(LDFLAGS) $(LDKERNELFLAGS) -o $@ -Ttext 0x1000 $^
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
|
|||||||
152
cpu/idt.c
Normal file
152
cpu/idt.c
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
#include "isr.h"
|
||||||
|
#include "gdt.h"
|
||||||
|
#include "../drivers/port.h"
|
||||||
|
#include "../console.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IDT_HANDLERS = 256,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t low_offset;
|
||||||
|
uint16_t selector;
|
||||||
|
uint8_t always0;
|
||||||
|
uint8_t type: 4;
|
||||||
|
uint8_t s: 1;
|
||||||
|
uint8_t dpl: 2;
|
||||||
|
uint8_t p: 1;
|
||||||
|
uint16_t high_offset;
|
||||||
|
} __attribute__((packed)) idt_gate_t;
|
||||||
|
|
||||||
|
idt_gate_t idt[IDT_HANDLERS];
|
||||||
|
|
||||||
|
#define low_16(address) (uint16_t)((address) & 0xFFFF)
|
||||||
|
#define high_16(address) (uint16_t)(((address) >> 16) & 0xFFFF)
|
||||||
|
|
||||||
|
#define STS_IG32 0xE // 32-bit Interrupt Gate
|
||||||
|
#define STS_TG32 0xF // 32-bit Trap Gate
|
||||||
|
|
||||||
|
void set_idt_gate(int n, _Bool istrap, uint32_t handler, uint8_t dpl) {
|
||||||
|
idt[n].low_offset = low_16(handler);
|
||||||
|
idt[n].selector = 0x08; // see GDT
|
||||||
|
idt[n].always0 = 0;
|
||||||
|
idt[n].type = istrap ? STS_TG32 : STS_IG32;
|
||||||
|
idt[n].s = 0;
|
||||||
|
idt[n].dpl = dpl;
|
||||||
|
idt[n].p = 1;
|
||||||
|
idt[n].high_offset = high_16(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// defined in vectors.S
|
||||||
|
extern const uint32_t default_handlers[];
|
||||||
|
|
||||||
|
void init_idt() {
|
||||||
|
if (default_handlers[0] == 0) {
|
||||||
|
panic("handler table empty\n");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < IDT_HANDLERS; i++) {
|
||||||
|
set_idt_gate(i, 0, default_handlers[i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * const exception_messages[] = {
|
||||||
|
[0] = "Division By Zero",
|
||||||
|
[1] = "Debug",
|
||||||
|
[2] = "Non Maskable Interrupt",
|
||||||
|
[3] = "Breakpoint",
|
||||||
|
[4] = "Into Detected Overflow",
|
||||||
|
[5] = "Out of Bounds",
|
||||||
|
[6] = "Invalid Opcode",
|
||||||
|
[7] = "No Coprocessor",
|
||||||
|
|
||||||
|
[8] = "Double Fault",
|
||||||
|
[9] = "Coprocessor Segment Overrun",
|
||||||
|
[10] = "Bad TSS",
|
||||||
|
[11] = "Segment Not Present",
|
||||||
|
[12] = "Stack Fault",
|
||||||
|
[13] = "General Protection Fault",
|
||||||
|
[14] = "Page Fault",
|
||||||
|
[15] = "Unknown Interrupt",
|
||||||
|
|
||||||
|
[16] = "Coprocessor Fault",
|
||||||
|
[17] = "Alignment Check",
|
||||||
|
[18] = "Machine Check",
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ARRLEN(a) (sizeof(a) / sizeof(a[0]))
|
||||||
|
|
||||||
|
static isr_t interrupt_handlers[IDT_HANDLERS];
|
||||||
|
|
||||||
|
void register_interrupt_handler(uint8_t i, isr_t handler) {
|
||||||
|
interrupt_handlers[i] = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trap(registers_t *r) {
|
||||||
|
if (r->int_no < 32) {
|
||||||
|
const char* msg = "Reserved";
|
||||||
|
if (r->int_no < ARRLEN(exception_messages)) {
|
||||||
|
msg = exception_messages[r->int_no];
|
||||||
|
}
|
||||||
|
panic(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interrupt_handlers[r->int_no] != 0) {
|
||||||
|
isr_t handler = interrupt_handlers[r->int_no];
|
||||||
|
handler(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// EOI
|
||||||
|
if (r->int_no >= 40) {
|
||||||
|
port_byte_out(0xA0, 0x20); /* follower */
|
||||||
|
}
|
||||||
|
if (r->int_no >= 32) {
|
||||||
|
port_byte_out(0x20, 0x20); /* leader */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_pic() {
|
||||||
|
// ICW1
|
||||||
|
port_byte_out(0x20, 0x11);
|
||||||
|
port_byte_out(0xA0, 0x11);
|
||||||
|
|
||||||
|
// ICW2
|
||||||
|
port_byte_out(0x21, 0x20);
|
||||||
|
port_byte_out(0xA1, 0x28);
|
||||||
|
|
||||||
|
// ICW3
|
||||||
|
port_byte_out(0x21, 0x04);
|
||||||
|
port_byte_out(0xA1, 0x02);
|
||||||
|
|
||||||
|
// ICW4
|
||||||
|
port_byte_out(0x21, 0x01);
|
||||||
|
port_byte_out(0xA1, 0x01);
|
||||||
|
|
||||||
|
// OCW1
|
||||||
|
port_byte_out(0x21, 0x0);
|
||||||
|
port_byte_out(0xA1, 0x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t limit;
|
||||||
|
void* base;
|
||||||
|
} __attribute__((packed)) idt_register_t;
|
||||||
|
|
||||||
|
static idt_register_t idt_reg;
|
||||||
|
|
||||||
|
void load_idt() {
|
||||||
|
init_idt();
|
||||||
|
|
||||||
|
idt_reg.base = &idt;
|
||||||
|
idt_reg.limit = sizeof(idt) - 1;
|
||||||
|
asm("lidt (%0)" : : "r"(&idt_reg));
|
||||||
|
|
||||||
|
init_pic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli() {
|
||||||
|
asm("cli");
|
||||||
|
}
|
||||||
|
|
||||||
|
void sti() {
|
||||||
|
asm("sti");
|
||||||
|
}
|
||||||
49
cpu/isr.h
Normal file
49
cpu/isr.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IRQ0 = 32,
|
||||||
|
IRQ1,
|
||||||
|
IRQ2,
|
||||||
|
IRQ3,
|
||||||
|
IRQ4,
|
||||||
|
IRQ5,
|
||||||
|
IRQ6,
|
||||||
|
IRQ7,
|
||||||
|
IRQ8,
|
||||||
|
IRQ9,
|
||||||
|
IRQ10,
|
||||||
|
IRQ11,
|
||||||
|
IRQ12,
|
||||||
|
IRQ13,
|
||||||
|
IRQ14,
|
||||||
|
IRQ15,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Struct which aggregates many registers.
|
||||||
|
* It matches exactly the pushes on vectors.S. From the bottom:
|
||||||
|
* - pushed by the processor automatically
|
||||||
|
* - `push byte`s on the isr-specific code: error code, then int number
|
||||||
|
* - segment registers
|
||||||
|
* - all the registers by pusha
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
|
||||||
|
uint32_t gs, fs, es, ds;
|
||||||
|
uint32_t int_no, err_code; // Interrupt number and error code (if applicable)
|
||||||
|
uint32_t eip, cs, eflags; // Pushed by the processor automatically
|
||||||
|
|
||||||
|
uint32_t useresp, ss; // Pushed by the processor for userspace interrupts
|
||||||
|
} registers_t;
|
||||||
|
|
||||||
|
void isr_install();
|
||||||
|
|
||||||
|
void isr_handler(registers_t *r);
|
||||||
|
|
||||||
|
typedef void (*isr_t)(registers_t *);
|
||||||
|
|
||||||
|
void register_interrupt_handler(uint8_t n, isr_t handler);
|
||||||
|
|
||||||
|
void load_idt();
|
||||||
|
void cli();
|
||||||
|
void sti();
|
||||||
55
cpu/vectors.S
Normal file
55
cpu/vectors.S
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
.global trapret
|
||||||
|
|
||||||
|
alltraps:
|
||||||
|
# Build trap frame.
|
||||||
|
pushl %ds
|
||||||
|
pushl %es
|
||||||
|
pushl %fs
|
||||||
|
pushl %gs
|
||||||
|
pushal
|
||||||
|
|
||||||
|
mov $0x10, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
|
||||||
|
# Call trap(tf), where tf=%esp
|
||||||
|
pushl %esp
|
||||||
|
call trap
|
||||||
|
add $4, %esp
|
||||||
|
// execution falls through to trapret
|
||||||
|
|
||||||
|
trapret:
|
||||||
|
popal
|
||||||
|
popl %gs
|
||||||
|
popl %fs
|
||||||
|
popl %es
|
||||||
|
popl %ds
|
||||||
|
addl $0x8, %esp # trapno and errcode
|
||||||
|
iret
|
||||||
|
|
||||||
|
.macro handler i
|
||||||
|
vector\i :
|
||||||
|
.if (!(\i == 8 || (\i >= 10 && \i <= 14) || \i == 17))
|
||||||
|
pushl $0
|
||||||
|
.endif
|
||||||
|
pushl $\i
|
||||||
|
jmp alltraps
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.altmacro
|
||||||
|
|
||||||
|
.macro irq_insertX number
|
||||||
|
.section .text
|
||||||
|
handler \number
|
||||||
|
|
||||||
|
.section .rodata
|
||||||
|
.long vector\number
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.section .rodata
|
||||||
|
.global default_handlers
|
||||||
|
default_handlers:
|
||||||
|
.set i,0
|
||||||
|
.rept 256
|
||||||
|
irq_insertX %i
|
||||||
|
.set i, i+1
|
||||||
|
.endr
|
||||||
80
drivers/ata.c
Normal file
80
drivers/ata.c
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// stolen from https://github.com/dhavalhirdhav/LearnOS/blob/master/drivers/ata/ata.c
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "ata.h"
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
BSY: a 1 means that the controller is busy executing a command. No register should be accessed (except the digital output register) while this bit is set.
|
||||||
|
RDY: a 1 means that the controller is ready to accept a command, and the drive is spinning at correct speed..
|
||||||
|
WFT: a 1 means that the controller detected a write fault.
|
||||||
|
SKC: a 1 means that the read/write head is in position (seek completed).
|
||||||
|
DRQ: a 1 means that the controller is expecting data (for a write) or is sending data (for a read). Don't access the data register while this bit is 0.
|
||||||
|
COR: a 1 indicates that the controller had to correct data, by using the ECC bytes (error correction code: extra bytes at the end of the sector that allows to verify its integrity and, sometimes, to correct errors).
|
||||||
|
IDX: a 1 indicates the the controller retected the index mark (which is not a hole on hard-drives).
|
||||||
|
ERR: a 1 indicates that an error occured. An error code has been placed in the error register.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STATUS_BSY 0x80
|
||||||
|
#define STATUS_RDY 0x40
|
||||||
|
#define STATUS_DRQ 0x08
|
||||||
|
#define STATUS_DF 0x20
|
||||||
|
#define STATUS_ERR 0x01
|
||||||
|
|
||||||
|
//This is really specific to our OS now, assuming ATA bus 0 master
|
||||||
|
//Source - OsDev wiki
|
||||||
|
static void ATA_wait_BSY();
|
||||||
|
static void ATA_wait_DRQ();
|
||||||
|
void read_sectors_ATA_PIO(uint32_t target_address, uint32_t LBA, uint8_t sector_count)
|
||||||
|
{
|
||||||
|
|
||||||
|
ATA_wait_BSY();
|
||||||
|
port_byte_out(0x1F6, 0xE0 | ((LBA >>24) & 0xF));
|
||||||
|
port_byte_out(0x1F2, sector_count);
|
||||||
|
port_byte_out(0x1F3, (uint8_t) LBA);
|
||||||
|
port_byte_out(0x1F4, (uint8_t)(LBA >> 8));
|
||||||
|
port_byte_out(0x1F5, (uint8_t)(LBA >> 16));
|
||||||
|
port_byte_out(0x1F7, 0x20); //Send the read command
|
||||||
|
|
||||||
|
uint16_t *target = (uint16_t*) target_address;
|
||||||
|
|
||||||
|
for (int j = 0; j < sector_count; j++)
|
||||||
|
{
|
||||||
|
ATA_wait_BSY();
|
||||||
|
ATA_wait_DRQ();
|
||||||
|
for(int i = 0; i < 256; i++)
|
||||||
|
target[i] = port_word_in(0x1F0);
|
||||||
|
target += 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_sectors_ATA_PIO(uint32_t LBA, uint8_t sector_count, uint32_t* bytes)
|
||||||
|
{
|
||||||
|
ATA_wait_BSY();
|
||||||
|
port_byte_out(0x1F6,0xE0 | ((LBA >>24) & 0xF));
|
||||||
|
port_byte_out(0x1F2,sector_count);
|
||||||
|
port_byte_out(0x1F3, (uint8_t) LBA);
|
||||||
|
port_byte_out(0x1F4, (uint8_t)(LBA >> 8));
|
||||||
|
port_byte_out(0x1F5, (uint8_t)(LBA >> 16));
|
||||||
|
port_byte_out(0x1F7,0x30); //Send the write command
|
||||||
|
|
||||||
|
for (int j =0;j<sector_count;j++)
|
||||||
|
{
|
||||||
|
ATA_wait_BSY();
|
||||||
|
ATA_wait_DRQ();
|
||||||
|
for(int i=0;i<256;i++)
|
||||||
|
{
|
||||||
|
port_long_out(0x1F0, bytes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ATA_wait_BSY() //Wait for bsy to be 0
|
||||||
|
{
|
||||||
|
while (port_byte_in(0x1F7) & STATUS_BSY);
|
||||||
|
}
|
||||||
|
static void ATA_wait_DRQ() //Wait fot drq to be 1
|
||||||
|
{
|
||||||
|
while(!(port_byte_in(0x1F7) & STATUS_RDY));
|
||||||
|
}
|
||||||
5
drivers/ata.h
Normal file
5
drivers/ata.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void read_sectors_ATA_PIO(uint32_t target_address, uint32_t LBA, uint8_t sector_count);
|
||||||
|
void write_sectors_ATA_PIO(uint32_t LBA, uint8_t sector_count, uint32_t* bytes);
|
||||||
36
drivers/keyboard.c
Normal file
36
drivers/keyboard.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include "keyboard.h"
|
||||||
|
#include "../cpu/isr.h"
|
||||||
|
#include "../console.h"
|
||||||
|
#include "port.h"
|
||||||
|
#include "../lib/mem.h"
|
||||||
|
|
||||||
|
static const char sc_ascii[] = {
|
||||||
|
'?', '?', '1', '2', '3', '4', '5', '6',
|
||||||
|
'7', '8', '9', '0', '-', '=', '?', '?', 'q', 'w', 'e', 'r', 't', 'y',
|
||||||
|
'u', 'i', 'o', 'p', '[', ']', '\n', '?', 'a', 's', 'd', 'f', 'g',
|
||||||
|
'h', 'j', 'k', 'l', ';', '\'', '`', '?', '\\', 'z', 'x', 'c', 'v',
|
||||||
|
'b', 'n', 'm', ',', '.', '/', '?', '?', '?', ' ',
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { kbd_buf_capacity = 1024 };
|
||||||
|
|
||||||
|
static void interrupt_handler(registers_t *r) {
|
||||||
|
uint8_t scancode = port_byte_in(0x60);
|
||||||
|
if (scancode < sizeof(sc_ascii)) {
|
||||||
|
char c = sc_ascii[scancode];
|
||||||
|
if (kbd_buf_size < kbd_buf_capacity) {
|
||||||
|
kbd_buf[kbd_buf_size++] = c;
|
||||||
|
}
|
||||||
|
char string[] = {c, '\0'};
|
||||||
|
printk(string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* kbd_buf;
|
||||||
|
unsigned kbd_buf_size;
|
||||||
|
|
||||||
|
void init_keyboard() {
|
||||||
|
kbd_buf = kmalloc(kbd_buf_capacity);
|
||||||
|
|
||||||
|
register_interrupt_handler(IRQ1, interrupt_handler);
|
||||||
|
}
|
||||||
6
drivers/keyboard.h
Normal file
6
drivers/keyboard.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void init_keyboard();
|
||||||
|
|
||||||
|
extern unsigned kbd_buf_size;
|
||||||
|
extern char *kbd_buf;
|
||||||
9
kernel.c
9
kernel.c
@ -1,12 +1,19 @@
|
|||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "drivers/vga.h"
|
#include "drivers/vga.h"
|
||||||
#include "drivers/uart.h"
|
#include "drivers/uart.h"
|
||||||
|
#include "drivers/keyboard.h"
|
||||||
|
#include "cpu/isr.h"
|
||||||
|
|
||||||
|
|
||||||
void _start() {
|
void _start() {
|
||||||
uartinit();
|
uartinit();
|
||||||
|
init_keyboard();
|
||||||
|
load_idt();
|
||||||
|
sti();
|
||||||
|
|
||||||
vga_clear_screen();
|
vga_clear_screen();
|
||||||
printk("\nYABLOKO\n");
|
printk("\nYABLOKO\n> ");
|
||||||
|
while (1) {
|
||||||
asm("hlt");
|
asm("hlt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
lib/mem.c
Normal file
12
lib/mem.c
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#include "mem.h"
|
||||||
|
|
||||||
|
static void* freeptr;
|
||||||
|
|
||||||
|
void* kmalloc(size_t size) {
|
||||||
|
if (!freeptr) {
|
||||||
|
freeptr = (void*)(1<<20);
|
||||||
|
}
|
||||||
|
void* result = freeptr;
|
||||||
|
freeptr += size;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user