I'm trying to implement SMP in my OS, but I wouldnt make this post if everything went OK
Here is code:
Code: Select all
USE16
ORG 0h
;!!NOT ASSEMBLED!!
CONSTANTS:
CodeSeg_32 equ 50h
GDS equ 48h
SDA equ 800h
CONSTANTS_END:
;!!ASSEMBLED!!
BEGIN:
jmp START
DATASECT:
DAP:
DAP_Size db 10h ;1h
DAP_Res1 db 0 ;2h
DAP_Bytes2Transfer db 1h ;3h
DAP_Res2 db 0 ;4h
DAP_Buff_Addr1 dw 0h ;6h
DAP_Buff_Addr2 dw 1F0h ;8h
DAP_LBA dq 3h ;9h
DAT_Disk_Num db 80h ;12h number of device 80h-winchester
DAT_Num_Of_Sects dw 20h ;13h the number of 512byte sectors, that contain your kernel
END_DAP:
VID:
VID_Cursor dw 0h ;15h
END_VID:
GDT:
dw GDT_ENDS - GDT_STARTS - 1h ;17h
dd 80000h + GDT_STARTS
GDT_STARTS:
;Records:
; 1.-CER-00- Kernel Code segment
; 2.-DRW-00- Global Data Segment
; 3.-DRO-11- SDA
; 4.-DRW-00- NON Permanent Data
; 5.-DRW-00- System Stack
; 6.-DRW-00- Process Table
; 7.-DRO-00- FONT
; 8.-DRO-11- NON Permanent data area (For aplications)
; 9.-DRW-00- Process Space
;10.-CER-00- Temporary almight Code Segment
REC0:
dq 0h
REC1:
Limit_0_15 dw 01000h
Base_0_15 dw 02C00h
Base_16_23 db 0h
Access db 10011010b;||Present bit||Priviligies||1||Code-1, Data - 0||if want to execute from low levels - 1, else 0|| can write here? yes=1||0||
LimAndFlags db 01000000b;||Granularity||1||0||0||Limit 16-19||
Base_24_31 db 0h
REC2:
aLimit_0_15 dw 0FFFFh
aBase_0_15 dw 0h
aBase_16_23 db 0h
aAccess db 10010010b;||Present bit||Priviligies||1||Code-1, Data - 0||if want to execute from low levels - 1, else 0|| can write here? yes=1||0||
aLimAndFlags db 11001111b;||Granularity||1||0||0||Limit 16-19||
aBase_24_31 db 0h
REC3:
bLimit_0_15 dw 1FFh
bBase_0_15 dw 800h
bBase_16_23 db 0h
bAccess db 11110000b;||Present bit||Priviligies||1||Code-1, Data - 0||if want to execute from low levels - 1, else 0|| can write here? yes=1||0||
bLimAndFlags db 01000000b;||Granularity||1||0||0||Limit 16-19||
bBase_24_31 db 0h
REC4: ;
cLimit_0_15 dw 0FFFh
cBase_0_15 dw 0A00h
cBase_16_23 db 0h
cAccess db 10010010b;||Present bit||Priviligies||1||Code-1, Data - 0||if want to execute from low levels - 1, else 0|| can write here? yes=1||0||
cLimAndFlags db 01000000b;||Granularity||1||0||0||Limit 16-19||
cBase_24_31 db 0h
REC5:
dLimit_0_15 dw 04FFh
dBase_0_15 dw 1A00h
dBase_16_23 db 0h
dAccess db 10010010b;||Present bit||Priviligies||1||Code-1, Data - 0||if want to execute from low levels - 1, else 0|| can write here? yes=1||0||
dLimAndFlags db 01000000b;||Granularity||1||0||0||Limit 16-19||
dBase_24_31 db 0h
REC6:
eLimit_0_15 dw 03FFh
eBase_0_15 dw 1F00h
eBase_16_23 db 0h
eAccess db 10010010b;||Present bit||Priviligies||1||Code-1, Data - 0||if want to execute from low levels - 1, else 0|| can write here? yes=1||0||
eLimAndFlags db 01000000b;||Granularity||1||0||0||Limit 16-19||
eBase_24_31 db 0h
REC7:
fLimit_0_15 dw 0FFh
fBase_0_15 dw 2300h
fBase_16_23 db 0h
fAccess db 10010000b;||Present bit||Priviligies||1||Code-1, Data - 0||if want to execute from low levels - 1, else 0|| can write here? yes=1||0||
fLimAndFlags db 01000000b;||Granularity||1||0||0||Limit 16-19||
fBase_24_31 db 0h
; ______________________________________________
;| MEMORY HOLE OF 2048d BYTES FOR IDT |
;|______________________________________________|
REC8:
gLimit_0_15 dw 0FFFh
gBase_0_15 dw 0A00h
gBase_16_23 db 0h
gAccess db 11110000b;||Present bit||Priviligies||1||Code-1, Data - 0||if want to execute from low levels - 1, else 0|| can write here? yes=1||0||
gLimAndFlags db 01000000b;||Granularity||1||0||0||Limit 16-19||
gBase_24_31 db 0h
REC9: ; this segment will define memory space of programms depending on memory map
iLimit_0_15 dw 0h
iBase_0_15 dw 0h
iBase_16_23 db 0h
iAccess db 10011010b;||Present bit||Priviligies||1||Code-1, Data - 0||if want to execute from low levels - 1, else 0|| can write here? yes=1||0||
iLimAndFlags db 11000000b;||Granularity||1||0||0||Limit 16-19||
iBase_24_31 db 0h
REC10:
hLimit_0_15 dw 0FFFFh
hBase_0_15 dw 0h
hBase_16_23 db 0h
hAccess db 10011000b;||Present bit||Priviligies||1||Code-1, Data - 0||if want to execute from low levels - 1, else 0|| can write here? yes=1||0||
hLimAndFlags db 11001111b;||Granularity||1||0||0||Limit 16-19||
hBase_24_31 db 0h
GDT_ENDS:
;FINALY OS IS MAPPED LIKE THIS
; 00000000h | 000007FFh | GDT (descriptor + 255 entries)
; 00000800h | 000009FFh | SDA(system data area)
; 00000A00h | 000019FFh | non permanent data area(cursor, mouse coords, time, config tables etc) in 2 segments 00 and 11 privl - 4096 bytes
; 00001A00h | 00001EFFh | SYSTEM STACK (1280 bytes)
; 00001F00h | 000022FFh | PT(process table)
; 00002300h | 000023FFh | FONT for keyboard to ASCII translation
; 00002400h | 00002BFFh | IDT (255 entries + descriptor)
; 00002C00h | x | kernel code(ints inside)
;
;
; 000A0000h | 000AFFFFh | Video Video Memory
; 000B8000h | 000BFFFFh | Text Video Memory
END_DATASECT:
ERROR:
nop
nop
jmp ERROR
START:
mov ax, 8000h
mov ds, ax
xor ax, ax
mov fs, ax
mov ax, 9000h
mov ss, ax
mov esp, 0500h
mov ax, 80h
mov gs, ax
mov bp, BEGIN
;here is it! everything prepared
;ds,cs - point to this segment
;es points to b800h
;ss points to higher place
;gs points to the first secto of kernel
;bp points to the start of datasect
;fs points to 0
; its time for action!
LOAD_KERN: ; service for reading data from disk specified DAT_Disk_Num
mov ah, 42h
xor al, al
mov dl, [cs:bp+12h]
mov si, DAP
mov cx, [cs:bp+13h]
READ_LOOP:
pusha
int 13h
jc ERROR
popa
add word [ds:si+6h], 20h
inc byte [ds:si+8h]
loop READ_LOOP ; service ends here
END_LOAD_KERN:
;data loaded to 1F00h starting with process table
;
mov ax, 80h
mov gs, ax
COLLECT_DATA:
DETECT_VENDOR:
xor eax, eax
cpuid
mov [gs:0h], ecx
MEMORY_MAP:
mov byte [gs:180h], 0h
mov di, gs
mov es, di
mov di, 181h
xor ebx, ebx
mov edx, 534D4150h
MM_LOOP:
mov eax, 0E820h
mov ecx, 24d
int 15h
jc ERROR
add di, 24d
inc byte [gs:180h]
cmp ebx, 0h
jne MM_LOOP
;here we loaded SDA(System Data Area) with following
;_SDA_________________________________________________
;800h(dd) vendor: 'ntel' - Intel
;804h(dd) ROOT COMPLEX BASE ADDRESS
;808h(dd) MP TABLE ADDRESS
;80Ch(db) !!??!!
;80Dh(dw) !!??!!
;80Fh(db) ACPI version number (WILL COLLECT IN PM)
;810h(dd) RSDT tables !PHYSICAL! address (WILL COLLECT IN PM)
;814h(dd) FADT TABLE ADDRESS !PHYSICAL! (WILL COLLECT IN PM)
;818h(db) NUMBER OF IO APICS PRESENT
;819h(dd) IO APIC-1 CONFIG ADDRESS
;81Dh(db) IO APIC-1 ID
;81Eh(dd) IO APIC-2 CONFIG ADDRESS
;822h(db) IO APIC-2 ID
;823h(10b) RESERVED (for future additional io apics)
;82Dh(dd) LAPIC ADDRESS
;831h(db) NUMBER OF CPUS IN SYSTEM (UP TO 4 WILL BE SUPPORTED)
;832h(11b) CPU1
;83Dh(11b) CPU2
;848h(11b) CPU3
;853h(11b) CPU4
;85Eh(
;
;
;
;
;FREE SPACE...
;
;980h(db) number of memory map tables entries
;981h( ) memory map
;______________________________________________________
;!!??!! == reserved
;done
; its time to set up our kernel for pmode
PMJMP:
cli
lea eax, [cs:bp+17h]
lgdt [eax]
mov ax, 0x2401
int 0x15
mov eax, cr0
or eax, 1h
mov cr0, eax
jmp pword CodeSeg_32:80000h+PMODE
USE32
PMODE: ;congrates! we are in PM!
;!!!TEMPORARY!!!
; PIC_CONFIG: ;configuring PIC
; mov al, 11h
; out 20h, al
; out 0A0h, al
; mov al, 20h ;IRQ0-7 = ints 20h-27h
; out 21h, al ;IRQ8-16 = ints 28h-2Fh
; mov al, 28h
; out 0A1h, al
;mov al, 4h ;some master/slave setup
; out 21h, al
; mov al, 2h
; out 0A1h, al
; mov al, 1h ;i dont know what this does
; out 21h, al
; out 0A1h, al
; MASK: ; mask ints to allow every int
; mov al, 0h
;out 0A1h, al
; out 21h, al
SETREG32: ; here it loads segment registers and esp
mov ax, 10h
mov ds, ax
mov fs, ax
mov es, ax
mov gs, ax
mov ax, 30h
mov ss, ax
mov esp, 4FFh
;ds,fs, es, gs = 10h
;ss = 30h
;esp = 4FFh
;cs = 50h(temporory 'almight' code segment)
;
;All right! Lets configure the rest of ****...
MAKE_IT_WORK: ;sets up GDT table to its working location and loads IDT and sets IOPL to 00
mov ebp, 80000h+17h
xor esi, esi
mov ecx, GDT_ENDS - GDT_STARTS + 6d
call MOVE_BLOCK
mov dword [ds:2h], 6h
lgdt [0h]
lidt [02400h] ;relocate GDT and IDT to its working location
SET_FLAGS_PRIVL:
pushfw
and word [ss:esp], 0CFFFh
popfw
;LATER I WILL SCAN MEMORY HERE...
; NOW WE CONFIGURE HARDWARE........
ACPI: ; parsing ACPI tables
RDSP:
mov ax, [ds:40Eh]
mov bx, 10h
mul bx
mov ebx, eax
mov ecx, 100000h
sub ecx, ebx
mov eax, 'RSD '
call ROM_SRC
SAVE_RSDT:
mov al, [ds:ebx+ecx+0Fh]
mov [ds:80Fh], al
mov eax, [ds:ebx+ecx+10h]
mov [ds:810h], eax
LOCATE_TABLES:
mov ebx, [ds:810h]
mov eax, [ds:ebx+4]
sub eax, 32d
mov ecx, 4h
div cl
xchg eax, ecx
push ecx
mov eax, 'FACP'
call IDEN_TABLE
mov [ds:SDA+14h], edi
; maybe more when I need ...
_MP_:
FPS: ;looking for floated point structure
mov ax, [ds:40Eh]
mov bx, 10h
mul bx
mov ebx, eax
mov ecx, 100000h
sub ecx, ebx
mov eax, '_MP_'
call ROM_SRC
SAVE_FPS:
mov eax, [ds:ebx+ecx+4h]
mov [ds:SDA+8h], eax
mov edx, [ds:eax+36d]
mov [ds:SDA+2Dh], edx
READ_MP_: ;parsing mp tables and place extracted data to system data area
mov ebx, eax
xor ecx, ecx
mov cl, 44d
call RMP_
ENABLE_APIC:
DISABLE_PIC:
mov al, 0FFh
out 21h, al
out 0A1h, al ; OSDEV wiki says thats the way to disable pic
IMCR:
mov al, 70h
out 22h, al
mov al, 1h
out 23h, al ;IMCR - in case BIOS didnt take care of it
SPURIOUS_INTS_REG: ;trying to enable APIC through Spurious ints reg
mov ebx, [ds:SDA+2Dh] ; lapic address
or dword [ds:ebx+0F0h], 100h
MSR_IA32_APIC_BASE_ENABLE_BT: ;trying to enable LAPIC through MSR
xor ecx, ecx
mov cl, 1Bh
rdmsr
or edx, 800h
wrmsr
;now its time for IOAPIC.....
RCBA: ; getting root complex base address
mov eax, 8000F8F0h
call PCI_READ
mov [ds:SDA+4h], eax ; saving to System Data Area
IOAPIC:
mov edi, [ds:SDA+4h] ;ICH specs say that i have to set bit 1 of RCBA+31FFh to enable IO APIC
add edi, 31FFh
mov eax, [ds:edi]
or eax, 1
mov [ds:edi], eax
mov eax, [ds:edi] ; and read that reg once again to ... I dont know - spec say I have to
ASSIGN_IDS:
cmp byte [ds:SDA+18h], 0h ; if no IO APICs - go to endless loop
jz LOOLP
xor ecx, ecx
mov cl, [ds:SDA+18h] ; moving number of IO APICs to counter
LP_ASSIGN:
mov al, [ds:SDA+1Dh+(ecx*5)] ;assigning APIC ID retrieved from MP
shl eax, 16d
mov ebx, [ds:SDA+19h+(ecx*5)] ; getting address of current IO APIC
xor edx, edx
mov [ds:ebx], edx
mov [ds:ebx+10h], eax ;configuring IO APIC ID
loop LP_ASSIGN
sti
LOOLP:
nop
jmp LOOLP
MOVE_BLOCK: ; function that moves block of data specified from ds:ebp to ds:esi with length ecx
mov al, [ds:ebp+ecx-1]
mov [ds:esi+ecx-1], al
loop MOVE_BLOCK
ret
IDEN_TABLE:
mov edi, [ds:ebx+((ecx-1)*4)+36d]
cmp eax, [ds:edi]
je RET_PT
loop IDEN_TABLE
jmp LOOLP
RET_PT:
ret
ROM_SRC:
cmp eax, [ds:ebx+ecx]
je RET_PT_SRC
loop ROM_SRC
RET_PT_SRC:
ret
RMP_: ;parsing MP tables
cmp byte [ds:ebx+ecx], 1h
jb FOUND_PROC
je FOUND_BUS
cmp byte [ds:ebx+ecx], 3h
jb FOUND_IOAPIC
jae FOUND_IRQSRC
FOUND_PROC:
cmp byte [ds:SDA+31h], 4h
ja F_PR_OF
xor eax, eax
mov al, [ds:SDA+31h]
mov dl, 11d
mul dl
xchg edx, eax
mov eax, [ds:ebx+ecx+1]
mov [ds:edx+SDA+32h], eax
mov eax, [ds:ebx+ecx+5]
mov [ds:edx+SDA+32h+4], eax
mov eax, [ds:ebx+ecx+9]
mov [ds:edx+SDA+32h+8], eax
inc byte [ds:SDA+31h]
F_PR_OF:
add ecx, 14h
jmp DEC_LOOP_RMP
FOUND_BUS:
jmp F_8BT
FOUND_IOAPIC:
cmp byte [ds:SDA+18h], 2h
ja F_8BT
bt word [ds:ebx+ecx+3], 0
jae F_8BT
xor edx, edx
mov dl, [ds:SDA+18h]
mov al, [ds:ebx+ecx+1]
mov [ds:SDA+1Dh+edx*5], al
mov eax, [ds:ebx+(ecx+4)]
mov [ds:SDA+19h+(edx*5)], eax
inc byte [ds:SDA+18h]
jmp F_8BT
FOUND_IRQSRC:
jmp F_8BT
F_8BT:
add cx, 8h
DEC_LOOP_RMP:
cmp cx, [ds:ebx+4h]
jb RMP_
RET_PT_RMP:
ret
PCI_READ: ;eax == address
mov dx, 0CF8h
out dx, eax
mov dx, 0CFCh
in eax, dx
ret ;eax == input
PCI_WRITE: ;eax == address, ebx == output
mov dx, 0CF8h
out dx, eax
mov dx, 0CFCh
xchg ebx, eax
in eax, dx
ret ; no output...
times 175d db 0 ;total must be 1024d
db 'F'