mirror of
https://github.com/cccriscv/mini-riscv-os.git
synced 2025-11-16 04:24:33 +00:00
refactor
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,4 +7,6 @@
|
||||
*.bak
|
||||
bak
|
||||
.vscode
|
||||
*.img
|
||||
*.dsk
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ string.c
|
||||
|
||||
QEMU = qemu-system-riscv32
|
||||
QFLAGS = -nographic -smp 4 -machine virt -bios none
|
||||
QFLAGS += -drive file=fs.img,if=none,format=raw,id=x0
|
||||
QFLAGS += -drive if=none,format=raw,file=hdd.dsk,id=x0
|
||||
QFLAGS += -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
|
||||
|
||||
OBJDUMP = riscv64-unknown-elf-objdump
|
||||
|
||||
all: os.elf
|
||||
all: clean os.elf hdd.dsk qemu
|
||||
|
||||
os.elf: $(OBJ)
|
||||
$(CC) $(CFLAGS) -T os.ld -o os.elf $^
|
||||
@@ -34,10 +34,10 @@ qemu: $(TARGET)
|
||||
$(QEMU) $(QFLAGS) -kernel os.elf
|
||||
|
||||
clean:
|
||||
rm -f *.elf
|
||||
rm -f *.elf *.img *.dsk
|
||||
|
||||
fs.img:
|
||||
qemu-img create -f raw fs.img 50M
|
||||
hdd.dsk:
|
||||
dd if=/dev/urandom of=hdd.dsk bs=1M count=32
|
||||
|
||||
.PHONY : debug
|
||||
debug: all
|
||||
|
||||
Binary file not shown.
@@ -19,12 +19,13 @@ void os_start()
|
||||
{
|
||||
uart_init();
|
||||
lib_puts("OS start\n");
|
||||
virtio_disk_init();
|
||||
user_init();
|
||||
trap_init();
|
||||
plic_init();
|
||||
virtio_disk_init();
|
||||
timer_init(); // start timer interrupt ...
|
||||
virtio_tester();
|
||||
virtio_tester(1);
|
||||
virtio_tester(0);
|
||||
}
|
||||
|
||||
int os_main(void)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// ref: https://github.com/qemu/qemu/blob/master/include/hw/riscv/virt.h
|
||||
// Intro: https://github.com/ianchen0119/AwesomeCS/wiki/2-5-RISC-V::%E4%B8%AD%E6%96%B7%E8%88%87%E7%95%B0%E5%B8%B8%E8%99%95%E7%90%86----PLIC-%E4%BB%8B%E7%B4%B9
|
||||
#define PLIC_BASE 0x0c000000L
|
||||
#define PLIC_BASE 0x0c000000
|
||||
#define PLIC_PRIORITY(id) (PLIC_BASE + (id)*4)
|
||||
#define PLIC_PENDING(id) (PLIC_BASE + 0x1000 + ((id) / 32))
|
||||
#define PLIC_MENABLE(hart) (PLIC_BASE + 0x2000 + (hart)*0x80)
|
||||
@@ -15,10 +15,16 @@ void plic_init()
|
||||
int hart = r_tp();
|
||||
// QEMU Virt machine support 7 priority (1 - 7),
|
||||
// The "0" is reserved, and the lowest priority is "1".
|
||||
*(uint32_t *)PLIC_PRIORITY(UART0_IRQ) = 1;
|
||||
for (size_t i = VIRTIO_IRQ; i <= UART0_IRQ; i++)
|
||||
{
|
||||
*(uint32_t *)PLIC_PRIORITY(i) = 1;
|
||||
}
|
||||
|
||||
/* Enable UART0 */
|
||||
*(uint32_t *)PLIC_MENABLE(hart) = (1 << UART0_IRQ);
|
||||
/* Enable UART0 and VIRTIO */
|
||||
for (size_t i = VIRTIO_IRQ; i <= UART0_IRQ; i++)
|
||||
{
|
||||
*(uint32_t *)PLIC_MENABLE(hart) |= (1 << i);
|
||||
}
|
||||
|
||||
/* Set priority threshold for UART0. */
|
||||
|
||||
|
||||
@@ -14,8 +14,9 @@ void external_handler()
|
||||
{
|
||||
lib_isr();
|
||||
}
|
||||
else if (irq == VIRTIO_IRQ)
|
||||
else if (0 < irq < 9)
|
||||
{
|
||||
panic("Virio IRQ");
|
||||
virtio_disk_isr();
|
||||
}
|
||||
else if (irq)
|
||||
@@ -63,7 +64,7 @@ reg_t trap_handler(reg_t epc, reg_t cause)
|
||||
else
|
||||
{
|
||||
/* Synchronous trap - exception */
|
||||
lib_puts("Sync exceptions!\n");
|
||||
lib_printf("Sync exceptions! cause code: %d\n", cause_code);
|
||||
while (1)
|
||||
{
|
||||
/* code */
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#ifndef __TYPES_H__
|
||||
#define __TYPES_H__
|
||||
|
||||
typedef signed char int8;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned char uchar;
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef short int16;
|
||||
typedef unsigned short uint16;
|
||||
typedef int int32;
|
||||
typedef unsigned uint32;
|
||||
typedef long long int64;
|
||||
typedef unsigned long long uint64;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
#endif
|
||||
@@ -53,8 +53,6 @@ void user_task3(void)
|
||||
}
|
||||
}
|
||||
|
||||
extern virtio_tester();
|
||||
|
||||
void user_init()
|
||||
{
|
||||
// lock_init(&lock);
|
||||
|
||||
@@ -5,30 +5,15 @@
|
||||
#define BSIZE 1024 // block size
|
||||
#define PGSHIFT 12
|
||||
|
||||
struct buf
|
||||
struct blk
|
||||
{
|
||||
int valid; // has data been read from disk?
|
||||
int disk; // does disk "own" buf?
|
||||
uint32 dev;
|
||||
uint32 blockno;
|
||||
lock_t lock;
|
||||
uint32 refcnt;
|
||||
struct buf *prev; // LRU cache list
|
||||
struct buf *next;
|
||||
unsigned char data[BSIZE];
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
lock_t lock;
|
||||
struct buf buf[30];
|
||||
|
||||
// Linked list of all buffers, through prev/next.
|
||||
// Sorted by how recently the buffer was used.
|
||||
// head.next is most recent, head.prev is least.
|
||||
struct buf head;
|
||||
} bcache;
|
||||
|
||||
static struct disk
|
||||
{
|
||||
char pages[2 * PGSIZE];
|
||||
@@ -42,7 +27,7 @@ static struct disk
|
||||
char free[NUM];
|
||||
struct
|
||||
{
|
||||
struct buf *b;
|
||||
struct blk *b;
|
||||
char status;
|
||||
} info[NUM];
|
||||
uint16 used_idx;
|
||||
@@ -52,38 +37,51 @@ static struct disk
|
||||
struct lock vdisk_lock;
|
||||
} __attribute__((aligned(PGSIZE))) disk;
|
||||
|
||||
void virtio_tester()
|
||||
struct blk b[3];
|
||||
|
||||
void virtio_tester(int write)
|
||||
{
|
||||
// int valid; // has data been read from disk?
|
||||
// int disk; // does disk "own" buf?
|
||||
// uint32 dev;
|
||||
// uint32 blockno;
|
||||
// lock_t lock;
|
||||
// uint32 refcnt;
|
||||
// struct buf *prev; // LRU cache list
|
||||
// struct buf *next;
|
||||
// unsigned char data[BSIZE];
|
||||
struct buf b[3];
|
||||
lib_puts("buffer init...\n");
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
if (!b[0].dev)
|
||||
{
|
||||
lib_puts("buffer init...\n");
|
||||
for (size_t i = 0; i < 1; i++)
|
||||
{
|
||||
b[i].dev = 1; // always is 1
|
||||
b[i].blockno = i + 1;
|
||||
for (size_t j = 0; j < BSIZE; j++)
|
||||
{
|
||||
b[i].data[j] = 0;
|
||||
}
|
||||
|
||||
lock_init(&(b[i].lock));
|
||||
}
|
||||
}
|
||||
|
||||
if (write)
|
||||
{
|
||||
b[i].valid = 1;
|
||||
b[i].disk = 1;
|
||||
b[i].dev = 1;
|
||||
b[i].blockno = i;
|
||||
for (size_t j = 0; j < BSIZE; j++)
|
||||
{
|
||||
b[i].data[j] = (j + i + 1) % 10;
|
||||
b[0].data[j] = (j + 1) % 10;
|
||||
}
|
||||
|
||||
lock_init(&(b[i].lock));
|
||||
lib_puts("block write...\n");
|
||||
virtio_disk_rw(&b[0], write);
|
||||
lib_puts("done...!\n");
|
||||
}
|
||||
lib_puts("buffer write...\n");
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
else
|
||||
{
|
||||
virtio_disk_rw(&b[i], 1);
|
||||
for (size_t j = 0; j < BSIZE; j++)
|
||||
{
|
||||
b[0].data[j] = 0;
|
||||
}
|
||||
lib_puts("block read...\n");
|
||||
virtio_disk_rw(&b[0], write);
|
||||
size_t i = 0;
|
||||
for (; i < 10; i++)
|
||||
{
|
||||
lib_printf("%d ", b[0].data[i]);
|
||||
}
|
||||
lib_puts("\n");
|
||||
}
|
||||
lib_puts("wait...\n");
|
||||
}
|
||||
|
||||
void virtio_disk_init()
|
||||
@@ -99,6 +97,8 @@ void virtio_disk_init()
|
||||
{
|
||||
panic("could not find virtio disk");
|
||||
}
|
||||
/* Reset the device */
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
/* Set the ACKNOWLEDGE status bit to the status register. */
|
||||
status |= VIRTIO_CONFIG_S_ACKNOWLEDGE;
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
@@ -106,7 +106,7 @@ void virtio_disk_init()
|
||||
status |= VIRTIO_CONFIG_S_DRIVER;
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
/* negotiate features */
|
||||
uint64 features = *R(VIRTIO_MMIO_DEVICE_FEATURES);
|
||||
uint32 features = *R(VIRTIO_MMIO_DEVICE_FEATURES);
|
||||
features &= ~(1 << VIRTIO_BLK_F_RO);
|
||||
features &= ~(1 << VIRTIO_BLK_F_SCSI);
|
||||
features &= ~(1 << VIRTIO_BLK_F_CONFIG_WCE);
|
||||
@@ -129,12 +129,12 @@ void virtio_disk_init()
|
||||
*R(VIRTIO_MMIO_QUEUE_SEL) = 0;
|
||||
uint32 max = *R(VIRTIO_MMIO_QUEUE_NUM_MAX);
|
||||
if (max == 0)
|
||||
lib_puts("virtio disk has no queue 0\n");
|
||||
panic("virtio disk has no queue 0\n");
|
||||
if (max < NUM)
|
||||
lib_puts("virtio disk max queue too short\n");
|
||||
panic("virtio disk max queue too short\n");
|
||||
*R(VIRTIO_MMIO_QUEUE_NUM) = NUM;
|
||||
memset(disk.pages, 0, sizeof(disk.pages));
|
||||
*R(VIRTIO_MMIO_QUEUE_PFN) = ((uint64)disk.pages) >> PGSHIFT;
|
||||
*R(VIRTIO_MMIO_QUEUE_PFN) = ((uint32)disk.pages) >> PGSHIFT;
|
||||
|
||||
// desc = pages -- num * virtq_desc
|
||||
// avail = pages + 0x40 -- 2 * uint16, then num * uint16
|
||||
@@ -214,18 +214,11 @@ alloc3_desc(int *idx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void virtio_disk_rw(struct buf *b, int write)
|
||||
void virtio_disk_rw(struct blk *b, int write)
|
||||
{
|
||||
uint64 sector = b->blockno * (BSIZE / 512);
|
||||
|
||||
lock_acquire(&disk.vdisk_lock);
|
||||
|
||||
// the spec's Section 5.2 says that legacy block operations use
|
||||
// three descriptors: one for type/reserved/sector, one for the
|
||||
// data, one for a 1-byte status result.
|
||||
uint32 sector = b->blockno * (BSIZE / 512);
|
||||
|
||||
// allocate the three descriptors.
|
||||
lib_puts("rw init...\n");
|
||||
int idx[3];
|
||||
while (1)
|
||||
{
|
||||
@@ -244,15 +237,15 @@ void virtio_disk_rw(struct buf *b, int write)
|
||||
buf0->type = VIRTIO_BLK_T_OUT; // write the disk
|
||||
else
|
||||
buf0->type = VIRTIO_BLK_T_IN; // read the disk
|
||||
buf0->reserved = 0; // The reserved portion is used to pad the header to 16 bytes and move the 64-bit sector field to the correct place.
|
||||
buf0->reserved = 0; // The reserved portion is used to pad the header to 16 bytes and move the 32-bit sector field to the correct place.
|
||||
buf0->sector = sector; // specify the sector that we wanna modified.
|
||||
|
||||
disk.desc[idx[0]].addr = (uint64)buf0;
|
||||
disk.desc[idx[0]].addr = (uint32)buf0;
|
||||
disk.desc[idx[0]].len = sizeof(struct virtio_blk_req);
|
||||
disk.desc[idx[0]].flags = VRING_DESC_F_NEXT;
|
||||
disk.desc[idx[0]].next = idx[1];
|
||||
|
||||
disk.desc[idx[1]].addr = (uint64)b->data;
|
||||
disk.desc[idx[1]].addr = (uint32)b->data;
|
||||
disk.desc[idx[1]].len = BSIZE;
|
||||
if (write)
|
||||
disk.desc[idx[1]].flags = 0; // device reads b->data
|
||||
@@ -262,36 +255,27 @@ void virtio_disk_rw(struct buf *b, int write)
|
||||
disk.desc[idx[1]].next = idx[2];
|
||||
|
||||
disk.info[idx[0]].status = 0xff; // device writes 0 on success
|
||||
disk.desc[idx[2]].addr = (uint64)&disk.info[idx[0]].status;
|
||||
disk.desc[idx[2]].addr = (uint32)&disk.info[idx[0]].status;
|
||||
disk.desc[idx[2]].len = 1;
|
||||
disk.desc[idx[2]].flags = VRING_DESC_F_WRITE; // device writes the status
|
||||
disk.desc[idx[2]].next = 0;
|
||||
|
||||
// record struct buf for virtio_disk_intr().
|
||||
b->disk = 1;
|
||||
disk.info[idx[0]].b = b;
|
||||
|
||||
__sync_synchronize();
|
||||
|
||||
// tell the device the first index in our chain of descriptors.
|
||||
disk.avail->ring[disk.avail->idx % NUM] = idx[0];
|
||||
lib_puts("rw wait...\n");
|
||||
|
||||
__sync_synchronize();
|
||||
|
||||
// tell the device another avail ring entry is available.
|
||||
disk.avail->idx += 1; // not % NUM ...
|
||||
|
||||
__sync_synchronize();
|
||||
|
||||
*R(VIRTIO_MMIO_QUEUE_NOTIFY) = 0; // value is queue number
|
||||
|
||||
// Wait for virtio_disk_intr() to say request has finished.
|
||||
// while (b->disk == 1)
|
||||
// {
|
||||
// }
|
||||
*R(VIRTIO_MMIO_QUEUE_NOTIFY) = 0; // The device starts immediately when we write 0 to queue_notify.
|
||||
|
||||
disk.info[idx[0]].b = 0;
|
||||
free_chain(idx[0]);
|
||||
|
||||
lock_free(&disk.vdisk_lock);
|
||||
}
|
||||
|
||||
void virtio_disk_isr()
|
||||
@@ -319,8 +303,7 @@ void virtio_disk_isr()
|
||||
if (disk.info[id].status != 0)
|
||||
panic("virtio_disk_intr status");
|
||||
|
||||
struct buf *b = disk.info[id].b;
|
||||
b->disk = 0; // disk is done with buf
|
||||
struct blk *b = disk.info[id].b;
|
||||
|
||||
disk.used_idx += 1;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ typedef struct virtq_desc
|
||||
* flags: 用於控制 descriptor 。
|
||||
* next: 告訴 Device 下一個描述符的 Index 。如果指定了 VIRTQ_DESC_F_NEXT, Device 僅讀取該字段。否則無效。
|
||||
*/
|
||||
uint64 addr;
|
||||
uint32 addr;
|
||||
uint32 len;
|
||||
uint16 flags;
|
||||
uint16 next;
|
||||
@@ -115,5 +115,5 @@ typedef struct virtio_blk_req
|
||||
{
|
||||
uint32 type; // VIRTIO_BLK_T_IN or ..._OUT
|
||||
uint32 reserved; // 將 Header 擴充到 16-byte ,並將 64-bit sector 移到正確的位置。
|
||||
uint64 sector;
|
||||
uint32 sector;
|
||||
} virtio_blk_req_t;
|
||||
@@ -62,3 +62,4 @@ in the `LICENSE` file.
|
||||
- [Adventures in RISC-V](https://matrix89.github.io/writes/writes/experiments-in-riscv/)
|
||||
- [Xv6, a simple Unix-like teaching operating system](https://pdos.csail.mit.edu/6.828/2020/xv6.html)
|
||||
- [Basics of programming a UART](https://www.activexperts.com/serial-port-component/tutorials/uart/)
|
||||
- [QEMU RISC-V Virt Machine Platform](https://github.com/riscv/opensbi/blob/master/docs/platform/qemu_virt.md)
|
||||
|
||||
@@ -108,7 +108,7 @@ struct virtq_used
|
||||
+------------------+
|
||||
```
|
||||
|
||||
完成 Device Driver 方便我們在日後實現檔案系統。
|
||||
完成 Device Driver 會讓我們在日後實現檔案系統更為方便,此外,參考 xv6-riscv 的設計,我們還會需要實現一層 Buffer cache 用來同步硬碟上的資料。
|
||||
|
||||
### 指定寫入的 Sector
|
||||
|
||||
@@ -153,7 +153,7 @@ if(write)
|
||||
buf0->type = VIRTIO_BLK_T_OUT; // write the disk
|
||||
else
|
||||
buf0->type = VIRTIO_BLK_T_IN; // read the disk
|
||||
buf0->reserved = 0; // The reserved portion is used to pad the header to 16 bytes and move the 64-bit sector field to the correct place.
|
||||
buf0->reserved = 0; // The reserved portion is used to pad the header to 16 bytes and move the 32-bit sector field to the correct place.
|
||||
buf0->sector = sector; // specify the sector that we wanna modified.
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user