亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 2139 | 回復(fù): 3
打印 上一主題 下一主題

[CPU及多核] 多核與cache [復(fù)制鏈接]

論壇徽章:
13
程序設(shè)計版塊每日發(fā)帖之星
日期:2016-06-29 06:20:00每日論壇發(fā)貼之星
日期:2016-08-14 06:20:00操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-08-14 06:20:00每日論壇發(fā)貼之星
日期:2016-08-13 06:20:00數(shù)據(jù)庫技術(shù)版塊每日發(fā)帖之星
日期:2016-08-13 06:20:00程序設(shè)計版塊每日發(fā)帖之星
日期:2016-08-13 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-08-13 06:20:00每日論壇發(fā)貼之星
日期:2016-08-12 06:20:00數(shù)據(jù)庫技術(shù)版塊每日發(fā)帖之星
日期:2016-08-12 06:20:00程序設(shè)計版塊每日發(fā)帖之星
日期:2016-08-12 06:20:00操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-08-12 06:20:00綜合交流區(qū)版塊每日發(fā)帖之星
日期:2016-08-09 06:20:00
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2016-08-28 11:03 |只看該作者 |倒序瀏覽
本帖最后由 karma303 于 2016-08-28 11:06 編輯

------------舊帖重發(fā),希望管理員不要再刪帖了----------

自己最近在學(xué)習(xí)smp,順便寫下這些文章,跟大家分享。面向的讀者,是對x86硬件和os內(nèi)核有一定基礎(chǔ)的程序員。這個系列的主線,是實現(xiàn)一個簡單的,基于IA32的多核操作系統(tǒng)。

第一篇  點著每一個核
1.1   初識APIC
1.2   從修改bios開始


1.1 初識APIC
  從P6家族的CPU開始,intel引入了初始化多核的硬件機(jī)制. cpu上電之后,硬件會自動選擇一個核作為BSP(boot-strap processor), 剩余的核作為AP(application processor).注意,取這兩個名字,并不是因為這些核在硬件結(jié)構(gòu)上有區(qū)別,這些核是一模一樣的.只是在初始化階段,扮演的角色不同,AP幾乎2是剛上電就halt住1,而BSP則會像傳統(tǒng)的單核cpu里那樣,跳去執(zhí)行bios代碼.

  那么,怎樣把一段代碼交給某個ap執(zhí)行呢? 這是我才接觸多核時,第一關(guān)心的問題. 因為知道這一點,就知道怎么寫一個多核的操作系統(tǒng)了.
  先不看intel是怎么做的,現(xiàn)在假設(shè)你是硬件工程師,你會怎么設(shè)計?
  AP核都已經(jīng)"睡著"了,只有BSP核在運行我們的代碼,所以需要bsp給AP發(fā)消息,告訴它去執(zhí)行哪一段代碼. 發(fā)消息就是發(fā)中斷. cpu3通過中斷號跳轉(zhuǎn)到某段代碼是我們再熟悉不過的了.
  
  intel跟我們設(shè)計的大同小異, 為了實現(xiàn)核與核之間的通信,它設(shè)計了新的中斷控制器,取代舊有的8259A,名字也很形象,就叫andvanced programmable interrupt controller(APIC). 每個核有一個屬于自己的apic.
  

  (圖中的"IPI"即inter-processor interrupt, 即剛才提到的"核于核之間的中斷", 圖中的#processor都是一個core)

  向所有AP廣播IPI是很簡單的,只需要操作APIC的64位⁴的ICR寄存器: 往低32位寫入一個double word, IPI就發(fā)出去了.
  

  我們關(guān)心的位段是:
  Destination Shothand:
  00 No Shorthand    即禁用shorthand模式,因為有時我們往指定
                      的core發(fā)送IPI,就需要往ICR高32位寄存器的
                    destination field里填寫詳細(xì)的地址(通常是目
                    標(biāo)core的apic id)
  01 self
  10 all Including self
  11 all excluding self        這個是我們需要的

  Delivery Mode:    發(fā)送什么類型的IPI
  000: Fixed    即常規(guī)中斷,中斷號在vector位段里
  100: NMI        不可屏蔽中斷,會導(dǎo)致硬件重啟. vector ignored
  101: INIT        cause target core perform an INIT. vector must be 0
  110: Start Up   

  Delivery Status:  read only, 指示上次IPI的發(fā)送狀態(tài)
  0: Idle    發(fā)送完成
  1: Send Pending    發(fā)送未完成
  
  一些不常用的位,我們設(shè)置一下就不管它了.
  Destination Mode:  0
  Level          :   1
  Trigger Mode:        0

  我們再回憶一下我們的構(gòu)想:我們要給APs廣播一個IPI,通過這個IPI攜帶的中斷號,讓所有的AP跳去執(zhí)行某段代碼.
  就FIX類型的IPI而言, 它的實現(xiàn)跟我們的構(gòu)想完全一致.但在對AP的初始化上,也就是cpu上電后,APs進(jìn)入等待狀態(tài),怎么讓它們由這個狀態(tài)跳去執(zhí)行"某段代碼"(通常是為他們安排的初始化代碼)呢,intel的做了專門的設(shè)計,這個設(shè)計屬于IA32上smp 初始化協(xié)議⁵的一部分:
  1, 要往AP廣播兩次IPI,而不是一次.
     首先廣播一個INIT類型的IPI,然后廣播一個start-up類型的IPI.
  2, start-up IPI里的vector位段存放的不是中斷號,而是(target code address base / 0x1000). intel應(yīng)該是刻意的避免smp的初始化依賴于實模式的中斷機(jī)制.⁶

  好了, 現(xiàn)在我們可以暢想一下自己的代碼了(雖然對APIC的編程還不是很有信心). 我們計劃讓APs跳去執(zhí)行這樣一段代碼⁷:
  inc byte [cpu_count]
  mov bx, 0xb800
  mov ds, bx
  l: inc [cpu_count]
  jmp l
  cpu_count: db 0
  預(yù)想的結(jié)果,是屏幕左上角開始的第2個字符,一直到第(2+AP_count-1)個字符,會同時快速的跳躍. 每個字符的跳躍,對應(yīng)著一個核的運轉(zhuǎn).


  下一小節(jié)見.   2015,10,4

---------------------------------------------------------------------
1. 我用halt,只是形容它的狀態(tài),不是說它執(zhí)行了hlt指令.
2. 會完成一個硬件上的minimal self-configuration.
3. 準(zhǔn)確說應(yīng)該是"核", 以后此類的都需要你靠上下文區(qū)分.
4, In xAPIC mode the ICR is addressed as two 32-bit registers, ICR_LOW(ffe0 0300H) and ICR_HIGH(FFE0 0310H).
5, Multiprocessor Specification Version 1.4, 所謂協(xié)議,應(yīng)該是跟bios程序員的協(xié)議吧~
6, 在hlt模式下能不能直接用FIX IPI做跳轉(zhuǎn), 目前還沒測.
7, nasm語法,以后的匯編器也會使用nasm.


下一節(jié)  從修改bios開始

評分

參與人數(shù) 1可用積分 +10 收起 理由
amarant + 10 贊一個!

查看全部評分

論壇徽章:
13
程序設(shè)計版塊每日發(fā)帖之星
日期:2016-06-29 06:20:00每日論壇發(fā)貼之星
日期:2016-08-14 06:20:00操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-08-14 06:20:00每日論壇發(fā)貼之星
日期:2016-08-13 06:20:00數(shù)據(jù)庫技術(shù)版塊每日發(fā)帖之星
日期:2016-08-13 06:20:00程序設(shè)計版塊每日發(fā)帖之星
日期:2016-08-13 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-08-13 06:20:00每日論壇發(fā)貼之星
日期:2016-08-12 06:20:00數(shù)據(jù)庫技術(shù)版塊每日發(fā)帖之星
日期:2016-08-12 06:20:00程序設(shè)計版塊每日發(fā)帖之星
日期:2016-08-12 06:20:00操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-08-12 06:20:00綜合交流區(qū)版塊每日發(fā)帖之星
日期:2016-08-09 06:20:00
2 [報告]
發(fā)表于 2016-08-28 11:08 |只看該作者
1.2 從修改bios開始

  上一節(jié)末尾,我們決定對apic編程,讓cpu的每個AP核執(zhí)行一段loop代碼,使屏幕上的對應(yīng)區(qū)域的字符不停跳躍,變動。
  你肯定覺得,應(yīng)該在mbr里寫我們的代碼。是的,我開始就是這么做的。像這樣( 這不是我最初的“版本”,那個“版本”被逐漸修改掉了):
org 0x7c00
[bits 16]

;re-map apic base address to 0x8000
mov ecx, 1bh
rdmsr
and eax, 0xfff
or eax, 0x8000
wrmsr

;copy boot code for ap
;memcpy( ( char *)0x7000, unified_entry, 0xff )
mov ax, 0
mov es, ax
mov ds,ax
mov di, 0x7000
mov si, unified_entry
cld
mov cx, 0xff    ;enough
rep movsb

;send ipi
mov bx,0
mov ds,bx
mov dword [0x8300], 0xc4500        ;INIT IPI
mov dword [0x8300], 0xc4600|7        ;sipi, 7=0x7000<<12
jmp $        

unified_entry:        ;boot code for ap
    inc word [ap_count]   
    mov bx,0xb800
    mov gs,bx
    mov bx, [ap_count]
    shl bx, 1
    .spin:
        inc byte [gs:bx]
    jmp .spin   
ap_count: dw 0

jmp $
times 510-($-$$) db 0
dw 0x55aa

  這些代碼你能看個大概,除了開頭一段。那是把APIC寄存器映射到低端內(nèi)存, 因為它默認(rèn)是影射在0xFEE00300處,實模式下訪問不了1。
  但是,當(dāng)我們把這個文件匯編,dd到虛擬硬盤,啟動bochs2————屏幕上沒有動靜。
  這真是糟糕,這幾乎是最壞的結(jié)果。我們寧可bochs崩潰,那至少說明我們的指令做了什么。
  現(xiàn)在,怎么應(yīng)對就因人而異了:
  我們的第一反應(yīng)的大概都是Ctrl+C, info一下cpu,開始思索怎么調(diào)試,但你很快發(fā)現(xiàn)在bochs下調(diào)試smp不那么容易,我們只能info出來bsp的cpu,而且像APIC這種內(nèi)存映射式的寄存器,用xp命令查不了(那就是怎么都查不了了 );
  然后大概是google。網(wǎng)上能搜到的資料只有intel文檔.你可以選擇更細(xì)致的讀它(這是比較考驗心理素質(zhì)的);
  最后就是去論壇(比較少,我知道的只有osdev)問,像這種問題,只能是貼代碼問,似乎有些掃興。這還不是最壞的,最壞的是你在依賴論壇來解決非解決不可的問題,如果你有自學(xué)的經(jīng)歷,你應(yīng)該知道我在說什么。
   
  所以,選擇從修改bios開始,只是作者選擇的一種途徑。因為我之前知道bios有對apic的操作。我們準(zhǔn)備找到它那一部分代碼,先涂涂抹抹————我們急切的想看到APIC乃至AP能對我們的編程,作出一點響應(yīng)。


  bochs的bios代碼放在bochs-2.6/bios目錄下,它與bochs虛擬機(jī)是獨立的,不會被編譯鏈接進(jìn)bochs,這個目錄下有一個Makefile文件,控制其中的代碼最終生成一個BIOS-bochs-latest的二進(jìn)制文件,它相當(dāng)于真實機(jī)器里bios rom的鏡像,bios啟動時,會把它加載到0xf0000地址并跳去執(zhí)行,這與真實的機(jī)器沒有區(qū)別。
  bios起始是在16位模式下運行的, 中途會切換到保護(hù)模式,最后再切回實模式。我們關(guān)心的代碼集中在兩個文件:rombios32start.S和rombios32.c。下面,我們快速的把它們?yōu)g覽一遍。
  匯編代碼準(zhǔn)備好保護(hù)模式的運行環(huán)境后,會跳到c函數(shù)rombios32_init。我們在rombios32start.S一開始就看到這個跳轉(zhuǎn)動作:
>>>>>>>>>>>>>>>>>>>>>>>>>>>
_start:
  /* clear bss section */
  xor %eax, %eax
  mov $__bss_start, %edi
  mov $__bss_end, %ecx
  sub %edi, %ecx
  rep stosb

  /* copy data section */
  mov $_end, %esi
  mov $__data_start, %edi
  mov $__data_end, %ecx
  sub %edi, %ecx
  rep movsb

  jmp rombios32_init
<<<<<<<<<<<<<<<<<<<<<<<<

C函數(shù)robios32_init位于rombios32.c,函數(shù)不長,也很易讀:

>>>>>>>>>>>>>>>>>>>>>>>( 刪掉了部分針對qemu, EBDA的條件編譯,異常關(guān)機(jī)和屏幕打印代碼 )
void rombios32_init(uint32_t *s3_resume_vector,
                    uint8_t *shutdown_flag)
{
    ...
    ram_probe();
    cpu_probe();
    setup_mtrr();
    smp_probe();
    find_bios_table_area();
    if (*shutdown_flag == 0xfe) {
        ...
    }
    pci_bios_init();
    mptable_init();

    if (bios_table_cur_addr != 0 && i440_pcidev.bus != -1) {
        uuid_probe();
        smbios_init();
    }

    if (acpi_enabled)
        acpi_bios_init();
    ...
}
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

'probe'是“探測”,我們注意到上面調(diào)用了smp_probe()這個函數(shù),沒錯,apic的初始化就是在這兒完成的:

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/* find the number of CPUs by launching a SIPI to them */
void smp_probe(void)
{
    uint32_t val, sipi_vector;

    writew(&smp_cpus, 1);
    if (cpuid_features & CPUID_APIC) {

        /* enable local APIC */
        val = readl(APIC_BASE + APIC_SVR);
        val |= APIC_ENABLED;
        writel(APIC_BASE + APIC_SVR, val);

        /* copy AP boot code */
        memcpy((void *)AP_BOOT_ADDR, &smp_ap_boot_code_start,
               &smp_ap_boot_code_end - &smp_ap_boot_code_start);

        /* broadcast SIPI */
        writel(APIC_BASE + APIC_ICR_LOW, 0x000C4500);
        sipi_vector = AP_BOOT_ADDR >> 12;
        writel(APIC_BASE + APIC_ICR_LOW, 0x000C4600 | sipi_vector);
        ...
}
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  writew和writel分別是寫雙字節(jié)和4字節(jié)(^.^), 這段c代碼簡直就是我們剛才mbr的匯編碼的雙胞胎,唯一不同的是,它在一開始操作了一個叫APIC_SVR的寄存器,這是我們聞所未聞的,原來APIC默認(rèn)是disable的!
  這是一個好的信號,隨著對bios的熟悉,我們不經(jīng)意發(fā)現(xiàn)原先的代碼可能錯在哪兒,它為什么不工作。
  但此時,我才懶得回去折騰那段mbr呢(我對它已經(jīng)有恐懼癥了),就是要在bios里改,熟悉到瓜熟蒂落。那接下來做什么呢?我們把那段字符跳躍的代碼,搬到bios的AP init code里。
  bios的AP code位于rombios32start.S:

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  .code16
smp_ap_boot_code_start:
  cli
  xor %ax, %ax
  mov %ax, %ds

  mov $SMP_MSR_ADDR, %ebx
11:
  mov 0(%ebx), %ecx
  test %ecx, %ecx
  jz 12f
  mov 4(%ebx), %eax
  mov 8(%ebx), %edx
  wrmsr
  add $12, %ebx
  jmp 11b
12:
  lock incw smp_cpus
1:
  hlt
  jmp 1b
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

  除了幾行對MSR的操作會困擾我們, AP只是遞增下cpu記數(shù),然后就掛住了。smp_cpus是個匯編label, 相當(dāng)于C變量。
  話不多說,我們現(xiàn)在就動手修改。
>>>>>>>>>>>>>>>>>>>>>>>>>>>
smp_ap_boot_code_start:
  ...
  lock incw smp_cpus    /* smp_cpus++*/
  mov smp_cpus, %si    /* si = smp_cpus */
  shl $1, %si    /* si *= 2*/

  mov $0xb800, %bx
  mov %bx, %ds
1:
  incb 0(%si)
  /*hlt*/
  jmp 1b
smp_ap_boot_code_end:
<<<<<<<<<<<<<<<<<<<<<<<<<<
  AT&T風(fēng)格的匯編雖然不大好,但經(jīng);燠E在內(nèi)核,還是免不了要學(xué)的。不過我們不在以后的新代碼里用它,也希望這種匯編能在我們這一代結(jié)束。
  好啦,回到正題。代碼本身沒什么好說的,每個核根據(jù)smp_cpus在屏幕上定位不同的"點",并循環(huán)遞增其ascii碼,只是注意兩點:
1,寫完之后,先要在bios目錄make一下。這一步需要bcc,用apt-get就可以安裝。
2,接著,還要到源碼根目錄下,也就是bochs-2.6/,執(zhí)行sudo make install。它會把剛生成的ROM-BIOS-latest送到特定的路徑。

  然后啟動bochs就行啦,我們看到——————屏幕上第4個字符在跳~
  這真是喜憂參半,因為我們有3個AP核3,應(yīng)該是2,3,4號位的字符同時跳才對。我們的匯編碼明明是這么安排的。
  問題出在哪里呢?
  有多核經(jīng)驗的讀者,其實一開始就皺眉頭了,"你這樣寫是錯的":
  lock incw smp_cpus
  mov smp_cpus, %si

  對,盡管我們預(yù)期AP1,AP2,AP3的執(zhí)行順序是:
  lock incw smp_cpus
  mov smp_cpus, %si
  lock incw smp_cpus
  mov smp_cpus, %si
  lock incw smp_cpus
  mov smp_cpus, %si

  但實際很可能不是這樣,而是,AP1的incw剛剛結(jié)束,內(nèi)存總線就被AP2搶到了,從而又執(zhí)行一句incw,接著是AP3的incw...
  最后,3個CPU讀到的smp_cpus都是4,這恰好對應(yīng)我們剛才觀察到的現(xiàn)象。
  解決的方法,就是加鎖,這里先貼一種解決方案,我們下一小節(jié)見~~                       2015,10,11
>>>>>>>>>>>>>>>>>>>>>>>>>
...

  jmp 11b
12:
get_lock:
    lock bts $0, 0x6000
    jc get_lock
  lock incw smp_cpus
  mov $smp_cpus, %bx
  lock btr $0, 0x6000    /*release lock*/
  mov 0(%bx), %si

  ...

smp_ap_boot_code_end:
<<<<<<<<<<<<<<<<<<<<<<<<


1,可以訪問,但反而需要對保護(hù)模式有更深的了解。本文假設(shè)讀者是不知道保護(hù)模式的。
2,關(guān)于smp下bochs的開發(fā)環(huán)境的配置,參見我另一篇文章。
3,我在.bochsrc里配的是4核。

下一節(jié)  冰山一角————多核下的原子操作

論壇徽章:
20
程序設(shè)計版塊每日發(fā)帖之星
日期:2015-08-17 06:20:00程序設(shè)計版塊每日發(fā)帖之星
日期:2016-07-16 06:20:00程序設(shè)計版塊每日發(fā)帖之星
日期:2016-07-18 06:20:00每日論壇發(fā)貼之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16賽季CBA聯(lián)賽之江蘇
日期:2017-06-26 11:05:5615-16賽季CBA聯(lián)賽之上海
日期:2017-07-21 18:12:5015-16賽季CBA聯(lián)賽之青島
日期:2017-09-04 17:32:0515-16賽季CBA聯(lián)賽之吉林
日期:2018-03-26 10:02:16程序設(shè)計版塊每日發(fā)帖之星
日期:2016-07-15 06:20:0015-16賽季CBA聯(lián)賽之江蘇
日期:2016-07-07 18:37:512015亞冠之薩濟(jì)拖拉機(jī)
日期:2015-08-17 12:21:08
3 [報告]
發(fā)表于 2016-08-31 17:29 |只看該作者
贊,這個系列最近有更新么?

論壇徽章:
13
程序設(shè)計版塊每日發(fā)帖之星
日期:2016-06-29 06:20:00每日論壇發(fā)貼之星
日期:2016-08-14 06:20:00操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-08-14 06:20:00每日論壇發(fā)貼之星
日期:2016-08-13 06:20:00數(shù)據(jù)庫技術(shù)版塊每日發(fā)帖之星
日期:2016-08-13 06:20:00程序設(shè)計版塊每日發(fā)帖之星
日期:2016-08-13 06:20:00IT運維版塊每日發(fā)帖之星
日期:2016-08-13 06:20:00每日論壇發(fā)貼之星
日期:2016-08-12 06:20:00數(shù)據(jù)庫技術(shù)版塊每日發(fā)帖之星
日期:2016-08-12 06:20:00程序設(shè)計版塊每日發(fā)帖之星
日期:2016-08-12 06:20:00操作系統(tǒng)版塊每日發(fā)帖之星
日期:2016-08-12 06:20:00綜合交流區(qū)版塊每日發(fā)帖之星
日期:2016-08-09 06:20:00
4 [報告]
發(fā)表于 2016-09-22 18:07 |只看該作者
回復(fù) 3# nswcfd

沒有。這是去年上班時寫的,很想續(xù)寫,但一直沒機(jī)會。
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP