From de70d136fb615422c7397ea0fa7566771ded80c3 Mon Sep 17 00:00:00 2001 From: Mathieu Serandour Date: Fri, 14 Jan 2022 13:04:05 +0100 Subject: [PATCH] wip --- Makefile | 2 + kernel/drivers/nvme/commands.c | 82 ++++++-------------- kernel/drivers/nvme/commands.h | 12 +-- kernel/drivers/nvme/nvme.c | 134 +++++++++++++++++++++++---------- kernel/drivers/nvme/nvme.h | 4 + kernel/entry.c | 13 ++-- 6 files changed, 134 insertions(+), 113 deletions(-) diff --git a/Makefile b/Makefile index f77f22e..7620d55 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,8 @@ QEMU_COMMON_ARGS := -bios /usr/share/ovmf/OVMF.fd \ -vga virtio \ -no-reboot \ -D qemu.log \ + -trace "pci_nvme_*" \ + -trace "apic_*" \ -device nvme,drive=NVME1,serial=deadbeef \ -drive format=raw,if=none,id=NVME1,file= diff --git a/kernel/drivers/nvme/commands.c b/kernel/drivers/nvme/commands.c index dc16e31..97bc003 100644 --- a/kernel/drivers/nvme/commands.c +++ b/kernel/drivers/nvme/commands.c @@ -18,54 +18,6 @@ void doorbell_submission( } -/** - * @brief enqueue the sqe sbmission queue entry - * structure to the given submission queue. Update - * the associated doorbell register and the - * submission tail value in the sq queue structure. - * - * - * @param doorbell_stride the NVM doorbell stride - * @param regs the virtual address of the NVME - * register space (bar0 base) - * @param sq a pointer to the submission queue - * structure in which the command is to - * be enqueued - * @param sqe a pointer to the submission queue - * entry structure describing the command - * be enqueue - * @return int - */ -static int insert_command( - unsigned doorbell_stride, - struct regs* regs, - struct queue* sq, - struct subqueuee* sqe -) { - assert(!queue_full(sq)); - - volatile - struct subqueuee* tail = queue_tail_ptr(sq); - - memcpy(tail, sqe, sizeof(struct subqueuee)); - - log_warn("INSERT COMMAND %lx IN QUEUE %x", tail, sq->id); - - - uint16_t tail_idx = queue_produce(sq); - // doorbell - doorbell_submission( - doorbell_stride, - regs, - sq->id, // admin queue - tail_idx // new tail value - ); - - - return tail_idx; -} - - void async_command( unsigned doorbell_stride, struct regs* regs, @@ -76,12 +28,18 @@ void async_command( uint32_t nsid, uint64_t prp0, uint64_t prp1, - uint64_t cdw10, - uint64_t cdw11, - uint64_t cdw12 + uint32_t cdw10, + uint32_t cdw11, + uint32_t cdw12 ) { - - struct subqueuee commande = { + assert(!queue_full(sq)); + + volatile + struct subqueuee* tail = queue_tail_ptr(sq); + + + + *tail = (struct subqueuee) { .cmd = make_cmd( opcode, // opcode 0, // fused @@ -100,12 +58,14 @@ void async_command( .cdw12 = cdw12, }; + uint16_t tail_idx = queue_produce(sq); - insert_command( - doorbell_stride, - regs, - sq, - &commande + // doorbell + doorbell_submission( + doorbell_stride, + regs, + sq->id, // admin queue + tail_idx // new tail value ); } @@ -120,9 +80,9 @@ void sync_command( uint32_t nsid, uint64_t prp0, uint64_t prp1, - uint64_t cdw10, - uint64_t cdw11, - uint64_t cdw12 + uint32_t cdw10, + uint32_t cdw11, + uint32_t cdw12 ) { async_command( diff --git a/kernel/drivers/nvme/commands.h b/kernel/drivers/nvme/commands.h index a8584a3..6fc00ce 100644 --- a/kernel/drivers/nvme/commands.h +++ b/kernel/drivers/nvme/commands.h @@ -44,9 +44,9 @@ void async_command( uint32_t nsid, uint64_t prp0, uint64_t prp1, - uint64_t cdw10, - uint64_t cdw11, - uint64_t cdw12 + uint32_t cdw10, + uint32_t cdw11, + uint32_t cdw12 ); @@ -84,7 +84,7 @@ void sync_command( uint32_t nsid, uint64_t prp0, uint64_t prp1, - uint64_t cdw10, - uint64_t cdw11, - uint64_t cdw12 + uint32_t cdw10, + uint32_t cdw11, + uint32_t cdw12 ); diff --git a/kernel/drivers/nvme/nvme.c b/kernel/drivers/nvme/nvme.c index c061e3c..2c2d7ca 100644 --- a/kernel/drivers/nvme/nvme.c +++ b/kernel/drivers/nvme/nvme.c @@ -34,7 +34,7 @@ static void remove(driver_t* this); -#define HANDLED_NAMESPACES 4 +#define HANDLED_NAMESPACES 1 #define ADMIN_QUEUE_SIZE 2 #define IO_QUEUE_SIZE 64 @@ -76,11 +76,8 @@ void perform_read_command( struct data* data, struct regs* regs, uint64_t lba, - void* buf, - size_t count, - - uint16_t cmdid, - uint32_t nsid + void* _buf, + size_t count ); @@ -471,7 +468,7 @@ static void identify_namespace( ns->block_size_shift = lbafs[lbaid].ds; if(!ns->block_size_shift) ns->block_size_shift = 9; - + log_info("namespace:\n" " ns->id : %lx\n" @@ -501,8 +498,9 @@ static void identify_namespace( static void identify_active_namespaces( - struct data* data, - struct regs* regs + struct driver* this, + struct data* data, + struct regs* regs ) { // physical base address // of the destination data @@ -535,7 +533,17 @@ void identify_active_namespaces( data->nns = i; - + if(data->nns == 0) + log_warn("NVMe: no namespace found"); + else if(data->nns > 1) + log_warn("NVMe: Bincows currently only handles" + "one NVMe namespace per controller. " + "%u namespaces are ignored for device %s.", + + data->nns-1, + this->device->name + ); + log_warn("%u found namespaces: %x", data->nns, data->namespaces[0].id); // no need to keep this. @@ -690,17 +698,14 @@ int nvme_install(driver_t* this) { // actually it holds no usefull information identify_controller(data, bar0); - log_warn("creating IO queues"); createIOqueues(data, bar0); - - log_warn("identify_active_namespaces"); - identify_active_namespaces(data, bar0); + identify_active_namespaces(this, data, bar0); // iterate over identified namespaces - for(unsigned i = 0; i < data->nns; i++) - identify_namespace(data, bar0, i); - + //for(unsigned i = 0; i < data->nns; i++) + identify_namespace(data, bar0, 0); + sleep(10000); this->status = DRIVER_STATE_OK; @@ -710,18 +715,17 @@ int nvme_install(driver_t* this) { perform_read_command( data, bar0, - 0, + 0x001fca00 >> 9, vaddr, - 1, - 10, - 1 + 8 ); while(! queue_empty(&data->io_queues.sq)) sleep(1); + dump( vaddr, - 512, + 0x1000 /8, 32, DUMP_HEX8 ); @@ -783,32 +787,80 @@ static void remove(driver_t* this) { } +// better be well alligned static void perform_read_command( struct data* data, struct regs* regs, uint64_t lba, - void* buf, - size_t count, - - uint16_t cmdid, - uint32_t nsid + void* _buf, + size_t count ) { - uint64_t paddr = trv2p(buf); + // general assert protection + assert(lba < data->namespaces[0].capacity); + assert(lba + count < data->namespaces[0].capacity); + assert(data->namespaces[0].id == 1); + assert(data->nns >= 1); - async_command( // create IO completion queue - data->doorbell_stride, - regs, // NVMe register space - &data->io_queues.sq, // admin submission queue - OPCODE_IO_READ, - cmdid, // cmdid - nsid, // nsid - paddr, // prp0 - 0, // prp1 - lba&0xffffffff, // cdw10: low lba part - lba>>32, // cdw11: high lba part - count // cdw12 low part: count + // NVME PRP: must be dword aligned + assert_aligned(_buf, 4); + + uint64_t buf_vaddr = (uint64_t)_buf; + + + unsigned shift = data->namespaces[0].block_size_shift; + + + // must not cross a 4K page boudary + assert( + ((buf_vaddr + (1 << shift)) & ~0x0fff) + ==( buf_vaddr & ~0x0fff) ); -} + while(count != 0) { + unsigned c = 0; + + uint64_t page_base = buf_vaddr & ~0x0fff; + + // find the biggest size for the access + // that does not cross a page border (in + // our shitty architecture) + int i = 0; + while(1) { + uint64_t next = buf_vaddr + (1 << shift); + + // crossed a 4K page border + if((next & ~0x0fff) != page_base) + break; + + c++; + count--; + log_warn("%lx - %lx - %lx", next, page_base, (1 << shift)); + + buf_vaddr = next; + } + + // c == 0 if the buffer is not well aligned + assert(c != 0); + + + uint64_t paddr = trv2p((void*)buf_vaddr); + + async_command( // create IO completion queue + data->doorbell_stride, + regs, // NVMe register space + &data->io_queues.sq, // admin submission queue + OPCODE_IO_READ, + 0, // cmdid - unused + 1, // nsid + paddr, // prp0 + 0, // prp1 + lba&0xffffffff, // cdw10: low lba part + lba>>32, // cdw11: high lba part + c // cdw12 low part: count + ); + + buf_vaddr += c >> shift; + } +} diff --git a/kernel/drivers/nvme/nvme.h b/kernel/drivers/nvme/nvme.h index 805bc36..fc7db89 100644 --- a/kernel/drivers/nvme/nvme.h +++ b/kernel/drivers/nvme/nvme.h @@ -9,6 +9,10 @@ struct driver; int nvme_install(struct driver*); +// 512 - 1024 - 2048 - 4096 +int nvme_get_blocksize(struct driver*); + + /** * @brief read contiguous memory region from * NVME drive. On error, a kernel panic occurs. diff --git a/kernel/entry.c b/kernel/entry.c index 87bf73d..7992752 100644 --- a/kernel/entry.c +++ b/kernel/entry.c @@ -111,9 +111,7 @@ static void init_memory( ) { log_debug("init memory..."); init_physical_allocator(memmap_tag); - - - init_paging(memmap_tag); + init_paging (memmap_tag); // map MMIOs map_pages( @@ -191,6 +189,7 @@ void _start(struct stivale2_struct *stivale2_struct) { set_logging_level(LOG_LEVEL_DEBUG); setup_isrs(); + read_acpi_tables((void*)rsdp_tag_ptr->rsdp); init_memory(memmap_tag, framebuffer_tag); @@ -223,13 +222,17 @@ void _start(struct stivale2_struct *stivale2_struct) { // terminal is successfully installed init_gdt_table(); + puts(&_binary_bootmessage_txt); printf("boot logs:\n"); puts(log_get()); log_flush(); + hpet_init(); + apic_setup_clock(); + pcie_init(); pic_init(); @@ -237,8 +240,7 @@ void _start(struct stivale2_struct *stivale2_struct) { ps2kb_set_event_callback(kbhandler); - hpet_init(); - apic_setup_clock(); + //printf("issou"); @@ -246,6 +248,7 @@ void _start(struct stivale2_struct *stivale2_struct) { for(;;) { asm volatile("hlt"); + //log_info("clock()=%lu", clock()); } __builtin_unreachable();