OSDev.org

The Place to Start for Operating System Developers
It is currently Tue Mar 19, 2024 1:26 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 4 posts ] 
Author Message
 Post subject: QEMU resetting EHCI just after it's initialization
PostPosted: Sun Dec 11, 2022 11:03 pm 
Offline

Joined: Sun Dec 11, 2022 10:57 pm
Posts: 1
Hi, I wrote a code to initialize EHCI, but after some little time (about 1 second) after I switched on EHCI, qemu writes message in console:
Quote:
processing error - resetting ehci HC
. My processor is at long mode, but ehci x64 bit flag isn't set. Maybe I need somehow to connect x64 EHCI to qemu? But I didn't find any flags to do it. Is QEMU supports x64 EHCI?
Code:
ehci_controller.caps = (struct EhciCaps*)((uintptr_t)bar0);
    ehci_controller.regs = (struct EhciRegs*)((uintptr_t)bar0 + ehci_controller.caps->cap_length);
    ehci_controller.ehci_base2 = (uint32_t)(bar0);
    ehci_controller.ehci_base = (uint32_t)(uintptr_t)&ehci_controller.regs->usb_cmd;

    ehci_controller.frame_list = (uint32_t *)((uintptr_t)frame_list - KERN_BASE_ADDR);
#ifdef EHCI_DEBUG
    cprintf("frame_list: %p\n", ehci_controller.frame_list);
#endif // EHCI_DEBUG

    /* Init queue and td pools */
    ehci_controller.qh_pool = (struct EhciQueueHeader *)((uintptr_t)queues_pool - KERN_BASE_ADDR);
    ehci_controller.td_pool = (struct EhciTransferDescriptor *)((uintptr_t)transfer_descriptors_pool - KERN_BASE_ADDR);

    memset(ehci_controller.qh_pool, 0, sizeof (struct EhciQueueHeader) * EHCI_QH_MAX);
    memset(ehci_controller.td_pool, 0, sizeof (struct EhciTransferDescriptor) * EHCI_TD_MAX);
#ifdef EHCI_DEBUG
    cprintf("EHCI pools allocated\n");
#endif // EHCI_DEBUG

    /* Make sure we reset the controller */
    ehci_reset_controller();

    /* Async queue setup */
    struct EhciQueueHeader *async_qh = ehci_alloc_queue_header();

    async_qh->qh_link_pointer = ((uint32_t)((uintptr_t)async_qh)) | PTR_QH;
    async_qh->chars = QH_CHARS_HEAD;
    async_qh->caps = 0;
    async_qh->cur_link = 0;
    async_qh->next_link = PTR_TERMINATE;
    async_qh->alt_link = 0;
    async_qh->token = 0;

    for (uint32_t i = 0; i < QUEUE_BUFFERS_AMOUNT; ++i) {
        async_qh->buffer[i] = 0;
    }

    async_qh->transfer = 0;                       
    async_qh->queue_list.prev = &async_qh->queue_list;
    async_qh->queue_list.next = &async_qh->queue_list;
    ehci_controller.async_qh = async_qh;

    /* Periodic table setup */
    struct EhciQueueHeader *periodic_qh = ehci_alloc_queue_header();

    periodic_qh->qh_link_pointer = PTR_TERMINATE;
    periodic_qh->chars = 0;
    periodic_qh->caps = 0;
    periodic_qh->cur_link = 0;
    periodic_qh->next_link = PTR_TERMINATE;
    periodic_qh->alt_link = 0;
    periodic_qh->token = 0;

    for (uint32_t i = 0; i < QUEUE_BUFFERS_AMOUNT; ++i) {
        periodic_qh->buffer[i] = 0;
    }

    periodic_qh->transfer = 0;                         
    periodic_qh->queue_list.prev = &periodic_qh->queue_list;
    periodic_qh->queue_list.next = &periodic_qh->queue_list;

    ehci_controller.periodic_qh = periodic_qh;
    for (uint32_t i = 0; i < FRAME_LIST_SIZE; i++) {
        ehci_controller.frame_list[i] = PTR_QH | ((uint32_t)(uintptr_t)periodic_qh);
    }

    /* Check extended capabilities */
    uint32_t eecp = (RCR(HCC_PARAMS) & HCCPARAMS_EECP_MASK) >> HCCPARAMS_EECP_SHIFT;
    if (eecp >= 0x40) {
        uint32_t legacy_support = pci_config_read_dword(info->bus, info->device, info->function, eecp + USBLEGSUP);
        if (legacy_support & USBLEGSUP_HC_BIOS) {
        #ifdef EHCI_DEBUG
            cprintf("Disabling BIOS legacy support\n");
        #endif

            pci_config_write_dword(info->bus, info->device, info->function, eecp + USBLEGSUP, legacy_support | USBLEGSUP_HC_OS);
            for (;;) {
                legacy_support = pci_config_read_dword(info->bus, info->device, info->function, eecp + USBLEGSUP);
                if (((legacy_support & USBLEGSUP_HC_BIOS) == 0) && (legacy_support & USBLEGSUP_HC_OS)) {
                    break;
                }
            }
        }
    }

    /* Disable interrupts */
    WOR(USB_INTR, 0);

    /* Setup frame list */
    WOR(FRAME_INDEX, 0);
    WOR(PERIODIC_LIST_BASE, (uint32_t)(uintptr_t)ehci_controller.frame_list);
    WOR(ASYNC_LIST_ADDR, (uint32_t)(uintptr_t)ehci_controller.async_qh);
    WOR(CTRL_D_SEGMENT, 0);

    /* Clear USB status, just set first bits to 1's to discard last changes */
    WOR(USB_STS, ~0);

    /* Enable controller */
    /* (8 << CMD_ITC_SHIFT) - interrupt threshold control - 8 micro-frames */
    WOR(USB_CMD, (8 << CMD_ITC_SHIFT) | CMD_ASE | CMD_PSE | CMD_RS);

    /* Wait for halt */
    while (ROR(USB_STS) & STS_HCHALTED);

#ifdef EHCI_DEBUG
    cprintf("Ctrl d segment reg is 0x%x\n", ROR(CTRL_D_SEGMENT));
    cprintf("Async list address is 0x%x\n", ROR(ASYNC_LIST_ADDR));
    cprintf("Periodic list base if 0x%x\n", ROR(PERIODIC_LIST_BASE));
#endif

    /* Sets that all devices should be managed by the EHCI */
    WOR(CONFIG_FLAG, 1);
#ifdef EHCI_DEBUG
    cprintf("EHCI setup done. Probing ports.\n");
#endif


Top
 Profile  
 
 Post subject: Re: QEMU resetting EHCI just after it's initialization
PostPosted: Tue Jan 03, 2023 8:43 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5069
dainbow wrote:
Hi, I wrote a code to initialize EHCI, but after some little time (about 1 second) after I switched on EHCI, qemu writes message in console:

That error message comes from this line in the QEMU source code, but I'm not familiar enough with EHCI to figure out what situations cause that message to appear.

dainbow wrote:
My processor is at long mode, but ehci x64 bit flag isn't set.

That's normal. Many PC devices only support 32-bit addressing, even with a 64-bit CPU.


Top
 Profile  
 
 Post subject: Re: QEMU resetting EHCI just after it's initialization
PostPosted: Wed Jan 04, 2023 4:59 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
Hi,

First off, I don't like the EHCI for various reasons, and my suggestion to you is to skip it and move on to one of the other controllers, but this is just my humble opinion.

Second, I have a few questions/comments:
1) You don't have a URL to any other code, so I am assuming the 'ehci_controller' structure is byte packed. yes?
2) While you initialize the 'next_link', to be safe, you should initialize the 'alt_link' as well:
Code:
   async_qh->next_link = PTR_TERMINATE;
   async_qh->alt_link = 0;   //<------- should be PTR_TERMINATE
...and later...
Code:
periodic_qh->alt_link = 0;
...should be set the same. There were faulty EHCI controllers out there that wouldn't handle the NULL pointer well.
3) There should be more than one queue in your Async list.
Code:
async_qh->qh_link_pointer = ((uint32_t)((uintptr_t)async_qh)) | PTR_QH;
Points back to itself. This is valid, but usually not normal. It is normal to have multiple (at least 2) queues in your Async list. A Queue is 48 bytes and must be 32-byte aligned. Does 'ehci_alloc_queue_header()' return a 32-byte aligned memory location?
4) Does 'ehci_alloc_queue_header()' return a 4k aligned address? The Periodical List must be 4k aligned.
5) With...
Code:
/* Wait for halt */
    while (ROR(USB_STS) & STS_HCHALTED);
...Maybe change to
Code:
/* After setting the Run but, wait for halt bit to clear, indicating we actually started */
    while (ROR(USB_STS) & STS_HCHALTED);
...just so your comment doesn't throw off your thinking. Also, have you taken steps to make sure the while() loop is not optimized out?
6) Do you have a bootable image file you can share?

Ben
- https://www.fysnet.net/the_universal_serial_bus.htm


Top
 Profile  
 
 Post subject: Re: QEMU resetting EHCI just after it's initialization
PostPosted: Tue Jan 10, 2023 7:15 am 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
Just wondering if you made any progress.

Ben


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], SemrushBot [Bot] and 12 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group