Я использую DOS для загрузки и запуска моего приложения test.exe .Эта программа запускает BSP (Bootstrap Processor) в реальном режиме и обращается к таблице APIC на FEE0:0000
, чтобы включить SVI (ложное векторное прерывание) со смещением 0x0F0
и отправить последовательность INIT-SIPI-SIPI
, используя оба значения ICR_low
(смещение 0x300).) и ICR_high
(смещение 0x310).BSP входит в цикл jmp $ , чтобы остановить выполнение, и позволяет AP (процессору приложений) выполнять код по адресу 0000:8000
и печатать символ.
Похоже, сообщения не отправляются в точки доступа, потому что я не вижу, чтобы кто-то из них что-либо печатал на дисплее ..
Я использую FreeDos в реальном режиме.Для компиляции я использую FASM (плоский ассемблер)
Я использовал OsDev руководство, которое включает код, который я использую для тестирования (с некоторыми модификациями), как простойнасколько возможно, чтобы увидеть, смогу ли я заставить его работать.Я также сослался на руководство по Intel для программистов и другие спецификации, а также на учебник в Code Project.
Я только пытаюсь разбудить точки доступа и выполнить некоторый простой код.Все примеры, которые я нашел, входят в нереальный режим, защищенный режим, длинный режим или сосредоточены на многоядерной обработке.Я только пишу этот код, чтобы понять, как он работает.
Мой код:
format MZ
USE16
start:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
xor sp, sp
cld
;Clear screen
mov ax, 03h
int 10h
;Move payload to the desired address
mov si, payload
mov cx, payload_end-payload + 1
mov bx,es
mov ax,7c0h
mov es,ax
mov di,400h ;07c0:400 = 8000h
rep movsb
mov es,bx
;Enable APIC table
call enable_lapic
; Wakeup the other APs
;INIT
call lapic_send_init
mov cx, WAIT_10_ms
call us_wait
;SIPI
call lapic_send_sipi
mov cx, WAIT_200_us
call us_wait
;SIPI
call lapic_send_sipi
;Jump to the payload
;Para teste de acordar nucleos
jmp 0000h:8000h ;voltar esse depois
;Payload é o código que será movido para o endereço físico 0x08000
payload:
mov ax, cs
mov ds, ax
xor sp, sp
cld
;Only print letter 'A' directly to video memory
mov cx,0b800h
mov es,cx
mov di,00h
mov al,41h
stosb
cli
hlt
payload_end:
enable_lapic:
mov ecx, IA32_APIC_BASE_MSR
rdmsr
or ah, 08h ;Enable global APIC flag
wrmsr
and ah, 0f0h ; Mask to obtain APIC_Base address
mov DWORD [APIC_BASE], eax ;Save it
shr eax,16
mov bx,fs
mov fs,ax
mov ecx, DWORD [fs:APIC_REG_SIV] ;Load value from SIV (FEE0:00F0) to ecx
or ch, 01h ;bit8: APIC SOFTWARE enable/disable
mov DWORD [fs:APIC_REG_SIV], ecx ;Save it
mov fs,bx
ret
IA32_APIC_BASE_MSR = 1bh
APIC_REG_SIV = 0f0h
APIC_REG_ICR_LOW = 300h
APIC_REG_ICR_HIGH = 310h
APIC_REG_ID = 20h
APIC_BASE dd 00h
;CX = Wait (in ms) Max 65536 us (=0 on input)
us_wait:
mov dx, 80h ;POST Diagnose port, 1us per IO
xor si, si
rep outsb
ret
WAIT_10_ms = 10000
WAIT_200_us = 200
lapic_send_init:
mov eax, DWORD [APIC_BASE]
xor ebx, ebx
shr eax,16
mov cx,fs
mov fs,ax
mov DWORD [fs:APIC_REG_ICR_HIGH], ebx
mov ebx, 0c4500h
mov DWORD [fs:APIC_REG_ICR_LOW], ebx ;Writing the low DWORD sent the IPI
mov fs,cx
ret
lapic_send_sipi:
mov eax, DWORD [APIC_BASE]
xor ebx, ebx
shr eax,16
mov cx,fs
mov fs,ax
mov DWORD [fs:APIC_REG_ICR_HIGH], ebx
mov ebx, 0c4608h
mov DWORD [fs:APIC_REG_ICR_LOW], ebx ;Writing the low DWORD sent the IPI
mov fs,cx
ret
Я ожидаю, что BSP входит в бесконечный цикл, и AP выполняют код в 0000: 8000и напечатайте 'A' в видеопамяти.
11/06/2019 Привет всем!
Теперь у меня есть код, который может получить доступ к защищенному режиму.Поскольку мне трудно перейти в нереальный режим, я решил остаться в защищенном режиме и таким образом включить все ядра.
Это простой код, но, как сказал Майкл Петч, я пытался сделать это вситуация с загрузчиком.
Вот код:
"двоичный формат как 'bin'
use16
org 0x7C00
boot:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
xor sp, sp
;Clear screen
; mov ax, 03h
; int 10h
;Set VGA text mode 3
mov ax,0x3
int 0x10
;Move payload to the desired address
mov si, payload
mov cx, payload_end-payload + 1
;mov si,boot2
;mov cx,boot2_end-boot2+1
mov bx,es
mov ax,7c0h
mov es,ax
mov di,400h ;07c0:400 = 8000h
rep movsb
mov es,bx
;jmp 0000h:8000h
call enableA20Line
call enterProtectedMode
use32
;Enable the APIC
call enable_lapic
;INIT
call lapic_send_init
;mov cx, WAIT_10_ms
;call us_wait
.Verify1:
PAUSE
MOV EBX,[APIC_BASE]
MOV EAX,[EBX+0x300];
SHR EAX,12
TEST EAX,1
JNZ .Verify1
MOV EDI,[APIC_BASE]
ADD EDI,0xB0
MOV dword [EDI],0
;SIPI
call lapic_send_sipi
;mov cx, WAIT_200_us
;call us_wait
.Verify2:
PAUSE
MOV EBX,[APIC_BASE]
MOV EAX,[EBX+0x300];
SHR EAX,12
TEST EAX,1
JNZ .Verify2
MOV EDI,[APIC_BASE]
ADD EDI,0xB0
MOV dword [EDI],0
;SIPI
call lapic_send_sipi
;mov cx, WAIT_200_us
;call us_wait
.Verify3:
PAUSE
MOV EBX,[APIC_BASE]
MOV EAX,[EBX+0x300];
SHR EAX,12
TEST EAX,1
JNZ .Verify3
MOV EDI,[APIC_BASE]
ADD EDI,0xB0
MOV dword [EDI],0
;mov eax,0x8000
;jmp DWORD[eax]
;jmp boot2
;jmp 0x8000
;jmp $
;cli
;hlt
mov eax,0x000b8010
mov dword[eax],0e41h
cli
hlt
use16
enableA20Line:
mov ax,0x2401
int 0x15 ;enable A20 bit
ret
enterProtectedMode:
lgdt[gdt_pointer]
mov eax,cr0
or eax,0x1 ;set the protected mode bit on special cpu reg CR0
mov cr0,eax
jmp CODE_SEG:exit ;long jump to the code segment
exit:
ret
gdt_pointer:
dw gdt_end - gdt_start
dd gdt_start
CODE_SEG = gdt_code - gdt_start
DATA_SEG = gdt_data - gdt_start
gdt_start:
dq 0x0 ;NULL segment
gdt_code:
dw 0xFFFF
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xFFFF
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
;CX = Wait (in ms) Max 65536 us (=0 on input)
us_wait:
mov dx, 80h ;POST Diagnose port, 1us per IO
xor si, si
rep outsb
ret
WAIT_10_ms = 10000
WAIT_200_us = 200
use32
enable_lapic:
mov ecx, IA32_APIC_BASE_MSR
rdmsr
or ah, 08h ;bit11: APIC GLOBAL Enable/Disable
wrmsr
and ah, 0f0h
mov DWORD [APIC_BASE], eax
mov ecx, DWORD [eax+APIC_REG_SIV]
;or ch, 01h ;bit8: APIC SOFTWARE enable/disable
or edx,01FFh
mov DWORD [eax+APIC_REG_SIV], ecx
mov DWORD[eax+0B0h],00h
ret
lapic_send_init:
mov eax, DWORD [APIC_BASE]
xor ebx, ebx
mov DWORD [eax+APIC_REG_ICR_HIGH], ebx
mov ebx, 0c4500h
mov DWORD [eax+APIC_REG_ICR_LOW], ebx ;Writing the low DWORD sent the IPI
ret
lapic_send_sipi:
mov eax, DWORD [APIC_BASE]
xor ebx, ebx
mov DWORD [eax+APIC_REG_ICR_HIGH], ebx
mov ebx, 0c4608h
mov DWORD [eax+APIC_REG_ICR_LOW], ebx ;Writing the low DWORD sent the IPI
ret
IA32_APIC_BASE_MSR = 1bh
APIC_REG_SIV = 0f0h
APIC_REG_ICR_LOW = 300h
APIC_REG_ICR_HIGH = 310h
APIC_REG_ID = 20h
APIC_BASE dd 00h
boot2:
mov ax,DATA_SEG
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov esi,hello2
mov ebx,0b8000h
.loop:
lodsb
or al,al
jz halt
or eax,0x0100
mov word[ebx],ax
add ebx,2
jmp .loop
halt:
cli
hlt
hello2: db "Hello world!",0
boot2_end:
use16
payload:
mov ax,cs
mov ds,ax
xor sp,sp
mov ax,0b800h
mov es,ax
mov di,20h
mov ax,0e45h
mov [es:di],al
cli
hlt
;jmp $
payload_end:
times 510 - ($-$$) db 0 ; pad remaining 510 bytes with zeroes
dw 0xaa55 ; magic bootloader magic - marks this 512 byte sector bootable!"
Теперь я ищу процедуру задержки для отправки init и sipiЯ думаю, что это проблема, потому что это еще не работает.
BSP печатает букву «А» в позиции 10, и любой должен напечатать еще одну букву в позиции 20, но печатается только «А».
Есть какие-нибудь идеи, чтобы помочь мне, пока я ищу, как заставить его работать?
Заранее спасибо.
OBS: теперь я узнал, как использовать "qemu""эмулятор, и я имитирую все внутри него.
ВТОРОЕ РЕДАКТИРОВАНИЕ: КОД работает. Я использую эмулятор qemu только с 1 ядром. Когда я использую 2 или более ядер, код работает !!
Вам нужно использовать "qemu-system-x86_64 -cpu 486 -smp 2 'path'" без кавычек.
12/06/2019 Я пытался запустить его на реальном компьютере, но он только выполняет цикл сброса.Кто-нибудь знает об этом?
14/06/2019 Привет!Я снова здесь!Я имею дело с этой большой проблемой линейной адресации внутри DOS и решаю ее с помощью предыдущей программы .exe, которая копирует kernel.bin (программу, отправляющую INIT-SIPI-SIPI) на адрес 0xXXXXXXXX.Внутри kernel.bin я поставил «org 0xXXXXXXXX», теперь мне не нужно решать все указатели, которые я использую.Теперь последовательность INIT-SIPI-SIPI работает.
Ссылка: Переключение из защищенного режима в реальный режим в программе DOS EXE
Еще одна вещь, которую мне нужно сделать, этовыйдите из защищенного режима перед выходом из программы.Если я этого не сделаю, DOS вылетит.Поэтому я использовал ссылку выше, чтобы решить линейную адресацию (скопировав большую часть кода в известную позицию в памяти) и вернуть управление в DOS.
Это было забавно, потому что я помещал ядра AP в циклическую печать "Helloиз другого ядра "на экране и программы выхода BSP и возвращается к DOS.Независимо от того, что вы делаете, сообщение не может быть очищено.
Знайте, я буду работать над простым кодом батута, чтобы расставить ядра в разных положениях и выполнить 4 встречных подпрограммы.Это начало функции, чтобы разбудить ядра и дать им некоторую работу.После того, как я буду реализовывать обнаружение таблиц MP и MDAT, нужно сделать правильный путь.
Спасибо!