lesson 23, step 3

pull/6/head
Carlos 9 years ago
parent 92ff191c3d
commit de3d442569

@ -16,13 +16,9 @@ We add `-ffreestanding` when compiling `.o` files, which includes `kernel_entry
Before, we disabled libgcc (not libc) through the use of `-nostdlib` and we didn't re-enable
it for linking. Since this is tricky, we'll delete `-nostdlib`
`-nostdinc` was also pased to gcc, but we will need it for step 3.
2. Not setting a stack
----------------------
3. kernel.c `main()` function
2. kernel.c `main()` function
-----------------------------
Modify `kernel/kernel.c` and change `main()` to `kernel_main()` since gcc recognizes "main" as
@ -33,8 +29,16 @@ Change `boot/kernel_entry.asm` to point to the new name accordingly.
To fix the `i386-elf-ld: warning: cannot find entry symbol _start; defaulting to 0000000000001000`
warning message, add a `global _start;` and define the `_start:` label in `boot/kernel_entry.asm`.
4. Reinvented datatypes
3. Reinvented datatypes
-----------------------
It looks like it was a bad idea to define non-standard data types like `u32` and such, since
C99 introduces standard fixed-width data types like `uint32_t`
We need to include `<stdint.h>` which works even in `-ffreestanding` (but requires stdlibs)
and use those data types instead of our own, then delete them on `type.h`
<stddef.h> to provide size\_t

@ -1,6 +1,7 @@
#include "idt.h"
#include "type.h"
void set_idt_gate(int n, u32 handler) {
void set_idt_gate(int n, uint32_t handler) {
idt[n].low_offset = low_16(handler);
idt[n].sel = KERNEL_CS;
idt[n].always0 = 0;
@ -9,7 +10,7 @@ void set_idt_gate(int n, u32 handler) {
}
void set_idt() {
idt_reg.base = (u32) &idt;
idt_reg.base = (uint32_t) &idt;
idt_reg.limit = IDT_ENTRIES * sizeof(idt_gate_t) - 1;
/* Don't make the mistake of loading &idt -- always load &idt_reg */
__asm__ __volatile__("lidtl (%0)" : : "r" (&idt_reg));

@ -1,30 +1,30 @@
#ifndef IDT_H
#define IDT_H
#include "type.h"
#include <stdint.h>
/* Segment selectors */
#define KERNEL_CS 0x08
/* How every interrupt gate (handler) is defined */
typedef struct {
u16 low_offset; /* Lower 16 bits of handler function address */
u16 sel; /* Kernel segment selector */
u8 always0;
uint16_t low_offset; /* Lower 16 bits of handler function address */
uint16_t sel; /* Kernel segment selector */
uint8_t always0;
/* First byte
* Bit 7: "Interrupt is present"
* Bits 6-5: Privilege level of caller (0=kernel..3=user)
* Bit 4: Set to 0 for interrupt gates
* Bits 3-0: bits 1110 = decimal 14 = "32 bit interrupt gate" */
u8 flags;
u16 high_offset; /* Higher 16 bits of handler function address */
uint8_t flags;
uint16_t high_offset; /* Higher 16 bits of handler function address */
} __attribute__((packed)) idt_gate_t ;
/* A pointer to the array of interrupt handlers.
* Assembly instruction 'lidt' will read it */
typedef struct {
u16 limit;
u32 base;
uint16_t limit;
uint32_t base;
} __attribute__((packed)) idt_register_t;
#define IDT_ENTRIES 256
@ -33,7 +33,7 @@ idt_register_t idt_reg;
/* Functions implemented in idt.c */
void set_idt_gate(int n, u32 handler);
void set_idt_gate(int n, uint32_t handler);
void set_idt();
#endif

@ -11,38 +11,38 @@ isr_t interrupt_handlers[256];
/* Can't do this with a loop because we need the address
* of the function names */
void isr_install() {
set_idt_gate(0, (u32)isr0);
set_idt_gate(1, (u32)isr1);
set_idt_gate(2, (u32)isr2);
set_idt_gate(3, (u32)isr3);
set_idt_gate(4, (u32)isr4);
set_idt_gate(5, (u32)isr5);
set_idt_gate(6, (u32)isr6);
set_idt_gate(7, (u32)isr7);
set_idt_gate(8, (u32)isr8);
set_idt_gate(9, (u32)isr9);
set_idt_gate(10, (u32)isr10);
set_idt_gate(11, (u32)isr11);
set_idt_gate(12, (u32)isr12);
set_idt_gate(13, (u32)isr13);
set_idt_gate(14, (u32)isr14);
set_idt_gate(15, (u32)isr15);
set_idt_gate(16, (u32)isr16);
set_idt_gate(17, (u32)isr17);
set_idt_gate(18, (u32)isr18);
set_idt_gate(19, (u32)isr19);
set_idt_gate(20, (u32)isr20);
set_idt_gate(21, (u32)isr21);
set_idt_gate(22, (u32)isr22);
set_idt_gate(23, (u32)isr23);
set_idt_gate(24, (u32)isr24);
set_idt_gate(25, (u32)isr25);
set_idt_gate(26, (u32)isr26);
set_idt_gate(27, (u32)isr27);
set_idt_gate(28, (u32)isr28);
set_idt_gate(29, (u32)isr29);
set_idt_gate(30, (u32)isr30);
set_idt_gate(31, (u32)isr31);
set_idt_gate(0, (uint32_t)isr0);
set_idt_gate(1, (uint32_t)isr1);
set_idt_gate(2, (uint32_t)isr2);
set_idt_gate(3, (uint32_t)isr3);
set_idt_gate(4, (uint32_t)isr4);
set_idt_gate(5, (uint32_t)isr5);
set_idt_gate(6, (uint32_t)isr6);
set_idt_gate(7, (uint32_t)isr7);
set_idt_gate(8, (uint32_t)isr8);
set_idt_gate(9, (uint32_t)isr9);
set_idt_gate(10, (uint32_t)isr10);
set_idt_gate(11, (uint32_t)isr11);
set_idt_gate(12, (uint32_t)isr12);
set_idt_gate(13, (uint32_t)isr13);
set_idt_gate(14, (uint32_t)isr14);
set_idt_gate(15, (uint32_t)isr15);
set_idt_gate(16, (uint32_t)isr16);
set_idt_gate(17, (uint32_t)isr17);
set_idt_gate(18, (uint32_t)isr18);
set_idt_gate(19, (uint32_t)isr19);
set_idt_gate(20, (uint32_t)isr20);
set_idt_gate(21, (uint32_t)isr21);
set_idt_gate(22, (uint32_t)isr22);
set_idt_gate(23, (uint32_t)isr23);
set_idt_gate(24, (uint32_t)isr24);
set_idt_gate(25, (uint32_t)isr25);
set_idt_gate(26, (uint32_t)isr26);
set_idt_gate(27, (uint32_t)isr27);
set_idt_gate(28, (uint32_t)isr28);
set_idt_gate(29, (uint32_t)isr29);
set_idt_gate(30, (uint32_t)isr30);
set_idt_gate(31, (uint32_t)isr31);
// Remap the PIC
port_byte_out(0x20, 0x11);
@ -57,22 +57,22 @@ void isr_install() {
port_byte_out(0xA1, 0x0);
// Install the IRQs
set_idt_gate(32, (u32)irq0);
set_idt_gate(33, (u32)irq1);
set_idt_gate(34, (u32)irq2);
set_idt_gate(35, (u32)irq3);
set_idt_gate(36, (u32)irq4);
set_idt_gate(37, (u32)irq5);
set_idt_gate(38, (u32)irq6);
set_idt_gate(39, (u32)irq7);
set_idt_gate(40, (u32)irq8);
set_idt_gate(41, (u32)irq9);
set_idt_gate(42, (u32)irq10);
set_idt_gate(43, (u32)irq11);
set_idt_gate(44, (u32)irq12);
set_idt_gate(45, (u32)irq13);
set_idt_gate(46, (u32)irq14);
set_idt_gate(47, (u32)irq15);
set_idt_gate(32, (uint32_t)irq0);
set_idt_gate(33, (uint32_t)irq1);
set_idt_gate(34, (uint32_t)irq2);
set_idt_gate(35, (uint32_t)irq3);
set_idt_gate(36, (uint32_t)irq4);
set_idt_gate(37, (uint32_t)irq5);
set_idt_gate(38, (uint32_t)irq6);
set_idt_gate(39, (uint32_t)irq7);
set_idt_gate(40, (uint32_t)irq8);
set_idt_gate(41, (uint32_t)irq9);
set_idt_gate(42, (uint32_t)irq10);
set_idt_gate(43, (uint32_t)irq11);
set_idt_gate(44, (uint32_t)irq12);
set_idt_gate(45, (uint32_t)irq13);
set_idt_gate(46, (uint32_t)irq14);
set_idt_gate(47, (uint32_t)irq15);
set_idt(); // Load with ASM
}
@ -126,7 +126,7 @@ void isr_handler(registers_t r) {
kprint("\n");
}
void register_interrupt_handler(u8 n, isr_t handler) {
void register_interrupt_handler(uint8_t n, isr_t handler) {
interrupt_handlers[n] = handler;
}

@ -1,7 +1,7 @@
#ifndef ISR_H
#define ISR_H
#include "type.h"
#include <stdint.h>
/* ISRs reserved for CPU exceptions */
extern void isr0();
@ -73,10 +73,10 @@ extern void irq15();
/* Struct which aggregates many registers */
typedef struct {
u32 ds; /* Data segment selector */
u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
u32 int_no, err_code; /* Interrupt number and error code (if applicable) */
u32 eip, cs, eflags, useresp, ss; /* Pushed by the processor automatically */
uint32_t ds; /* Data segment selector */
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
uint32_t int_no, err_code; /* Interrupt number and error code (if applicable) */
uint32_t eip, cs, eflags, useresp, ss; /* Pushed by the processor automatically */
} registers_t;
void isr_install();
@ -84,6 +84,6 @@ void isr_handler(registers_t r);
void irq_install();
typedef void (*isr_t)(registers_t);
void register_interrupt_handler(u8 n, isr_t handler);
void register_interrupt_handler(uint8_t n, isr_t handler);
#endif

@ -3,8 +3,8 @@
/**
* Read a byte from the specified port
*/
u8 port_byte_in (u16 port) {
u8 result;
uint8_t port_byte_in (uint16_t port) {
uint8_t result;
/* Inline assembler syntax
* !! Notice how the source and destination registers are switched from NASM !!
*
@ -17,7 +17,7 @@ u8 port_byte_in (u16 port) {
return result;
}
void port_byte_out (u16 port, u8 data) {
void port_byte_out (uint16_t port, uint8_t data) {
/* Notice how here both registers are mapped to C variables and
* nothing is returned, thus, no equals '=' in the asm syntax
* However we see a comma since there are two variables in the input area
@ -26,12 +26,12 @@ void port_byte_out (u16 port, u8 data) {
__asm__ __volatile__("out %%al, %%dx" : : "a" (data), "d" (port));
}
u16 port_word_in (u16 port) {
u16 result;
uint16_t port_word_in (uint16_t port) {
uint16_t result;
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
return result;
}
void port_word_out (u16 port, u16 data) {
void port_word_out (uint16_t port, uint16_t data) {
__asm__ __volatile__("out %%ax, %%dx" : : "a" (data), "d" (port));
}

@ -1,11 +1,11 @@
#ifndef PORTS_H
#define PORTS_H
#include "../cpu/type.h"
#include <stdint.h>
unsigned char port_byte_in (u16 port);
void port_byte_out (u16 port, u8 data);
unsigned short port_word_in (u16 port);
void port_word_out (u16 port, u16 data);
unsigned char port_byte_in (uint16_t port);
void port_byte_out (uint16_t port, uint8_t data);
unsigned short port_word_in (uint16_t port);
void port_word_out (uint16_t port, uint16_t data);
#endif

@ -3,21 +3,21 @@
#include "ports.h"
#include "../libc/function.h"
u32 tick = 0;
uint32_t tick = 0;
static void timer_callback(registers_t regs) {
tick++;
UNUSED(regs);
}
void init_timer(u32 freq) {
void init_timer(uint32_t freq) {
/* Install the function we just wrote */
register_interrupt_handler(IRQ0, timer_callback);
/* Get the PIT value: hardware clock at 1193180 Hz */
u32 divisor = 1193180 / freq;
u8 low = (u8)(divisor & 0xFF);
u8 high = (u8)( (divisor >> 8) & 0xFF);
uint32_t divisor = 1193180 / freq;
uint8_t low = (uint8_t)(divisor & 0xFF);
uint8_t high = (uint8_t)( (divisor >> 8) & 0xFF);
/* Send the command */
port_byte_out(0x43, 0x36); /* Command port */
port_byte_out(0x40, low);

@ -1,8 +1,8 @@
#ifndef TIMER_H
#define TIMER_H
#include "type.h"
#include <stdint.h>
void init_timer(u32 freq);
void init_timer(uint32_t freq);
#endif

@ -1,16 +1,9 @@
#ifndef TYPE_H
#define TYPE_H
/* Instead of using 'chars' to allocate non-character bytes,
* we will use these new type with no semantic meaning */
typedef unsigned int u32;
typedef int s32;
typedef unsigned short u16;
typedef short s16;
typedef unsigned char u8;
typedef char s8;
#include <stdint.h>
#define low_16(address) (u16)((address) & 0xFFFF)
#define high_16(address) (u16)(((address) >> 16) & 0xFFFF)
#define low_16(address) (uint16_t)((address) & 0xFFFF)
#define high_16(address) (uint16_t)(((address) >> 16) & 0xFFFF)
#endif

@ -5,6 +5,7 @@
#include "../libc/string.h"
#include "../libc/function.h"
#include "../kernel/kernel.h"
#include <stdint.h>
#define BACKSPACE 0x0E
#define ENTER 0x1C
@ -26,7 +27,7 @@ const char sc_ascii[] = { '?', '?', '1', '2', '3', '4', '5', '6',
static void keyboard_callback(registers_t regs) {
/* The PIC leaves us the scancode in port 0x60 */
u8 scancode = port_byte_in(0x60);
uint8_t scancode = port_byte_in(0x60);
if (scancode > SC_MAX) return;
if (scancode == BACKSPACE) {

@ -1,3 +1 @@
#include "../cpu/type.h"
void init_keyboard();

@ -1,6 +1,7 @@
#include "screen.h"
#include "../cpu/ports.h"
#include "../libc/mem.h"
#include <stdint.h>
/* Declaration of private functions */
int get_cursor_offset();
@ -65,7 +66,7 @@ void kprint_backspace() {
* Sets the video cursor to the returned offset
*/
int print_char(char c, int col, int row, char attr) {
u8 *vidmem = (u8*) VIDEO_ADDRESS;
uint8_t *vidmem = (uint8_t*) VIDEO_ADDRESS;
if (!attr) attr = WHITE_ON_BLACK;
/* Error control: print a red 'E' if the coords aren't right */
@ -95,12 +96,12 @@ int print_char(char c, int col, int row, char attr) {
if (offset >= MAX_ROWS * MAX_COLS * 2) {
int i;
for (i = 1; i < MAX_ROWS; i++)
memory_copy((u8*)(get_offset(0, i) + VIDEO_ADDRESS),
(u8*)(get_offset(0, i-1) + VIDEO_ADDRESS),
memory_copy((uint8_t*)(get_offset(0, i) + VIDEO_ADDRESS),
(uint8_t*)(get_offset(0, i-1) + VIDEO_ADDRESS),
MAX_COLS * 2);
/* Blank last line */
char *last_line = (char*) (get_offset(0, MAX_ROWS-1) + (u8*) VIDEO_ADDRESS);
char *last_line = (char*) (get_offset(0, MAX_ROWS-1) + (uint8_t*) VIDEO_ADDRESS);
for (i = 0; i < MAX_COLS * 2; i++) last_line[i] = 0;
offset -= 2 * MAX_COLS;
@ -126,15 +127,15 @@ void set_cursor_offset(int offset) {
/* Similar to get_cursor_offset, but instead of reading we write data */
offset /= 2;
port_byte_out(REG_SCREEN_CTRL, 14);
port_byte_out(REG_SCREEN_DATA, (u8)(offset >> 8));
port_byte_out(REG_SCREEN_DATA, (uint8_t)(offset >> 8));
port_byte_out(REG_SCREEN_CTRL, 15);
port_byte_out(REG_SCREEN_DATA, (u8)(offset & 0xff));
port_byte_out(REG_SCREEN_DATA, (uint8_t)(offset & 0xff));
}
void clear_screen() {
int screen_size = MAX_COLS * MAX_ROWS;
int i;
u8 *screen = (u8*) VIDEO_ADDRESS;
uint8_t *screen = (uint8_t*) VIDEO_ADDRESS;
for (i = 0; i < screen_size; i++) {
screen[i*2] = ' ';

@ -1,8 +1,6 @@
#ifndef SCREEN_H
#define SCREEN_H
#include "../cpu/type.h"
#define VIDEO_ADDRESS 0xb8000
#define MAX_ROWS 25
#define MAX_COLS 80

@ -3,6 +3,7 @@
#include "kernel.h"
#include "../libc/string.h"
#include "../libc/mem.h"
#include <stdint.h>
void kernel_main() {
isr_install();
@ -18,8 +19,8 @@ void user_input(char *input) {
asm volatile("hlt");
} else if (strcmp(input, "PAGE") == 0) {
/* Lesson 22: Code to test kmalloc, the rest is unchanged */
u32 phys_addr;
u32 page = kmalloc(1000, 1, &phys_addr);
uint32_t phys_addr;
uint32_t page = kmalloc(1000, 1, &phys_addr);
char page_str[16] = "";
hex_to_ascii(page, page_str);
char phys_str[16] = "";

@ -1,24 +1,24 @@
#include "mem.h"
void memory_copy(u8 *source, u8 *dest, int nbytes) {
void memory_copy(uint8_t *source, uint8_t *dest, int nbytes) {
int i;
for (i = 0; i < nbytes; i++) {
*(dest + i) = *(source + i);
}
}
void memory_set(u8 *dest, u8 val, u32 len) {
u8 *temp = (u8 *)dest;
void memory_set(uint8_t *dest, uint8_t val, uint32_t len) {
uint8_t *temp = (uint8_t *)dest;
for ( ; len != 0; len--) *temp++ = val;
}
/* This should be computed at link time, but a hardcoded
* value is fine for now. Remember that our kernel starts
* at 0x1000 as defined on the Makefile */
u32 free_mem_addr = 0x10000;
uint32_t free_mem_addr = 0x10000;
/* Implementation is just a pointer to some free memory which
* keeps growing */
u32 kmalloc(u32 size, int align, u32 *phys_addr) {
uint32_t kmalloc(uint32_t size, int align, uint32_t *phys_addr) {
/* Pages are aligned to 4K, or 0x1000 */
if (align == 1 && (free_mem_addr & 0xFFFFF000)) {
free_mem_addr &= 0xFFFFF000;
@ -27,7 +27,7 @@ u32 kmalloc(u32 size, int align, u32 *phys_addr) {
/* Save also the physical address */
if (phys_addr) *phys_addr = free_mem_addr;
u32 ret = free_mem_addr;
uint32_t ret = free_mem_addr;
free_mem_addr += size; /* Remember to increment the pointer */
return ret;
}

@ -1,12 +1,12 @@
#ifndef MEM_H
#define MEM_H
#include "../cpu/type.h"
#include <stdint.h>
void memory_copy(u8 *source, u8 *dest, int nbytes);
void memory_set(u8 *dest, u8 val, u32 len);
void memory_copy(uint8_t *source, uint8_t *dest, int nbytes);
void memory_set(uint8_t *dest, uint8_t val, uint32_t len);
/* At this stage there is no 'free' implemented. */
u32 kmalloc(u32 size, int align, u32 *phys_addr);
uint32_t kmalloc(uint32_t size, int align, uint32_t *phys_addr);
#endif

@ -1,5 +1,5 @@
#include "string.h"
#include "../cpu/type.h"
#include <stdint.h>
/**
* K&R implementation
@ -23,7 +23,7 @@ void hex_to_ascii(int n, char str[]) {
append(str, 'x');
char zeros = 0;
s32 tmp;
int32_t tmp;
int i;
for (i = 28; i > 0; i -= 4) {
tmp = (n >> i) & 0xF;

Loading…
Cancel
Save