/** * Initializes memory mirror. * * Memory mirror allocates all available ram to specific range address. * If 1GB paging is supported, 1GB paging is used, otherwise only 4KB * paging is used, which means much more physical ram is used. */ void initialize_memory_mirror() { section_info_t* head = frame_pool; frame_pool = NULL; bool first_set = false; if (is_1GB_paging_supported() != 0) { for (puint_t start=0; start < maxram; start+=1<<30) { puint_t vaddress = start + ADDRESS_OFFSET(RESERVED_KBLOCK_RAM_MAPPINGS); v_address_t va; memcpy(&va, &vaddress, 8); puint_t* pml4 = (puint_t*)ALIGN(physical_to_virtual(get_active_page())); if (!PRESENT(pml4[va.pml])) { pdpt_t pdpt; memset(&pdpt, 0, sizeof(pdpt_t)); pdpt.number = get_free_frame(); pdpt.flaggable.present = 1; pdpt.flaggable.us = 0; pdpt.flaggable.rw = 1; pml4[va.pml] = pdpt.number; memset((void*)physical_to_virtual(ALIGN(pdpt.number)), 0, 0x1000); } puint_t* pdpt = (puint_t*)ALIGN(physical_to_virtual(pml4[va.pml])); page_directory1GB_t dir; memset(&dir, 0, sizeof(page_directory1GB_t)); dir.number = start; dir.flaggable.present = 1; dir.flaggable.ps = 1; dir.flaggable.rw = 1; pdpt[va.directory_ptr] = dir.number; if (!first_set) { first_set = true; frame_pool = head; } } } else { for (puint_t start=0; start < maxram; start+=0x1000) { puint_t kend = kernel_tmp_heap_start - 0xFFFFFFFF80000000 + 0x40000; if (kend+0x4000 >= tmp_heap && !first_set) { first_set = true; frame_pool = head; } puint_t vaddress = start + ADDRESS_OFFSET(RESERVED_KBLOCK_RAM_MAPPINGS); puint_t* paddress = get_page(vaddress, get_active_page(), true); page_t page; memset(&page, 0, sizeof(page_t)); page.address = start; page.flaggable.present = 1; page.flaggable.rw = 1; page.flaggable.us = 0; *paddress = page.address; } } }
/** * Returns address + physical identity map offset */ uintptr_t physical_to_virtual(puint_t paddress) { if (!__mem_mirror_present) return paddress; if (paddress == 0) return 0; return paddress + ADDRESS_OFFSET(RESERVED_KBLOCK_RAM_MAPPINGS); }
/** * Computes virtual to physical mapping. * * Checks for page hierarchy and determines what physical address will be. * If page structures are missing on the way to decode, physical address cannot * be found and this valid will contain 0, otherwise valid will contain 1 * * 1GB page sector (ram identity map) behaves slightly different, because it * needs different v_address_t type. */ ruint_t virtual_to_physical(uintptr_t vaddress, uintptr_t cr3, uint8_t* valid) { *valid = 1; v_address_t va; memcpy(&va, &vaddress, 8); puint_t* address = (puint_t*)ALIGN(physical_to_virtual(cr3)); address = (puint_t*)ALIGN(physical_to_virtual(address[va.pml])); if (!PRESENT(address)) { *valid = 0; return 0; } if (vaddress > ADDRESS_OFFSET(RESERVED_KBLOCK_RAM_MAPPINGS) && vaddress < ADDRESS_OFFSET((RESERVED_KBLOCK_RAM_MAPPINGS+1)) && is_1GB_paging_supported()) { v_address1GB_t va = *((v_address1GB_t*) &vaddress); page_directory1GB_t pd1gb; pd1gb.number = (uint64_t) address; return pd1gb.flaggable.address + va.offset; } address = (puint_t*)ALIGN(physical_to_virtual(address[va.directory_ptr])); if (!PRESENT(address)) { *valid = 0; return 0; } address = (puint_t*)ALIGN(physical_to_virtual(address[va.directory])); if (!PRESENT(address)) { *valid = 0; return 0; } if (!PRESENT(*address)) { *valid = 0; return 0; } puint_t physadd = *address; return ALIGN(physadd) + va.offset; }
static status_t GetEdidFromBIOS(edid1_raw& edidRaw) { // Get the EDID info from the video BIOS, and return B_OK if successful. #define ADDRESS_SEGMENT(address) ((addr_t)(address) >> 4) #define ADDRESS_OFFSET(address) ((addr_t)(address) & 0xf) vm86_state vmState; status_t status = vm86_prepare(&vmState, 0x2000); if (status != B_OK) { TRACE("GetEdidFromBIOS(); vm86_prepare() failed, status: 0x%lx\n", status); return status; } vmState.regs.eax = 0x4f15; vmState.regs.ebx = 0; // 0 = report DDC service vmState.regs.ecx = 0; vmState.regs.es = 0; vmState.regs.edi = 0; status = vm86_do_int(&vmState, 0x10); if (status == B_OK) { // AH contains the error code, and AL determines wether or not the // function is supported. if (vmState.regs.eax != 0x4f) status = B_NOT_SUPPORTED; // Test if DDC is supported by the monitor. if ((vmState.regs.ebx & 3) == 0) status = B_NOT_SUPPORTED; } if (status == B_OK) { // According to the author of the vm86 functions, the address of any // object to receive data must be >= 0x1000 and within the ram size // specified in the second argument of the vm86_prepare() call above. // Thus, the address of the struct to receive the EDID info is set to // 0x1000. edid1_raw* edid = (edid1_raw*)0x1000; vmState.regs.eax = 0x4f15; vmState.regs.ebx = 1; // 1 = read EDID vmState.regs.ecx = 0; vmState.regs.edx = 0; vmState.regs.es = ADDRESS_SEGMENT(edid); vmState.regs.edi = ADDRESS_OFFSET(edid); status = vm86_do_int(&vmState, 0x10); if (status == B_OK) { if (vmState.regs.eax != 0x4f) { status = B_NOT_SUPPORTED; } else { // Copy the EDID info to the caller's location, and compute the // checksum of the EDID info while copying. uint8 sum = 0; uint8 allOr = 0; uint8* dest = (uint8*)&edidRaw; uint8* src = (uint8*)edid; for (uint32 j = 0; j < sizeof(edidRaw); j++) { sum += *src; allOr |= *src; *dest++ = *src++; } if (allOr == 0) { TRACE("GetEdidFromBIOS(); EDID info contains only zeros\n"); status = B_ERROR; } else if (sum != 0) { TRACE("GetEdidFromBIOS(); Checksum error in EDID info\n"); status = B_ERROR; } } } } vm86_cleanup(&vmState); return status; }
static status_t GetEdidFromBIOS(edid1_raw& edidRaw) { // Get the EDID info from the video BIOS, and return B_OK if successful. #define ADDRESS_SEGMENT(address) ((addr_t)(address) >> 4) #define ADDRESS_OFFSET(address) ((addr_t)(address) & 0xf) bios_module_info* biosModule; status_t status = get_module(B_BIOS_MODULE_NAME, (module_info**)&biosModule); if (status != B_OK) { TRACE("GetEdidFromBIOS(): failed to get BIOS module: 0x%" B_PRIx32 "\n", status); return status; } bios_state* state; status = biosModule->prepare(&state); if (status != B_OK) { TRACE("GetEdidFromBIOS(): bios_prepare() failed: 0x%" B_PRIx32 "\n", status); put_module(B_BIOS_MODULE_NAME); return status; } bios_regs regs = {}; regs.eax = 0x4f15; regs.ebx = 0; // 0 = report DDC service regs.ecx = 0; regs.es = 0; regs.edi = 0; status = biosModule->interrupt(state, 0x10, ®s); if (status == B_OK) { // AH contains the error code, and AL determines whether or not the // function is supported. if (regs.eax != 0x4f) status = B_NOT_SUPPORTED; // Test if DDC is supported by the monitor. if ((regs.ebx & 3) == 0) status = B_NOT_SUPPORTED; } if (status == B_OK) { edid1_raw* edid = (edid1_raw*)biosModule->allocate_mem(state, sizeof(edid1_raw)); if (edid == NULL) { status = B_NO_MEMORY; goto out; } regs.eax = 0x4f15; regs.ebx = 1; // 1 = read EDID regs.ecx = 0; regs.edx = 0; regs.es = ADDRESS_SEGMENT(edid); regs.edi = ADDRESS_OFFSET(edid); status = biosModule->interrupt(state, 0x10, ®s); if (status == B_OK) { if (regs.eax != 0x4f) { status = B_NOT_SUPPORTED; } else { // Copy the EDID info to the caller's location, and compute the // checksum of the EDID info while copying. uint8 sum = 0; uint8 allOr = 0; uint8* dest = (uint8*)&edidRaw; uint8* src = (uint8*)edid; for (uint32 j = 0; j < sizeof(edidRaw); j++) { sum += *src; allOr |= *src; *dest++ = *src++; } if (allOr == 0) { TRACE("GetEdidFromBIOS(); EDID info contains only zeros\n"); status = B_ERROR; } else if (sum != 0) { TRACE("GetEdidFromBIOS(); Checksum error in EDID info\n"); status = B_ERROR; } } } } out: biosModule->finish(state); put_module(B_BIOS_MODULE_NAME); TRACE("GetEdidFromBIOS() status: 0x%" B_PRIx32 "\n", status); return status; }