mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-06-02 17:58:00 +00:00
Removal of NASM support and migration of .asm files to .s
This commit is contained in:
parent
0dc4593625
commit
ef3b761d4f
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
@ -9,6 +9,6 @@
|
|||||||
"ibm.output-colorizer",
|
"ibm.output-colorizer",
|
||||||
"wayou.vscode-todo-highlight",
|
"wayou.vscode-todo-highlight",
|
||||||
"gruntfuggly.todo-tree",
|
"gruntfuggly.todo-tree",
|
||||||
"13xforever.language-x86-64-assembly"
|
"maziac.asm-code-lens"
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -1,22 +0,0 @@
|
|||||||
; This file is part of Fennix Kernel.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
; modify it under the terms of the GNU General Public License as
|
|
||||||
; published by the Free Software Foundation, either version 3 of
|
|
||||||
; the License, or (at your option) any later version.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
; GNU General Public License for more details.
|
|
||||||
;
|
|
||||||
; You should have received a copy of the GNU General Public License
|
|
||||||
; along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
[bits 32]
|
|
||||||
|
|
||||||
section .bootstrap.text
|
|
||||||
|
|
||||||
global Multiboot1_start
|
|
||||||
Multiboot1_start:
|
|
||||||
int3
|
|
@ -15,6 +15,9 @@
|
|||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.intel_syntax noprefix
|
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
|
.section .bootstrap.text
|
||||||
|
|
||||||
|
.global Multiboot1_start
|
||||||
|
Multiboot1_start:
|
||||||
|
jmp .
|
@ -25,7 +25,7 @@ DetectCPUID:
|
|||||||
pushfd
|
pushfd
|
||||||
pop eax
|
pop eax
|
||||||
mov ecx, eax
|
mov ecx, eax
|
||||||
xor eax, 1 << 21
|
xor eax, 0x200000
|
||||||
push eax
|
push eax
|
||||||
popfd
|
popfd
|
||||||
pushfd
|
pushfd
|
||||||
@ -34,7 +34,7 @@ DetectCPUID:
|
|||||||
popfd
|
popfd
|
||||||
xor eax, ecx
|
xor eax, ecx
|
||||||
jz .NoCPUID
|
jz .NoCPUID
|
||||||
mov eax, 1
|
mov eax, 0x1
|
||||||
ret
|
ret
|
||||||
.NoCPUID:
|
.NoCPUID:
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
@ -48,9 +48,9 @@ Detect64Bit:
|
|||||||
jb .NoLongMode
|
jb .NoLongMode
|
||||||
mov eax, 0x80000001
|
mov eax, 0x80000001
|
||||||
cpuid
|
cpuid
|
||||||
test edx, 1 << 29
|
test edx, 0x20000000
|
||||||
jz .NoLongMode
|
jz .NoLongMode
|
||||||
mov eax, 1
|
mov eax, 0x1
|
||||||
ret
|
ret
|
||||||
.NoLongMode:
|
.NoLongMode:
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
@ -58,11 +58,11 @@ Detect64Bit:
|
|||||||
|
|
||||||
.global DetectPSE
|
.global DetectPSE
|
||||||
DetectPSE:
|
DetectPSE:
|
||||||
mov eax, 0x00000001
|
mov eax, 0x00000001
|
||||||
cpuid
|
cpuid
|
||||||
test edx, 0x00000008
|
test edx, 0x00000008
|
||||||
jz .NoPSE
|
jz .NoPSE
|
||||||
mov eax, 1
|
mov eax, 0x1
|
||||||
ret
|
ret
|
||||||
.NoPSE:
|
.NoPSE:
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
@ -70,11 +70,11 @@ DetectPSE:
|
|||||||
|
|
||||||
.global DetectPAE
|
.global DetectPAE
|
||||||
DetectPAE:
|
DetectPAE:
|
||||||
mov eax, 0x00000001
|
mov eax, 0x00000001
|
||||||
cpuid
|
cpuid
|
||||||
test edx, 0x00000040
|
test edx, 0x00000040
|
||||||
jz .NoPAE
|
jz .NoPAE
|
||||||
mov eax, 1
|
mov eax, 0x1
|
||||||
ret
|
ret
|
||||||
.NoPAE:
|
.NoPAE:
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.intel_syntax noprefix
|
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
.section .bootstrap.text
|
.section .bootstrap.text
|
||||||
|
|
||||||
@ -48,19 +46,19 @@ GDT32:
|
|||||||
.word 0x4092
|
.word 0x4092
|
||||||
.byte 0x00
|
.byte 0x00
|
||||||
GDT32_END:
|
GDT32_END:
|
||||||
|
nop
|
||||||
|
|
||||||
.global LoadGDT32
|
.global LoadGDT32
|
||||||
LoadGDT32:
|
LoadGDT32:
|
||||||
lgdt [gdtr]
|
lgdt [gdtr]
|
||||||
|
ljmp $0x8, $ActivateGDT
|
||||||
|
|
||||||
jmp 0x8:ActivateGDT
|
ActivateGDT:
|
||||||
ActivateGDT:
|
mov $0x10, %cx
|
||||||
mov cx, 0x10
|
mov %cx, %ss
|
||||||
mov ss, cx
|
mov %cx, %ds
|
||||||
mov ds, cx
|
mov %cx, %es
|
||||||
mov es, cx
|
mov %cx, %fs
|
||||||
mov fs, cx
|
mov $0x18, %cx
|
||||||
mov cx, 0x18
|
mov %cx, %gs
|
||||||
mov gs, cx
|
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
@ -15,49 +15,48 @@
|
|||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.intel_syntax noprefix
|
|
||||||
|
|
||||||
.code64
|
.code64
|
||||||
.section .bootstrap.data
|
.section .bootstrap.data
|
||||||
|
|
||||||
/* Access bits */
|
/* Access bits */
|
||||||
.equ A, 1 << 0
|
A = 0x1
|
||||||
.equ RW, 1 << 1
|
RW = 0x2
|
||||||
.equ DC, 1 << 2
|
DC = 0x4
|
||||||
.equ E, 1 << 3
|
E = 0x8
|
||||||
.equ S, 1 << 4
|
S = 0x10
|
||||||
.equ DPL0, 0 << 5
|
DPL0 = 0x0 /* 0 << 5 ???? */
|
||||||
.equ DPL1, 1 << 5
|
DPL1 = 0x20
|
||||||
.equ P, 1 << 7
|
P = 0x80
|
||||||
|
|
||||||
/* Flags bits */
|
/* Flags bits */
|
||||||
.equ LONG_MODE, 1 << 5
|
LONG_MODE = 0x20
|
||||||
.equ SZ_32, 1 << 6
|
SZ_32 = 0x40
|
||||||
.equ GRAN_4K, 1 << 7
|
GRAN_4K = 0x80
|
||||||
|
|
||||||
.global GDT64.Null
|
.global GDT64.Null
|
||||||
.global GDT64.Code
|
.global GDT64.Code
|
||||||
.global GDT64.Data
|
.global GDT64.Data
|
||||||
.global GDT64.Tss
|
.global GDT64.Tss
|
||||||
.global GDT64.Ptr
|
.global GDT64.Ptr
|
||||||
|
|
||||||
GDT64:
|
GDT64:
|
||||||
.equ GDT64.Null, $ - GDT64
|
GDT64.Null = . - GDT64
|
||||||
.quad 0
|
.quad 0
|
||||||
.equ GDT64.Code, $ - GDT64
|
GDT64.Code = . - GDT64
|
||||||
.long 0xFFFF
|
.long 0xFFFF
|
||||||
.byte 0
|
.byte 0
|
||||||
.byte P | S | E | RW
|
.byte P | S | E | RW
|
||||||
.byte GRAN_4K | LONG_MODE | 0xF
|
.byte GRAN_4K | LONG_MODE | 0xF
|
||||||
.byte 0
|
.byte 0
|
||||||
.equ GDT64.Data, $ - GDT64
|
GDT64.Data = . - GDT64
|
||||||
.long 0xFFFF
|
.long 0xFFFF
|
||||||
.byte 0
|
.byte 0
|
||||||
.byte P | S | RW
|
.byte P | S | RW
|
||||||
.byte GRAN_4K | SZ_32 | 0xF
|
.byte GRAN_4K | SZ_32 | 0xF
|
||||||
.byte 0
|
.byte 0
|
||||||
.equ GDT64.Tss, $ - GDT64
|
GDT64.Tss = . - GDT64
|
||||||
.long 0x00000068
|
.long 0x00000068
|
||||||
.long 0x00CF8900
|
.long 0x00CF8900
|
||||||
GDT64.Ptr:
|
GDT64.Ptr:
|
||||||
.word $ - GDT64 - 1
|
.word . - GDT64 - 1
|
||||||
.quad GDT64
|
.quad GDT64
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.intel_syntax noprefix
|
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
.extern Multiboot2_start
|
.extern Multiboot2_start
|
||||||
|
|
||||||
@ -91,3 +89,4 @@ EndTag_Start:
|
|||||||
.long EndTag_End - EndTag_Start
|
.long EndTag_End - EndTag_Start
|
||||||
EndTag_End:
|
EndTag_End:
|
||||||
MULTIBOOT2_HEADER_END:
|
MULTIBOOT2_HEADER_END:
|
||||||
|
nop
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
; This file is part of Fennix Kernel.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
; modify it under the terms of the GNU General Public License as
|
|
||||||
; published by the Free Software Foundation, either version 3 of
|
|
||||||
; the License, or (at your option) any later version.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
; GNU General Public License for more details.
|
|
||||||
;
|
|
||||||
; You should have received a copy of the GNU General Public License
|
|
||||||
; along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
[bits 32]
|
|
||||||
|
|
||||||
PAGE_TABLE_SIZE equ 0x4
|
|
||||||
|
|
||||||
section .bootstrap.data
|
|
||||||
align 0x1000
|
|
||||||
global BootPageTable
|
|
||||||
BootPageTable:
|
|
||||||
times (0x10000) dq 0 ; 0x4000 bytes will be used in UpdatePageTable
|
|
||||||
|
|
||||||
section .bootstrap.text
|
|
||||||
global UpdatePageTable
|
|
||||||
UpdatePageTable:
|
|
||||||
mov edi, (BootPageTable + 0x0000) ; First PML4E
|
|
||||||
mov eax, (BootPageTable + 0x1000) ; First PDPTE
|
|
||||||
or eax, 11b ; Bitwise OR on rax (PDPTE) with 11b (Present, Write)
|
|
||||||
mov dword [edi], eax ; Write 11b to PML4E
|
|
||||||
|
|
||||||
mov edi, (BootPageTable + 0x1000) ; First PDPTE
|
|
||||||
mov eax, (BootPageTable + 0x2000) ; First PDE
|
|
||||||
or eax, 11b ; Bitwise OR on rax (PDE) with 11b (Present, Write)
|
|
||||||
|
|
||||||
mov ecx, PAGE_TABLE_SIZE ; For loop instruction
|
|
||||||
mov ebx, 0x0 ; Value to store in the next 4 bytes
|
|
||||||
.FillPageTableLevel3:
|
|
||||||
mov dword [edi], eax ; Store modified PDE in PDPTE
|
|
||||||
mov dword [edi + 4], ebx ; Store the rbx value in the next 4 bytes
|
|
||||||
add eax, 0x1000 ; Increment (page size)
|
|
||||||
adc ebx, 0 ; Add 0 to carry flag
|
|
||||||
add edi, 8 ; Add 8 to rdi (next PDE)
|
|
||||||
loop .FillPageTableLevel3 ; Loop until rcx is 0
|
|
||||||
|
|
||||||
mov edi, (BootPageTable + 0x2000) ; First PDE
|
|
||||||
mov eax, 10000011b ; Present, Write, Large Page
|
|
||||||
|
|
||||||
mov ecx, (512 * PAGE_TABLE_SIZE) ; For loop instruction
|
|
||||||
mov ebx, 0x0 ; Value to store in the next 4 bytes
|
|
||||||
.FillPageTableLevel2:
|
|
||||||
mov dword [edi], eax ; Store modified PDE in PDPTE
|
|
||||||
mov dword [edi + 4], ebx ; Store the rbx value in the next 4 bytes
|
|
||||||
add eax, 1 << 21 ; Increment (page size)
|
|
||||||
adc ebx, 0 ; Add 0 (carry flag) to rbx to increment if there was a carry
|
|
||||||
add edi, 8 ; Add 8 to rdi (next PDE)
|
|
||||||
loop .FillPageTableLevel2 ; Loop until rcx is 0
|
|
||||||
|
|
||||||
ret
|
|
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
This file is part of Fennix Kernel.
|
||||||
|
|
||||||
|
Fennix Kernel is free software: you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of
|
||||||
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
Fennix Kernel is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PAGE_TABLE_SIZE = 0x4
|
||||||
|
|
||||||
|
.code32
|
||||||
|
.section .bootstrap.data
|
||||||
|
.align 0x1000
|
||||||
|
.global BootPageTable
|
||||||
|
BootPageTable:
|
||||||
|
.space 0x10000 /* 0x4000 bytes will be used in UpdatePageTable */
|
||||||
|
|
||||||
|
.section .bootstrap.text
|
||||||
|
.global UpdatePageTable
|
||||||
|
UpdatePageTable:
|
||||||
|
mov $(BootPageTable + 0x0000), %edi /* First PML4E */
|
||||||
|
mov $(BootPageTable + 0x1000), %eax /* First PDPTE */
|
||||||
|
or $0x3, %eax /* Bitwise OR on eax (PDPTE) with 11b (Present, Write) */
|
||||||
|
mov %eax, (%edi) /* Write 11b to PML4E */
|
||||||
|
|
||||||
|
mov $(BootPageTable + 0x1000), %edi /* First PDPTE */
|
||||||
|
mov $(BootPageTable + 0x2000), %eax /* First PDE */
|
||||||
|
or $0x3, %eax /* Bitwise OR on eax (PDE) with 11b (Present, Write) */
|
||||||
|
|
||||||
|
mov $PAGE_TABLE_SIZE, %ecx /* For loop instruction */
|
||||||
|
mov $0x0, %ebx /* Value to store in the next 4 bytes */
|
||||||
|
.FillPageTableLevel3:
|
||||||
|
mov %eax, (%edi) /* Store modified PDE in PDPTE */
|
||||||
|
mov %ebx, 0x4(%edi) /* Store the ebx value in the next 4 bytes */
|
||||||
|
add $0x1000, %eax /* Increment (page size) */
|
||||||
|
adc $0x0, %ebx /* Add 0 to carry flag */
|
||||||
|
add $0x8, %edi /* Add 8 to edi (next PDE) */
|
||||||
|
loop .FillPageTableLevel3 /* Loop until ecx is 0 */
|
||||||
|
|
||||||
|
mov $(BootPageTable + 0x2000), %edi /* First PDE */
|
||||||
|
mov $0x83, %eax /* Present, Write, Large Page */
|
||||||
|
|
||||||
|
mov $(512 * PAGE_TABLE_SIZE), %ecx /* For loop instruction */
|
||||||
|
mov $0x0, %ebx /* Value to store in the next 4 bytes */
|
||||||
|
.FillPageTableLevel2:
|
||||||
|
mov %eax, (%edi) /* Store modified PDE in PDPTE */
|
||||||
|
mov %ebx, 0x4(%edi) /* Store the ebx value in the next 4 bytes */
|
||||||
|
add $0x200000, %eax /* Increment (page size) */
|
||||||
|
adc $0x0, %ebx /* Add 0 (carry flag) to ebx to increment if there was a carry */
|
||||||
|
add $0x8, %edi /* Add 8 to edi (next PDE) */
|
||||||
|
loop .FillPageTableLevel2 /* Loop until ecx is 0 */
|
||||||
|
|
||||||
|
ret
|
@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Kernel.
|
|
||||||
|
|
||||||
Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.intel_syntax noprefix
|
|
||||||
|
|
||||||
.code32
|
|
||||||
|
|
||||||
.equ PAGE_TABLE_SIZE, 0x4
|
|
||||||
|
|
||||||
.section .bootstrap.data
|
|
||||||
.align 0x1000
|
|
||||||
.global BootPageTable
|
|
||||||
BootPageTable:
|
|
||||||
.rept 0x10000 /* 0x4000 bytes will be used in UpdatePageTable */
|
|
||||||
.long 0
|
|
||||||
.endr
|
|
||||||
|
|
||||||
.section .bootstrap.text
|
|
||||||
.global UpdatePageTable
|
|
||||||
UpdatePageTable:
|
|
||||||
mov edi, (BootPageTable + 0x0000) /* First PML4E */
|
|
||||||
mov eax, (BootPageTable + 0x1000) /* First PDPTE */
|
|
||||||
or eax, 0b11 /* Bitwise OR on rax (PDPTE) with 11b (Present, Write) */
|
|
||||||
mov dword [edi], eax /* Write 11b to PML4E */
|
|
||||||
|
|
||||||
mov edi, (BootPageTable + 0x1000) /* First PDPTE */
|
|
||||||
mov eax, (BootPageTable + 0x2000) /* First PDE */
|
|
||||||
or eax, 0b11 /* Bitwise OR on rax (PDE) with 11b (Present, Write) */
|
|
||||||
|
|
||||||
mov ecx, PAGE_TABLE_SIZE /* For loop instruction */
|
|
||||||
mov ebx, 0x0 /* Value to store in the next 4 bytes */
|
|
||||||
.FillPageTableLevel3:
|
|
||||||
mov dword [edi], eax /* Store modified PDE in PDPTE */
|
|
||||||
mov dword [edi + 4], ebx /* Store the rbx value in the next 4 bytes */
|
|
||||||
add eax, 0x1000 /* Increment (page size) */
|
|
||||||
adc ebx, 0 /* Add 0 to carry flag */
|
|
||||||
add edi, 8 /* Add 8 to rdi (next PDE) */
|
|
||||||
loop .FillPageTableLevel3 /* Loop until rcx is 0 */
|
|
||||||
|
|
||||||
mov edi, (BootPageTable + 0x2000) /* First PDE */
|
|
||||||
mov eax, 0b10000011 /* Present, Write, Large Page */
|
|
||||||
|
|
||||||
mov ecx, (512 * PAGE_TABLE_SIZE) /* For loop instruction */
|
|
||||||
mov ebx, 0x0 /* Value to store in the next 4 bytes */
|
|
||||||
.FillPageTableLevel2:
|
|
||||||
mov dword [edi], eax /* Store modified PDE in PDPTE */
|
|
||||||
mov dword [edi + 4], ebx /* Store the rbx value in the next 4 bytes */
|
|
||||||
add eax, 1 << 21 /* Increment (page size) */
|
|
||||||
adc ebx, 0 /* Add 0 (carry flag) to rbx to increment if there was a carry */
|
|
||||||
add edi, 8 /* Add 8 to rdi (next PDE) */
|
|
||||||
loop .FillPageTableLevel2 /* Loop until rcx is 0 */
|
|
||||||
|
|
||||||
ret
|
|
@ -1,112 +0,0 @@
|
|||||||
; This file is part of Fennix Kernel.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
; modify it under the terms of the GNU General Public License as
|
|
||||||
; published by the Free Software Foundation, either version 3 of
|
|
||||||
; the License, or (at your option) any later version.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
; GNU General Public License for more details.
|
|
||||||
;
|
|
||||||
; You should have received a copy of the GNU General Public License
|
|
||||||
; along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
[bits 32]
|
|
||||||
KERNEL_STACK_SIZE equ 0x4000 ; 16KB
|
|
||||||
|
|
||||||
extern DetectCPUID
|
|
||||||
extern Detect64Bit
|
|
||||||
extern DetectPSE
|
|
||||||
extern DetectPAE
|
|
||||||
extern multiboot_main
|
|
||||||
extern LoadGDT32
|
|
||||||
extern BootPageTable
|
|
||||||
extern UpdatePageTable
|
|
||||||
extern GDT64.Ptr
|
|
||||||
extern GDT64.Code
|
|
||||||
extern GDT64.Data
|
|
||||||
|
|
||||||
section .bootstrap.data
|
|
||||||
MB_HeaderMagic:
|
|
||||||
dq 0
|
|
||||||
|
|
||||||
MB_HeaderInfo:
|
|
||||||
dq 0
|
|
||||||
|
|
||||||
section .bootstrap.text
|
|
||||||
|
|
||||||
global Multiboot2_start
|
|
||||||
Multiboot2_start:
|
|
||||||
cli
|
|
||||||
|
|
||||||
mov [MB_HeaderMagic], eax
|
|
||||||
mov [MB_HeaderInfo], ebx
|
|
||||||
|
|
||||||
call DetectCPUID
|
|
||||||
cmp eax, 0
|
|
||||||
je $
|
|
||||||
|
|
||||||
call Detect64Bit
|
|
||||||
cmp eax, 0
|
|
||||||
je $
|
|
||||||
|
|
||||||
call DetectPSE
|
|
||||||
cmp eax, 0
|
|
||||||
je $
|
|
||||||
|
|
||||||
call DetectPAE
|
|
||||||
cmp eax, 0
|
|
||||||
je $
|
|
||||||
|
|
||||||
mov ecx, cr4
|
|
||||||
or ecx, 0x00000010 ; Set PSE in CR4
|
|
||||||
or ecx, 0x00000020 ; Set PAE in CR4
|
|
||||||
mov cr4, ecx
|
|
||||||
|
|
||||||
call LoadGDT32
|
|
||||||
call UpdatePageTable
|
|
||||||
|
|
||||||
mov ecx, BootPageTable
|
|
||||||
mov cr3, ecx
|
|
||||||
|
|
||||||
mov ecx, 0xC0000080 ; EFER
|
|
||||||
rdmsr
|
|
||||||
or eax, 0x800 | 0x100 | 0x1 ; Set LME, LMA, SCE
|
|
||||||
wrmsr
|
|
||||||
|
|
||||||
mov ecx, cr0
|
|
||||||
or ecx, 0x80000001 ; Set PG and PE in CR0
|
|
||||||
mov cr0, ecx
|
|
||||||
|
|
||||||
lgdt [GDT64.Ptr]
|
|
||||||
jmp GDT64.Code:HigherHalfStart
|
|
||||||
|
|
||||||
extern UpdatePageTable64
|
|
||||||
|
|
||||||
[bits 64]
|
|
||||||
HigherHalfStart:
|
|
||||||
mov ax, GDT64.Data
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
mov ss, ax
|
|
||||||
|
|
||||||
call UpdatePageTable64
|
|
||||||
|
|
||||||
mov rsp, KernelStack + KERNEL_STACK_SIZE
|
|
||||||
mov rdi, [MB_HeaderMagic]
|
|
||||||
mov rsi, [MB_HeaderInfo]
|
|
||||||
push rsi
|
|
||||||
push rdi
|
|
||||||
call multiboot_main
|
|
||||||
.Hang:
|
|
||||||
hlt
|
|
||||||
jmp .Hang
|
|
||||||
|
|
||||||
section .bootstrap.bss
|
|
||||||
align 16
|
|
||||||
KernelStack:
|
|
||||||
resb KERNEL_STACK_SIZE
|
|
@ -15,10 +15,8 @@
|
|||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.intel_syntax noprefix
|
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
.equ KERNEL_STACK_SIZE, 0x4000 /* 16KB */
|
KERNEL_STACK_SIZE = 0x4000 /* 16KB */
|
||||||
|
|
||||||
.extern DetectCPUID
|
.extern DetectCPUID
|
||||||
.extern Detect64Bit
|
.extern Detect64Bit
|
||||||
@ -45,67 +43,71 @@ MB_HeaderInfo:
|
|||||||
Multiboot2_start:
|
Multiboot2_start:
|
||||||
cli
|
cli
|
||||||
|
|
||||||
mov [MB_HeaderMagic], eax
|
mov %eax, [MB_HeaderMagic]
|
||||||
mov [MB_HeaderInfo], ebx
|
mov %ebx, [MB_HeaderInfo]
|
||||||
|
|
||||||
call DetectCPUID
|
call DetectCPUID
|
||||||
cmp eax, 0
|
cmp $0, %eax
|
||||||
je $
|
je .
|
||||||
|
|
||||||
call Detect64Bit
|
call Detect64Bit
|
||||||
cmp eax, 0
|
cmp $0, %eax
|
||||||
je $
|
je .
|
||||||
|
|
||||||
call DetectPSE
|
call DetectPSE
|
||||||
cmp eax, 0
|
cmp $0, %eax
|
||||||
je $
|
je .
|
||||||
|
|
||||||
call DetectPAE
|
call DetectPAE
|
||||||
cmp eax, 0
|
cmp $0, %eax
|
||||||
je $
|
je .
|
||||||
|
|
||||||
mov ecx, cr4
|
mov %cr4, %ecx
|
||||||
or ecx, 0x00000010 /* Set PSE in CR4 */
|
or $0x00000010, %ecx /* PSE */
|
||||||
or ecx, 0x00000020 /* Set PAE in CR4 */
|
or $0x00000020, %ecx /* PAE */
|
||||||
mov cr4, ecx
|
mov %ecx, %cr4
|
||||||
|
|
||||||
call LoadGDT32
|
call LoadGDT32
|
||||||
call UpdatePageTable
|
call UpdatePageTable
|
||||||
|
|
||||||
mov ecx, BootPageTable
|
mov $BootPageTable, %ecx
|
||||||
mov cr3, ecx
|
mov %ecx, %cr3
|
||||||
|
|
||||||
mov ecx, 0xC0000080 /* EFER */
|
mov $0xC0000080, %ecx /* EFER */
|
||||||
rdmsr
|
rdmsr
|
||||||
or eax, 0x800 | 0x100 | 0x1 /* Set LME, LMA, SCE */
|
or $0x800, %eax /* LME */
|
||||||
|
or $0x100, %eax /* LMA */
|
||||||
|
or $0x1, %eax /* SCE */
|
||||||
wrmsr
|
wrmsr
|
||||||
|
|
||||||
mov ecx, cr0
|
mov %cr0, %ecx
|
||||||
or ecx, 0x80000001 /* Set PG and PE in CR0 */
|
or $0x80000000, %ecx /* PG */
|
||||||
mov cr0, ecx
|
or $0x1, %ecx /* PE */
|
||||||
|
mov %ecx, %cr0
|
||||||
|
|
||||||
lgdt [GDT64.Ptr]
|
lgdt [GDT64.Ptr]
|
||||||
jmp GDT64.Code:HigherHalfStart
|
ljmp $GDT64.Code, $HigherHalfStart
|
||||||
|
|
||||||
.extern UpdatePageTable64
|
.extern UpdatePageTable64
|
||||||
|
|
||||||
.code64
|
.code64
|
||||||
HigherHalfStart:
|
HigherHalfStart:
|
||||||
mov ax, GDT64.Data
|
mov GDT64.Data, %ax
|
||||||
mov ds, ax
|
mov %ax, %ds
|
||||||
mov es, ax
|
mov %ax, %es
|
||||||
mov fs, ax
|
mov %ax, %fs
|
||||||
mov gs, ax
|
mov %ax, %gs
|
||||||
mov ss, ax
|
mov %ax, %ss
|
||||||
|
|
||||||
call UpdatePageTable64
|
call UpdatePageTable64
|
||||||
|
|
||||||
mov rsp, KernelStack + KERNEL_STACK_SIZE
|
mov $(KernelStack + KERNEL_STACK_SIZE), %rsp
|
||||||
mov rbp, 0
|
mov $0x0, %rbp
|
||||||
mov rdi, [MB_HeaderMagic]
|
|
||||||
mov rsi, [MB_HeaderInfo]
|
mov [MB_HeaderMagic], %rdi
|
||||||
push rsi
|
mov [MB_HeaderInfo], %rsi
|
||||||
push rdi
|
push %rsi
|
||||||
|
push %rdi
|
||||||
call multiboot_main
|
call multiboot_main
|
||||||
.Hang:
|
.Hang:
|
||||||
hlt
|
hlt
|
@ -42,362 +42,363 @@ warning: left shift count >= width of type
|
|||||||
|
|
||||||
namespace APIC
|
namespace APIC
|
||||||
{
|
{
|
||||||
// headache
|
// headache
|
||||||
// https://www.amd.com/system/files/TechDocs/24593.pdf
|
// https://www.amd.com/system/files/TechDocs/24593.pdf
|
||||||
// https://www.naic.edu/~phil/software/intel/318148.pdf
|
// https://www.naic.edu/~phil/software/intel/318148.pdf
|
||||||
|
|
||||||
uint32_t APIC::Read(uint32_t Register)
|
uint32_t APIC::Read(uint32_t Register)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (Register != APIC_ICRLO &&
|
if (Register != APIC_ICRLO &&
|
||||||
Register != APIC_ICRHI &&
|
Register != APIC_ICRHI &&
|
||||||
Register != APIC_ID)
|
Register != APIC_ID)
|
||||||
debug("APIC::Read(%#lx) [x2=%d]", Register, x2APICSupported ? 1 : 0);
|
debug("APIC::Read(%#lx) [x2=%d]", Register, x2APICSupported ? 1 : 0);
|
||||||
#endif
|
#endif
|
||||||
if (x2APICSupported)
|
if (x2APICSupported)
|
||||||
{
|
{
|
||||||
if (Register != APIC_ICRHI)
|
if (Register != APIC_ICRHI)
|
||||||
return s_cst(uint32_t, rdmsr((Register >> 4) + 0x800));
|
return s_cst(uint32_t, rdmsr((Register >> 4) + 0x800));
|
||||||
else
|
else
|
||||||
return s_cst(uint32_t, rdmsr(0x30 + 0x800));
|
return s_cst(uint32_t, rdmsr(0x30 + 0x800));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CPU::MemBar::Barrier();
|
CPU::MemBar::Barrier();
|
||||||
uint32_t ret = *((volatile uint32_t *)((uintptr_t)APICBaseAddress + Register));
|
uint32_t ret = *((volatile uint32_t *)((uintptr_t)APICBaseAddress + Register));
|
||||||
CPU::MemBar::Barrier();
|
CPU::MemBar::Barrier();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIC::Write(uint32_t Register, uint32_t Value)
|
void APIC::Write(uint32_t Register, uint32_t Value)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (Register != APIC_EOI &&
|
if (Register != APIC_EOI &&
|
||||||
Register != APIC_TDCR &&
|
Register != APIC_TDCR &&
|
||||||
Register != APIC_TIMER &&
|
Register != APIC_TIMER &&
|
||||||
Register != APIC_TICR &&
|
Register != APIC_TICR &&
|
||||||
Register != APIC_ICRLO &&
|
Register != APIC_ICRLO &&
|
||||||
Register != APIC_ICRHI)
|
Register != APIC_ICRHI)
|
||||||
debug("APIC::Write(%#lx, %#lx) [x2=%d]", Register, Value, x2APICSupported ? 1 : 0);
|
debug("APIC::Write(%#lx, %#lx) [x2=%d]", Register, Value, x2APICSupported ? 1 : 0);
|
||||||
#endif
|
#endif
|
||||||
if (x2APICSupported)
|
if (x2APICSupported)
|
||||||
{
|
{
|
||||||
if (Register != APIC_ICRHI)
|
if (Register != APIC_ICRHI)
|
||||||
wrmsr((Register >> 4) + 0x800, Value);
|
wrmsr((Register >> 4) + 0x800, Value);
|
||||||
else
|
else
|
||||||
wrmsr(MSR_X2APIC_ICR, Value);
|
wrmsr(MSR_X2APIC_ICR, Value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CPU::MemBar::Barrier();
|
CPU::MemBar::Barrier();
|
||||||
*((volatile uint32_t *)(((uintptr_t)APICBaseAddress) + Register)) = Value;
|
*((volatile uint32_t *)(((uintptr_t)APICBaseAddress) + Register)) = Value;
|
||||||
CPU::MemBar::Barrier();
|
CPU::MemBar::Barrier();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIC::IOWrite(uint64_t Base, uint32_t Register, uint32_t Value)
|
void APIC::IOWrite(uint64_t Base, uint32_t Register, uint32_t Value)
|
||||||
{
|
{
|
||||||
debug("APIC::IOWrite(%#lx, %#lx, %#lx)", Base, Register, Value);
|
debug("APIC::IOWrite(%#lx, %#lx, %#lx)", Base, Register, Value);
|
||||||
CPU::MemBar::Barrier();
|
CPU::MemBar::Barrier();
|
||||||
*((volatile uint32_t *)(((uintptr_t)Base))) = Register;
|
*((volatile uint32_t *)(((uintptr_t)Base))) = Register;
|
||||||
CPU::MemBar::Barrier();
|
CPU::MemBar::Barrier();
|
||||||
*((volatile uint32_t *)(((uintptr_t)Base + 16))) = Value;
|
*((volatile uint32_t *)(((uintptr_t)Base + 16))) = Value;
|
||||||
CPU::MemBar::Barrier();
|
CPU::MemBar::Barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t APIC::IORead(uint64_t Base, uint32_t Register)
|
uint32_t APIC::IORead(uint64_t Base, uint32_t Register)
|
||||||
{
|
{
|
||||||
debug("APIC::IORead(%#lx, %#lx)", Base, Register);
|
debug("APIC::IORead(%#lx, %#lx)", Base, Register);
|
||||||
CPU::MemBar::Barrier();
|
CPU::MemBar::Barrier();
|
||||||
*((volatile uint32_t *)(((uintptr_t)Base))) = Register;
|
*((volatile uint32_t *)(((uintptr_t)Base))) = Register;
|
||||||
CPU::MemBar::Barrier();
|
CPU::MemBar::Barrier();
|
||||||
uint32_t ret = *((volatile uint32_t *)(((uintptr_t)Base + 16)));
|
uint32_t ret = *((volatile uint32_t *)(((uintptr_t)Base + 16)));
|
||||||
CPU::MemBar::Barrier();
|
CPU::MemBar::Barrier();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIC::EOI() { this->Write(APIC_EOI, 0); }
|
void APIC::EOI() { this->Write(APIC_EOI, 0); }
|
||||||
|
|
||||||
void APIC::WaitForIPI()
|
void APIC::WaitForIPI()
|
||||||
{
|
{
|
||||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
icr.raw = this->Read(APIC_ICRLO);
|
icr.raw = this->Read(APIC_ICRLO);
|
||||||
} while (icr.DeliveryStatus != Idle);
|
CPU::Pause();
|
||||||
}
|
} while (icr.DeliveryStatus != Idle);
|
||||||
|
}
|
||||||
|
|
||||||
void APIC::IPI(int CPU, InterruptCommandRegisterLow icr)
|
void APIC::IPI(int CPU, InterruptCommandRegisterLow icr)
|
||||||
{
|
{
|
||||||
SmartCriticalSection(APICLock);
|
SmartCriticalSection(APICLock);
|
||||||
if (x2APICSupported)
|
if (x2APICSupported)
|
||||||
{
|
{
|
||||||
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
||||||
this->WaitForIPI();
|
this->WaitForIPI();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->Write(APIC_ICRHI, (CPU << 24));
|
this->Write(APIC_ICRHI, (CPU << 24));
|
||||||
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
||||||
this->WaitForIPI();
|
this->WaitForIPI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIC::SendInitIPI(int CPU)
|
void APIC::SendInitIPI(int CPU)
|
||||||
{
|
{
|
||||||
SmartCriticalSection(APICLock);
|
SmartCriticalSection(APICLock);
|
||||||
if (x2APICSupported)
|
if (x2APICSupported)
|
||||||
{
|
{
|
||||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||||
icr.DeliveryMode = INIT;
|
icr.DeliveryMode = INIT;
|
||||||
icr.Level = Assert;
|
icr.Level = Assert;
|
||||||
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
||||||
this->WaitForIPI();
|
this->WaitForIPI();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||||
icr.DeliveryMode = INIT;
|
icr.DeliveryMode = INIT;
|
||||||
icr.Level = Assert;
|
icr.Level = Assert;
|
||||||
this->Write(APIC_ICRHI, (CPU << 24));
|
this->Write(APIC_ICRHI, (CPU << 24));
|
||||||
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
||||||
this->WaitForIPI();
|
this->WaitForIPI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIC::SendStartupIPI(int CPU, uint64_t StartupAddress)
|
void APIC::SendStartupIPI(int CPU, uint64_t StartupAddress)
|
||||||
{
|
{
|
||||||
SmartCriticalSection(APICLock);
|
SmartCriticalSection(APICLock);
|
||||||
if (x2APICSupported)
|
if (x2APICSupported)
|
||||||
{
|
{
|
||||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||||
icr.Vector = s_cst(uint8_t, StartupAddress >> 12);
|
icr.Vector = s_cst(uint8_t, StartupAddress >> 12);
|
||||||
icr.DeliveryMode = Startup;
|
icr.DeliveryMode = Startup;
|
||||||
icr.Level = Assert;
|
icr.Level = Assert;
|
||||||
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
||||||
this->WaitForIPI();
|
this->WaitForIPI();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||||
icr.Vector = s_cst(uint8_t, StartupAddress >> 12);
|
icr.Vector = s_cst(uint8_t, StartupAddress >> 12);
|
||||||
icr.DeliveryMode = Startup;
|
icr.DeliveryMode = Startup;
|
||||||
icr.Level = Assert;
|
icr.Level = Assert;
|
||||||
this->Write(APIC_ICRHI, (CPU << 24));
|
this->Write(APIC_ICRHI, (CPU << 24));
|
||||||
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
||||||
this->WaitForIPI();
|
this->WaitForIPI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t APIC::IOGetMaxRedirect(uint32_t APICID)
|
uint32_t APIC::IOGetMaxRedirect(uint32_t APICID)
|
||||||
{
|
{
|
||||||
uint32_t TableAddress = (this->IORead((((ACPI::MADT *)PowerManager->GetMADT())->ioapic[APICID]->Address), GetIOAPICVersion));
|
uint32_t TableAddress = (this->IORead((((ACPI::MADT *)PowerManager->GetMADT())->ioapic[APICID]->Address), GetIOAPICVersion));
|
||||||
return ((IOAPICVersion *)&TableAddress)->MaximumRedirectionEntry;
|
return ((IOAPICVersion *)&TableAddress)->MaximumRedirectionEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIC::RawRedirectIRQ(uint16_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status)
|
void APIC::RawRedirectIRQ(uint16_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status)
|
||||||
{
|
{
|
||||||
uint64_t Value = Vector;
|
uint64_t Value = Vector;
|
||||||
|
|
||||||
int64_t IOAPICTarget = -1;
|
int64_t IOAPICTarget = -1;
|
||||||
for (uint64_t i = 0; ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i] != 0; i++)
|
for (uint64_t i = 0; ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i] != 0; i++)
|
||||||
if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase <= GSI)
|
if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase <= GSI)
|
||||||
if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase + IOGetMaxRedirect(s_cst(uint32_t, i)) > GSI)
|
if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase + IOGetMaxRedirect(s_cst(uint32_t, i)) > GSI)
|
||||||
{
|
{
|
||||||
IOAPICTarget = i;
|
IOAPICTarget = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IOAPICTarget == -1)
|
if (IOAPICTarget == -1)
|
||||||
{
|
{
|
||||||
error("No ISO table found for I/O APIC");
|
error("No ISO table found for I/O APIC");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: IOAPICRedirectEntry Entry = {.raw = 0};
|
// TODO: IOAPICRedirectEntry Entry = {.raw = 0};
|
||||||
|
|
||||||
if (Flags & ActiveHighLow)
|
if (Flags & ActiveHighLow)
|
||||||
Value |= (1 << 13);
|
Value |= (1 << 13);
|
||||||
|
|
||||||
if (Flags & EdgeLevel)
|
if (Flags & EdgeLevel)
|
||||||
Value |= (1 << 15);
|
Value |= (1 << 15);
|
||||||
|
|
||||||
if (!Status)
|
if (!Status)
|
||||||
Value |= (1 << 16);
|
Value |= (1 << 16);
|
||||||
|
|
||||||
Value |= (((uintptr_t)CPU) << 56);
|
Value |= (((uintptr_t)CPU) << 56);
|
||||||
uint32_t IORegister = (GSI - ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->GSIBase) * 2 + 16;
|
uint32_t IORegister = (GSI - ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->GSIBase) * 2 + 16;
|
||||||
|
|
||||||
this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister, (uint32_t)Value);
|
this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister, (uint32_t)Value);
|
||||||
this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister + 1, (uint32_t)(Value >> 32));
|
this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister + 1, (uint32_t)(Value >> 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIC::RedirectIRQ(int CPU, uint16_t IRQ, int Status)
|
void APIC::RedirectIRQ(int CPU, uint16_t IRQ, int Status)
|
||||||
{
|
{
|
||||||
for (uint64_t i = 0; i < ((ACPI::MADT *)PowerManager->GetMADT())->iso.size(); i++)
|
for (uint64_t i = 0; i < ((ACPI::MADT *)PowerManager->GetMADT())->iso.size(); i++)
|
||||||
if (((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource == IRQ)
|
if (((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource == IRQ)
|
||||||
{
|
{
|
||||||
debug("[ISO %d] Mapping to source IRQ%#d GSI:%#lx on CPU %d",
|
debug("[ISO %d] Mapping to source IRQ%#d GSI:%#lx on CPU %d",
|
||||||
i, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, CPU);
|
i, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, CPU);
|
||||||
|
|
||||||
this->RawRedirectIRQ(((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource + 0x20, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->Flags, CPU, Status);
|
this->RawRedirectIRQ(((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource + 0x20, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->Flags, CPU, Status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
debug("Mapping IRQ%d on CPU %d", IRQ, CPU);
|
debug("Mapping IRQ%d on CPU %d", IRQ, CPU);
|
||||||
this->RawRedirectIRQ(IRQ + 0x20, IRQ, 0, CPU, Status);
|
this->RawRedirectIRQ(IRQ + 0x20, IRQ, 0, CPU, Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIC::RedirectIRQs(int CPU)
|
void APIC::RedirectIRQs(int CPU)
|
||||||
{
|
{
|
||||||
SmartCriticalSection(APICLock);
|
SmartCriticalSection(APICLock);
|
||||||
debug("Redirecting IRQs...");
|
debug("Redirecting IRQs...");
|
||||||
for (uint8_t i = 0; i < 16; i++)
|
for (uint8_t i = 0; i < 16; i++)
|
||||||
this->RedirectIRQ(CPU, i, 1);
|
this->RedirectIRQ(CPU, i, 1);
|
||||||
debug("Redirecting IRQs completed.");
|
debug("Redirecting IRQs completed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
APIC::APIC(int Core)
|
APIC::APIC(int Core)
|
||||||
{
|
{
|
||||||
SmartCriticalSection(APICLock);
|
SmartCriticalSection(APICLock);
|
||||||
APIC_BASE BaseStruct = {.raw = rdmsr(MSR_APIC_BASE)};
|
APIC_BASE BaseStruct = {.raw = rdmsr(MSR_APIC_BASE)};
|
||||||
uint64_t BaseLow = BaseStruct.ApicBaseLo;
|
uint64_t BaseLow = BaseStruct.ApicBaseLo;
|
||||||
uint64_t BaseHigh = BaseStruct.ApicBaseHi;
|
uint64_t BaseHigh = BaseStruct.ApicBaseHi;
|
||||||
this->APICBaseAddress = BaseLow << 12u | BaseHigh << 32u;
|
this->APICBaseAddress = BaseLow << 12u | BaseHigh << 32u;
|
||||||
trace("APIC Address: %#lx", this->APICBaseAddress);
|
trace("APIC Address: %#lx", this->APICBaseAddress);
|
||||||
Memory::Virtual().Map((void *)this->APICBaseAddress, (void *)this->APICBaseAddress, Memory::PTFlag::RW | Memory::PTFlag::PCD);
|
Memory::Virtual().Map((void *)this->APICBaseAddress, (void *)this->APICBaseAddress, Memory::PTFlag::RW | Memory::PTFlag::PCD);
|
||||||
|
|
||||||
bool x2APICSupported = false;
|
bool x2APICSupported = false;
|
||||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||||
{
|
{
|
||||||
CPU::x86::AMD::CPUID0x00000001 cpuid;
|
CPU::x86::AMD::CPUID0x00000001 cpuid;
|
||||||
cpuid.Get();
|
cpuid.Get();
|
||||||
if (cpuid.ECX.x2APIC)
|
if (cpuid.ECX.x2APIC)
|
||||||
{
|
{
|
||||||
// x2APICSupported = cpuid.ECX.x2APIC;
|
// x2APICSupported = cpuid.ECX.x2APIC;
|
||||||
fixme("x2APIC is supported");
|
fixme("x2APIC is supported");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
||||||
{
|
{
|
||||||
CPU::x86::Intel::CPUID0x00000001 cpuid;
|
CPU::x86::Intel::CPUID0x00000001 cpuid;
|
||||||
cpuid.Get();
|
cpuid.Get();
|
||||||
if (cpuid.ECX.x2APIC)
|
if (cpuid.ECX.x2APIC)
|
||||||
{
|
{
|
||||||
// x2APICSupported = cpuid.ECX.x2APIC;
|
// x2APICSupported = cpuid.ECX.x2APIC;
|
||||||
fixme("x2APIC is supported");
|
fixme("x2APIC is supported");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x2APICSupported)
|
if (x2APICSupported)
|
||||||
{
|
{
|
||||||
this->x2APICSupported = true;
|
this->x2APICSupported = true;
|
||||||
wrmsr(MSR_APIC_BASE, (rdmsr(MSR_APIC_BASE) | (1 << 11)) & ~(1 << 10));
|
wrmsr(MSR_APIC_BASE, (rdmsr(MSR_APIC_BASE) | (1 << 11)) & ~(1 << 10));
|
||||||
BaseStruct.EN = 1;
|
BaseStruct.EN = 1;
|
||||||
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BaseStruct.EN = 1;
|
BaseStruct.EN = 1;
|
||||||
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->Write(APIC_TPR, 0x0);
|
this->Write(APIC_TPR, 0x0);
|
||||||
// this->Write(APIC_SVR, this->Read(APIC_SVR) | 0x100); // 0x1FF or 0x100 ? on https://wiki.osdev.org/APIC is 0x100
|
// this->Write(APIC_SVR, this->Read(APIC_SVR) | 0x100); // 0x1FF or 0x100 ? on https://wiki.osdev.org/APIC is 0x100
|
||||||
|
|
||||||
if (!this->x2APICSupported)
|
if (!this->x2APICSupported)
|
||||||
{
|
{
|
||||||
this->Write(APIC_DFR, 0xF0000000);
|
this->Write(APIC_DFR, 0xF0000000);
|
||||||
this->Write(APIC_LDR, this->Read(APIC_ID));
|
this->Write(APIC_LDR, this->Read(APIC_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
|
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
|
||||||
|
|
||||||
for (size_t i = 0; i < madt->nmi.size(); i++)
|
for (size_t i = 0; i < madt->nmi.size(); i++)
|
||||||
{
|
{
|
||||||
if (madt->nmi[i]->processor != 0xFF && Core != madt->nmi[i]->processor)
|
if (madt->nmi[i]->processor != 0xFF && Core != madt->nmi[i]->processor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32_t nmi = 0x402;
|
uint32_t nmi = 0x402;
|
||||||
if (madt->nmi[i]->flags & 2)
|
if (madt->nmi[i]->flags & 2)
|
||||||
nmi |= 1 << 13;
|
nmi |= 1 << 13;
|
||||||
if (madt->nmi[i]->flags & 8)
|
if (madt->nmi[i]->flags & 8)
|
||||||
nmi |= 1 << 15;
|
nmi |= 1 << 15;
|
||||||
if (madt->nmi[i]->lint == 0)
|
if (madt->nmi[i]->lint == 0)
|
||||||
this->Write(APIC_LINT0, nmi);
|
this->Write(APIC_LINT0, nmi);
|
||||||
else if (madt->nmi[i]->lint == 1)
|
else if (madt->nmi[i]->lint == 1)
|
||||||
this->Write(APIC_LINT1, nmi);
|
this->Write(APIC_LINT1, nmi);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the spurrious interrupt vector
|
// Setup the spurrious interrupt vector
|
||||||
Spurious Spurious = {.raw = this->Read(APIC_SVR)};
|
Spurious Spurious = {.raw = this->Read(APIC_SVR)};
|
||||||
Spurious.Vector = IRQ223; // TODO: Should I map the IRQ to something?
|
Spurious.Vector = IRQ223; // TODO: Should I map the IRQ to something?
|
||||||
Spurious.Software = 1;
|
Spurious.Software = 1;
|
||||||
this->Write(APIC_SVR, s_cst(uint32_t, Spurious.raw));
|
this->Write(APIC_SVR, s_cst(uint32_t, Spurious.raw));
|
||||||
|
|
||||||
static int once = 0;
|
static int once = 0;
|
||||||
if (!once++)
|
if (!once++)
|
||||||
{
|
{
|
||||||
// Disable PIT
|
// Disable PIT
|
||||||
outb(0x43, 0x28);
|
outb(0x43, 0x28);
|
||||||
outb(0x40, 0x0);
|
outb(0x40, 0x0);
|
||||||
|
|
||||||
// Disable PIC
|
// Disable PIC
|
||||||
outb(0x21, 0xFF);
|
outb(0x21, 0xFF);
|
||||||
outb(0xA1, 0xFF);
|
outb(0xA1, 0xFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
APIC::~APIC() {}
|
APIC::~APIC() {}
|
||||||
|
|
||||||
void Timer::OnInterruptReceived(TrapFrame *Frame) { UNUSED(Frame); }
|
void Timer::OnInterruptReceived(TrapFrame *Frame) { UNUSED(Frame); }
|
||||||
|
|
||||||
void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds)
|
void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds)
|
||||||
{
|
{
|
||||||
SmartCriticalSection(APICLock);
|
SmartCriticalSection(APICLock);
|
||||||
LVTTimer timer = {.raw = 0};
|
LVTTimer timer = {.raw = 0};
|
||||||
timer.Vector = s_cst(uint8_t, Vector);
|
timer.Vector = s_cst(uint8_t, Vector);
|
||||||
timer.TimerMode = 0;
|
timer.TimerMode = 0;
|
||||||
if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0)
|
if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0)
|
||||||
this->lapic->Write(APIC_TDCR, DivideBy128);
|
this->lapic->Write(APIC_TDCR, DivideBy128);
|
||||||
else
|
else
|
||||||
this->lapic->Write(APIC_TDCR, DivideBy16);
|
this->lapic->Write(APIC_TDCR, DivideBy16);
|
||||||
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks * Miliseconds));
|
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks * Miliseconds));
|
||||||
this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw));
|
this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw));
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer::Timer(APIC *apic) : Interrupts::Handler(0) /* IRQ0 */
|
Timer::Timer(APIC *apic) : Interrupts::Handler(0) /* IRQ0 */
|
||||||
{
|
{
|
||||||
SmartCriticalSection(APICLock);
|
SmartCriticalSection(APICLock);
|
||||||
this->lapic = apic;
|
this->lapic = apic;
|
||||||
LVTTimerDivide Divider = DivideBy16;
|
LVTTimerDivide Divider = DivideBy16;
|
||||||
|
|
||||||
trace("Initializing APIC timer on CPU %d", GetCurrentCPU()->ID);
|
trace("Initializing APIC timer on CPU %d", GetCurrentCPU()->ID);
|
||||||
|
|
||||||
this->lapic->Write(APIC_TDCR, Divider);
|
this->lapic->Write(APIC_TDCR, Divider);
|
||||||
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
||||||
|
|
||||||
TimeManager->Sleep(1, Time::Units::Milliseconds);
|
TimeManager->Sleep(1, Time::Units::Milliseconds);
|
||||||
|
|
||||||
// Mask the timer
|
// Mask the timer
|
||||||
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);
|
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);
|
||||||
Ticks = 0xFFFFFFFF - this->lapic->Read(APIC_TCCR);
|
Ticks = 0xFFFFFFFF - this->lapic->Read(APIC_TCCR);
|
||||||
|
|
||||||
// Config for IRQ0 timer
|
// Config for IRQ0 timer
|
||||||
LVTTimer timer = {.raw = 0};
|
LVTTimer timer = {.raw = 0};
|
||||||
timer.Vector = IRQ0;
|
timer.Vector = IRQ0;
|
||||||
timer.Mask = Unmasked;
|
timer.Mask = Unmasked;
|
||||||
timer.TimerMode = LVTTimerMode::OneShot;
|
timer.TimerMode = LVTTimerMode::OneShot;
|
||||||
|
|
||||||
// Initialize APIC timer
|
// Initialize APIC timer
|
||||||
this->lapic->Write(APIC_TDCR, Divider);
|
this->lapic->Write(APIC_TDCR, Divider);
|
||||||
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks));
|
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks));
|
||||||
this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw));
|
this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw));
|
||||||
trace("%d APIC Timer %d ticks in.", GetCurrentCPU()->ID, Ticks);
|
trace("%d APIC Timer %d ticks in.", GetCurrentCPU()->ID, Ticks);
|
||||||
KPrint("APIC Timer: \e8888FF%ld\eCCCCCC ticks.", Ticks);
|
KPrint("APIC Timer: \e8888FF%ld\eCCCCCC ticks.", Ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer::~Timer()
|
Timer::~Timer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,136 +0,0 @@
|
|||||||
; This file is part of Fennix Kernel.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
; modify it under the terms of the GNU General Public License as
|
|
||||||
; published by the Free Software Foundation, either version 3 of
|
|
||||||
; the License, or (at your option) any later version.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
; GNU General Public License for more details.
|
|
||||||
;
|
|
||||||
; You should have received a copy of the GNU General Public License
|
|
||||||
; along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
; This has to be the same as enum SMPTrampolineAddress.
|
|
||||||
TRAMPOLINE_PAGE_TABLE equ 0x500
|
|
||||||
TRAMPOLINE_START_ADDR equ 0x520
|
|
||||||
TRAMPOLINE_STACK equ 0x570
|
|
||||||
TRAMPOLINE_GDT equ 0x580
|
|
||||||
TRAMPOLINE_IDT equ 0x590
|
|
||||||
TRAMPOLINE_CORE equ 0x600
|
|
||||||
TRAMPOLINE_START equ 0x2000
|
|
||||||
|
|
||||||
[bits 16]
|
|
||||||
|
|
||||||
extern StartCPU
|
|
||||||
global _trampoline_start
|
|
||||||
_trampoline_start:
|
|
||||||
cli
|
|
||||||
mov ax, 0x0
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
mov ss, ax
|
|
||||||
o32 lgdt [ProtectedMode_gdtr - _trampoline_start + TRAMPOLINE_START]
|
|
||||||
mov eax, cr0
|
|
||||||
or al, 0x1
|
|
||||||
mov cr0, eax
|
|
||||||
jmp 0x8:(Trampoline32 - _trampoline_start + TRAMPOLINE_START)
|
|
||||||
|
|
||||||
[bits 32]
|
|
||||||
section .text
|
|
||||||
Trampoline32:
|
|
||||||
mov bx, 0x10
|
|
||||||
mov ds, bx
|
|
||||||
mov es, bx
|
|
||||||
mov ss, bx
|
|
||||||
mov eax, dword [TRAMPOLINE_PAGE_TABLE]
|
|
||||||
mov cr3, eax
|
|
||||||
mov eax, cr4
|
|
||||||
or eax, 1 << 5 ; Set the PAE-bit, which is the 6th bit (bit 5).
|
|
||||||
or eax, 1 << 7
|
|
||||||
mov cr4, eax
|
|
||||||
mov ecx, 0xc0000080
|
|
||||||
rdmsr
|
|
||||||
or eax,1 << 8 ; LME
|
|
||||||
wrmsr
|
|
||||||
mov eax, cr0
|
|
||||||
or eax, 1 << 31
|
|
||||||
mov cr0, eax
|
|
||||||
lgdt [LongMode_gdtr - _trampoline_start + TRAMPOLINE_START]
|
|
||||||
jmp 0x8:(Trampoline64 - _trampoline_start + TRAMPOLINE_START)
|
|
||||||
|
|
||||||
[bits 64]
|
|
||||||
Trampoline64:
|
|
||||||
mov ax, 0x10
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov ss, ax
|
|
||||||
mov ax, 0x0
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
lgdt [TRAMPOLINE_GDT]
|
|
||||||
lidt [TRAMPOLINE_IDT]
|
|
||||||
mov rsp, [TRAMPOLINE_STACK]
|
|
||||||
mov rbp, 0x0 ; Terminate stack traces here.
|
|
||||||
; Reset RFLAGS.
|
|
||||||
push 0x0
|
|
||||||
popf
|
|
||||||
mov rax, qword vcode64
|
|
||||||
call vcode64
|
|
||||||
|
|
||||||
vcode64:
|
|
||||||
push rbp
|
|
||||||
; Set up SSE
|
|
||||||
mov rax, cr0
|
|
||||||
; btr eax, 2
|
|
||||||
; bts eax, 1
|
|
||||||
; mov cr0, rax
|
|
||||||
mov rax, cr4
|
|
||||||
bts eax, 9
|
|
||||||
bts eax, 10
|
|
||||||
mov cr4, rax
|
|
||||||
mov rax, qword TrampolineExit
|
|
||||||
call rax
|
|
||||||
|
|
||||||
align 16
|
|
||||||
LongMode_gdtr:
|
|
||||||
dw LongModeGDTEnd - LongModeGDTStart - 1
|
|
||||||
dq LongModeGDTStart - _trampoline_start + TRAMPOLINE_START
|
|
||||||
|
|
||||||
align 16
|
|
||||||
LongModeGDTStart:
|
|
||||||
dq 0 ; NULL segment
|
|
||||||
dq 0x00AF98000000FFFF ; Code segment
|
|
||||||
dq 0x00CF92000000FFFF ; Data segment
|
|
||||||
LongModeGDTEnd:
|
|
||||||
|
|
||||||
align 16
|
|
||||||
ProtectedMode_gdtr:
|
|
||||||
dw ProtectedModeGDTEnd - ProtectedModeGDTStart - 1
|
|
||||||
dd ProtectedModeGDTStart - _trampoline_start + TRAMPOLINE_START
|
|
||||||
|
|
||||||
align 16
|
|
||||||
ProtectedModeGDTStart:
|
|
||||||
dq 0 ; NULL segment
|
|
||||||
dq 0x00CF9A000000FFFF ; Code segment
|
|
||||||
dq 0x00CF92000000FFFF ; Data segment
|
|
||||||
ProtectedModeGDTEnd:
|
|
||||||
|
|
||||||
align 16
|
|
||||||
ProtectedMode_idtr:
|
|
||||||
dw 0
|
|
||||||
dd 0
|
|
||||||
dd 0
|
|
||||||
align 16
|
|
||||||
|
|
||||||
global _trampoline_end
|
|
||||||
_trampoline_end:
|
|
||||||
|
|
||||||
TrampolineExit:
|
|
||||||
call StartCPU
|
|
||||||
|
|
||||||
times 512 - ($-$$) db 0
|
|
179
Architecture/amd64/cpu/SMPTrampoline.s
Normal file
179
Architecture/amd64/cpu/SMPTrampoline.s
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
This file is part of Fennix Kernel.
|
||||||
|
|
||||||
|
Fennix Kernel is free software: you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of
|
||||||
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
Fennix Kernel is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This has to be the same as enum SMPTrampolineAddress. */
|
||||||
|
TRAMPOLINE_PAGE_TABLE = 0x500
|
||||||
|
TRAMPOLINE_START_ADDR = 0x520
|
||||||
|
TRAMPOLINE_STACK = 0x570
|
||||||
|
TRAMPOLINE_GDT = 0x580
|
||||||
|
TRAMPOLINE_IDT = 0x590
|
||||||
|
TRAMPOLINE_CORE = 0x600
|
||||||
|
TRAMPOLINE_START = 0x2000
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
|
||||||
|
/* ========== 16-bit ========== */
|
||||||
|
|
||||||
|
.code16
|
||||||
|
.global _trampoline_start
|
||||||
|
_trampoline_start:
|
||||||
|
cli
|
||||||
|
cld
|
||||||
|
call Trampoline16
|
||||||
|
|
||||||
|
Trampoline16:
|
||||||
|
mov $0x0, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %gs
|
||||||
|
mov %ax, %ss
|
||||||
|
|
||||||
|
/* Load Protected Mode GDT */
|
||||||
|
lgdt [ProtectedMode_gdtr - _trampoline_start + TRAMPOLINE_START]
|
||||||
|
|
||||||
|
/* Enable Protected Mode */
|
||||||
|
mov %cr0, %eax
|
||||||
|
or $0x1, %al
|
||||||
|
mov %eax, %cr0
|
||||||
|
|
||||||
|
/* Jump to Protected Mode */
|
||||||
|
ljmp $0x8, $(Trampoline32 - _trampoline_start + TRAMPOLINE_START)
|
||||||
|
|
||||||
|
/* ========== 32-bit ========== */
|
||||||
|
|
||||||
|
.code32
|
||||||
|
Trampoline32:
|
||||||
|
mov $0x10, %bx
|
||||||
|
mov %bx, %ds
|
||||||
|
mov %bx, %es
|
||||||
|
mov %bx, %ss
|
||||||
|
|
||||||
|
/* Set a page table */
|
||||||
|
mov [TRAMPOLINE_PAGE_TABLE], %eax
|
||||||
|
mov %eax, %cr3
|
||||||
|
|
||||||
|
/* Enable PAE and PSE */
|
||||||
|
mov %cr4, %eax
|
||||||
|
or $0x20, %eax /* PAE */
|
||||||
|
or $0x80, %eax /* PSE */
|
||||||
|
mov %eax, %cr4
|
||||||
|
|
||||||
|
/* Enable Long Mode */
|
||||||
|
mov $0xC0000080, %ecx
|
||||||
|
rdmsr
|
||||||
|
or $0x100, %eax /* LME */
|
||||||
|
wrmsr
|
||||||
|
|
||||||
|
/* Enable paging */
|
||||||
|
mov %cr0, %eax
|
||||||
|
or $0x80000000, %eax /* PG */
|
||||||
|
mov %eax, %cr0
|
||||||
|
|
||||||
|
/* Load Long Mode GDT */
|
||||||
|
lgdt [LongMode_gdtr - _trampoline_start + TRAMPOLINE_START]
|
||||||
|
|
||||||
|
/* Jump to Long Mode */
|
||||||
|
ljmp $0x8, $(Trampoline64 - _trampoline_start + TRAMPOLINE_START)
|
||||||
|
|
||||||
|
/* ========== 64-bit ========== */
|
||||||
|
|
||||||
|
.code64
|
||||||
|
Trampoline64:
|
||||||
|
mov $0x10, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %ss
|
||||||
|
|
||||||
|
mov $0x0, %ax
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %gs
|
||||||
|
|
||||||
|
/* Set custom GDT & IDT */
|
||||||
|
lgdt [TRAMPOLINE_GDT]
|
||||||
|
lidt [TRAMPOLINE_IDT]
|
||||||
|
|
||||||
|
/* Set up stack */
|
||||||
|
mov [TRAMPOLINE_STACK], %rsp
|
||||||
|
mov $0x0, %rbp
|
||||||
|
|
||||||
|
/* Reset RFLAGS */
|
||||||
|
push $0x0
|
||||||
|
popf
|
||||||
|
|
||||||
|
/* Jump to TrampolinePrepareExit */
|
||||||
|
call TrampolineExit
|
||||||
|
|
||||||
|
.extern StartCPU
|
||||||
|
TrampolineExit:
|
||||||
|
mov $StartCPU, %rax
|
||||||
|
call *%rax
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
ProtectedMode_gdtr:
|
||||||
|
.word ProtectedModeGDTEnd - ProtectedModeGDTStart - 1
|
||||||
|
.long ProtectedModeGDTStart - _trampoline_start + TRAMPOLINE_START
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
ProtectedModeGDTStart:
|
||||||
|
/* NULL segment */
|
||||||
|
.quad 0x0
|
||||||
|
|
||||||
|
/* Code segment */
|
||||||
|
.word 0xFFFF
|
||||||
|
.word 0x0000
|
||||||
|
.byte 0x00
|
||||||
|
.word 0xCF9A
|
||||||
|
.byte 0x00
|
||||||
|
|
||||||
|
/* Data segment */
|
||||||
|
.word 0xFFFF
|
||||||
|
.word 0x0000
|
||||||
|
.byte 0x00
|
||||||
|
.word 0xCF92
|
||||||
|
.byte 0x00
|
||||||
|
ProtectedModeGDTEnd:
|
||||||
|
nop
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
LongMode_gdtr:
|
||||||
|
.word LongModeGDTEnd - LongModeGDTStart - 1
|
||||||
|
.quad LongModeGDTStart - _trampoline_start + TRAMPOLINE_START
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
LongModeGDTStart:
|
||||||
|
/* NULL segment */
|
||||||
|
.quad 0x0
|
||||||
|
|
||||||
|
/* Code segment */
|
||||||
|
.word 0xFFFF
|
||||||
|
.word 0x0000
|
||||||
|
.byte 0x00
|
||||||
|
.word 0xAF98
|
||||||
|
.byte 0x00
|
||||||
|
|
||||||
|
/* Data segment */
|
||||||
|
.word 0xFFFF
|
||||||
|
.word 0x0000
|
||||||
|
.byte 0x00
|
||||||
|
.word 0xCF92
|
||||||
|
.byte 0x00
|
||||||
|
LongModeGDTEnd:
|
||||||
|
nop
|
||||||
|
|
||||||
|
.global _trampoline_end
|
||||||
|
_trampoline_end:
|
@ -32,13 +32,13 @@ extern "C" uint64_t _trampoline_start, _trampoline_end;
|
|||||||
/* https://wiki.osdev.org/Memory_Map_(x86) */
|
/* https://wiki.osdev.org/Memory_Map_(x86) */
|
||||||
enum SMPTrampolineAddress
|
enum SMPTrampolineAddress
|
||||||
{
|
{
|
||||||
PAGE_TABLE = 0x500,
|
PAGE_TABLE = 0x500,
|
||||||
START_ADDR = 0x520,
|
START_ADDR = 0x520,
|
||||||
STACK = 0x570,
|
STACK = 0x570,
|
||||||
GDT = 0x580,
|
GDT = 0x580,
|
||||||
IDT = 0x590,
|
IDT = 0x590,
|
||||||
CORE = 0x600,
|
CORE = 0x600,
|
||||||
TRAMPOLINE_START = 0x2000
|
TRAMPOLINE_START = 0x2000
|
||||||
};
|
};
|
||||||
|
|
||||||
std::atomic_bool CPUEnabled = false;
|
std::atomic_bool CPUEnabled = false;
|
||||||
@ -50,92 +50,106 @@ SafeFunction CPUData *GetCPU(long id) { return &CPUs[id]; }
|
|||||||
|
|
||||||
SafeFunction CPUData *GetCurrentCPU()
|
SafeFunction CPUData *GetCurrentCPU()
|
||||||
{
|
{
|
||||||
if (unlikely(!Interrupts::apic[0]))
|
if (unlikely(!Interrupts::apic[0]))
|
||||||
return &CPUs[0]; /* No APIC means we are on the BSP. */
|
return &CPUs[0]; /* No APIC means we are on the BSP. */
|
||||||
|
|
||||||
int CoreID = ((APIC::APIC *)Interrupts::apic[0])->Read(APIC::APIC_ID) >> 24;
|
int CoreID = ((APIC::APIC *)Interrupts::apic[0])->Read(APIC::APIC_ID) >> 24;
|
||||||
|
|
||||||
if (unlikely((&CPUs[CoreID])->IsActive != true))
|
if (unlikely((&CPUs[CoreID])->IsActive != true))
|
||||||
{
|
{
|
||||||
error("CPU %d is not active!", CoreID);
|
error("CPU %d is not active!", CoreID);
|
||||||
assert((&CPUs[0])->IsActive == true); /* We can't continue without the BSP. */
|
assert((&CPUs[0])->IsActive == true); /* We can't continue without the BSP. */
|
||||||
return &CPUs[0];
|
return &CPUs[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
assert((&CPUs[CoreID])->Checksum == CPU_DATA_CHECKSUM); /* This should never happen. */
|
assert((&CPUs[CoreID])->Checksum == CPU_DATA_CHECKSUM); /* This should never happen. */
|
||||||
return &CPUs[CoreID];
|
return &CPUs[CoreID];
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void StartCPU()
|
extern "C" void StartCPU()
|
||||||
{
|
{
|
||||||
CPU::Interrupts(CPU::Disable);
|
CPU::Interrupts(CPU::Disable);
|
||||||
int CoreID = (int)*reinterpret_cast<int *>(CORE);
|
int CoreID = (int)*reinterpret_cast<int *>(CORE);
|
||||||
CPU::InitializeFeatures(CoreID);
|
CPU::InitializeFeatures(CoreID);
|
||||||
// Initialize GDT and IDT
|
// Initialize GDT and IDT
|
||||||
Interrupts::Initialize(CoreID);
|
Interrupts::Initialize(CoreID);
|
||||||
Interrupts::Enable(CoreID);
|
Interrupts::Enable(CoreID);
|
||||||
Interrupts::InitializeTimer(CoreID);
|
Interrupts::InitializeTimer(CoreID);
|
||||||
asmv("mov %0, %%rsp" ::"r"((&CPUs[CoreID])->Stack));
|
asmv("mov %0, %%rsp" ::"r"((&CPUs[CoreID])->Stack));
|
||||||
|
|
||||||
CPU::Interrupts(CPU::Enable);
|
CPU::Interrupts(CPU::Enable);
|
||||||
KPrint("\e058C19CPU \e8888FF%d \e058C19is online", CoreID);
|
KPrint("\e058C19CPU \e8888FF%d \e058C19is online", CoreID);
|
||||||
CPUEnabled.store(true, std::memory_order_release);
|
CPUEnabled.store(true, std::memory_order_release);
|
||||||
CPU::Halt(true);
|
CPU::Halt(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace SMP
|
namespace SMP
|
||||||
{
|
{
|
||||||
int CPUCores = 0;
|
int CPUCores = 0;
|
||||||
|
|
||||||
void Initialize(void *madt)
|
void Initialize(void *_madt)
|
||||||
{
|
{
|
||||||
int Cores = ((ACPI::MADT *)madt)->CPUCores + 1;
|
ACPI::MADT *madt = (ACPI::MADT *)_madt;
|
||||||
|
|
||||||
if (Config.Cores > ((ACPI::MADT *)madt)->CPUCores + 1)
|
int Cores = madt->CPUCores + 1;
|
||||||
KPrint("More cores requested than available. Using %d cores", ((ACPI::MADT *)madt)->CPUCores + 1);
|
|
||||||
else if (Config.Cores != 0)
|
|
||||||
Cores = Config.Cores;
|
|
||||||
|
|
||||||
CPUCores = Cores;
|
if (Config.Cores > madt->CPUCores + 1)
|
||||||
|
KPrint("More cores requested than available. Using %d cores", madt->CPUCores + 1);
|
||||||
|
else if (Config.Cores != 0)
|
||||||
|
Cores = Config.Cores;
|
||||||
|
|
||||||
uint64_t TrampolineLength = (uintptr_t)&_trampoline_end - (uintptr_t)&_trampoline_start;
|
CPUCores = Cores;
|
||||||
Memory::Virtual().Map(0x0, 0x0, Memory::PTFlag::RW);
|
|
||||||
/* We reserved the TRAMPOLINE_START address inside Physical class. */
|
|
||||||
Memory::Virtual().Map((void *)TRAMPOLINE_START, (void *)TRAMPOLINE_START, TrampolineLength, Memory::PTFlag::RW);
|
|
||||||
memcpy((void *)TRAMPOLINE_START, &_trampoline_start, TrampolineLength);
|
|
||||||
debug("Trampoline address: %#lx-%#lx", TRAMPOLINE_START, TRAMPOLINE_START + TrampolineLength);
|
|
||||||
|
|
||||||
void *CPUTmpStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
|
uint64_t TrampolineLength = (uintptr_t)&_trampoline_end - (uintptr_t)&_trampoline_start;
|
||||||
asmv("sgdt [0x580]\n"
|
Memory::Virtual().Map(0x0, 0x0, Memory::PTFlag::RW);
|
||||||
"sidt [0x590]\n");
|
/* We reserved the TRAMPOLINE_START address inside Physical class. */
|
||||||
VPOKE(uintptr_t, STACK) = (uintptr_t)CPUTmpStack + STACK_SIZE;
|
Memory::Virtual().Map((void *)TRAMPOLINE_START, (void *)TRAMPOLINE_START, TrampolineLength, Memory::PTFlag::RW);
|
||||||
VPOKE(uintptr_t, PAGE_TABLE) = (uintptr_t)KernelPageTable;
|
memcpy((void *)TRAMPOLINE_START, &_trampoline_start, TrampolineLength);
|
||||||
VPOKE(uint64_t, START_ADDR) = (uintptr_t)&StartCPU;
|
debug("Trampoline address: %#lx-%#lx", TRAMPOLINE_START, TRAMPOLINE_START + TrampolineLength);
|
||||||
|
|
||||||
for (int i = 0; i < Cores; i++)
|
void *CPUTmpStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
|
||||||
{
|
asmv("sgdt [0x580]");
|
||||||
debug("Initializing CPU %d", i);
|
asmv("sidt [0x590]");
|
||||||
if ((((APIC::APIC *)Interrupts::apic[0])->Read(APIC::APIC_ID) >> 24) != ((ACPI::MADT *)madt)->lapic[i]->ACPIProcessorId)
|
VPOKE(uintptr_t, STACK) = (uintptr_t)CPUTmpStack + STACK_SIZE;
|
||||||
{
|
VPOKE(uintptr_t, PAGE_TABLE) = (uintptr_t)KernelPageTable;
|
||||||
VPOKE(int, CORE) = i;
|
VPOKE(uintptr_t, START_ADDR) = (uintptr_t)&StartCPU;
|
||||||
|
|
||||||
((APIC::APIC *)Interrupts::apic[0])->Write(APIC::APIC_ICRHI, (((ACPI::MADT *)madt)->lapic[i]->APICId << 24));
|
for (int i = 0; i < Cores; i++)
|
||||||
((APIC::APIC *)Interrupts::apic[0])->Write(APIC::APIC_ICRLO, 0x500);
|
{
|
||||||
|
ACPI::MADT::LocalAPIC *lapic = madt->lapic[i];
|
||||||
|
debug("Initializing CPU %d", lapic->APICId);
|
||||||
|
if ((((APIC::APIC *)Interrupts::apic[0])->Read(APIC::APIC_ID) >> 24) != lapic->APICId)
|
||||||
|
{
|
||||||
|
VPOKE(int, CORE) = i;
|
||||||
|
|
||||||
((APIC::APIC *)Interrupts::apic[0])->SendInitIPI(((ACPI::MADT *)madt)->lapic[i]->APICId);
|
((APIC::APIC *)Interrupts::apic[0])->Write(APIC::APIC_ICRHI, (lapic->APICId << 24));
|
||||||
((APIC::APIC *)Interrupts::apic[0])->SendStartupIPI(((ACPI::MADT *)madt)->lapic[i]->APICId, TRAMPOLINE_START);
|
((APIC::APIC *)Interrupts::apic[0])->Write(APIC::APIC_ICRLO, 0x500);
|
||||||
|
|
||||||
while (!CPUEnabled.load(std::memory_order_acquire))
|
((APIC::APIC *)Interrupts::apic[0])->SendInitIPI(lapic->APICId);
|
||||||
CPU::Pause();
|
TimeManager->Sleep(5, Time::Units::Milliseconds);
|
||||||
CPUEnabled.store(false, std::memory_order_release);
|
((APIC::APIC *)Interrupts::apic[0])->SendStartupIPI(lapic->APICId, TRAMPOLINE_START);
|
||||||
trace("CPU %d loaded.", ((ACPI::MADT *)madt)->lapic[i]->APICId);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
KPrint("\e058C19CPU \e8888FF%d \e058C19is the BSP", ((ACPI::MADT *)madt)->lapic[i]->APICId);
|
|
||||||
}
|
|
||||||
|
|
||||||
KernelAllocator.FreePages(CPUTmpStack, TO_PAGES(STACK_SIZE + 1));
|
debug("Waiting for CPU %d to load...", lapic->APICId);
|
||||||
/* We are going to unmap the page after we are done with it. */
|
uint64_t Timeout = TimeManager->CalculateTarget(2, Time::Units::Seconds);
|
||||||
Memory::Virtual().Unmap(0x0);
|
while (CPUEnabled.load(std::memory_order_acquire) == false)
|
||||||
}
|
{
|
||||||
|
if (TimeManager->GetCounter() > Timeout)
|
||||||
|
{
|
||||||
|
error("CPU %d failed to load!", lapic->APICId);
|
||||||
|
KPrint("\eFF8C19CPU \e8888FF%d \eFF8C19failed to load!", lapic->APICId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CPU::Pause();
|
||||||
|
}
|
||||||
|
trace("CPU %d loaded.", lapic->APICId);
|
||||||
|
CPUEnabled.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
KPrint("\e058C19CPU \e8888FF%d \e058C19is the BSP", lapic->APICId);
|
||||||
|
}
|
||||||
|
|
||||||
|
KernelAllocator.FreePages(CPUTmpStack, TO_PAGES(STACK_SIZE + 1));
|
||||||
|
/* We are going to unmap the page after we are done with it. */
|
||||||
|
Memory::Virtual().Unmap(0x0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
; This file is part of Fennix Kernel.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
; modify it under the terms of the GNU General Public License as
|
|
||||||
; published by the Free Software Foundation, either version 3 of
|
|
||||||
; the License, or (at your option) any later version.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
; GNU General Public License for more details.
|
|
||||||
;
|
|
||||||
; You should have received a copy of the GNU General Public License
|
|
||||||
; along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
[bits 32]
|
|
||||||
|
|
||||||
section .bootstrap.text
|
|
||||||
|
|
||||||
global Multiboot1_start
|
|
||||||
Multiboot1_start:
|
|
||||||
int3
|
|
@ -15,6 +15,9 @@
|
|||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.intel_syntax noprefix
|
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
|
.section .bootstrap.text
|
||||||
|
|
||||||
|
.global Multiboot1_start
|
||||||
|
Multiboot1_start:
|
||||||
|
jmp .
|
@ -1,46 +0,0 @@
|
|||||||
; This file is part of Fennix Kernel.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
; modify it under the terms of the GNU General Public License as
|
|
||||||
; published by the Free Software Foundation, either version 3 of
|
|
||||||
; the License, or (at your option) any later version.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
; GNU General Public License for more details.
|
|
||||||
;
|
|
||||||
; You should have received a copy of the GNU General Public License
|
|
||||||
; along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
[bits 32]
|
|
||||||
|
|
||||||
KERNEL_VIRTUAL_BASE equ 0xC0000000 ; 3GB or 0xC0000000
|
|
||||||
KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22) ; 768
|
|
||||||
|
|
||||||
section .bootstrap.data
|
|
||||||
align 0x1000
|
|
||||||
global BootPageTable
|
|
||||||
BootPageTable:
|
|
||||||
dd 0x00000083
|
|
||||||
dd 0x00400083
|
|
||||||
dd 0x00800083
|
|
||||||
dd 0x00C00083
|
|
||||||
dd 0x01000083
|
|
||||||
dd 0x01400083
|
|
||||||
dd 0x01800083
|
|
||||||
dd 0x01C00083
|
|
||||||
dd 0x02000083
|
|
||||||
dd 0x02400083
|
|
||||||
times (KERNEL_PAGE_NUMBER - 10) dd 0
|
|
||||||
dd 0x00000083
|
|
||||||
dd 0x00400083
|
|
||||||
dd 0x00800083
|
|
||||||
dd 0x00C00083
|
|
||||||
dd 0x01000083
|
|
||||||
dd 0x01400083
|
|
||||||
dd 0x01800083
|
|
||||||
dd 0x01C00083
|
|
||||||
dd 0x02000083
|
|
||||||
dd 0x02400083
|
|
||||||
times (1024 - KERNEL_PAGE_NUMBER - 10) dd 0
|
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
This file is part of Fennix Kernel.
|
||||||
|
|
||||||
|
Fennix Kernel is free software: you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of
|
||||||
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
Fennix Kernel is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.code32
|
||||||
|
KERNEL_VIRTUAL_BASE = 0xC0000000 /* 3GB */
|
||||||
|
KERNEL_PAGE_NUMBER = 768 /* KERNEL_VIRTUAL_BASE >> 22 */
|
||||||
|
|
||||||
|
.section .bootstrap.data
|
||||||
|
.align 0x1000
|
||||||
|
.global BootPageTable
|
||||||
|
BootPageTable:
|
||||||
|
.long 0x00000083
|
||||||
|
.long 0x00400083
|
||||||
|
.long 0x00800083
|
||||||
|
.long 0x00C00083
|
||||||
|
.long 0x01000083
|
||||||
|
.long 0x01400083
|
||||||
|
.long 0x01800083
|
||||||
|
.long 0x01C00083
|
||||||
|
.long 0x02000083
|
||||||
|
.long 0x02400083
|
||||||
|
.rept (KERNEL_PAGE_NUMBER - 10)
|
||||||
|
.long 0
|
||||||
|
.endr
|
||||||
|
.long 0x00000083
|
||||||
|
.long 0x00400083
|
||||||
|
.long 0x00800083
|
||||||
|
.long 0x00C00083
|
||||||
|
.long 0x01000083
|
||||||
|
.long 0x01400083
|
||||||
|
.long 0x01800083
|
||||||
|
.long 0x01C00083
|
||||||
|
.long 0x02000083
|
||||||
|
.long 0x02400083
|
||||||
|
.rept (1024 - KERNEL_PAGE_NUMBER - 10)
|
||||||
|
.long 0
|
||||||
|
.endr
|
@ -1,86 +0,0 @@
|
|||||||
; This file is part of Fennix Kernel.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
; modify it under the terms of the GNU General Public License as
|
|
||||||
; published by the Free Software Foundation, either version 3 of
|
|
||||||
; the License, or (at your option) any later version.
|
|
||||||
;
|
|
||||||
; Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
; GNU General Public License for more details.
|
|
||||||
;
|
|
||||||
; You should have received a copy of the GNU General Public License
|
|
||||||
; along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
[bits 32]
|
|
||||||
KERNEL_STACK_SIZE equ 0x4000 ; 16KB
|
|
||||||
|
|
||||||
extern DetectCPUID
|
|
||||||
extern Detect64Bit
|
|
||||||
extern DetectPSE
|
|
||||||
extern DetectPAE
|
|
||||||
extern multiboot_main
|
|
||||||
extern LoadGDT32
|
|
||||||
extern BootPageTable
|
|
||||||
|
|
||||||
section .bootstrap.data
|
|
||||||
MB_HeaderMagic:
|
|
||||||
dq 0
|
|
||||||
|
|
||||||
MB_HeaderInfo:
|
|
||||||
dq 0
|
|
||||||
|
|
||||||
section .bootstrap.text
|
|
||||||
|
|
||||||
global Multiboot2_start
|
|
||||||
Multiboot2_start:
|
|
||||||
cli
|
|
||||||
|
|
||||||
mov [MB_HeaderMagic], eax
|
|
||||||
mov [MB_HeaderInfo], ebx
|
|
||||||
|
|
||||||
call DetectCPUID
|
|
||||||
cmp eax, 0
|
|
||||||
je $
|
|
||||||
|
|
||||||
; call Detect64Bit
|
|
||||||
; cmp eax, 0
|
|
||||||
; je $
|
|
||||||
|
|
||||||
call DetectPSE
|
|
||||||
cmp eax, 0
|
|
||||||
je $
|
|
||||||
|
|
||||||
; call DetectPAE
|
|
||||||
; cmp eax, 0
|
|
||||||
; je $
|
|
||||||
|
|
||||||
mov ecx, cr4
|
|
||||||
or ecx, 0x00000010 ; Set PSE in CR4
|
|
||||||
; or ecx, 0x00000020 ; Set PAE in CR4
|
|
||||||
mov cr4, ecx
|
|
||||||
|
|
||||||
call LoadGDT32
|
|
||||||
|
|
||||||
mov ecx, BootPageTable
|
|
||||||
mov cr3, ecx
|
|
||||||
|
|
||||||
mov ecx, cr0
|
|
||||||
or ecx, 0x80000001 ; Set PG and PE in CR0
|
|
||||||
mov cr0, ecx
|
|
||||||
|
|
||||||
mov esp, KernelStack + KERNEL_STACK_SIZE
|
|
||||||
mov eax, [MB_HeaderMagic]
|
|
||||||
mov ebx, [MB_HeaderInfo]
|
|
||||||
push ebx
|
|
||||||
push eax
|
|
||||||
call multiboot_main
|
|
||||||
.Hang:
|
|
||||||
hlt
|
|
||||||
jmp .Hang
|
|
||||||
|
|
||||||
section .bootstrap.bss
|
|
||||||
align 16
|
|
||||||
KernelStack:
|
|
||||||
resb KERNEL_STACK_SIZE
|
|
79
Architecture/i386/Bootstrap/Multiboot/2/Start.s
Normal file
79
Architecture/i386/Bootstrap/Multiboot/2/Start.s
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
This file is part of Fennix Kernel.
|
||||||
|
|
||||||
|
Fennix Kernel is free software: you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of
|
||||||
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
Fennix Kernel is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.code32
|
||||||
|
KERNEL_STACK_SIZE = 0x4000 /* 16KB */
|
||||||
|
|
||||||
|
.extern DetectCPUID
|
||||||
|
.extern DetectPSE
|
||||||
|
.extern multiboot_main
|
||||||
|
.extern LoadGDT32
|
||||||
|
.extern BootPageTable
|
||||||
|
|
||||||
|
.section .bootstrap.data
|
||||||
|
MB_HeaderMagic:
|
||||||
|
.quad 0
|
||||||
|
|
||||||
|
MB_HeaderInfo:
|
||||||
|
.quad 0
|
||||||
|
|
||||||
|
.section .bootstrap.text
|
||||||
|
|
||||||
|
.global Multiboot2_start
|
||||||
|
Multiboot2_start:
|
||||||
|
cli
|
||||||
|
|
||||||
|
mov %eax, [MB_HeaderMagic]
|
||||||
|
mov %ebx, [MB_HeaderInfo]
|
||||||
|
|
||||||
|
call DetectCPUID
|
||||||
|
cmp $0, %eax
|
||||||
|
je .
|
||||||
|
|
||||||
|
call DetectPSE
|
||||||
|
cmp $0, %eax
|
||||||
|
je .
|
||||||
|
|
||||||
|
mov %cr4, %ecx
|
||||||
|
or $0x00000010, %ecx /* PSE */
|
||||||
|
mov %ecx, %cr4
|
||||||
|
|
||||||
|
call LoadGDT32
|
||||||
|
|
||||||
|
mov $BootPageTable, %ecx
|
||||||
|
mov %ecx, %cr3
|
||||||
|
|
||||||
|
mov %cr0, %ecx
|
||||||
|
or $0x80000000, %ecx /* PG */
|
||||||
|
mov %ecx, %cr0
|
||||||
|
|
||||||
|
mov $(KernelStack + KERNEL_STACK_SIZE), %esp
|
||||||
|
mov $0x0, %ebp
|
||||||
|
|
||||||
|
mov [MB_HeaderMagic], %eax
|
||||||
|
mov [MB_HeaderInfo], %ebx
|
||||||
|
push %ebx
|
||||||
|
push %eax
|
||||||
|
call multiboot_main
|
||||||
|
.Hang:
|
||||||
|
hlt
|
||||||
|
jmp .Hang
|
||||||
|
|
||||||
|
.section .bootstrap.bss
|
||||||
|
.align 16
|
||||||
|
KernelStack:
|
||||||
|
.space KERNEL_STACK_SIZE
|
29
Makefile
29
Makefile
@ -11,8 +11,6 @@ NM = ../$(COMPILER_PATH)/$(COMPILER_ARCH)nm
|
|||||||
OBJCOPY = ../$(COMPILER_PATH)/$(COMPILER_ARCH)objcopy
|
OBJCOPY = ../$(COMPILER_PATH)/$(COMPILER_ARCH)objcopy
|
||||||
OBJDUMP = ../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
|
OBJDUMP = ../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
|
||||||
GDB = ../$(COMPILER_PATH)/$(COMPILER_ARCH)gdb
|
GDB = ../$(COMPILER_PATH)/$(COMPILER_ARCH)gdb
|
||||||
RUSTC = /usr/bin/rustc
|
|
||||||
NASM = /usr/bin/nasm
|
|
||||||
|
|
||||||
RUST_TARGET_PATH = Architecture/$(OSARCH)/rust-target.json
|
RUST_TARGET_PATH = Architecture/$(OSARCH)/rust-target.json
|
||||||
|
|
||||||
@ -22,19 +20,16 @@ GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD)
|
|||||||
BMP_SOURCES = $(shell find ./ -type f -name '*.bmp')
|
BMP_SOURCES = $(shell find ./ -type f -name '*.bmp')
|
||||||
PSF_SOURCES = $(shell find ./ -type f -name '*.psf')
|
PSF_SOURCES = $(shell find ./ -type f -name '*.psf')
|
||||||
ifeq ($(OSARCH), amd64)
|
ifeq ($(OSARCH), amd64)
|
||||||
ASM_SOURCES = $(shell find ./ -type f -name '*.asm' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*")
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*")
|
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*")
|
||||||
s_SOURCES = $(shell find ./ -type f -name '*.s' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*")
|
s_SOURCES = $(shell find ./ -type f -name '*.s' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*")
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*")
|
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*")
|
||||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*")
|
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*")
|
||||||
else ifeq ($(OSARCH), i386)
|
else ifeq ($(OSARCH), i386)
|
||||||
ASM_SOURCES = $(shell find ./ -type f -name '*.asm' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*")
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*")
|
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*")
|
||||||
s_SOURCES = $(shell find ./ -type f -name '*.s' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*")
|
s_SOURCES = $(shell find ./ -type f -name '*.s' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*")
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*")
|
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*")
|
||||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*")
|
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*")
|
||||||
else ifeq ($(OSARCH), aarch64)
|
else ifeq ($(OSARCH), aarch64)
|
||||||
ASM_SOURCES = $(shell find ./ -type f -name '*.asm' -not -path "./Architecture/amd64/*" -not -path "./Architecture/i386/*")
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./Architecture/amd64/*" -not -path "./Architecture/i386/*")
|
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./Architecture/amd64/*" -not -path "./Architecture/i386/*")
|
||||||
s_SOURCES = $(shell find ./ -type f -name '*.s' -not -path "./Architecture/amd64/*" -not -path "./Architecture/i386/*")
|
s_SOURCES = $(shell find ./ -type f -name '*.s' -not -path "./Architecture/amd64/*" -not -path "./Architecture/i386/*")
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./Architecture/amd64/*" -not -path "./Architecture/i386/*")
|
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./Architecture/amd64/*" -not -path "./Architecture/i386/*")
|
||||||
@ -98,14 +93,6 @@ LDFLAGS += -TArchitecture/aarch64/linker.ld -fPIC -pie \
|
|||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(OSARCH), amd64)
|
|
||||||
NASMFLAGS := -f elf64
|
|
||||||
else ifeq ($(OSARCH), i386)
|
|
||||||
NASMFLAGS := -f elf32
|
|
||||||
else ifeq ($(OSARCH), aarch64)
|
|
||||||
NASMFLAGS :=
|
|
||||||
endif
|
|
||||||
|
|
||||||
# -finstrument-functions for __cyg_profile_func_enter & __cyg_profile_func_exit. Used for profiling and debugging.
|
# -finstrument-functions for __cyg_profile_func_enter & __cyg_profile_func_exit. Used for profiling and debugging.
|
||||||
ifeq ($(DEBUG), 1)
|
ifeq ($(DEBUG), 1)
|
||||||
# CFLAGS += --coverage
|
# CFLAGS += --coverage
|
||||||
@ -119,11 +106,8 @@ ifneq ($(OSARCH), aarch64)
|
|||||||
CFLAGS += -fstack-check
|
CFLAGS += -fstack-check
|
||||||
endif
|
endif
|
||||||
LDFLAGS += -ggdb3 -O0
|
LDFLAGS += -ggdb3 -O0
|
||||||
NASMFLAGS += -F dwarf -g
|
ASFLAGS += -g --gstabs --gdwarf-5 -D
|
||||||
WARNCFLAG += -Wno-unused-function -Wno-maybe-uninitialized -Wno-builtin-declaration-mismatch -Wno-unknown-pragmas -Wno-unused-parameter -Wno-unused-variable
|
WARNCFLAG += -Wno-unused-function -Wno-maybe-uninitialized -Wno-builtin-declaration-mismatch -Wno-unknown-pragmas -Wno-unused-parameter -Wno-unused-variable
|
||||||
ifeq ($(TESTING), 1)
|
|
||||||
CFLAGS += -DTESTING
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -156,20 +140,13 @@ $(KERNEL_FILENAME): $(OBJ)
|
|||||||
$(info Compiling $<)
|
$(info Compiling $<)
|
||||||
$(CPP) $(CFLAGS) $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c++20 -c $< -o $@ -fno-exceptions -fno-rtti
|
$(CPP) $(CFLAGS) $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c++20 -c $< -o $@ -fno-exceptions -fno-rtti
|
||||||
|
|
||||||
%.o: %.asm
|
|
||||||
ifeq ($(OSARCH), aarch64)
|
|
||||||
$(error aarch64 does not support NASM)
|
|
||||||
endif
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(NASM) $< $(NASMFLAGS) -o $@
|
|
||||||
|
|
||||||
%.o: %.S
|
%.o: %.S
|
||||||
$(info Compiling $<)
|
$(info Compiling $<)
|
||||||
$(AS) -c $< -o $@
|
$(AS) $(ASFLAGS) -c $< -o $@
|
||||||
|
|
||||||
%.o: %.s
|
%.o: %.s
|
||||||
$(info Compiling $<)
|
$(info Compiling $<)
|
||||||
$(AS) -c $< -o $@
|
$(AS) $(ASFLAGS) -c $< -o $@
|
||||||
|
|
||||||
%.o: %.psf
|
%.o: %.psf
|
||||||
ifeq ($(OSARCH), amd64)
|
ifeq ($(OSARCH), amd64)
|
||||||
|
@ -139,7 +139,7 @@ namespace CPU
|
|||||||
/**
|
/**
|
||||||
* @brief Pause the CPU
|
* @brief Pause the CPU
|
||||||
*/
|
*/
|
||||||
SafeFunction static inline void Pause(bool Loop = false)
|
SafeFunction static __always_inline inline void Pause(bool Loop = false)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -166,15 +166,15 @@ namespace CPU
|
|||||||
{
|
{
|
||||||
asmv("CPUStopLoop:\n"
|
asmv("CPUStopLoop:\n"
|
||||||
"msr daifset, #2\n" // Disable IRQs (bit 1 of the DAIF register)
|
"msr daifset, #2\n" // Disable IRQs (bit 1 of the DAIF register)
|
||||||
"wfi\n" // Wait for Interrupt (puts the processor in low-power state until an interrupt occurs)
|
"wfi\n" // Wait for Interrupt (puts the processor in low-power state until an interrupt occurs)
|
||||||
"b CPUStopLoop"); // Branch to the beginning of the loop
|
"b CPUStopLoop"); // Branch to the beginning of the loop
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Halt the CPU
|
* @brief Halt the CPU
|
||||||
*/
|
*/
|
||||||
SafeFunction static inline void Halt(bool Loop = false)
|
SafeFunction static __always_inline inline void Halt(bool Loop = false)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -206,7 +206,7 @@ namespace CPU
|
|||||||
void InitializeFeatures(long Core);
|
void InitializeFeatures(long Core);
|
||||||
|
|
||||||
/** @brief Get CPU counter value. */
|
/** @brief Get CPU counter value. */
|
||||||
uintptr_t Counter();
|
uint64_t Counter();
|
||||||
|
|
||||||
namespace x32
|
namespace x32
|
||||||
{
|
{
|
||||||
@ -280,7 +280,7 @@ namespace CPU
|
|||||||
uint32_t eax; // Accumulator
|
uint32_t eax; // Accumulator
|
||||||
|
|
||||||
uint32_t InterruptNumber; // Interrupt Number
|
uint32_t InterruptNumber; // Interrupt Number
|
||||||
uint32_t ErrorCode; // Error code
|
uint32_t ErrorCode; // Error code
|
||||||
|
|
||||||
uint32_t eip; // Instruction Pointer
|
uint32_t eip; // Instruction Pointer
|
||||||
uint32_t cs; // Code Segment
|
uint32_t cs; // Code Segment
|
||||||
@ -598,7 +598,7 @@ namespace CPU
|
|||||||
uint64_t rax; // Accumulator
|
uint64_t rax; // Accumulator
|
||||||
|
|
||||||
uint64_t InterruptNumber; // Interrupt Number
|
uint64_t InterruptNumber; // Interrupt Number
|
||||||
uint64_t ErrorCode; // Error code
|
uint64_t ErrorCode; // Error code
|
||||||
|
|
||||||
uint64_t rip; // Instruction Pointer
|
uint64_t rip; // Instruction Pointer
|
||||||
uint64_t cs; // Code Segment
|
uint64_t cs; // Code Segment
|
||||||
@ -911,9 +911,9 @@ namespace CPU
|
|||||||
uint64_t x29; // Frame pointer
|
uint64_t x29; // Frame pointer
|
||||||
uint64_t x30; // Program counter
|
uint64_t x30; // Program counter
|
||||||
|
|
||||||
uint64_t sp_el0; // Stack pointer
|
uint64_t sp_el0; // Stack pointer
|
||||||
uint64_t elr_el1; // Exception Link Register
|
uint64_t elr_el1; // Exception Link Register
|
||||||
uint64_t spsr_el1; // Saved Program Status Register
|
uint64_t spsr_el1; // Saved Program Status Register
|
||||||
uint64_t ErrorCode /* esr_el1 */; // Exception Syndrome Register
|
uint64_t ErrorCode /* esr_el1 */; // Exception Syndrome Register
|
||||||
|
|
||||||
uint64_t InterruptNumber /* iar_el1 */; // Interrupt Acknowledge Register
|
uint64_t InterruptNumber /* iar_el1 */; // Interrupt Acknowledge Register
|
||||||
|
Loading…
x
Reference in New Issue
Block a user