mirror of
https://github.com/cfenollosa/os-tutorial.git
synced 2024-10-27 20:34:19 +00:00
Lesson 23, section 6
This commit is contained in:
parent
c473761432
commit
b109691179
@ -7,7 +7,7 @@ OBJ = ${C_SOURCES:.c=.o cpu/interrupt.o}
|
|||||||
CC = /usr/local/i386elfgcc/bin/i386-elf-gcc
|
CC = /usr/local/i386elfgcc/bin/i386-elf-gcc
|
||||||
GDB = /usr/local/i386elfgcc/bin/i386-elf-gdb
|
GDB = /usr/local/i386elfgcc/bin/i386-elf-gdb
|
||||||
# -g: Use debugging symbols in gcc
|
# -g: Use debugging symbols in gcc
|
||||||
CFLAGS = -g -ffreestanding -Wall -Wextra -fno-exceptions
|
CFLAGS = -g -ffreestanding -Wall -Wextra -fno-exceptions -m32
|
||||||
|
|
||||||
# First rule is run by default
|
# First rule is run by default
|
||||||
os-image.bin: boot/bootsect.bin kernel.bin
|
os-image.bin: boot/bootsect.bin kernel.bin
|
||||||
@ -33,7 +33,7 @@ debug: os-image.bin kernel.elf
|
|||||||
# Generic rules for wildcards
|
# Generic rules for wildcards
|
||||||
# To make an object, always compile from its .c
|
# To make an object, always compile from its .c
|
||||||
%.o: %.c ${HEADERS}
|
%.o: %.c ${HEADERS}
|
||||||
${CC} ${CFLAGS} -ffreestanding -c $< -o $@
|
${CC} ${CFLAGS} -c $< -o $@
|
||||||
|
|
||||||
%.o: %.asm
|
%.o: %.asm
|
||||||
nasm $< -f elf -o $@
|
nasm $< -f elf -o $@
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
*Concepts you may want to Google beforehand: XX*
|
*Concepts you may want to Google beforehand: freestanding, uint32_t, size_t,*
|
||||||
|
|
||||||
**Goal: Fix miscellaneous issues with our code**
|
**Goal: Fix miscellaneous issues with our code**
|
||||||
|
|
||||||
@ -16,7 +16,8 @@ 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
|
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`
|
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.
|
`-nostdinc` was also pased to gcc, but we will need it for step 3, so let's delete it.
|
||||||
|
|
||||||
|
|
||||||
2. kernel.c `main()` function
|
2. kernel.c `main()` function
|
||||||
-----------------------------
|
-----------------------------
|
||||||
@ -69,11 +70,23 @@ bit telling whether interrupts are on or off.
|
|||||||
In other words the interrupt handler automatically restores interrupts whether or not
|
In other words the interrupt handler automatically restores interrupts whether or not
|
||||||
interrupts were enabled before this interrupt
|
interrupts were enabled before this interrupt
|
||||||
|
|
||||||
|
|
||||||
On `cpu/isr.h`, `struct registers_t` has a couple issues.
|
On `cpu/isr.h`, `struct registers_t` has a couple issues.
|
||||||
First, the alleged `esp` is renamed to `useless`.
|
First, the alleged `esp` is renamed to `useless`.
|
||||||
The value is useless because it has to do with the current stack context, not what was interrupted.
|
The value is useless because it has to do with the current stack context, not what was interrupted.
|
||||||
Then, we rename `useresp` to `esp`
|
Then, we rename `useresp` to `esp`
|
||||||
|
|
||||||
Finally, we add `cld` just before `call isr_handler` on `cpu/interrupt.asm`
|
We add `cld` just before `call isr_handler` on `cpu/interrupt.asm` as suggested
|
||||||
|
by the osdev wiki.
|
||||||
|
|
||||||
|
There is a final, important issue with `cpu/interrupt.asm`. The common stubs create an instance
|
||||||
|
of `struct registers` on the stack and then call the C handler. But that breaks the ABI, since
|
||||||
|
the stack belongs to the called function and they may change them as they please. It is needed
|
||||||
|
to pass the struct as a pointer.
|
||||||
|
|
||||||
|
To achieve this, edit `cpu/isr.h` and `cpu/isr.c` and change `registers_t r` into `registers_t *t`,
|
||||||
|
then, instead of accessing the fields of the struct via `.`, access the fields of the pointer via `->`.
|
||||||
|
Finally, in `cpu/interrupt.asm`, and add a `push esp` before calling both `isr_handler` and
|
||||||
|
`irq_handler` -- remember to also `pop eax` to clear the pointer afterwards.
|
||||||
|
|
||||||
|
Both current callbacks, the timer and the keyboard, also need to be changed to use a pointer to
|
||||||
|
`registers_t`.
|
||||||
|
@ -13,13 +13,14 @@ isr_common_stub:
|
|||||||
mov es, ax
|
mov es, ax
|
||||||
mov fs, ax
|
mov fs, ax
|
||||||
mov gs, ax
|
mov gs, ax
|
||||||
|
push esp ; registers_t *r
|
||||||
; 2. Call C handler
|
; 2. Call C handler
|
||||||
cld ; C code following the sysV ABI requires DF to be clear on function entry
|
cld ; C code following the sysV ABI requires DF to be clear on function entry
|
||||||
call isr_handler
|
call isr_handler
|
||||||
|
|
||||||
; 3. Restore state
|
; 3. Restore state
|
||||||
pop eax
|
pop eax
|
||||||
|
pop eax
|
||||||
mov ds, ax
|
mov ds, ax
|
||||||
mov es, ax
|
mov es, ax
|
||||||
mov fs, ax
|
mov fs, ax
|
||||||
@ -39,9 +40,11 @@ irq_common_stub:
|
|||||||
mov es, ax
|
mov es, ax
|
||||||
mov fs, ax
|
mov fs, ax
|
||||||
mov gs, ax
|
mov gs, ax
|
||||||
|
push esp
|
||||||
cld
|
cld
|
||||||
call irq_handler ; Different than the ISR code
|
call irq_handler ; Different than the ISR code
|
||||||
pop ebx ; Different than the ISR code
|
pop ebx ; Different than the ISR code
|
||||||
|
pop ebx
|
||||||
mov ds, bx
|
mov ds, bx
|
||||||
mov es, bx
|
mov es, bx
|
||||||
mov fs, bx
|
mov fs, bx
|
||||||
@ -110,218 +113,186 @@ global irq15
|
|||||||
|
|
||||||
; 0: Divide By Zero Exception
|
; 0: Divide By Zero Exception
|
||||||
isr0:
|
isr0:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 0
|
push byte 0
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 1: Debug Exception
|
; 1: Debug Exception
|
||||||
isr1:
|
isr1:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 1
|
push byte 1
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 2: Non Maskable Interrupt Exception
|
; 2: Non Maskable Interrupt Exception
|
||||||
isr2:
|
isr2:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 2
|
push byte 2
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 3: Int 3 Exception
|
; 3: Int 3 Exception
|
||||||
isr3:
|
isr3:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 3
|
push byte 3
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 4: INTO Exception
|
; 4: INTO Exception
|
||||||
isr4:
|
isr4:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 4
|
push byte 4
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 5: Out of Bounds Exception
|
; 5: Out of Bounds Exception
|
||||||
isr5:
|
isr5:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 5
|
push byte 5
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 6: Invalid Opcode Exception
|
; 6: Invalid Opcode Exception
|
||||||
isr6:
|
isr6:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 6
|
push byte 6
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 7: Coprocessor Not Available Exception
|
; 7: Coprocessor Not Available Exception
|
||||||
isr7:
|
isr7:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 7
|
push byte 7
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 8: Double Fault Exception (With Error Code!)
|
; 8: Double Fault Exception (With Error Code!)
|
||||||
isr8:
|
isr8:
|
||||||
cli
|
|
||||||
push byte 8
|
push byte 8
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 9: Coprocessor Segment Overrun Exception
|
; 9: Coprocessor Segment Overrun Exception
|
||||||
isr9:
|
isr9:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 9
|
push byte 9
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 10: Bad TSS Exception (With Error Code!)
|
; 10: Bad TSS Exception (With Error Code!)
|
||||||
isr10:
|
isr10:
|
||||||
cli
|
|
||||||
push byte 10
|
push byte 10
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 11: Segment Not Present Exception (With Error Code!)
|
; 11: Segment Not Present Exception (With Error Code!)
|
||||||
isr11:
|
isr11:
|
||||||
cli
|
|
||||||
push byte 11
|
push byte 11
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 12: Stack Fault Exception (With Error Code!)
|
; 12: Stack Fault Exception (With Error Code!)
|
||||||
isr12:
|
isr12:
|
||||||
cli
|
|
||||||
push byte 12
|
push byte 12
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 13: General Protection Fault Exception (With Error Code!)
|
; 13: General Protection Fault Exception (With Error Code!)
|
||||||
isr13:
|
isr13:
|
||||||
cli
|
|
||||||
push byte 13
|
push byte 13
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 14: Page Fault Exception (With Error Code!)
|
; 14: Page Fault Exception (With Error Code!)
|
||||||
isr14:
|
isr14:
|
||||||
cli
|
|
||||||
push byte 14
|
push byte 14
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 15: Reserved Exception
|
; 15: Reserved Exception
|
||||||
isr15:
|
isr15:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 15
|
push byte 15
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 16: Floating Point Exception
|
; 16: Floating Point Exception
|
||||||
isr16:
|
isr16:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 16
|
push byte 16
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 17: Alignment Check Exception
|
; 17: Alignment Check Exception
|
||||||
isr17:
|
isr17:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 17
|
push byte 17
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 18: Machine Check Exception
|
; 18: Machine Check Exception
|
||||||
isr18:
|
isr18:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 18
|
push byte 18
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 19: Reserved
|
; 19: Reserved
|
||||||
isr19:
|
isr19:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 19
|
push byte 19
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 20: Reserved
|
; 20: Reserved
|
||||||
isr20:
|
isr20:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 20
|
push byte 20
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 21: Reserved
|
; 21: Reserved
|
||||||
isr21:
|
isr21:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 21
|
push byte 21
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 22: Reserved
|
; 22: Reserved
|
||||||
isr22:
|
isr22:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 22
|
push byte 22
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 23: Reserved
|
; 23: Reserved
|
||||||
isr23:
|
isr23:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 23
|
push byte 23
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 24: Reserved
|
; 24: Reserved
|
||||||
isr24:
|
isr24:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 24
|
push byte 24
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 25: Reserved
|
; 25: Reserved
|
||||||
isr25:
|
isr25:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 25
|
push byte 25
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 26: Reserved
|
; 26: Reserved
|
||||||
isr26:
|
isr26:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 26
|
push byte 26
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 27: Reserved
|
; 27: Reserved
|
||||||
isr27:
|
isr27:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 27
|
push byte 27
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 28: Reserved
|
; 28: Reserved
|
||||||
isr28:
|
isr28:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 28
|
push byte 28
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 29: Reserved
|
; 29: Reserved
|
||||||
isr29:
|
isr29:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 29
|
push byte 29
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 30: Reserved
|
; 30: Reserved
|
||||||
isr30:
|
isr30:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 30
|
push byte 30
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
|
||||||
; 31: Reserved
|
; 31: Reserved
|
||||||
isr31:
|
isr31:
|
||||||
cli
|
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 31
|
push byte 31
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
@ -116,13 +116,13 @@ char *exception_messages[] = {
|
|||||||
"Reserved"
|
"Reserved"
|
||||||
};
|
};
|
||||||
|
|
||||||
void isr_handler(registers_t r) {
|
void isr_handler(registers_t *r) {
|
||||||
kprint("received interrupt: ");
|
kprint("received interrupt: ");
|
||||||
char s[3];
|
char s[3];
|
||||||
int_to_ascii(r.int_no, s);
|
int_to_ascii(r->int_no, s);
|
||||||
kprint(s);
|
kprint(s);
|
||||||
kprint("\n");
|
kprint("\n");
|
||||||
kprint(exception_messages[r.int_no]);
|
kprint(exception_messages[r->int_no]);
|
||||||
kprint("\n");
|
kprint("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,15 +130,15 @@ void register_interrupt_handler(uint8_t n, isr_t handler) {
|
|||||||
interrupt_handlers[n] = handler;
|
interrupt_handlers[n] = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void irq_handler(registers_t r) {
|
void irq_handler(registers_t *r) {
|
||||||
/* After every interrupt we need to send an EOI to the PICs
|
/* After every interrupt we need to send an EOI to the PICs
|
||||||
* or they will not send another interrupt again */
|
* or they will not send another interrupt again */
|
||||||
if (r.int_no >= 40) port_byte_out(0xA0, 0x20); /* slave */
|
if (r->int_no >= 40) port_byte_out(0xA0, 0x20); /* slave */
|
||||||
port_byte_out(0x20, 0x20); /* master */
|
port_byte_out(0x20, 0x20); /* master */
|
||||||
|
|
||||||
/* Handle the interrupt in a more modular way */
|
/* Handle the interrupt in a more modular way */
|
||||||
if (interrupt_handlers[r.int_no] != 0) {
|
if (interrupt_handlers[r->int_no] != 0) {
|
||||||
isr_t handler = interrupt_handlers[r.int_no];
|
isr_t handler = interrupt_handlers[r->int_no];
|
||||||
handler(r);
|
handler(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,13 @@ extern void irq15();
|
|||||||
#define IRQ14 46
|
#define IRQ14 46
|
||||||
#define IRQ15 47
|
#define IRQ15 47
|
||||||
|
|
||||||
/* Struct which aggregates many registers */
|
/* Struct which aggregates many registers.
|
||||||
|
* It matches exactly the pushes on interrupt.asm. From the bottom:
|
||||||
|
* - Pushed by the processor automatically
|
||||||
|
* - `push byte`s on the isr-specific code: error code, then int number
|
||||||
|
* - All the registers by pusha
|
||||||
|
* - `push eax` whose lower 16-bits contain DS
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t ds; /* Data segment selector */
|
uint32_t ds; /* Data segment selector */
|
||||||
uint32_t edi, esi, ebp, useless, ebx, edx, ecx, eax; /* Pushed by pusha. */
|
uint32_t edi, esi, ebp, useless, ebx, edx, ecx, eax; /* Pushed by pusha. */
|
||||||
@ -80,10 +86,10 @@ typedef struct {
|
|||||||
} registers_t;
|
} registers_t;
|
||||||
|
|
||||||
void isr_install();
|
void isr_install();
|
||||||
void isr_handler(registers_t r);
|
void isr_handler(registers_t *r);
|
||||||
void irq_install();
|
void irq_install();
|
||||||
|
|
||||||
typedef void (*isr_t)(registers_t);
|
typedef void (*isr_t)(registers_t*);
|
||||||
void register_interrupt_handler(uint8_t n, isr_t handler);
|
void register_interrupt_handler(uint8_t n, isr_t handler);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
uint32_t tick = 0;
|
uint32_t tick = 0;
|
||||||
|
|
||||||
static void timer_callback(registers_t regs) {
|
static void timer_callback(registers_t *regs) {
|
||||||
tick++;
|
tick++;
|
||||||
UNUSED(regs);
|
UNUSED(regs);
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ const char sc_ascii[] = { '?', '?', '1', '2', '3', '4', '5', '6',
|
|||||||
'H', 'J', 'K', 'L', ';', '\'', '`', '?', '\\', 'Z', 'X', 'C', 'V',
|
'H', 'J', 'K', 'L', ';', '\'', '`', '?', '\\', 'Z', 'X', 'C', 'V',
|
||||||
'B', 'N', 'M', ',', '.', '/', '?', '?', '?', ' '};
|
'B', 'N', 'M', ',', '.', '/', '?', '?', '?', ' '};
|
||||||
|
|
||||||
static void keyboard_callback(registers_t regs) {
|
static void keyboard_callback(registers_t *regs) {
|
||||||
/* The PIC leaves us the scancode in port 0x60 */
|
/* The PIC leaves us the scancode in port 0x60 */
|
||||||
uint8_t scancode = port_byte_in(0x60);
|
uint8_t scancode = port_byte_in(0x60);
|
||||||
|
|
||||||
|
@ -9,6 +9,9 @@ void kernel_main() {
|
|||||||
isr_install();
|
isr_install();
|
||||||
irq_install();
|
irq_install();
|
||||||
|
|
||||||
|
asm("int $2");
|
||||||
|
asm("int $3");
|
||||||
|
|
||||||
kprint("Type something, it will go through the kernel\n"
|
kprint("Type something, it will go through the kernel\n"
|
||||||
"Type END to halt the CPU or PAGE to request a kmalloc()\n> ");
|
"Type END to halt the CPU or PAGE to request a kmalloc()\n> ");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user