From bf870a1dde437a48ae40d092a14e164c861ea102 Mon Sep 17 00:00:00 2001 From: Minep Date: Thu, 18 Aug 2022 12:34:03 +0100 Subject: [PATCH 1/1] fix: READ_CAPACITY command for 12 bytes CDB SCSI device. fix: PACKET command hangs in Virtualbox when try to write readonly drive. fix: possible null pointer dereference in pcache_commit_all. chore: attach cdrom into QEMU's IDE bus. --- lunaix-os/config/make-debug-tool | 2 ++ lunaix-os/hal/ahci/ahci.c | 17 +++++++++++++---- lunaix-os/hal/ahci/ata.c | 5 +++-- lunaix-os/hal/ahci/atapi.c | 13 ++++++++++--- lunaix-os/includes/hal/ahci/hba.h | 11 +++++++++-- lunaix-os/includes/hal/ahci/scsi.h | 3 +++ lunaix-os/kernel/fs/pcache.c | 4 ++++ lunaix-os/makefile | 6 +++--- 8 files changed, 47 insertions(+), 14 deletions(-) diff --git a/lunaix-os/config/make-debug-tool b/lunaix-os/config/make-debug-tool index 2376ede..061cbc0 100644 --- a/lunaix-os/config/make-debug-tool +++ b/lunaix-os/config/make-debug-tool @@ -9,6 +9,8 @@ QEMU_OPTIONS := -s -S -m 1G \ -d cpu_reset \ -d trace:ide_dma_cb \ -drive id=disk,file="machine/disk0.vdi",if=none \ + -drive id=cdrom,file="$(BUILD_DIR)/$(OS_ISO)",readonly=on,if=none,format=raw \ -device ahci,id=ahci \ -device ide-hd,drive=disk,bus=ahci.0 \ + -device ide-cd,drive=cdrom,bus=ahci.1 \ -monitor telnet::$(QEMU_MON_PORT),server,nowait & \ No newline at end of file diff --git a/lunaix-os/hal/ahci/ahci.c b/lunaix-os/hal/ahci/ahci.c index a04bca7..21eaa1d 100644 --- a/lunaix-os/hal/ahci/ahci.c +++ b/lunaix-os/hal/ahci/ahci.c @@ -172,7 +172,8 @@ ahci_init() port_regs[HBA_RPxCMD] |= HBA_PxCMD_ST; if (!ahci_init_device(port)) { - kprintf(KERROR "fail to init device"); + kprintf(KERROR "init fail: 0x%x@p%d\n", port->regs[HBA_RPxSIG], i); + continue; } block_mount_disk(port->device); @@ -383,12 +384,20 @@ ahci_init_device(struct hba_port* port) * SATA AHCI HBA Spec, Section 5.3.7 * SCSI Command Reference Manual, Section 3.26 */ - struct scsi_cdb16* cdb16 = (struct scsi_cdb16*)cmd_table->atapi_cmd; sata_create_fis(cmd_fis, ATA_PACKET, 512 << 8, 0); - scsi_create_packet16(cdb16, SCSI_READ_CAPACITY_16, 0, 512); - cdb16->misc1 = 0x10; // service action + // for dev use 12 bytes cdb, READ_CAPACITY must use the 10 bytes variation. + if (port->device->cbd_size == 12) { + struct scsi_cdb12* cdb12 = (struct scsi_cdb12*)cmd_table->atapi_cmd; + // ugly tricks to construct 10 byte cdb from 12 byte cdb + scsi_create_packet12(cdb12, SCSI_READ_CAPACITY_10, 0, 512 << 8); + } else { + struct scsi_cdb16* cdb16 = (struct scsi_cdb16*)cmd_table->atapi_cmd; + scsi_create_packet16(cdb16, SCSI_READ_CAPACITY_16, 0, 512); + cdb16->misc1 = 0x10; // service action + } + cmd_header->transferred_size = 0; cmd_header->options |= HBA_CMDH_ATAPI; diff --git a/lunaix-os/hal/ahci/ata.c b/lunaix-os/hal/ahci/ata.c index a77e03b..118bf11 100644 --- a/lunaix-os/hal/ahci/ata.c +++ b/lunaix-os/hal/ahci/ata.c @@ -9,8 +9,9 @@ void sata_read_error(struct hba_port* port) { uint32_t tfd = port->regs[HBA_RPxTFD]; - port->device->last_error = (tfd >> 8) & 0xff; - port->device->last_status = tfd & 0xff; + port->device->last_result.sense_key = (tfd & 0xf000) >> 12; + port->device->last_result.error = (tfd & 0x0f00) >> 8; + port->device->last_result.status = tfd & 0x00ff; } int diff --git a/lunaix-os/hal/ahci/atapi.c b/lunaix-os/hal/ahci/atapi.c index 85c3bab..76c3795 100644 --- a/lunaix-os/hal/ahci/atapi.c +++ b/lunaix-os/hal/ahci/atapi.c @@ -37,8 +37,15 @@ scsi_create_packet16(struct scsi_cdb16* cdb, void scsi_parse_capacity(struct hba_device* device, uint32_t* parameter) { - device->max_lba = SCSI_FLIP(*(parameter + 1)); - device->block_size = SCSI_FLIP(*(parameter + 2)); + if (device->cbd_size == SCSI_CDB16) { + device->max_lba = + SCSI_FLIP(*(parameter + 1)) | (SCSI_FLIP(*parameter) << 32); + device->block_size = SCSI_FLIP(*(parameter + 2)); + } else { + // for READ_CAPACITY(10) + device->max_lba = SCSI_FLIP(*(parameter)); + device->block_size = SCSI_FLIP(*(parameter + 1)); + } } int @@ -90,7 +97,7 @@ __scsi_buffer_io(struct hba_device* dev, while (retries < MAX_RETRY) { port->regs[HBA_RPxCI] = bitmask; - wait_until(!(port->regs[HBA_RPxCI] & bitmask)); + wait_until_expire(!(port->regs[HBA_RPxCI] & bitmask), 1000000); if ((port->regs[HBA_RPxTFD] & HBA_PxTFD_ERR)) { // 有错误 diff --git a/lunaix-os/includes/hal/ahci/hba.h b/lunaix-os/includes/hal/ahci/hba.h index c868c6f..92a2b5a 100644 --- a/lunaix-os/includes/hal/ahci/hba.h +++ b/lunaix-os/includes/hal/ahci/hba.h @@ -33,6 +33,8 @@ #define HBA_PxINTR_DMA (1 << 2) #define HBA_PxINTR_DHR (1) #define HBA_PxINTR_DPS (1 << 5) +#define HBA_PxINTR_TFEE (1 << 30) +#define HBA_PxINTR_IFE (1 << 27) #define HBA_PxTFD_ERR (1) #define HBA_PxTFD_BSY (1 << 7) #define HBA_PxTFD_DRQ (1 << 3) @@ -100,8 +102,13 @@ struct hba_device uint32_t block_size; uint64_t wwn; uint8_t cbd_size; - uint8_t last_error; - uint8_t last_status; + struct + { + uint8_t sense_key; + uint8_t error; + uint8_t status; + uint8_t reserve; + } last_result; uint32_t alignment_offset; uint32_t block_per_sec; uint32_t capabilities; diff --git a/lunaix-os/includes/hal/ahci/scsi.h b/lunaix-os/includes/hal/ahci/scsi.h index 0635614..fee899f 100644 --- a/lunaix-os/includes/hal/ahci/scsi.h +++ b/lunaix-os/includes/hal/ahci/scsi.h @@ -14,6 +14,9 @@ #define SCSI_WRITE_BLOCKS_16 0x8a #define SCSI_WRITE_BLOCKS_12 0xaa +#define SCSI_CDB16 16 +#define SCSI_CDB12 12 + struct scsi_cdb12 { uint8_t opcode; diff --git a/lunaix-os/kernel/fs/pcache.c b/lunaix-os/kernel/fs/pcache.c index 9d883f9..8ef8fc8 100644 --- a/lunaix-os/kernel/fs/pcache.c +++ b/lunaix-os/kernel/fs/pcache.c @@ -189,6 +189,10 @@ pcache_commit(struct v_inode* inode, struct pcache_pg* page) void pcache_commit_all(struct v_inode* inode) { + if (!inode->pg_cache) { + return; + } + struct pcache* cache = inode->pg_cache; struct pcache_pg *pos, *n; diff --git a/lunaix-os/makefile b/lunaix-os/makefile index 879304b..20de158 100644 --- a/lunaix-os/makefile +++ b/lunaix-os/makefile @@ -51,20 +51,20 @@ clean: @sleep 1 run: $(BUILD_DIR)/$(OS_ISO) - @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) $(QEMU_OPTIONS) + @qemu-system-i386 $(QEMU_OPTIONS) @sleep 1 @telnet 127.0.0.1 $(QEMU_MON_PORT) debug-qemu: all-debug @i686-elf-objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg - @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) $(QEMU_OPTIONS) + @qemu-system-i386 $(QEMU_OPTIONS) @sleep 1 @$(QEMU_MON_TERM) -- telnet 127.0.0.1 $(QEMU_MON_PORT) @gdb -s $(BUILD_DIR)/kernel.dbg -ex "target remote localhost:1234" debug-qemu-vscode: all-debug @i686-elf-objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg - @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) $(QEMU_OPTIONS) + @qemu-system-i386 $(QEMU_OPTIONS) @sleep 0.5 @telnet 127.0.0.1 $(QEMU_MON_PORT) -- 2.27.0