diff --git a/docs/README.md b/docs/README.md index 492ad39..15413d8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -183,7 +183,7 @@ The Pure64 information table is located at `0x0000000000005000` and ends at `0x0 Memory AddressVariable SizeNameDescription 0x500064-bitACPIAddress of the ACPI tables 0x500832-bitCPU_BSP_IDAPIC ID of the BSP -0x501016-bitCPU_SPEEDSpeed of the CPUs in MegaHertz (MHz) +0x500C - 0x5011  For future use 0x501216-bitCPU_CORES_ACTIVEThe number of CPU cores that were activated in the system 0x501416-bitCPU_CORES_DETECTThe number of CPU cores that were detected in the system 0x50168-bitCPU_MEM_PHYSICALThe number of bits that are valid for a physical address @@ -200,6 +200,8 @@ The Pure64 information table is located at `0x0000000000005000` and ends at `0x0 0x504C16-bitHPET Counter MinumumMinimum Counter for the High Precision Event Timer 0x504E8-bitHPET CountersNumber of Counter in the High Precision Event Timer 0x504F  For future use +0x505064-bitT0RDTSC at Pure64 start +0x505864-bitT1RDTSC at Pure64 end 0x506064-bitLAPICLocal APIC address 0x5068 - 0x507F  For future use 0x508064-bitVIDEO_BASEBase memory for video (if graphics mode set) diff --git a/src/boot/bios-pxe.asm b/src/boot/bios-pxe.asm index f695018..184e5b9 100644 --- a/src/boot/bios-pxe.asm +++ b/src/boot/bios-pxe.asm @@ -121,7 +121,7 @@ check_A20: cmp ax, 0x004F ; Return value in AX should equal 0x004F if command supported and successful jne halt - cmp byte [VBEModeInfoBlock.BitsPerPixel], 24 ; Make sure this matches the number of bits for the mode! + cmp byte [VBEModeInfoBlock.BitsPerPixel], 32 ; Make sure this matches the number of bits for the mode! jne halt ; If set bit mode was unsuccessful then bail out or bx, 0x4000 ; Use linear/flat frame buffer model (set bit 14) mov ax, 0x4F02 ; SET SuperVGA VIDEO MODE - http://www.ctyme.com/intr/rb-0275.htm diff --git a/src/boot/uefi.asm b/src/boot/uefi.asm index 9588654..0a8e366 100644 --- a/src/boot/uefi.asm +++ b/src/boot/uefi.asm @@ -139,7 +139,7 @@ EntryPoint: ; Find the address of the ACPI data from the UEFI configuration table mov rax, [EFI_SYSTEM_TABLE] mov rcx, [rax + EFI_SYSTEM_TABLE_NUMBEROFENTRIES] - shl rcx, 3 ; Quick multiply by 4 + shl rcx, 3 ; Quick multiply by 8 mov rsi, [CONFIG] nextentry: dec rcx @@ -367,6 +367,11 @@ get_memmap: ; Stop interrupts cli + ; Get T0 timestamp + rdtsc ; Read the timestamp counter into EDX:EAX + mov [0x5FFC], edx + mov [0x5FF8], eax + ; Copy Pure64 to the correct memory address mov rsi, PAYLOAD mov rdi, 0x8000 diff --git a/src/init/acpi.asm b/src/init/acpi.asm index 301957d..a16e920 100644 --- a/src/init/acpi.asm +++ b/src/init/acpi.asm @@ -119,17 +119,13 @@ nextACPITable: pop rsi ; Pop an Entry address from the stack lodsd add ecx, 1 - mov ebx, 'APIC' ; Signature for the Multiple APIC Description Table - cmp eax, ebx + cmp eax, 'APIC' ; Signature for the Multiple APIC Description Table je foundAPICTable - mov ebx, 'HPET' ; Signature for the HPET Description Table - cmp eax, ebx + cmp eax, 'HPET' ; Signature for the HPET Description Table je foundHPETTable - mov ebx, 'MCFG' ; Signature for the PCIe Enhanced Configuration Mechanism - cmp eax, ebx + cmp eax, 'MCFG' ; Signature for the PCIe Enhanced Configuration Mechanism je foundMCFGTable - mov ebx, 'FACP' ; Signature for the Fixed ACPI Description Table - cmp eax, ebx + cmp eax, 'FACP' ; Signature for the Fixed ACPI Description Table je foundFADTTable jmp nextACPITable @@ -320,28 +316,38 @@ parseAPICTable_done: ; ----------------------------------------------------------------------------- ; High Precision Event Timer (HPET) +; +; ACPI Memory Layout +; 4 byte - Signature +; 4 byte - Length of HPET in bytes +; 1 byte - Revision +; 1 byte - Checksum +; 6 byte - OEMID +; 8 byte - OEM Table ID +; 4 byte - OEM Revision +; 4 byte - Creator ID +; 4 byte - Creator Revision +; 1 byte - Hardware Revision ID +; 1 byte - # of Comparators (5:0), COUNT_SIZE_CAP (6), Legacy IRQ (7) +; 2 byte - PCI Vendor ID +; 1 byte - Address Space ID +; 1 byte - Register bit width +; 1 byte - Register bit offset +; 1 byte - Reserved +; 8 byte - Base Address Value +; 1 byte - HPET Number +; 2 byte - Main Counter Minimum +; 1 byte - Page Protection +; ; http://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf parseHPETTable: - lodsd ; Length of HPET in bytes - lodsb ; Revision - lodsb ; Checksum - lodsd ; OEMID (First 4 bytes) - lodsw ; OEMID (Last 2 bytes) - lodsq ; OEM Table ID - lodsd ; OEM Revision - lodsd ; Creator ID - lodsd ; Creator Revision - - lodsb ; Hardware Revision ID - lodsb ; # of Comparators (5:0), COUNT_SIZE_CAP (6), Legacy IRQ (7) - lodsw ; PCI Vendor ID - lodsd ; Generic Address Structure - lodsq ; Base Address Value + ; At this point RSI points to the Length of HPET in bytes + mov ebx, [rsi] ; Should be 0x38 + mov rax, [rsi + 40] ; Base Address Value mov [p_HPET_Address], rax ; Save the Address of the HPET - lodsb ; HPET Number - lodsw ; Main Counter Minimum + mov ax, [rsi + 49] ; Main Counter Minimum mov [p_HPET_CounterMin], ax ; Save the Counter Minimum - lodsb ; Page Protection And OEM Attribute + add rsi, rbx ; Add the table length to RSI ret ; ----------------------------------------------------------------------------- diff --git a/src/init/serial.asm b/src/init/serial.asm index b784e2a..c4c674d 100644 --- a/src/init/serial.asm +++ b/src/init/serial.asm @@ -14,7 +14,7 @@ init_serial: ; Enable divisor register for setting baud rate mov dx, COM_PORT_LINE_CONTROL - mov dl, 0x80 ; DLB (7 set) + mov al, 0x80 ; DLB (7 set) out dx, al ; Send the divisor (baud rate will be 115200 / divisor) @@ -27,7 +27,7 @@ init_serial: ; Disable divisor register and set values mov dx, COM_PORT_LINE_CONTROL - mov al, 00000111b ; 8 data bits (0-1 set), one stop bit (2 set), no parity (3-5 clear), DLB (7 clear) + mov al, 00000011b ; 8 data bits (0-1 set), one stop bit (2 clear), no parity (3-5 clear), DLB (7 clear) out dx, al ; Disable modem control diff --git a/src/init/smp.asm b/src/init/smp.asm index 1903817..7d4d511 100644 --- a/src/init/smp.asm +++ b/src/init/smp.asm @@ -9,7 +9,13 @@ init_smp: ; Check if we want the AP's to be enabled.. if not then skip to end cmp byte [cfg_smpinit], 1 ; Check if SMP should be enabled - jne noMP ; If not then skip SMP init + jne init_smp_done ; If not then skip SMP init + + ; Check if multiple CPUs were detected via the ACPI tables + xor ecx, ecx + mov cx, [p_cpu_detected] + cmp cx, 1 + je init_smp_done ; Only 1 CPU detected, skip SMP init mov edx, [p_BSP] ; Get the BSP APIC ID mov esi, IM_DetectedCoreIDs ; List of 32-bit APIC IDs @@ -60,8 +66,8 @@ smp_send_INIT_skipcore: smp_send_INIT_done: - ; Wait 500 microseconds - mov eax, 500 + ; Wait + mov eax, 500 ; 500 microseconds (0.5ms) call timer_delay mov esi, IM_DetectedCoreIDs @@ -97,9 +103,9 @@ smp_send_SIPI_verify: smp_send_SIPI_x2APIC: ; Send 'Startup' IPI to destination using vector 0x08 to specify entry-point is at the memory-address 0x00008000 push rcx - mov ecx, APIC_ICR ; Interrupt Command Register (ICR); bits 63-0 + mov ecx, APIC_ICR ; Interrupt Command Register (ICR); bits 63-0 shl rax, 32 - mov ax, 0x4608 ; Vector 0x08 + mov ax, 0x4608 ; Vector 0x08 call apic_write pop rcx @@ -111,28 +117,11 @@ smp_send_SIPI_skipcore: smp_send_SIPI_done: - ; Wait 10000 microseconds for the AP's to finish - mov eax, 10000 - call timer_delay - -noMP: - - ; Calculate base speed of CPU - cpuid - xor edx, edx - xor eax, eax - rdtsc - push rax - mov rax, 1024 + ; Wait for the AP's to finish + mov eax, 10000 ; 10000 microseconds (10ms) call timer_delay - rdtsc - pop rdx - sub rax, rdx - xor edx, edx - mov rcx, 1024 - div rcx - mov [p_cpu_speed], ax +init_smp_done: ret diff --git a/src/init/timer.asm b/src/init/timer.asm index 0b87585..d629359 100644 --- a/src/init/timer.asm +++ b/src/init/timer.asm @@ -65,10 +65,16 @@ init_timer_hpet: ; Calculate the HPET frequency mov rbx, rax ; Move Counter Clock Period to RBX xor rdx, rdx - mov rax, 1000000000000000 ; femotoseconds per second - div rbx ; RDX:RAX / RBX + mov rax, 1000000000000000 ; femtoseconds per second + div rbx ; RDX:RAX / RBX = frequency in Hz mov [p_HPET_Frequency], eax ; Save the HPET frequency + ; Precompute cycles per microsecond (freq_Hz / 1,000,000) + xor rdx, rdx + mov ecx, 1000000 + div rcx + mov [p_HPET_CyclesPerUs], rax + ; Disable interrupts on all timers xor ebx, ebx mov bl, [p_HPET_Timers] @@ -140,24 +146,17 @@ hpet_delay: push rax mov rbx, rax ; Save delay to RBX - xor edx, edx - xor ecx, ecx - call hpet_read ; Get HPET General Capabilities and ID Register - shr rax, 32 - mov rcx, rax ; RCX = RAX >> 32 (timer period in femtoseconds) - mov rax, 1000000000 - div rcx ; Divide 1000000000 (RDX:RAX) / RCX (converting from period in femtoseconds to frequency in MHz) - mul rbx ; RAX *= RBX, should get number of HPET cycles to wait, save result in RBX + mov rax, [p_HPET_CyclesPerUs] ; Use precomputed cycles per microsecond + mul rbx ; RAX = cycles to wait mov rbx, rax mov ecx, HPET_MAIN_COUNTER call hpet_read ; Get HPET counter in RAX - add rbx, rax ; RBX += RAX Until when to wait + add rbx, rax ; RBX = target counter value hpet_delay_loop: ; Stay in this loop until the HPET timer reaches the expected value - mov ecx, HPET_MAIN_COUNTER + pause call hpet_read ; Get HPET counter in RAX - cmp rax, rbx ; If RAX >= RBX then jump to end, otherwise jump to loop - jae hpet_delay_end - jmp hpet_delay_loop + cmp rax, rbx + jb hpet_delay_loop hpet_delay_end: pop rax @@ -291,6 +290,7 @@ kvm_delay: call kvm_get_usec add rbx, rax ; Add elapsed time kvm_delay_wait: + pause call kvm_get_usec cmp rax, rbx jb kvm_delay_wait diff --git a/src/interrupt.asm b/src/interrupt.asm index 0897f80..dda8092 100644 --- a/src/interrupt.asm +++ b/src/interrupt.asm @@ -159,27 +159,5 @@ exception_gate_main_hang: ; ----------------------------------------------------------------------------- -; ----------------------------------------------------------------------------- -; create_gate -; rax = address of handler -; rdi = gate # to configure -create_gate: - push rdi - push rax - - shl rdi, 4 ; quickly multiply rdi by 16 - stosw ; store the low word (15:0) - shr rax, 16 - add rdi, 4 ; skip the gate marker - stosw ; store the high word (31:16) - shr rax, 16 - stosd ; store the high dword (63:32) - - pop rax - pop rdi - ret -; ----------------------------------------------------------------------------- - - ; ============================================================================= ; EOF diff --git a/src/pure64.asm b/src/pure64.asm index 655bf0c..24cbeaa 100644 --- a/src/pure64.asm +++ b/src/pure64.asm @@ -64,6 +64,10 @@ bootmode: %ifdef BIOS mov [p_BootDisk], bh ; Save disk from where system was booted from + rdtsc ; Read the timestamp counter into EDX:EAX + mov [0x5FFC], edx + mov [0x5FF8], eax + mov eax, 16 ; Set the correct segment registers mov ds, ax mov es, ax @@ -145,8 +149,7 @@ pdpte_low_32: pop eax add eax, 0x00001000 ; 4KiB later (512 records x 8 bytes) dec ecx - cmp ecx, 0 - jne pdpte_low_32 + jnz pdpte_low_32 ; Create the temporary low Page-Directory Entries (PDE). ; A single PDE can map 2MiB of RAM @@ -211,6 +214,11 @@ start64: mov ax, 0x03 ; Set flags for legacy ports (in case of no ACPI data) mov [p_IAPC_BOOT_ARCH], ax + ; Save EBDA segment from BDA (BIOS Data Area) + movzx esi, word [0x040E] ; EBDA segment + shl esi, 4 ; Convert to proper address + mov [p_EBDA], rsi + ; Mask all PIC interrupts mov al, 0xFF out 0x21, al @@ -435,41 +443,33 @@ clearcs64: ; Build the IDT xor edi, edi ; create the 64-bit IDT (at linear address 0x0000000000000000) + ; exception_gate and interrupt_gate are within the Pure64 binary (0x8000-0x97FF), + ; so bits 31:16 and 63:32 of their addresses are always 0. mov ecx, 32 make_exception_gates: ; make gates for exception handlers mov eax, exception_gate - push rax ; save the exception gate to the stack for later use stosw ; store the low word (15:0) of the address mov ax, SYS64_CODE_SEL stosw ; store the segment selector mov ax, 0x8E00 stosw ; store exception gate marker - pop rax ; get the exception gate back - shr rax, 16 - stosw ; store the high word (31:16) of the address - shr rax, 16 - stosd ; store the extra high dword (63:32) of the address. xor eax, eax - stosd ; reserved + stosw ; store the high word (31:16) of the address (always 0) + stosq ; store bits 63:32 of address + reserved (always 0) dec ecx jnz make_exception_gates mov ecx, 256-32 make_interrupt_gates: ; make gates for the other interrupts mov eax, interrupt_gate - push rax ; save the interrupt gate to the stack for later use stosw ; store the low word (15:0) of the address mov ax, SYS64_CODE_SEL stosw ; store the segment selector mov ax, 0x8F00 stosw ; store interrupt gate marker - pop rax ; get the interrupt gate back - shr rax, 16 - stosw ; store the high word (31:16) of the address - shr rax, 16 - stosd ; store the extra high dword (63:32) of the address. xor eax, eax - stosd ; reserved + stosw ; store the high word (31:16) of the address (always 0) + stosq ; store bits 63:32 of address + reserved (always 0) dec ecx jnz make_interrupt_gates @@ -807,9 +807,7 @@ pde_end: mov eax, [p_BSP] stosd - mov di, 0x5010 - mov ax, [p_cpu_speed] - stosw + mov di, 0x5012 mov ax, [p_cpu_activated] stosw mov ax, [p_cpu_detected] @@ -850,6 +848,10 @@ no_address_size: mov al, [p_HPET_Timers] stosb + mov esi, 0x5FF8 ; Address of T0 + mov di, 0x5050 + movsq + mov di, 0x5060 mov rax, [p_LocalAPICAddress] stosq @@ -958,6 +960,12 @@ lfb_wc_end: call read_floppy ; Then load whole floppy at memory %endif + mov edi, 0x5058 + rdtsc ; Gather T1 to EDX:EAX + shl rdx, 32 ; Shift low bits to high + or rax, rdx + stosq + ; Clear all registers (skip the stack pointer) clear_regs: xor eax, eax ; These 32-bit calls also clear the upper bits of the 64-bit registers diff --git a/src/sysvar.asm b/src/sysvar.asm index af8779a..eb46fa2 100644 --- a/src/sysvar.asm +++ b/src/sysvar.asm @@ -38,9 +38,11 @@ VBEModeInfoBlock: equ 0x0000000000005F00 ; 256 bytes ; DQ - Starting at offset 0, increments by 0x8 p_ACPITableAddress: equ SystemVariables + 0x00 +p_HPET_CyclesPerUs: equ SystemVariables + 0x08 ; Precomputed HPET cycles per microsecond p_LocalAPICAddress: equ SystemVariables + 0x10 p_HPET_Address: equ SystemVariables + 0x28 sys_timer: equ SystemVariables + 0x30 +p_EBDA: equ SystemVariables + 0x38 ; DD - Starting at offset 0x80, increments by 4 p_BSP: equ SystemVariables + 0x80