USB on real hw

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: USB on real hw

Post by BenLunt »

I don't know what you mean by changing Bochs settings.
The USB specification states that, for the Control Pipe, a low-speed device must have a MPS of 8, a full-speed device can have a MPS of 8, 16, 32, or 64, while a high-speed device must have a MPS of 64.
There is no settings to change that, and there shouldn't be.

If you declare the MSD as full speed, Bochs currently sets the Control Pipe MPS to 64. You can change this in the source code to either 8, 16, 32, or 64. If you do, remember to change the Device Descriptor and the d.endpoint_info[0] information as well.

Code: Select all

  0x40,       /*  u8  bMaxPacketSize; 64 Bytes */
  ...
d.endpoint_info[USB_CONTROL_EP].max_packet_size = 64; // Control ep0
Depending on the speed you choose, there are a few places in the code that you have to do this. Hence, it shouldn't really be changed.

Also, Bochs absolutely does allow you to change the speed of the device.

Code: Select all

usb_uhci: port2=disk, options2="speed:full, path:../common/hdd.img"
In your bochsrc.txt file, you can set the speed to full, high, or super. However, since you are currently using the uhci, full is the only option. An MSD device must not be low-speed.

Here is the bochsrc.txt file I use to run your latest image:

Code: Select all

config_interface: win32config

romimage: file=C:/bochs/bochs/bios/BIOS-bochs-latest

cpu: model=broadwell_ult
cpu: count=1, ips=50000000, reset_on_triple_fault=1, ignore_bad_msrs=1
cpu: cpuid_limit_winnt=0

clock: sync=none, time0=local

memory: guest=512, host=512

vgaromimage: file=C:/bochs/bochs/bios/VGABIOS-lgpl-latest
vga: extension=vbe, update_freq=5, realtime=1, ddc=builtin

ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9

ata0-master: type=disk, path="BonsOS_serial_1.img", model="BonsOS_serial_1.img", sect_size=512

boot: disk

floppy_bootsig_check: disabled=0

log: log.txt

panic: action=ask
error: action=report
info: action=report
debug: action=ignore

mouse: enabled=0, type=imps2
private_colormap: enabled=0

pci: enabled=1, chipset=i440fx
magic_break: enabled=1

usb_uhci: enabled=1
usb_uhci: port2=disk, options2="speed:full, path:../common/hdd.img, debug"
The serial.txt file has:

Code: Select all

src/interrupts/exceptions.c:84 #DE: Divide by zero exception

System halted.
Ben
User avatar
Bonfra
Member
Member
Posts: 270
Joined: Wed Feb 19, 2020 1:08 pm
Libera.chat IRC: Bonfra
Location: Italy

Re: USB on real hw

Post by Bonfra »

BenLunt wrote:I don't know what you mean by changing Bochs settings.
The USB specification states that, for the Control Pipe, a low-speed device must have a MPS of 8, a full-speed device can have a MPS of 8, 16, 32, or 64, while a high-speed device must have a MPS of 64.
There is no settings to change that, and there shouldn't be.
I'm sorry for my poor phrasing, I'm not practical with Bochs I meant to declare the USB device as a specific speed and not leave the default but obviously you already tried that I'm sorry. Since my driver relies on the status of the USB port to choose the packet size and somehow it doesn't recognize the port to be connected to a full speed device before initialization it outputs a zero as a packet size and so divides the size of the data in N packets of size zero.
BenLunt wrote:
The serial.txt file has:

Code: Select all

src/interrupts/exceptions.c:84 #DE: Divide by zero exception

System halted.
This is weird, in the last commit I added some more logging to the image that should at least suggest where the crash happened. Anyway I'm pushing a new image that hardcodes the packet size to 8 if the port is in an unknown state (?). Basically I'm modifying this line.

Here is the image
Regards, Bonfra.
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: USB on real hw

Post by BenLunt »

Bonfra wrote:Anyway I'm pushing a new image...
Got it. Will try it out when I get a chance.
Bonfra wrote:...that hardcodes the packet size to 8 if the port is in an unknown state (?). Basically I'm modifying this line.
There is nothing wrong with using an 8-byte packet size on any device (for the control pipe). It is perfectly legal.
However, usually, and it is stated in the specs, you assume an 8-byte MPS for low-speed, and 64-byte MPS for full- and high-speed. Once you retrieve the first 8 bytes of the Device Descriptor, you then adjust accordingly.

Ben
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: USB on real hw

Post by BenLunt »

It looks like you get everything up to and including the "INQUIRY" CBW out, but your fail on the Data IN.

Code: Select all

00458250000e[USBMSD] DATA IN EP1: Packet Toggle indicator doesn't match Device Toggle indicator. 1 != 0
This is the first time you read from the Bulk IN endpoint, correct? The Toggle should be 0.
Remember, each endpoint (and most of the time, each direction), has its own toggle bit.

Are you using a toggle bit of 0 for the CBW, then "carrying" this over to the Data IN? That would be wrong.

The Toggle will be 0 for the CBW, 0 for the Data IN, and then assuming only one data IN for the INQUIRY, a toggle of 1 for the CSW.
The next out (which should be another CBW) will have a toggle of 1 now, with the first in having a toggle of 0.

Ben
User avatar
Bonfra
Member
Member
Posts: 270
Joined: Wed Feb 19, 2020 1:08 pm
Libera.chat IRC: Bonfra
Location: Italy

Re: USB on real hw

Post by Bonfra »

BenLunt wrote:It looks like you get everything up to and including the "INQUIRY" CBW out, but your fail on the Data IN.

Code: Select all

00458250000e[USBMSD] DATA IN EP1: Packet Toggle indicator doesn't match Device Toggle indicator. 1 != 0
This is the first time you read from the Bulk IN endpoint, correct? The Toggle should be 0.
Remember, each endpoint (and most of the time, each direction), has its own toggle bit.

Are you using a toggle bit of 0 for the CBW, then "carrying" this over to the Data IN? That would be wrong.
Hm no every time i initialize a new transfer operation i hardcode a start value for the toggle and all the packets of the same request follow the sequence.
This means that for example if I start a control in transfer of 6 packets they'll have toggle: [ 1, 0, 1, 0, 1, 0 ]
Same thing for bluks. I'm not sure why my code starts toggle at 0 for out transfers and at 1 for in transfer. Maybe I misunderstood some documents...
Here, here and here. So you are suggesting keeping a flag stored along the infos for the endpoint and using that to have consistencies along transfers?

EDIT:
From the wiki:
https://wiki.osdev.org/Universal_Serial_Bus wrote: Data toggle synchronization works differently depending on the type of transfer used:
- Control transfers initialize the endpoint's data toggle bits to 0 with a SETUP packet.
- Interrupt and Bulk endpoints initialize their data toggle bits to 0 upon any configuration event.
So for control transfers, I got it right by starting every new transfer at zero and going forward flipping for each packet, since the toggle state resets for each new transfer (since it always starts with a setup packet). Instead for bulk I'm a bit confused. "0 upon any configuration event" means every time a control packet with SET_CONFIGURATION in the setup is sent to another endpoint? or something else? Does this mean that even if the bulk transfer ends I should keep track of the current toggle to continue the sequence for the next one?
Regards, Bonfra.
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: USB on real hw

Post by BenLunt »

Bonfra wrote:Does this mean that even if the bulk transfer ends I should keep track of the current toggle to continue the sequence for the next one?
Exactly. Bulk endpoints don't understand when a "new transfer" begins. Every Bulk TD toggles its toggle bit. Only on an EP reset does it "start over" at 0.
An EP reset can be a CONFIG request, CLEAR_FEATURE request, or an actual hard reset.

Ben
User avatar
Bonfra
Member
Member
Posts: 270
Joined: Wed Feb 19, 2020 1:08 pm
Libera.chat IRC: Bonfra
Location: Italy

Re: USB on real hw

Post by Bonfra »

YES! kinda, the device answers to the inquiry and the read capacy commands successfully. I'm correctly printing the product ID, the LBA size and the block size.
Trying to read the first LBA fails tho... I'm not sure how to decide the max packet size so I'm using the read12 command which be supported on any scsi device theoretically. IDK maybe I'm missing some bits somewhere, still working on QEMU but not in real hw... well I pushed the image with the updated code and some other logs. Meanwhile I'm scanning back and forth the SCSI specs looking for some dumb mistake.
Thanks a lot again :)
I really doubt after this there is going to be anything else wrong (i really hope)
Regards, Bonfra.
thewrongchristian
Member
Member
Posts: 426
Joined: Tue Apr 03, 2018 2:44 am

Re: USB on real hw

Post by thewrongchristian »

Bonfra wrote:YES! kinda, the device answers to the inquiry and the read capacy commands successfully. I'm correctly printing the product ID, the LBA size and the block size.
Trying to read the first LBA fails tho... I'm not sure how to decide the max packet size so I'm using the read12 command which be supported on any scsi device theoretically. IDK maybe I'm missing some bits somewhere, still working on QEMU but not in real hw... well I pushed the image with the updated code and some other logs. Meanwhile I'm scanning back and forth the SCSI specs looking for some dumb mistake.
Thanks a lot again :)
I really doubt after this there is going to be anything else wrong (i really hope)
The difference between a read10 and read12 is the transfer length, which is a count of logical blocks to transfer.

Assuming a block size of 512 bytes, that allows for a transfer size of about 32MB (16 bit count, 25 bits total) with read10, and read12 allows for considerably larger transfers, probably bigger than most USB media (32 bit count, 41 bits total.)

Given that read10/write10 is completely practical for use with most USB drives, it wouldn't surprise me if read12 wasn't supported.

Have you tried with read10?
User avatar
Bonfra
Member
Member
Posts: 270
Joined: Wed Feb 19, 2020 1:08 pm
Libera.chat IRC: Bonfra
Location: Italy

Re: USB on real hw

Post by Bonfra »

thewrongchristian wrote: The difference between a read10 and read12 is the transfer length, which is a count of logical blocks to transfer.

Assuming a block size of 512 bytes, that allows for a transfer size of about 32MB (16 bit count, 25 bits total) with read10, and read12 allows for considerably larger transfers, probably bigger than most USB media (32 bit count, 41 bits total.)

Given that read10/write10 is completely practical for use with most USB drives, it wouldn't surprise me if read12 wasn't supported.

Have you tried with read10?
The block size of the device is of 0x20000, so I assumed read12 could be fine, but yea! read10 works great! I'm able to read from the device. This last one was dumb I could've figured that out XD

So... I'm calling this driver a success :) It all works. now I need to make the code actually look pretty and work for some other special cases but yea other than that, thanks a lot for the awesome help! I think this thread has fulfilled it's purpose
Regards, Bonfra.
Alex0vSky
Posts: 2
Joined: Mon Oct 02, 2023 5:43 pm
Contact:

Re: USB on real hw

Post by Alex0vSky »

I noticed such a difference between hardware and QEMU.
When you are waiting to resetting "Status active" in"qTD_Token", in QEMU you need to make something like "sleep". In my "sleep" role I had a call to interrupt the BIOS for display.
It may be useful for you to look at the GitHub repository https://github.com/Alex0vSky/TinyEhci, although it is purely assembler (nasm) and everything is confusing to fit into 512 bytes.
rdos
Member
Member
Posts: 3296
Joined: Wed Oct 01, 2008 1:55 pm

Re: USB on real hw

Post by rdos »

I think you should always assume the maximum packet size is eight bytes unless you know otherwise from the descriptor
nullplan
Member
Member
Posts: 1789
Joined: Wed Aug 30, 2017 8:24 am

Re: USB on real hw

Post by nullplan »

rdos wrote:I think you should always assume the maximum packet size is eight bytes unless you know otherwise from the descriptor
Yeah. I mean, it makes little difference. The only things you need in order to know the correct packet size are the "address device" and "get descriptor" requests (for the first 8 bytes of the device descriptor), and those all fit inside 8 bytes. Unless you are on XHCI, then you don't even need "address device".
Carpe diem!
User avatar
Bonfra
Member
Member
Posts: 270
Joined: Wed Feb 19, 2020 1:08 pm
Libera.chat IRC: Bonfra
Location: Italy

Re: USB on real hw

Post by Bonfra »

rdos wrote:I think you should always assume the maximum packet size is eight bytes unless you know otherwise from the descriptor
Hm the max packet size in the device descriptor for my hardware is 64 but I have to use read10 cause any larger read won't work for some reason.
Regards, Bonfra.
nullplan
Member
Member
Posts: 1789
Joined: Wed Aug 30, 2017 8:24 am

Re: USB on real hw

Post by nullplan »

Bonfra wrote:Hm the max packet size in the device descriptor for my hardware is 64 but I have to use read10 cause any larger read won't work for some reason.
That's something different. The max packet size for EP 0 just tells you how big the packets on the control pipe can be. What you are talking about is what part of SCSI is implemented. That is a completely different layer of communication.
Carpe diem!
User avatar
Bonfra
Member
Member
Posts: 270
Joined: Wed Feb 19, 2020 1:08 pm
Libera.chat IRC: Bonfra
Location: Italy

Re: USB on real hw

Post by Bonfra »

I'm sorry I'm still not that proficient with SCSI I mistakenly assumed it was the same from the USB descriptor. So this is a specific length for SCSI, how do I get it? is it in the inquiry result or another specific command I must send?
Regards, Bonfra.
Post Reply