OSDev http://osdev.su/ |
|
Самый простой способ запустить SMP http://osdev.su/viewtopic.php?f=6&t=1318 |
Страница 1 из 1 |
Автор: | gdt [ 17 апр 2017, 16:05 ] |
Заголовок сообщения: | Самый простой способ запустить SMP |
Всем привет! Пытался завести smp, исходники брал https://github.com/pdoane/osdev - не завелось) Но это другой разговор. И на какое время забросил все, пока не наткнулся на http://stackoverflow.com/questions/9809 ... -look-like Там в камменте есть код запуска AP колхозным способом - без парсинга таблиц, напрямую писать в регистр(предполагая, что по этому адресу таки отражен регистр). Так делать нельзя ICR_LOW = 0xFEE00300 Код: MOV ESI, ICR_LOW ; Load address of ICR low dword into ESI. MOV EAX, 000C4500H ; Load ICR encoding for broadcast INIT IPI ; to all APs into EAX. MOV [ESI], EAX ; Broadcast INIT IPI to all APs ; 10-millisecond delay loop. MOV EAX, 000C46XXH ; Load ICR encoding for broadcast SIPI IP ; to all APs into EAX, where xx is the vector computed in step 10. MOV [ESI], EAX ; Broadcast SIPI IPI to all APs ; 200-microsecond delay loop MOV [ESI], EAX ; Broadcast second SIPI IPI to all APs ; Waits for the timer interrupt until the timer expires У меня получился такой код Вот что он должен делать: -копировать trampoline код для AP по известному адресу, у нас это 0x1000 - вектор 0x01 (это то, что мы отправляем SIPI IP) -выполнять INIT-SIPI-SIPI -AP должен выполнить trampoline код, который инкрементирует переменную по известному адресу - 0x2000 Код: .equ STARTUP_CODE_ADDRESS, 0x1000 .equ SPINLOCK_ADDRESS, 0x2000 /* PIC */ .equ PIC_ICR_ADDRESS, 0xFEE00300 .equ IA32_APIC_BASE, 0x1B /* Must come before they are used. */ .equ CODE_SEG, 8 .equ DATA_SEG, gdt_data - gdt_start /* 10 */ .code16 .global _start _start: cli xor %ax, %ax mov %ax, %ds lgdt gdt_descriptor mov %cr0, %eax orl $0x1, %eax mov %eax, %cr0 ljmp $CODE_SEG, $protected_mode .code32 protected_mode: mov $DATA_SEG, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs mov %ax, %ss /* Копируем trampoline код, теперь он доступен по адресу 0x1000 */ cld movl $init_len, %ecx movl $init, %esi movl $STARTUP_CODE_ADDRESS, %edi rep movsb /* Обнуляем SPINLOCK_ADDRESS - общая для всех процессоров переменная*/ movb $0x00, SPINLOCK_ADDRESS /* Включаем APIC */ movl $IA32_APIC_BASE, %ecx rdmsr bts $11, %eax wrmsr /* Load address of ICR low dword into ESI. */ movl $PIC_ICR_ADDRESS, %esi /* Load ICR encoding for broadcast INIT IPI to all APs. */ movl $0x000C4500, %eax /* Broadcast INIT IPI to all APs */ movl %eax, (%esi) /* 10-millisecond delay loop. */ movl $0x000fffff,%ecx delay10: dec %ecx jnz delay10 /* Load ICR encoding for broadcast SIPI IP to all APs. The low byte of this is the vector which encodes the staring address for the processors! This address is multiplied by 0x1000: processors start at CS = vector * 0x100 and IP = 0. mov $0x000C4600 + STARTUP_CODE_ADDRESS / 0x1000, %eax */ movl $0x000C4601, %eax /* Broadcast SIPI IPI to all APs. */ movl %eax, (%esi) /* 200-microsecond delay loop. */ /* Broadcast second SIPI IPI to all APs */ movl %eax, (%esi) /* Здесь ждем запуска 3-х процессоров */ not_started: cmpb $3, SPINLOCK_ADDRESS jne not_started ok: movl $0x254B254F, 0xb8000 //print 'OK' hlt /* Trampoline код */ .code16 init: cli cld xor %ax, %ax mov %ax, %ds mov %ax, %es mov %ax, %ss incb SPINLOCK_ADDRESS wbinvd hlt .equ init_len, . - init /* GDT */ gdt_start: gdt_null: .long 0x0 .long 0x0 gdt_code: .word 0xffff .word 0x0 .byte 0x0 .byte 0b10011010 .byte 0b11001111 .byte 0x0 gdt_data: .word 0xffff .word 0x0 .byte 0x0 .byte 0b10010010 .byte 0b11001111 .byte 0x0 gdt_end: gdt_descriptor: .word gdt_end - gdt_start .long gdt_start .org 510 .word 0xaa55 Makefile Код: MAIN := main.img
$(MAIN): main.S $(AS) -o main.o '$<' $(LD) --oformat binary -o '$@' -Ttext 0x7C00 main.o clean: rm -f '$(MAIN)' run: $(MAIN) qemu -smp 4 -fda '$(MAIN)' |
Автор: | gdt [ 24 апр 2017, 14:36 ] |
Заголовок сообщения: | Re: Самый простой способ запустить SMP |
Теперь заработало. Я просто невероятно счастлив!) Запутался в скобочках, $ и поинтерах в асме. Лог боша - бесценен. А еще APIC нужно включать перед работой) На свой вопрос про паузы INIT-SIPI-SIPI (10мс и 200мс) ответ получил: qemu и vmware - без делея работают, бош - нужно выдержать только первую задержку 10мс. Поэтому в коде есть loop между INIT и SIPI Так же во всех эмуляторах и гипервизоре можно выполнить упрощенно INIT-SIPI. Хотя должно быть INIT - SIPI с нулевым вектором - SIPI с вектором. qemu отрабатывает правильно, а бош и vmware почему-то выполняют SIPI с нулевым вектором, хотя должны отбросить этот вектор и ждать следующий SIPI. Код: 00029807591i[APIC1 ] Deliver Start Up IPI 00029807591i[CPU1 ] CPU 1 started up at 0000:00000000 by APIC Код в обновил. Хотелось бы вычистить код от мусора и сделать законченный учебный пример. |
Автор: | pavia [ 25 апр 2017, 06:55 ] |
Заголовок сообщения: | Re: Самый простой способ запустить SMP |
Это было бы замечательно. |
Автор: | Himik [ 11 июн 2017, 21:49 ] |
Заголовок сообщения: | Re: Самый простой способ запустить SMP |
Только лучше в intel-синтаксисе (ключ -masm=intel), а то выглядит архаично. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |