From fe628466b41f5144fe6bf11769ea2d8db1210e5c Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Mon, 6 Apr 2026 10:38:44 +0200 Subject: [PATCH] usbdrv Read from USB flash drive --- .gitignore | 1 + aux/limine_img_amd64.sh | 30 +++++++ aux/write_img.sh | 19 +++++ kernel/device/storage/usbdrv.c | 149 +++++++++++++++++++++++++++++++-- kernel/device/usb/usb.c | 18 +++- kernel/device/usb/xhci.c | 4 + 6 files changed, 211 insertions(+), 10 deletions(-) create mode 100755 aux/limine_img_amd64.sh create mode 100755 aux/write_img.sh diff --git a/.gitignore b/.gitignore index efd9086..7ba03df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ iso_root +img_root mop3.iso bochs-log.txt bochs-com1.txt diff --git a/aux/limine_img_amd64.sh b/aux/limine_img_amd64.sh new file mode 100755 index 0000000..2f40312 --- /dev/null +++ b/aux/limine_img_amd64.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +make -C boot/limine +rm -rf img_root +mkdir -p img_root/boot/limine +mkdir -p img_root/EFI/BOOT + +cp -v kernel/build/kernel.elf img_root/boot/ +cp -v boot/limine/limine-bios.sys boot/limine/limine.conf img_root/boot/limine/ +cp -v boot/limine/limine-bios-cd.bin boot/limine/limine-uefi-cd.bin img_root/boot/limine/ +cp -v boot/limine/BOOTX64.EFI boot/limine/BOOTIA32.EFI img_root/EFI/BOOT/ +cp -v mop3dist.tar.lz4 img_root/boot/ + +dd if=/dev/zero of=mop3.img bs=1M count=64 + +parted -s mop3.img mklabel msdos mkpart primary fat32 1MiB 100% set 1 boot on + +LOOPDEV=$(sudo losetup -Pf --show mop3.img) +sudo mkfs.fat -F 32 ${LOOPDEV}p1 + +mkdir -p mnt +sudo mount ${LOOPDEV}p1 mnt + +sudo cp -rv img_root/* mnt/ + +sudo umount mnt +sudo losetup -d $LOOPDEV +rmdir mnt + +boot/limine/limine bios-install mop3.img diff --git a/aux/write_img.sh b/aux/write_img.sh new file mode 100755 index 0000000..d7c9ff0 --- /dev/null +++ b/aux/write_img.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# Requires sudo +# USAGE: ./aux/write_img.sh /dev/sda + +TARGET="$1" + +if [ -z "$TARGET" ]; then + exit 1 +fi + +if [ ! -b "$TARGET" ]; then + echo "Not a block device" + exit 1 +fi + +set -x + +dd if=./mop3.img of="$TARGET" bs=4M status=progress oflag=direct conv=notrunc,sync && sync diff --git a/kernel/device/storage/usbdrv.c b/kernel/device/storage/usbdrv.c index 86816c8..48a134a 100644 --- a/kernel/device/storage/usbdrv.c +++ b/kernel/device/storage/usbdrv.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -14,7 +15,10 @@ #include #include -/* REF: https://en.wikipedia.org/wiki/SCSI */ +/* REF: + * https://en.wikipedia.org/wiki/SCSI + * https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf + */ static int usb_ms_send_cbw (struct xhci* xhci, struct xhci_usb_device* usb_device, uint8_t bulk_out_endpoint, uintptr_t cbw_phys, uint64_t* lockflags) { @@ -147,6 +151,79 @@ done: return ret; } +static int usb_ms_scsi_read (struct xhci* xhci, struct xhci_usb_device* usb_device, + uint8_t bulk_in_endpoint, uint8_t bulk_out_endpoint, + uint8_t* out_buffer, uint32_t lba, uint16_t sector_count, + size_t sector_size, uint64_t* lockflags) { + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + int ret; + + uintptr_t cbw_phys = pmm_alloc (1); + struct usb_ms_cbw* cbw = (struct usb_ms_cbw*)(cbw_phys + (uintptr_t)hhdm->offset); + memset (cbw, 0, PAGE_SIZE); + + size_t data_pages = div_align_up (sector_count * sector_size, PAGE_SIZE); + uintptr_t data_phys = pmm_alloc (data_pages); + uint8_t* data = (uint8_t*)(data_phys + (uintptr_t)hhdm->offset); + memset (data, 0, PAGE_SIZE * data_pages); + + uintptr_t csw_phys = pmm_alloc (1); + struct usb_ms_csw* csw = (struct usb_ms_csw*)(csw_phys + (uintptr_t)hhdm->offset); + memset (csw, 0, PAGE_SIZE); + + uint8_t cdb[10] = { + 0x28, + 0x00, + /* LBA */ + (uint8_t)((lba & 0xFF000000) >> 24), + (uint8_t)((lba & 0x00FF0000) >> 16), + (uint8_t)((lba & 0x0000FF00) >> 8), + (uint8_t)((lba & 0xFF)), + 0x00, + /* Transfer Length */ + (uint8_t)((sector_count & 0xFF00) >> 8), + (uint8_t)((sector_count & 0x00FF)), + 0x00, + }; + + cbw->signature = USB_CBW_SIGNATURE; + cbw->tag = 0x12345678; + cbw->dir = 0x80; + cbw->lun = 0; + cbw->cmd_len = sizeof (cdb); + cbw->length = sector_count * sector_size; + memcpy (cbw->data, cdb, sizeof (cdb)); + + if ((ret = usb_ms_send_cbw (xhci, usb_device, bulk_out_endpoint, cbw_phys, lockflags)) < 0) { + goto done; + } + + if ((ret = usb_ms_read_data (xhci, usb_device, bulk_in_endpoint, data_phys, + sector_count * sector_size, lockflags)) < 0) { + goto done; + } + + if ((ret = usb_ms_read_csw (xhci, usb_device, bulk_in_endpoint, csw_phys, lockflags)) < 0) { + goto done; + } + + if (csw->status != 0 || csw->signature != USB_CSW_SIGNATURE) { + DEBUG ("Failed to read sectors. CSW status=%u residue=%u\n", csw->status, csw->residue); + ret = -ST_USB_CTRL_ERROR; + goto done; + } + + memcpy (out_buffer, data, sector_count * sector_size); + + ret = ST_OK; + +done: + pmm_free (cbw_phys, 1); + pmm_free (data_phys, data_pages); + pmm_free (csw_phys, 1); + return ret; +} + static void usbdrv_setup_endpoints (struct usbdrv* usbdrv) { for (size_t ep = 0; ep < usbdrv->usb_device->endpoints_count; ep++) { struct xhci_usb_device_endpoint* endpoint = &usbdrv->usb_device->endpoints[ep]; @@ -175,9 +252,34 @@ static void usbdrv_setup_endpoints (struct usbdrv* usbdrv) { } } -DEFINE_DEVICE_OP (usbdrv_read) {} +DEFINE_DEVICE_OP (usbdrv_read) { + uint64_t fd; -DEFINE_DEVICE_OP (usbdrv_write) {} + if (a1 == NULL || a2 == NULL || a3 == NULL) + return -ST_BAD_ADDRESS_SPACE; + + size_t sector = *(size_t*)a1; + size_t sector_count = *(size_t*)a2; + uint8_t* buffer = a3; + + struct usbdrv* usbdrv = device->udata; + + spin_unlock (&device->lock, *lockflags); + spin_lock (&usbdrv->xhci->device->lock, &fd); + spin_lock (&device->lock, lockflags); + + int ret = usb_ms_scsi_read (usbdrv->xhci, usbdrv->usb_device, usbdrv->bulk_in.endpoint_addr, + usbdrv->bulk_out.endpoint_addr, buffer, sector, sector_count, + usbdrv->sector_size, &fd); + + spin_unlock (&device->lock, *lockflags); + spin_unlock (&usbdrv->xhci->device->lock, fd); + spin_lock (&device->lock, lockflags); + + return ret; +} + +DEFINE_DEVICE_OP (usbdrv_write) { return -ST_XDRV_WRITE_ERROR; } DEFINE_DEVICE_OP (usbdrv_get_device_type) { if (a1 == NULL) @@ -190,11 +292,34 @@ DEFINE_DEVICE_OP (usbdrv_get_device_type) { return ST_OK; } -DEFINE_DEVICE_OP (usbdrv_get_sector_size) {} +DEFINE_DEVICE_OP (usbdrv_get_sector_size) { + if (a1 == NULL) + return -ST_BAD_ADDRESS_SPACE; -DEFINE_DEVICE_OP (usbdrv_get_size) {} + size_t* secsize = (size_t*)a1; + + struct usbdrv* usbdrv = device->udata; + + *secsize = usbdrv->sector_size; + + return ST_OK; +} + +DEFINE_DEVICE_OP (usbdrv_get_size) { + if (a1 == NULL) + return -ST_BAD_ADDRESS_SPACE; + + size_t* size = (size_t*)a1; + + struct usbdrv* usbdrv = device->udata; + + *size = (usbdrv->sector_size * usbdrv->sector_count); + + return ST_OK; +} DEFINE_DEVICE_INIT (usbdrv_init) { + uint64_t fd; int ret; struct usbdrv_init* init = arg; @@ -209,6 +334,8 @@ DEFINE_DEVICE_INIT (usbdrv_init) { device->udata = usbdrv; + spin_lock (&usbdrv->xhci->device->lock, &fd); + usbdrv_setup_endpoints (usbdrv); ret = @@ -223,15 +350,23 @@ DEFINE_DEVICE_INIT (usbdrv_init) { usbdrv->bulk_out.endpoint_addr, init->lockflags); } - if (ret < 0) + if (ret < 0) { + free (usbdrv); + spin_unlock (&usbdrv->xhci->device->lock, fd); return false; + } ret = usb_ms_scsi_read_capacity (usbdrv->xhci, usbdrv->usb_device, usbdrv->bulk_in.endpoint_addr, usbdrv->bulk_out.endpoint_addr, &usbdrv->sector_size, &usbdrv->sector_count, init->lockflags); - if (ret < 0) + if (ret < 0) { + free (usbdrv); + spin_unlock (&usbdrv->xhci->device->lock, fd); return false; + } + + spin_unlock (&usbdrv->xhci->device->lock, fd); DEBUG ("sector_count = %zu, sector_size = %u\n", usbdrv->sector_count, usbdrv->sector_size); diff --git a/kernel/device/usb/usb.c b/kernel/device/usb/usb.c index 102d8d1..90e2b9a 100644 --- a/kernel/device/usb/usb.c +++ b/kernel/device/usb/usb.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -16,7 +17,13 @@ static atomic_int usb_ms_counter = 0; static struct device* usb_ms_init (struct xhci* xhci, struct xhci_usb_device* usb_device, struct proc* proc, struct reschedule_ctx* rctx, uint64_t* lockflags) { - static device_op_func_t ops[] = {0}; + static device_op_func_t ops[] = { + [XDRV_GET_SIZE] = &usbdrv_get_size, + [XDRV_GET_SECTOR_SIZE] = &usbdrv_get_sector_size, + [XDRV_GET_DEVICE_TYPE] = &usbdrv_get_device_type, + [XDRV_READ] = &usbdrv_read, + [XDRV_WRITE] = &usbdrv_write, + }; struct usbdrv_init init = { .xhci = xhci, @@ -27,8 +34,13 @@ static struct device* usb_ms_init (struct xhci* xhci, struct xhci_usb_device* us char key[30]; snprintf (key, sizeof (key), "usbdrv%d", atomic_fetch_add (&usb_ms_counter, 1)); - return device_create (DEVICE_TYPE_DRIVE, key, ops, lengthof (ops), &usbdrv_init, &usbdrv_fini, - &init, proc, rctx); + struct device* device = device_create (DEVICE_TYPE_DRIVE, key, ops, lengthof (ops), &usbdrv_init, + &usbdrv_fini, &init, proc, rctx); + + if (device != NULL) + device_probe_partitions (proc, rctx, device); + + return device; } struct usb_driver_info usb_driver_infos[USB_DRIVER_MAX_MATCHES] = { diff --git a/kernel/device/usb/xhci.c b/kernel/device/usb/xhci.c index bde884c..9f5a361 100644 --- a/kernel/device/usb/xhci.c +++ b/kernel/device/usb/xhci.c @@ -918,8 +918,12 @@ static void xhci_poll_setup_init_ifs (struct xhci* xhci, struct xhci_usb_device* if (if_->desc.if_class == info->if_class && if_->desc.if_subclass == info->if_subclass && if_->desc.if_proto == info->if_proto) { + spin_unlock (&xhci->device->lock, *lockflags); + struct device* device = info->init (xhci, usb_device, thiscpu->kproc, &rctx, lockflags); + spin_lock (&xhci->device->lock, lockflags); + if (device == NULL) DEBUG ("USB driver failed to initialize. Skipping device!\n");