Skip to content

Commit

Permalink
add basic 32bit support for x86
Browse files Browse the repository at this point in the history
  • Loading branch information
stlankes committed Sep 15, 2024
1 parent 10c85f8 commit 9a7e50e
Show file tree
Hide file tree
Showing 14 changed files with 237 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ target = "x86_64-eduos.json"

[target.i686-eduos]
rustflags = [
"-C", "link-arg=-Tsrc/arch/x86/link_i686.ld", "-C", "relocation-model=static"
"-C", "link-arg=-Tsrc/arch/x86/kernel/link_i686.ld", "-C", "relocation-model=static"
]
runner = "qemu-system-x86_64 -display none -serial stdio -smp 1 -m 256M -device isa-debug-exit,iobase=0xf4,iosize=0x04 -kernel"

Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ jobs:
run: cargo --version
- name: Install bootimage
run: cargo install bootimage
- name: Build
- name: Build (x86_64)
run:
cargo build
- name: Build (i686)
run:
cargo build --target=i686-eduos.json
- name: run (ubuntu)
if: ${{ matrix.os == 'ubuntu-latest' }}
run: ./test.sh
Expand Down
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 4 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ default = ["qemu-exit"]
spin = "0.9"
simple-chunk-allocator = "0.1.5"
qemu-exit = { version = "3.0", optional = true }
bootloader = "0.9.29"

[target.'cfg(target_arch = "x86_64")'.dependencies.x86]
version = "0.52"
default-features = false
x86 = { version = "0.52", default-features = false }
cfg-if = "1.0"

[target.'cfg(target_arch = "x86_64")'.dependencies]
bootloader = "0.9.29"
14 changes: 14 additions & 0 deletions i686-eduos.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"llvm-target": "i686-unknown-none",
"target-endian": "little",
"target-pointer-width": "32",
"target-c-int-width": "32",
"os": "none",
"arch": "x86",
"data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128",
"features": "-mmx,-sse,+soft-float",
"executables": true,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"panic-strategy": "abort"
}
6 changes: 5 additions & 1 deletion src/arch/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
// Implementations for x86_64.
/// Currently, eduOS supports only x86_64 (64 bit)
/// and x86 (32 bit) code. Both architecture are similar
/// and share the code in the directory x86

// Implementations for x86_64 and x86.
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
pub mod x86;

Expand Down
54 changes: 54 additions & 0 deletions src/arch/x86/kernel/entry32.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# This is the kernel's entry point. We could either call main here,
# or we can use this to setup the stack or other nice stuff, like
# perhaps setting up the GDT and segments. Please note that interrupts
# are disabled at this point: More on interrupts later!

.code32

.set BOOT_STACK_SIZE, 4096

# We use a special name to map this section at the begin of our kernel
# => Multiboot expects its magic number at the beginning of the kernel.
.section .mboot, "a"

# This part MUST be 4 byte aligned, so we solve that issue using '.align 4'.
.align 4
mboot:
# Multiboot macros to make a few lines more readable later
.set MULTIBOOT_PAGE_ALIGN, (1 << 0)
.set MULTIBOOT_MEMORY_INFO, (1 << 1)
.set MULTIBOOT_HEADER_MAGIC, 0x1BADB002
.set MULTIBOOT_HEADER_FLAGS, MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
.set MULTIBOOT_CHECKSUM, -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)

# This is the GRUB Multiboot header. A boot signature
.4byte MULTIBOOT_HEADER_MAGIC
.4byte MULTIBOOT_HEADER_FLAGS
.4byte MULTIBOOT_CHECKSUM
.4byte 0, 0, 0, 0, 0 # address fields

.section .text
.align 4
.extern main
.extern shutdown
.global _start
_start:
cli # avoid any interrupt

# Initialize stack pointer
mov esp, OFFSET BOOT_STACK
add esp, BOOT_STACK_SIZE - 16

call main
# eax has the return value of main
push eax
call shutdown
L0:
hlt
jmp L0

.section .data
.align 4096
.global BOOT_STACK
BOOT_STACK:
.fill BOOT_STACK_SIZE, 1, 0xcd
27 changes: 27 additions & 0 deletions src/arch/x86/kernel/link_i686.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
ENTRY(_start)
phys = 0x000000100000;

SECTIONS
{
kernel_start = phys;
.mboot phys : AT(ADDR(.mboot)) {
KEEP(*(.mboot))
KEEP(*(.mboot.*))
}
.text ALIGN(4096) : AT(ADDR(.text)) {
*(.text)
*(.text.*)
}
.rodata ALIGN(4096) : AT(ADDR(.rodata)) {
*(.rodata)
*(.rodata.*)
}
.data ALIGN(4096) : AT(ADDR(.data)) {
*(.data)
*(.data.*)
}
.bss ALIGN(4096) : AT(ADDR(.bss)) {
*(.bss)
*(.bss.*)
}
}
11 changes: 8 additions & 3 deletions src/arch/x86/kernel/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
pub mod processor;
pub mod serial;
#[cfg(target_arch = "x86_64")]
mod start;
pub mod switch;
pub mod task;
pub(crate) mod switch;
pub(crate) mod task;

#[cfg(target_arch = "x86_64")]
use bootloader::BootInfo;

#[cfg(target_arch = "x86_64")]
pub(crate) static mut BOOT_INFO: Option<&'static BootInfo> = None;

#[cfg(target_arch = "x86")]
core::arch::global_asm!(include_str!("entry32.s"));
21 changes: 21 additions & 0 deletions src/arch/x86/kernel/switch.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::arch::asm;

#[cfg(target_arch = "x86_64")]
macro_rules! save_context {
() => {
concat!(
Expand All @@ -26,6 +27,7 @@ macro_rules! save_context {
};
}

#[cfg(target_arch = "x86_64")]
macro_rules! restore_context {
() => {
concat!(
Expand Down Expand Up @@ -53,6 +55,7 @@ macro_rules! restore_context {
};
}

#[cfg(target_arch = "x86_64")]
#[naked]
pub unsafe extern "C" fn switch(_old_stack: *mut usize, _new_stack: usize) {
// rdi = old_stack => the address to store the old rsp
Expand All @@ -68,3 +71,21 @@ pub unsafe extern "C" fn switch(_old_stack: *mut usize, _new_stack: usize) {
options(noreturn)
);
}

#[cfg(target_arch = "x86")]
pub unsafe extern "C" fn switch(_old_stack: *mut usize, _new_stack: usize) {
asm!(
// store all registers
"pushfd",
"pushad",
// switch stack
"mov edi, [esp+10*4]",
"mov [edi], esp",
"mov esp, [esp+11*4]",
// restore registers
"popad",
"popfd",
"ret",
options(noreturn)
);
}
60 changes: 60 additions & 0 deletions src/arch/x86/kernel/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::scheduler::{do_exit, get_current_taskid};
use core::mem::size_of;
use core::ptr::write_bytes;

#[cfg(target_arch = "x86_64")]
#[repr(C, packed)]
struct State {
/// R15 register
Expand Down Expand Up @@ -48,6 +49,31 @@ struct State {
rip: u64,
}

#[cfg(target_arch = "x86")]
#[repr(C, packed)]
struct State {
/// EDI register
edi: u32,
/// ESI register
esi: u32,
/// EBP register
ebp: u32,
/// (pseudo) ESP register
esp: u32,
/// EBX register
ebx: u32,
/// EDX register
edx: u32,
/// ECX register
ecx: u32,
/// EAX register
eax: u32,
/// status flags
eflags: u32,
/// instruction pointer
eip: u32,
}

extern "C" fn leave_task() -> ! {
debug!("finish task {}", get_current_taskid());

Expand All @@ -59,6 +85,7 @@ extern "C" fn leave_task() -> ! {
}

impl TaskFrame for Task {
#[cfg(target_arch = "x86_64")]
fn create_stack_frame(&mut self, func: extern "C" fn()) {
unsafe {
let mut stack: *mut u64 = ((*self.stack).top()).as_mut_ptr();
Expand Down Expand Up @@ -90,4 +117,37 @@ impl TaskFrame for Task {
self.last_stack_pointer = stack as usize;
}
}

#[cfg(target_arch = "x86")]
fn create_stack_frame(&mut self, func: extern "C" fn()) {
unsafe {
let mut stack: *mut u32 = ((*self.stack).top()).as_mut_ptr();

write_bytes((*self.stack).bottom().as_mut_ptr::<u8>(), 0xCD, STACK_SIZE);

/* Only marker for debugging purposes, ... */
*stack = 0xDEADBEEFu32;
stack = (stack as usize - size_of::<u32>()) as *mut u32;

/* the first-function-to-be-called's arguments, ... */
//TODO: add arguments

/* and the "caller" we shall return to.
* This procedure cleans the task after exit. */
*stack = (leave_task as *const ()) as u32;
stack = (stack as usize - size_of::<State>()) as *mut u32;

let state: *mut State = stack as *mut State;
write_bytes(state, 0x00, 1);

(*state).esp = (stack as usize + size_of::<State>()) as u32;
(*state).ebp = (*state).esp + size_of::<u32>() as u32;

(*state).eip = (func as *const ()) as u32;
(*state).eflags = 0x1002u32;

/* Set the task's stack pointer entry to the stack we have crafted right now. */
self.last_stack_pointer = stack as usize;
}
}
}
34 changes: 29 additions & 5 deletions src/arch/x86/mm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::arch::x86::kernel::BOOT_INFO;
use crate::scheduler::task::Stack;
use bootloader::bootinfo::MemoryRegionType;
use core::ops::Deref;

#[cfg(target_arch = "x86")]
pub use x86::bits32::paging::VAddr as VirtAddr;
#[cfg(target_arch = "x86_64")]
pub use x86::bits64::paging::VAddr as VirtAddr;

#[derive(Copy, Clone)]
Expand All @@ -19,15 +19,26 @@ impl BootStack {

impl Stack for BootStack {
fn top(&self) -> VirtAddr {
self.end - 16u64
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86")] {
self.end - 16u32
} else {
self.end - 16u64
}
}
}

fn bottom(&self) -> VirtAddr {
self.start
}
}

pub fn get_boot_stack() -> BootStack {
#[cfg(target_arch = "x86_64")]
pub(crate) fn get_boot_stack() -> BootStack {
use crate::arch::x86::kernel::BOOT_INFO;
use bootloader::bootinfo::MemoryRegionType;
use core::ops::Deref;

unsafe {
let regions = BOOT_INFO.unwrap().memory_map.deref();

Expand All @@ -43,3 +54,16 @@ pub fn get_boot_stack() -> BootStack {
panic!("Unable to determine the kernel stack");
}
}

#[cfg(target_arch = "x86")]
extern "C" {
static BOOT_STACK: usize;
}

#[cfg(target_arch = "x86")]
pub(crate) fn get_boot_stack() -> BootStack {
BootStack::new(
unsafe { VirtAddr(BOOT_STACK.try_into().unwrap()) },
unsafe { VirtAddr((BOOT_STACK + 0x1000).try_into().unwrap()) },
)
}
3 changes: 1 addition & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ extern crate spin;
extern crate x86;

// These need to be visible to the linker, so we need to export them.
use crate::arch::processor::shutdown;
use crate::consts::HEAP_SIZE;
#[cfg(target_arch = "x86_64")]
use arch::processor::*;
use core::panic::PanicInfo;
pub use logging::*;
use simple_chunk_allocator::{heap, heap_bitmap, GlobalChunkAllocator, PageAligned};
Expand Down
4 changes: 2 additions & 2 deletions src/scheduler/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ impl TaskStack {

impl Stack for TaskStack {
fn top(&self) -> VirtAddr {
VirtAddr::from((&(self.buffer[STACK_SIZE - 16]) as *const _) as u64)
VirtAddr::from((&(self.buffer[STACK_SIZE - 16]) as *const _) as usize)
}

fn bottom(&self) -> VirtAddr {
VirtAddr::from((&(self.buffer[0]) as *const _) as u64)
VirtAddr::from((&(self.buffer[0]) as *const _) as usize)
}
}

Expand Down

0 comments on commit 9a7e50e

Please sign in to comment.