void arch_debug_serial_putchar(const char c) { cpu_status state = 0; if (!debug_debugger_running()) { state = disable_interrupts(); acquire_spinlock(&sSerialOutputSpinlock); } _arch_debug_serial_putchar(c); if (!debug_debugger_running()) { release_spinlock(&sSerialOutputSpinlock); restore_interrupts(state); } }
void arch_debug_serial_puts(const char *s) { cpu_status state = 0; if (!debug_debugger_running()) { state = disable_interrupts(); acquire_spinlock(&sSerialOutputSpinlock); } while (*s != '\0') { _arch_debug_serial_putchar(*s); s++; } if (!debug_debugger_running()) { release_spinlock(&sSerialOutputSpinlock); restore_interrupts(state); } }
status_t PhysicalMemoryAllocator::Allocate(size_t size, void **logicalAddress, void **physicalAddress) { // TODO: physicalAddress should be a phys_addr_t*! #ifdef HAIKU_TARGET_PLATFORM_HAIKU 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 *)(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; } size_t arrayLength = 0; int32 arrayToUse = 0; for (int32 i = 0; i < fArrayCount; i++) { if (fBlockSize[i] >= size) { arrayToUse = i; arrayLength = fArrayLength[i]; break; } } int32 retries = 5000; while (retries-- > 0) { if (!_Lock()) return B_ERROR; TRACE(("PMA: will use array %ld (blocksize: %ld) to allocate %ld bytes\n", arrayToUse, fBlockSize[arrayToUse], size)); uint8 *targetArray = fArray[arrayToUse]; uint32 arrayOffset = fArrayOffset[arrayToUse] % arrayLength; for (size_t i = arrayOffset + 1; i != arrayOffset; i++) { if (i >= arrayLength) i -= arrayLength; if (targetArray[i] == 0) { // found a free slot fArrayOffset[arrayToUse] = i; // fill upwards to the smallest block uint32 fillSize = 1; uint32 arrayIndex = i; for (int32 j = arrayToUse; j >= 0; j--) { memset(&fArray[j][arrayIndex], 1, fillSize); fillSize <<= 1; arrayIndex <<= 1; } // fill downwards to the biggest block arrayIndex = i >> 1; for (int32 j = arrayToUse + 1; j < fArrayCount; j++) { fArray[j][arrayIndex]++; if (fArray[j][arrayIndex] > 1) break; arrayIndex >>= 1; } _Unlock(); size_t offset = fBlockSize[arrayToUse] * i; *logicalAddress = (void *)((uint8 *)fLogicalBase + offset); *physicalAddress = (void *)(fPhysicalBase + offset); return B_OK; } } // no slot found _Unlock(); TRACE_ERROR(("PMA: found no free slot to store %ld bytes (%ld tries left)\n", size, retries)); // we provide a scratch space here, memory will probably be freed // as soon as some other transfer is completed and cleaned up. // just wait a bit to give other threads a chance to free some slots. snooze(100); }
status_t PhysicalMemoryAllocator::Allocate(size_t size, void **logicalAddress, phys_addr_t *physicalAddress) { #ifdef HAIKU_TARGET_PLATFORM_HAIKU if (debug_debugger_running()) { if (size > fDebugChunkSize) { kprintf("usb allocation of %" B_PRIuSIZE " does not fit debug chunk size %" B_PRIuSIZE "!\n", size, fDebugChunkSize); return B_NO_MEMORY; } for (size_t i = 0; i < sizeof(fDebugUseMap) * 8; i++) { uint64 mask = 1LL << i; if ((fDebugUseMap & mask) == 0) { fDebugUseMap |= mask; *logicalAddress = (void *)((uint8 *)fLogicalBase + fDebugBase + i * fDebugChunkSize); *physicalAddress = (phys_addr_t)(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; } size_t arrayLength = 0; int32 arrayToUse = 0; for (int32 i = 0; i < fArrayCount; i++) { if (fBlockSize[i] >= size) { arrayToUse = i; arrayLength = fArrayLength[i]; break; } } if (!_Lock()) return B_ERROR; while (true) { TRACE(("PMA: will use array %ld (blocksize: %ld) to allocate %ld bytes\n", arrayToUse, fBlockSize[arrayToUse], size)); uint8 *targetArray = fArray[arrayToUse]; uint32 arrayOffset = fArrayOffset[arrayToUse] % arrayLength; for (size_t i = arrayOffset + 1; i != arrayOffset; i++) { if (i >= arrayLength) i -= arrayLength; if (targetArray[i] == 0) { // found a free slot fArrayOffset[arrayToUse] = i; // fill upwards to the smallest block uint32 fillSize = 1; uint32 arrayIndex = i; for (int32 j = arrayToUse; j >= 0; j--) { memset(&fArray[j][arrayIndex], 1, fillSize); fillSize <<= 1; arrayIndex <<= 1; } // fill downwards to the biggest block arrayIndex = i >> 1; for (int32 j = arrayToUse + 1; j < fArrayCount; j++) { fArray[j][arrayIndex]++; if (fArray[j][arrayIndex] > 1) break; arrayIndex >>= 1; } _Unlock(); size_t offset = fBlockSize[arrayToUse] * i; *logicalAddress = (void *)((uint8 *)fLogicalBase + offset); *physicalAddress = (phys_addr_t)(fPhysicalBase + offset); return B_OK; } } // no slot found, we need to wait ConditionVariableEntry entry; fNoMemoryCondition.Add(&entry); fMemoryWaitersCount++; _Unlock(); TRACE_ERROR(("PMA: found no free slot to store %ld bytes, waiting\n", size)); entry.Wait(); if (!_Lock()) return B_ERROR; fMemoryWaitersCount--; }
void x86_page_fault_exception(struct iframe* frame) { Thread* thread = thread_get_current_thread(); addr_t cr2 = x86_read_cr2(); addr_t newip; if (debug_debugger_running()) { // If this CPU or this thread has a fault handler, we're allowed to be // here. if (thread != NULL) { cpu_ent* cpu = &gCPU[smp_get_current_cpu()]; if (cpu->fault_handler != 0) { debug_set_page_fault_info(cr2, frame->ip, (frame->error_code & 0x2) != 0 ? DEBUG_PAGE_FAULT_WRITE : 0); frame->ip = cpu->fault_handler; frame->bp = cpu->fault_handler_stack_pointer; return; } if (thread->fault_handler != 0) { kprintf("ERROR: thread::fault_handler used in kernel " "debugger!\n"); debug_set_page_fault_info(cr2, frame->ip, (frame->error_code & 0x2) != 0 ? DEBUG_PAGE_FAULT_WRITE : 0); frame->ip = reinterpret_cast<uintptr_t>(thread->fault_handler); return; } } // otherwise, not really panic("page fault in debugger without fault handler! Touching " "address %p from ip %p\n", (void*)cr2, (void*)frame->ip); return; } else if ((frame->flags & 0x200) == 0) { // interrupts disabled // If a page fault handler is installed, we're allowed to be here. // TODO: Now we are generally allowing user_memcpy() with interrupts // disabled, which in most cases is a bug. We should add some thread // flag allowing to explicitly indicate that this handling is desired. uintptr_t handler = reinterpret_cast<uintptr_t>(thread->fault_handler); if (thread && thread->fault_handler != 0) { if (frame->ip != handler) { frame->ip = handler; return; } // The fault happened at the fault handler address. This is a // certain infinite loop. panic("page fault, interrupts disabled, fault handler loop. " "Touching address %p from ip %p\n", (void*)cr2, (void*)frame->ip); } // If we are not running the kernel startup the page fault was not // allowed to happen and we must panic. panic("page fault, but interrupts were disabled. Touching address " "%p from ip %p\n", (void*)cr2, (void*)frame->ip); return; } else if (thread != NULL && thread->page_faults_allowed < 1) { panic("page fault not allowed at this place. Touching address " "%p from ip %p\n", (void*)cr2, (void*)frame->ip); return; } enable_interrupts(); vm_page_fault(cr2, frame->ip, (frame->error_code & 0x2)!= 0, // write access (frame->error_code & 0x10) != 0, // instruction fetch (frame->error_code & 0x4) != 0, // userland &newip); if (newip != 0) { // the page fault handler wants us to modify the iframe to set the // IP the cpu will return to this ip frame->ip = newip; } }
extern "C" void arch_arm_data_abort(struct iframe *frame) { Thread *thread = thread_get_current_thread(); bool isUser = (frame->spsr & 0x1f) == 0x10; addr_t far = arm_get_far(); bool isWrite = true; addr_t newip = 0; #ifdef TRACE_ARCH_INT print_iframe("Data Abort", frame); dprintf("FAR: %08lx, thread: %s\n", far, thread->name); #endif IFrameScope scope(frame); if (debug_debugger_running()) { // If this CPU or this thread has a fault handler, we're allowed to be // here. if (thread != NULL) { cpu_ent* cpu = &gCPU[smp_get_current_cpu()]; if (cpu->fault_handler != 0) { debug_set_page_fault_info(far, frame->pc, isWrite ? DEBUG_PAGE_FAULT_WRITE : 0); frame->svc_sp = cpu->fault_handler_stack_pointer; frame->pc = cpu->fault_handler; return; } if (thread->fault_handler != 0) { kprintf("ERROR: thread::fault_handler used in kernel " "debugger!\n"); debug_set_page_fault_info(far, frame->pc, isWrite ? DEBUG_PAGE_FAULT_WRITE : 0); frame->pc = thread->fault_handler; return; } } // otherwise, not really panic("page fault in debugger without fault handler! Touching " "address %p from pc %p\n", (void *)far, (void *)frame->pc); return; } else if ((frame->spsr & (1 << 7)) != 0) { // interrupts disabled // If a page fault handler is installed, we're allowed to be here. // TODO: Now we are generally allowing user_memcpy() with interrupts // disabled, which in most cases is a bug. We should add some thread // flag allowing to explicitly indicate that this handling is desired. if (thread && thread->fault_handler != 0) { if (frame->pc != thread->fault_handler) { frame->pc = thread->fault_handler; return; } // The fault happened at the fault handler address. This is a // certain infinite loop. panic("page fault, interrupts disabled, fault handler loop. " "Touching address %p from pc %p\n", (void*)far, (void*)frame->pc); } // If we are not running the kernel startup the page fault was not // allowed to happen and we must panic. panic("page fault, but interrupts were disabled. Touching address " "%p from pc %p\n", (void *)far, (void *)frame->pc); return; } else if (thread != NULL && thread->page_faults_allowed < 1) { panic("page fault not allowed at this place. Touching address " "%p from pc %p\n", (void *)far, (void *)frame->pc); return; } enable_interrupts(); vm_page_fault(far, frame->pc, isWrite, false, isUser, &newip); if (newip != 0) { // the page fault handler wants us to modify the iframe to set the // IP the cpu will return to to be this ip frame->pc = newip; } }