mirror of
https://github.com/ZeroOSProject/ZeroOS.git
synced 2026-09-13 02:24:42 +08:00
vi and busybox
This commit is contained in:
+346
@@ -0,0 +1,346 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
mod console;
|
||||
mod drivers;
|
||||
mod efi;
|
||||
mod elf;
|
||||
mod font;
|
||||
mod framebuffer;
|
||||
mod fs;
|
||||
mod gdt;
|
||||
mod interrupts;
|
||||
mod io;
|
||||
mod ipc;
|
||||
mod log;
|
||||
mod memory;
|
||||
mod paging;
|
||||
mod services;
|
||||
mod syscall;
|
||||
mod task;
|
||||
mod tty;
|
||||
mod user;
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
use efi::{EFI_SUCCESS, EfiHandle, EfiStatus, EfiSystemTable};
|
||||
use framebuffer::Framebuffer;
|
||||
use memory::PhysicalMemoryManager;
|
||||
use paging::{AddressSpace, PageFlags};
|
||||
use tty::Tty;
|
||||
|
||||
static mut MEMORY_MAP_BUFFER: [u8; 65536] = [0; 65536];
|
||||
static mut PHYSICAL_MEMORY: PhysicalMemoryManager = PhysicalMemoryManager::new();
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "efiapi" fn efi_main(
|
||||
image_handle: EfiHandle,
|
||||
system_table: *mut EfiSystemTable,
|
||||
) -> EfiStatus {
|
||||
unsafe {
|
||||
io::disable_interrupts();
|
||||
|
||||
let Some(boot_services) = efi::boot_services(system_table) else {
|
||||
halt_forever();
|
||||
};
|
||||
|
||||
let Some(gop) = efi::locate_gop(boot_services) else {
|
||||
halt_forever();
|
||||
};
|
||||
|
||||
let Some(framebuffer) = Framebuffer::from_gop(gop) else {
|
||||
halt_forever();
|
||||
};
|
||||
|
||||
let mut tty = Tty::new(framebuffer);
|
||||
tty.clear();
|
||||
console::init(&raw mut tty);
|
||||
let mut logger = log::KernelLogger::new(&mut tty);
|
||||
logger.info(b"ZeroOS kernel initializing");
|
||||
|
||||
drivers::platform::pic::remap_and_mask_all();
|
||||
logger.ok(b"pic");
|
||||
|
||||
if let Some(unix_seconds) = efi::read_unix_time(system_table) {
|
||||
drivers::platform::timer::set_wall_clock_boot_time(unix_seconds);
|
||||
logger.ok(b"UEFI time");
|
||||
} else {
|
||||
logger.info(b"UEFI time unavailable");
|
||||
}
|
||||
|
||||
let Some(memory_map) = efi::get_memory_map(
|
||||
boot_services,
|
||||
(&raw mut MEMORY_MAP_BUFFER).cast::<u8>(),
|
||||
65536,
|
||||
) else {
|
||||
halt_forever();
|
||||
};
|
||||
logger.ok(b"UEFI memory map");
|
||||
|
||||
let memory = &mut *(&raw mut PHYSICAL_MEMORY);
|
||||
task::init();
|
||||
memory.init_from_uefi_memory_map(memory_map);
|
||||
let stats = memory.stats();
|
||||
let _ = (stats.total_pages, stats.free_pages, stats.used_pages);
|
||||
logger.ok(b"physical memory manager");
|
||||
|
||||
fs::vfs::init();
|
||||
logger.ok(b"vfs");
|
||||
ipc::init();
|
||||
logger.ok(b"ipc");
|
||||
|
||||
let ahci_disks = drivers::storage::ahci::init(memory);
|
||||
let mut ext4_user_image = None;
|
||||
let mut ext4_user_path = None;
|
||||
if ahci_disks > 0 {
|
||||
logger.ok(b"ahci");
|
||||
if let Some(mut disk) = drivers::storage::ahci::first_disk() {
|
||||
match drivers::storage::partition::find_linux_partition(&mut disk) {
|
||||
Ok(partition) => {
|
||||
let mut root =
|
||||
drivers::storage::partition::PartitionBlockDevice::new(disk, partition);
|
||||
match fs::ext4::mount(&mut root) {
|
||||
Ok(ext4) => {
|
||||
logger.ok(b"ext4");
|
||||
let _ = fs::ext4::mount_vfs_tree(&mut root, &ext4);
|
||||
fs::ext4::register_root(root, ext4);
|
||||
match fs::ext4::load_path(
|
||||
&mut root,
|
||||
&ext4,
|
||||
memory,
|
||||
b"/usr/bin/busybox",
|
||||
) {
|
||||
Ok(image) => {
|
||||
ext4_user_image = Some(image);
|
||||
ext4_user_path = Some(b"/usr/bin/busybox" as &'static [u8]);
|
||||
logger.ok(b"ext4 /usr/bin/busybox");
|
||||
}
|
||||
Err(_) => match fs::ext4::load_path(
|
||||
&mut root,
|
||||
&ext4,
|
||||
memory,
|
||||
b"/usr/bin/sh",
|
||||
) {
|
||||
Ok(image) => {
|
||||
ext4_user_image = Some(image);
|
||||
ext4_user_path = Some(b"/usr/bin/sh" as &'static [u8]);
|
||||
logger.ok(b"ext4 /usr/bin/sh");
|
||||
}
|
||||
Err(_) => logger.info(b"ext4 userspace not loaded"),
|
||||
},
|
||||
}
|
||||
}
|
||||
Err(_) => logger.info(b"ext4 not mounted"),
|
||||
}
|
||||
}
|
||||
Err(_) => logger.info(b"no linux gpt partition"),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.info(b"no ahci disk");
|
||||
}
|
||||
|
||||
let (loaded_user_image, loaded_user_path) = if let Some(image) = ext4_user_image {
|
||||
(Some(image), ext4_user_path)
|
||||
} else if let Some(image) =
|
||||
fs::uefi::load_file(image_handle, boot_services, memory, fs::uefi::BASH_PATH)
|
||||
{
|
||||
(Some(image), Some(b"/bin/bash" as &'static [u8]))
|
||||
} else if let Some(image) =
|
||||
fs::uefi::load_file(image_handle, boot_services, memory, fs::uefi::SH_PATH)
|
||||
{
|
||||
(Some(image), Some(b"/bin/sh" as &'static [u8]))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
let userspace_image_found = loaded_user_image.is_some();
|
||||
if loaded_user_image.is_some() {
|
||||
if let (Some(image), Some(path)) = (&loaded_user_image, loaded_user_path) {
|
||||
let _ = fs::vfs::mount_static_file(path, image.ptr, image.len);
|
||||
let _ = fs::vfs::mount_static_file(b"/usr/bin/busybox", image.ptr, image.len);
|
||||
let _ = fs::vfs::mount_static_file(b"/bin/busybox", image.ptr, image.len);
|
||||
let _ = fs::vfs::mount_static_file(b"/usr/bin/sh", image.ptr, image.len);
|
||||
let _ = fs::vfs::mount_static_file(b"/usr/bin/bash", image.ptr, image.len);
|
||||
let _ = fs::vfs::mount_static_file(b"/bin/sh", image.ptr, image.len);
|
||||
let _ = fs::vfs::mount_static_file(b"/bin/bash", image.ptr, image.len);
|
||||
}
|
||||
logger.ok(b"userspace image loaded from esp");
|
||||
} else {
|
||||
logger.info(b"no /bin/bash or /bin/sh on esp, using built-in user program");
|
||||
}
|
||||
|
||||
gdt::init();
|
||||
logger.ok(b"gdt");
|
||||
|
||||
if interrupts::init(memory).is_none() {
|
||||
halt_forever();
|
||||
}
|
||||
logger.ok(b"idt");
|
||||
|
||||
drivers::platform::timer::init();
|
||||
logger.ok(b"pit timer");
|
||||
|
||||
drivers::input::ps2::init();
|
||||
logger.ok(b"ps/2 keyboard");
|
||||
|
||||
let Some(mut address_space) = AddressSpace::new_kernel(memory) else {
|
||||
halt_forever();
|
||||
};
|
||||
logger.ok(b"address space");
|
||||
|
||||
let mut userspace_program = None;
|
||||
let user_entry = if let Some(image) = loaded_user_image {
|
||||
match elf::load_user_elf(&image, memory) {
|
||||
Some(program) => {
|
||||
logger.ok(b"elf userspace program");
|
||||
userspace_program = Some(user::UserAux {
|
||||
entry: program.entry,
|
||||
phdr: program.phdr,
|
||||
phent: program.phent,
|
||||
phnum: program.phnum,
|
||||
});
|
||||
Some(program.entry)
|
||||
}
|
||||
None => {
|
||||
logger.info(b"elf load failed, using built-in user program");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let Some(test_page) = memory.alloc_page() else {
|
||||
halt_forever();
|
||||
};
|
||||
if address_space
|
||||
.map_page(
|
||||
memory,
|
||||
0xffff_8000_0000_0000,
|
||||
test_page as u64,
|
||||
PageFlags::WRITABLE,
|
||||
)
|
||||
.is_none()
|
||||
{
|
||||
halt_forever();
|
||||
}
|
||||
let _ = address_space.translate(0xffff_8000_0000_0000);
|
||||
let _ = address_space.unmap_page(0xffff_8000_0000_0000);
|
||||
memory.free_page(test_page);
|
||||
let _ = (address_space.root_table(), address_space.identity_tables());
|
||||
logger.ok(b"paging smoke test");
|
||||
|
||||
let Some(final_memory_map) = efi::get_memory_map(
|
||||
boot_services,
|
||||
(&raw mut MEMORY_MAP_BUFFER).cast::<u8>(),
|
||||
65536,
|
||||
) else {
|
||||
logger.info(b"final UEFI memory map failed");
|
||||
halt_forever();
|
||||
};
|
||||
logger.ok(b"final UEFI memory map");
|
||||
|
||||
let exit_status = ((*boot_services).exit_boot_services)(image_handle, final_memory_map.key);
|
||||
if exit_status != EFI_SUCCESS {
|
||||
logger.info(b"exit boot services failed");
|
||||
halt_forever();
|
||||
}
|
||||
logger.ok(b"exit boot services");
|
||||
|
||||
address_space.activate();
|
||||
logger.ok(b"cr3");
|
||||
tty.clear();
|
||||
if user_entry.is_some() {
|
||||
if loaded_user_path == Some(b"/usr/bin/busybox" as &'static [u8]) {
|
||||
console::write(b"enter userspace: /usr/bin/busybox sh\r\n");
|
||||
} else if loaded_user_path == Some(b"/usr/bin/sh" as &'static [u8]) {
|
||||
console::write(b"enter userspace: /usr/bin/sh\r\n");
|
||||
} else if loaded_user_path == Some(b"/usr/bin/bash" as &'static [u8]) {
|
||||
console::write(b"enter userspace: /usr/bin/bash\r\n");
|
||||
} else {
|
||||
console::write(b"enter userspace: /bin/bash\r\n");
|
||||
}
|
||||
} else if userspace_image_found {
|
||||
console::write(b"/bin/bash found but ELF load failed; enter built-in userspace\r\n");
|
||||
} else {
|
||||
console::write(b"/bin/bash not found on ESP; enter built-in userspace\r\n");
|
||||
}
|
||||
syscall::init(memory, &raw mut address_space);
|
||||
io::enable_interrupts();
|
||||
if let Some(entry) = user_entry {
|
||||
if loaded_user_path == Some(b"/usr/bin/busybox" as &'static [u8]) {
|
||||
user::enter_elf_with_args(
|
||||
entry,
|
||||
&[b"/usr/bin/busybox", b"sh"],
|
||||
user_program_or_default(user_entry, userspace_program),
|
||||
);
|
||||
} else if loaded_user_path == Some(b"/usr/bin/sh" as &'static [u8]) {
|
||||
user::enter_elf_with_args(
|
||||
entry,
|
||||
&[b"/usr/bin/sh"],
|
||||
user_program_or_default(user_entry, userspace_program),
|
||||
);
|
||||
} else if loaded_user_path == Some(b"/usr/bin/bash" as &'static [u8]) {
|
||||
user::enter_elf_with_args(
|
||||
entry,
|
||||
&[b"/usr/bin/bash"],
|
||||
user_program_or_default(user_entry, userspace_program),
|
||||
);
|
||||
} else if loaded_user_path == Some(b"/bin/sh" as &'static [u8]) {
|
||||
user::enter_elf_with_args(
|
||||
entry,
|
||||
&[b"/bin/sh"],
|
||||
user_program_or_default(user_entry, userspace_program),
|
||||
);
|
||||
} else {
|
||||
user::enter_elf_with_args(
|
||||
entry,
|
||||
&[b"/bin/bash"],
|
||||
user_program_or_default(user_entry, userspace_program),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
user::enter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn kernel_loop(tty: &mut Tty) -> ! {
|
||||
loop {
|
||||
while let Some(ch) = drivers::input::ps2::read_char() {
|
||||
match ch {
|
||||
0x08 => tty.backspace(),
|
||||
b'\r' => tty.write_bytes(b"\r\n"),
|
||||
ch => tty.put_char(ch),
|
||||
}
|
||||
}
|
||||
halt();
|
||||
}
|
||||
}
|
||||
|
||||
fn halt() {
|
||||
unsafe {
|
||||
core::arch::asm!("hlt", options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
|
||||
fn user_program_or_default(entry: Option<u64>, aux: Option<user::UserAux>) -> user::UserAux {
|
||||
aux.unwrap_or(user::UserAux {
|
||||
entry: entry.unwrap_or(0),
|
||||
phdr: 0,
|
||||
phent: 0,
|
||||
phnum: 0,
|
||||
})
|
||||
}
|
||||
|
||||
fn halt_forever() -> ! {
|
||||
loop {
|
||||
halt();
|
||||
}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo) -> ! {
|
||||
halt_forever();
|
||||
}
|
||||
Reference in New Issue
Block a user