From 416a802b9cdb8a4172a98c4c48893b402cc2b348 Mon Sep 17 00:00:00 2001 From: fslongjin Date: Tue, 30 Aug 2022 20:34:52 +0800 Subject: [PATCH] new: xhci get descriptor --- Makefile | 8 +- kernel/driver/pci/msi.c | 2 + kernel/driver/usb/usb.h | 125 +++++- kernel/driver/usb/xhci/xhci.c | 793 +++++++++++++++++++++++++++++----- kernel/driver/usb/xhci/xhci.h | 149 ++++++- kernel/main.c | 9 +- run.sh | 22 +- 7 files changed, 980 insertions(+), 128 deletions(-) diff --git a/Makefile b/Makefile index 1a87b4c1..25420eda 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,22 @@ SUBDIRS = kernel user - +# ifndef $(EMULATOR) +ifeq ($(EMULATOR), ) +export EMULATOR=__NO_EMULATION__ +endif export ARCH=__x86_64__ export ROOT_PATH=$(shell pwd) export DEBUG=DEBUG -export GLOBAL_CFLAGS := -mcmodel=large -fno-builtin -m64 -fno-stack-protector -D $(ARCH) -O1 +export GLOBAL_CFLAGS := -mcmodel=large -fno-builtin -m64 -fno-stack-protector -D $(ARCH) -D $(EMULATOR) -O1 ifeq ($(DEBUG), DEBUG) GLOBAL_CFLAGS += -g endif + .PHONY: all all: kernel user diff --git a/kernel/driver/pci/msi.c b/kernel/driver/pci/msi.c index e18b1fc2..3f47fbef 100644 --- a/kernel/driver/pci/msi.c +++ b/kernel/driver/pci/msi.c @@ -164,6 +164,7 @@ int pci_enable_msi(struct msi_desc_t *msi_desc) if (msi_desc->pci.msi_attribute.is_msix) // MSI-X { + kdebug("is msix"); // 读取msix的信息 struct pci_msix_cap_t cap = __msi_read_msix_cap_list(msi_desc, cap_ptr); // 映射msix table @@ -181,6 +182,7 @@ int pci_enable_msi(struct msi_desc_t *msi_desc) } else { + kdebug("is msi"); tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值 message_control = (tmp >> 16) & 0xffff; diff --git a/kernel/driver/usb/usb.h b/kernel/driver/usb/usb.h index 6e90bddf..e1068b0a 100644 --- a/kernel/driver/usb/usb.h +++ b/kernel/driver/usb/usb.h @@ -1,4 +1,5 @@ #pragma once +#include // usb设备在pci总线上的class #define USB_CLASS 0xC @@ -9,17 +10,127 @@ #define USB_TYPE_OHCI 0x10 #define USB_TYPE_EHCI 0x20 #define USB_TYPE_XHCI 0x30 -#define USB_TYPE_UNSPEC 0x80 // Unspecified -#define USB_TYPE_DEVICE 0xfe // USB Device(Not controller) +#define USB_TYPE_UNSPEC 0x80 // Unspecified +#define USB_TYPE_DEVICE 0xfe // USB Device(Not controller) // Reset wait times(milliseconds) ,USB 2.0 specs, page 153, section 7.1.7.5, paragraph 3 -#define USB_TIME_RST_RH 50 // reset on a root hub -#define USB_TIME_RST_MIN 10 // minimum delay for a reset -#define USB_TIME_RST_NOMORE 3 // No more than this between resets for root hubs -#define USB_TIME_RST_REC 10 // reset recovery +#define USB_TIME_RST_RH 50 // reset on a root hub +#define USB_TIME_RST_MIN 10 // minimum delay for a reset +#define USB_TIME_RST_NOMORE 3 // No more than this between resets for root hubs +#define USB_TIME_RST_REC 10 // reset recovery + +/** + * @brief usb 设备描述符 + * + */ +struct usb_device_desc +{ + uint8_t len; + uint8_t type; + uint16_t usb_version; + uint8_t _class; + uint8_t subclass; + uint8_t protocol; + uint8_t max_packet_size; + + uint16_t vendor_id; + uint16_t product_id; + uint16_t device_rel; + uint8_t manufacturer_index; + uint8_t procuct_index; + + uint8_t serial_index; + uint8_t config; // number of configurations +}; + +/** + * @brief usb设备请求包 + * + */ +struct usb_request_packet_t +{ + uint8_t request_type; + uint8_t request; + uint16_t value; + + uint16_t index; + uint16_t length; +}; +// usb设备请求包的request_type字段的值 +#define __USB_REQ_TYPE_H2D 0x00 +#define __USB_REQ_TYPE_D2H 0x80 + +#define __USB_REQ_TYPE_STANDARD 0x00 +#define __USB_REQ_TYPE_CLASS 0x20 +#define __USB_REQ_TYPE_VENDOR 0x40 +#define __USB_REQ_TYPE_RSVD 0x60 + +#define __USB_REQ_TYPE_DEVICE 0x00 +#define __USB_REQ_TYPE_INTERFACE 0x01 +#define __USB_REQ_TYPE_ENDPOINT 0x02 +#define __USB_REQ_TYPE_OTHER 0x03 + +#define USB_REQ_TYPE_GET_REQUEST (__USB_REQ_TYPE_D2H | __USB_REQ_TYPE_STANDARD | __USB_REQ_TYPE_DEVICE) +#define USB_REQ_TYPE_SET_REQUEST (__USB_REQ_TYPE_H2D | __USB_REQ_TYPE_STANDARD | __USB_REQ_TYPE_DEVICE) +#define USB_REQ_TYPE_SET_INTERFACE (__USB_REQ_TYPE_H2D | __USB_REQ_TYPE_STANDARD | __USB_REQ_TYPE_INTERFACE) + +// device requests +enum +{ + USB_REQ_GET_STATUS = 0, + USB_REQ_CLEAR_FEATURE, + USB_REQ_SET_FEATURE = 3, + USB_REQ_SET_ADDRESS = 5, + USB_REQ_GET_DESCRIPTOR = 6, + USB_REQ_SET_DESCRIPTOR, + USB_REQ_GET_CONFIGURATION, + USB_REQ_SET_CONFIGURATION, + // interface requests + USB_REQ_GET_INTERFACE, + USB_REQ_SET_INTERFACE, + // standard endpoint requests + USB_REQ_SYNCH_FRAME, + // Device specific + USB_REQ_GET_MAX_LUNS = 0xFE, + USB_REQ_BULK_ONLY_RESET +}; + +// Descriptor types +enum +{ + USB_DT_DEVICE = 1, + USB_DT_CONFIG, + USB_DT_STRING, + USB_DT_INTERFACE, + USB_DT_ENDPOINT, + USB_DT_DEVICE_QUALIFIER, + USB_DT_OTHER_SPEED_CONFIG, + USB_DT_INTERFACE_POWER, + USB_DT_OTG, + USB_DT_DEBUG, + USB_DT_INTERFACE_ASSOSIATION, + + USB_DT_HID = 0x21, + USB_DT_HID_REPORT, + USB_DT_HID_PHYSICAL, + + USB_DT_INTERFACE_FUNCTION = 0x24, + USB_DT_ENDPOINT_FUNCTION, + + HUB = 0x29 +}; + +// transfer types (Endpoint types) (USB 2.0 page 270) +enum +{ + USB_EP_CONTROL = 0, + USB_EP_ISOCHRONOUS, + USB_EP_BULK, + USB_EP_INTERRUPT +}; /** * @brief 初始化usb驱动程序 - * + * */ void usb_init(); \ No newline at end of file diff --git a/kernel/driver/usb/xhci/xhci.c b/kernel/driver/usb/xhci/xhci.c index 8319dd24..3a37b49f 100644 --- a/kernel/driver/usb/xhci/xhci.c +++ b/kernel/driver/usb/xhci/xhci.c @@ -38,6 +38,17 @@ static int xhci_hc_init_intr(int id); static int xhci_hc_start_ports(int id); static int xhci_send_command(int id, struct xhci_TRB_t *trb, const bool do_ring); +static uint64_t xhci_initialize_slot(const int id, const int slot_id, const int port, const int speed, const int max_packet); +static void xhci_initialize_ep(const int id, const uint64_t slot_vaddr, const int slot_id, const int ep_num, const int max_packet, const int type, const int direction, const int speed, const int ep_interval); +static int xhci_set_address(const int id, const uint64_t slot_vaddr, const int slot_id, const bool block); +static int xhci_control_in(const int id, void *target, const int in_size, const int slot_id, const int max_packet); +static int xhci_setup_stage(struct xhci_ep_ring_info_t *ep, const struct usb_request_packet_t *packet, const uint8_t direction); +static int xhci_data_stage(struct xhci_ep_ring_info_t *ep, uint64_t buf_vaddr, uint8_t trb_type, const uint32_t size, uint8_t direction, const int max_packet, const uint64_t status_vaddr); +static int xhci_status_stage(const int id, uint8_t direction, uint64_t status_buf_vaddr); +static int xhci_wait_for_interrupt(const int id, uint64_t status_vaddr); + +static struct xhci_ep_context_t ep_ctx = {0}; +struct xhci_slot_context_t slot_ctx = {0}; hardware_intr_controller xhci_hc_intr_controller = { @@ -58,36 +69,31 @@ hardware_intr_controller xhci_hc_intr_controller = 这种情况下,我们必须从32bit的寄存器的0地址处开始读取32bit,然后通过移位的方式得到其中的字节。 */ -#define xhci_read_cap_reg32(id, offset) (*(uint32_t *)(xhci_hc[id].vbase + offset)) -#define xhci_get_ptr_cap_reg32(id, offset) ((uint32_t *)(xhci_hc[id].vbase + offset)) -#define xhci_write_cap_reg32(id, offset, value) (*(uint32_t *)(xhci_hc[id].vbase + offset) = (uint32_t)value) +#define xhci_read_cap_reg32(id, offset) (*(uint32_t *)(xhci_hc[id].vbase + (offset))) +#define xhci_get_ptr_cap_reg32(id, offset) ((uint32_t *)(xhci_hc[id].vbase + (offset))) +#define xhci_write_cap_reg32(id, offset, value) (*(uint32_t *)(xhci_hc[id].vbase + (offset)) = (uint32_t)(value)) -#define xhci_read_cap_reg64(id, offset) (*(uint64_t *)(xhci_hc[id].vbase + offset)) -#define xhci_get_ptr_reg64(id, offset) ((uint64_t *)(xhci_hc[id].vbase + offset)) -#define xhci_write_cap_reg64(id, offset, value) (*(uint64_t *)(xhci_hc[id].vbase + offset) = (uint64_t)value) +#define xhci_read_cap_reg64(id, offset) (*(uint64_t *)(xhci_hc[id].vbase + (offset))) +#define xhci_get_ptr_reg64(id, offset) ((uint64_t *)(xhci_hc[id].vbase + (offset))) +#define xhci_write_cap_reg64(id, offset, value) (*(uint64_t *)(xhci_hc[id].vbase + (offset)) = (uint64_t)(value)) -#define xhci_read_op_reg8(id, offset) (*(uint8_t *)(xhci_hc[id].vbase_op + offset)) -#define xhci_get_ptr_op_reg8(id, offset) ((uint8_t *)(xhci_hc[id].vbase_op + offset)) -#define xhci_write_op_reg8(id, offset, value) (*(uint8_t *)(xhci_hc[id].vbase_op + offset) = (uint8_t)value) +#define xhci_read_op_reg8(id, offset) (*(uint8_t *)(xhci_hc[id].vbase_op + (offset))) +#define xhci_get_ptr_op_reg8(id, offset) ((uint8_t *)(xhci_hc[id].vbase_op + (offset))) +#define xhci_write_op_reg8(id, offset, value) (*(uint8_t *)(xhci_hc[id].vbase_op + (offset)) = (uint8_t)(value)) -#define xhci_read_op_reg32(id, offset) (*(uint32_t *)(xhci_hc[id].vbase_op + offset)) -#define xhci_get_ptr_op_reg32(id, offset) ((uint32_t *)(xhci_hc[id].vbase_op + offset)) -#define xhci_write_op_reg32(id, offset, value) (*(uint32_t *)(xhci_hc[id].vbase_op + offset) = (uint32_t)value) +#define xhci_read_op_reg32(id, offset) (*(uint32_t *)(xhci_hc[id].vbase_op + (offset))) +#define xhci_get_ptr_op_reg32(id, offset) ((uint32_t *)(xhci_hc[id].vbase_op + (offset))) +#define xhci_write_op_reg32(id, offset, value) (*(uint32_t *)(xhci_hc[id].vbase_op + (offset)) = (uint32_t)(value)) -#define xhci_read_op_reg64(id, offset) (*(uint64_t *)(xhci_hc[id].vbase_op + offset)) -#define xhci_get_ptr_op_reg64(id, offset) ((uint64_t *)(xhci_hc[id].vbase_op + offset)) -#define xhci_write_op_reg64(id, offset, value) (*(uint64_t *)(xhci_hc[id].vbase_op + offset) = (uint64_t)value) +#define xhci_read_op_reg64(id, offset) (*(uint64_t *)(xhci_hc[id].vbase_op + (offset))) +#define xhci_get_ptr_op_reg64(id, offset) ((uint64_t *)(xhci_hc[id].vbase_op + (offset))) +#define xhci_write_op_reg64(id, offset, value) (*(uint64_t *)(xhci_hc[id].vbase_op + (offset)) = (uint64_t)(value)) -#define xhci_write_mem32(vaddr, value) (*(uint32_t *)(vaddr) = value) -#define xhci_write_mem64(vaddr, value) (*(uint64_t *)(vaddr) = value) +#define xhci_write_mem32(vaddr, value) (*(uint32_t *)(vaddr) = (value)) +#define xhci_write_mem64(vaddr, value) (*(uint64_t *)(vaddr) = (value)) #define xhci_read_mem32(vaddr) (*(uint32_t *)(vaddr)) #define xhci_read_mem64(vaddr) (*(uint64_t *)(vaddr)) -// 读取xhci中断寄存器组的值 -#define xhci_read_intr_reg32(id, set_id, offset) (*(uint32_t *)(xhci_hc[id].vbase + xhci_hc[id].rts_offset + 0x20 * (set_id + 1) + offset)) -// 向xhci中断寄存器组写入值 -#define xhci_write_intr_reg32(id, set_id, offset, value) (*(uint32_t *)(xhci_hc[id].vbase + xhci_hc[id].rts_offset + 0x20 * (set_id + 1) + offset) = value) - /** * @brief 计算中断寄存器组虚拟地址 * @param id 主机控制器id @@ -134,6 +140,11 @@ hardware_intr_controller xhci_hc_intr_controller = ptr->cycle = 1; \ } while (0) +// 设置endpoint结构体的dequeue_cycle_state bit +#define xhci_ep_set_dequeue_cycle_state(ep_ctx_ptr, state) ((ep_ctx_ptr)->tr_dequeue_ptr |= ((state)&1)) +// 获取endpoint结构体的dequeue_cycle_state bit +#define xhci_ep_get_dequeue_cycle_state(ep_ctx_ptr) (((ep_ctx_ptr)->tr_dequeue_ptr) & 1) + /** * @brief 在controller数组之中寻找可用插槽 * @@ -159,7 +170,7 @@ static int xhci_hc_find_available_id() * @param trb 要存储到的trb的地址 * @param address 待读取trb的地址 */ -static __always_inline void xhci_get_trb(struct xhci_TRB_t *trb, const uint32_t address) +static __always_inline void xhci_get_trb(struct xhci_TRB_t *trb, const uint64_t address) { trb->param = xhci_read_mem64(address); trb->status = xhci_read_mem32(address + 8); @@ -172,13 +183,100 @@ static __always_inline void xhci_get_trb(struct xhci_TRB_t *trb, const uint32_t * @param trb 源trb * @param address 拷贝的目标地址 */ -static __always_inline void xhci_set_trb(struct xhci_TRB_t *trb, const uint32_t address) +static __always_inline void xhci_set_trb(struct xhci_TRB_t *trb, const uint64_t address) { xhci_write_mem64(address, trb->param); xhci_write_mem32(address + 8, trb->status); xhci_write_mem32(address + 12, trb->command); } +/** + * @brief 将ep结构体写入到设备上下文中的对应块内 + * + * @param id 主机控制器id + * @param slot_vaddr 设备上下文虚拟地址 + * @param ep_num ep结构体要写入到哪个块中(在设备上下文中的块号) + * @param ep 源数据 + */ +static __always_inline void __write_ep(int id, uint64_t slot_vaddr, int ep_num, struct xhci_ep_context_t *ep) +{ + memcpy((void *)(slot_vaddr + ep_num * xhci_hc[id].context_size), ep, sizeof(struct xhci_ep_context_t)); +} + +/** + * @brief 从设备上下文中的对应块内读取数据到ep结构体 + * + * @param id 主机控制器id + * @param slot_vaddr 设备上下文虚拟地址 + * @param ep_num 要从哪个块中读取(在设备上下文中的块号) + * @param ep 目标地址 + */ +static __always_inline void __read_from_ep(int id, uint64_t slot_vaddr, int ep_num, struct xhci_ep_context_t *ep) +{ + memcpy(ep, (void *)(slot_vaddr + ep_num * xhci_hc[id].context_size), sizeof(struct xhci_ep_context_t)); +} + +/** + * @brief 将slot上下文数组结构体写入插槽的上下文空间 + * + * @param vaddr 目标地址 + * @param slot_ctx slot上下文数组 + */ +static __always_inline void __write_slot(const uint64_t vaddr, struct xhci_slot_context_t *slot_ctx) +{ + memcpy((void *)vaddr, slot_ctx, sizeof(struct xhci_slot_context_t)); +} + +/** + * @brief 从指定地址读取slot context + * + * @param slot_ctx 目标地址 + * @param slot_vaddr 源地址 + * @return __always_inline + */ +static __always_inline void __read_from_slot(struct xhci_slot_context_t *slot_ctx, uint64_t slot_vaddr) +{ + memcpy(slot_ctx, (void *)slot_vaddr, sizeof(struct xhci_slot_context_t)); +} + +/** + * @brief 写入doorbell寄存器 + * + * @param id 主机控制器id + * @param slot_id usb控制器插槽id(0用作命令门铃,其他的用于具体的设备的门铃) + * @param value endpoint + */ +static __always_inline void __xhci_write_doorbell(const int id, const uint16_t slot_id, const uint32_t value) +{ + // 确保写入门铃寄存器之前,所有的写操作均已完成 + io_mfence(); + xhci_write_cap_reg32(id, xhci_hc[id].db_offset + slot_id * sizeof(uint32_t), value); + io_mfence(); +} + +/** + * @brief 将trb写入指定的ring中,并更新下一个要写入的地址的值 + * + * @param ep_info 端点信息结构体 + * @param trb 待写入的trb + */ +static __always_inline void __xhci_write_trb(struct xhci_ep_ring_info_t *ep_info, struct xhci_TRB_t *trb) +{ + memcpy((void *)ep_info->current_ep_ring_vaddr, trb, sizeof(struct xhci_TRB_t)); + + ep_info->current_ep_ring_vaddr += sizeof(struct xhci_TRB_t); + + struct xhci_TRB_normal_t *ptr = (struct xhci_TRB_normal_t *)(ep_info->current_ep_ring_vaddr); + + // ring到头了,转换cycle,然后回到第一个trb + if (unlikely(ptr->TRB_type == TRB_TYPE_LINK)) + { + ptr->cycle = ep_info->current_ep_ring_cycle; + ep_info->current_ep_ring_vaddr = ep_info->ep_ring_vbase; + ep_info->current_ep_ring_cycle ^= 1; + } +} + /** * @brief 停止xhci主机控制器 * @@ -215,7 +313,6 @@ static int xhci_hc_stop(int id) static int xhci_hc_reset(int id) { int retval = 0; - kdebug("usbsts=%#010lx", xhci_read_op_reg32(id, XHCI_OPS_USBSTS)); io_mfence(); // 判断HCHalted是否置位 if ((xhci_read_op_reg32(id, XHCI_OPS_USBSTS) & (1 << 0)) == 0) @@ -231,11 +328,10 @@ static int xhci_hc_reset(int id) // reset uint32_t cmd = xhci_read_op_reg32(id, XHCI_OPS_USBCMD); io_mfence(); - kdebug("cmd=%#010lx", cmd); + cmd |= (1 << 1); xhci_write_op_reg32(id, XHCI_OPS_USBCMD, cmd); io_mfence(); - kdebug("after rst, sts=%#010lx", xhci_read_op_reg32(id, XHCI_OPS_USBSTS)); io_mfence(); while (xhci_read_op_reg32(id, XHCI_OPS_USBCMD) & (1 << 1)) { @@ -244,7 +340,7 @@ static int xhci_hc_reset(int id) if (--timeout == 0) return -ETIMEDOUT; } - // kdebug("reset done!, timeout=%d", timeout); + return retval; } @@ -540,16 +636,14 @@ void xhci_hc_irq_enable(uint64_t irq_num) io_mfence(); if (WARN_ON(cid == -1)) return; - kdebug("start msi"); + io_mfence(); pci_start_msi(xhci_hc[cid].pci_dev_hdr); - kdebug("start sched"); + io_mfence(); xhci_hc_start_sched(cid); - kdebug("start ports"); io_mfence(); xhci_hc_start_ports(cid); - kdebug("enabled"); } void xhci_hc_irq_disable(uint64_t irq_num) @@ -565,6 +659,13 @@ void xhci_hc_irq_disable(uint64_t irq_num) io_mfence(); } +/** + * @brief xhci中断的安装函数 + * + * @param irq_num 要安装的中断向量号 + * @param arg 参数 + * @return uint64_t 错误码 + */ uint64_t xhci_hc_irq_install(uint64_t irq_num, void *arg) { int cid = xhci_find_hcid_by_irq_num(irq_num); @@ -586,8 +687,6 @@ uint64_t xhci_hc_irq_install(uint64_t irq_num, void *arg) msi_desc.pci.msi_attribute.is_msix = 1; io_mfence(); int retval = pci_enable_msi(&msi_desc); - kdebug("pci retval = %d", retval); - kdebug("xhci irq %d installed.", irq_num); return 0; } @@ -611,9 +710,7 @@ void xhci_hc_irq_uninstall(uint64_t irq_num) */ void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs) { - // todo: handle irq - kdebug("USB irq received."); - + // kdebug("USB irq received."); /* 写入usb status寄存器,以表明当前收到了中断,清除usb status寄存器中的EINT位 需要先清除这个位,再清除interrupter中的pending bit) @@ -622,24 +719,25 @@ void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs) // 读取第0个usb interrupter的intr management寄存器 const uint32_t iman0 = xhci_read_intr_reg32(cid, 0, XHCI_IR_MAN); - kdebug("iman0=%d", iman0); - if ((iman0 & 3) == 3) // 中断被启用,且pending不为0 + uint64_t dequeue_reg = xhci_read_intr_reg64(cid, 0, XHCI_IR_DEQUEUE); + + if (((iman0 & 3) == 3) || (dequeue_reg & 8)) // 中断被启用,且pending不为0 { // 写入1以清除该interrupter的pending bit xhci_write_intr_reg32(cid, 0, XHCI_IR_MAN, iman0 | 3); - + io_mfence(); struct xhci_TRB_t event_trb, origin_trb; // event ring trb以及其对应的command trb uint64_t origin_vaddr; // 暂存当前trb的起始地址 uint64_t last_event_ring_vaddr = xhci_hc[cid].current_event_ring_vaddr; - xhci_get_trb(&event_trb, xhci_hc[cid].current_event_ring_vaddr); - while ((event_trb.command & 1) == xhci_hc[cid].current_event_ring_cycle) // 循环处理处于当前周期的所有event ring { + struct xhci_TRB_cmd_complete_t *event_trb_ptr = (struct xhci_TRB_cmd_complete_t *)&event_trb; if ((event_trb.command & (1 << 2)) == 0) // 当前event trb不是由于short packet产生的 { + switch (event_trb_ptr->code) // 判断它的完成码 { case TRB_COMP_TRB_SUCCESS: // trb执行成功,则将结果返回到对应的command ring的trb里面 @@ -647,7 +745,7 @@ void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs) switch (event_trb_ptr->TRB_type) // 根据event trb类型的不同,采取不同的措施 { case TRB_TYPE_COMMAND_COMPLETION: // 命令已经完成 - origin_vaddr = event_trb.param; + origin_vaddr = (uint64_t)phys_2_virt(event_trb.param); // 获取对应的command trb xhci_get_trb(&origin_trb, origin_vaddr); @@ -668,6 +766,7 @@ void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs) origin_trb.status |= XHCI_IRQ_DONE; // 将command trb写入到表中 xhci_set_trb(&origin_trb, origin_vaddr); + // kdebug("set origin:%#018lx", origin_vaddr); break; } break; @@ -682,7 +781,7 @@ void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs) { case TRB_TYPE_TRANS_EVENT: // 当前 event trb是 transfer event TRB // If SPD was encountered in this TD, comp_code will be SPD, else it should be SUCCESS (specs 4.10.1.1) - xhci_write_mem32(event_trb.param, (event_trb.status | XHCI_IRQ_DONE)); // return code + bytes *not* transferred + xhci_write_mem32(phys_2_virt(event_trb.param), (event_trb.status | XHCI_IRQ_DONE)); // return code + bytes *not* transferred break; default: @@ -694,11 +793,17 @@ void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs) last_event_ring_vaddr = xhci_hc[cid].current_event_ring_vaddr; xhci_hc[cid].current_event_ring_vaddr += sizeof(struct xhci_TRB_t); xhci_get_trb(&event_trb, xhci_hc[cid].current_event_ring_vaddr); + if (((struct xhci_TRB_normal_t *)&event_trb)->TRB_type == TRB_TYPE_LINK) + { + xhci_hc[cid].current_event_ring_vaddr = xhci_hc[cid].event_ring_vaddr; + xhci_get_trb(&event_trb, xhci_hc[cid].current_event_ring_vaddr); + } } // 当前event ring cycle的TRB处理结束 // 更新dequeue指针, 并清除event handler busy标志位 - xhci_write_intr_reg64(cid, 0, XHCI_IR_DEQUEUE, last_event_ring_vaddr | (1 << 3)); + xhci_write_intr_reg64(cid, 0, XHCI_IR_DEQUEUE, virt_2_phys(last_event_ring_vaddr) | (1 << 3)); + io_mfence(); } } /** @@ -713,7 +818,9 @@ static int xhci_reset_port(const int id, const int port) int retval = 0; // 相对于op寄存器基地址的偏移量 uint64_t port_status_offset = XHCI_OPS_PRS + port * 16; - // kdebug("to reset %d, offset=%#018lx", port, port_status_offset); + // kdebug("to reset %d, portsc=%#010lx", port, (xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC))); + // kdebug("to reset %d, usbcmd=%#010lx", port, xhci_read_op_reg32(id, XHCI_OPS_USBCMD)); + // kdebug("to reset %d, usbsts=%#010lx", port, xhci_read_op_reg32(id, XHCI_OPS_USBSTS)); io_mfence(); // 检查端口电源状态 if ((xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC) & (1 << 9)) == 0) @@ -768,15 +875,18 @@ static int xhci_reset_port(const int id, const int port) usleep(USB_TIME_RST_REC * 1000); uint32_t val = xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC); io_mfence(); + // 如果reset之后,enable bit仍然是1,那么说明reset成功 if (val & (1 << 1)) { + retval = 0; io_mfence(); // 清除status change bit xhci_write_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC, (1 << 9) | XHCI_PORTUSB_CHANGE_BITS); io_mfence(); } - retval = 0; + else + retval = -1; } // 如果usb2端口成功reset,则处理该端口的active状态 @@ -797,6 +907,506 @@ static int xhci_reset_port(const int id, const int port) return retval; } +/** + * @brief 初始化设备slot的上下文,并将其写入dcbaap中的上下文index数组 + * - at this time, we don't know if the device is a hub or not, so we don't + * set the slot->hub, ->mtt, ->ttt, ->etc, items. + * + * @param id 控制器id + * @param slot_id enable_slot命令分配的插槽id + * @param port 端口号 + * @param speed 端口速度 + * @param max_packet 最大数据包大小 + * @return uint64_t 初始化好的设备上下文空间的虚拟地址 + */ +static uint64_t xhci_initialize_slot(const int id, const int slot_id, const int port, const int speed, const int max_packet) +{ + // 暂时只初始化slot和control EP0 + + // 申请上下文数据结构所占用的内存空间 + + uint64_t device_context_vaddr = (uint64_t)kzalloc(xhci_hc[id].context_size * 2, 0); + // kdebug("slot id=%d, device_context_vaddr=%#018lx, port=%d", slot_id, device_context_vaddr, port); + // 写到数组中 + xhci_write_mem64(xhci_hc[id].dcbaap_vaddr + (slot_id * sizeof(uint64_t)), virt_2_phys(device_context_vaddr)); + + slot_ctx.entries = 1; + slot_ctx.speed = speed; + slot_ctx.route_string = 0; + slot_ctx.rh_port_num = port + 1; // 由于xhci控制器是1-base的,因此把驱动程序中存储的端口号加1,才是真实的端口号 + slot_ctx.max_exit_latency = 0; // 稍后会计算这个值 + slot_ctx.int_target = 0; // 当前全部使用第0个interrupter + slot_ctx.slot_state = XHCI_SLOT_STATE_DISABLED_OR_ENABLED; + slot_ctx.device_address = 0; + + // 将slot信息写入上下文空间 + __write_slot(device_context_vaddr, &slot_ctx); + + xhci_initialize_ep(id, device_context_vaddr, slot_id, XHCI_EP_CONTROL, max_packet, USB_EP_CONTROL, 0, speed, 0); + + return device_context_vaddr; +} + +/** + * @brief 初始化endpoint + * + * @param id 控制器id + * @param slot_vaddr slot上下文的虚拟地址 + * @param slot_id 插槽id + * @param ep_num 端点上下文在slot上下文区域内的编号 + * @param max_packet 最大数据包大小 + * @param type 端点类型 + * @param direction 传输方向 + * @param speed 传输速度 + * @param ep_interval 端点的连续请求间隔 + */ +static void xhci_initialize_ep(const int id, const uint64_t slot_vaddr, const int slot_id, const int ep_num, const int max_packet, const int type, const int direction, const int speed, const int ep_interval) +{ + // 由于目前只实现获取设备的描述符,因此暂时只支持control ep + if (type != USB_EP_CONTROL) + return; + memset(&ep_ctx, 0, sizeof(struct xhci_ep_context_t)); + + xhci_hc[id].control_ep_info.ep_ring_vbase = xhci_create_ring(XHCI_TRBS_PER_RING); + // 申请ep的 transfer ring + ep_ctx.tr_dequeue_ptr = virt_2_phys(xhci_hc[id].control_ep_info.ep_ring_vbase); + xhci_ep_set_dequeue_cycle_state(&ep_ctx, XHCI_TRB_CYCLE_ON); + + xhci_hc[id].control_ep_info.current_ep_ring_vaddr = xhci_hc[id].control_ep_info.ep_ring_vbase; + xhci_hc[id].control_ep_info.current_ep_ring_cycle = xhci_ep_get_dequeue_cycle_state(&ep_ctx); + // kdebug("ep_ctx.tr_dequeue_ptr = %#018lx", ep_ctx.tr_dequeue_ptr); + // kdebug("xhci_hc[id].control_ep_info.current_ep_ring_cycle = %d", xhci_hc[id].control_ep_info.current_ep_ring_cycle); + + // 设置初始值 + ep_ctx.max_packet_size = max_packet; + ep_ctx.linear_stream_array = 0; + ep_ctx.max_primary_streams = 0; + ep_ctx.mult = 0; + ep_ctx.ep_state = XHCI_EP_STATE_DISABLED; + ep_ctx.hid = 0; + ep_ctx.ep_type = 4; + ep_ctx.average_trb_len = 8; // 所有的control ep的该值均为8 + ep_ctx.err_cnt = 3; + ep_ctx.max_burst_size = 0; + ep_ctx.interval = ep_interval; + // 将ep的信息写入到slot上下文中对应的ep的块中 + __write_ep(id, slot_vaddr, ep_num, &ep_ctx); +} + +/** + * @brief 向usb控制器发送 address_device命令 + * + * @param id 主机控制器id + * @param slot_vaddr 插槽上下文的虚拟基地址 + * @param slot_id 插槽id + * @param block 是否阻断 set address 信息向usb设备的传输 + * @return int 错误码 + */ +static int xhci_set_address(const int id, const uint64_t slot_vaddr, const int slot_id, const bool block) +{ + int retval = 0; + // 创建输入上下文缓冲区 + uint64_t input_ctx_buffer = (uint64_t)kzalloc(xhci_hc[id].context_size * 32, 0); + + // 置位input control context和slot context的add bit + xhci_write_mem32(input_ctx_buffer + 4, 0x3); + + // 拷贝slot上下文和control ep上下文到输入上下文中 + __write_slot(input_ctx_buffer + xhci_hc[id].context_size, (struct xhci_slot_context_t *)slot_vaddr); + + __write_ep(id, input_ctx_buffer, 2, (struct xhci_ep_context_t *)(slot_vaddr + XHCI_EP_CONTROL * xhci_hc[id].context_size)); + + struct xhci_TRB_normal_t trb = {0}; + trb.buf_paddr = virt_2_phys(input_ctx_buffer); + trb.bei = (block ? 1 : 0); + trb.TRB_type = TRB_TYPE_ADDRESS_DEVICE; + trb.intr_target = 0; + trb.cycle = xhci_hc[id].cmd_trb_cycle; + trb.Reserved |= ((slot_id << 8) & 0xffff); + + retval = xhci_send_command(id, (struct xhci_TRB_t *)&trb, true); + if (unlikely(retval != 0)) + { + kerror("slotid:%d, address device failed", slot_id); + + goto failed; + } + + struct xhci_TRB_cmd_complete_t *trb_done = (struct xhci_TRB_cmd_complete_t *)&trb; + // kdebug("address slot: comp code=%d", trb_done->code); + if (trb_done->code == TRB_COMP_TRB_SUCCESS) // 成功执行 + { + // 如果要从控制器获取刚刚设置的设备地址的话,可以在这里读取slot context + // ksuccess("slot %d successfully addressed.", slot_id); + struct xhci_slot_context_t slot; + struct xhci_ep_context_t ep; + __read_from_slot(&slot, slot_vaddr); + slot_ctx.slot_state = slot.slot_state; + slot_ctx.device_address = slot.device_address; + __read_from_ep(id, slot_vaddr, 1, &ep); + // kdebug("ep.ep_state=%d, slot_state=%d", ep.ep_state, slot.slot_state); + ep_ctx.ep_state = ep.ep_state; + ep_ctx.max_packet_size = ep.max_packet_size; + retval = 0; + } + else + retval = -EAGAIN; +done:; +failed:; + kfree((void *)input_ctx_buffer); + return retval; +} + +/** + * @brief 在指定的端点的ring中,写入一个setup stage TRB + * + * @param ep 端点信息结构体 + * @param packet usb请求包 + * @param direction 传输的方向 + * @return int 产生的TRB数量 + */ +static int xhci_setup_stage(struct xhci_ep_ring_info_t *ep, const struct usb_request_packet_t *packet, const uint8_t direction) +{ + // kdebug("ep->current_ep_ring_cycle=%d", ep->current_ep_ring_cycle); + struct xhci_TRB_setup_stage_t trb = {0}; + trb.bmRequestType = packet->request_type; + trb.bRequest = packet->request; + trb.wValue = packet->value; + trb.wIndex = packet->index; + trb.wLength = packet->length; + trb.transfer_legth = 8; + trb.intr_target = 0; // 使用第0个interrupter + trb.cycle = ep->current_ep_ring_cycle; + trb.ioc = 0; + trb.idt = 1; + trb.TRB_type = TRB_TYPE_SETUP_STAGE; + trb.trt = direction; + + // 将setup stage trb拷贝到ep的transfer ring中 + __xhci_write_trb(ep, (struct xhci_TRB_t *)&trb); + return 1; +} + +/** + * @brief 向指定的端点中写入data stage trb + * + * @param ep 端点信息结构体 + * @param buf_vaddr 数据缓冲区虚拟地址 + * @param trb_type trb类型 + * @param size 要传输的数据大小 + * @param direction 传输方向 + * @param max_packet 最大请求包大小 + * @param status_vaddr event data TRB的缓冲区(4字节,且地址按照16字节对齐) + * @return int 产生的TRB数量 + */ +static int xhci_data_stage(struct xhci_ep_ring_info_t *ep, uint64_t buf_vaddr, uint8_t trb_type, const uint32_t size, uint8_t direction, const int max_packet, const uint64_t status_vaddr) +{ + if (size == 0) + return 0; + int64_t remain_bytes = size; + uint32_t remain_packets = (size + max_packet - 1) / max_packet; + struct xhci_TRB_data_stage_t trb = {0}; + int count_packets = 0; + // 分多个trb来执行 + while (remain_bytes > 0) + { + --remain_packets; + + trb.buf_paddr = virt_2_phys(buf_vaddr); + trb.intr_target = 0; + trb.TD_size = remain_packets; + trb.transfer_length = (remain_bytes < max_packet ? size : max_packet); + trb.dir = direction; + trb.TRB_type = trb_type; + trb.chain = 1; + trb.ent = (remain_packets == 0); + trb.cycle = ep->current_ep_ring_cycle; + trb.ioc = 0; + + // 将data stage trb拷贝到ep的transfer ring中 + __xhci_write_trb(ep, (struct xhci_TRB_t *)&trb); + + buf_vaddr += max_packet; + remain_bytes -= max_packet; + ++count_packets; + + // 对于data stage trb而言,除了第一个trb以外,剩下的trb都是NORMAL的,并且dir是无用的 + trb_type = TRB_TYPE_NORMAL; + direction = 0; + } + + // 写入data event trb, 待完成后,完成信息将会存到status_vaddr指向的地址中 + memset(&trb, 0, sizeof(struct xhci_TRB_data_stage_t *)); + trb.buf_paddr = virt_2_phys(status_vaddr); + trb.intr_target = 0; + trb.cycle = ep->current_ep_ring_cycle; + trb.ioc = 1; + trb.TRB_type = TRB_TYPE_EVENT_DATA; + __xhci_write_trb(ep, (struct xhci_TRB_t *)&trb); + + return count_packets + 1; +} + +/** + * @brief 填写xhci status stage TRB到control ep的transfer ring + * + * @param id 主机控制器id + * @param direction 方向:(h2d:0, d2h:1) + * @param status_buf_vaddr + * @return int 创建的TRB数量 + */ +static int xhci_status_stage(const int id, uint8_t direction, uint64_t status_buf_vaddr) +{ + // kdebug("write status stage trb"); + { + struct xhci_TRB_status_stage_t trb = {0}; + + // 写入status stage trb + trb.intr_target = 0; + trb.cycle = xhci_hc[id].control_ep_info.current_ep_ring_cycle; + trb.ent = 0; + trb.ioc = 1; + trb.TRB_type = TRB_TYPE_STATUS_STAGE; + trb.dir = direction; + __xhci_write_trb(&xhci_hc[id].control_ep_info, (struct xhci_TRB_t *)&trb); + } + + { + // 写入event data TRB + struct xhci_TRB_data_stage_t trb = {0}; + trb.buf_paddr = virt_2_phys(status_buf_vaddr); + trb.intr_target = 0; + trb.TRB_type = TRB_TYPE_EVENT_DATA; + trb.ioc = 1; + + trb.cycle = xhci_hc[id].control_ep_info.current_ep_ring_cycle; + + __xhci_write_trb(&xhci_hc[id].control_ep_info, (struct xhci_TRB_t *)&trb); + } + return 2; +} + +/** + * @brief 等待状态数据被拷贝到status缓冲区中 + * + * @param id 主机控制器id + * @param status_vaddr status 缓冲区 + * @return int 错误码 + */ +static int xhci_wait_for_interrupt(const int id, uint64_t status_vaddr) +{ + int timer = 500; + while (timer) + { + if (xhci_read_mem32(status_vaddr) & XHCI_IRQ_DONE) + { + uint32_t status = xhci_read_mem32(status_vaddr); + // 判断完成码 + switch (xhci_get_comp_code(status)) + { + case TRB_COMP_TRB_SUCCESS: + case TRB_COMP_SHORT_PACKET: + return 0; + break; + case TRB_COMP_STALL_ERROR: + case TRB_COMP_DATA_BUFFER_ERROR: + case TRB_COMP_BABBLE_DETECTION: + return -EINVAL; + default: + kerror("xhci wait interrupt: status=%#010x, complete_code=%d", status, xhci_get_comp_code(status)); + return -EIO; + } + } + --timer; + usleep(1000); + } + + kerror(" USB xHCI Interrupt wait timed out."); + return -ETIMEDOUT; +} + +/** + * @brief 从指定插槽的control endpoint读取信息 + * + * @param id 主机控制器id + * @param target 读取到的信息存放到的位置 + * @param in_size 要读取的数据的大小 + * @param slot_id 插槽id + * @param max_packet 最大数据包大小 + * @return int 读取到的数据的大小 + */ +static int xhci_control_in(const int id, void *target, const int in_size, const int slot_id, const int max_packet) +{ + + uint64_t status_buf_vaddr = (uint64_t)kzalloc(16, 0); // 本来是要申请4bytes的buffer的,但是因为xhci控制器需要16bytes对齐,因此申请16bytes + uint64_t data_buf_vaddr = (uint64_t)kzalloc(256, 0); + int retval = 0; + struct usb_request_packet_t packet = {0}; + packet.request_type = USB_REQ_TYPE_GET_REQUEST; + packet.request = USB_REQ_GET_DESCRIPTOR; + packet.value = (USB_DT_DEVICE << 8); + packet.length = in_size; + + // 往control ep写入一个setup stage trb + xhci_setup_stage(&xhci_hc[id].control_ep_info, &packet, XHCI_DIR_IN); + xhci_data_stage(&xhci_hc[id].control_ep_info, data_buf_vaddr, TRB_TYPE_DATA_STAGE, in_size, XHCI_DIR_IN_BIT, max_packet, status_buf_vaddr); + +/* + QEMU doesn't quite handle SETUP/DATA/STATUS transactions correctly. + It will wait for the STATUS TRB before it completes the transfer. + Technically, you need to check for a good transfer before you send the + STATUS TRB. However, since QEMU doesn't update the status until after + the STATUS TRB, waiting here will not complete a successful transfer. + Bochs and real hardware handles this correctly, however QEMU does not. + If you are using QEMU, do not ring the doorbell here. Ring the doorbell + *after* you place the STATUS TRB on the ring. + (See bug report: https://bugs.launchpad.net/qemu/+bug/1859378 ) +*/ +#ifndef __QEMU_EMULATION__ + // 如果不是qemu虚拟机,则可以直接发起传输 + // kdebug(" not qemu"); + __xhci_write_doorbell(id, slot_id, XHCI_EP_CONTROL); + retval = xhci_wait_for_interrupt(id, status_buf_vaddr); + if (unlikely(retval != 0)) + goto failed; +#endif + memset((void *)status_buf_vaddr, 0, 16); + xhci_status_stage(id, XHCI_DIR_OUT_BIT, status_buf_vaddr); + + __xhci_write_doorbell(id, slot_id, XHCI_EP_CONTROL); + + retval = xhci_wait_for_interrupt(id, status_buf_vaddr); + + if (unlikely(retval != 0)) + goto failed; + + // 将读取到的数据拷贝到目标区域 + memcpy(target, (void *)data_buf_vaddr, in_size); + retval = in_size; + goto done; + +failed:; + kdebug("wait 4 interrupt failed"); + retval = 0; +done:; + // 释放内存 + kfree((void *)status_buf_vaddr); + kfree((void *)data_buf_vaddr); + return retval; +} + +/** + * @brief 获取端口的描述信息 + * + * @param id 主机控制器id + * @param port_id 端口id + * @return int 错误码 + */ +static int xhci_get_descriptor(const int id, const int port_id) +{ + int retval = 0; + int count = 0; + struct usb_device_desc dev_desc = {0}; + uint32_t dword; + // 计算port register set相对于operational registers基地址的偏移量 + uint32_t port_register_offset = XHCI_OPS_PRS + 16 * port_id; + + // 读取指定端口的port sc寄存器 + dword = xhci_read_op_reg32(id, port_register_offset + XHCI_PORT_PORTSC); + + // 读取端口速度。 full=1, low=2, high=3, super=4 + uint32_t speed = ((dword >> 10) & 0xf); + + /* + * Some devices will only send the first 8 bytes of the device descriptor + * while in the default state. We must request the first 8 bytes, then reset + * the port, set address, then request all 18 bytes. + */ + struct xhci_TRB_normal_t trb = {0}; + trb.TRB_type = TRB_TYPE_ENABLE_SLOT; + if (xhci_send_command(id, (struct xhci_TRB_t *)&trb, true) != 0) + { + kerror("portid:%d: send enable slot failed", port_id); + return -ETIMEDOUT; + } + + uint32_t slot_id = ((struct xhci_TRB_cmd_complete_t *)&trb)->slot_id; + int16_t max_packet; + if (slot_id != 0) // slot id不为0时,是合法的slot id + { + // 为不同速度的设备确定最大的数据包大小 + switch (speed) + { + case XHCI_PORT_SPEED_LOW: + max_packet = 8; + break; + case XHCI_PORT_SPEED_FULL: + case XHCI_PORT_SPEED_HI: + max_packet = 64; + break; + case XHCI_PORT_SPEED_SUPER: + max_packet = 512; + break; + } + } + + // 初始化接口的上下文 + uint64_t slot_vaddr = xhci_initialize_slot(id, slot_id, port_id, speed, max_packet); + + // 发送 address_device命令 + retval = xhci_set_address(id, slot_vaddr, slot_id, true); + if (retval != 0) + return retval; + + // 发送用于 “get_descriptor” 的数据包。 + count = xhci_control_in(id, &dev_desc, 8, slot_id, max_packet); + if (unlikely(count == 0)) + return -EAGAIN; + + /* + TODO: if the dev_desc.max_packet was different than what we have as max_packet, + you would need to change it here and in the slot context by doing a + evaluate_slot_context call. + */ + + // 重置当前端口 + xhci_reset_port(id, port_id); + + // 再次发送 set_address命令 + retval = xhci_set_address(id, slot_vaddr, slot_id, false); + if (retval != 0) + return retval; + + count = xhci_control_in(id, &dev_desc, 18, slot_id, max_packet); + if (unlikely(count == 0)) + return -EAGAIN; + + // print the descriptor + printk(" Found USB Device:\n" + " port: %i\n" + " len: %i\n" + " type: %i\n" + " version: %01X.%02X\n" + " class: %i\n" + " subclass: %i\n" + " protocol: %i\n" + " max packet size: %i\n" + " vendor id: 0x%04X\n" + " product id: 0x%04X\n" + " release ver: %i%i.%i%i\n" + " manufacture index: %i (index to a string)\n" + " product index: %i\n" + " serial index: %i\n" + " number of configs: %i\n", + port_id, dev_desc.len, dev_desc.type, dev_desc.usb_version >> 8, dev_desc.usb_version & 0xFF, dev_desc._class, dev_desc.subclass, + dev_desc.protocol, dev_desc.max_packet_size, dev_desc.vendor_id, dev_desc.product_id, + (dev_desc.device_rel & 0xF000) >> 12, (dev_desc.device_rel & 0x0F00) >> 8, + (dev_desc.device_rel & 0x00F0) >> 4, (dev_desc.device_rel & 0x000F) >> 0, + dev_desc.manufacturer_index, dev_desc.procuct_index, dev_desc.serial_index, dev_desc.config); + + return 0; +} + /** * @brief 启用xhci控制器的端口 * @@ -809,7 +1419,8 @@ static int xhci_hc_start_ports(int id) // 注意,这两个循环应该不能合并到一起,因为可能存在usb2端口offset在前,usb3端口在后的情况,那样的话就会出错 // 循环启动所有的usb3端口 - for (int i = 0; i < xhci_hc[id].port_num; ++i) + // for (int i = 0; i < xhci_hc[id].port_num; ++i) + for (int i = 0; i < 1; ++i) { if (XHCI_PORT_IS_USB3(id, i) && XHCI_PORT_IS_ACTIVE(id, i)) { @@ -818,12 +1429,12 @@ static int xhci_hc_start_ports(int id) if (likely(xhci_reset_port(id, i) == 0)) // 如果端口reset成功,就获取它的描述符 // 否则,reset函数会把它给设置为未激活,并且标志配对的usb2端口是激活的 { - // xhci_hc_get_descriptor(id, i); - ++cnt; + if (xhci_get_descriptor(id, i) == 0) + ++cnt; } } } - kdebug("active usb3 ports:%d", cnt); + kdebug("Active usb3 ports:%d", cnt); // 循环启动所有的usb2端口 for (int i = 0; i < xhci_hc[id].port_num; ++i) @@ -834,8 +1445,10 @@ static int xhci_hc_start_ports(int id) if (likely(xhci_reset_port(id, i) == 0)) // 如果端口reset成功,就获取它的描述符 // 否则,reset函数会把它给设置为未激活,并且标志配对的usb2端口是激活的 { - // xhci_hc_get_descriptor(id, i); - ++cnt; + if (xhci_get_descriptor(id, i) == 0) + ++cnt; + else + break; } } } @@ -883,7 +1496,7 @@ static int xhci_hc_init_intr(int id) io_mfence(); xhci_write_intr_reg32(id, 0, XHCI_IR_TABLE_SIZE, 1); // 当前只有1个segment io_mfence(); - xhci_write_intr_reg64(id, 0, XHCI_IR_DEQUEUE, virt_2_phys(xhci_hc[id].event_ring_vaddr) | (1 << 3)); // 写入dequeue寄存器,并清除busy位(写1就会清除) + xhci_write_intr_reg64(id, 0, XHCI_IR_DEQUEUE, virt_2_phys(xhci_hc[id].current_event_ring_vaddr) | (1 << 3)); // 写入dequeue寄存器,并清除busy位(写1就会清除) io_mfence(); xhci_write_intr_reg64(id, 0, XHCI_IR_TABLE_ADDR, virt_2_phys(xhci_hc[id].event_ring_table_vaddr)); // 写入table地址 io_mfence(); @@ -912,22 +1525,7 @@ static int xhci_hc_init_intr(int id) } /** - * @brief 写入doorbell寄存器 - * - * @param id 主机控制器id - * @param slot_id usb控制器插槽id(0用作命令门铃,其他的用于具体的设备的门铃) - * @param value 要写入的值 - */ -static __always_inline void __xhci_write_doorbell(const int id, const uint16_t slot_id, const uint32_t value) -{ - // 确保写入门铃寄存器之前,所有的写操作均已完成 - io_sfence(); - xhci_write_cap_reg32(id, xhci_hc[id].db_offset + slot_id * sizeof(uint32_t), value); - io_sfence(); -} - -/** - * @brief 往xhci控制器发送命令 + * @brief 往xhci控制器发送trb, 并将返回的数据存入原始的trb中 * * @param id xhci控制器号 * @param trb 传输请求块 @@ -939,9 +1537,9 @@ static int xhci_send_command(int id, struct xhci_TRB_t *trb, const bool do_ring) uint64_t origin_trb_vaddr = xhci_hc[id].cmd_trb_vaddr; // 必须先写入参数和状态数据,最后写入command - xhci_write_mem64(xhci_hc[id].cmd_trb_vaddr, trb->param); // 参数 - xhci_write_mem32(xhci_hc[id].cmd_trb_vaddr + 8, trb->status); // 状态 - xhci_write_mem32(xhci_hc[id].cmd_trb_vaddr + 12, trb->command); // 命令 + xhci_write_mem64(xhci_hc[id].cmd_trb_vaddr, trb->param); // 参数 + xhci_write_mem32(xhci_hc[id].cmd_trb_vaddr + 8, trb->status); // 状态 + xhci_write_mem32(xhci_hc[id].cmd_trb_vaddr + 12, trb->command | xhci_hc[id].cmd_trb_cycle); // 命令 xhci_hc[id].cmd_trb_vaddr += sizeof(struct xhci_TRB_t); // 跳转到下一个trb @@ -958,27 +1556,26 @@ static int xhci_send_command(int id, struct xhci_TRB_t *trb, const bool do_ring) if (do_ring) // 按响命令门铃 { - kdebug("to ring.."); __xhci_write_doorbell(id, 0, 0); - kdebug("ring.."); + // 等待中断产生 - int timer = 20; + int timer = 400; + const uint32_t iman0 = xhci_read_intr_reg32(id, 0, XHCI_IR_MAN); // Now wait for the interrupt to happen // We use bit 31 of the command dword since it is reserved - - while (timer && ((xhci_read_mem32(origin_trb_vaddr + 12) & (1 << 31)) == 0)) + while (timer && ((xhci_read_mem32(origin_trb_vaddr + 8) & XHCI_IRQ_DONE) == 0)) { usleep(1000); --timer; } uint32_t x = xhci_read_cap_reg32(id, xhci_hc[id].rts_offset + 0x20); - kdebug("ip=%#010lx", x); if (timer == 0) - kwarn("USB xHCI Command Interrupt wait timed out."); + return -ETIMEDOUT; else { - kdebug("interrupt done"); + xhci_get_trb(trb, origin_trb_vaddr); + trb->status &= (~XHCI_IRQ_DONE); } } return 0; @@ -1024,6 +1621,14 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) // kdebug("dev_hdr->BAR0 & (~0xf)=%#018lx", dev_hdr->BAR0 & (~0xf)); mm_map_phys_addr(xhci_hc[cid].vbase, dev_hdr->BAR0 & (~0xf), 65536, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, true); io_mfence(); + + // 计算operational registers的地址 + xhci_hc[cid].vbase_op = xhci_hc[cid].vbase + (xhci_read_cap_reg32(cid, XHCI_CAPS_CAPLENGTH) & 0xff); + io_mfence(); + // 重置xhci控制器 + FAIL_ON_TO(xhci_hc_reset(cid), failed); + io_mfence(); + // 读取xhci控制寄存器 uint16_t iversion = *(uint16_t *)(xhci_hc[cid].vbase + XHCI_CAPS_HCIVERSION); @@ -1037,10 +1642,6 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) memcpy(&hcs1, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCSPARAMS1), sizeof(struct xhci_caps_HCSPARAMS1_reg_t)); memcpy(&hcs2, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCSPARAMS2), sizeof(struct xhci_caps_HCSPARAMS2_reg_t)); - // kdebug("hcc1.xECP=%#010lx", hcc1.xECP); - // 计算operational registers的地址 - xhci_hc[cid].vbase_op = xhci_hc[cid].vbase + (xhci_read_cap_reg32(cid, XHCI_CAPS_CAPLENGTH) & 0xff); - io_mfence(); xhci_hc[cid].db_offset = xhci_read_cap_reg32(cid, XHCI_CAPS_DBOFF) & (~0x3); // bits [1:0] reserved io_mfence(); xhci_hc[cid].rts_offset = xhci_read_cap_reg32(cid, XHCI_CAPS_RTSOFF) & (~0x1f); // bits [4:0] reserved. @@ -1072,9 +1673,7 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) // 关闭legacy支持 FAIL_ON_TO(xhci_hc_stop_legacy(cid), failed); io_mfence(); - // 重置xhci控制器 - FAIL_ON_TO(xhci_hc_reset(cid), failed); - io_mfence(); + // 端口配对 FAIL_ON_TO(xhci_hc_pair_ports(cid), failed); io_mfence(); @@ -1084,10 +1683,10 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) xhci_hc[cid].page_size = (xhci_read_op_reg32(cid, XHCI_OPS_PAGESIZE) & 0xffff) << 12; io_mfence(); // 获取设备上下文空间 - xhci_hc[cid].dcbaap_vaddr = (uint64_t)kmalloc(2048, 0); // 分配2KB的设备上下文地址数组空间 - memset((void *)xhci_hc[cid].dcbaap_vaddr, 0, 2048); + xhci_hc[cid].dcbaap_vaddr = (uint64_t)kzalloc(2048, 0); // 分配2KB的设备上下文地址数组空间 + io_mfence(); - kdebug("dcbaap_vaddr=%#018lx", xhci_hc[cid].dcbaap_vaddr); + // kdebug("dcbaap_vaddr=%#018lx", xhci_hc[cid].dcbaap_vaddr); if (unlikely(!xhci_is_aligned64(xhci_hc[cid].dcbaap_vaddr))) // 地址不是按照64byte对齐 { kerror("dcbaap isn't 64 byte aligned."); @@ -1113,7 +1712,7 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) xhci_write_op_reg64(cid, XHCI_OPS_CRCR, virt_2_phys(xhci_hc[cid].cmd_ring_vaddr) | xhci_hc[cid].cmd_trb_cycle); // 写入配置寄存器 uint32_t max_slots = hcs1.max_slots; - kdebug("max slots = %d", max_slots); + // kdebug("max slots = %d", max_slots); io_mfence(); xhci_write_op_reg32(cid, XHCI_OPS_CONFIG, max_slots); io_mfence(); @@ -1129,16 +1728,6 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) spin_unlock(&xhci_controller_init_lock); io_mfence(); - // 发送nop - struct xhci_TRB_normal_t nop_trb = {0}; - nop_trb.cycle = xhci_hc[cid].cmd_trb_cycle; - nop_trb.TRB_type = TRB_TYPE_ENABLE_SLOT; - nop_trb.ioc = 1; - kdebug("to send nop TRB"); - xhci_send_command(cid, &nop_trb, true); - xhci_send_command(cid, &nop_trb, true); - kdebug("nop TRB send OK"); - return; failed_free_dyn:; // 释放动态申请的内存 diff --git a/kernel/driver/usb/xhci/xhci.h b/kernel/driver/usb/xhci/xhci.h index deca79de..46d1102a 100644 --- a/kernel/driver/usb/xhci/xhci.h +++ b/kernel/driver/usb/xhci/xhci.h @@ -8,7 +8,7 @@ // ========== irq BEGIN =========== -#define XHCI_IRQ_DONE (1<<31) // 当command trb 的status的第31位被驱动程序置位时,表明该trb已经执行完成(这是由于xhci规定,第31位可以由驱动程序自行决定用途) +#define XHCI_IRQ_DONE (1 << 31) // 当command trb 的status的第31位被驱动程序置位时,表明该trb已经执行完成(这是由于xhci规定,第31位可以由驱动程序自行决定用途) /** * @brief 每个xhci控制器的中断向量号 * @@ -188,6 +188,10 @@ struct xhci_ops_config_reg_t #define XHCI_TRB_CYCLE_OFF 0 #define XHCI_TRB_CYCLE_ON 1 +// 获取、设置trb中的status部分的complete code +#define xhci_get_comp_code(status) (((status) >> 24) & 0x7f) +#define xhci_set_comp_code(code) ((code & 0x7f) << 24) + /** * @brief xhci通用TRB结构 * @@ -220,7 +224,7 @@ struct xhci_TRB_normal_t uint16_t Reserved; // 保留且置为0 } __attribute__((packed)); -struct xhci_TRB_setup_state_t +struct xhci_TRB_setup_stage_t { uint8_t bmRequestType; uint8_t bRequest; @@ -229,14 +233,14 @@ struct xhci_TRB_setup_state_t uint16_t wIndex; uint16_t wLength; - unsigned transfer_legth : 17; - unsigned resv1 : 5; // Reserved and zero'd + unsigned transfer_legth : 17; // TRB transfer length + unsigned resv1 : 5; // Reserved and zero'd unsigned intr_target : 10; unsigned cycle : 1; unsigned resv2 : 4; // Reserved and zero'd - unsigned ioc : 1; - unsigned idt : 1; + unsigned ioc : 1; // interrupt on complete + unsigned idt : 1; // immediate data (should always set for setup TRB) unsigned resv3 : 3; // Reserved and zero'd unsigned TRB_type : 6; unsigned trt : 2; // Transfer type @@ -354,8 +358,132 @@ struct xhci_intr_moderation_t #define XHCI_PORTUSB_CHANGE_BITS ((1 << 17) | (1 << 18) | (1 << 20) | (1 << 21) | (1 << 22)) +// 存储于portsc中的端口速度的可用值 +#define XHCI_PORT_SPEED_FULL 1 +#define XHCI_PORT_SPEED_LOW 2 +#define XHCI_PORT_SPEED_HI 3 +#define XHCI_PORT_SPEED_SUPER 4 + // ======= Port status and control registers END ==== +// ======= Device Slot Context BEGIN ==== + +/** + * @brief 设备上下文结构体 + * + */ +struct xhci_slot_context_t +{ + unsigned route_string : 20; + unsigned speed : 4; + unsigned Rsvd0 : 1; // Reserved and zero'd + unsigned mtt : 1; // multi-TT + unsigned hub : 1; + unsigned entries : 5; // count of context entries + + uint16_t max_exit_latency; + uint8_t rh_port_num; // root hub port number + uint8_t num_ports; // number of ports + + uint8_t tt_hub_slot_id; + uint8_t tt_port_num; + unsigned ttt : 2; // TT Think Time + unsigned Rsvd2 : 4; + unsigned int_target : 10; // Interrupter target + + uint8_t device_address; + unsigned Rsvd1 : 19; + unsigned slot_state : 5; +} __attribute__((packed)); + +#define XHCI_SLOT_STATE_DISABLED_OR_ENABLED 0 +#define XHCI_SLOT_STATE_DEFAULT 1 +#define XHCI_SLOT_STATE_ADDRESSED 2 +#define XHCI_SLOT_STATE_CONFIGURED 3 + +// ======= Device Slot Context END ==== + +// ======= Device Endpoint Context BEGIN ==== + +#define XHCI_EP_STATE_DISABLED 0 +#define XHCI_EP_STATE_RUNNING 1 +#define XHCI_EP_STATE_HALTED 2 +#define XHCI_EP_STATE_STOPPED 3 +#define XHCI_EP_STATE_ERROR 4 + +// End Point Doorbell numbers +#define XHCI_SLOT_CNTX 0 +#define XHCI_EP_CONTROL 1 +#define XHCI_EP1_OUT 2 +#define XHCI_EP1_IN 3 +#define XHCI_EP2_OUT 4 +#define XHCI_EP2_IN 5 +#define XHCI_EP3_OUT 6 +#define XHCI_EP3_IN 7 +#define XHCI_EP4_OUT 8 +#define XHCI_EP4_IN 9 +#define XHCI_EP5_OUT 10 +#define XHCI_EP5_IN 11 +#define XHCI_EP6_OUT 12 +#define XHCI_EP6_IN 13 +#define XHCI_EP7_OUT 14 +#define XHCI_EP7_IN 15 +#define XHCI_EP8_OUT 16 +#define XHCI_EP8_IN 17 +#define XHCI_EP9_OUT 18 +#define XHCI_EP9_IN 19 +#define XHCI_EP10_OUT 20 +#define XHCI_EP10_IN 21 +#define XHCI_EP11_OUT 22 +#define XHCI_EP11_IN 23 +#define XHCI_EP12_OUT 24 +#define XHCI_EP12_IN 25 +#define XHCI_EP13_OUT 26 +#define XHCI_EP13_IN 27 +#define XHCI_EP14_OUT 28 +#define XHCI_EP14_IN 29 +#define XHCI_EP15_OUT 30 +#define XHCI_EP15_IN 31 + +// xhci 传输方向(用于setup stage TRB) +#define XHCI_DIR_NO_DATA 0 +#define XHCI_DIR_OUT 2 +#define XHCI_DIR_IN 3 + +// xhci传输方向(单个bit的表示) +#define XHCI_DIR_OUT_BIT 0 +#define XHCI_DIR_IN_BIT 1 + +/** + * @brief xhci 端点上下文结构体 + * + */ +struct xhci_ep_context_t +{ + unsigned ep_state : 3; + unsigned Rsvd0 : 5; // Reserved and zero'd + unsigned mult : 2; // the maximum supported number of bursts within an interval + unsigned max_primary_streams : 5; + unsigned linear_stream_array : 1; + uint8_t interval; + uint8_t max_esti_payload_hi; // Max Endpoint Service Time Interval Payload (High 8bit) + + unsigned Rsvd1 : 1; + unsigned err_cnt : 2; // error count. 当错误发生时,该位会自减。当减为0时,控制器会把这个端点挂起 + unsigned ep_type : 3; // endpoint type + unsigned Rsvd2 : 1; + unsigned hid : 1; // Host Initiate Disable + uint8_t max_burst_size; + uint16_t max_packet_size; + + uint64_t tr_dequeue_ptr; // 第0bit为dequeue cycle state, 第1~3bit应保留。 + + uint16_t average_trb_len; // 平均TRB长度。该部分不应为0 + uint16_t max_esti_payload_lo; // Max Endpoint Service Time Interval Payload (Low 16bit) +} __attribute__((packed)); + +// ======= Device Endpoint Context END ==== + // 端口信息标志位 #define XHCI_PROTOCOL_USB2 0 #define XHCI_PROTOCOL_USB3 1 @@ -376,6 +504,12 @@ struct xhci_port_info_t uint8_t reserved; } __attribute__((packed)); +struct xhci_ep_ring_info_t +{ + uint64_t ep_ring_vbase; // transfer ring的基地址 + uint64_t current_ep_ring_vaddr; // transfer ring下一个要写入的地址 + uint8_t current_ep_ring_cycle; // 当前ep的cycle bit +}; struct xhci_host_controller_t { struct pci_device_structure_general_device_t *pci_dev_hdr; // 指向pci header结构体的指针 @@ -385,7 +519,7 @@ struct xhci_host_controller_t uint32_t rts_offset; // Runtime Register Space offset uint32_t db_offset; // Doorbell offset uint32_t ext_caps_off; // 扩展能力寄存器偏移量 - uint8_t context_size; // 上下文大小 + uint8_t context_size; // 设备上下文大小 uint16_t port_num; // 总的端口数量 uint8_t port_num_u2; // usb 2.0端口数量 uint8_t port_num_u3; // usb 3端口数量 @@ -399,6 +533,7 @@ struct xhci_host_controller_t uint8_t cmd_trb_cycle; // 当前command ring cycle uint8_t current_event_ring_cycle; // 当前event ring cycle struct xhci_port_info_t ports[XHCI_MAX_ROOT_HUB_PORTS]; // 指向端口信息数组的指针(由于端口offset是从1开始的,因此该数组第0项为空) + struct xhci_ep_ring_info_t control_ep_info; // 控制端点的信息 }; // Common TRB types diff --git a/kernel/main.c b/kernel/main.c index a28e98b3..deed7d36 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -88,22 +88,21 @@ void system_initialize() cpu_core_info[0].stack_start = _stack_start; cpu_core_info[0].tss_vaddr = (uint64_t)&initial_tss[0]; - kdebug("cpu_core_info[0].tss_vaddr=%#018lx", cpu_core_info[0].tss_vaddr); - kdebug("cpu_core_info[0].stack_start%#018lx", cpu_core_info[0].stack_start); + // kdebug("cpu_core_info[0].tss_vaddr=%#018lx", cpu_core_info[0].tss_vaddr); + // kdebug("cpu_core_info[0].stack_start%#018lx", cpu_core_info[0].stack_start); // 初始化中断描述符表 sys_vector_init(); // 初始化内存管理单元 mm_init(); - + // 内存管理单元初始化完毕后,需要立即重新初始化显示驱动。 // 原因是,系统启动初期,framebuffer被映射到48M地址处, // mm初始化完毕后,若不重新初始化显示驱动,将会导致错误的数据写入内存,从而造成其他模块崩溃 // 对显示模块进行低级初始化,不启用double buffer scm_reinit(); - // =========== 重新设置initial_tss[0]的ist uchar *ptr = (uchar *)kzalloc(STACK_SIZE, 0) + STACK_SIZE; ((struct process_control_block *)(ptr - STACK_SIZE))->cpu_id = 0; @@ -158,7 +157,7 @@ void system_initialize() io_mfence(); // current_pcb->preempt_count = 0; // kdebug("cpu_get_core_crysral_freq()=%ld", cpu_get_core_crysral_freq()); - + process_init(); // 启用double buffer scm_enable_double_buffer(); diff --git a/run.sh b/run.sh index 30574d40..c3e73972 100755 --- a/run.sh +++ b/run.sh @@ -7,6 +7,16 @@ fi GENERATE_ISO=0 IN_DOCKER=0 +IA32_USE_QEMU=1 +bochsrc="./bochsrc" +ARCH="x86_64" + +if [ ${IA32_USE_QEMU} == "1" ];then + export EMULATOR=__QEMU_EMULATION__ +else + export EMULATOR=__NO_EMULATION__ +fi + # 第一个参数如果是--notbuild 那就不构建,直接运行 if [ ! "$1" == "--nobuild" ]; then echo "开始构建..." @@ -28,9 +38,6 @@ if [ ! "$1" == "--nobuild" ]; then fi fi -IA32_USE_QEMU=1 -bochsrc="./bochsrc" -ARCH="x86_64" # 内核映像 root_folder="$(pwd)" @@ -128,8 +135,13 @@ flag_can_run=1 allflags=$(qemu-system-x86_64 -cpu help | awk '/flags/ {y=1; getline}; y {print}' | tr ' ' '\n' | grep -Ev "^$" | sed -r 's|^|+|' | tr '\n' ',' | sed -r "s|,$||") +# 请根据自己的需要,在-d 后方加入所需的trace事件 + +# 标准的trace events +qemu_trace_std=cpu_reset,guest_errors,trace:check_exception,exec,cpu # 调试usb的trace -qemu_trace_usb=trace:usb_xhci_reset,trace:usb_xhci_run,trace:usb_xhci_stop,trace:usb_xhci_irq_msi,trace:usb_xhci_irq_msix,trace:usb_xhci_port_reset +qemu_trace_usb=trace:usb_xhci_reset,trace:usb_xhci_run,trace:usb_xhci_stop,trace:usb_xhci_irq_msi,trace:usb_xhci_irq_msix,trace:usb_xhci_port_reset,trace:msix_write_config,trace:usb_xhci_irq_msix,trace:usb_xhci_irq_msix_use,trace:usb_xhci_irq_msix_unuse,trace:usb_xhci_irq_msi,trace:usb_xhci_* + qemu_accel=kvm if [ "${OS}" == "Darwin" ]; then @@ -142,7 +154,7 @@ if [ $flag_can_run -eq 1 ]; then else qemu-system-x86_64 -d bin/disk.img -m 512M -smp 2,cores=2,threads=1,sockets=1 \ -boot order=d \ - -monitor stdio -d cpu_reset,guest_errors,trace:check_exception,exec,cpu,out_asm,in_asm,${qemu_trace_usb} \ + -monitor stdio -d ${qemu_trace_std} \ -s -S -cpu IvyBridge,apic,x2apic,+fpu,check,${allflags} -rtc clock=host,base=localtime -serial file:serial_opt.txt \ -drive id=disk,file=bin/disk.img,if=none \ -device ahci,id=ahci \