Add: Starting kernel repos
This commit is contained in:
commit
c0c4dbc665
|
@ -0,0 +1 @@
|
|||
log.txt
|
|
@ -0,0 +1,17 @@
|
|||
include Makefile.common
|
||||
|
||||
all: k.iso
|
||||
|
||||
k.iso: install
|
||||
./tools/create_iso.sh
|
||||
|
||||
install:
|
||||
mkdir -p $(GRUBDIR)
|
||||
$(MAKE) -C $(SOURCEDIR) $@
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(SOURCEDIR) $@
|
||||
$(RM) kernel.iso
|
||||
$(RM) -r iso
|
||||
|
||||
.PHONY: $(GRUBDIR) install
|
|
@ -0,0 +1,6 @@
|
|||
CFLAGS = -std=gnu99 -Os -Wall -Wextra -fno-builtin -ffreestanding -m32 -fno-asynchronous-unwind-tables -fno-common -fno-pie -march=i486 -fno-stack-protector -ffunction-sections -fdata-sections
|
||||
LDFLAGS = -nostdlib -Wl,--build-id=none,--gc-sections -nostartfiles -static -m32
|
||||
ASFLAGS = -m32
|
||||
GRUBDIR = iso
|
||||
SOURCEDIR = src
|
||||
TARGET = kernel
|
|
@ -0,0 +1,22 @@
|
|||
# Introduction
|
||||
|
||||
This kernel is written as a educative project. The goal is to have a kernel able to run a basic shell. To allow that, this kernel have to implement :
|
||||
- [X] Protected mode (loading gdt)
|
||||
- [X] Manage interrupt (loading idt and enabling interrupt)
|
||||
- [X] Manage IRQ (enable PIC)
|
||||
- [X] Running and Userland (TSS)
|
||||
- [X] Let the userland call the kernel (syscall)
|
||||
- [ ] Running multiple userland (ordonnanceur)
|
||||
- [ ] Running elf binary
|
||||
- [ ] Having a small libc and needed syscall to run the shell
|
||||
- [ ] (Bonus) Having a basic visual interface (VGA ?)
|
||||
|
||||
This kernel has been written using :
|
||||
- The tutorial Pépin OS - Réaliser son propre système (in french): https://michelizza.developpez.com/realiser-son-propre-systeme
|
||||
- The educative k project from former EPITA (Engineering School) system laboratory LSE:
|
||||
https://k.lse.epita.fr/
|
||||
https://github.com/Galli24/kernel-k-project
|
||||
- The ressources on the website OSDev:
|
||||
https://wiki.osdev.org/Main_Page
|
||||
- The in Intel® 64 and IA-32 Architectures, Software Developer’s Manual, Volume 3A: System Programming Guide, Part 1:
|
||||
https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html
|
|
@ -0,0 +1,32 @@
|
|||
include ../Makefile.common
|
||||
|
||||
OBJS = \
|
||||
boot.o \
|
||||
kernel.o \
|
||||
serial.o \
|
||||
isr.o \
|
||||
debug.o \
|
||||
syscall.o \
|
||||
int.o \
|
||||
gdt.o \
|
||||
idt.o \
|
||||
pic_controler.o \
|
||||
userland.o \
|
||||
launch_process.o \
|
||||
|
||||
DEPS = $(OBJS:.o=.d)
|
||||
|
||||
CPPFLAGS += -MMD -Iinclude
|
||||
CFLAGS += $(K_EXTRA_CFLAGS) -g -nostdlib
|
||||
LDFLAGS += -Wl,-Tkernel.lds
|
||||
LDLIBS =
|
||||
|
||||
all: $(TARGET) $(OBJS)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
|
||||
install: $(TARGET)
|
||||
install $(TARGET) ../$(GRUBDIR)/$(TARGET)
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJS) $(DEPS) $(TARGET)
|
|
@ -0,0 +1,109 @@
|
|||
/* Declare constants for the multiboot header. */
|
||||
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
|
||||
.set MEMINFO, 1<<1 /* provide memory map */
|
||||
.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */
|
||||
.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */
|
||||
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */
|
||||
|
||||
/*
|
||||
Declare a multiboot header that marks the program as a kernel. These are magic
|
||||
values that are documented in the multiboot standard. The bootloader will
|
||||
search for this signature in the first 8 KiB of the kernel file, aligned at a
|
||||
32-bit boundary. The signature is in its own section so the header can be
|
||||
forced to be within the first 8 KiB of the kernel file.
|
||||
*/
|
||||
.section .multiboot
|
||||
.align 4
|
||||
.long MAGIC
|
||||
.long FLAGS
|
||||
.long CHECKSUM
|
||||
|
||||
/*
|
||||
The multiboot standard does not define the value of the stack pointer register
|
||||
(esp) and it is up to the kernel to provide a stack. This allocates room for a
|
||||
small stack by creating a symbol at the bottom of it, then allocating 16384
|
||||
bytes for it, and finally creating a symbol at the top. The stack grows
|
||||
downwards on x86. The stack is in its own section so it can be marked nobits,
|
||||
which means the kernel file is smaller because it does not contain an
|
||||
uninitialized stack. The stack on x86 must be 16-byte aligned according to the
|
||||
System V ABI standard and de-facto extensions. The compiler will assume the
|
||||
stack is properly aligned and failure to align the stack will result in
|
||||
undefined behavior.
|
||||
*/
|
||||
.section .bss
|
||||
.align 16
|
||||
stack_bottom:
|
||||
.skip 16384 # 16 KiB
|
||||
stack_top:
|
||||
|
||||
/*
|
||||
The linker script specifies _start as the entry point to the kernel and the
|
||||
bootloader will jump to this position once the kernel has been loaded. It
|
||||
doesn't make sense to return from this function as the bootloader is gone.
|
||||
*/
|
||||
.section .text
|
||||
.global _start
|
||||
.type _start, @function
|
||||
_start:
|
||||
/*
|
||||
The bootloader has loaded us into 32-bit protected mode on a x86
|
||||
machine. Interrupts are disabled. Paging is disabled. The processor
|
||||
state is as defined in the multiboot standard. The kernel has full
|
||||
control of the CPU. The kernel can only make use of hardware features
|
||||
and any code it provides as part of itself. There's no printf
|
||||
function, unless the kernel provides its own <stdio.h> header and a
|
||||
printf implementation. There are no security restrictions, no
|
||||
safeguards, no debugging mechanisms, only what the kernel provides
|
||||
itself. It has absolute and complete power over the
|
||||
machine.
|
||||
*/
|
||||
|
||||
/*
|
||||
To set up a stack, we set the esp register to point to the top of the
|
||||
stack (as it grows downwards on x86 systems). This is necessarily done
|
||||
in assembly as languages such as C cannot function without a stack.
|
||||
*/
|
||||
mov $stack_top, %esp
|
||||
|
||||
/*
|
||||
This is a good place to initialize crucial processor state before the
|
||||
high-level kernel is entered. It's best to minimize the early
|
||||
environment where crucial features are offline. Note that the
|
||||
processor is not fully initialized yet: Features such as floating
|
||||
point instructions and instruction set extensions are not initialized
|
||||
yet. The GDT should be loaded here. Paging should be enabled here.
|
||||
C++ features such as global constructors and exceptions will require
|
||||
runtime support to work as well.
|
||||
*/
|
||||
|
||||
/*
|
||||
Enter the high-level kernel. The ABI requires the stack is 16-byte
|
||||
aligned at the time of the call instruction (which afterwards pushes
|
||||
the return pointer of size 4 bytes). The stack was originally 16-byte
|
||||
aligned above and we've pushed a multiple of 16 bytes to the
|
||||
stack since (pushed 0 bytes so far), so the alignment has thus been
|
||||
preserved and the call is well defined.
|
||||
*/
|
||||
call kernel_main
|
||||
|
||||
/*
|
||||
If the system has nothing more to do, put the computer into an
|
||||
infinite loop. To do that:
|
||||
1) Disable interrupts with cli (clear interrupt enable in eflags).
|
||||
They are already disabled by the bootloader, so this is not needed.
|
||||
Mind that you might later enable interrupts and return from
|
||||
kernel_main (which is sort of nonsensical to do).
|
||||
2) Wait for the next interrupt to arrive with hlt (halt instruction).
|
||||
Since they are disabled, this will lock up the computer.
|
||||
3) Jump to the hlt instruction if it ever wakes up due to a
|
||||
non-maskable interrupt occurring or due to system management mode.
|
||||
*/
|
||||
cli
|
||||
1: hlt
|
||||
jmp 1b
|
||||
|
||||
/*
|
||||
Set the size of the _start symbol to the current location '.' minus its start.
|
||||
This is useful when debugging or when you implement call tracing.
|
||||
*/
|
||||
.size _start, . - _start
|
|
@ -0,0 +1,87 @@
|
|||
#include "debug.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "serial.h"
|
||||
|
||||
int print_variadic(char *msg, va_list args)
|
||||
{
|
||||
while (*msg != '\0')
|
||||
{
|
||||
if (*(msg + 1) != '\0' && *msg == '%')
|
||||
{
|
||||
switch (*(msg + 1))
|
||||
{
|
||||
case 'd':
|
||||
write_serial_nb(va_arg(args, int), false);
|
||||
break;
|
||||
case 's':
|
||||
write_serial(va_arg(args, char *));
|
||||
break;
|
||||
case 'b':
|
||||
write_serial_bin(va_arg(args, char *), false);
|
||||
break;
|
||||
case 'c':
|
||||
write_serial_char(va_arg(args, int));
|
||||
break;
|
||||
default:
|
||||
write_serial("?");
|
||||
break;
|
||||
}
|
||||
msg += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_serial_char(*msg);
|
||||
msg++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int debug_info(char *fnt, char *msg, ...)
|
||||
{
|
||||
write_serial("\033[0;34m[INFO]\033[0m ");
|
||||
write_serial(fnt);
|
||||
write_serial("\t: ");
|
||||
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
print_variadic(msg, args);
|
||||
va_end(args);
|
||||
|
||||
write_serial("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int debug_warn(char *fnt, char *msg, ...)
|
||||
{
|
||||
write_serial("\033[0;33m[WARNING]\033[0m ");
|
||||
write_serial(fnt);
|
||||
write_serial("\t: ");
|
||||
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
print_variadic(msg, args);
|
||||
va_end(args);
|
||||
|
||||
write_serial("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int debug_err(char *fnt, char *msg, ...)
|
||||
{
|
||||
write_serial("\033[0;31m[ERROR]\033[0m ");
|
||||
write_serial(fnt);
|
||||
write_serial("\t: ");
|
||||
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
print_variadic(msg, args);
|
||||
va_end(args);
|
||||
|
||||
write_serial("\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_INFO(...) debug_info(__func__, ##__VA_ARGS__)
|
||||
#define DEBUG_WARN(...) debug_warn(__func__, ##__VA_ARGS__)
|
||||
#define DEBUG_ERR(...) debug_err(__func__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_INFO(...)
|
||||
#define DEBUG_WARN(...)
|
||||
#define DEBUG_ERR(...)
|
||||
#endif
|
||||
|
||||
int debug_info(char *fnt, char *msg, ...);
|
||||
int debug_warn(char *fnt, char *msg, ...);
|
||||
int debug_err(char *fnt, char *msg, ...);
|
||||
|
||||
#endif /* DEBUG_H */
|
|
@ -0,0 +1,140 @@
|
|||
#define __GDT__
|
||||
#define __TSS__
|
||||
|
||||
#include "gdt.h"
|
||||
#include <types.h>
|
||||
#include "serial.h"
|
||||
#include "debug.h"
|
||||
#include "tss.h"
|
||||
#include "userland.h"
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
const char *s = src;
|
||||
char *d = dest;
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
*d++ = *s++;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
struct tss user_land_tss;
|
||||
|
||||
struct segment_desc_param {
|
||||
u16 Limit_1;
|
||||
u32 Base;
|
||||
u8 Type;
|
||||
u8 S;
|
||||
u8 DPL;
|
||||
u8 P;
|
||||
u8 Limit_2;
|
||||
u8 AVL;
|
||||
u8 L;
|
||||
u8 D_B;
|
||||
u8 G;
|
||||
};
|
||||
|
||||
struct segdesc init_descriptor(struct segment_desc_param param)
|
||||
{
|
||||
struct segdesc descriptor;
|
||||
|
||||
descriptor.Limit_1 = param.Limit_1;
|
||||
descriptor.Limit_2 = param.Limit_2;
|
||||
|
||||
descriptor.Base_1 = (u16) param.Base;
|
||||
descriptor.Base_2 = (u8) (param.Base >> 16);
|
||||
descriptor.Base_3 = (u8) (param.Base >> 24);
|
||||
|
||||
descriptor.Type = (param.Type & 0x000F);
|
||||
|
||||
descriptor.Flag_1 = param.S;
|
||||
descriptor.Flag_1 |= (param.DPL << 1);
|
||||
descriptor.Flag_1 |= (param.P << 3);
|
||||
|
||||
descriptor.Flag_2 = param.AVL;
|
||||
descriptor.Flag_2 |= (param.L << 1);
|
||||
descriptor.Flag_2 |= (param.D_B << 2);
|
||||
descriptor.Flag_2 |= (param.G << 3);
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
void init_gdt(void)
|
||||
{
|
||||
DEBUG_INFO("Initializing GDT");
|
||||
|
||||
DEBUG_INFO("GDT BASE ADDRESS: %d", (u32) &kgdtr);
|
||||
DEBUG_INFO("GDT LIMIT: %d", sizeof(gdt) - 1);
|
||||
kgdtr.limit = sizeof(gdt) - 1;
|
||||
kgdtr.base = (u32) gdt;
|
||||
|
||||
memcpy((char*) 0x30000, &userland, 1000);
|
||||
|
||||
gdt[0] = init_descriptor((struct segment_desc_param) { .Limit_1 = 0,
|
||||
.Base = 0, .Type = 0, .S = 0, .DPL = 0, .P = 0,
|
||||
.Limit_2 = 0, .AVL = 0, .L = 0, .D_B = 0, .G = 0 });
|
||||
|
||||
// Code
|
||||
gdt[1] = init_descriptor((struct segment_desc_param) { .Limit_1 = 0xFFFF,
|
||||
.Base = 0, .Type = 0x0B, .S = 1, .DPL = 0, .P = 1,
|
||||
.Limit_2 = 0x02, .AVL = 0, .L = 0, .D_B = 1, .G = 1 });
|
||||
// Data
|
||||
gdt[2] = init_descriptor((struct segment_desc_param) { .Limit_1 = 0xFFFF,
|
||||
.Base = 0, .Type = 2, .S = 1, .DPL = 0, .P = 1,
|
||||
.Limit_2 = 0x02, .AVL = 0, .L = 0, .D_B = 1, .G = 1 });
|
||||
|
||||
// Code
|
||||
gdt[3] = init_descriptor((struct segment_desc_param) { .Limit_1 = 0xFFFF,
|
||||
.Base = 0x30000, .Type = 0x0B, .S = 1, .DPL = 3, .P = 1,
|
||||
.Limit_2 = 0x0F, .AVL = 0, .L = 0, .D_B = 1, .G = 1 });
|
||||
|
||||
// Data
|
||||
gdt[4] = init_descriptor((struct segment_desc_param) { .Limit_1 = 0xFFFF,
|
||||
.Base = 0x30000, .Type = 2, .S = 1, .DPL = 3, .P = 1,
|
||||
.Limit_2 = 0x0F, .AVL = 0, .L = 0, .D_B = 1, .G = 1 });
|
||||
|
||||
user_land_tss.ssp = 0x0;
|
||||
user_land_tss.io_map_base_address = 0x0;
|
||||
user_land_tss.ss0 = 0x10;
|
||||
user_land_tss.esp0 = 0x20000;
|
||||
|
||||
DEBUG_INFO("TSS BASE ADDRESS: %d", (u32) &user_land_tss);
|
||||
|
||||
gdt[5] = init_descriptor((struct segment_desc_param) { .Limit_1 = sizeof(user_land_tss),
|
||||
.Base = &user_land_tss, .Type = 0x09, .S = 0, .DPL = 3, .P = 1,
|
||||
.Limit_2 = 0x00, .AVL = 0, .L = 0, .D_B = 0, .G = 0 });
|
||||
|
||||
for (int i = 0; i < sizeof(gdt) / 8; i++)
|
||||
{
|
||||
char *ptr = (char *) &gdt[i];
|
||||
DEBUG_INFO("--------------------");
|
||||
DEBUG_INFO("GDT[%d] : Entry number : %d", i, i * 8);
|
||||
DEBUG_INFO("\tLIMIT : %d", (u16) ptr[0] | ((ptr[6] & 0x0F) << 16));
|
||||
// TODO : Fix display of base address
|
||||
DEBUG_INFO("\tBASE : %d", (u32) ptr[2] | ((u32) (((u8) ptr[4]) << 16)) | ((u32) (((u8) ptr[7]) << 24)));
|
||||
DEBUG_INFO("\tTYPE : %b |Data 0 / Code 1|Expand Down 1|Writable 1|Accessed 1|", (u8) ptr[5] & 0x0F);
|
||||
DEBUG_INFO("\tFlag : %b |Present 1|Level ring 0 / ring 1|System 0 / Code - Data 1|", (u8) ptr[5] >> 4);
|
||||
DEBUG_INFO("\tFlag : %b |Granularity 1|16 bits 0 / 32 bits 1|64 bits 1|Available for system 1|", (u8) ptr[6] >> 4);
|
||||
}
|
||||
DEBUG_INFO("--------------------");
|
||||
|
||||
|
||||
asm volatile ("lgdt (kgdtr)");
|
||||
|
||||
asm volatile (
|
||||
"movw $0x10, %ax \n\
|
||||
movw %ax, %ds \n\
|
||||
movw %ax, %es \n\
|
||||
movw %ax, %fs \n\
|
||||
movw %ax, %gs \n\
|
||||
movw %ax, %ss \n\
|
||||
ljmp $0x08, $next \n\
|
||||
next: \n"
|
||||
);
|
||||
|
||||
DEBUG_INFO("SS0 %d", user_land_tss.ss0);
|
||||
DEBUG_INFO("ESP0 %d", user_land_tss.esp0);
|
||||
|
||||
DEBUG_INFO("GDT LOADED");
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef GDT_H
|
||||
#define GDT_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
struct gdtr {
|
||||
u16 limit;
|
||||
u32 base;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct segdesc {
|
||||
u16 Limit_1;
|
||||
u16 Base_1;
|
||||
u8 Base_2;
|
||||
u8 Type : 4;
|
||||
u8 Flag_1 : 4;
|
||||
u8 Limit_2 : 4;
|
||||
u8 Flag_2 : 4;
|
||||
u8 Base_3;
|
||||
} __attribute__((packed));
|
||||
|
||||
#ifdef __GDT__
|
||||
static struct segdesc gdt[6];
|
||||
struct gdtr kgdtr;
|
||||
#endif
|
||||
|
||||
void init_gdt(void);
|
||||
void temp_run_process(void);
|
||||
|
||||
#endif /* !GDT_H */
|
|
@ -0,0 +1,100 @@
|
|||
#define __IDT__
|
||||
|
||||
#include "idt.h"
|
||||
#include <types.h>
|
||||
#include "serial.h"
|
||||
#include "pic_controler.h"
|
||||
#include "debug.h"
|
||||
#include "int.h"
|
||||
|
||||
/*
|
||||
Make space for the interrupt descriptor table
|
||||
Tell the CPU where that space is (see GDT Tutorial: lidt works the very same way as lgdt)
|
||||
Tell the PIC that you no longer want to use the BIOS defaults (see Programming the PIC chips)
|
||||
Write a couple of ISR handlers (see Interrupt Service Routines) for both IRQs and exceptions
|
||||
Put the addresses of the ISR handlers in the appropriate descriptors (in Interrupt Descriptor Table)
|
||||
Enable all supported interrupts in the IRQ mask (of the PIC)
|
||||
*/
|
||||
|
||||
struct interrupt_gate_param {
|
||||
u32 Offset;
|
||||
u16 SegSelect;
|
||||
u8 Type;
|
||||
u8 D;
|
||||
u8 DPL;
|
||||
u8 P;
|
||||
};
|
||||
|
||||
struct idt_segdesc init_gate(struct interrupt_gate_param param)
|
||||
{
|
||||
if (param.Type == 5)
|
||||
{
|
||||
param.Offset = 0;
|
||||
param.D = 0;
|
||||
param.Offset = 0;
|
||||
}
|
||||
|
||||
struct idt_segdesc descriptor;
|
||||
|
||||
descriptor.Offset = param.Offset;
|
||||
descriptor.Offset2 = param.Offset >> 16;
|
||||
|
||||
descriptor.SegSelect = param.SegSelect;
|
||||
|
||||
descriptor.empty = 0;
|
||||
descriptor.bits = 0;
|
||||
|
||||
descriptor.Type = param.Type | (param.D << 3);
|
||||
|
||||
descriptor.Flags |= param.DPL << 1;
|
||||
descriptor.Flags |= param.P << 3;
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
void init_idt(void)
|
||||
{
|
||||
DEBUG_INFO("Initializing IDT");
|
||||
|
||||
DEBUG_INFO("IDT BASE ADDRESS: %d", (u32) &kidtr);
|
||||
DEBUG_INFO("IDT LIMIT: %d", sizeof(idt) - 1);
|
||||
kidtr.limit = sizeof(idt) - 1;
|
||||
kidtr.base = (u32) idt;
|
||||
|
||||
for (int i = 0; i < sizeof(idt); i++)
|
||||
{
|
||||
idt[i] = init_gate((struct interrupt_gate_param) { .Offset = (u32) _asm_default_int, .SegSelect = 0x08,
|
||||
.Type = 0x06, .D = 1, .DPL = 0, .P = 1 });
|
||||
}
|
||||
|
||||
idt[32] = init_gate((struct interrupt_gate_param) { .Offset = (u32) _asm_irq_0, .SegSelect = 0x08,
|
||||
.Type = 0x06, .D = 1, .DPL = 0, .P = 1 });
|
||||
|
||||
idt[33] = init_gate((struct interrupt_gate_param) { .Offset = (u32) _asm_irq_1, .SegSelect = 0x08,
|
||||
.Type = 0x06, .D = 1, .DPL = 0, .P = 1 });
|
||||
|
||||
idt[48] = init_gate((struct interrupt_gate_param) { .Offset = (u32) _asm_sycall_handler, .SegSelect = 0x08,
|
||||
.Type = 0x07, .D = 1, .DPL = 3, .P = 1 });
|
||||
|
||||
#ifdef DEBUG_IDT
|
||||
for (int i = 0; i < 49; i++)
|
||||
{
|
||||
char *ptr = (char *) &idt[i];
|
||||
DEBUG_INFO("--------------------");
|
||||
DEBUG_INFO("IDT[%d]:", i);
|
||||
DEBUG_INFO("\tOffset : %d", (u32) ptr[0] | (ptr[6] << 16));
|
||||
DEBUG_INFO("\tSegment Selector : %d | %b | %b |Index|GDT 0 / LDT 1|Level ring 0 / ring 1|", (u16) ptr[2] >> 3, ptr[2] >> 2, ptr[2]);
|
||||
DEBUG_INFO("\tZeroes : %d", (u8) ptr[4]);
|
||||
DEBUG_INFO("\tFlag : %b |16 bits 0 / 32 bits 1|Task 101 / Interrupt 110 / Trap 111|", (u8) ptr[5] & 0x0F);
|
||||
DEBUG_INFO("\tFlag : %b |Present|Level ring 0 / ring 1|Zero|", (u8) ptr[5] >> 4);
|
||||
}
|
||||
DEBUG_INFO("--------------------");
|
||||
#endif
|
||||
|
||||
asm volatile ("lidtl (kidtr)");
|
||||
|
||||
DEBUG_INFO("IDT LOADED");
|
||||
|
||||
DEBUG_INFO("ENABLING STI");
|
||||
asm volatile ("sti");
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef IDT_H
|
||||
#define IDT_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
struct idtr {
|
||||
u16 limit;
|
||||
u32 base;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct idt_segdesc {
|
||||
u16 Offset;
|
||||
u16 SegSelect;
|
||||
u8 empty : 5;
|
||||
u8 bits : 3;
|
||||
u8 Type : 4;
|
||||
u8 Flags : 4;
|
||||
u16 Offset2;
|
||||
} __attribute__((packed));
|
||||
|
||||
#ifdef __IDT__
|
||||
static struct idt_segdesc idt[256];
|
||||
struct idtr kidtr;
|
||||
#endif
|
||||
|
||||
void init_idt(void);
|
||||
|
||||
#endif /* !IDT_H */
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
#define bool int
|
||||
#define false 0
|
||||
#define true 1
|
||||
|
||||
#endif /* !TYPES_H */
|
|
@ -0,0 +1,83 @@
|
|||
.extern isr_default_int, isr_clock_int, isr_kbd_int, syscall_handler
|
||||
.global _asm_default_int, _asm_irq_0, _asm_irq_1, _asm_sycall_handler
|
||||
|
||||
_asm_default_int:
|
||||
pushal
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
push %gs
|
||||
push %ebx
|
||||
mov $0x10,%bx
|
||||
mov %bx,%ds
|
||||
pop %ebx
|
||||
call isr_default_int
|
||||
pop %gs
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
popal
|
||||
iret
|
||||
|
||||
_asm_irq_0:
|
||||
pushal
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
push %gs
|
||||
push %ebx
|
||||
mov $0x10,%bx
|
||||
mov %bx,%ds
|
||||
pop %ebx
|
||||
call isr_clock_int
|
||||
movb $0x20,%al
|
||||
outb %al,$0x20
|
||||
pop %gs
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
popal
|
||||
iret
|
||||
|
||||
_asm_irq_1:
|
||||
pushal
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
push %gs
|
||||
push %ebx
|
||||
mov $0x10,%bx
|
||||
mov %bx,%ds
|
||||
pop %ebx
|
||||
call isr_kbd_int
|
||||
movb $0x20,%al
|
||||
outb %al,$0x20
|
||||
pop %gs
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
popal
|
||||
iret
|
||||
|
||||
_asm_sycall_handler:
|
||||
pushal
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
push %gs
|
||||
push %ebx
|
||||
mov $0x10,%bx
|
||||
mov %bx,%ds
|
||||
pop %ebx
|
||||
push %ebx
|
||||
push %eax
|
||||
call syscall_handler
|
||||
pop %ebx
|
||||
pop %ebx
|
||||
pop %gs
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
mov %eax,28(%esp)
|
||||
popal
|
||||
iret
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef INT_H
|
||||
#define INT_H
|
||||
|
||||
void _asm_default_int(void);
|
||||
void _asm_irq_0(void);
|
||||
void _asm_irq_1(void);
|
||||
int _asm_sycall_handler(int eax, int ebx);
|
||||
|
||||
#endif /* !INT_H */
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef IO_H_
|
||||
#define IO_H_
|
||||
|
||||
#include <types.h>
|
||||
|
||||
static inline void outb(u16 port, u8 val)
|
||||
{
|
||||
asm volatile ("outb %0, %1" : /* No output */ : "a"(val), "d"(port));
|
||||
}
|
||||
|
||||
static inline u8 inb(u16 port)
|
||||
{
|
||||
u8 res;
|
||||
|
||||
asm volatile ("inb %1, %0" : "=&a"(res) : "d"(port));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void outw(u16 port, u16 val)
|
||||
{
|
||||
asm volatile ("outw %0, %1" : /* No output */ : "a"(val), "d"(port));
|
||||
}
|
||||
|
||||
static inline u16 inw(u16 port)
|
||||
{
|
||||
u16 res;
|
||||
|
||||
asm volatile ("inw %1, %0" : "=&a"(res) : "d"(port));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void io_wait(void)
|
||||
{
|
||||
outb(0x80, 0);
|
||||
}
|
||||
|
||||
#endif /* !IO_H_ */
|
|
@ -0,0 +1,47 @@
|
|||
#include <types.h>
|
||||
#include "io.h"
|
||||
#include "serial.h"
|
||||
#include "pic_controler.h"
|
||||
#include "debug.h"
|
||||
#include "syscall.h"
|
||||
|
||||
void isr_default_int(void)
|
||||
{
|
||||
DEBUG_INFO("An INT has been raised, entering default interrupt handler.");
|
||||
}
|
||||
|
||||
void isr_clock_int(void)
|
||||
{
|
||||
DEBUG_INFO("Enterring clock interrupt handler.");
|
||||
}
|
||||
|
||||
void isr_kbd_int(void)
|
||||
{
|
||||
DEBUG_INFO("Enterring keyboard interrupt handler.");
|
||||
|
||||
int x = inb(0x60);
|
||||
DEBUG_INFO("Keyboard input: %d", x);
|
||||
}
|
||||
|
||||
void syscall_handler(int eax, int ebx)
|
||||
{
|
||||
DEBUG_INFO("Syscall %d has been called from the userland with parameter %d", eax, ebx);
|
||||
|
||||
switch (eax)
|
||||
{
|
||||
case 1:
|
||||
char t = *((char *) ebx);
|
||||
DEBUG_INFO("Syscall write : %d", (int) t);
|
||||
return write(1, (u32) ebx);
|
||||
break;
|
||||
case 2:
|
||||
DEBUG_INFO("Syscall keyboard");
|
||||
return keyboard();
|
||||
break;
|
||||
default:
|
||||
DEBUG_INFO("No syscall %d", eax);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#include <types.h>
|
||||
|
||||
#include "gdt.h"
|
||||
#include "idt.h"
|
||||
#include "pic_controler.h"
|
||||
#include "serial.h"
|
||||
#include "debug.h"
|
||||
#include "tss.h"
|
||||
#include "launch_process.h"
|
||||
|
||||
void main(void)
|
||||
{
|
||||
DEBUG_INFO("Entering Main Function");
|
||||
|
||||
launch_process(0x28, 0x30000, 0x20, 0x18, 0x20);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
DEBUG_INFO("Waiting for an interrupt");
|
||||
asm volatile ("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
void kernel_main(void)
|
||||
{
|
||||
init_serial();
|
||||
|
||||
DEBUG_INFO("Starting kernel");
|
||||
|
||||
init_gdt();
|
||||
init_idt();
|
||||
pic_init();
|
||||
|
||||
main();
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
ENTRY(_start)
|
||||
OUTPUT_FORMAT("elf32-i386")
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text : ALIGN(CONSTANT(MAXPAGESIZE)) {
|
||||
_TEXT_START_ = .;
|
||||
*(.multiboot) *(.text)
|
||||
_TEXT_END_ = .;
|
||||
}
|
||||
|
||||
.data : ALIGN(CONSTANT(MAXPAGESIZE)) {
|
||||
_DATA_START_ = .;
|
||||
*(.data)
|
||||
_DATA_END_ = .;
|
||||
}
|
||||
|
||||
.bss : ALIGN(CONSTANT(MAXPAGESIZE)) {
|
||||
_BSS_START_ = .;
|
||||
*(.bss)
|
||||
_BSS_END_ = .;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
#include "launch_process.h"
|
||||
|
||||
#include "tss.h"
|
||||
#include "debug.h"
|
||||
|
||||
void launch_process(int tss, int memory_start, int userland_stack, int userland_code, int userland_data)
|
||||
{
|
||||
// Setting DPL and GDT bits
|
||||
userland_stack += 3;
|
||||
userland_code += 3;
|
||||
userland_data += 3;
|
||||
|
||||
DEBUG_INFO("LAUCHING USER LAND PROCESS");
|
||||
|
||||
asm volatile (" \n \
|
||||
movw %0, %%ax \n \
|
||||
ltr %%ax \n \
|
||||
movw %%ss, %1 \n \
|
||||
movl %%esp, %2 \n \
|
||||
cli \n \
|
||||
push %3 \n \
|
||||
push %4 \n \
|
||||
pushfl \n \
|
||||
popl %%eax \n \
|
||||
orl $0x200, %%eax \n \
|
||||
and $0xffffbfff, %%eax \n \
|
||||
push %%eax \n \
|
||||
push %5 \n \
|
||||
push $0x0 \n \
|
||||
movl $0x20000, %6 \n \
|
||||
movw %7, %%ax \n \
|
||||
movw %%ax, %%ds \n \
|
||||
iret" : "=m" (tss),
|
||||
"=m" (user_land_tss.ss0),
|
||||
"=m" (user_land_tss.esp0),
|
||||
"=m" (userland_stack),
|
||||
"=m" (memory_start),
|
||||
"=m" (userland_code),
|
||||
"=m" (user_land_tss.esp0),
|
||||
"=m" (userland_data));
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef LAUNCH_PROCESS_H
|
||||
#define LAUNCH_PROCESS_H
|
||||
|
||||
void launch_process(int tss, int memory_start, int userland_stack, int userland_code, int userland_data);
|
||||
|
||||
#endif /* !LAUNCH_PROCESS_H */
|
|
@ -0,0 +1,108 @@
|
|||
#include <types.h>
|
||||
|
||||
#include "pic_controler.h"
|
||||
#include "io.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define PIC1 0x20 /* IO base address for master PIC */
|
||||
#define PIC2 0xA0 /* IO base address for slave PIC */
|
||||
#define PIC1_COMMAND PIC1
|
||||
#define PIC1_DATA (PIC1+1)
|
||||
#define PIC2_COMMAND PIC2
|
||||
#define PIC2_DATA (PIC2+1)
|
||||
|
||||
#define ICW1_ICW4 0x01 /* Indicates that ICW4 will be present */
|
||||
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
|
||||
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
|
||||
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
|
||||
#define ICW1_INIT 0x10 /* Initialization - 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) */
|
||||
|
||||
#define PIC_EOI 0x20 /* End-of-interrupt command code */
|
||||
|
||||
void PIC_sendEOI(unsigned char irq)
|
||||
{
|
||||
if(irq >= 8)
|
||||
outb(PIC2_COMMAND,PIC_EOI);
|
||||
|
||||
outb(PIC1_COMMAND,PIC_EOI);
|
||||
}
|
||||
|
||||
void IRQ_set_mask(unsigned char IRQline) {
|
||||
u16 port;
|
||||
u8 value;
|
||||
|
||||
if(IRQline < 8) {
|
||||
port = PIC1_DATA;
|
||||
} else {
|
||||
port = PIC2_DATA;
|
||||
IRQline -= 8;
|
||||
}
|
||||
value = inb(port) | (1 << IRQline);
|
||||
outb(port, value);
|
||||
}
|
||||
|
||||
void IRQ_clear_mask(unsigned char IRQline) {
|
||||
u16 port;
|
||||
u8 value;
|
||||
|
||||
if(IRQline < 8) {
|
||||
port = PIC1_DATA;
|
||||
} else {
|
||||
port = PIC2_DATA;
|
||||
IRQline -= 8;
|
||||
}
|
||||
value = inb(port) & ~(1 << IRQline);
|
||||
outb(port, value);
|
||||
}
|
||||
|
||||
void pic_init(void)
|
||||
{
|
||||
DEBUG_INFO("Initializing PIC");
|
||||
|
||||
unsigned char a1, a2;
|
||||
|
||||
a1 = inb(PIC1_DATA); // save masks
|
||||
a2 = inb(PIC2_DATA);
|
||||
|
||||
outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); // starts the initialization sequence (in cascade mode)
|
||||
io_wait();
|
||||
outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||
io_wait();
|
||||
|
||||
DEBUG_INFO("Setting PIC 1 IRQ offset to 32");
|
||||
outb(PIC1_DATA, 0x20); // ICW2: Master PIC vector offset
|
||||
io_wait();
|
||||
|
||||
DEBUG_INFO("Setting PIC 2 IRQ offset to 40");
|
||||
outb(PIC2_DATA, 0x28); // ICW2: Slave PIC vector offset
|
||||
io_wait();
|
||||
outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
|
||||
io_wait();
|
||||
outb(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010)
|
||||
io_wait();
|
||||
|
||||
outb(PIC1_DATA, ICW4_8086); // ICW4: have the PICs use 8086 mode (and not 8080 mode)
|
||||
io_wait();
|
||||
outb(PIC2_DATA, ICW4_8086);
|
||||
io_wait();
|
||||
|
||||
outb(PIC1_DATA, a1); // restore saved masks.
|
||||
outb(PIC2_DATA, a2);
|
||||
|
||||
DEBUG_INFO("Setting all IRQs to be masked");
|
||||
for (unsigned char i = 0; i < 16; i++)
|
||||
{
|
||||
IRQ_set_mask(i);
|
||||
}
|
||||
|
||||
DEBUG_INFO("Unmasking IRQ 1 - Keyboard");
|
||||
IRQ_clear_mask(1);
|
||||
|
||||
DEBUG_INFO("PIC initialized");
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef PIC_CONTROLER_H
|
||||
#define PIC_CONTROLER_H
|
||||
|
||||
void PIC_sendEOI(unsigned char irq);
|
||||
void pic_init(void);
|
||||
|
||||
#endif /* !PIC_CONTROLER_H */
|
|
@ -0,0 +1,88 @@
|
|||
#include "serial.h"
|
||||
|
||||
#include "io.h"
|
||||
|
||||
#define PORT 0x3f8 // COM1
|
||||
|
||||
int strlen(char *str)
|
||||
{
|
||||
int i = 0;
|
||||
while (str[i++] != '\0');
|
||||
return i;
|
||||
}
|
||||
|
||||
int init_serial()
|
||||
{
|
||||
outb(PORT + 1, 0x00); // Disable all interrupts
|
||||
outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
|
||||
outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
||||
outb(PORT + 1, 0x00); // (hi byte)
|
||||
outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit
|
||||
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
||||
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
||||
}
|
||||
|
||||
int write_serial_nb(int nb, int ln)
|
||||
{
|
||||
if (nb < 10)
|
||||
{
|
||||
while ((inb(PORT + 5) & 0x20) == 0);
|
||||
outb(PORT, nb + '0');
|
||||
return 0;
|
||||
}
|
||||
|
||||
write_serial_nb(nb / 10, false);
|
||||
|
||||
while ((inb(PORT + 5) & 0x20) == 0);
|
||||
outb(PORT, nb % 10 + '0');
|
||||
|
||||
if (ln)
|
||||
{
|
||||
while ((inb(PORT + 5) & 0x20) == 0);
|
||||
outb(PORT, '\n');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_serial_bin(int nb, int ln)
|
||||
{
|
||||
if (nb < 2)
|
||||
{
|
||||
while ((inb(PORT + 5) & 0x20) == 0);
|
||||
outb(PORT, nb + '0');
|
||||
return 0;
|
||||
}
|
||||
|
||||
write_serial_bin(nb / 2, false);
|
||||
|
||||
while ((inb(PORT + 5) & 0x20) == 0);
|
||||
outb(PORT, nb % 2 + '0');
|
||||
|
||||
if (ln)
|
||||
{
|
||||
while ((inb(PORT + 5) & 0x20) == 0);
|
||||
outb(PORT, '\n');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_serial_char(char c)
|
||||
{
|
||||
while ((inb(PORT + 5) & 0x20) == 0);
|
||||
outb(PORT, c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_serial(char * s)
|
||||
{
|
||||
for (size_t i = 0; i < strlen(s); i++)
|
||||
{
|
||||
while ((inb(PORT + 5) & 0x20) == 0);
|
||||
outb(PORT, s[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef SERIAL_H
|
||||
#define SERIAL_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
int init_serial();
|
||||
int write_serial(char *s);
|
||||
int write_serial_nb(int nb, bool ln);
|
||||
int write_serial_bin(int nb, int ln);
|
||||
int write_serial_char(char c);
|
||||
|
||||
#endif /* SERIAL_H */
|
|
@ -0,0 +1,26 @@
|
|||
#include "syscall.h"
|
||||
#include "debug.h"
|
||||
#include "serial.h"
|
||||
|
||||
/*
|
||||
* Syscall handler for write, currently only serial write is supported.
|
||||
* Use the fd 1, to make a serial write.
|
||||
*/
|
||||
int write(int fd, void *buf)
|
||||
{
|
||||
if (fd != 1)
|
||||
return -1;
|
||||
|
||||
if (write_serial(buf))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Syscall handler for keyboard input, this function is currently not implemented.
|
||||
*/
|
||||
int keyboard(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef SYSCALL_H
|
||||
#define SYSCALL_H
|
||||
|
||||
int write(int fd, void *buf);
|
||||
int keyboard(void);
|
||||
|
||||
#endif /* !SYSCALL_H */
|
|
@ -0,0 +1,52 @@
|
|||
#ifndef TSS_H
|
||||
#define TSS_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
struct tss
|
||||
{
|
||||
u16 previous_task;
|
||||
u16 reserved_1;
|
||||
u32 esp0;
|
||||
u16 ss0;
|
||||
u16 reserved_2;
|
||||
u32 esp1;
|
||||
u16 ss1;
|
||||
u16 reserved_3;
|
||||
u32 esp2;
|
||||
u16 ss2;
|
||||
u16 reserved_4;
|
||||
u32 cr3;
|
||||
u32 eip;
|
||||
u32 eflags;
|
||||
u32 eax;
|
||||
u32 ecx;
|
||||
u32 edx;
|
||||
u32 ebx;
|
||||
u32 esp;
|
||||
u32 ebp;
|
||||
u32 esi;
|
||||
u32 edi;
|
||||
u16 es;
|
||||
u16 reserved_5;
|
||||
u16 cs;
|
||||
u16 reserved_6;
|
||||
u16 ss;
|
||||
u16 reserved_7;
|
||||
u16 ds;
|
||||
u16 reserved_8;
|
||||
u16 fs;
|
||||
u16 reserved_9;
|
||||
u16 gs;
|
||||
u16 reserved_10;
|
||||
u16 lst_seg_select;
|
||||
u16 reserved_11;
|
||||
u16 t_bitmap : 1;
|
||||
u16 reserved_12 : 15;
|
||||
u16 io_map_base_address;
|
||||
u32 ssp;
|
||||
} __attribute__((packed));
|
||||
|
||||
extern struct tss user_land_tss;
|
||||
|
||||
#endif /* !TSS_H */
|
|
@ -0,0 +1,26 @@
|
|||
#include "userland.h"
|
||||
|
||||
void userland(void)
|
||||
{
|
||||
int res = 0;
|
||||
// asm ("mov $1, %0" : "=r" (res));
|
||||
// asm volatile ("movl $2, %eax; int $0x30");
|
||||
// asm("movl %%eax,%0" : "=r"(res));
|
||||
// asm volatile ("int $0x30");
|
||||
char *str = (void *) 0x100;
|
||||
str[0] = 'H';
|
||||
str[1] = 'e';
|
||||
str[2] = 'l';
|
||||
str[3] = 'l';
|
||||
str[4] = 'o';
|
||||
str[5] = '\0';
|
||||
asm volatile ("mov $1, %%eax; movl $0x30100, %%ebx; int $0x30; movl %%eax, %0" : "=r" (res));
|
||||
// asm volatile ("mov $1, %%eax; movl %0, %%ebx; int $0x30" : "=m" (str));
|
||||
// asm ("mov $1, %eax; int $0x30");
|
||||
// asm ("movl %0, %eax; int $0x30" : "=m" (res));
|
||||
// asm ("movl %eax, %eax; int $0x30");
|
||||
// asm ("movl $28, %eax; movl $5, %ebx; int $0x30");
|
||||
// asm ("movl $43, %eax; movl $7, %ebx; int $0x30");
|
||||
while (1);
|
||||
return; /* never go there */
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef USERLAND_H
|
||||
#define USERLAND_H
|
||||
|
||||
void userland(void);
|
||||
|
||||
#endif /* !USERLAND_H */
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
|
||||
mkdir -p iso/boot/grub
|
||||
echo "menuentry \"kernel\" {
|
||||
multiboot /kernel
|
||||
}" > iso/boot/grub/grub.cfg
|
||||
|
||||
grub-mkrescue -o kernel.iso iso
|
Loading…
Reference in New Issue