diff --git a/build/neutron.img b/build/neutron.img index 0fda5ba..4ebf1c8 100644 Binary files a/build/neutron.img and b/build/neutron.img differ diff --git a/src/drivers/acpi.c b/src/drivers/acpi.c index 7ad542f..8aa42e9 100644 --- a/src/drivers/acpi.c +++ b/src/drivers/acpi.c @@ -1,11 +1,16 @@ //Neutron project //ACPI driver +#include +#include + #include "./acpi.h" #include "./pit.h" #include "../stdlib.h" #include "./gfx.h" +EFI_SYSTEM_TABLE* quark_get_efi_systable(void); + uint32_t acpi_smi_cmd; uint8_t acpi_en; uint8_t acpi_dis; @@ -21,7 +26,6 @@ uint8_t acpi_pm1_ctl_len; * Initializes ACPI */ uint32_t acpi_init(void){ - gfx_verbose_println("Initializing ACPI"); //Find the RSDP acpi_rsdp_t* rsdp = acpi_find_rsdp(); //If no RSDP was found, return @@ -31,7 +35,7 @@ uint32_t acpi_init(void){ } //Fetch RSDT from RSDP - acpi_rsdt_t* rsdt = (acpi_rsdt_t*)rsdp->rsdt_ptr; + acpi_rsdt_t* rsdt = (acpi_rsdt_t*)(uint64_t)rsdp->rsdt_ptr; //Check if it's valid if(!acpi_sdt_checksum(&rsdt->hdr)){ gfx_verbose_println("Error: RSDP is not valid"); @@ -93,6 +97,7 @@ uint32_t acpi_init(void){ gfx_verbose_println("Sending enable commands (this might take a while)"); //Enable ACPI outb(acpi_smi_cmd, acpi_en); + /* uint32_t start = pit_ticks(); while((pit_ticks() - start <= 1500) && ((inw(acpi_pm1a_ctl) & acpi_sci_en) == 0)); @@ -101,6 +106,7 @@ uint32_t acpi_init(void){ while((pit_ticks() - start <= 1500) && ((inw(acpi_pm1b_ctl) & acpi_sci_en) == 0)); } + */ gfx_verbose_println("ACPI successfully initialized"); @@ -147,14 +153,13 @@ uint8_t acpi_sdt_checksum(acpi_sdt_hdr_t* rsdt){ * Finds ACPI RSDT pointer (RSDP) in memory */ acpi_rsdp_t* acpi_find_rsdp(void){ - //Go through addresses 0xE0000 - 0xFFFFF - for(void* ptr = (void*)0xE0000; ptr <= (void*)0xFFFFF; ptr++){ - //Check the signature - //Note that we use memcmp as the signature is not zero-terminated - if(memcmp(((acpi_rsdp_t*)ptr)->signature, "RSD PTR ", 8) == 0) - return ptr; + //Search for the pointer in the UEFI config table + EFI_CONFIGURATION_TABLE* config_table = quark_get_efi_systable()->ConfigurationTable; + for(uint32_t i = 0; i < quark_get_efi_systable()->NumberOfTableEntries; i++){ + //If the GUID is ACPI 1.0 RSDP pointer GUID, return it + if(memcmp(&(config_table[i].VendorGuid), &(EFI_GUID)ACPI_TABLE_GUID, sizeof(EFI_GUID)) == 0) + return config_table[i].VendorTable; } - //Return null if no RSDP was found return NULL; } @@ -167,7 +172,7 @@ void* rsdt_find(acpi_rsdt_t* rsdt, char* table){ //Cycle through each entry for(uint32_t e = 0; e < rsdt_entries; e++){ //Get the SDT header - acpi_sdt_hdr_t* hdr = (acpi_sdt_hdr_t*)(rsdt->ptrs + e); + acpi_sdt_hdr_t* hdr = (acpi_sdt_hdr_t*)(uint64_t)(rsdt->ptrs + e); //Compare its signature with the desired one if(*(uint32_t*)(hdr) == *(uint32_t*)(table)) return (void*)hdr; diff --git a/src/drivers/acpi.h b/src/drivers/acpi.h index 089be7c..8aca17e 100644 --- a/src/drivers/acpi.h +++ b/src/drivers/acpi.h @@ -19,7 +19,7 @@ typedef struct { //ACPI RSDT table typedef struct { acpi_sdt_hdr_t hdr; - acpi_sdt_hdr_t** ptrs; + uint32_t ptrs; } __attribute__((packed)) acpi_rsdt_t; //ACPI RSDP structure @@ -28,7 +28,7 @@ typedef struct { uint8_t checksum; char oem[6]; uint8_t rev; - acpi_sdt_hdr_t* rsdt_ptr; + uint32_t rsdt_ptr; } __attribute__((packed)) acpi_rsdp_t; //ACPI Generic Address Structure (GAS) diff --git a/src/drivers/gfx.c b/src/drivers/gfx.c index cfb0204..9d39e76 100644 --- a/src/drivers/gfx.c +++ b/src/drivers/gfx.c @@ -55,7 +55,7 @@ void gfx_init(void){ //If it hadn't been found, print an error if(graphics_output == NULL){ quark_get_efi_systable()->ConOut->OutputString(quark_get_efi_systable()->ConOut, - (CHAR16*)L"Unable to find the graphics output protocol\r\n"); + (CHAR16*)L"Error: Unable to find the graphics output protocol\r\n"); while(1); } else { quark_get_efi_systable()->ConOut->OutputString(quark_get_efi_systable()->ConOut, @@ -68,7 +68,7 @@ void gfx_init(void){ res_y = graphics_output->Mode->Info->VerticalResolution; vbe_buffer = (color32_t*)graphics_output->Mode->FrameBufferBase; //Allocate the second buffer based on the screen size - //sec_buffer = (color32_t*)malloc(res_x * res_y * sizeof(color32_t)); + sec_buffer = (color32_t*)malloc(res_x * res_y * sizeof(color32_t)); } /* @@ -164,8 +164,8 @@ void gfx_choose_best(void){ //Do not exceed the display resolution uint32_t mode_res_x = mode_info->HorizontalResolution; uint32_t mode_res_y = mode_info->VerticalResolution; - if((mode_res_x > best_res_x || mode_res_y > best_res_y)/* && - mode_res_y <= mon_best_res_y && mode_res_x <= mon_best_res_x*/){ + if((mode_res_x > best_res_x || mode_res_y > best_res_y) && + mode_res_y <= mon_best_res_y && mode_res_x <= mon_best_res_x){ //Record the new best mode best_res_y = mode_res_y; best_res_x = mode_res_x; diff --git a/src/quark.c b/src/quark.c index c0f608e..f06e240 100644 --- a/src/quark.c +++ b/src/quark.c @@ -140,10 +140,10 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable //Initialize x87 FPU __asm__ volatile("finit"); //Do some initialization stuff - //dram_init(); + dram_init(); //Set verbose mode - quark_verbose = 0; + quark_verbose = 1; gfx_set_verbose(quark_verbose); //Initialize PICs @@ -191,7 +191,7 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable //Do some graphics-related initialization stuff gfx_init(); - gfx_set_buf(GFX_BUF_VBE); //Enable doublebuffering + gfx_set_buf(GFX_BUF_SEC); //Enable doublebuffering gfx_fill(COLOR32(255, 0, 0, 0)); gfx_set_font(font_neutral); @@ -206,8 +206,7 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable gfx_draw_xbm((p2d_t){.x = (gfx_res_x() - neutron_logo_width) / 2, .y = 50}, neutron_logo_bits, (p2d_t){.x = neutron_logo_width, .y = neutron_logo_height}, COLOR32(255, 255, 255, 255), COLOR32(255, 0, 0, 0)); //Print the boot process - quark_boot_status(">>> Loading... <<<", 0); - while(1); + quark_boot_status(">>> Loading <<<", 0); //Initialize PS/2 quark_boot_status(">>> Initializing PS/2 <<<", 15); @@ -225,7 +224,7 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable quark_boot_status(">>> Configuring GUI <<<", 90); gui_init(); //The loading process is done! - quark_boot_status(">>> Done! <<<", 100); + quark_boot_status(">>> Done <<<", 100); //Constantly update the GUI while(1){ @@ -239,7 +238,7 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable void quark_exc(void){ //Print some info unsigned int ip; - __asm__ volatile("mov %0, %%edx" : "=r" (ip)); + __asm__ volatile("mov %%edx, %0" : "=r" (ip)); gfx_panic(ip, QUARK_PANIC_CPUEXC_CODE); //Hang diff --git a/src/stdlib.c b/src/stdlib.c index 3bc9ce8..cb3e39a 100644 --- a/src/stdlib.c +++ b/src/stdlib.c @@ -1,25 +1,22 @@ //Neutron Project //C Standard Library +#include +#include + #include "./stdlib.h" #include "./drivers/gfx.h" +EFI_SYSTEM_TABLE* quark_get_efi_systable(void); + free_block_t* first_free_block; void* gen_free_base; void* gen_free_top; -uint32_t bad_ram_size = 0; +uint64_t bad_ram_size = 0; uint64_t total_ram_size = 0; -uint32_t usable_ram_size = 0; uint32_t stdlib_usable_ram(void){ - return usable_ram_size; -} - -/* - * Trigger bochs magic breakpoint - */ -volatile void breakpoint(){ - __asm__("xchgw %bx, %bx;"); + return total_ram_size; } /* @@ -29,57 +26,73 @@ void abort(){ while(1); } -/* - * Print a string through Bochs's E9 debug port if the port_e9_hack config setting is enabled - */ -void puts_e9(char* str){ - char c; - //Fetch the next character - while(c = *(str++)) - outb(0xE9, c); //Write it -} - /* * Initialize the dynamic memory allocator */ void dram_init(void){ - first_free_block = NULL; - //Parse the memory map - //It was put in memory as a result of a - // collaboration between Muon-2 and BIOS - uint32_t blk_type = 0; - volatile void* volatile block_base = (void*)(0x93C00); - //Keep track of the block with the most size - size_t largest_blk_size = 0; - void* largset_blk_ptr = NULL; - //Type=0 marks the end - while((blk_type = *(uint32_t*)(block_base + 16)) != 0){ - //Fetch block base - uint64_t base = *(uint64_t*)(block_base); - //Fetch block length - uint64_t size = *(uint64_t*)(block_base + 8); - //Record the total amount of available RAM - total_ram_size += size; - //Only record the block if it's marked as type 1 (usable RAM) - if(blk_type == 1 && size > 0){ - //Only record the block if it stretches over the fifth megabyte - // and its size is larger than the currently found one - if(size + base >= 5 * 1024 * 1024 && size > largest_blk_size){ - uint64_t shrink = (5 * 1024 * 1025) - base; - size -= shrink; - largest_blk_size = size; - largset_blk_ptr = (void*)base + shrink; - } - } else if(blk_type == 5){ //Type 5 means bad RAM (used to tell the user) - bad_ram_size += size; + //Get the memory map from EFI + EFI_MEMORY_DESCRIPTOR* buf; + uint64_t desc_size; + uint32_t desc_ver; + uint64_t size, map_key, mapping_size; + EFI_MEMORY_DESCRIPTOR* desc; + EFI_STATUS status; + uint32_t i = 0; + //Allocate some memory + size = sizeof(EFI_MEMORY_DESCRIPTOR) * 31; + mem_map_retry: + size += sizeof(EFI_MEMORY_DESCRIPTOR) * 31; + status = quark_get_efi_systable()->BootServices->AllocatePool(EfiLoaderData, size, (void*)&buf); + if(EFI_ERROR(status)){ + quark_get_efi_systable()->ConOut->OutputString(quark_get_efi_systable()->ConOut, + (CHAR16*)L"Failed to allocate memory for the memory map\r\n"); + while(1); + } + //Map the memory + status = quark_get_efi_systable()->BootServices->GetMemoryMap(&size, buf, &map_key, &desc_size, &desc_ver); + //Re-allocate the buffer with a different size if the current one isn't sufficient + if(EFI_ERROR(status)){ + if(status == EFI_BUFFER_TOO_SMALL){ + quark_get_efi_systable()->BootServices->FreePool(buf); + goto mem_map_retry; + } else { + quark_get_efi_systable()->ConOut->OutputString(quark_get_efi_systable()->ConOut, + (CHAR16*)L"Failed to get the memory map\r\n"); + while(1); + } + } + + desc = buf; + void* best_block_start = NULL; + uint64_t best_block_size = 0; + //Fetch the next descriptor + while((void*)desc < (void*)buf + size){ + mapping_size = desc->NumberOfPages * EFI_PAGE_SIZE; + + //If a new free memory block was found, record it + if(desc->Type == EfiConventionalMemory && mapping_size > best_block_size){ + best_block_size = mapping_size; + best_block_start = (void*)desc->PhysicalStart; } - //Move on to the next block - block_base += 24; + //Record bad RAM + else if(desc->Type == EfiUnusableMemory){ + bad_ram_size += mapping_size; + } + + desc = (void*)desc + desc_size; + i++; + } + + //Set up general free heap + gen_free_base = best_block_start; + gen_free_top = best_block_start + best_block_size; + total_ram_size += best_block_size; + + if(gen_free_top == NULL){ + quark_get_efi_systable()->ConOut->OutputString(quark_get_efi_systable()->ConOut, + (CHAR16*)L"No usable memory was found\r\n"); + while(1); } - //Save the information - gen_free_base = largset_blk_ptr; - gen_free_top = largset_blk_ptr + largest_blk_size; - usable_ram_size = largest_blk_size; } /* @@ -198,10 +211,13 @@ void* memset(void* dst, int ch, size_t size){ */ void* memcpy(void* destination, const void* source, size_t num){ //We can use the REP MOVx instruction to perform a blazing-fast memory-to-memory data transfer + //Q = 8 bytes at a time //D = 4 bytes at a time //W = 2 bytes at a time //B = 1 byte at a time - if(num % 4 == 0) + if(num % 8 == 0) + __asm__ volatile("rep movsq" : : "D" (destination), "S" (source), "c" (num / 4)); + else if(num % 4 == 0) __asm__ volatile("rep movsd" : : "D" (destination), "S" (source), "c" (num / 4)); else if(num % 2 == 0) __asm__ volatile("rep movsw" : : "D" (destination), "S" (source), "c" (num / 2));