From 6eba063647cc4ff5aa863e1b5dc5093c22a3acb0 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sun, 22 Feb 2009 20:46:27 +0000 Subject: [PATCH] * Added simplified possibility to schedule UHCI transfers from within KDL. * Added debugger commands to resolve usb_ids to pipes. * Adjusted the physical memory allocator to be usable in a slimmed down mode when running inside the kernel debugger. * Implemented USB keyboard support for KDL through a kernel debugger add-on. * Added kgetc() and made use of it where previously individual methods were used to ensure that reading characters always goes through the kernel debugger add-ons and the other methods. This has some preconditions to meet though: 1) The keyboard must be in the boot protocol (currently the case but needs to be revisited once we have a full usb_hid). 2) The keyboard must be attached to a UHCI root port (i.e. not use EHCI or OHCI, also not through hubs unless those are USB 1.1). 3) the usb_hid driver has to be opened for this to work. This means that for the time between initializing USB and when usb_hid is opened by the input_server there is no keyboard support. Also note that this has no way of detecting hot-plug, meaning that you can't re-attach your USB keyboard from the hub to the root port once in KDL. On the bright side of things, since this is a non-destructive mechanism it is possible to enter and leave KDL without loosing the USB state. Tested OK in QEMU, not tested on real hardware yet, will see in a few minutes. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29291 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- build/jam/HaikuImage | 3 +- headers/private/kernel/debug.h | 1 + .../usb/PhysicalMemoryAllocator.cpp | 33 +++++ .../usb/PhysicalMemoryAllocator.h | 6 + src/add-ons/kernel/bus_managers/usb/Stack.cpp | 9 ++ src/add-ons/kernel/bus_managers/usb/usb.cpp | 24 ++++ src/add-ons/kernel/bus_managers/usb/usb_p.h | 3 + src/add-ons/kernel/busses/usb/uhci.cpp | 132 ++++++++++++++++-- src/add-ons/kernel/busses/usb/uhci.h | 8 +- src/add-ons/kernel/debugger/Jamfile | 1 + .../drivers/input/usb_hid/KeyboardDevice.cpp | 34 ++++- src/system/kernel/debug/blue_screen.cpp | 3 +- src/system/kernel/debug/debug.cpp | 48 +++---- 13 files changed, 266 insertions(+), 39 deletions(-) diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index e649289f6a..c7b28672f1 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -156,7 +156,8 @@ AddFilesToHaikuImage beos system add-ons kernel busses usb : uhci ohci ehci ; AddFilesToHaikuImage beos system add-ons kernel console : vga_text ; AddFilesToHaikuImage beos system add-ons kernel debugger - : $(X86_ONLY)disasm hangman invalidate_on_exit ; + : $(X86_ONLY)disasm hangman invalidate_on_exit + usb_keyboard ; AddFilesToHaikuImage beos system add-ons kernel file_systems : $(BEOS_ADD_ONS_FILE_SYSTEMS) ; AddFilesToHaikuImage beos system add-ons kernel generic diff --git a/headers/private/kernel/debug.h b/headers/private/kernel/debug.h index 8e5580f956..551223232c 100644 --- a/headers/private/kernel/debug.h +++ b/headers/private/kernel/debug.h @@ -115,6 +115,7 @@ extern void debug_set_page_fault_info(addr_t faultAddress, addr_t pc, extern debug_page_fault_info* debug_get_page_fault_info(); extern void debug_trap_cpu_in_kdl(bool returnIfHandedOver); +extern char kgetc(void); extern void kputs(const char *string); extern void kputs_unfiltered(const char *string); extern void kprintf_unfiltered(const char *format, ...) diff --git a/src/add-ons/kernel/bus_managers/usb/PhysicalMemoryAllocator.cpp b/src/add-ons/kernel/bus_managers/usb/PhysicalMemoryAllocator.cpp index 0c37dae54b..f7ec3c984a 100644 --- a/src/add-ons/kernel/bus_managers/usb/PhysicalMemoryAllocator.cpp +++ b/src/add-ons/kernel/bus_managers/usb/PhysicalMemoryAllocator.cpp @@ -66,6 +66,12 @@ PhysicalMemoryAllocator::PhysicalMemoryAllocator(const char *name, fManagedMemory = fBlockSize[0] * fArrayLength[0]; size_t roundedSize = biggestSize * minCountPerBlock; +#if KDEBUG + fDebugBase = roundedSize; + fDebugChunkSize = 64; + fDebugUseMap = 0; + roundedSize += sizeof(fDebugUseMap) * 8 * fDebugChunkSize; +#endif roundedSize = (roundedSize + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); fArea = create_area(fName, &fLogicalBase, B_ANY_KERNEL_ADDRESS, @@ -122,6 +128,24 @@ status_t PhysicalMemoryAllocator::Allocate(size_t size, void **logicalAddress, void **physicalAddress) { +#if KDEBUG + if (debug_debugger_running()) { + for (int32 i = 0; i < 64; i++) { + uint64 mask = 1LL << i; + if ((fDebugUseMap & mask) == 0) { + fDebugUseMap |= mask; + *logicalAddress = (void *)((uint8 *)fLogicalBase + fDebugBase + + i * fDebugChunkSize); + *physicalAddress = (void *)((uint8 *)fPhysicalBase + fDebugBase + + i * fDebugChunkSize); + return B_OK; + } + } + + return B_NO_MEMORY; + } +#endif + if (size == 0 || size > fBlockSize[fArrayCount - 1]) { TRACE_ERROR(("PMA: bad value for allocate (%ld bytes)\n", size)); return B_BAD_VALUE; @@ -198,6 +222,15 @@ status_t PhysicalMemoryAllocator::Deallocate(size_t size, void *logicalAddress, void *physicalAddress) { +#if KDEBUG + if (debug_debugger_running()) { + uint32 index = ((uint8 *)logicalAddress - (uint8 *)fLogicalBase + - fDebugBase) / fDebugChunkSize; + fDebugUseMap &= ~(1LL << index); + return B_OK; + } +#endif + if (size == 0 || size > fBlockSize[fArrayCount - 1]) { TRACE_ERROR(("PMA: bad value for deallocate (%ld bytes)\n", size)); return B_BAD_VALUE; diff --git a/src/add-ons/kernel/bus_managers/usb/PhysicalMemoryAllocator.h b/src/add-ons/kernel/bus_managers/usb/PhysicalMemoryAllocator.h index 35e074c0c8..a898a4ed39 100644 --- a/src/add-ons/kernel/bus_managers/usb/PhysicalMemoryAllocator.h +++ b/src/add-ons/kernel/bus_managers/usb/PhysicalMemoryAllocator.h @@ -57,6 +57,12 @@ private: size_t *fArrayLength; size_t *fArrayOffset; uint8 **fArray; + +#if KDEBUG + uint32 fDebugBase; + uint32 fDebugChunkSize; + uint64 fDebugUseMap; +#endif }; #endif // !_PHYSICAL_MEMORY_ALLOCATOR_H_ diff --git a/src/add-ons/kernel/bus_managers/usb/Stack.cpp b/src/add-ons/kernel/bus_managers/usb/Stack.cpp index 272c3b3195..2a06da66ee 100644 --- a/src/add-ons/kernel/bus_managers/usb/Stack.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Stack.cpp @@ -206,6 +206,15 @@ Stack::GetObject(usb_id id) } +Object * +Stack::GetObjectNoLock(usb_id id) +{ + if (id >= fObjectMaxCount) + return NULL; + return fObjectArray[id]; +} + + int32 Stack::ExploreThread(void *data) { diff --git a/src/add-ons/kernel/bus_managers/usb/usb.cpp b/src/add-ons/kernel/bus_managers/usb/usb.cpp index 7cf2f375b1..af13e7d18a 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb.cpp +++ b/src/add-ons/kernel/bus_managers/usb/usb.cpp @@ -16,6 +16,25 @@ Stack *gUSBStack = NULL; +static int +debug_get_pipe_for_id(int argc, char **argv) +{ + if (gUSBStack == NULL) + return 1; + + if (!is_debug_variable_defined("_usbPipeID")) + return 2; + + uint64 id = get_debug_variable("_usbPipeID", 0); + Object *object = gUSBStack->GetObjectNoLock((usb_id)id); + if (!object || (object->Type() & USB_OBJECT_PIPE) == 0) + return 3; + + set_debug_variable("_usbPipe", (uint64)object); + return 0; +} + + static int32 bus_std_ops(int32 op, ...) { @@ -58,6 +77,9 @@ bus_std_ops(int32 op, ...) } gUSBStack = stack; + add_debugger_command("get_usb_pipe_for_id", + &debug_get_pipe_for_id, + "Gets the config for a USB pipe"); #ifndef __HAIKU__ // Plain R5 workaround, see comment above. shared = create_area("shared usb stack", &address, @@ -73,6 +95,8 @@ bus_std_ops(int32 op, ...) TRACE_MODULE("uninit\n"); delete gUSBStack; gUSBStack = NULL; + remove_debugger_command("get_usb_pipe_for_id", + &debug_get_pipe_for_id); break; default: diff --git a/src/add-ons/kernel/bus_managers/usb/usb_p.h b/src/add-ons/kernel/bus_managers/usb/usb_p.h index d343ac0d22..d6cb61cb70 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb_p.h +++ b/src/add-ons/kernel/bus_managers/usb/usb_p.h @@ -126,6 +126,9 @@ public: void PutUSBID(usb_id id); Object * GetObject(usb_id id); + // only for the kernel debugger + Object * GetObjectNoLock(usb_id id); + void AddBusManager(BusManager *bus); int32 IndexOfBusManager(BusManager *bus); BusManager * BusManagerAt(int32 index); diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index 1a3365b19c..e384348330 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -19,6 +19,33 @@ pci_module_info *UHCI::sPCIModule = NULL; +static int32 sDebuggerCommandAdded = 0; + + +static int +debug_process_transfer(int argc, char **argv) +{ + Pipe *pipe = (Pipe *)get_debug_variable("_usbPipe", 0); + if (pipe == NULL) + return 2; + + // check if we have a UHCI bus at all + if (pipe->GetBusManager()->TypeName()[0] != 'u') + return 3; + + uint8 *data = (uint8 *)get_debug_variable("_usbTransferData", 0); + if (data == NULL) + return 4; + + size_t length = (size_t)get_debug_variable("_usbTransferLength", 0); + if (length == 0) + return 5; + + Transfer transfer(pipe); + transfer.SetData(data, length); + return ((UHCI *)pipe->GetBusManager())->ProcessDebugTransfer(&transfer); +} + static int32 uhci_std_ops(int32 op, ...) @@ -197,9 +224,9 @@ Queue::TerminateByStrayDescriptor() status_t -Queue::AppendTransfer(uhci_qh *transfer) +Queue::AppendTransfer(uhci_qh *transfer, bool lock) { - if (!Lock()) + if (lock && !Lock()) return B_ERROR; transfer->link_log = NULL; @@ -219,15 +246,16 @@ Queue::AppendTransfer(uhci_qh *transfer) element->link_phy = transfer->this_phy | QH_NEXT_IS_QH; } - Unlock(); + if (lock) + Unlock(); return B_OK; } status_t -Queue::RemoveTransfer(uhci_qh *transfer) +Queue::RemoveTransfer(uhci_qh *transfer, bool lock) { - if (!Lock()) + if (lock && !Lock()) return B_ERROR; if (fQueueTop == transfer) { @@ -241,7 +269,8 @@ Queue::RemoveTransfer(uhci_qh *transfer) fQueueHead->element_phy = transfer->link_phy; } - Unlock(); + if (lock) + Unlock(); return B_OK; } else { uhci_qh *element = fQueueTop; @@ -249,7 +278,8 @@ Queue::RemoveTransfer(uhci_qh *transfer) if (element->link_log == transfer) { element->link_log = transfer->link_log; element->link_phy = transfer->link_phy; - Unlock(); + if (lock) + Unlock(); return B_OK; } @@ -257,7 +287,8 @@ Queue::RemoveTransfer(uhci_qh *transfer) } } - Unlock(); + if (lock) + Unlock(); return B_BAD_VALUE; } @@ -374,8 +405,9 @@ UHCI::UHCI(pci_info *info, Stack *stack) // 1: low speed control transfers // 2: full speed control transfers // 3: bulk transfers + // 4: debug queue // TODO: 4: bandwidth reclamation queue - fQueueCount = 4; + fQueueCount = 5; fQueues = new(std::nothrow) Queue *[fQueueCount]; if (!fQueues) { delete_area(fFrameArea); @@ -462,6 +494,12 @@ UHCI::UHCI(pci_info *info, Stack *stack) WriteReg16(UHCI_USBINTR, UHCI_USBINTR_CRC | UHCI_USBINTR_IOC | UHCI_USBINTR_SHORT); + if (atomic_add(&sDebuggerCommandAdded, 1) == 0) { + add_debugger_command("uhci_process_transfer", + &debug_process_transfer, + "Processes a USB transfer with the given variables"); + } + TRACE("UHCI host controller driver constructed\n"); fInitOK = true; } @@ -469,6 +507,11 @@ UHCI::UHCI(pci_info *info, Stack *stack) UHCI::~UHCI() { + if (atomic_add(&sDebuggerCommandAdded, -1) == 1) { + remove_debugger_command("uhci_process_transfer", + &debug_process_transfer); + } + int32 result = 0; fStopFinishThread = true; fStopFinishIsochronousThread = true; @@ -607,6 +650,77 @@ UHCI::SubmitTransfer(Transfer *transfer) } +status_t +UHCI::ProcessDebugTransfer(Transfer *transfer) +{ + uhci_td *firstDescriptor = NULL; + uhci_qh *transferQueue = NULL; + status_t result = CreateFilledTransfer(transfer, &firstDescriptor, + &transferQueue); + if (result < B_OK) + return result; + + fQueues[UHCI_DEBUG_QUEUE]->AppendTransfer(transferQueue, false); + + while (true) { + bool transferOK = false; + bool transferError = false; + uhci_td *descriptor = firstDescriptor; + + while (descriptor) { + uint32 status = descriptor->status; + if (status & TD_STATUS_ACTIVE) + break; + + if (status & TD_ERROR_MASK) { + transferError = true; + break; + } + + if ((descriptor->link_phy & TD_TERMINATE) + || (descriptor->status & TD_STATUS_ACTLEN_MASK) + < (descriptor->token >> TD_TOKEN_MAXLEN_SHIFT)) { + transferOK = true; + break; + } + + descriptor = (uhci_td *)descriptor->link_log; + } + + if (!transferOK && !transferError) { + spin(200); + continue; + } + + if (transferOK) { + size_t actualLength = 0; + uint8 lastDataToggle = 0; + if (transfer->TransferPipe()->Direction() == Pipe::In) { + // data to read out + iovec *vector = transfer->Vector(); + size_t vectorCount = transfer->VectorCount(); + + actualLength = ReadDescriptorChain(firstDescriptor, + vector, vectorCount, &lastDataToggle); + } else { + // read the actual length that was sent + actualLength = ReadActualLength(firstDescriptor, + &lastDataToggle); + } + + transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0); + } + + fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transferQueue, false); + FreeDescriptorChain(firstDescriptor); + FreeTransferQueue(transferQueue); + return transferOK ? B_OK : B_IO_ERROR; + } + + return B_ERROR; +} + + status_t UHCI::CancelQueuedTransfers(Pipe *pipe, bool force) { diff --git a/src/add-ons/kernel/busses/usb/uhci.h b/src/add-ons/kernel/busses/usb/uhci.h index 2b04663268..45a697aa57 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -20,6 +20,7 @@ #define UHCI_FULL_SPEED_CONTROL_QUEUE 2 #define UHCI_BULK_QUEUE 3 #define UHCI_BANDWIDTH_RECLAMATION_QUEUE 4 +#define UHCI_DEBUG_QUEUE 4 struct pci_info; struct pci_module_info; @@ -39,8 +40,10 @@ public: status_t LinkTo(Queue *other); status_t TerminateByStrayDescriptor(); - status_t AppendTransfer(uhci_qh *transfer); - status_t RemoveTransfer(uhci_qh *transfer); + status_t AppendTransfer(uhci_qh *transfer, + bool lock = true); + status_t RemoveTransfer(uhci_qh *transfer, + bool lock = true); addr_t PhysicalAddress(); @@ -94,6 +97,7 @@ public: status_t Start(); virtual status_t SubmitTransfer(Transfer *transfer); + status_t ProcessDebugTransfer(Transfer *transfer); virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force); status_t CancelQueuedIsochronousTransfers(Pipe *pipe, bool force); status_t SubmitRequest(Transfer *transfer); diff --git a/src/add-ons/kernel/debugger/Jamfile b/src/add-ons/kernel/debugger/Jamfile index 90f35c9900..0594932f75 100644 --- a/src/add-ons/kernel/debugger/Jamfile +++ b/src/add-ons/kernel/debugger/Jamfile @@ -7,3 +7,4 @@ SubInclude HAIKU_TOP src add-ons kernel debugger disasm ; SubInclude HAIKU_TOP src add-ons kernel debugger hangman ; SubInclude HAIKU_TOP src add-ons kernel debugger invalidate_on_exit ; SubInclude HAIKU_TOP src add-ons kernel debugger laplinkll ; +SubInclude HAIKU_TOP src add-ons kernel debugger usb_keyboard ; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp index 7c0ee4987e..549db8930d 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp @@ -10,11 +10,26 @@ #include "KeyboardDevice.h" #include #include +#include // input server private for raw_key_info, KB_READ, etc... #include "kb_mouse_driver.h" +static usb_id sDebugKeyboardPipe = 0; +static size_t sDebugKeyboardReportSize = 0; +static int32 sDebuggerCommandAdded = 0; + + +static int +debug_get_keyboard_config(int argc, char **argv) +{ + set_debug_variable("_usbPipeID", (uint64)sDebugKeyboardPipe); + set_debug_variable("_usbReportSize", (uint64)sDebugKeyboardReportSize); + return 0; +} + + KeyboardDevice::KeyboardDevice(usb_device device, usb_pipe interruptPipe, size_t interfaceIndex, report_insn *instructions, size_t instructionCount, size_t totalReportSize) @@ -34,12 +49,23 @@ KeyboardDevice::KeyboardDevice(usb_device device, usb_pipe interruptPipe, } SetBaseName("input/keyboard/usb/"); + + if (atomic_add(&sDebuggerCommandAdded, 1) == 0) { + add_debugger_command("get_usb_keyboard_config", + &debug_get_keyboard_config, + "Gets the required config of the USB keyboard"); + } } KeyboardDevice::~KeyboardDevice() { free(fLastTransferBuffer); + + if (atomic_add(&sDebuggerCommandAdded, -1) == 1) { + remove_debugger_command("get_usb_keyboard_config", + &debug_get_keyboard_config); + } } @@ -410,9 +436,13 @@ KeyboardDevice::_InterpretBuffer() key = KEY_Break; else if (key == 0xe && (current[0] & 1)) key = KEY_SysRq; -#if 0 - else if (keyDown && key == 0x0d) // ToDo: remove again +#if 1 + else if (keyDown && key == 0x0d) { + // ToDo: remove again + sDebugKeyboardPipe = fInterruptPipe; + sDebugKeyboardReportSize = fTotalReportSize; panic("keyboard requested halt.\n"); + } #endif else if (key == 0) { // unmapped key diff --git a/src/system/kernel/debug/blue_screen.cpp b/src/system/kernel/debug/blue_screen.cpp index 3c48421ace..c3bdbc5e59 100644 --- a/src/system/kernel/debug/blue_screen.cpp +++ b/src/system/kernel/debug/blue_screen.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -139,7 +140,7 @@ next_line(void) text[i], sScreen.boot_debug_output ? 0x6f : 0xf6); } - char c = blue_screen_getchar(); + char c = kgetc(); if (c == 's') { sScreen.ignore_output = true; } else if (c == 'q' && in_command_invocation()) { diff --git a/src/system/kernel/debug/debug.cpp b/src/system/kernel/debug/debug.cpp index 43dd3e0702..5fd140494e 100644 --- a/src/system/kernel/debug/debug.cpp +++ b/src/system/kernel/debug/debug.cpp @@ -408,27 +408,8 @@ read_line(char* buffer, int32 maxLength, bool done = false; char c = 0; - char (*readChar)(void); - if (sBlueScreenOutput) - readChar = blue_screen_getchar; - else - readChar = arch_debug_serial_getchar; - while (!done) { - bool hasChar = false; - for (uint32 i = 0; i < kMaxDebuggerModules; i++) { - if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_getchar) { - int getChar = sDebuggerModules[i]->debugger_getchar(); - if (getChar >= 0) { - hasChar = true; - c = (char)getChar; - break; - } - } - } - - if (!hasChar) - c = readChar(); + c = kgetc(); switch (c) { case '\n': @@ -487,12 +468,12 @@ read_line(char* buffer, int32 maxLength, } break; case 27: // escape sequence - c = readChar(); + c = kgetc(); if (c != '[') { // ignore broken escape sequence break; } - c = readChar(); + c = kgetc(); switch (c) { case 'C': // right arrow if (position < length) { @@ -548,7 +529,7 @@ read_line(char* buffer, int32 maxLength, case '5': // if "5~", it's PAGE UP case '6': // if "6~", it's PAGE DOWN { - if (readChar() != '~') + if (kgetc() != '~') break; // PAGE UP: search backward, PAGE DOWN: forward @@ -603,7 +584,7 @@ read_line(char* buffer, int32 maxLength, } case '3': // if "3~", it's DEL { - if (readChar() != '~') + if (kgetc() != '~') break; if (position < length) @@ -649,6 +630,25 @@ read_line(char* buffer, int32 maxLength, } +char +kgetc(void) +{ + // give the kernel debugger modules a chance first + for (uint32 i = 0; i < kMaxDebuggerModules; i++) { + if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_getchar) { + int getChar = sDebuggerModules[i]->debugger_getchar(); + if (getChar >= 0) + return (char)getChar; + } + } + + if (sBlueScreenOutput) + return blue_screen_getchar(); + + return arch_debug_serial_getchar(); +} + + int kgets(char* buffer, int length) {