Skip to content

Commit

Permalink
amd64 "port" boots and prints "Hello World" to debug
Browse files Browse the repository at this point in the history
  • Loading branch information
thepowersgang committed Jan 26, 2015
1 parent 7b8d06d commit af7c1f3
Show file tree
Hide file tree
Showing 7 changed files with 316 additions and 23 deletions.
32 changes: 23 additions & 9 deletions Kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ARCH ?= amd64
RUSTC ?= rustc
ifeq ($(ARCH),amd64)
LD := x86_64-elf-ld
LD := x86_64-elf-ld
AS := x86_64-elf-as
OBJDUMP := x86_64-elf-objdump
else ifeq ($(ARCH),x86)
LD := i586-elf-ld
Expand All @@ -22,31 +22,45 @@ OBJDIR := .obj/$(ARCH)/
# Compiler Options
LINKFLAGS := -T arch/$(ARCH)/link.ld
LINKFLAGS += -Map $(OBJDIR)map.txt
LINKFLAGS += -z max-page-size=0x1000
RUSTFLAGS := -O --cfg arch__$(ARCH) --target=arch/$(ARCH)/target.json

# Objects
LIBCORE := $(OBJDIR)libcore.rlib
OBJS := start.o kernel.o libcore.rlib

OBJS := $(OBJS:%=$(OBJDIR)%)
BIN := ../kernel.$(ARCH).bin

.PHONY: all clean

all: ../kernel.$(ARCH).bin

clean:
$(RM) -rf ../kernel.$(ARCH).bin $(OBJDIR)
$(RM) -rf $(BIN) $(BIN).dsm $(OBJDIR)

../kernel.$(ARCH).bin: $(OBJS) arch/$(ARCH)/link.ld
# Final link command
$(BIN): $(OBJS) arch/$(ARCH)/link.ld
$(LD) -o $@ $(LINKFLAGS) $(OBJS)
$(OBJDUMP) -S $@ > $@.dsm
ifeq ($(ARCH),amd64)
@mv $@ [email protected]
@x86_64-elf-objcopy [email protected] -F elf32-i386 $@
endif

$(OBJDIR)libcore.rlib: ../libcore/lib.rs
# Compile libcore from ../libcore/
$(OBJDIR)libcore.rlib: ../libcore/lib.rs Makefile
@mkdir -p $(dir $@)
$(RUSTC) $(RUSTFLAGS) -o $@ --crate-type=lib $<
$(RUSTC) $(RUSTFLAGS) -o $@ --crate-type=lib --emit=link,dep-info $<

$(OBJDIR)kernel.o: main.rs $(LIBCORE)
# Compile rust kernel object
$(OBJDIR)kernel.o: main.rs $(LIBCORE) Makefile
@mkdir -p $(dir $@)
$(RUSTC) $(RUSTFLAGS) -o $@ --emit=obj $< --extern core=$(LIBCORE)
$(RUSTC) $(RUSTFLAGS) -o $@ --emit=obj,dep-info $< --extern core=$(LIBCORE)

$(OBJDIR)start.o: arch/$(ARCH)/start.S
# Compile architecture's assembly stub
$(OBJDIR)start.o: arch/$(ARCH)/start.S Makefile
@mkdir -p $(dir $@)
$(AS) $(ASFLAGS) -o $@ $<

# Include dependency files
-include $(OBJ:%=%.d)
43 changes: 43 additions & 0 deletions Kernel/arch/amd64/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Rust BareBones OS
* - By John Hodge (Mutabah/thePowersGang)
*
* arch/amd64/debug.rs
* - Debug output channel
*
* Writes debug to the standard PC serial port (0x3F8 .. 0x3FF)
*
* == LICENCE ==
* This code has been put into the public domain, there are no restrictions on
* its use, and the author takes no liability.
*/
use prelude::*;

/// Write a string to the output channel
///
/// This method is unsafe because it does port accesses without synchronisation
pub unsafe fn puts(s: &str)
{
for b in s.bytes()
{
putb(b);
}
}

/// Write a single byte to the output channel
///
/// This method is unsafe because it does port accesses without synchronisation
pub unsafe fn putb(b: u8)
{
// Wait for the serial port's fifo to not be empty
while (::arch::x86_io::inb(0x3F8+5) & 0x20) == 0
{
// Do nothing
}
// Send the byte out the serial port
::arch::x86_io::outb(0x3F8, b);

// Also send to the bochs 0xe9 hack
::arch::x86_io::outb(0xe9, b);
}

24 changes: 15 additions & 9 deletions Kernel/arch/amd64/link.ld
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
ENTRY(start)
OUTPUT_FORMAT(elf32-i386)
OUTPUT_FORMAT(elf64-x86-64)

KERNEL_BASE = 0xFFFFFFFF80000000;

SECTIONS {
.multiboot : AT(ADDR(.multiboot)) {
. = 0x100000;

. += SIZEOF_HEADERS;

.init : AT(ADDR(.init)) {
*(.multiboot)
*(.inittext)
}

. += KERNEL_BASE;

.text : AT(ADDR(.text) - KERNEL_BASE) {
.text ALIGN(0x1000) : AT(ADDR(.text) - KERNEL_BASE) {
*(.text .text.*)
}

/* read-only data, page aligned to allow use of the no-execute feature */
. = ALIGN(0x1000);
.rodata : AT(ADDR(.rodata) - KERNEL_BASE) {
.rodata ALIGN(0x1000) : AT(ADDR(.rodata) - KERNEL_BASE) {
*(.rodata .rodata.*)
}

/* Read-write data, page aligned for the .padata section */
. = ALIGN(0x1000);
.data : AT(ADDR(.data) - KERNEL_BASE) {
.data ALIGN(0x1000) : AT(ADDR(.data) - KERNEL_BASE) {
*(.padata)
*(.data .data.*)
}
Expand All @@ -32,7 +35,10 @@ SECTIONS {
*(.bss .bss.*)
}

. = ALIGN(0x1000);
kernel_end = .;

/DISCARD/ : {
*(.note .note.*)
}
}

18 changes: 18 additions & 0 deletions Kernel/arch/amd64/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Rust BareBones OS
* - By John Hodge (Mutabah/thePowersGang)
*
* arch/amd64/mod.rs
* - Top-level file for amd64 architecture
*
* == LICENCE ==
* This code has been put into the public domain, there are no restrictions on
* its use, and the author takes no liability.
*/

// x86 port IO
mod x86_io;

// Debug output channel (uses serial)
pub mod debug;

162 changes: 157 additions & 5 deletions Kernel/arch/amd64/start.S
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ MULTIBOOT_REQVIDMODE = (1<<2)
MULTIBOOT_HEADER_MAGIC = 0x1BADB002
MULTIBOOT_HEADER_FLAGS = (MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_REQVIDMODE)
MULTIBOOT_CHECKSUM = -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
.section .multiboot
.section .multiboot, "a"
.globl mboot
mboot:
.long MULTIBOOT_HEADER_MAGIC
Expand All @@ -35,15 +35,167 @@ mboot:
.long 0 /* Height (no preference) */
.long 32 /* Depth (32-bit preferred) */

#define DEBUG(c) mov $0x3f8, %dx ; mov $c, %al ; outb %al, %dx

/* === Code === */
.section .text
.section .inittext, "ax"
.globl start
.code32
start:
// The kernel starts in protected mode (32-bit mode, we want to switch to long mode)
.l:
jmp .l
/* The kernel starts in protected mode (32-bit mode, we want to switch to long mode) */

/* 1. Save multiboot state */
mov %eax, mboot_sig - KERNEL_BASE
mov %ebx, mboot_ptr - KERNEL_BASE

/* 2. Ensure that the CPU support long mode */
mov $0x80000000, %eax
cpuid
/* - Check if CPUID supports the field we want to query */
cmp $0x80000001, %eax
jbe not64bitCapable
/* - Test the IA-32e bit */
mov $0x80000001, %eax
cpuid
test $0x20000000, %edx /* bit 29 = */
jz not64bitCapable

/* 3. Set up state for long mode */
/* Enable:
PGE (Page Global Enable)
+ PAE (Physical Address Extension)
+ PSE (Page Size Extensions)
*/
mov %cr4, %eax
or $(0x80|0x20|0x10), %eax
mov %eax, %cr4

/* Load PDP4 */
mov $(init_pml4 - KERNEL_BASE), %eax
mov %eax, %cr3

/* Enable IA-32e mode (Also enables SYSCALL and NX) */
mov $0xC0000080, %ecx
rdmsr
or $(1 << 11)|(1 << 8)|(1 << 0), %eax /* NXE, LME, SCE */
wrmsr

/* Enable paging and enter long mode */
mov %cr0, %eax
or $0x80010000, %eax /* PG & WP */
mov %eax, %cr0
lgdt GDTPtr_low - KERNEL_BASE
ljmp $0x08, $start64


not64bitCapable:
/* If the CPU isn't 64-bit capable, print a message to serial/b8000 then busy wait */
mov $0x3f8, %dx
mov $'N', %al ; outb %al, %dx
movw $0x100|'N', 0xb8000
mov $'o', %al ; outb %al, %dx
movw $0x100|'o', 0xb8002
mov $'t', %al ; outb %al, %dx
movw $0x100|'t', 0xb8004
mov $'6', %al ; outb %al, %dx
movw $0x100|'6', 0xb8006
mov $'4', %al ; outb %al, %dx
movw $0x100|'4', 0xb8008

not64bitCapable.loop:
hlt
jmp not64bitCapable.loop
.code64
.globl start64
start64:
/* Running in 64-bit mode, jump to high memory */
lgdt GDTPtr
mov $start64_high, %rax
jmp *%rax

.section .text
.extern kmain
.globl start64_high
start64_high:
/* and clear low-memory mapping */
mov $0, %rax
mov %rax, init_pml4 - KERNEL_BASE + 0

/* Set up segment registers */
mov $0x10, %ax
mov %ax, %ss
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs

/* Set up stack pointer */
mov $init_stack, %rsp

/* call the rust code */
call kmain

/* and if that returns (it shouldn't) loop forever */
start64.loop:
hlt
jmp start64.loop



/* === Page-aligned data === */
.section .padata
/* Initial paging structures, four levels */
/* The +3 for sub-pages indicates "present (1) + writable (2)" */
init_pml4:
.quad low_pdpt - KERNEL_BASE + 3 /* low map for startup, will be cleared before rust code runs */
.rept 512 - 3
.quad 0
.endr
.quad 0 /* If you so wish, this is a good place for the "Fractal" mapping */
.quad init_pdpt - KERNEL_BASE + 3 /* Final mapping */
low_pdpt:
.quad init_pd - KERNEL_BASE + 3 /* early init identity map */
.rept 512 - 1
.quad 0
.endr
init_pdpt: /* covers the top 512GB, 1GB each entry */
.rept 512 - 2
.quad 0
.endr
.quad init_pd - KERNEL_BASE + 3 /* at -2GB, identity map the kernel image */
.quad 0
init_pd:
/* 0x80 = Page size extension */
.quad 0x000000 + 0x80 + 3 /* Map 2MB, enough for a 1MB kernel */
.quad 0x200000 + 0x80 + 3 /* - give it another 2MB, just in case */
.rept 512 - 2
.quad 0
.endr
init_stack_base:
.rept 0x1000 * 2
.byte 0
.endr
init_stack:

/* === General Data === */
.section .data
mboot_sig: .long 0
mboot_ptr: .long 0

/* Global Descriptor Table */
GDTPtr_low:
.word GDT - GDTEnd
.long GDT - KERNEL_BASE
GDTPtr:
.word GDT - GDTEnd
.quad GDT
.globl GDT
GDT:
.long 0, 0
.long 0x00000000, 0x00209A00 /* 0x08: 64-bit Code */
.long 0x00000000, 0x00009200 /* 0x10: 64-bit Data */
.long 0x00000000, 0x0040FA00 /* 0x18: 32-bit User Code */
.long 0x00000000, 0x0040F200 /* 0x20: User Data */
.long 0x00000000, 0x0020FA00 /* 0x28: 64-bit User Code */
.long 0x00000000, 0x0000F200 /* 0x30: User Data (64 version) */
GDTEnd:
Loading

0 comments on commit af7c1f3

Please sign in to comment.