diff --git a/build/neutron.img b/build/neutron.img index 8f621d2..0fda5ba 100644 Binary files a/build/neutron.img and b/build/neutron.img differ diff --git a/builder.py b/builder.py index c0acb98..e5b5c98 100644 --- a/builder.py +++ b/builder.py @@ -70,7 +70,7 @@ def get_c_files(dir_name): print('Bulding system image') print(' Creating image file') -os.system('dd if=/dev/zero of=build/neutron.img count=' + str(image_size_sectors) + ' > /dev/null') +os.system('dd if=/dev/zero of=build/neutron.img count=' + str(image_size_sectors) + ' > /dev/null 2>&1') os.system('mformat -i build/neutron.img -f ' + str(image_size_sectors / 2)) print(' Creating filesystem') os.system('mmd -i build/neutron.img ::/EFI') diff --git a/neutron.nbuild b/neutron.nbuild index d19a316..1fe87dc 100644 --- a/neutron.nbuild +++ b/neutron.nbuild @@ -1,7 +1,6 @@ .c src/quark.c src/isr_wrapper.s -src/a20.s src/stdlib.c src/gui/gui.c diff --git a/src/a20.s b/src/a20.s deleted file mode 100644 index cdaef73..0000000 --- a/src/a20.s +++ /dev/null @@ -1,41 +0,0 @@ -.globl enable_a20 -.align 4 -.intel_syntax noprefix - -enable_a20: ;//enables the A20 line, allowing us to use more than a megabyte of RAM - ;//input: none - ;//output: none - ;// - push ax ;//save AX - call a20_wait ;//wait for the keyboard controller to be ready - mov al, 0xAD ;//write 0xAD - out 0x64, al ;//to port 0x64 (keyboard controller) - call a20_wait ;// - mov al, 0xD0 ;// - out 0x64, al ;// - call a20_wait_2 ;// - in al, 0x60 ;//input from port 0x60 - push ax ;//save AX - call a20_wait ;// - mov al, 0xD1 ;// - out 0x64, al ;// - call a20_wait ;// - pop ax ;//restore AX - or al, 2 ;//set bit 1 of AL - out 0x60, al ;// - call a20_wait ;// - mov al, 0xAE ;// - out 0x64, al ;// - call a20_wait ;// - pop ax ;//restore AX - ret ;//return from subroutine -a20_wait: - in al, 0x64 ;// - test al, 2 ;// - jnz a20_wait ;// - ret ;// -a20_wait_2: - in al, 0x64 ;// - test al, 1 ;// - jz a20_wait_2 ;// - ret ;// diff --git a/src/drivers/gfx.c b/src/drivers/gfx.c index 8bd10b3..cfb0204 100644 --- a/src/drivers/gfx.c +++ b/src/drivers/gfx.c @@ -1,9 +1,15 @@ //Neutron Project //Kernel graphics driver +#include +#include +#include + #include "./gfx.h" #include "../stdlib.h" +EFI_SYSTEM_TABLE* quark_get_efi_systable(void); + //The video buffer pointers color32_t* vbe_buffer; color32_t* sec_buffer; @@ -16,6 +22,8 @@ const uint8_t* font; uint8_t buf_sel; //Is gfx_verbose_println() enabled or not? uint8_t verbose_enabled; +//Pointer to the graphics output protocol +EFI_GRAPHICS_OUTPUT_PROTOCOL* graphics_output; /* * Retrieve the horizontal resolution @@ -42,14 +50,131 @@ color32_t* gfx_buffer(void){ * Initialize the graphics driver */ void gfx_init(void){ - //Read the VBE buffer pointer (it was written in memory by the second stage loader) - vbe_buffer = (color32_t*)(*(uint64_t*)(0x8FC00UL)); - //Read the display resolution - uint32_t res = *(uint32_t*)(0x8FC04); - res_y = res & 0xFFFF; - res_x = (res >> 16) & 0xFFFF; + //Find the graphics output protocol + gfx_find_gop(); + //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"); + while(1); + } else { + quark_get_efi_systable()->ConOut->OutputString(quark_get_efi_systable()->ConOut, + (CHAR16*)L"GOP found\r\n"); + } + //Choose the best video mode + gfx_choose_best(); + //Retrieve its parameters + res_x = graphics_output->Mode->Info->HorizontalResolution; + 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)); +} + +/* + * Finds the EFI Graphics Output Protocol + */ +void gfx_find_gop(void){ + //Set the GOP to NULL + graphics_output = NULL; + //Handle the graphics output protocol + //Firstly, through the ConsoleOut handle + EFI_STATUS status; + status = quark_get_efi_systable()->BootServices->HandleProtocol(quark_get_efi_systable()->ConsoleOutHandle, + &((EFI_GUID)EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID), (void**)&graphics_output); + if(!EFI_ERROR(status)) + return; + //Then, directly + status = quark_get_efi_systable()->BootServices->LocateProtocol(&((EFI_GUID)EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID), + NULL, (void**)graphics_output); + if(!EFI_ERROR(status)) + return; + //Lastly, locate by handle + uint64_t handle_count = 0; + EFI_HANDLE* handle; + status = quark_get_efi_systable()->BootServices->LocateHandleBuffer(ByProtocol, + &((EFI_GUID)EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID), NULL, &handle_count, &handle); + if(EFI_ERROR(status)) + return; + status = quark_get_efi_systable()->BootServices->HandleProtocol(handle, + &((EFI_GUID)EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID), (void*)&graphics_output); +} + +/* + * Chooses the best available video mode + */ +void gfx_choose_best(void){ + EFI_STATUS status; + + quark_get_efi_systable()->ConOut->OutputString(quark_get_efi_systable()->ConOut, + (CHAR16*)L"Probing video mode list\r\n"); + + //Get the EDID + uint64_t handle_count = 0; + EFI_HANDLE* handle; + EFI_EDID_DISCOVERED_PROTOCOL* edid; + status = quark_get_efi_systable()->BootServices->LocateHandleBuffer(ByProtocol, + &((EFI_GUID)EFI_EDID_DISCOVERED_PROTOCOL_GUID), NULL, &handle_count, &handle); + if(EFI_ERROR(status)){ + quark_get_efi_systable()->ConOut->OutputString(quark_get_efi_systable()->ConOut, + (CHAR16*)L"Error: unable to find EDID protocol handle\r\n"); + while(1); + } + status = quark_get_efi_systable()->BootServices->HandleProtocol(handle, + &((EFI_GUID)EFI_EDID_DISCOVERED_PROTOCOL_GUID), (void*)&edid); + //Parse it + //To be specific, its detailed timing descriptors + uint32_t mon_best_res_x; + uint32_t mon_best_res_y; + //Go through advanced timing descriptors + for(uint32_t base = 54; base <= 108; base += 18){ + uint32_t mon_res_x = *(uint8_t* volatile)(edid->Edid + base + 2) << 4; + uint32_t mon_res_y = *(uint8_t* volatile)(edid->Edid + base + 5) << 4; + if(mon_res_x > mon_best_res_x || mon_res_y > mon_best_res_y){ + mon_best_res_x = mon_res_x; + mon_best_res_y = mon_res_y; + } + } + + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* mode_info; + uint64_t mode_info_size; + uint32_t best_res_x; + uint32_t best_res_y; + uint32_t best_mode_num; + //Go through each mode and query its properties + for(uint32_t i = 0; i < graphics_output->Mode->MaxMode; i++){ + //Query mode information + status = graphics_output->QueryMode(graphics_output, i, &mode_info_size, &mode_info); + //If we encounter an error + if(EFI_ERROR(status)){ + //If the error is "not started" + if(status == EFI_NOT_STARTED){ + //Start it and query mode info once again + status = graphics_output->SetMode(graphics_output, graphics_output->Mode->Mode); + status = graphics_output->QueryMode(graphics_output, i, &mode_info_size, &mode_info); + } else { + //In case of any other error, skip this mode + continue; + } + } + + //Only choose BGRReserved modes + if(mode_info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor){ + //Fetch mode resolution and compare it with the best one currently discovered + //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*/){ + //Record the new best mode + best_res_y = mode_res_y; + best_res_x = mode_res_x; + best_mode_num = i; + } + } + } + //Set the mode + graphics_output->SetMode(graphics_output, best_mode_num); } /* diff --git a/src/drivers/gfx.h b/src/drivers/gfx.h index 4e514c4..4dda10e 100644 --- a/src/drivers/gfx.h +++ b/src/drivers/gfx.h @@ -25,6 +25,8 @@ uint32_t gfx_res_y(void); color32_t* gfx_buffer(void); void gfx_init(void); +void gfx_find_gop(void); +void gfx_choose_best(void); void gfx_flip(void); void gfx_set_font(const unsigned char* fnt); void gfx_set_buf(unsigned char buf); diff --git a/src/quark.c b/src/quark.c index c0ad2d1..c0f608e 100644 --- a/src/quark.c +++ b/src/quark.c @@ -50,6 +50,13 @@ uint8_t quark_verbose; //Pointer to the EFI system table EFI_SYSTEM_TABLE* quark_efi_systable; +/* + * Gets the EFI system table + */ +EFI_SYSTEM_TABLE* quark_get_efi_systable(void){ + return quark_efi_systable; +} + /* * This function is called whenever the user chooses the system color */ @@ -110,7 +117,7 @@ void quark_boot_status(char* str, uint32_t progress){ (p2d_t){.x = gfx_res_x() / 3, .y = 2}, COLOR32(255, 64, 64, 64)); gfx_draw_filled_rect((p2d_t){.x = gfx_res_x() / 3, .y = gfx_res_y() * 3 / 4}, (p2d_t){.x = gfx_res_x() / 300 * progress, .y = 2}, COLOR32(255, 255, 255, 255)); - gfx_flip(); + //gfx_flip(); } else { //If we are, draw print the string using verbose mode gfx_verbose_println(str); @@ -121,28 +128,26 @@ void quark_boot_status(char* str, uint32_t progress){ * The entry point for the kernel */ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable){ - //Disable the watchdog timer - SystemTable->BootServices->SetWatchdogTimer(0, 0, 0, NULL); //Save the system table pointer quark_efi_systable = SystemTable; + //Disable the watchdog timer + quark_efi_systable->BootServices->SetWatchdogTimer(0, 0, 0, NULL); //Print the boot string - SystemTable->ConOut->OutputString(SystemTable->ConOut, (CHAR16*)L"Neutron (UEFI version) is starting up"); - while(1); + quark_efi_systable->ConOut->OutputString(SystemTable->ConOut, (CHAR16*)L"Neutron (UEFI version) is starting up\r\n"); //Disable interrupts __asm__ volatile("cli"); //Initialize x87 FPU __asm__ volatile("finit"); //Do some initialization stuff - enable_a20(); - dram_init(); + //dram_init(); //Set verbose mode - quark_verbose = *(uint8_t*)(0x8FC10); + quark_verbose = 0; gfx_set_verbose(quark_verbose); //Initialize PICs - pic_init(32, 40); //Remap IRQs + /*pic_init(32, 40); //Remap IRQs //Set up IDT struct idt_entry* idt = (struct idt_entry*)malloc(256 * sizeof(struct idt_entry)); //Set every exception IDT entry using the same pattern @@ -182,11 +187,11 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable //Enable interrupts __asm__ volatile("sti"); //Enable non-maskable interrupts - outb(0x70, 0); + outb(0x70, 0);*/ //Do some graphics-related initialization stuff gfx_init(); - gfx_set_buf(GFX_BUF_SEC); //Enable doublebuffering + gfx_set_buf(GFX_BUF_VBE); //Enable doublebuffering gfx_fill(COLOR32(255, 0, 0, 0)); gfx_set_font(font_neutral); @@ -202,6 +207,7 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable (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); //Initialize PS/2 quark_boot_status(">>> Initializing PS/2 <<<", 15); diff --git a/src/test.c b/src/test.c deleted file mode 100644 index 9925fea..0000000 --- a/src/test.c +++ /dev/null @@ -1,7 +0,0 @@ -#include -#include - -EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable){ - SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello, UEFI!\n\r"); - while(1); -} \ No newline at end of file