Added bios loader
parent
b2653f5f55
commit
ff9dae24ff
|
@ -0,0 +1,31 @@
|
|||
sectalign off
|
||||
|
||||
; stage 1 is sector 0, loaded at 0x7C00
|
||||
%include "stage1.asm"
|
||||
|
||||
; GPT area from sector 1 to 33, loaded at 0x7E00
|
||||
times (33*512) db 0
|
||||
|
||||
; stage 2, loaded at 0xC000
|
||||
stage2:
|
||||
%include "stage2.asm"
|
||||
align 512, db 0
|
||||
stage2.end:
|
||||
|
||||
; the maximum size of stage2 is 4 KiB
|
||||
times (4*1024)-($-stage2) db 0
|
||||
|
||||
; ISO compatibility, uses up space until 0x12400
|
||||
%include "iso.asm"
|
||||
|
||||
times 3072 db 0 ; Pad to 0x13000
|
||||
|
||||
; stage3, loaded at 0x13000
|
||||
stage3:
|
||||
; %defstr STAGE3_STR %[STAGE3]
|
||||
; incbin STAGE3_STR
|
||||
; align 512, db 0
|
||||
.end:
|
||||
|
||||
; the maximum size of the boot loader portion is 384 KiB
|
||||
times (384*1024)-($-$$) db 0
|
|
@ -0,0 +1,176 @@
|
|||
SECTION .text
|
||||
USE16
|
||||
|
||||
cpuid_required_features:
|
||||
.edx equ cpuid_edx.fpu | cpuid_edx.pse | cpuid_edx.pge | cpuid_edx.fxsr
|
||||
.ecx equ 0
|
||||
|
||||
cpuid_check:
|
||||
; If bit 21 of EFLAGS can be changed, then CPUID is supported
|
||||
pushfd ;Save EFLAGS
|
||||
pushfd ;Store EFLAGS
|
||||
xor dword [esp],0x00200000 ;Invert the ID bit in stored EFLAGS
|
||||
popfd ;Load stored EFLAGS (with ID bit inverted)
|
||||
pushfd ;Store EFLAGS again (ID bit may or may not be inverted)
|
||||
pop eax ;eax = modified EFLAGS (ID bit may or may not be inverted)
|
||||
xor eax,[esp] ;eax = whichever bits were changed
|
||||
popfd ;Restore original EFLAGS
|
||||
test eax,0x00200000 ;eax = zero if ID bit can't be changed, else non-zero
|
||||
jz .no_cpuid
|
||||
|
||||
mov eax, 1
|
||||
cpuid
|
||||
|
||||
and edx, cpuid_required_features.edx
|
||||
cmp edx, cpuid_required_features.edx
|
||||
jne .error
|
||||
|
||||
and ecx, cpuid_required_features.ecx
|
||||
cmp ecx, cpuid_required_features.ecx
|
||||
jne .error
|
||||
|
||||
ret
|
||||
|
||||
.no_cpuid:
|
||||
mov si, .msg_cpuid
|
||||
call print
|
||||
|
||||
mov si, .msg_line
|
||||
call print
|
||||
|
||||
jmp .halt
|
||||
|
||||
.error:
|
||||
push ecx
|
||||
push edx
|
||||
|
||||
mov si, .msg_features
|
||||
call print
|
||||
|
||||
mov si, .msg_line
|
||||
call print
|
||||
|
||||
mov si, .msg_edx
|
||||
call print
|
||||
|
||||
pop ebx
|
||||
push ebx
|
||||
shr ebx, 16
|
||||
call print_hex
|
||||
|
||||
pop ebx
|
||||
call print_hex
|
||||
|
||||
mov si, .msg_must_contain
|
||||
call print
|
||||
|
||||
mov ebx, cpuid_required_features.edx
|
||||
shr ebx, 16
|
||||
call print_hex
|
||||
|
||||
mov ebx, cpuid_required_features.edx
|
||||
call print_hex
|
||||
|
||||
mov si, .msg_line
|
||||
call print
|
||||
|
||||
mov si, .msg_ecx
|
||||
call print
|
||||
|
||||
pop ebx
|
||||
push ebx
|
||||
shr ebx, 16
|
||||
call print_hex
|
||||
|
||||
pop ebx
|
||||
call print_hex
|
||||
|
||||
mov si, .msg_must_contain
|
||||
call print
|
||||
|
||||
mov ebx, cpuid_required_features.ecx
|
||||
shr ebx, 16
|
||||
call print_hex
|
||||
|
||||
mov ebx, cpuid_required_features.ecx
|
||||
call print_hex
|
||||
|
||||
mov si, .msg_line
|
||||
call print
|
||||
|
||||
.halt:
|
||||
cli
|
||||
hlt
|
||||
jmp .halt
|
||||
|
||||
.msg_cpuid: db "CPUID not supported",0
|
||||
.msg_features: db "Required CPU features are not present",0
|
||||
.msg_line: db 13,10,0
|
||||
.msg_edx: db "EDX ",0
|
||||
.msg_ecx: db "ECX ",0
|
||||
.msg_must_contain: db " must contain ",0
|
||||
|
||||
cpuid_edx:
|
||||
.fpu equ 1 << 0
|
||||
.vme equ 1 << 1
|
||||
.de equ 1 << 2
|
||||
.pse equ 1 << 3
|
||||
.tsc equ 1 << 4
|
||||
.msr equ 1 << 5
|
||||
.pae equ 1 << 6
|
||||
.mce equ 1 << 7
|
||||
.cx8 equ 1 << 8
|
||||
.apic equ 1 << 9
|
||||
.sep equ 1 << 11
|
||||
.mtrr equ 1 << 12
|
||||
.pge equ 1 << 13
|
||||
.mca equ 1 << 14
|
||||
.cmov equ 1 << 15
|
||||
.pat equ 1 << 16
|
||||
.pse_36 equ 1 << 17
|
||||
.psn equ 1 << 18
|
||||
.clfsh equ 1 << 19
|
||||
.ds equ 1 << 21
|
||||
.acpi equ 1 << 22
|
||||
.mmx equ 1 << 23
|
||||
.fxsr equ 1 << 24
|
||||
.sse equ 1 << 25
|
||||
.sse2 equ 1 << 26
|
||||
.ss equ 1 << 27
|
||||
.htt equ 1 << 28
|
||||
.tm equ 1 << 29
|
||||
.ia64 equ 1 << 30
|
||||
.pbe equ 1 << 31
|
||||
|
||||
cpuid_ecx:
|
||||
.sse3 equ 1 << 0
|
||||
.pclmulqdq equ 1 << 1
|
||||
.dtes64 equ 1 << 2
|
||||
.monitor equ 1 << 3
|
||||
.ds_cpl equ 1 << 4
|
||||
.vmx equ 1 << 5
|
||||
.smx equ 1 << 6
|
||||
.est equ 1 << 7
|
||||
.tm2 equ 1 << 8
|
||||
.ssse3 equ 1 << 9
|
||||
.cnxt_id equ 1 << 10
|
||||
.sdbg equ 1 << 11
|
||||
.fma equ 1 << 12
|
||||
.cmpxchg16b equ 1 << 13
|
||||
.xtpr equ 1 << 14
|
||||
.pdcm equ 1 << 15
|
||||
.pcid equ 1 << 17
|
||||
.dca equ 1 << 18
|
||||
.sse4_1 equ 1 << 19
|
||||
.sse4_2 equ 1 << 20
|
||||
.x2apic equ 1 << 21
|
||||
.movbe equ 1 << 22
|
||||
.popcnt equ 1 << 23
|
||||
.tsc_deadline equ 1 << 24
|
||||
.aes equ 1 << 25
|
||||
.xsave equ 1 << 26
|
||||
.osxsave equ 1 << 27
|
||||
.avx equ 1 << 28
|
||||
.f16c equ 1 << 29
|
||||
.rdrand equ 1 << 30
|
||||
.hypervisor equ 1 << 31
|
|
@ -0,0 +1,128 @@
|
|||
SECTION .text ; cannot use .data
|
||||
|
||||
struc GDTEntry
|
||||
.limitl resw 1
|
||||
.basel resw 1
|
||||
.basem resb 1
|
||||
.attribute resb 1
|
||||
.flags__limith resb 1
|
||||
.baseh resb 1
|
||||
endstruc
|
||||
|
||||
gdt_attr:
|
||||
.present equ 1 << 7
|
||||
.ring1 equ 1 << 5
|
||||
.ring2 equ 1 << 6
|
||||
.ring3 equ 1 << 5 | 1 << 6
|
||||
.user equ 1 << 4
|
||||
;user
|
||||
.code equ 1 << 3
|
||||
; code
|
||||
.conforming equ 1 << 2
|
||||
.readable equ 1 << 1
|
||||
; data
|
||||
.expand_down equ 1 << 2
|
||||
.writable equ 1 << 1
|
||||
.accessed equ 1 << 0
|
||||
;system
|
||||
; legacy
|
||||
.tssAvailabe16 equ 0x1
|
||||
.ldt equ 0x2
|
||||
.tssBusy16 equ 0x3
|
||||
.call16 equ 0x4
|
||||
.task equ 0x5
|
||||
.interrupt16 equ 0x6
|
||||
.trap16 equ 0x7
|
||||
.tssAvailabe32 equ 0x9
|
||||
.tssBusy32 equ 0xB
|
||||
.call32 equ 0xC
|
||||
.interrupt32 equ 0xE
|
||||
.trap32 equ 0xF
|
||||
; long mode
|
||||
.ldt32 equ 0x2
|
||||
.tssAvailabe64 equ 0x9
|
||||
.tssBusy64 equ 0xB
|
||||
.call64 equ 0xC
|
||||
.interrupt64 equ 0xE
|
||||
.trap64 equ 0xF
|
||||
|
||||
gdt_flag:
|
||||
.granularity equ 1 << 7
|
||||
.available equ 1 << 4
|
||||
;user
|
||||
.default_operand_size equ 1 << 6
|
||||
; code
|
||||
.long_mode equ 1 << 5
|
||||
; data
|
||||
.reserved equ 1 << 5
|
||||
|
||||
gdtr:
|
||||
dw gdt.end + 1 ; size
|
||||
dq gdt ; offset
|
||||
|
||||
gdt:
|
||||
.null equ $ - gdt
|
||||
dq 0
|
||||
|
||||
.lm64_code equ $ - gdt
|
||||
istruc GDTEntry
|
||||
at GDTEntry.limitl, dw 0
|
||||
at GDTEntry.basel, dw 0
|
||||
at GDTEntry.basem, db 0
|
||||
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.code
|
||||
at GDTEntry.flags__limith, db gdt_flag.long_mode
|
||||
at GDTEntry.baseh, db 0
|
||||
iend
|
||||
|
||||
.lm64_data equ $ - gdt
|
||||
istruc GDTEntry
|
||||
at GDTEntry.limitl, dw 0
|
||||
at GDTEntry.basel, dw 0
|
||||
at GDTEntry.basem, db 0
|
||||
; AMD System Programming Manual states that the writeable bit is ignored in long mode, but ss can not be set to this descriptor without it
|
||||
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.writable
|
||||
at GDTEntry.flags__limith, db 0
|
||||
at GDTEntry.baseh, db 0
|
||||
iend
|
||||
|
||||
.pm32_code equ $ - gdt
|
||||
istruc GDTEntry
|
||||
at GDTEntry.limitl, dw 0xFFFF
|
||||
at GDTEntry.basel, dw 0
|
||||
at GDTEntry.basem, db 0
|
||||
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.code | gdt_attr.readable
|
||||
at GDTEntry.flags__limith, db 0xF | gdt_flag.granularity | gdt_flag.default_operand_size
|
||||
at GDTEntry.baseh, db 0
|
||||
iend
|
||||
|
||||
.pm32_data equ $ - gdt
|
||||
istruc GDTEntry
|
||||
at GDTEntry.limitl, dw 0xFFFF
|
||||
at GDTEntry.basel, dw 0
|
||||
at GDTEntry.basem, db 0
|
||||
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.writable
|
||||
at GDTEntry.flags__limith, db 0xF | gdt_flag.granularity | gdt_flag.default_operand_size
|
||||
at GDTEntry.baseh, db 0
|
||||
iend
|
||||
|
||||
.pm16_code equ $ - gdt
|
||||
istruc GDTEntry
|
||||
at GDTEntry.limitl, dw 0xFFFF
|
||||
at GDTEntry.basel, dw 0
|
||||
at GDTEntry.basem, db 0
|
||||
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.code | gdt_attr.readable
|
||||
at GDTEntry.flags__limith, db 0xF
|
||||
at GDTEntry.baseh, db 0
|
||||
iend
|
||||
|
||||
.pm16_data equ $ - gdt
|
||||
istruc GDTEntry
|
||||
at GDTEntry.limitl, dw 0xFFFF
|
||||
at GDTEntry.basel, dw 0
|
||||
at GDTEntry.basem, db 0
|
||||
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.writable
|
||||
at GDTEntry.flags__limith, db 0xF
|
||||
at GDTEntry.baseh, db 0
|
||||
iend
|
||||
|
||||
.end equ $ - gdt
|
|
@ -0,0 +1,161 @@
|
|||
; Simple ISO emulation with el torito
|
||||
|
||||
; Fill until CD sector 0x10
|
||||
times (0x10*2048)-($-$$) db 0
|
||||
|
||||
; Volume record
|
||||
;TODO: fill in more fields
|
||||
iso_volume_record:
|
||||
db 1 ; Type volume record
|
||||
db "CD001" ; Identifier
|
||||
db 1 ; Version
|
||||
db 0 ; Unused
|
||||
times 32 db ' ' ; System identifier
|
||||
.volume_id: ; Volume identifier
|
||||
db 'Redox OS'
|
||||
times 32-($-.volume_id) db ' '
|
||||
times 8 db 0 ; Unused
|
||||
db 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15 ; Volume space size (0x15)
|
||||
times 32 db 0 ; Unused
|
||||
db 0x01, 0x00, 0x00, 0x01 ; Volume set size
|
||||
db 0x01, 0x00, 0x00, 0x01 ; Volume sequence number
|
||||
db 0x00, 0x08, 0x08, 0x00 ; Logical block size in little and big endian
|
||||
|
||||
times 156-($-iso_volume_record) db 0
|
||||
|
||||
; Root directory entry
|
||||
.root_directory:
|
||||
db 0x22 ; Length of entry
|
||||
db 0x00 ; Length of extended attributes
|
||||
db 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 ; Location of extent (0x14)
|
||||
db 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 ; Size of extent
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; Recording time
|
||||
db 0x02 ; File flags
|
||||
db 0x00 ; Interleaved file unit size
|
||||
db 0x00 ; Interleaved gap size
|
||||
db 0x01, 0x00, 0x00, 0x01 ; Volume sequence number
|
||||
db 0x01 ; Length of file identifier
|
||||
db 0x00 ; File identifier
|
||||
|
||||
times 128 db ' ' ; Volume set identifier
|
||||
times 128 db ' ' ; Publisher identifier
|
||||
times 128 db ' ' ; Data preparer identifier
|
||||
times 128 db ' ' ; Application identifier
|
||||
times 37 db ' ' ; Copyright file ID
|
||||
times 37 db ' ' ; Abstract file ID
|
||||
times 37 db ' ' ; Bibliographic file ID
|
||||
|
||||
times 881-($-iso_volume_record) db 0
|
||||
|
||||
db 1 ; File structure version
|
||||
|
||||
; Fill until CD sector 0x11
|
||||
times (0x11*2048)-($-$$) db 0
|
||||
|
||||
; Boot record
|
||||
iso_boot_record:
|
||||
db 0 ; Type boot record
|
||||
db "CD001" ; Identifier
|
||||
db 1 ; Version
|
||||
db "EL TORITO SPECIFICATION" ; Boot system identifier
|
||||
times 0x47-($ - iso_boot_record) db 0 ; Padding
|
||||
dd 0x13 ; Sector of boot catalog
|
||||
|
||||
; Fill until CD sector 0x12
|
||||
times (0x12*2048)-($-$$) db 0
|
||||
|
||||
; Terminator
|
||||
iso_terminator:
|
||||
db 0xFF ; Type terminator
|
||||
db "CD001" ; Identifier
|
||||
db 1 ; Version
|
||||
|
||||
; Fill until CD sector 0x13
|
||||
times (0x13*2048)-($-$$) db 0
|
||||
|
||||
; Boot catalog
|
||||
iso_boot_catalog:
|
||||
|
||||
; Validation entry
|
||||
.validation:
|
||||
db 1 ; Header ID
|
||||
db 0 ; Platform ID (x86)
|
||||
dw 0 ; Reserved
|
||||
times 24 db 0 ; ID string
|
||||
dw 0x55aa ; Checksum
|
||||
dw 0xaa55 ; Key
|
||||
|
||||
; Default entry
|
||||
.default:
|
||||
db 0x88 ; Bootable
|
||||
db 4 ; Hard drive emulation
|
||||
dw 0 ; Load segment (0 is platform default)
|
||||
db 0xEE ; Partition type (0xEE is protective MBR)
|
||||
db 0 ; Unused
|
||||
dw 1 ; Sector count
|
||||
dd 0 ; Start address for virtual disk
|
||||
times 20 db 0 ; Padding
|
||||
|
||||
; EFI section header entry
|
||||
.efi_section_header:
|
||||
db 0x91 ; Final header
|
||||
db 0xEF ; Platform ID (EFI)
|
||||
dw 1 ; Number of section header entries
|
||||
times 28 db 0 ; ID string
|
||||
|
||||
; EFI section entry
|
||||
.efi_section_entry:
|
||||
db 0x88 ; Bootable
|
||||
db 0 ; No emulation
|
||||
dw 0 ; Load segment (0 is platform default)
|
||||
db 0 ; Partition type (not used)
|
||||
db 0 ; Unused
|
||||
dw 512 ; Sector count (1 MiB = 512 CD sectors)
|
||||
dd 512 ; Start address for virtual disk (1 MiB = 512 CD sectors)
|
||||
times 20 db 0 ; Padding
|
||||
|
||||
; Fill until CD sector 0x14
|
||||
times (0x14*2048)-($-$$) db 0
|
||||
|
||||
iso_root_directory:
|
||||
.self:
|
||||
db 0x22 ; Length of entry
|
||||
db 0x00 ; Length of extended attributes
|
||||
db 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 ; Location of extent (0x14)
|
||||
db 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 ; Size of extent
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; Recording time
|
||||
db 0x02 ; File flags
|
||||
db 0x00 ; Interleaved file unit size
|
||||
db 0x00 ; Interleaved gap size
|
||||
db 0x01, 0x00, 0x00, 0x01 ; Volume sequence number
|
||||
db 0x01 ; Length of file identifier
|
||||
db 0x00 ; File identifier
|
||||
|
||||
.parent:
|
||||
db 0x22 ; Length of entry
|
||||
db 0x00 ; Length of extended attributes
|
||||
db 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 ; Location of extent (0x14)
|
||||
db 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 ; Size of extent
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; Recording time
|
||||
db 0x02 ; File flags
|
||||
db 0x00 ; Interleaved file unit size
|
||||
db 0x00 ; Interleaved gap size
|
||||
db 0x01, 0x00, 0x00, 0x01 ; Volume sequence number
|
||||
db 0x01 ; Length of file identifier
|
||||
db 0x01 ; File identifier
|
||||
|
||||
.boot_cat:
|
||||
db 0x2C ; Length of entry
|
||||
db 0x00 ; Length of extended attributes
|
||||
db 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13 ; Location of extent (0x13)
|
||||
db 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 ; Size of extent
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; Recording time
|
||||
db 0x00 ; File flags
|
||||
db 0x00 ; Interleaved file unit size
|
||||
db 0x00 ; Interleaved gap size
|
||||
db 0x01, 0x00, 0x00, 0x01 ; Volume sequence number
|
||||
db 0x0A ; Length of file identifier
|
||||
db "BOOT.CAT;1",0 ; File identifier
|
||||
|
||||
; Fill until CD sector 0x15
|
||||
times (0x15*2048)-($-$$) db 0
|
|
@ -0,0 +1,56 @@
|
|||
SECTION .text
|
||||
USE32
|
||||
|
||||
long_mode:
|
||||
.func: dq 0
|
||||
.page_table: dd 0
|
||||
|
||||
.entry:
|
||||
; disable interrupts
|
||||
cli
|
||||
|
||||
; disable paging
|
||||
mov eax, cr0
|
||||
and eax, 0x7FFFFFFF
|
||||
mov cr0, eax
|
||||
|
||||
; enable FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension
|
||||
mov eax, cr4
|
||||
or eax, 1 << 9 | 1 << 7 | 1 << 5 | 1 << 4
|
||||
mov cr4, eax
|
||||
|
||||
; load long mode GDT
|
||||
lgdt [gdtr]
|
||||
|
||||
; enable long mode
|
||||
mov ecx, 0xC0000080 ; Read from the EFER MSR.
|
||||
rdmsr
|
||||
or eax, 1 << 11 | 1 << 8 ; Set the Long-Mode-Enable and NXE bit.
|
||||
wrmsr
|
||||
|
||||
; set page table
|
||||
mov eax, [.page_table]
|
||||
mov cr3, eax
|
||||
|
||||
; enabling paging and protection simultaneously
|
||||
mov eax, cr0
|
||||
or eax, 1 << 31 | 1 << 16 | 1 ;Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode
|
||||
mov cr0, eax
|
||||
|
||||
; far jump to enable Long Mode and load CS with 64 bit segment
|
||||
jmp gdt.lm64_code:.inner
|
||||
|
||||
USE64
|
||||
|
||||
.inner:
|
||||
; load all the other segments with 64 bit data segments
|
||||
mov rax, gdt.lm64_data
|
||||
mov ds, rax
|
||||
mov es, rax
|
||||
mov fs, rax
|
||||
mov gs, rax
|
||||
mov ss, rax
|
||||
|
||||
; jump to specified function
|
||||
mov rax, [.func]
|
||||
jmp rax
|
|
@ -0,0 +1,67 @@
|
|||
SECTION .text
|
||||
USE16
|
||||
|
||||
; provide function for printing in x86 real mode
|
||||
|
||||
; print a string and a newline
|
||||
; CLOBBER
|
||||
; ax
|
||||
print_line:
|
||||
mov al, 13
|
||||
call print_char
|
||||
mov al, 10
|
||||
jmp print_char
|
||||
|
||||
; print a string
|
||||
; IN
|
||||
; si: points at zero-terminated String
|
||||
; CLOBBER
|
||||
; si, ax
|
||||
print:
|
||||
pushf
|
||||
cld
|
||||
.loop:
|
||||
lodsb
|
||||
test al, al
|
||||
jz .done
|
||||
call print_char
|
||||
jmp .loop
|
||||
.done:
|
||||
popf
|
||||
ret
|
||||
|
||||
; print a character
|
||||
; IN
|
||||
; al: character to print
|
||||
print_char:
|
||||
pusha
|
||||
mov bx, 7
|
||||
mov ah, 0x0e
|
||||
int 0x10
|
||||
popa
|
||||
ret
|
||||
|
||||
; print a number in hex
|
||||
; IN
|
||||
; bx: the number
|
||||
; CLOBBER
|
||||
; al, cx
|
||||
print_hex:
|
||||
mov cx, 4
|
||||
.lp:
|
||||
mov al, bh
|
||||
shr al, 4
|
||||
|
||||
cmp al, 0xA
|
||||
jb .below_0xA
|
||||
|
||||
add al, 'A' - 0xA - '0'
|
||||
.below_0xA:
|
||||
add al, '0'
|
||||
|
||||
call print_char
|
||||
|
||||
shl bx, 4
|
||||
loop .lp
|
||||
|
||||
ret
|
|
@ -0,0 +1,36 @@
|
|||
SECTION .text
|
||||
USE16
|
||||
|
||||
protected_mode:
|
||||
|
||||
.func: dd 0
|
||||
|
||||
.entry:
|
||||
; disable interrupts
|
||||
cli
|
||||
|
||||
; load protected mode GDT
|
||||
lgdt [gdtr]
|
||||
|
||||
; set protected mode bit of cr0
|
||||
mov eax, cr0
|
||||
or eax, 1
|
||||
mov cr0, eax
|
||||
|
||||
; far jump to load CS with 32 bit segment
|
||||
jmp gdt.pm32_code:.inner
|
||||
|
||||
USE32
|
||||
|
||||
.inner:
|
||||
; load all the other segments with 32 bit data segments
|
||||
mov eax, gdt.pm32_data
|
||||
mov ds, eax
|
||||
mov es, eax
|
||||
mov fs, eax
|
||||
mov gs, eax
|
||||
mov ss, eax
|
||||
|
||||
; jump to specified function
|
||||
mov eax, [.func]
|
||||
jmp eax
|
|
@ -0,0 +1,222 @@
|
|||
ORG 0x7C00
|
||||
SECTION .text
|
||||
USE16
|
||||
|
||||
stage1: ; dl comes with disk
|
||||
; initialize segment registers
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
|
||||
; initialize stack
|
||||
mov sp, 0x7C00
|
||||
|
||||
; initialize CS
|
||||
push ax
|
||||
push word .set_cs
|
||||
retf
|
||||
|
||||
.set_cs:
|
||||
|
||||
; save disk number
|
||||
mov [disk], dl
|
||||
|
||||
mov si, stage_msg
|
||||
call print
|
||||
mov al, '1'
|
||||
call print_char
|
||||
call print_line
|
||||
|
||||
; read CHS gemotry
|
||||
; CL (bits 0-5) = maximum sector number
|
||||
; CL (bits 6-7) = high bits of max cylinder number
|
||||
; CH = low bits of maximum cylinder number
|
||||
; DH = maximum head number
|
||||
mov ah, 0x08
|
||||
mov dl, [disk]
|
||||
xor di, di
|
||||
int 0x13
|
||||
jc error ; carry flag set on error
|
||||
mov bl, ch
|
||||
mov bh, cl
|
||||
shr bh, 6
|
||||
mov [chs.c], bx
|
||||
shr dx, 8
|
||||
inc dx ; returns heads - 1
|
||||
mov [chs.h], dx
|
||||
and cl, 0x3f
|
||||
mov [chs.s], cl
|
||||
|
||||
mov eax, (stage2 - stage1) / 512
|
||||
mov bx, stage2
|
||||
mov cx, (stage3.end - stage2) / 512
|
||||
mov dx, 0
|
||||
call load
|
||||
|
||||
mov si, stage_msg
|
||||
call print
|
||||
mov al, '2'
|
||||
call print_char
|
||||
call print_line
|
||||
|
||||
jmp stage2.entry
|
||||
|
||||
; load some sectors from disk to a buffer in memory
|
||||
; buffer has to be below 1MiB
|
||||
; IN
|
||||
; ax: start sector
|
||||
; bx: offset of buffer
|
||||
; cx: number of sectors (512 Bytes each)
|
||||
; dx: segment of buffer
|
||||
; CLOBBER
|
||||
; ax, bx, cx, dx, si
|
||||
; TODO rewrite to (eventually) move larger parts at once
|
||||
; if that is done increase buffer_size_sectors in startup-common to that (max 0x80000 - startup_end)
|
||||
load:
|
||||
cmp cx, 127
|
||||
jbe .good_size
|
||||
|
||||
pusha
|
||||
mov cx, 127
|
||||
call load
|
||||
popa
|
||||
add eax, 127
|
||||
add dx, 127 * 512 / 16
|
||||
sub cx, 127
|
||||
|
||||
jmp load
|
||||
.good_size:
|
||||
mov [DAPACK.addr], eax
|
||||
mov [DAPACK.buf], bx
|
||||
mov [DAPACK.count], cx
|
||||
mov [DAPACK.seg], dx
|
||||
|
||||
call print_dapack
|
||||
|
||||
cmp byte [chs.s], 0
|
||||
jne .chs
|
||||
;INT 0x13 extended read does not work on CDROM!
|
||||
mov dl, [disk]
|
||||
mov si, DAPACK
|
||||
mov ah, 0x42
|
||||
int 0x13
|
||||
jc error ; carry flag set on error
|
||||
ret
|
||||
|
||||
.chs:
|
||||
; calculate CHS
|
||||
xor edx, edx
|
||||
mov eax, [DAPACK.addr]
|
||||
div dword [chs.s] ; divide by sectors
|
||||
mov ecx, edx ; move sector remainder to ecx
|
||||
xor edx, edx
|
||||
div dword [chs.h] ; divide by heads
|
||||
; eax has cylinders, edx has heads, ecx has sectors
|
||||
|
||||
; Sector cannot be greater than 63
|
||||
inc ecx ; Sector is base 1
|
||||
cmp ecx, 63
|
||||
ja error_chs
|
||||
|
||||
; Head cannot be greater than 255
|
||||
cmp edx, 255
|
||||
ja error_chs
|
||||
|
||||
; Cylinder cannot be greater than 1023
|
||||
cmp eax, 1023
|
||||
ja error_chs
|
||||
|
||||
; Move CHS values to parameters
|
||||
mov ch, al
|
||||
shl ah, 6
|
||||
and cl, 0x3f
|
||||
or cl, ah
|
||||
shl dx, 8
|
||||
|
||||
; read from disk using CHS
|
||||
mov al, [DAPACK.count]
|
||||
mov ah, 0x02 ; disk read (CHS)
|
||||
mov bx, [DAPACK.buf]
|
||||
mov dl, [disk]
|
||||
push es ; save ES
|
||||
mov es, [DAPACK.seg]
|
||||
int 0x13
|
||||
pop es ; restore EC
|
||||
jc error ; carry flag set on error
|
||||
ret
|
||||
|
||||
print_dapack:
|
||||
mov bx, [DAPACK.addr + 2]
|
||||
call print_hex
|
||||
|
||||
mov bx, [DAPACK.addr]
|
||||
call print_hex
|
||||
|
||||
mov al, '#'
|
||||
call print_char
|
||||
|
||||
mov bx, [DAPACK.count]
|
||||
call print_hex
|
||||
|
||||
mov al, ' '
|
||||
call print_char
|
||||
|
||||
mov bx, [DAPACK.seg]
|
||||
call print_hex
|
||||
|
||||
mov al, ':'
|
||||
call print_char
|
||||
|
||||
mov bx, [DAPACK.buf]
|
||||
call print_hex
|
||||
|
||||
call print_line
|
||||
|
||||
ret
|
||||
|
||||
error_chs:
|
||||
mov ah, 0
|
||||
|
||||
error:
|
||||
call print_line
|
||||
|
||||
mov bh, 0
|
||||
mov bl, ah
|
||||
call print_hex
|
||||
|
||||
mov al, ' '
|
||||
call print_char
|
||||
|
||||
mov si, error_msg
|
||||
call print
|
||||
call print_line
|
||||
.halt:
|
||||
cli
|
||||
hlt
|
||||
jmp .halt
|
||||
|
||||
%include "print.asm"
|
||||
|
||||
stage_msg: db "Stage ",0
|
||||
error_msg: db "ERROR",0
|
||||
|
||||
disk: db 0
|
||||
|
||||
chs:
|
||||
.c: dd 0
|
||||
.h: dd 0
|
||||
.s: dd 0
|
||||
|
||||
DAPACK:
|
||||
db 0x10
|
||||
db 0
|
||||
.count: dw 0 ; int 13 resets this to # of blocks actually read/written
|
||||
.buf: dw 0 ; memory buffer destination address (0:7c00)
|
||||
.seg: dw 0 ; in memory page zero
|
||||
.addr: dq 0 ; put the lba to read in this spot
|
||||
|
||||
times 446-($-$$) db 0
|
||||
partitions: times 4 * 16 db 0
|
||||
db 0x55
|
||||
db 0xaa
|
|
@ -0,0 +1,134 @@
|
|||
SECTION .text
|
||||
USE16
|
||||
|
||||
stage2.entry:
|
||||
; check for required features
|
||||
call cpuid_check
|
||||
|
||||
; enable A20-Line via IO-Port 92, might not work on all motherboards
|
||||
in al, 0x92
|
||||
or al, 2
|
||||
out 0x92, al
|
||||
|
||||
mov dword [protected_mode.func], stage3.entry
|
||||
jmp protected_mode.entry
|
||||
|
||||
%include "cpuid.asm"
|
||||
%include "gdt.asm"
|
||||
%include "long_mode.asm"
|
||||
%include "protected_mode.asm"
|
||||
%include "thunk.asm"
|
||||
|
||||
USE32
|
||||
|
||||
stage3.entry:
|
||||
; stage3 stack at 448 KiB (512KiB minus 64KiB disk buffer)
|
||||
mov esp, 0x70000
|
||||
|
||||
; push arguments
|
||||
mov eax, thunk.int16
|
||||
push eax
|
||||
mov eax, thunk.int15
|
||||
push eax
|
||||
mov eax, thunk.int13
|
||||
push eax
|
||||
mov eax, thunk.int10
|
||||
push eax
|
||||
xor eax, eax
|
||||
mov al, [disk]
|
||||
push eax
|
||||
mov eax, kernel.entry
|
||||
push eax
|
||||
mov eax, [stage3 + 0x18]
|
||||
call eax
|
||||
.halt:
|
||||
cli
|
||||
hlt
|
||||
jmp .halt
|
||||
|
||||
kernel:
|
||||
.stack: dq 0
|
||||
.func: dq 0
|
||||
.args: dq 0
|
||||
|
||||
.entry:
|
||||
; page_table: usize
|
||||
mov eax, [esp + 4]
|
||||
mov [long_mode.page_table], eax
|
||||
|
||||
; stack: u64
|
||||
mov eax, [esp + 8]
|
||||
mov [.stack], eax
|
||||
mov eax, [esp + 12]
|
||||
mov [.stack + 4], eax
|
||||
|
||||
; func: u64
|
||||
mov eax, [esp + 16]
|
||||
mov [.func], eax
|
||||
mov eax, [esp + 20]
|
||||
mov [.func + 4], eax
|
||||
|
||||
; args: *const KernelArgs
|
||||
mov eax, [esp + 24]
|
||||
mov [.args], eax
|
||||
|
||||
; long_mode: usize
|
||||
mov eax, [esp + 28]
|
||||
test eax, eax
|
||||
jz .inner32
|
||||
|
||||
mov eax, .inner64
|
||||
mov [long_mode.func], eax
|
||||
jmp long_mode.entry
|
||||
|
||||
.inner32:
|
||||
; disable paging
|
||||
mov eax, cr0
|
||||
and eax, 0x7FFFFFFF
|
||||
mov cr0, eax
|
||||
|
||||
;TODO: PAE (1 << 5)
|
||||
; enable FXSAVE/FXRSTOR, Page Global, and Page Size Extension
|
||||
mov eax, cr4
|
||||
or eax, 1 << 9 | 1 << 7 | 1 << 4
|
||||
mov cr4, eax
|
||||
|
||||
; set page table
|
||||
mov eax, [long_mode.page_table]
|
||||
mov cr3, eax
|
||||
|
||||
; enabling paging and protection simultaneously
|
||||
mov eax, cr0
|
||||
; Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode
|
||||
or eax, 1 << 31 | 1 << 16 | 1
|
||||
mov cr0, eax
|
||||
|
||||
; enable FPU
|
||||
;TODO: move to Rust
|
||||
mov eax, cr0
|
||||
and al, 11110011b ; Clear task switched (3) and emulation (2)
|
||||
or al, 00100010b ; Set numeric error (5) monitor co-processor (1)
|
||||
mov cr0, eax
|
||||
fninit
|
||||
|
||||
mov esp, [.stack]
|
||||
mov eax, [.args]
|
||||
push eax
|
||||
mov eax, [.func]
|
||||
call eax
|
||||
.halt32:
|
||||
cli
|
||||
hlt
|
||||
jmp .halt32
|
||||
|
||||
USE64
|
||||
|
||||
.inner64:
|
||||
mov rsp, [.stack]
|
||||
mov rax, [.func]
|
||||
mov rdi, [.args]
|
||||
call rax
|
||||
.halt64:
|
||||
cli
|
||||
hlt
|
||||
jmp .halt64
|
|
@ -0,0 +1,149 @@
|
|||
SECTION .text
|
||||
USE32
|
||||
|
||||
thunk:
|
||||
.int10:
|
||||
mov dword [.func], .int10_real
|
||||
jmp .enter
|
||||
|
||||
.int13:
|
||||
mov dword [.func], .int13_real
|
||||
jmp .enter
|
||||
|
||||
.int15:
|
||||
mov dword [.func], .int15_real
|
||||
jmp .enter
|
||||
|
||||
.int16:
|
||||
mov dword [.func], .int16_real
|
||||
jmp .enter
|
||||
|
||||
.func: dd 0
|
||||
.esp: dd 0
|
||||
.cr0: dd 0
|
||||
|
||||
.enter:
|
||||
; save flags
|
||||
pushfd
|
||||
|
||||
; save registers
|
||||
pushad
|
||||
|
||||
; save esp
|
||||
mov [.esp], esp
|
||||
|
||||
; load gdt
|
||||
lgdt [gdtr]
|
||||
|
||||
; far jump to protected mode 16-bit
|
||||
jmp gdt.pm16_code:.pm16
|
||||
|
||||
.exit:
|
||||
; set segment selectors to 32-bit protected mode
|
||||
mov eax, gdt.pm32_data
|
||||
mov ds, eax
|
||||
mov es, eax
|
||||
mov fs, eax
|
||||
mov gs, eax
|
||||
mov ss, eax
|
||||
|
||||
; restore esp
|
||||
mov esp, [.esp]
|
||||
|
||||
; restore registers
|
||||
popad
|
||||
|
||||
; restore flags
|
||||
popfd
|
||||
|
||||
; return
|
||||
ret
|
||||
|
||||
USE16
|
||||
|
||||
.int10_real:
|
||||
int 0x10
|
||||
ret
|
||||
|
||||
.int13_real:
|
||||
int 0x13
|
||||
ret
|
||||
|
||||
.int15_real:
|
||||
int 0x15
|
||||
ret
|
||||
|
||||
.int16_real:
|
||||
int 0x16
|
||||
ret
|
||||
|
||||
.pm16:
|
||||
; set segment selectors to protected mode 16-bit
|
||||
mov eax, gdt.pm16_data
|
||||
mov ds, eax
|
||||
mov es, eax
|
||||
mov fs, eax
|
||||
mov gs, eax
|
||||
mov ss, eax
|
||||
|
||||
; save cr0
|
||||
mov eax, cr0
|
||||
mov [.cr0], eax
|
||||
|
||||
; disable paging and protected mode
|
||||
and eax, 0x7FFFFFFE
|
||||
mov cr0, eax
|
||||
|
||||
; far jump to real mode
|
||||
jmp 0:.real
|
||||
|
||||
.real:
|
||||
; set segment selectors to real mode
|
||||
mov eax, 0
|
||||
mov ds, eax
|
||||
mov es, eax
|
||||
mov fs, eax
|
||||
mov gs, eax
|
||||
mov ss, eax
|
||||
|
||||
; set stack
|
||||
mov esp, 0x7C00 - 64
|
||||
|
||||
; load registers and ES
|
||||
pop es
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebp
|
||||
pop ebx
|
||||
pop edx
|
||||
pop ecx
|
||||
pop eax
|
||||
|
||||
; enable interrupts
|
||||
sti
|
||||
|
||||
; call real mode function
|
||||
call [.func]
|
||||
|
||||
; disable interrupts
|
||||
cli
|
||||
|
||||
; save registers and ES
|
||||
push eax
|
||||
push ecx
|
||||
push edx
|
||||
push ebx
|
||||
push ebp
|
||||
push esi
|
||||
push edi
|
||||
push es
|
||||
|
||||
; load gdt (BIOS sometimes overwrites this)
|
||||
lgdt [gdtr]
|
||||
|
||||
; restore cr0, will enable protected mode
|
||||
mov eax, [.cr0]
|
||||
mov cr0, eax
|
||||
|
||||
; far jump to protected mode 32-bit
|
||||
jmp gdt.pm32_code:.exit
|
Loading…
Reference in New Issue