Compare commits

..

17 Commits

Author SHA1 Message Date
Bananymous 31aa157201 Kernel: Don't require framebuffer
Initializes virtual tty only if framebuffer is initialized
2023-10-16 01:44:54 +03:00
Bananymous 5977341610 Kernel: PCI checks if ethernet device is E1000 before initialization
I used to treat all ethernet deivices as E1000 but now it is actually
verified before initialization
2023-10-16 01:44:54 +03:00
Bananymous 76f17bd569 Kernel: PCIDevice stores its vendor id and device id 2023-10-16 01:44:54 +03:00
Bananymous 6b1b3d333c BuildSystem: add cmake variable UEFI_BOOT
If this variable is defined in cmake, image will be build with esp
and booted with uefi.
2023-10-16 01:44:54 +03:00
Bananymous cb65be3e33 Toolchain: Build grub with efi capabilities 2023-10-16 01:37:12 +03:00
Bananymous dafc016293 Kernel: Clear TTY when setting as current
Actually this should replace from old buffer, but this works
for now.
2023-10-13 17:20:26 +03:00
Bananymous c7b6fc950a Kernel: Don't crash if header type != 0 in bar region creation
Also remove spammy debug printing
2023-10-13 16:32:32 +03:00
Bananymous 45a6783c3d Kernel: Cleanup GDT code 2023-10-13 16:18:22 +03:00
Bananymous 6b180da4e8 Kernel: Separate scheduler execution and stack loading
Not sure if this is actually needed, but this allows actual
executing function to be in clean environment
2023-10-13 16:17:27 +03:00
Bananymous cf4f5f64a5 Kernel: add NEVER_INLINE and make Interruptable not constructable 2023-10-13 16:17:27 +03:00
Bananymous 5630f64175 Kernel: Add 16 more irq handlers
IDT will now panic if trying to assing handler for non supported
irq.
2023-10-13 16:17:27 +03:00
Bananymous 1d61bccfc3 Kernel: Debug temporary debug print just to beginning when full 2023-10-13 12:43:52 +03:00
Bananymous f842a9255f Kernel: Allow getting ACPI headers with same signature 2023-10-13 11:24:21 +03:00
Bananymous 72f3c378dd Kernel: Fix PhysicalRange mapping size 2023-10-13 03:45:01 +03:00
Bananymous 39be6ab099 Kernel: Add temporary terminal output before controlling terminal
Starting work on getting this boot on real hardware.
2023-10-13 03:31:36 +03:00
Bananymous 773dcdd3a2 Kernel: Check whether ELF address space can be loaded
Before reserving address space in SYS_EXEC verify that ELF address
space is actually loadable. For example when trying to execute the
kernel binary in userspace, binarys address space would overlap with
current kernel address space. Now kernel won't crash anymore and
will just send SIGKILL to the process calling exec*().
2023-10-12 22:59:36 +03:00
Bananymous f0820e6f24 Shell: Fix parsing $ with unknown character 2023-10-12 22:24:27 +03:00
37 changed files with 440 additions and 187 deletions

1
.gitignore vendored
View File

@ -5,4 +5,5 @@ base/
*.tar.*
toolchain/*/
!toolchain/local/
!base-sysroot.tar.gz

View File

@ -22,6 +22,10 @@ if(DEFINED QEMU_ACCEL)
set(QEMU_ACCEL -accel ${QEMU_ACCEL})
endif()
if(DEFINED UEFI_BOOT)
set(UEFI_BOOT 1)
endif()
add_compile_options(-mno-sse -mno-sse2)
add_compile_definitions(__enable_sse=0)
@ -67,7 +71,7 @@ add_custom_target(libstdc++
)
add_custom_target(image
COMMAND ${CMAKE_COMMAND} -E env SYSROOT="${BANAN_SYSROOT}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/image.sh
COMMAND ${CMAKE_COMMAND} -E env BANAN_ARCH="${BANAN_ARCH}" SYSROOT="${BANAN_SYSROOT}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" TOOLCHAIN="${TOOLCHAIN_PREFIX}" UEFI_BOOT="${UEFI_BOOT}" ${CMAKE_SOURCE_DIR}/image.sh
DEPENDS kernel-install
DEPENDS ban-install
DEPENDS libc-install
@ -77,7 +81,7 @@ add_custom_target(image
)
add_custom_target(image-full
COMMAND ${CMAKE_COMMAND} -E env SYSROOT="${BANAN_SYSROOT}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/image-full.sh
COMMAND ${CMAKE_COMMAND} -E env BANAN_ARCH="${BANAN_ARCH}" SYSROOT="${BANAN_SYSROOT}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" TOOLCHAIN="${TOOLCHAIN_PREFIX}" UEFI_BOOT="${UEFI_BOOT}" ${CMAKE_SOURCE_DIR}/image-full.sh
DEPENDS kernel-install
DEPENDS ban-install
DEPENDS libc-install
@ -92,19 +96,19 @@ add_custom_target(check-fs
)
add_custom_target(qemu
COMMAND ${CMAKE_COMMAND} -E env BANAN_ARCH="${BANAN_ARCH}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/qemu.sh -serial stdio ${QEMU_ACCEL}
COMMAND ${CMAKE_COMMAND} -E env BANAN_ARCH="${BANAN_ARCH}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" UEFI_BOOT="${UEFI_BOOT}" ${CMAKE_SOURCE_DIR}/qemu.sh -serial stdio ${QEMU_ACCEL}
DEPENDS image
USES_TERMINAL
)
add_custom_target(qemu-nographic
COMMAND ${CMAKE_COMMAND} -E env BANAN_ARCH="${BANAN_ARCH}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/qemu.sh -nographic ${QEMU_ACCEL}
COMMAND ${CMAKE_COMMAND} -E env BANAN_ARCH="${BANAN_ARCH}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" UEFI_BOOT="${UEFI_BOOT}" ${CMAKE_SOURCE_DIR}/qemu.sh -nographic ${QEMU_ACCEL}
DEPENDS image
USES_TERMINAL
)
add_custom_target(qemu-debug
COMMAND ${CMAKE_COMMAND} -E env BANAN_ARCH="${BANAN_ARCH}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/qemu.sh -serial stdio -d int -no-reboot
COMMAND ${CMAKE_COMMAND} -E env BANAN_ARCH="${BANAN_ARCH}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" UEFI_BOOT="${UEFI_BOOT}" ${CMAKE_SOURCE_DIR}/qemu.sh -serial stdio -d int -no-reboot
DEPENDS image
USES_TERMINAL
)

View File

@ -27,6 +27,8 @@ namespace LibELF
LoadableELF::~LoadableELF()
{
if (!m_loaded)
return;
for (const auto& program_header : m_program_headers)
{
switch (program_header.p_type)
@ -155,6 +157,29 @@ namespace LibELF
return false;
}
bool LoadableELF::is_address_space_free() const
{
for (const auto& program_header : m_program_headers)
{
switch (program_header.p_type)
{
case PT_NULL:
break;
case PT_LOAD:
{
vaddr_t page_vaddr = program_header.p_vaddr & PAGE_ADDR_MASK;
size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
if (!m_page_table.is_range_free(page_vaddr, pages * PAGE_SIZE))
return false;
break;
}
default:
ASSERT_NOT_REACHED();
}
}
return true;
}
void LoadableELF::reserve_address_space()
{
for (const auto& program_header : m_program_headers)
@ -174,6 +199,7 @@ namespace LibELF
ASSERT_NOT_REACHED();
}
}
m_loaded = true;
}
BAN::ErrorOr<void> LoadableELF::load_page_to_memory(vaddr_t address)

View File

@ -27,6 +27,7 @@ namespace LibELF
Kernel::vaddr_t entry_point() const;
bool contains(Kernel::vaddr_t address) const;
bool is_address_space_free() const;
void reserve_address_space();
BAN::ErrorOr<void> load_page_to_memory(Kernel::vaddr_t address);
@ -47,6 +48,7 @@ namespace LibELF
BAN::Vector<ElfNativeProgramHeader> m_program_headers;
size_t m_virtual_page_count = 0;
size_t m_physical_page_count = 0;
bool m_loaded { false };
};
}

Binary file not shown.

View File

@ -4,29 +4,50 @@ set -e
DISK_SIZE=$[50 * 1024 * 1024]
MOUNT_DIR=/mnt
truncate -s 0 $DISK_IMAGE_PATH
truncate -s $DISK_SIZE $DISK_IMAGE_PATH
truncate -s 0 "$DISK_IMAGE_PATH"
truncate -s $DISK_SIZE "$DISK_IMAGE_PATH"
sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_IMAGE_PATH > /dev/null
g # gpt
n # new partition
1 # partition number 1
# default (from the beginning of the disk)
+1MiB # bios boot partiton size
n # new partition
2 # partition number 2
# default (right after bios boot partition)
# default (to the end of disk)
t # set type
1 # ... of partition 1
4 # bios boot partition
t # set type
2 # ... of partition 2
20 # Linux filesystem
w # write changes
if [ "$UEFI_BOOT" == "1" ]; then
sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk "$DISK_IMAGE_PATH" > /dev/null
g # gpt
n # new partition
1 # partition number 1
# default (from the beginning of the disk)
+16M # efi system size
n # new partition
2 # partition number 2
# default (right after efi system partition)
# default (to the end of disk)
t # set type
1 # ... of partition 1
1 # efi system
t # set type
2 # ... of partition 2
20 # Linux filesystem
w # write changes
EOF
else
sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk "$DISK_IMAGE_PATH" > /dev/null
g # gpt
n # new partition
1 # partition number 1
# default (from the beginning of the disk)
+1M # bios boot partition size
n # new partition
2 # partition number 2
# default (right after bios partition)
# default (to the end of disk)
t # set type
1 # ... of partition 1
4 # bios boot partition
t # set type
2 # ... of partition 2
20 # Linux filesystem
w # write changes
EOF
fi
LOOP_DEV=$(sudo losetup -f --show $DISK_IMAGE_PATH)
LOOP_DEV=$(sudo losetup -f --show "$DISK_IMAGE_PATH")
sudo partprobe $LOOP_DEV
PARTITION1=${LOOP_DEV}p1
@ -34,8 +55,23 @@ PARTITION2=${LOOP_DEV}p2
sudo mkfs.ext2 -d $SYSROOT -b 1024 -q $PARTITION2
sudo mount $PARTITION2 $MOUNT_DIR
sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV
sudo umount $MOUNT_DIR
if [[ "$UEFI_BOOT" == "1" ]]; then
sudo mkfs.fat $PARTITION1 > /dev/null
sudo mount $PARTITION1 "$MOUNT_DIR"
sudo mkdir -p "$MOUNT_DIR/EFI/BOOT"
sudo "$TOOLCHAIN/bin/grub-mkstandalone" -O "$BANAN_ARCH-efi" -o "$MOUNT_DIR/EFI/BOOT/BOOTX64.EFI" "boot/grub/grub.cfg=$TOOLCHAIN/grub-memdisk.cfg"
sudo umount "$MOUNT_DIR"
sudo mount $PARTITION2 "$MOUNT_DIR"
sudo mkdir -p "$MOUNT_DIR/boot/grub"
sudo cp "$TOOLCHAIN/grub-uefi.cfg" "$MOUNT_DIR/boot/grub/grub.cfg"
sudo umount "$MOUNT_DIR"
else
sudo mount $PARTITION2 "$MOUNT_DIR"
sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory="$MOUNT_DIR/boot" $LOOP_DEV
sudo mkdir -p "$MOUNT_DIR/boot/grub"
sudo cp "$TOOLCHAIN/grub-legacy-boot.cfg" "$MOUNT_DIR/boot/grub/grub.cfg"
sudo umount "$MOUNT_DIR"
fi
sudo losetup -d $LOOP_DEV

View File

@ -1,11 +1,19 @@
#!/bin/bash
set -e
if [ ! -f $DISK_IMAGE_PATH ]; then
$(dirname "$0")/image-full.sh
exit 0
fi
fdisk -l $DISK_IMAGE_PATH | grep -q 'EFI System'; IMAGE_IS_UEFI=$?
[[ $UEFI_BOOT == 1 ]]; CREATE_IS_UEFI=$?
if [ $IMAGE_IS_UEFI -ne $CREATE_IS_UEFI ]; then
echo Converting disk image to/from UEFI
$(dirname "$0")/image-full.sh
exit 0
fi
MOUNT_DIR=/mnt
LOOP_DEV=$(sudo losetup -f --show $DISK_IMAGE_PATH)

View File

@ -1,4 +1,4 @@
#include <BAN/Assert.h>
#include <BAN/Array.h>
#include <kernel/GDT.h>
#include <string.h>
@ -56,44 +56,44 @@ namespace Kernel::GDT
static constexpr uint16_t s_tss_offset = 0x28;
static TaskStateSegment* s_tss = nullptr;
static SegmentDescriptor* s_gdt = nullptr;
static TaskStateSegment s_tss;
static BAN::Array<SegmentDescriptor, 7> s_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high
static GDTR s_gdtr;
static void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
{
SegmentDescriptor& desc = *(SegmentDescriptor*)((uintptr_t)s_gdt + offset);
desc.base1 = base;
desc.base2 = base >> 16;
desc.base3 = base >> 24;
ASSERT(offset % sizeof(SegmentDescriptor) == 0);
desc.limit1 = limit;
desc.limit2 = limit >> 16;
SegmentDescriptor& desc = s_gdt[offset / sizeof(SegmentDescriptor)];
desc.base1 = (base >> 0) & 0xFFFF;
desc.base2 = (base >> 16) & 0xFF;
desc.base3 = (base >> 24) & 0xFF;
desc.access = access;
desc.limit1 = (limit >> 0) & 0xFFFF;
desc.limit2 = (limit >> 16) & 0x0F;
desc.flags = flags;
desc.access = access & 0xFF;
desc.flags = flags & 0x0F;
}
static void write_tss()
{
s_tss = new TaskStateSegment();
ASSERT(s_tss);
memset(&s_tss, 0x00, sizeof(TaskStateSegment));
s_tss.iopb = sizeof(TaskStateSegment);
memset(s_tss, 0x00, sizeof(TaskStateSegment));
s_tss->rsp0 = 0;
uintptr_t base = (uintptr_t)s_tss;
uint64_t base = (uint64_t)&s_tss;
write_entry(s_tss_offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
SegmentDescriptor& desc = *(SegmentDescriptor*)((uintptr_t)s_gdt + s_tss_offset + 0x08);
SegmentDescriptor& desc = s_gdt[s_tss_offset / sizeof(SegmentDescriptor) + 1];
desc.low = base >> 32;
desc.high = 0;
}
void set_tss_stack(uintptr_t rsp)
{
s_tss->rsp0 = rsp;
s_tss.rsp0 = rsp;
}
static void flush_gdt()
@ -108,12 +108,8 @@ namespace Kernel::GDT
void initialize()
{
constexpr uint32_t descriptor_count = 6 + 1; // tss takes 2
s_gdt = new SegmentDescriptor[descriptor_count];
ASSERT(s_gdt);
s_gdtr.address = (uint64_t)s_gdt;
s_gdtr.size = descriptor_count * sizeof(SegmentDescriptor) - 1;
s_gdtr.address = (uint64_t)&s_gdt;
s_gdtr.size = s_gdt.size() * sizeof(SegmentDescriptor) - 1;
write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code

View File

@ -1,3 +1,4 @@
#include <BAN/Array.h>
#include <BAN/Errors.h>
#include <kernel/IDT.h>
#include <kernel/InterruptController.h>
@ -8,10 +9,8 @@
#include <kernel/Scheduler.h>
#include <kernel/Timer/PIT.h>
#include <unistd.h>
#define REGISTER_ISR_HANDLER(i) register_interrupt_handler(i, isr ## i)
#define REGISTER_IRQ_HANDLER(i) register_interrupt_handler(IRQ_VECTOR_BASE + i, irq ## i)
#define ISR_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
namespace Kernel::IDT
{
@ -63,7 +62,9 @@ namespace Kernel::IDT
static IDTR s_idtr;
static GateDescriptor* s_idt = nullptr;
static Interruptable* s_interruptables[0x10] {};
#define X(num) 1 +
static BAN::Array<Interruptable*, IRQ_LIST_X 0> s_interruptables;
#undef X
enum ISR
{
@ -356,58 +357,18 @@ done:
void register_irq_handler(uint8_t irq, Interruptable* interruptable)
{
if (irq > s_interruptables.size())
Kernel::panic("Trying to assign handler for irq {} while only {} are supported", irq, s_interruptables.size());
s_interruptables[irq] = interruptable;
}
extern "C" void isr0();
extern "C" void isr1();
extern "C" void isr2();
extern "C" void isr3();
extern "C" void isr4();
extern "C" void isr5();
extern "C" void isr6();
extern "C" void isr7();
extern "C" void isr8();
extern "C" void isr9();
extern "C" void isr10();
extern "C" void isr11();
extern "C" void isr12();
extern "C" void isr13();
extern "C" void isr14();
extern "C" void isr15();
extern "C" void isr16();
extern "C" void isr17();
extern "C" void isr18();
extern "C" void isr19();
extern "C" void isr20();
extern "C" void isr21();
extern "C" void isr22();
extern "C" void isr23();
extern "C" void isr24();
extern "C" void isr25();
extern "C" void isr26();
extern "C" void isr27();
extern "C" void isr28();
extern "C" void isr29();
extern "C" void isr30();
extern "C" void isr31();
#define X(num) extern "C" void isr ## num();
ISR_LIST_X
#undef X
extern "C" void irq0();
extern "C" void irq1();
extern "C" void irq2();
extern "C" void irq3();
extern "C" void irq4();
extern "C" void irq5();
extern "C" void irq6();
extern "C" void irq7();
extern "C" void irq8();
extern "C" void irq9();
extern "C" void irq10();
extern "C" void irq11();
extern "C" void irq12();
extern "C" void irq13();
extern "C" void irq14();
extern "C" void irq15();
#define X(num) extern "C" void irq ## num();
IRQ_LIST_X
#undef X
extern "C" void syscall_asm();
@ -420,55 +381,13 @@ done:
s_idtr.offset = (uint64_t)s_idt;
s_idtr.size = 0x100 * sizeof(GateDescriptor) - 1;
REGISTER_ISR_HANDLER(0);
REGISTER_ISR_HANDLER(1);
REGISTER_ISR_HANDLER(2);
REGISTER_ISR_HANDLER(3);
REGISTER_ISR_HANDLER(4);
REGISTER_ISR_HANDLER(5);
REGISTER_ISR_HANDLER(6);
REGISTER_ISR_HANDLER(7);
REGISTER_ISR_HANDLER(8);
REGISTER_ISR_HANDLER(9);
REGISTER_ISR_HANDLER(10);
REGISTER_ISR_HANDLER(11);
REGISTER_ISR_HANDLER(12);
REGISTER_ISR_HANDLER(13);
REGISTER_ISR_HANDLER(14);
REGISTER_ISR_HANDLER(15);
REGISTER_ISR_HANDLER(16);
REGISTER_ISR_HANDLER(17);
REGISTER_ISR_HANDLER(18);
REGISTER_ISR_HANDLER(19);
REGISTER_ISR_HANDLER(20);
REGISTER_ISR_HANDLER(21);
REGISTER_ISR_HANDLER(22);
REGISTER_ISR_HANDLER(23);
REGISTER_ISR_HANDLER(24);
REGISTER_ISR_HANDLER(25);
REGISTER_ISR_HANDLER(26);
REGISTER_ISR_HANDLER(27);
REGISTER_ISR_HANDLER(28);
REGISTER_ISR_HANDLER(29);
REGISTER_ISR_HANDLER(30);
REGISTER_ISR_HANDLER(31);
#define X(num) register_interrupt_handler(num, isr ## num);
ISR_LIST_X
#undef X
REGISTER_IRQ_HANDLER(0);
REGISTER_IRQ_HANDLER(1);
REGISTER_IRQ_HANDLER(2);
REGISTER_IRQ_HANDLER(3);
REGISTER_IRQ_HANDLER(4);
REGISTER_IRQ_HANDLER(5);
REGISTER_IRQ_HANDLER(6);
REGISTER_IRQ_HANDLER(7);
REGISTER_IRQ_HANDLER(8);
REGISTER_IRQ_HANDLER(9);
REGISTER_IRQ_HANDLER(10);
REGISTER_IRQ_HANDLER(11);
REGISTER_IRQ_HANDLER(12);
REGISTER_IRQ_HANDLER(13);
REGISTER_IRQ_HANDLER(14);
REGISTER_IRQ_HANDLER(15);
#define X(num) register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
IRQ_LIST_X
#undef X
register_syscall_handler(0x80, syscall_asm);

View File

@ -158,6 +158,22 @@ irq 12
irq 13
irq 14
irq 15
irq 16
irq 17
irq 18
irq 19
irq 20
irq 21
irq 22
irq 23
irq 24
irq 25
irq 26
irq 27
irq 28
irq 29
irq 30
irq 31
// arguments in RAX, RBX, RCX, RDX, RSI, RDI
// System V ABI: RDI, RSI, RDX, RCX, R8, R9

View File

@ -108,7 +108,7 @@ namespace Kernel
static BAN::ErrorOr<void> initialize();
static ACPI& get();
const SDTHeader* get_header(const char[4]);
const SDTHeader* get_header(BAN::StringView signature, uint32_t index);
private:
ACPI() = default;

View File

@ -1,3 +1,4 @@
#pragma once
#define ALWAYS_INLINE inline __attribute__((always_inline))
#define NEVER_INLINE __attribute__((noinline))

View File

@ -11,14 +11,16 @@ namespace Kernel
class Interruptable
{
public:
Interruptable() = default;
void set_irq(int irq);
void enable_interrupt();
void disable_interrupt();
virtual void handle_irq() = 0;
protected:
Interruptable() = default;
~Interruptable() {}
private:
int m_irq { -1 };
};

View File

@ -13,6 +13,7 @@ namespace Kernel
class E1000 final : public NetworkDriver
{
public:
static bool probe(PCI::Device&);
static BAN::ErrorOr<BAN::UniqPtr<E1000>> create(PCI::Device&);
~E1000();

View File

@ -75,6 +75,9 @@ namespace Kernel::PCI
uint8_t header_type() const { return m_header_type; }
uint16_t vendor_id() const { return m_vendor_id; }
uint16_t device_id() const { return m_device_id; }
BAN::ErrorOr<uint8_t> get_irq();
BAN::ErrorOr<BAN::UniqPtr<BarRegion>> allocate_bar_region(uint8_t bar_num);
@ -107,6 +110,8 @@ namespace Kernel::PCI
uint8_t m_prog_if;
uint8_t m_header_type;
uint16_t m_vendor_id;
uint16_t m_device_id;
BAN::Optional<uint8_t> m_offset_msi;
BAN::Optional<uint8_t> m_offset_msi_x;

View File

@ -31,6 +31,7 @@ namespace Kernel
static bool is_valid_tid(pid_t tid);
[[noreturn]] void execute_current_thread();
[[noreturn]] void _execute_current_thread();
[[noreturn]] void delete_current_process_and_thread();
private:

View File

@ -43,7 +43,8 @@ namespace Kernel
virtual uint32_t width() const override;
virtual uint32_t height() const override;
virtual void putchar_impl(uint8_t) override;
virtual void clear() override { putchar_impl('\e'); putchar_impl('['); putchar_impl('2'); putchar_impl('J'); }
virtual void update() override;
@ -51,6 +52,7 @@ namespace Kernel
protected:
virtual BAN::StringView name() const override { return m_name; }
virtual void putchar_impl(uint8_t) override;
private:
SerialTTY(Serial);

View File

@ -38,7 +38,8 @@ namespace Kernel
virtual uint32_t height() const = 0;
virtual uint32_t width() const = 0;
void putchar(uint8_t ch);
virtual void putchar_impl(uint8_t ch) = 0;
virtual void clear() = 0;
virtual bool has_data_impl() const override;
@ -47,6 +48,7 @@ namespace Kernel
: CharacterDevice(mode, uid, gid)
{ }
virtual void putchar_impl(uint8_t ch) = 0;
virtual BAN::ErrorOr<size_t> read_impl(off_t, void*, size_t) override;
virtual BAN::ErrorOr<size_t> write_impl(off_t, const void*, size_t) override;

View File

@ -21,15 +21,16 @@ namespace Kernel
virtual uint32_t height() const override { return m_height; }
virtual uint32_t width() const override { return m_width; }
virtual void putchar_impl(uint8_t ch) override;
virtual void clear() override;
protected:
virtual BAN::StringView name() const override { return m_name; }
virtual void putchar_impl(uint8_t ch) override;
private:
VirtualTTY(TerminalDriver*);
void clear();
void reset_ansi();
void handle_ansi_csi(uint8_t ch);
void handle_ansi_csi_color();

View File

@ -222,13 +222,20 @@ namespace Kernel
return {};
}
const ACPI::SDTHeader* ACPI::get_header(const char signature[4])
const ACPI::SDTHeader* ACPI::get_header(BAN::StringView signature, uint32_t index)
{
if (signature.size() != 4)
{
dprintln("Trying to get ACPI header with {} byte signature ??", signature.size());
return nullptr;
}
uint32_t cnt = 0;
for (auto& mapped_header : m_mapped_headers)
{
auto* header = mapped_header.as_header();
if (memcmp(header->signature, signature, 4) == 0)
return header;
if (memcmp(header->signature, signature.data(), 4) == 0)
if (cnt++ == index)
return header;
}
return nullptr;
}

View File

@ -95,7 +95,7 @@ namespace Kernel
return nullptr;
}
const MADT* madt = (const MADT*)Kernel::ACPI::get().get_header("APIC");
const MADT* madt = (const MADT*)Kernel::ACPI::get().get_header("APIC"sv, 0);
if (madt == nullptr)
{
dprintln("Could not find MADT header");

View File

@ -6,6 +6,10 @@
#include <kernel/Terminal/TTY.h>
#include <kernel/Timer/Timer.h>
#include <ctype.h>
extern TerminalDriver* g_terminal_driver;
namespace Debug
{
@ -64,6 +68,50 @@ namespace Debug
return Kernel::Serial::putchar_any(ch);
if (Kernel::TTY::is_initialized())
return Kernel::TTY::putchar_current(ch);
if (g_terminal_driver)
{
static uint32_t col = 0;
static uint32_t row = 0;
uint32_t row_copy = row;
if (ch == '\n')
{
row++;
col = 0;
}
else if (ch == '\r')
{
col = 0;
}
else
{
if (!isprint(ch))
ch = '?';
g_terminal_driver->putchar_at(ch, col, row, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
col++;
if (col >= g_terminal_driver->width())
{
row++;
col = 0;
}
}
if (row >= g_terminal_driver->height())
row = 0;
if (row != row_copy)
{
for (uint32_t i = col; i < g_terminal_driver->width(); i++)
{
g_terminal_driver->putchar_at(' ', i, row, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
if (row + 1 < g_terminal_driver->height())
g_terminal_driver->putchar_at(' ', i, row + 1, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
}
}
}
}
void print_prefix(const char* file, int line)

View File

@ -23,7 +23,7 @@ namespace Kernel
m_vaddr = PageTable::kernel().reserve_free_contiguous_pages(m_bitmap_pages, KERNEL_OFFSET);
ASSERT(m_vaddr);
PageTable::kernel().map_range_at(m_paddr, m_vaddr, size, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
PageTable::kernel().map_range_at(m_paddr, m_vaddr, m_bitmap_pages * PAGE_SIZE, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
memset((void*)m_vaddr, 0x00, m_bitmap_pages * PAGE_SIZE);
@ -36,8 +36,6 @@ namespace Kernel
ull bits = m_data_pages % ull_bits;
ull_bitmap_ptr()[off] = ~(~0ull << bits);
}
dprintln("physical range needs {} pages for bitmap", m_bitmap_pages);
}
paddr_t PhysicalRange::paddr_for_bit(ull bit) const

View File

@ -112,6 +112,45 @@ namespace Kernel
volatile uint16_t special;
} __attribute__((packed));
// https://www.intel.com/content/dam/doc/manual/pci-pci-x-family-gbe-controllers-software-dev-manual.pdf (section 5.2)
bool E1000::probe(PCI::Device& pci_device)
{
// Intel device
if (pci_device.vendor_id() != 0x8086)
return false;
switch (pci_device.device_id())
{
case 0x1019:
case 0x101A:
case 0x1010:
case 0x1012:
case 0x101D:
case 0x1079:
case 0x107A:
case 0x107B:
case 0x100F:
case 0x1011:
case 0x1026:
case 0x1027:
case 0x1028:
case 0x1107:
case 0x1112:
case 0x1013:
case 0x1018:
case 0x1076:
case 0x1077:
case 0x1078:
case 0x1017:
case 0x1016:
case 0x100e:
case 0x1015:
return true;
default:
return false;
}
}
BAN::ErrorOr<BAN::UniqPtr<E1000>> E1000::create(PCI::Device& pci_device)
{
E1000* e1000 = new E1000();

View File

@ -173,8 +173,9 @@ namespace Kernel::PCI
switch (pci_device.subclass())
{
case 0x00:
if (auto res = E1000::create(pci_device); res.is_error())
dprintln("E1000: {}", res.error());
if (E1000::probe(pci_device))
if (auto res = E1000::create(pci_device); res.is_error())
dprintln("E1000: {}", res.error());
break;
default:
dprintln("unsupported ethernet device (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if());
@ -190,7 +191,11 @@ namespace Kernel::PCI
BAN::ErrorOr<BAN::UniqPtr<BarRegion>> BarRegion::create(PCI::Device& device, uint8_t bar_num)
{
ASSERT(device.header_type() == 0x00);
if (device.header_type() != 0x00)
{
dprintln("BAR regions for non general devices are not supported");
return BAN::Error::from_errno(ENOTSUP);
}
// disable io/mem space while reading bar
uint16_t command = device.read_word(PCI_REG_COMMAND);
@ -333,6 +338,15 @@ namespace Kernel::PCI
m_prog_if = read_byte(0x09);
m_header_type = read_byte(0x0E);
uint32_t device = read_dword(0x00);
m_vendor_id = device & 0xFFFF;
m_device_id = device >> 16;
dprintln("PCI {2H}:{2H}.{2H} has {2H}.{2H}.{2H}",
m_bus, m_dev, m_func,
m_class_code, m_subclass, m_prog_if
);
enumerate_capabilites();
}
@ -390,11 +404,9 @@ namespace Kernel::PCI
{
case 0x05:
m_offset_msi = capability_offset;
dprintln("{}:{}.{} has MSI", m_bus, m_dev, m_func);
break;
case 0x11:
m_offset_msi_x = capability_offset;
dprintln("{}:{}.{} has MSI-X", m_bus, m_dev, m_func);
break;
default:
break;

View File

@ -123,6 +123,11 @@ namespace Kernel
TRY(process->m_cmdline.back().append(path));
process->m_loadable_elf = TRY(load_elf_for_exec(credentials, path, "/"sv, process->page_table()));
if (!process->m_loadable_elf->is_address_space_free())
{
dprintln("Could not load ELF address space");
return BAN::Error::from_errno(ENOEXEC);
}
process->m_loadable_elf->reserve_address_space();
process->m_is_userspace = true;
@ -460,6 +465,11 @@ namespace Kernel
m_loadable_elf.clear();
m_loadable_elf = TRY(load_elf_for_exec(m_credentials, executable_path, m_working_directory, page_table()));
if (!m_loadable_elf->is_address_space_free())
{
dprintln("ELF has unloadable address space");
MUST(sys_raise(SIGKILL));
}
m_loadable_elf->reserve_address_space();
m_userspace_info.entry = m_loadable_elf->entry_point();

View File

@ -7,7 +7,10 @@
#include <kernel/Scheduler.h>
#include <kernel/Timer/PIT.h>
#if 1
#define SCHEDULER_VERIFY_STACK 1
#define SCHEDULER_VERIFY_INTERRUPT_STATE 1
#if SCHEDULER_VERIFY_INTERRUPT_STATE
#define VERIFY_STI() ASSERT(interrupts_enabled())
#define VERIFY_CLI() ASSERT(!interrupts_enabled())
#else
@ -202,6 +205,7 @@ namespace Kernel
delete thread;
execute_current_thread();
ASSERT_NOT_REACHED();
}
void Scheduler::execute_current_thread()
@ -210,6 +214,20 @@ namespace Kernel
load_temp_stack();
PageTable::kernel().load();
_execute_current_thread();
ASSERT_NOT_REACHED();
}
NEVER_INLINE void Scheduler::_execute_current_thread()
{
VERIFY_CLI();
#if SCHEDULER_VERIFY_STACK
vaddr_t rsp;
read_rsp(rsp);
ASSERT((vaddr_t)s_temp_stack <= rsp && rsp <= (vaddr_t)s_temp_stack + sizeof(s_temp_stack));
ASSERT(&PageTable::current() == &PageTable::kernel());
#endif
Thread* current = &current_thread();

View File

@ -27,6 +27,7 @@ namespace Kernel
void TTY::set_as_current()
{
s_tty = this;
clear();
auto inode_or_error = DevFileSystem::get().root_inode()->find_inode("tty"sv);
if (inode_or_error.is_error())

View File

@ -46,7 +46,7 @@ namespace Kernel
BAN::ErrorOr<void> HPET::initialize(bool force_pic)
{
auto* header = (ACPI::HPET*)ACPI::get().get_header("HPET");
auto* header = (ACPI::HPET*)ACPI::get().get_header("HPET"sv, 0);
if (header == nullptr)
return BAN::Error::from_errno(ENODEV);

View File

@ -82,6 +82,8 @@ static void parse_command_line()
extern "C" uint8_t g_userspace_start[];
extern "C" uint8_t g_userspace_end[];
TerminalDriver* g_terminal_driver = nullptr;
static void init2(void*);
extern "C" void kernel_main()
@ -114,6 +116,10 @@ extern "C" void kernel_main()
PageTable::initialize();
dprintln("PageTable initialized");
g_terminal_driver = VesaTerminalDriver::create();
if (g_terminal_driver)
dprintln("VESA initialized");
Heap::initialize();
dprintln("Heap initialzed");
@ -141,12 +147,11 @@ extern "C" void kernel_main()
dprintln("Serial devices initialized");
}
TerminalDriver* terminal_driver = VesaTerminalDriver::create();
ASSERT(terminal_driver);
dprintln("VESA initialized");
auto vtty = MUST(VirtualTTY::create(terminal_driver));
dprintln("Virtual TTY initialized");
if (g_terminal_driver)
{
auto vtty = MUST(VirtualTTY::create(g_terminal_driver));
dprintln("Virtual TTY initialized");
}
MUST(Scheduler::initialize());
dprintln("Scheduler initialized");

View File

@ -51,8 +51,7 @@ void laihost_panic(const char* msg)
void* laihost_scan(const char* sig, size_t index)
{
ASSERT(index == 0);
return (void*)ACPI::get().get_header(sig);
return (void*)ACPI::get().get_header(sig, index);
}
void* laihost_map(size_t address, size_t count)

View File

@ -1,9 +1,18 @@
#!/bin/bash
set -e
if [ -z ${OVMF_PATH+x} ]; then
OVMF_PATH="/usr/share/ovmf/x64/OVMF.fd"
fi
if [ "$UEFI_BOOT" == "1" ]; then
BIOS_ARGS="-bios $OVMF_PATH -net none"
fi
qemu-system-$BANAN_ARCH \
-m 128 \
-smp 2 \
$BIOS_ARGS \
-drive format=raw,id=disk,file=${DISK_IMAGE_PATH},if=none \
-device ahci,id=ahci \
-device ide-hd,drive=disk,bus=ahci.0 \

View File

@ -3,6 +3,7 @@ set -e
BINUTILS_VERSION="binutils-2.39"
GCC_VERSION="gcc-12.2.0"
GRUB_VERSION="grub-2.06"
cd $(dirname "$0")
@ -74,7 +75,7 @@ if [ ! -f ${PREFIX}/bin/${TARGET}-g++ ]; then
fi
mkdir -p build/${GCC_VERSION}/
cd build/${GCC_VERSION}/
pushd build/${GCC_VERSION}/
../../${GCC_VERSION}/configure \
--target="$TARGET" \
@ -87,4 +88,34 @@ if [ ! -f ${PREFIX}/bin/${TARGET}-g++ ]; then
make -j $(nproc) all-target-libgcc CFLAGS_FOR_TARGET='-g -O2 -mcmodel=large -mno-red-zone'
make install-gcc install-target-libgcc
popd
fi
if [ ! -f ${PREFIX}/bin/grub-mkstandalone ]; then
echo "Building ${GRUB_VERSION}"
if [ ! -f ${GRUB_VERSION}.tar.xz ]; then
wget https://ftp.gnu.org/gnu/grub/${GRUB_VERSION}.tar.xz
fi
if [ ! -d $GRUB_VERSION ]; then
tar xvf ${GRUB_VERSION}.tar.xz
fi
mkdir -p build/${GRUB_VERSION}/
pushd build/${GRUB_VERSION}/
../../${GRUB_VERSION}/configure \
--target="$ARCH" \
--prefix="$PREFIX" \
--with-platform="efi" \
--disable-werror
make -j $(nproc)
make install
popd
fi

View File

@ -0,0 +1,23 @@
menuentry "banan-os" {
multiboot /boot/banan-os.kernel root=/dev/sda2
}
menuentry "banan-os (no serial)" {
multiboot /boot/banan-os.kernel root=/dev/sda2 noserial
}
menuentry "banan-os (only serial)" {
multiboot /boot/banan-os.kernel root=/dev/sda2 console=ttyS0
}
menuentry "banan-os (no apic)" {
multiboot /boot/banan-os.kernel root=/dev/sda2 noapic
}
menuentry "banan-os (no apic, no serial)" {
multiboot /boot/banan-os.kernel root=/dev/sda2 noapic noserial
}
menuentry "banan-os (no apic, only serial)" {
multiboot /boot/banan-os.kernel root=/dev/sda2 noapic console=ttyS0
}

View File

@ -0,0 +1,2 @@
insmod part_gpt
configfile (hd0,gpt2)/boot/grub/grub.cfg

View File

@ -0,0 +1,26 @@
insmod part_gpt
set root=(hd0,gpt2)
menuentry "banan-os" {
multiboot /boot/banan-os.kernel root=/dev/sda2
}
menuentry "banan-os (no serial)" {
multiboot /boot/banan-os.kernel root=/dev/sda2 noserial
}
menuentry "banan-os (only serial)" {
multiboot /boot/banan-os.kernel root=/dev/sda2 console=ttyS0
}
menuentry "banan-os (no apic)" {
multiboot /boot/banan-os.kernel root=/dev/sda2 noapic
}
menuentry "banan-os (no apic, no serial)" {
multiboot /boot/banan-os.kernel root=/dev/sda2 noapic noserial
}
menuentry "banan-os (no apic, only serial)" {
multiboot /boot/banan-os.kernel root=/dev/sda2 noapic console=ttyS0
}

View File

@ -156,7 +156,9 @@ BAN::Optional<BAN::String> parse_dollar(BAN::StringView command, size_t& i)
return output;
}
return "$"sv;
BAN::String temp = "$"sv;
MUST(temp.push_back(command[i]));
return temp;
}
BAN::StringView strip_whitespace(BAN::StringView sv)