1 Commits

Author SHA1 Message Date
f037adcebd feat: start setup virtio 2022-09-01 20:45:40 +02:00
14 changed files with 308 additions and 227 deletions

View File

@@ -19,7 +19,7 @@ forced to be within the first 8 KiB of the kernel file.
.long CHECKSUM
#.include "gdt.S"
.section .data.boot
.section .data
gdt:
.quad 0x0000000000000000
.quad 0x00CF9A000000FFFF
@@ -42,7 +42,7 @@ 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.boot
.section .bss
.align 16
stack_bottom:
.skip 16384 # 16 KiB
@@ -53,7 +53,7 @@ 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.boot
.section .text
.global _start
.type _start, @function
_start:
@@ -103,25 +103,6 @@ _start:
continue_boot:
sti
// setting up paging
// id map first 4MB using PSE. With
movl $135, kernel_page_directory - 0xC0000000
movl $135, kernel_page_directory - 0xC0000000 + 3072
// load into cr3
movl $kernel_page_directory - 0xC0000000, %eax
movl %eax, %cr3
// enable PSE TODO validate if PSE is actually supported
movl %cr4, %eax
orl $0x10, %eax
movl %eax, %cr4
// enable paging
movl %cr0, %eax
orl $0x80000000, %eax
movl %eax, %cr0
nop
pushl 0
popl %eax
/*
Enter the high-level kernel. The ABI requires the stack is 16-byte
aligned at the time of the call instruction (which afterwards pushes

21
include/endian.h Normal file
View File

@@ -0,0 +1,21 @@
//
// Created by rick on 14-5-22.
//
#ifndef NEW_KERNEL_ENDIAN_H
#define NEW_KERNEL_ENDIAN_H
#include <stdint.h>
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define leu16_to_native(x) x
#define leu32_to_native(x) x
#else
#define leu16_to_native(x) ((x) >> 8 | (x) << 8)
#define leu32_to_native(x) (((x)>>24)&0xff) | \
(((x)<<8)&0xff0000) | \
(((x)>>8)&0xff00) | \
(((x)<<24)&0xff000000)
#endif
#endif //NEW_KERNEL_ENDIAN_H

View File

@@ -14,7 +14,8 @@
#define PCI_CLASS_BRIDGE 0x06
// class MASS STORAGE 0x01
#define PCI_SUB_CLASS_IDE 0x01
#define PCI_SUB_CLASS_MASS_SCSI 0x00
#define PCI_SUB_CLASS_MASS_IDE 0x01
// class BRIDGE 0x06
#define PCI_SUB_CLASS_PCI_PCI_BRIDGE_4 0x04

View File

@@ -0,0 +1,18 @@
//
// Created by rick on 14-5-22.
//
#ifndef NEW_KERNEL_VIRTIO_H
#define NEW_KERNEL_VIRTIO_H
#define PCI_VENDOR_VIRTIO 0x1af4
#define PCI_DEVICE_VIRTIO_NETWORK 0x1000
#define PCI_DEVICE_VIRTIO_BLOCK 0x1001
#define PCI_DEVICE_VIRTIO_BALLOON 0x1002
#define PCI_DEVICE_VIRTIO_CONSOLE 0x1003
#define PCI_DEVICE_VIRTIO_SCSI 0x1004
#define PCI_DEVICE_VIRTIO_ENTROPY 0x1005
#define PCI_DEVICE_VIRTIO_9P 0x1009
#endif //NEW_KERNEL_VIRTIO_H

View File

@@ -5,39 +5,4 @@
#ifndef NEW_KERNEL_PAGING_H
#define NEW_KERNEL_PAGING_H
#define PAGING_MASK_4K 0xFFFFF000
#define PAGING_MASK_4M 0xFFC00000
#define DIRECTORY_PRESENT_BIT (0)
#define DIRECTORY_RW_BIT (1)
#define DIRECTORY_US_BIT (2)
#define DIRECTORY_WT_BIT (3)
#define DIRECTORY_CACHE_BIT (4)
#define DIRECTORY_ACCESSED_BIT (5)
#define DIRECTORY_PAGE_SIZE_BIT (7)
#define DIRECTORY_ADDR_MASK 0xFFFFF000
#define DIRECTORY_PRESENT_MASK (1 << DIRECTORY_PRESENT_BIT)
#define DIRECTORY_RW_MASK (1 << DIRECTORY_RW_BIT)
#define DIRECTORY_US_MASK (1 << DIRECTORY_US_BIT)
#define DIRECTORY_WT_MASK (1 << DIRECTORY_WT_BIT)
#define DIRECTORY_CACHE_MASK (1 << DIRECTORY_CACHE_BIT)
#define DIRECTORY_ACCESSED_MASK (1 << DIRECTORY_ACCESSED_BIT)
#define DIRECTORY_PAGE_SIZE_MASK (1 << DIRECTORY_PAGE_SIZE_BIT)
#define DIRECTORY_SIZE 1024
#define PAGING_MODE_4M (1 << 0)
#define PAGING_MODE_RW (1 << 1)
#define PAGING_MODE_US (1 << 2)
#define PAGING_RESULT_OK 0
#define PAGING_RESULT_INUSE 1
#define PAGING_RESULT_ALIGN 2
#define PAGING_RESULT_ERR 99
typedef uint32_t page_directory_entry;
typedef uint32_t page_table_entry;
#endif //NEW_KERNEL_PAGING_H

View File

@@ -1,10 +0,0 @@
//
// Created by rick on 17-10-21.
//
#ifndef NEW_KERNEL_VMM_H
#define NEW_KERNEL_VMM_H
void vmm_init(multiboot_info_t *multiboot_info);
#endif //NEW_KERNEL_VMM_H

103
include/virtio_queue.h Normal file
View File

@@ -0,0 +1,103 @@
#ifndef VIRTQUEUE_H
#define VIRTQUEUE_H
/*
* Virtual I/O Device (VIRTIO) Version 1.2
* Committee Specification Draft 01
* 09 May 2022
* Copyright (c) OASIS Open 2022. All Rights Reserved.
* Source: http://docs.oasis-open.org/virtio/virtio/v1.2/csd01/listings/
* Latest stage of narrative specification: http://docs.oasis-open.org/virtio/virtio/v1.2/virtio-v1.2.html
* TC IPR Statement: https://github.com/oasis-tcs/virtio-admin/blob/master/IPR.md
*/
/*
* An interface for efficient virtio implementation.
*/
#include <stdint.h>
/* This marks a buffer as continuing via the next field. */
#define VIRTQ_DESC_F_NEXT 1
/* This marks a buffer as write-only (otherwise read-only). */
#define VIRTQ_DESC_F_WRITE 2
/* This means the buffer contains a list of buffer descriptors. */
#define VIRTQ_DESC_F_INDIRECT 4
/* The device uses this in used->flags to advise the driver: don't kick me
* when you add a buffer. It's unreliable, so it's simply an
* optimization. */
#define VIRTQ_USED_F_NO_NOTIFY 1
/* The driver uses this in avail->flags to advise the device: don't
* interrupt me when you consume a buffer. It's unreliable, so it's
* simply an optimization. */
#define VIRTQ_AVAIL_F_NO_INTERRUPT 1
/* Support for indirect descriptors */
#define VIRTIO_F_INDIRECT_DESC 28
/* Support for avail_event and used_event fields */
#define VIRTIO_F_EVENT_IDX 29
/* Arbitrary descriptor layouts. */
#define VIRTIO_F_ANY_LAYOUT 27
/* Virtqueue descriptors: 16 bytes.
* These can chain together via "next". */
struct virtq_desc {
/* Address (guest-physical). */
le64 addr;
/* Length. */
le32 len;
/* The flags as indicated above. */
le16 flags;
/* We chain unused descriptors via this, too */
le16 next;
};
struct virtq_avail {
le16 flags;
le16 idx;
le16 ring[];
/* Only if VIRTIO_F_EVENT_IDX: le16 used_event; */
};
/* le32 is used here for ids for padding reasons. */
struct virtq_used_elem {
/* Index of start of used descriptor chain. */
le32 id;
/* Total length of the descriptor chain which was written to. */
le32 len;
};
struct virtq_used {
le16 flags;
le16 idx;
struct virtq_used_elem ring[];
/* Only if VIRTIO_F_EVENT_IDX: le16 avail_event; */
};
struct virtq {
unsigned int num;
struct virtq_desc *desc;
struct virtq_avail *avail;
struct virtq_used *used;
};
static inline int virtq_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old_idx)
{
return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old_idx);
}
/* Get location of event indices (only with VIRTIO_F_EVENT_IDX) */
static inline le16 *virtq_used_event(struct virtq *vq)
{
/* For backwards compat, used event index is at *end* of avail ring. */
return &vq->avail->ring[vq->num];
}
static inline le16 *virtq_avail_event(struct virtq *vq)
{
/* For backwards compat, avail event index is at *end* of used ring. */
return (le16 *)&vq->used->ring[vq->num];
}
#endif /* VIRTQUEUE_H */

View File

@@ -421,7 +421,7 @@ void ide_register_block_devices() {
uint8_t att_used ide_pci_validate(const pci_device *device) {
if (device->class != PCI_CLASS_MASS_STORAGE
|| device->subclass != PCI_SUB_CLASS_IDE
|| device->subclass != PCI_SUB_CLASS_MASS_IDE
|| (device->programInterface != 0x8A && device->programInterface != 0x80)) {
return PCI_VALIDATE_FAIL;
}
@@ -686,7 +686,7 @@ PCI_DRIVER(900) = {
.validatable = true,
.initialisable = true,
.match.class = PCI_CLASS_MASS_STORAGE,
.match.subclass = PCI_SUB_CLASS_IDE,
.match.subclass = PCI_SUB_CLASS_MASS_IDE,
.mask.class = true,
.mask.subclass = true,
.validate = ide_pci_validate,

View File

@@ -0,0 +1,46 @@
//
// Created by rick on 14-5-22.
//
#include <endian.h>
#include <myke/drivers/pci/pci.h>
#include <myke/drivers/pci/virtio.h>
uint8_t att_used virtio_pci_block_validate(const pci_device *pci_device) {
uint32_t capacity_l = pci_config_read_double_word(pci_device->bus, pci_device->slot, pci_device->func, 0x14);
uint32_t capacity_h = pci_config_read_double_word(pci_device->bus, pci_device->slot, pci_device->func, 0x18);
uint32_t segment_size_max = pci_config_read_double_word(pci_device->bus, pci_device->slot, pci_device->func, 0x1c);
uint32_t segment_count_max = pci_config_read_double_word(pci_device->bus, pci_device->slot, pci_device->func, 0x20);
uint16_t cylinder_count = pci_config_read_word(pci_device->bus, pci_device->slot, pci_device->func, 0x24);
uint8_t head_count = pci_config_read_byte(pci_device->bus, pci_device->slot, pci_device->func, 0x26);
uint8_t sector_count = pci_config_read_byte(pci_device->bus, pci_device->slot, pci_device->func, 0x27);
uint32_t block_length = pci_config_read_double_word(pci_device->bus, pci_device->slot, pci_device->func, 0x28);
capacity_l = leu32_to_native(capacity_l);
capacity_h = leu32_to_native(capacity_h);
uint64_t capacity = ((uint64_t) capacity_h) >> 32 | capacity_l;
return PCI_VALIDATE_FAIL;
}
uint8_t att_used virtio_pci_block_initialize(pci_device *pci_device) {
return PCI_INIT_FAIL;
}
PCI_DRIVER(900) = {
.name = "pci-virtio-block",
.description = "Para-virtualized Block Device",
.validatable = true,
.initialisable = true,
.match.class = PCI_CLASS_MASS_STORAGE,
.match.subclass = PCI_SUB_CLASS_MASS_SCSI,
.match.vendor = PCI_VENDOR_VIRTIO,
.match.device = PCI_DEVICE_VIRTIO_BLOCK,
.mask.class = true,
.mask.subclass = true,
.mask.vendor = true,
.mask.device = true,
.validate = virtio_pci_block_validate,
.initialize = virtio_pci_block_initialize,
};

View File

@@ -13,7 +13,7 @@
#include <myke/libk/kprint.h>
#include <myke/libk/libk.h>
#include <myke/libk/syscall.h>
#include <myke/mem/vmm.h>
#include <myke/mem/mem.h>
#include <myke/util/init.h>
#include <myke/tasks/task.h>
@@ -21,6 +21,15 @@ const int version_major = 0,
version_minor = 0,
version_patch = 1;
void init_mmap(multiboot_info_t *multiboot_info) {
if (multiboot_info->flags & (1 << 6)) {
mmap_init_multiboot((struct multiboot_mmap_entry *) multiboot_info->mmap_addr,
multiboot_info->mmap_length / sizeof(struct multiboot_mmap_entry));
} else {
k_panics("mmap invalid!\n");
}
}
void init_pci_system() {
pci_scan();
pci_init_drivers();
@@ -29,9 +38,6 @@ void init_pci_system() {
void att_noreturn att_used kmain(multiboot_info_t *multiboot_info, uint32_t mb_name) {
// early init
isr_install();
// initialize memory management
vmm_init(multiboot_info);
// initialize early modules (kprint etc.)
init_execute_all(INIT_STAGE_EARLY_BOOT_0);
@@ -42,6 +48,8 @@ void att_noreturn att_used kmain(multiboot_info_t *multiboot_info, uint32_t mb_n
store_bootloader_info(multiboot_info);
// initialize memory management
init_mmap(multiboot_info);
// safe multiboot info for later use
debug_store_info(multiboot_info);

View File

@@ -2,80 +2,58 @@
// Created by rick on 21-02-21.
//
#include <sys/types.h>
#include <attributes.h>
#include <stdbool.h>
#include <sys/types.h>
#include <myke/mem/paging.h>
#include <sys/param.h>
#define PAGING_DIR_INDEX(virt) ((virt) >> 22)
#define PAGING_TABLE_INDEX(virt) ((virt) >> 12 & 0x03FF)
#define TABLE_ADDR_MASK 0xFFFFF000
#define DIRECTORY_SIZE 1024
#define KERNEL_OFFSET 0xC0000000
const uint32_t x = TABLE_ADDR_MASK;
typedef struct {
union {
struct {
bool present: 1;
bool read_write: 1;
bool user_mode: 1;
bool write_through: 1;
bool cache_disabled: 1;
bool accessed: 1;
char ignored: 1;
bool page_size: 1;
bool global: 1; // ignored
uint8_t avail: 3;
} att_packed;
uint32_t addr;
};
} att_packed page_directory_entry;
// One page table, only 4M
#define PAGING_STATE_EARLY 0
#define PAGING_STATE_FULL 60
typedef struct {
union {
struct {
bool present: 1;
bool read_write: 1;
bool user_supervisor: 1;
bool write_through: 1;
bool cache_disabled: 1;
bool accessed: 1;
bool dirty: 1;
char ignored: 1;
bool global: 1;
uint8_t available: 3;
} att_packed;
uint32_t addr;
};
} att_packed page_table_entry;
page_directory_entry att_aligned(4096) kernel_page_directory[DIRECTORY_SIZE] = {0};
page_directory_entry page_directory[DIRECTORY_SIZE] att_aligned(4096);
int paging_state = PAGING_STATE_EARLY;
void paging_load_directory(uintptr_t physical_address) {
asm volatile("mov %%eax, %%cr3" : : "a" (physical_address));
}
uintptr_t paging_get_current_directory_physical() {
uintptr_t directory_address;
asm volatile("mov %%cr3, %%eax" : "=a" (directory_address));
return directory_address;
}
page_directory_entry *paging_get_current() {
return kernel_page_directory;
}
int paging_map_4m(uintptr_t physical_address, uintptr_t virtual_address, int count, int mode) {
if (virtual_address & ~PAGING_MASK_4M || physical_address & PAGING_MASK_4M) {
// address not 4M aligned
return PAGING_RESULT_ALIGN;
}
page_directory_entry *dir = paging_get_current();
for (int i = 0; i < count; ++i) {
page_directory_entry current_val = dir[PAGING_DIR_INDEX(virtual_address) + i];
if (current_val & DIRECTORY_PRESENT_MASK) {
return PAGING_RESULT_INUSE;
void page_pre_init() {
for (int i = 0; i < DIRECTORY_SIZE; ++i) {
page_directory[i].read_write = true;
page_directory[i].user_mode = false;
page_directory[i].present = false;
}
}
page_directory_entry mask = DIRECTORY_PAGE_SIZE_MASK;
if (mode & PAGING_MODE_RW) {
mask |= DIRECTORY_RW_MASK;
}
if (mode & PAGING_MODE_US) {
mask |= DIRECTORY_US_MASK;
}
for (int i = 0; i < count; ++i) {
dir[PAGING_DIR_INDEX(virtual_address) + i] = physical_address & mask;
}
paging_load_directory((uintptr_t) dir);
return PAGING_RESULT_OK;
}
int paging_map_memory(uintptr_t physical_address, uintptr_t virtual_address, int count, int mode) {
if (mode & PAGING_MODE_4M) {
return paging_map_4m(physical_address, virtual_address, count, mode);
}
if (paging_state < PAGING_STATE_FULL) {
// can't allocate 4K pages yet
if ((virtual_address & ~PAGING_MASK_4M) != (physical_address & ~PAGING_MASK_4M)) {
return PAGING_RESULT_ERR; // not in same pos in 4M page
}
int table_index = PAGING_TABLE_INDEX(virtual_address);
int pages = DIV_ROUND_UP(table_index + count, 1024);
return paging_map_4m(physical_address & PAGING_MASK_4M,
virtual_address & PAGING_MASK_4M,
pages,
mode | PAGING_MODE_4M);
}
return PAGING_RESULT_ERR;
}

View File

@@ -1,24 +0,0 @@
//
// Created by rick on 17-10-21.
//
#include <sys/types.h>
#include <myke/libk/libk.h>
#include <myke/mem/mem.h>
#include <myke/mem/vmm.h>
void vmm_init(multiboot_info_t *multiboot_info) {
if (!(multiboot_info->flags & MULTIBOOT_INFO_MEM_MAP)) {
k_panics("No MMAP info available");
}
mmap_init_multiboot((struct multiboot_mmap_entry *) multiboot_info->mmap_addr,
multiboot_info->mmap_length / sizeof(struct multiboot_mmap_entry));
}
void* vmm_map_physical(uintptr_t physical) {
}
void* vmm_unmap_physical(uintptr_t physical) {
}
void* vmm_unmap_virtual(uintptr_t virtual) {
}

View File

@@ -37,6 +37,10 @@ while [[ "$#" -gt 0 ]]; do
ARGS="${ARGS} -drive id=disk1,file=$2,if=none -device ahci,id=ahci -device ide-drive,drive=disk1,bus=ahci.0"
shift 2
;;
--virtio)
ARGS="$ARGS -drive id=disk1,file=$2,if=virtio"
shift 2
;;
-m | --max-cpu)
ARGS="${ARGS} -cpu max"
shift

View File

@@ -10,34 +10,24 @@ SECTIONS
loaded at by the bootloader. */
. = 1M;
_kernel_start = .;
.data.boot ALIGN(4K) : {
*(.multiboot)
*(.data.boot)
}
.text.boot ALIGN(4K) : {
*(.text.boot)
}
.bss.boot ALIGN(4K) : {
*(.bss.boot)
}
. += 0xC0000000;
/* First put the multiboot header, as it is required to be put very early
early in the image or the bootloader won't recognize the file format.
Next we'll put the .text section. */
.text ALIGN(4K) : AT(ADDR(.text)-0xC0000000)
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
/* Read-only data. */
.rodata ALIGN(4K) : AT(ADDR(.rodata)-0xC0000000)
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
/* Read-write data (initialized) */
.data ALIGN(4K) : AT(ADDR(.data)-0xC0000000)
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
@@ -63,12 +53,12 @@ SECTIONS
}
/* Read-write data (uninitialized) and stack */
.bss ALIGN(4K) : AT(ADDR(.bss)-0xC0000000)
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
_kernel_end = . - 0xC0000000;
_kernel_end = .;
/DISCARD/ : {
*(.eh_frame);