Bonfra wrote:Would you like me to compile without VESA so you can test it on bochs or do you prefer the exact image that produced the outputs above?
An image I can load and run with Bochs, please.
Bonfra wrote:Basically, I'm starting and stopping the schedule for every transaction. before every operation, I clear it all with TD_TERMINATE and put a queue head as the first element pointing to the first TD so they get evaluated breath first.
(Note that Breadth First is horizontal. Only one TD in that Queue will be executed, moving to the next Queue in this frame. Any concurrent TDs in any of these QHs will not be executed until the next frame or if any QH points back to any of these existing QHs. Are your intentions Depth First instead of Breadth First?)
In my opinion, it is not safe practice to start and stop the schedule. I am away from my desk, which means I am away from my notes, but if memory serves, the UHCI expects all memory to be static until the next frame. i.e.: during a frame, all memory that can be accessed by the controller is assumed to have already be written to physical memory. i.e.: you should not write to any Queue or TD that can be accessed by the UHCI during this frame (1ms). Same for reads, you should not assume any read is valid until the end-of-frame interrupt has been triggered.
Any read or write via an emulator will be instant. i.e.: as soon as the write is encountered, any further read from that memory will read the new value. However, on real hardware, the controller can and probably will read a full page (4k for example) of physical memory, using that cached page until a memory address is outside that 4k, triggering another 4k read. Therefore, any write to that 4k memory after the controller has read it, will not be valid until the next frame when the controller is required to read it again from physical memory.
At end-of-frame, the controller is to write back any memory that it may have modified (status flags, length, etc.), as well as when you stop the controller. What if you have written to a memory position that the controller thinks has been static, in turn writing back its values, over-writing your modification?
Again, this is all from memory, but if it serves me correctly, you should not write to any memory that the controller will access during that particular frame, and you must not read from any address that the controller can access during this frame until the end-of-frame is triggered.
A suggested way to do this is to have multiple periodical schedules within your frame's stack. i.e.: have every odd frame number point to one periodical stack, and every even frame number point to another stack. As for control/bulk TDs, do a similar technique. Every odd frame uses one stream of Control/Bulk Queues/TDs and every even numbered frame uses another stream. Then all you have to do is see which frame number the UHCI is on and use the correct periodical/control/bulk stream. With this technique, you can safely read and write to the "dormant" stream at will, as long as you take less than 1ms to make the modifications *and* none of the streams overlap each other. i.e.: no QH/TD in the odd stream is present in the even stream.
So, once you start the controller, you should not have to stop it until there is an error or a shut-down/sleep is triggered.
Does this make sense? I hope.
Ben
-
https://www.fysnet.net/osdesign_book_series.htm