This commit is contained in:
2026-02-15 16:14:57 +04:00
parent c94866f688
commit 2c70ec98d8
6 changed files with 197 additions and 20 deletions

View File

@@ -226,6 +226,8 @@ struct process *create_process(const void *image, size_t image_size) {
paddr < (paddr_t)__free_ram_end; paddr += PAGE_SIZE) paddr < (paddr_t)__free_ram_end; paddr += PAGE_SIZE)
map_page(page_table, paddr, paddr, PAGE_R | PAGE_W | PAGE_X); map_page(page_table, paddr, paddr, PAGE_R | PAGE_W | PAGE_X);
map_page(page_table, VIRTIO_BLK_PADDR, VIRTIO_BLK_PADDR, PAGE_R | PAGE_W);
for (uint32_t off = 0; off < image_size; off += PAGE_SIZE) { for (uint32_t off = 0; off < image_size; off += PAGE_SIZE) {
paddr_t page = alloc_pages(1); paddr_t page = alloc_pages(1);
@@ -269,24 +271,116 @@ void yield(void) {
switch_context(&prev->sp, &next->sp); switch_context(&prev->sp, &next->sp);
} }
// ===== Disk I/O =====
uint32_t virtio_reg_read32(unsigned offset) {
return *((volatile uint32_t *)(VIRTIO_BLK_PADDR + offset));
}
uint64_t virtio_reg_read64(unsigned offset) {
return *((volatile uint64_t *)(VIRTIO_BLK_PADDR + offset));
}
void virtio_reg_write32(unsigned offset, uint32_t value) {
*((volatile uint32_t *)(VIRTIO_BLK_PADDR + offset)) = value;
}
void virtio_reg_fetch_and_or32(unsigned offset, uint32_t value) {
virtio_reg_write32(offset, virtio_reg_read32(offset) | value);
}
struct virtio_virtq *virtq_init(unsigned index) {
paddr_t virtq_paddr = alloc_pages(
align_up(sizeof(struct virtio_virtq), PAGE_SIZE) / PAGE_SIZE);
struct virtio_virtq *vq = (struct virtio_virtq *)virtq_paddr;
vq->queue_index = index;
vq->used_index = (volatile uint16_t *)&vq->used.index;
virtio_reg_write32(VIRTIO_REG_QUEUE_SEL, index);
virtio_reg_write32(VIRTIO_REG_QUEUE_NUM, VIRTQ_ENTRY_NUM);
virtio_reg_write32(VIRTIO_REG_QUEUE_ALIGN, 0);
virtio_reg_write32(VIRTIO_REG_QUEUE_PFN, virtq_paddr);
return vq;
}
void virtio_blk_init(void) {
if (virtio_reg_read32(VIRTIO_REG_MAGIC) != 0x74726976)
PANIC("virtio: invalid magic value");
if (virtio_reg_read32(VIRTIO_REG_VERSION) != 1)
PANIC("virtio: invalid version");
if (virtio_reg_read32(VIRTIO_REG_DEVICE_ID) != VIRTIO_DEVICE_BLK)
PANIC("virtio: invalid device id");
virtio_reg_write32(VIRTIO_REG_DEVICE_STATUS, 0);
virtio_reg_fetch_and_or32(VIRTIO_REG_DEVICE_STATUS, VIRTIO_STATUS_ACK);
virtio_reg_fetch_and_or32(VIRTIO_REG_DEVICE_STATUS, VIRTIO_STATUS_DRIVER);
virtio_reg_fetch_and_or32(VIRTIO_REG_DEVICE_STATUS, VIRTIO_STATUS_FEAT_OK);
blk_request_vq = virtq_init(0);
virtio_reg_write32(VIRTIO_REG_DEVICE_STATUS, VIRTIO_STATUS_DRIVER_OK);
blk_capacity =
virtio_reg_read64(VIRTIO_REG_DEVICE_CONFIG + 0) * SECTOR_SIZE;
printf("virtio-blk: capacity is %d bytes\n", blk_capacity);
blk_req_paddr =
alloc_pages(align_up(sizeof(*blk_req), PAGE_SIZE) / PAGE_SIZE);
blk_req = (struct virtio_blk_req *)blk_req_paddr;
}
void virtq_kick(struct virtio_virtq *vq, int desc_index) {
vq->avail.ring[vq->avail.index % VIRTQ_ENTRY_NUM] = desc_index;
vq->avail.index++;
__sync_synchronize();
virtio_reg_write32(VIRTIO_REG_QUEUE_NOTIFY, vq->queue_index);
vq->last_used_index++;
}
bool virtq_is_busy(struct virtio_virtq *vq) {
return vq->last_used_index != *vq->used_index;
}
void read_write_disk(void *buf, unsigned sector, int is_write) {
if (sector >= blk_capacity / SECTOR_SIZE) {
printf("virtio: tried to read/write sector=%d, but capacity is %d\n",
sector, blk_capacity / SECTOR_SIZE);
return;
}
blk_req->sector = sector;
blk_req->type = is_write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN;
if (is_write)
memcpy(blk_req->data, buf, SECTOR_SIZE);
struct virtio_virtq *vq = blk_request_vq;
vq->descs[0].addr = blk_req_paddr;
vq->descs[0].len = sizeof(uint32_t) * 2 + sizeof(uint64_t);
vq->descs[0].flags = VIRTQ_DESC_F_NEXT;
vq->descs[0].next = 1;
vq->descs[1].addr = blk_req_paddr + offsetof(struct virtio_blk_req, data);
vq->descs[1].len = SECTOR_SIZE;
vq->descs[1].flags =
VIRTQ_DESC_F_NEXT | (is_write ? 0 : VIRTQ_DESC_F_WRITE);
vq->descs[1].next = 2;
vq->descs[2].addr = blk_req_paddr + offsetof(struct virtio_blk_req, status);
vq->descs[2].len = sizeof(uint8_t);
vq->descs[2].flags = VIRTQ_DESC_F_WRITE;
virtq_kick(vq, 0);
while (virtq_is_busy(vq))
;
if (blk_req->status != 0) {
printf("virtio: warn: failed to read/write sector=%d status=%d\n",
sector, blk_req->status);
return;
}
if (!is_write)
memcpy(buf, blk_req->data, SECTOR_SIZE);
}
// ===== ENTRY POINT ===== // ===== ENTRY POINT =====
struct process *proc_a;
struct process *proc_b;
void proc_a_entry(void) {
while (1) {
putchar('A');
yield();
}
}
void proc_b_entry(void) {
while (1) {
putchar('B');
yield();
}
}
void kernel_main(void) { void kernel_main(void) {
memset(__bss, 0, (size_t)__bss_end - (size_t)__bss); memset(__bss, 0, (size_t)__bss_end - (size_t)__bss);
@@ -294,6 +388,15 @@ void kernel_main(void) {
WRITE_CSR(stvec, (uint32_t)kernel_entry); WRITE_CSR(stvec, (uint32_t)kernel_entry);
virtio_blk_init();
char buf[SECTOR_SIZE];
read_write_disk(buf, 0, false);
printf("first sector: %s\n", buf);
strcpy(buf, "hello from kernel!!!\n");
read_write_disk(buf, 0, true);
idle_proc = create_process(NULL, 0); idle_proc = create_process(NULL, 0);
idle_proc->pid = -1; idle_proc->pid = -1;
current_proc = idle_proc; current_proc = idle_proc;

View File

@@ -75,6 +75,79 @@ struct process *idle_proc;
#define PAGE_X (1 << 3) #define PAGE_X (1 << 3)
#define PAGE_U (1 << 4) #define PAGE_U (1 << 4)
// ===== Disk I/O =====
#define SECTOR_SIZE 512
#define VIRTQ_ENTRY_NUM 16
#define VIRTIO_DEVICE_BLK 2
#define VIRTIO_BLK_PADDR 0x10001000
#define VIRTIO_REG_MAGIC 0x00
#define VIRTIO_REG_VERSION 0x04
#define VIRTIO_REG_DEVICE_ID 0x08
#define VIRTIO_REG_QUEUE_SEL 0x30
#define VIRTIO_REG_QUEUE_NUM_MAX 0x34
#define VIRTIO_REG_QUEUE_NUM 0x38
#define VIRTIO_REG_QUEUE_ALIGN 0x3c
#define VIRTIO_REG_QUEUE_PFN 0x40
#define VIRTIO_REG_QUEUE_READY 0x44
#define VIRTIO_REG_QUEUE_NOTIFY 0x50
#define VIRTIO_REG_DEVICE_STATUS 0x70
#define VIRTIO_REG_DEVICE_CONFIG 0x100
#define VIRTIO_STATUS_ACK 1
#define VIRTIO_STATUS_DRIVER 2
#define VIRTIO_STATUS_DRIVER_OK 4
#define VIRTIO_STATUS_FEAT_OK 8
#define VIRTQ_DESC_F_NEXT 1
#define VIRTQ_DESC_F_WRITE 2
#define VIRTQ_AVAIL_F_NO_INTERRUPT 1
#define VIRTIO_BLK_T_IN 0
#define VIRTIO_BLK_T_OUT 1
struct virtq_desc {
uint64_t addr;
uint32_t len;
uint16_t flags;
uint16_t next;
} __attribute__((packed));
struct virtq_avail {
uint16_t flags;
uint16_t index;
uint16_t ring[VIRTQ_ENTRY_NUM];
} __attribute__((packed));
struct virtq_used_elem {
uint32_t id;
uint32_t len;
} __attribute__((packed));
struct virtq_used {
uint16_t flags;
uint16_t index;
struct virtq_used_elem ring[VIRTQ_ENTRY_NUM];
} __attribute__((packed));
struct virtio_virtq {
struct virtq_desc descs[VIRTQ_ENTRY_NUM];
struct virtq_avail avail;
struct virtq_used used __attribute__((aligned(PAGE_SIZE)));
int queue_index;
volatile uint16_t *used_index;
uint16_t last_used_index;
} __attribute__((packed));
struct virtio_blk_req {
uint32_t type;
uint32_t reserved;
uint64_t sector;
uint8_t data[512];
uint8_t status;
} __attribute__((packed));
struct virtio_virtq *blk_request_vq;
struct virtio_blk_req *blk_req;
paddr_t blk_req_paddr;
unsigned blk_capacity;
// ===== Macros ===== // ===== Macros =====
#define READ_CSR(reg) \ #define READ_CSR(reg) \
({ \ ({ \

BIN
src/lorem.txt Normal file

Binary file not shown.

View File

@@ -1,4 +1,6 @@
@echo off @echo off
make kernel make kernel
cd /d "C:\Program Files\qemu" cd /d "C:\Program Files\qemu"
qemu-system-riscv32.exe -machine virt -bios default -nographic -serial mon:stdio --no-reboot -kernel %~dp0kernel.elf qemu-system-riscv32.exe -machine virt -bios default -nographic -serial mon:stdio --no-reboot -drive id=drive0,file=lorem.txt,format=raw,if=none -device virtio-blk-device,drive=drive0,bus=virtio-mmio-bus.0 -kernel %~dp0kernel.elf

View File

@@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash
set -xue set -xue
make kernel && qemu-system-riscv32 -machine virt -bios default -nographic -serial mon:stdio --no-reboot -kernel kernel.elf make kernel && qemu-system-riscv32 -machine virt -bios default -nographic -serial mon:stdio --no-reboot -drive id=drive0,file=lorem.txt,format=raw,if=none -device virtio-blk-device,drive=drive0,bus=virtio-mmio-bus.0 -kernel kernel.elf

View File

@@ -1,7 +1,6 @@
#include "user.h" #include "user.h"
void main(void) { void main(void) {
*((volatile int *)0x80200000) = 0x1234; // new!
for (;;) for (;;)
; ;
} }