This commit is contained in:
ianchen0119
2021-06-28 17:47:31 +08:00
parent f7230c0a8a
commit 42410f8ede
12 changed files with 89 additions and 98 deletions

2
.gitignore vendored
View File

@@ -7,4 +7,6 @@
*.bak *.bak
bak bak
.vscode .vscode
*.img
*.dsk

View File

@@ -18,12 +18,12 @@ string.c
QEMU = qemu-system-riscv32 QEMU = qemu-system-riscv32
QFLAGS = -nographic -smp 4 -machine virt -bios none 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 QFLAGS += -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
OBJDUMP = riscv64-unknown-elf-objdump OBJDUMP = riscv64-unknown-elf-objdump
all: os.elf all: clean os.elf hdd.dsk qemu
os.elf: $(OBJ) os.elf: $(OBJ)
$(CC) $(CFLAGS) -T os.ld -o os.elf $^ $(CC) $(CFLAGS) -T os.ld -o os.elf $^
@@ -34,10 +34,10 @@ qemu: $(TARGET)
$(QEMU) $(QFLAGS) -kernel os.elf $(QEMU) $(QFLAGS) -kernel os.elf
clean: clean:
rm -f *.elf rm -f *.elf *.img *.dsk
fs.img: hdd.dsk:
qemu-img create -f raw fs.img 50M dd if=/dev/urandom of=hdd.dsk bs=1M count=32
.PHONY : debug .PHONY : debug
debug: all debug: all

Binary file not shown.

View File

@@ -19,12 +19,13 @@ void os_start()
{ {
uart_init(); uart_init();
lib_puts("OS start\n"); lib_puts("OS start\n");
virtio_disk_init();
user_init(); user_init();
trap_init(); trap_init();
plic_init(); plic_init();
virtio_disk_init();
timer_init(); // start timer interrupt ... timer_init(); // start timer interrupt ...
virtio_tester(); virtio_tester(1);
virtio_tester(0);
} }
int os_main(void) int os_main(void)

View File

@@ -2,7 +2,7 @@
// ref: https://github.com/qemu/qemu/blob/master/include/hw/riscv/virt.h // 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 // 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_PRIORITY(id) (PLIC_BASE + (id)*4)
#define PLIC_PENDING(id) (PLIC_BASE + 0x1000 + ((id) / 32)) #define PLIC_PENDING(id) (PLIC_BASE + 0x1000 + ((id) / 32))
#define PLIC_MENABLE(hart) (PLIC_BASE + 0x2000 + (hart)*0x80) #define PLIC_MENABLE(hart) (PLIC_BASE + 0x2000 + (hart)*0x80)
@@ -15,10 +15,16 @@ void plic_init()
int hart = r_tp(); int hart = r_tp();
// QEMU Virt machine support 7 priority (1 - 7), // QEMU Virt machine support 7 priority (1 - 7),
// The "0" is reserved, and the lowest priority is "1". // 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 */ /* Enable UART0 and VIRTIO */
*(uint32_t *)PLIC_MENABLE(hart) = (1 << UART0_IRQ); for (size_t i = VIRTIO_IRQ; i <= UART0_IRQ; i++)
{
*(uint32_t *)PLIC_MENABLE(hart) |= (1 << i);
}
/* Set priority threshold for UART0. */ /* Set priority threshold for UART0. */

View File

@@ -14,8 +14,9 @@ void external_handler()
{ {
lib_isr(); lib_isr();
} }
else if (irq == VIRTIO_IRQ) else if (0 < irq < 9)
{ {
panic("Virio IRQ");
virtio_disk_isr(); virtio_disk_isr();
} }
else if (irq) else if (irq)
@@ -63,7 +64,7 @@ reg_t trap_handler(reg_t epc, reg_t cause)
else else
{ {
/* Synchronous trap - exception */ /* Synchronous trap - exception */
lib_puts("Sync exceptions!\n"); lib_printf("Sync exceptions! cause code: %d\n", cause_code);
while (1) while (1)
{ {
/* code */ /* code */

View File

@@ -1,13 +1,12 @@
#ifndef __TYPES_H__ #ifndef __TYPES_H__
#define __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 unsigned char uint8;
typedef short int16;
typedef unsigned short uint16; typedef unsigned short uint16;
typedef int int32; typedef unsigned int uint32;
typedef unsigned uint32;
typedef long long int64;
typedef unsigned long long uint64;
#endif #endif

View File

@@ -53,8 +53,6 @@ void user_task3(void)
} }
} }
extern virtio_tester();
void user_init() void user_init()
{ {
// lock_init(&lock); // lock_init(&lock);

View File

@@ -5,30 +5,15 @@
#define BSIZE 1024 // block size #define BSIZE 1024 // block size
#define PGSHIFT 12 #define PGSHIFT 12
struct buf struct blk
{ {
int valid; // has data been read from disk?
int disk; // does disk "own" buf?
uint32 dev; uint32 dev;
uint32 blockno; uint32 blockno;
lock_t lock; lock_t lock;
uint32 refcnt; uint32 refcnt;
struct buf *prev; // LRU cache list
struct buf *next;
unsigned char data[BSIZE]; 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 static struct disk
{ {
char pages[2 * PGSIZE]; char pages[2 * PGSIZE];
@@ -42,7 +27,7 @@ static struct disk
char free[NUM]; char free[NUM];
struct struct
{ {
struct buf *b; struct blk *b;
char status; char status;
} info[NUM]; } info[NUM];
uint16 used_idx; uint16 used_idx;
@@ -52,38 +37,51 @@ static struct disk
struct lock vdisk_lock; struct lock vdisk_lock;
} __attribute__((aligned(PGSIZE))) disk; } __attribute__((aligned(PGSIZE))) disk;
void virtio_tester() struct blk b[3];
void virtio_tester(int write)
{ {
// int valid; // has data been read from disk? if (!b[0].dev)
// 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++)
{ {
b[i].valid = 1; lib_puts("buffer init...\n");
b[i].disk = 1; for (size_t i = 0; i < 1; i++)
b[i].dev = 1; {
b[i].blockno = i; b[i].dev = 1; // always is 1
b[i].blockno = i + 1;
for (size_t j = 0; j < BSIZE; j++) for (size_t j = 0; j < BSIZE; j++)
{ {
b[i].data[j] = (j + i + 1) % 10; b[i].data[j] = 0;
} }
lock_init(&(b[i].lock)); lock_init(&(b[i].lock));
} }
lib_puts("buffer write...\n");
for (size_t i = 0; i < 3; i++)
{
virtio_disk_rw(&b[i], 1);
} }
lib_puts("wait...\n");
if (write)
{
for (size_t j = 0; j < BSIZE; j++)
{
b[0].data[j] = (j + 1) % 10;
}
lib_puts("block write...\n");
virtio_disk_rw(&b[0], write);
lib_puts("done...!\n");
}
else
{
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");
}
} }
void virtio_disk_init() void virtio_disk_init()
@@ -99,6 +97,8 @@ void virtio_disk_init()
{ {
panic("could not find virtio disk"); panic("could not find virtio disk");
} }
/* Reset the device */
*R(VIRTIO_MMIO_STATUS) = status;
/* Set the ACKNOWLEDGE status bit to the status register. */ /* Set the ACKNOWLEDGE status bit to the status register. */
status |= VIRTIO_CONFIG_S_ACKNOWLEDGE; status |= VIRTIO_CONFIG_S_ACKNOWLEDGE;
*R(VIRTIO_MMIO_STATUS) = status; *R(VIRTIO_MMIO_STATUS) = status;
@@ -106,7 +106,7 @@ void virtio_disk_init()
status |= VIRTIO_CONFIG_S_DRIVER; status |= VIRTIO_CONFIG_S_DRIVER;
*R(VIRTIO_MMIO_STATUS) = status; *R(VIRTIO_MMIO_STATUS) = status;
/* negotiate features */ /* 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_RO);
features &= ~(1 << VIRTIO_BLK_F_SCSI); features &= ~(1 << VIRTIO_BLK_F_SCSI);
features &= ~(1 << VIRTIO_BLK_F_CONFIG_WCE); features &= ~(1 << VIRTIO_BLK_F_CONFIG_WCE);
@@ -129,12 +129,12 @@ void virtio_disk_init()
*R(VIRTIO_MMIO_QUEUE_SEL) = 0; *R(VIRTIO_MMIO_QUEUE_SEL) = 0;
uint32 max = *R(VIRTIO_MMIO_QUEUE_NUM_MAX); uint32 max = *R(VIRTIO_MMIO_QUEUE_NUM_MAX);
if (max == 0) if (max == 0)
lib_puts("virtio disk has no queue 0\n"); panic("virtio disk has no queue 0\n");
if (max < NUM) 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; *R(VIRTIO_MMIO_QUEUE_NUM) = NUM;
memset(disk.pages, 0, sizeof(disk.pages)); 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 // desc = pages -- num * virtq_desc
// avail = pages + 0x40 -- 2 * uint16, then num * uint16 // avail = pages + 0x40 -- 2 * uint16, then num * uint16
@@ -214,18 +214,11 @@ alloc3_desc(int *idx)
return 0; 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); uint32 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.
// allocate the three descriptors. // allocate the three descriptors.
lib_puts("rw init...\n");
int idx[3]; int idx[3];
while (1) while (1)
{ {
@@ -244,15 +237,15 @@ void virtio_disk_rw(struct buf *b, int write)
buf0->type = VIRTIO_BLK_T_OUT; // write the disk buf0->type = VIRTIO_BLK_T_OUT; // write the disk
else else
buf0->type = VIRTIO_BLK_T_IN; // read the disk 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. 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]].len = sizeof(struct virtio_blk_req);
disk.desc[idx[0]].flags = VRING_DESC_F_NEXT; disk.desc[idx[0]].flags = VRING_DESC_F_NEXT;
disk.desc[idx[0]].next = idx[1]; 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; disk.desc[idx[1]].len = BSIZE;
if (write) if (write)
disk.desc[idx[1]].flags = 0; // device reads b->data 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.desc[idx[1]].next = idx[2];
disk.info[idx[0]].status = 0xff; // device writes 0 on success 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]].len = 1;
disk.desc[idx[2]].flags = VRING_DESC_F_WRITE; // device writes the status disk.desc[idx[2]].flags = VRING_DESC_F_WRITE; // device writes the status
disk.desc[idx[2]].next = 0; disk.desc[idx[2]].next = 0;
// record struct buf for virtio_disk_intr(). // record struct buf for virtio_disk_intr().
b->disk = 1;
disk.info[idx[0]].b = b; disk.info[idx[0]].b = b;
__sync_synchronize();
// tell the device the first index in our chain of descriptors. // tell the device the first index in our chain of descriptors.
disk.avail->ring[disk.avail->idx % NUM] = idx[0]; disk.avail->ring[disk.avail->idx % NUM] = idx[0];
lib_puts("rw wait...\n");
__sync_synchronize(); __sync_synchronize();
// tell the device another avail ring entry is available. // tell the device another avail ring entry is available.
disk.avail->idx += 1; // not % NUM ... disk.avail->idx += 1; // not % NUM ...
__sync_synchronize(); *R(VIRTIO_MMIO_QUEUE_NOTIFY) = 0; // The device starts immediately when we write 0 to queue_notify.
*R(VIRTIO_MMIO_QUEUE_NOTIFY) = 0; // value is queue number
// Wait for virtio_disk_intr() to say request has finished.
// while (b->disk == 1)
// {
// }
disk.info[idx[0]].b = 0; disk.info[idx[0]].b = 0;
free_chain(idx[0]);
lock_free(&disk.vdisk_lock);
} }
void virtio_disk_isr() void virtio_disk_isr()
@@ -319,8 +303,7 @@ void virtio_disk_isr()
if (disk.info[id].status != 0) if (disk.info[id].status != 0)
panic("virtio_disk_intr status"); panic("virtio_disk_intr status");
struct buf *b = disk.info[id].b; struct blk *b = disk.info[id].b;
b->disk = 0; // disk is done with buf
disk.used_idx += 1; disk.used_idx += 1;
} }

View File

@@ -59,7 +59,7 @@ typedef struct virtq_desc
* flags: 用於控制 descriptor 。 * flags: 用於控制 descriptor 。
* next: 告訴 Device 下一個描述符的 Index 。如果指定了 VIRTQ_DESC_F_NEXT Device 僅讀取該字段。否則無效。 * next: 告訴 Device 下一個描述符的 Index 。如果指定了 VIRTQ_DESC_F_NEXT Device 僅讀取該字段。否則無效。
*/ */
uint64 addr; uint32 addr;
uint32 len; uint32 len;
uint16 flags; uint16 flags;
uint16 next; uint16 next;
@@ -115,5 +115,5 @@ typedef struct virtio_blk_req
{ {
uint32 type; // VIRTIO_BLK_T_IN or ..._OUT uint32 type; // VIRTIO_BLK_T_IN or ..._OUT
uint32 reserved; // 將 Header 擴充到 16-byte ,並將 64-bit sector 移到正確的位置。 uint32 reserved; // 將 Header 擴充到 16-byte ,並將 64-bit sector 移到正確的位置。
uint64 sector; uint32 sector;
} virtio_blk_req_t; } virtio_blk_req_t;

View File

@@ -62,3 +62,4 @@ in the `LICENSE` file.
- [Adventures in RISC-V](https://matrix89.github.io/writes/writes/experiments-in-riscv/) - [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) - [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/) - [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)

View File

@@ -108,7 +108,7 @@ struct virtq_used
+------------------+ +------------------+
``` ```
完成 Device Driver 方便我們在日後實現檔案系統。 完成 Device Driver 會讓我們在日後實現檔案系統更為方便,此外,參考 xv6-riscv 的設計,我們還會需要實現一層 Buffer cache 用來同步硬碟上的資料
### 指定寫入的 Sector ### 指定寫入的 Sector
@@ -153,7 +153,7 @@ if(write)
buf0->type = VIRTIO_BLK_T_OUT; // write the disk buf0->type = VIRTIO_BLK_T_OUT; // write the disk
else else
buf0->type = VIRTIO_BLK_T_IN; // read the disk 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. buf0->sector = sector; // specify the sector that we wanna modified.
``` ```