diff --git a/Makefile b/Makefile index b99b716..2eb9643 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ clean: rm -fr *$(OBJ_EXT) *$(OUT_EXT) *$(TMP_EXT) run: all - $(QEMU) -smp 2 '$(RUN_FILE)' + $(QEMU) -drive 'file=$(RUN_FILE),format=raw' -smp 2 debug: all $(QEMU) -hda '$(RUN_FILE)' -S -s & diff --git a/TODO.md b/TODO.md index 2c9d9cd..b841237 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,13 @@ # TODO -- cache: wbinvd +- cache: + + - http://stackoverflow.com/questions/1756825/how-can-i-do-a-cpu-cache-flush + - http://stackoverflow.com/questions/10989403/how-is-x86-instruction-cache-synchronized + + - wbinvd: write back from cache to memory, and invalidate all cache + - invd: just invalidate, but don't write back + - clflush: flush only selected cache lines - lidt, interrupts, IDTR: @@ -29,14 +36,8 @@ Bunch of basic dupes: + - answered: http://stackoverflow.com/questions/4119504/real-mode-memory-addressing-explanation - http://stackoverflow.com/questions/3819699/what-does-ds40207a-mean-in-assembly - - http://stackoverflow.com/questions/17210620/assembler-calculating-a-memory-address-with-register-base?lq=1 - - http://stackoverflow.com/questions/18736663/what-does-the-colon-mean-in-x86-assembly-gas-syntax-as-in-dsbx - - http://stackoverflow.com/questions/20717890/how-to-interpret-gs0x14?lq=1 - - http://stackoverflow.com/questions/26058665/fs-register-in-assembly-code?lq=1 - - http://stackoverflow.com/questions/4903906/assembly-using-the-data-segment-register-ds answer with minimal example and mention QEMU vs real hardwre http://wiki.osdev.org/Segmentation - - http://stackoverflow.com/questions/7844963/how-to-interpret-segment-register-accesses-on-x86-64?lq=1 - - http://stackoverflow.com/questions/9249315/what-is-gs-in-assembly?rq=1 In actual OSes: @@ -79,20 +80,6 @@ - ACPI -- multiprocessing, multi-threading: - - - http://stackoverflow.com/questions/7308391/how-is-concurrency-done-in-intel-x86-assembly - - http://stackoverflow.com/questions/980999/what-does-multicore-assembly-language-look-like - - http://stackoverflow.com/questions/714905/threads-in-x86-assembler-using-the-gnu-assember-as - - http://stackoverflow.com/questions/1622388/running-code-on-different-processor-x86-assembly - - https://github.com/cirosantilli/oszur11-operating-system-examples/tree/1af6451852887fac3d7206d4d09714c181c81d1e/Chapter_07_Threads - - http://stackoverflow.com/questions/663958/how-to-control-which-core-a-process-runs-on - - http://stackoverflow.com/questions/2986931/the-way-cores-processes-and-threads-work-exactly?rq=1 - - http://stackoverflow.com/questions/1516530/assembly-and-multicore-cpus?lq=1 - - http://stackoverflow.com/questions/419486/multithreading-and-interrupts - - http://stackoverflow.com/questions/15091165/inter-processor-interrupt-usage - - http://stackoverflow.com/questions/26452323/how-can-we-use-multi-core-and-cpu-on-assembly-boot-loader-x86 - - play with hardware - set a pixel on screen in protected mode http://stackoverflow.com/questions/14419088/assembly-draw-a-pixel-on-the-screen-in-protected-mode @@ -140,3 +127,5 @@ - BIOS memory detect: http://stackoverflow.com/questions/21820814/what-happens-with-a-processor-when-it-tries-to-access-a-nonexistent-physical-add + +- `40h:6Ch` a bios timer incremented at 18.2 Hz: ` diff --git a/bios.md b/bios.md index 8db1038..63a1faf 100644 --- a/bios.md +++ b/bios.md @@ -4,8 +4,6 @@ - - Can only be used in real mode. ## Documentation diff --git a/bios_carriage_return.S b/bios_carriage_return.S index 7701431..3b2e370 100644 --- a/bios_carriage_return.S +++ b/bios_carriage_return.S @@ -11,7 +11,7 @@ Carriage returns are needed just like in old days. #include "common.h" BEGIN - PRINT $msg + PRINT_STRING $msg hlt msg: .asciz "hello\n\rworld" diff --git a/bios_newline.S b/bios_newline.S index abc2f9e..325e288 100644 --- a/bios_newline.S +++ b/bios_newline.S @@ -11,7 +11,7 @@ Carriage returns are needed just like in old days. #include "common.h" BEGIN - PRINT $msg + PRINT_STRING $msg hlt msg: .asciz "hello\nworld" diff --git a/bios_scroll.S b/bios_scroll.S index 856065f..94afb57 100644 --- a/bios_scroll.S +++ b/bios_scroll.S @@ -37,7 +37,7 @@ which gets filled with the background color in bh. BEGIN CLEAR -PRINT $stair +PRINT_STRING $stair /* Function ID. */ mov $0x06, %ah diff --git a/common.h b/common.h index b7e825c..bff646c 100644 --- a/common.h +++ b/common.h @@ -455,12 +455,12 @@ Print a null terminated string. Use as: - PRINT $s + PRINT_STRING $s hlt s: .asciz "string" */ -.macro PRINT s +.macro PRINT_STRING s LOCAL end, loop mov s, %si mov $0x0e, %ah @@ -651,3 +651,5 @@ end: /* PIC. */ #define PIC_CMD_RESET $0x20 +#define PIC_ICR_ADDRESS $0xFEE00300 + diff --git a/gdb.gdb b/gdb.gdb index 2d8e5bd..c648388 100644 --- a/gdb.gdb +++ b/gdb.gdb @@ -14,7 +14,7 @@ end break *0x7c00 continue -# 0x1234 is a magic address. Add a: +# Magic address. Add a: # mov %ax, 0x1234 # to your program to break there. awatch *0x9000 diff --git a/initial_state.S b/initial_state.S index 48ef32b..d69b7b3 100644 --- a/initial_state.S +++ b/initial_state.S @@ -31,7 +31,7 @@ Thus it usually contains 0x80. .endm .macro INITIAL_PRINT x - PRINT $\x\()s + PRINT_STRING $\x\()s PRINT_BYTES $\x, $2 PRINT_NEWLINE .endm @@ -79,7 +79,7 @@ STAGE2 .irp reg, ax, bx, cx, dx, cs, ds, es, fs, gs, ss INITIAL_PRINT \reg .endr - PRINT $cr0s + PRINT_STRING $cr0s PRINT_BYTES cr0, $4 PRINT_NEWLINE diff --git a/modes-of-operation.md b/modes-of-operation.md index 25d10ea..041fd48 100644 --- a/modes-of-operation.md +++ b/modes-of-operation.md @@ -13,6 +13,17 @@ Covered on Intel Volume 3. Specially useful is the "Transitions Among the Proces CPU starts here for backwards compatibility. + + +It is possible to use 32-bit registers in this mode with the "Operand Size Override Prefix" `0x66`. + +TODO: is it possible to access memory above 1M like this: + + mov $1, 0xF0000000 + mov $1, (%eax) + + + ## IA-32e Wikipedia seems to call it *long mode*: diff --git a/smp.S b/smp.S index c5edf9e..99ba87c 100644 --- a/smp.S +++ b/smp.S @@ -1,38 +1,105 @@ /* # SMP + +Expected output: "SMP started" + +TODO get working: + +- http://stackoverflow.com/questions/16364817/assessing-the-apic-and-creating-ipis-in-x86-assembly + Closest quesiton so far! Almost there! + Table 8-1. Broadcast INIT-SIPI-SIPI Sequence and Choice of Timeouts contains actual code! + TODO: how to sleep the right ammount of time? +- http://stackoverflow.com/questions/15091165/inter-processor-interrupt-usage +- http://stackoverflow.com/questions/1516530/assembly-and-multicore-cpus?lq=1 +- http://stackoverflow.com/questions/1622388/running-code-on-different-processor-x86-assembly +- http://stackoverflow.com/questions/26452323/how-can-we-use-multi-core-and-cpu-on-assembly-boot-loader-x86 +- http://stackoverflow.com/questions/2986931/the-way-cores-processes-and-threads-work-exactly?rq=1 +- http://stackoverflow.com/questions/419486/multithreading-and-interrupts +- http://stackoverflow.com/questions/663958/how-to-control-which-core-a-process-runs-on +- http://stackoverflow.com/questions/714905/threads-in-x86-assembler-using-the-gnu-assember-as +- http://stackoverflow.com/questions/7308391/how-is-concurrency-done-in-intel-x86-assembly +- http://stackoverflow.com/questions/980999/what-does-multicore-assembly-language-look-like +- http://stackoverflow.com/questions/28047092/by-which-instruction-the-secondary-core-is-triggered-while-starting-the-secondar?rq=1 +- http://stackoverflow.com/questions/23962839/how-to-correctly-use-a-startup-ipi-to-start-an-application-processor?rq=1 +- https://github.com/cirosantilli/oszur11-operating-system-examples/tree/1af6451852887fac3d7206d4d09714c181c81d1e/Chapter_07_Threads */ #include "common.h" BEGIN + CLEAR + /* + TODO do we need 32-bit mode? The APIC register + FEE00300 is too high for 16-bit? + */ + PROTECTED_MODE /* Setup the code that will be run on the other processors when they start up. + Should be somewhere into the first 1Mb, + as processors starte in real mode. */ + cld mov $init_len, %ecx mov $init, %esi - mov $0xFFFFFFF0, %edi + mov $0x1000, %edi rep movsb + /* Setup the value that threads will modify for us. */ + movb $0, 0x2000 + /* - Destination Shorthand = 11 = all except self - Trigger Mode = ? - Level = ? - Delivery Status = 0 = Idle - Destination Mode = ? = Does not matter since shorthand used - Delivery Mode = 110 = Startup - Vector = ? = does it matter for SIPI? + Move data into the lower ICR register: + this should start the other processors. + - Destination Shorthand = 11 = all except self + - Trigger Mode = ? + - Level = ? + - Delivery Status = 0 = Idle + - Destination Mode = ? = Does not matter since shorthand used + - Delivery Mode = 110 = Startup + - Vector = ? = does it matter for SIPI? */ - movl $0x000C0600, 0xFEE00300 + + /* Load address of ICR low dword into ESI. */ + mov PIC_ICR_ADDRESS, %esi + /* Load ICR encoding for broadcast INIT IPI to all APs. */ + mov $0x000C4500, %eax + /* Broadcast INIT IPI to all APs */ + mov %eax, (%esi) + /* + 10-millisecond delay loop. + TODO + */ + /* + 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. + */ + /*TODO*/ + mov $0x000C4601, %eax + /* Broadcast SIPI IPI to all APs. */ + mov %eax, (%esi) + /* 200-microsecond delay loop. */ + /* TODO */ + /* Broadcast second SIPI IPI to all APs */ + mov %eax, (%esi) + /* Wait for the timer interrupt until the timer expires. */ /* Busy loop until another thread changes this memory. */ - movb $0, 0x2000 not_started: cmpb $1, 0x2000 jne not_started - PUTC $'a + + VGA_PRINT_STRING $message + /* Testing if it is possible in 16-bit real mode. */ + /*PRINT_STRING $message*/ hlt +message: + .asciz "SMP started" +.code16 init: - movl $1, 0x2000 + movb $1, 0x2000 + /* TODO mandatory? */ + wbinvd hlt .equ init_len, . - init diff --git a/smp.md b/smp.md index 22a834b..8b49c59 100644 --- a/smp.md +++ b/smp.md @@ -10,7 +10,9 @@ > Wait-for-SIPI. As part of its initialization, the primary thread sends a special inter-processor-interrupt (IPI) over the APIC called a SIPI (Startup IPI) to each thread that is in WFS. The SIPI contains the address from which that thread should start fetching code. -- https://en.wikipedia.org/wiki/Inter-processor_interrupt +- + +- - Linux kernel `arch/x86/kernel/smpboot.c` @@ -32,7 +34,7 @@ GPU competitor basically. - One huge advantage: Phi is programmed with x86! + One huge advantage: Phi is programmed with x86, unlike GPUs which have no low level API: - - @@ -46,3 +48,20 @@ processors on the system bus as the BSP. The remaining processors are designated > Following a power-up or reset, the APs complete a minimal self-configuration, then wait for a startup signal (a SIPI message) from the BSP processor. Upon receiving a SIPI message, an AP executes the BIOS AP configuration code, which ends with the AP being placed in halt state. + +## AP + +Application processor: all processors except the boot one. + +## ICR + +## Interrupt command register + +When we write to it, interrupts are sent. + +It is memory mapped to `0xFEE0 0300`. + +[Intel Manual Volume 3 System Programming Guide - 325384-056US September 2015](https://web.archive.org/web/20151025081259/http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-system-programming-manual-325384.pdf) + +- 10.6 "ISSUING INTERPROCESSOR INTERRUPTS" documents its format +- Table 10-1 Local APIC Register Address Map documents where it is mapped to in memory