Solaris 8系統核心介紹

Solaris 8系統核心介紹


零,前言
筆者使用Solaris的經驗並不久,之前花了很多時間在LinuxWindows的平台上撰寫驅動程式,這次因為一個工作機會所以在Solaris上面撰寫驅動程式,從中讓我了解到不同系統的差異性,也因此我希望可以有機會把我的經驗與各位分享,讓日後有需要撰寫Solaris上面驅動程式或是系統設計的朋友們,可以有一個參考的例子。
當然囉,各位熟悉Solaris平台的玩家們對於上面驅動程式的開發環境應該都有所了解,在Solaris上面常用來開發的介面就是DDI/DKI (Device Driver Interface / Driver Kernel Interface),透過這些介面可以使用Solaris所定義的一些驅動程式介面,對於撰寫核心程式碼的人來說可以省去不少事情。而且,Solaris背後有Sun在主推這套系統,也因此有機會獲得許多大型企業或是重視系統穩定的開發者採用。
本文,主要是以Solaris 8為主,這是筆者唯一使用過的Solaris平台,如果各位有何意見或是看法,隨時歡迎與我聯繫..….^_^
一, Solaris DDI and DKI
寫過Linux Device Driver的朋友應該會注意到一件事情,這就是在Linux平台上面一直都沒有一個公定的驅動程式設計介面來讓所有人遵循,舉個例子來說,如果現在我們要在Linux上面開發驅動程式時,大多數人的做法都是去看/proc/ksyms中所列出的Linux核心函式,再參考核心的程式碼來了解該如何使用這些函式。
相對於LinuxSolaris上面有非常完備的驅動程式設計介面,Sun把它命名為DDIDevice Driver Interface﹞與 DKIDriver Kernel Interface﹞,透過這些介面所寫的驅動程式,我們可以確保在Solaris平台上面的相容問題,就算在Sparc或是i86pcx86﹞的平台上,也可以比較容易達到Source Code 層面的平台相容性。也就是說,如果我們透過DDIDKI的介面來撰寫我們的驅動程式時,我們所開發的驅動程式可以儘可能避免顧慮到太多硬體相容問題,而這些需要依各平台而做不同調整的工作,就由Sun來幫我們處理掉了。在Solaris 8的環境中,DDI的函式是實作在 “/kernel/genunix”中,我們可以透過指令nm來得知這樣的結果
 /usr/ccs/bin/nm /kernel/genunix
…………
[3333] | 532448| 12|FUNC |GLOB |0 |1 |ddi_add_child
[3447] | 550456| 40|FUNC |GLOB |0 |1 |ddi_add_eventcall
[2917] | 518812| 12|FUNC |GLOB |0 |1 |ddi_add_fastintr
[2447] | 518800| 12|FUNC |GLOB |0 |1 |ddi_add_intr
[2083] | 518824| 48|FUNC |GLOB |0 |1 |ddi_add_softintr
[1048] | 550024| 160|FUNC |LOCL |0 |1 |ddi_all_drivers_devid_to_
devlist
[3472] | 532480| 224|FUNC |GLOB |0 |1 |ddi_append_dev
[1038] | 536420| 124|FUNC |LOCL |0 |1 |ddi_append_minor_node
[3643] | 516844| 12|FUNC |GLOB |0 |1 |ddi_apply_range
[3622] | 532244| 8|FUNC |GLOB |0 |1 |ddi_binding_name
[4525] | 518484| 44|FUNC |GLOB |0 |1 |ddi_btop
[2406] | 518528| 44|FUNC |GLOB |0 |1 |ddi_btopr
…………
透過nm我們可以發現,實際上DDI的函式要存在系統中,首先就必須要把genunix載入到核心記憶體中,而genunix也正是整個Solaris系統的主要核心,它提供了許多驅動程式模組最基本的核心函式,所以在Solairs 8的架構中,genunix會在 krtldKernel Loader﹞之後,緊接著備載入到系統中,藉此才能建構一個基本的Solaris核心運作環境。
如下圖﹝一﹞,我們可以看到在Solaris 8環境中載入的Kernel模組,其中DDI函式是由genunix在載入Kernel後所提供的。

圖﹝一﹞
二,檔案格式
Solaris所使用的檔案系統格式為ELF(Executable and Linkable Format),與Linux所採用的檔案格式相同,在這個段落中我們會試著去檢視Solaris上面執行檔、目的檔以及驅動程式的檔案格式,讓各位可以先有一個初步的了解。
如下圖﹝二﹞所示,這是Solaris上面一般的執行檔,我們可以注意到它的e_typeET_EXEC,這就是在ELF中屬於執行檔的屬性。相對的如下圖﹝三﹞所示,這是在Solaris上面ELF目的檔的格式,我們可以注意到它的e_type屬性為ET_REL,也就是Relocatable
圖﹝二﹞

圖﹝三﹞
接下來,我們試著在Solaris中編譯我們的驅動程式

 
/usr/local/bin/gcc -D_KERNEL -c driver.c
/usr/ccs/bin/ld -r -o driver driver.o

其中,指令 “ld” 加上一個 “-r” 的參數是代表在連結的過程中,”ld” 將不會對尚未解決的參考符號﹝unresolved references﹞發出錯誤的訊息。
編譯完成後,我們來檢視驅動程式編譯後產生的檔案格式。如下圖﹝四﹞,我們發現Solaris上面驅動程式的檔案格式與目的檔的檔案格式是一致的,Solaris的驅動程式中所包含尚未解決的參考符號﹝unresolved references﹞將會在驅動程式載入核心的過程中才動態的進行處理。也就是說,Solaris驅動程式所呼叫到的核心函式都是在載入系統時才進行動態連結的,這樣的概念與Linux上面的驅動程式概念是一致的。而且,Solaris也支援如同Linux上面的動態載入驅動程式,對於驅動程式的架構來說算是相當有彈性的做法。

圖﹝四﹞
三,Solaris記憶體結構
Solaris目前有Sparc以及X86的平台上面的版本,在筆者寫這篇文章的同時,我主要是在UltraSPARC-IIi 440MHz的機器上面進行我日常的工作。同時,我也把Solaris 8安裝在我的X86機器上,其中我發現了一些有趣的部分,像是在UltraSPARC上的sun4u版本,它的記憶體架構與在x86上的i86pc版本就有許多的不同,不過筆者對於Sparc的架構其實不是很熟悉,所以在撰寫測試程式的過程中,其實有些結果讓我滿意外的,我想主要是因為與過去在X86平台上面看到的結果有所不同。
首先,Solaris Internals這本書上有sun4csun4m(圖﹝五﹞)sun4d(圖﹝六﹞)的記憶體架構圖。雖然我沒有使用過這三套系統,不過由這些參考資料中,可以了解到一個系統設計上的演進,其實滿有趣的。

圖﹝五﹞
圖﹝六﹞
接下來,重點就放在我目前使用的Solaris sun4u版本,這個版本讓我比較意外的是它的Kernel Mode記憶體位置竟是在整個虛擬記憶體的中間,與sun4csun4msun4d甚至是X86的版本都相當的不同,我沒有花時間在探索Sparc的硬體對於支援這樣架構的優劣點,不過,我把實際上測試的結果繪成如下圖﹝七﹞

圖﹝七﹞
如圖﹝七﹞所示,在sun4u的系統中,應用程式的堆疊會由虛擬記憶體的最上層由上往下延伸,接下來便是應用程式所載入的動態函式庫,由0xFF3E0000(可能因應用程式而有所不同)往下延伸。而應用程式的載入起始點為0x00010000,以該位址為起點依序把ELF檔的內容對應到記憶體中。而最大的不同就在於Kernel Mode的記憶體位置是位於 0x10000000 – 0x80000000 之間,不過我想這個數值應該是可以調整的,不過筆者沒有試著去找出這樣的修改方式。
相對於sun4u的架構,筆者也在X86上安裝Solaris 8後,進行一樣的測試,結果如下圖﹝八﹞

圖﹝八﹞
其實,我們很容易可以發現在X86的機器上面,Solaris 8Kernel Mode 是劃分到最上層的記憶體位址,而真正屬於Kernel Mode的記憶體大小為512MB,應用程式使用的動態函式庫載入位址則由0xE000000開始向下延伸。應用程式載入的起始點則由0x08050000開始。
四,System Call
作業系統核心通常都會提供一組系統呼叫,透過這些由核心所提供的系統呼叫,使用者的程式可以充分的利用系統所提供的功能,進一步的來發揮所在系統平台的特性與優勢。以我們常見的Windows NT平台來說,它允許使用者的程式透過2E中斷來使用Windows NT所提供的系統呼叫,在Linux的平台上,則是透過80號中斷,來達成這樣的任務,而在Solaris呢﹖ 這就是筆者在這段落所要介紹的部分,我會舉出一些實際的例子來驗證Solaris是如何讓使用者透過它的系統呼叫來完成工作。
在這一個段落中,筆者將以X86的機器為主要的實驗平台,我安裝的版本為Solaris 86/00﹞, 我沒有用過Solaris 8以外的版本,不過我相信基本上Solaris X86上的實作方式應該不至於差異太大,如果有一些系統差異上的問題,歡迎各位可以隨時給我一些建議。
首先,我先介紹一下在X86的保護模式環境下作業系統可以透過哪些方式提供系統呼叫給位於User Mode的應用程式
﹝1﹞ Interrupt Gates
e由使用者的應用程式,透過呼叫中斷的方式轉換特權等級到Kernel ModeRing 0﹞來使用核心在Kernel Mode中所實作的系統呼叫。
﹝2﹞ Call Gates
e透過一個遠程呼叫﹝Far Call﹞,改變特權等級至Kernel ModeRing 0﹞中,如此讓在User ModeRing 3﹞的程式,可以藉此呼叫並執行位於Kernel ModeRing 0﹞的程式碼。
如下圖,這是在Intel文件上面可以看到的Protection Rings,而Call Gates的存在就是讓User Mode的程式,可以執行Kernel Mode的程式碼,不過相對來說,User Mode的程式碼比起Kernel Mode的程式碼可靠度較低,所以Call Gates只能在相同等級或是由低特權等級到高特權等級的過程才適用,並無法透過Call Gates在較高特權等級的程式中來執行低特權等級程式中的程式碼,例如﹕無法透過Call GatesKernel ModeRing 0﹞中呼叫並執行User ModeRing 3﹞程式碼。

圖﹝九﹞
Linux的環境中,系統提供了以80號中斷為基礎的System Call,也就是說我們所撰寫的程式,可以透過80號中斷來使用Linux Kernel所提供的系統服務,我們舉個例子來說,如下
int my_fork()
{
__asm__(“
movl $0x2,%eax //SYS_fork
int $0x80
“);
}
段程式碼,是在Linux上面,透過80號中斷呼叫系統所提供的fork函式。對於Linux80號中斷所提供的System Call有興趣的讀者,可自行參閱Linux Kernel原始碼中的檔案 “/arch/i386/kernel/entry.S “ 
不過在Solaris 8 for X86的版本上,可就不是透過80號中斷來實作它的系統呼叫了,我們可以參考如下的程式碼﹕
 int my_fork()
{
__asm__(“
movl $0x2,%eax //SYS_fork
lcall $0x27,$0x0
“);
}
Solaris上面實際上是透過一個長程的呼叫,透過Call Gates機制引發特權等級的切換,來使用系統所提供的System Call
在我們繼續討論之前,我們可以先透過檔案“/usr/include/sys/syscall.h” 來得知目前Solaris 8平台上面提供了哪些系統呼叫,我舉一部份的內容如下﹕

很明顯的,我們可以看到Solaris for i86pc的版本中,是透過遠程呼叫的方式來使用System Call。不過,除了核心所提供的系統呼叫可以透過遠程呼叫的方式來完成以外,還有一些核心提供的呼叫,是允許使用者程式透過中斷的觸發來使用的,例如gethrvtime ()” 是透過 0xd2 中斷來呼叫的﹕
….…
#define SYS_exit 1
#define SYS_fork 2
#define SYS_read 3
#define SYS_write 4
#define SYS_open 5
#define SYS_close 6
#define SYS_wait 7
….…
#define SYS_mount 21
#define SYS_umount 22
#define SYS_setuid 23
#define SYS_getuid 24
#define SYS_stime 25
#define SYS_pcsample 26
….…
目前Solaris 8版本中,共定義了 256System CallNumber﹝由0–255﹞,如果各位要直接在Solaris上透過組合語言來寫程式的話,那System Call的呼叫會是一個很不錯的解決方案。如果透過libc所包裝好的函式,那樣寫起程式來會比較有彈性,因為不同平台的組合語言以及中斷的參數會有所不同,如果透過libc所包裝好的函式,那樣在不同硬體平台上的Solaris應用程式,就可以維持一定程度的相容性。
接下來,在我用C寫的程式中加入部分的組合語言,來驗證我所呼叫的System Call與用libc呼叫所得到的結果是否一致,來得知這些System Call的呼叫是否真的有發生作用,程式碼如下﹕

程式的執行結果如下﹕
我們可以看到,像是my_fork()my_gethrtime()my_getppid()my_getuid()都可以順利的運作,像是因為我們呼叫了fork()System Call所以程式碼在my_fork()之後,便會產生兩個Process來執行之後的程式碼,也因此我們可以看到兩份由printf()所秀出來的顯示字串。其它像是getppid()getuid()直接透過System Call版本的函式與透過libc呼叫的函式所傳回的結果均相同,由此我們可以得知我們直接呼叫System Call函式的結果是正確的。
如下圖,這是在Solaris 8當中所提供的兩種機制,讓使用者程式可以呼叫Solaris 核心所提供的系統呼叫。

#include <stdio.h>
#include <sys/syscall.h>
//
int my_gethrtime();
int my_getppid();
int my_getuid();
int my_fork();
int my_sync();
//
int main()
{
my_fork();
my_sync();
printf(“\ngethrtime:%xh_%xh”,my_gethrtime(),gethrtime());
printf(“\nppid:%xh_%xh”,my_getppid(),getppid());
printf(“\nuid:%xh_%xh”,my_getuid(),getuid());
}
int my_gethrtime()
{
__asm__(“
movl $3,%eax //gethrtime
int $0xd2
“);
}
int my_getppid()
{
__asm__(“
movl $0x14,%eax
lcall $0x27,$0x0
movl %edx,%eax
“);
}
int my_getuid()
{
__asm__(“
movl $24,%eax //SYS_getuid
lcall $0x27,$0x0
movl %edx,%eax
“);
}
int my_fork()
{
__asm__(“
movl $0x2,%eax //SYS_fork
lcall $0x27,$0x0
“);
}
int my_sync()
{
__asm__(“
movl $36,%eax //SYS_sync
lcall $0x27,$0x0
“);
}

Solaris上面實際上是透過一個長程的呼叫,透過Call Gates機制引發特權等級的切換,來使用系統所提供的System Call
在我們繼續討論之前,我們可以先透過檔案“/usr/include/sys/syscall.h” 來得知目前Solaris 8平台上面提供了哪些系統呼叫,我舉一部份的內容如下﹕

很明顯的,我們可以看到Solaris for i86pc的版本中,是透過遠程呼叫的方式來使用System Call。不過,除了核心所提供的系統呼叫可以透過遠程呼叫的方式來完成以外,還有一些核心提供的呼叫,是允許使用者程式透過中斷的觸發來使用的,例如gethrvtime ()” 是透過 0xd2 中斷來呼叫的﹕
….…
#define SYS_exit 1
#define SYS_fork 2
#define SYS_read 3
#define SYS_write 4
#define SYS_open 5
#define SYS_close 6
#define SYS_wait 7
….…
#define SYS_mount 21
#define SYS_umount 22
#define SYS_setuid 23
#define SYS_getuid 24
#define SYS_stime 25
#define SYS_pcsample 26
….…
目前Solaris 8版本中,共定義了 256System CallNumber﹝由0–255﹞,如果各位要直接在Solaris上透過組合語言來寫程式的話,那System Call的呼叫會是一個很不錯的解決方案。如果透過libc所包裝好的函式,那樣寫起程式來會比較有彈性,因為不同平台的組合語言以及中斷的參數會有所不同,如果透過libc所包裝好的函式,那樣在不同硬體平台上的Solaris應用程式,就可以維持一定程度的相容性。
接下來,在我用C寫的程式中加入部分的組合語言,來驗證我所呼叫的System Call與用libc呼叫所得到的結果是否一致,來得知這些System Call的呼叫是否真的有發生作用,程式碼如下﹕
#include <stdio.h>
#include <sys/syscall.h>
//
int my_gethrtime();
int my_getppid();
int my_getuid();
int my_fork();
int my_sync();
//
int main()
{
my_fork();
my_sync();
printf(“\ngethrtime:%xh_%xh”,my_gethrtime(),gethrtime());
printf(“\nppid:%xh_%xh”,my_getppid(),getppid());
printf(“\nuid:%xh_%xh”,my_getuid(),getuid());
}
int my_gethrtime()
{
__asm__(“
movl $3,%eax //gethrtime
int $0xd2
“);
}
int my_getppid()
{
__asm__(“
movl $0x14,%eax
lcall $0x27,$0x0
movl %edx,%eax
“);
}
int my_getuid()
{
__asm__(“
movl $24,%eax //SYS_getuid
lcall $0x27,$0x0
movl %edx,%eax
“);
}
int my_fork()
{
__asm__(“
movl $0x2,%eax //SYS_fork
lcall $0x27,$0x0
“);
}
int my_sync()
{
__asm__(“
movl $36,%eax //SYS_sync
lcall $0x27,$0x0
“);
}
程式的執行結果如下﹕
我們可以看到,像是my_fork()my_gethrtime()my_getppid()my_getuid()都可以順利的運作,像是因為我們呼叫了fork()System Call所以程式碼在my_fork()之後,便會產生兩個Process來執行之後的程式碼,也因此我們可以看到兩份由printf()所秀出來的顯示字串。其它像是getppid()getuid()直接透過System Call版本的函式與透過libc呼叫的函式所傳回的結果均相同,由此我們可以得知我們直接呼叫System Call函式的結果是正確的。
如下圖,這是在Solaris 8當中所提供的兩種機制,讓使用者程式可以呼叫Solaris 核心所提供的系統呼叫。
# ./test
gethrtime:7bb0bf36h_7bb0b799h
ppid:1d7bh_1d7bh
uid:3eeh_3eeh
gethrtime:8a646195h_8a645a42h
ppid:1d7ah_1d7ah
uid:3eeh_3eeh
#


圖﹝十﹞
五,驅動程式的載入
Solaris 8的系統中,有一個ksyms (kernel symbols driver)的驅動程式﹝位於/usr/kernel/drv/ksyms﹞,它會透過一個Kernel Thread來動態的更新目前KernelSymbol Table,每當我們載入或是卸下一個驅動程式時,它就會自動的去更新檔案 “/dev/ksyms”,也就是說,如果我們想要知道目前驅動程式有哪些函式可以呼叫時,就可以去檢視這一個檔案,不過這個檔案是以ELF檔的格式存在於Solaris系統中,因此在我們檢視這檔案內容時,我們需要透過一些工具程式讓我們可以比較容易的去閱讀檔案中的內容。我們看到Solaris /dev/ksyms 檔案時,其實熟悉Linux的讀者一定很自然的會想到Linux上的 “/proc/ksyms”,與Solaris不同的地方在於Linux上的ksyms是以單純的文字檔格式存在,透過這些資訊,我們可以很清楚的了解目前系統中所提供的核心函式,這對於我們撰寫該平台上的驅動程式會有相當大的助益。
如下,我們可以透過 elfdump來檢視 /dev/ksyms中的函式資料
# /usr/ccs/bin/elfdump /dev/ksyms
……………….
[1] 0xfe8051c4 0x0000000e FUNC LOCL 0 ABS kadb_error10
[2] 0xfe81dffe 0x00000000 NOTY LOCL 0 ABS audit_anchorpath_L
[3] 0xfe8051d4 0x0000000e FUNC LOCL 0 ABS kadb_error11
[4] 0xfe8051e4 0x0000000e FUNC LOCL 0 ABS kadb_error12
[5] 0xfe8051f4 0x0000000e FUNC LOCL 0 ABS kadb_error13
[6] 0xfe805204 0x0000000e FUNC LOCL 0 ABS kadb_error14
[7] 0xfe805214 0x0000000e FUNC LOCL 0 ABS kadb_error15
[8] 0xfec024bc 0x00000008 OBJT LOCL 0 ABS kstat_hash_table
[9] 0xfe81d022 0x00000000 NOTY LOCL 0 ABS recv_L
[10] 0xfe805224 0x0000000e FUNC LOCL 0 ABS kadb_error16
[11] 0xfec04f10 0x00000000 NOTY LOCL 0 ABS sec_svc_control_inf
……………….
[7048] 0xfea777c4 0x00000250 FUNC LOCL 0 ABS fdc_enhance_probe
[7049] 0xfe80e900 0x00000014 FUNC GLOB 0 ABS ddi_dma_unbindhdl
[7050] 0xfe80e8c4 0x00000014 FUNC GLOB 0 ABS ddi_dma_allochdl
[7051] 0xfe81d3b0 0x0000001a FUNC GLOB 0 ABS lm_shrlock
……………….
其中,標示為 “FUNC” Symbol就是我們可以在撰寫Solaris驅動程式時呼叫的函式。
接下來,筆者實際把驅動程式載入與卸下,來檢視整個系統的運作過程。首先,我們載入驅動程式

add_drv -m”* 0777 other other” -i pci1146,6750 pci554

並且透過工具 modinfo來檢視目前系統中所有已經載入的驅動程式模組
我們可以看到,剛剛我們載入的驅動程式pci554已經列在系統目前已載入的模組資料中了,接下來我們檢視“/dev/ksyms” 來看看驅動程式 pci554中的函式、全域變數….等,是否也會列在該檔案中。
像是在pci554程式中的函式
# modinfo
Id Loadaddr Size Info Rev Module Name
6 10126000 42cb 1 1 specfs (filesystem for specfs)
8 1012bb88 2d38 1 1 TS (time sharing sched class)
9 1012e450 894 – 1 TS_DPTBL (Time sharing dispatch table)
10 1012e4d4 264cf 2 1 ufs (filesystem for ufs)
11 10152f07 10a4c 226 1 rpcmod (RPC syscall)
11 10152f07 10a4c 1 1 rpcmod (rpc interface str mod)
12 10161b97 5520c 0 1 ip (IP Streams module)
……………
107 1025e5a2 279a 88 1 devinfo (DEVINFO Driver 1.31)
108 102ee3b5 1526 70 1 pci554 (PCI21554 driver v0.00)
109 102fc2bb b5b 176 1 inst_sync (instance binding syscall)
110 1012afa7 b2c 23 1 ptm (Master streams driver ‘ptm’)
111 10300c21 c2e 24 1 pts (Slave Stream Pseudo Terminal dr)
……………
並且透過工具 modinfo來檢視目前系統中所有已經載入的驅動程式模組
# modinfo
Id Loadaddr Size Info Rev Module Name
6 10126000 42cb 1 1 specfs (filesystem for specfs)
8 1012bb88 2d38 1 1 TS (time sharing sched class)
9 1012e450 894 – 1 TS_DPTBL (Time sharing dispatch table)
10 1012e4d4 264cf 2 1 ufs (filesystem for ufs)
11 10152f07 10a4c 226 1 rpcmod (RPC syscall)
11 10152f07 10a4c 1 1 rpcmod (rpc interface str mod)
12 10161b97 5520c 0 1 ip (IP Streams module)
……………
107 1025e5a2 279a 88 1 devinfo (DEVINFO Driver 1.31)
108 102ee3b5 1526 70 1 pci554 (PCI21554 driver v0.00)
109 102fc2bb b5b 176 1 inst_sync (instance binding syscall)
110 1012afa7 b2c 23 1 ptm (Master streams driver ‘ptm’)
111 10300c21 c2e 24 1 pts (Slave Stream Pseudo Terminal dr)
……………
我們都可以在該檔案中找到載入Kernel Mode後的相關訊息

 
# /usr/ccs/bin/elfdump /dev/ksyms
……………
[5353] 0x102ef414 0x00000028 FUNC LOCL 0 ABS pb_strategy
[5354] 0x102ee3b8 0x0000006c FUNC LOCL 0 ABS pci21554_interrupt_gen
[5355] 0x102ef0e0 0x000000a4 FUNC LOCL 0 ABS pb_detach
……………
[13727] 0x102ee690 0x00000734 FUNC GLOB 0 ABS Cfg_21554_mem_space
[13728] 0x10479b34 0x00000004 OBJT GLOB 0 ABS bar2addr
[13729] 0x10479b20 0x00000004 OBJT GLOB 0 ABS device_21554
[13730] 0x102ee660 0x00000030 FUNC GLOB 0 ABS _info
[13731] 0x10479b38 0x00000004 OBJT GLOB 0 ABS bar2_handle
[13732] 0x10479b28 0x00000004 OBJT GLOB 0 ABS vendor_21554
……………

也就是說,當我們載入驅動程式後,其它的驅動程式也可以呼叫我們所提供的函式,這樣的特性與在Linux中撰寫驅動程式是一樣的,由於整個Solaris Kernel支援完整的動態載入機制,每個目的檔格式的驅動程式在載入核心後,就如同是整個完整核心的一部份,這些資料透過 ksyms 的動態維護,可以再我們載入新的驅動程式進行Kernel Mode的動態連結時,了解是否有未存在於Kernel中的Symbol,而發出警告,進一步的結束不完整的驅動程式載入過程。
static int pci21554_interrupt_gen()
 ddi_acc_handle_t bar2_handle;
char * bar2addr;
# /usr/ccs/bin/elfdump /dev/ksyms
……………
[5353] 0x102ef414 0x00000028 FUNC LOCL 0 ABS pb_strategy
[5354] 0x102ee3b8 0x0000006c FUNC LOCL 0 ABS pci21554_interrupt_gen
[5355] 0x102ef0e0 0x000000a4 FUNC LOCL 0 ABS pb_detach
……………
[13727] 0x102ee690 0x00000734 FUNC GLOB 0 ABS Cfg_21554_mem_space
[13728] 0x10479b34 0x00000004 OBJT GLOB 0 ABS bar2addr
[13729] 0x10479b20 0x00000004 OBJT GLOB 0 ABS device_21554
[13730] 0x102ee660 0x00000030 FUNC GLOB 0 ABS _info
[13731] 0x10479b38 0x00000004 OBJT GLOB 0 ABS bar2_handle
[13732] 0x10479b28 0x00000004 OBJT GLOB 0 ABS vendor_21554
……………
六,結語
在這篇文章的最後,我相信各位對於Solaris系統會有不錯的了解,本文主要是針對筆者認為值得深入了解的部分進行探討,其實如果要探索Solaris的核心架構,本文可能只是一個引導的角色,有許多更為深入的主題,需要透過各位
接下來的努力才會更加熟悉。
Solaris不像Linux是一個完全Open Source的作業系統,所以有很多的資訊我們無法單純的從Source Code來得知,能做的就是去反組譯一些程式碼,並自行撰寫測試程式,不過說真的,這是一個很有趣的過程,畢竟對我來說Solaris算是一個新的領域,在這之前我一直沒有機會實際的去接觸它。透過這篇文章,希望可以與各位同好分享我的經驗,若有任何意見也歡迎各位來信指教。
My E-Mailhlchou@mail2000.com.tw
七,參考文件
[2]Writing Device Driver,Sun Microsystems
[3]Solaris Internals ,Core Kernel Architecture,Jim MauroRichard McDougall
[5] Linux Kernel Internals http://www.moses.uklinux.net/lki-single.html
[6]Intel Architecture Software Developer’s ManualVolume 3System Programming
[7] The dynamic Solaris kernel , http://www.unixinsider.com/swol-02-2000/swol-02-insidesolaris.html