A. 怎樣在linux系統下直接打開移動硬碟
的一個非常好的文章可以清楚地解釋如何啟動火線和USB設備 Linux操作系統的原理。
希望它在對任何有興趣把Linux操作系統安裝到外部設備的人有所幫助。
原始的網址
從火線設備上啟動Linux
可移動驅動器上安裝Linux操作系統
難度等級:中等
Martyn Honeyford([email protected]) IBM英國實驗室 軟體工程師
宣可達([email protected])翻譯 webzi@linuxsir
2004年7月15日
2005年7月26日開始翻譯,7月28日完成。
翻譯經驗不多。如有不妥,歡迎EMAIL交流。
使用一個外部驅動器是一個極棒的方法,能給你的老硬體帶來新生和讓你在你不能(或者不想)改變內置硬碟的計算機上使用Linux系統。
假設你想使用Linux在一個雙啟動環境,但是你的計算機硬碟又沒有任何空餘的空間。一種解決方法是使用"live"的linux發行版本象是Knoppix,他們這能直接從CD啟動運行。 對於偶爾使用,這是一種可行的辦法,但是它有若乾的劣勢:
*你將會仍然需要些固定文件存儲。如果你只是操作少量的文件,一張1.44MB的磁碟就可以勝任,或者一個USB快閃記憶體棒適合中等量的文件,但是這些都不夠理想。
*當使用一個LiveCD 的時候,最困難、最糟糕、最不可能的是安裝你自己的應用程序或者定製現存的程序。
*使用LiveCD在性能上的犧牲,在啟動初所有的設備檢測時尤為明顯,同樣發生使用中(所有的文件從 CD 載入通常是比從硬碟中載入慢的多)。
的確,還有其他可選方案。舉例來說,你可以買額外的內置驅動器並且在此安裝Linux操作系統。但是常常,你可能沒有任何空閑的擴展阜。(這特別容易發生在筆記本上,通常他們只允許一個內置硬碟。)
或者,你可以使用一個較大的硬碟取代當前的硬碟, 獲得額外空間用於安裝 Linux操作系統。 然而,這的確是一個耗費大量時間的方案,需要你重新安裝現有的操作系統在新的硬碟, 重新安裝和配置你所有應用程序, 和恢復所有數據。
更好的解決方案是購買一個外置硬碟並安裝 Linux操作系統。 這樣使得你在想使用Linux系統時候不必涉及現有的硬體和軟體而只是簡單連接外部驅動器。
可選的可移動設備
可用於安裝Linux操作系統設備涵蓋磁碟驅動器、USB-快閃記憶體設備、通過USB/火線連接的硬碟等等。
在一個小容量的設備中安裝linux是可行的,例如在一個1.44MB的磁碟或者一個32MB的USB棒中,他們通常(必須)為特定目的定製,採用裁減的發行版本,例如,拯救中斷的安裝過程。
外置的硬碟在為使用一個常規目的的linux系統提供最大的靈活性同時,帶來一個合理的成本。
許多不同的廠商提供許多種不同容量的外置的驅動器。 (Maxtor, 西西部數據, 等等)。這些驅動器還會包含一個外置盒子,用於固定標準的 3-1/2 寸或 2-1/2 寸 IDE 硬碟。 然後這些驅動器經由 USB 或 IEEE1394(火線) 連接到計算機。
USB 受到在二個主要的版本中的影響,1.1 和 2.0. 1.1 版速度為12 Mbit/ s(每秒1Mbit) ,而 2.0 版支持最高達到 480 Mbit/s 的傳輸速度。 大多數2.0相容的驅動器也向後兼容1.1,通常建議盡量不要採用1.1介面除非沒有其他的選擇(因為其低速不適應此環境。)
火線標准也定義若干不同的速度, 實際上,大部分人所指的FireWire ,是「FireWire400」標准 ,支持最大傳輸速度為 400 Mbit/s 。
USB2.0和火線在速度上不分伯仲: 雖然 USB 2.0 有比較高的傳輸速度, 但是實際中因為協議的不同兩者速度十分的接近。 如果你的計算機擁有2種介面, 最好使用USB而非火線(理由我將後將解釋), 但是如果只有火線介面,當然你就選擇它了。為了實現最大的靈活性, 可以選擇眾多同時支持 USB 2.0 和火線的驅動器中的一種。(像我稍後將在這一個文章中使用的那個一樣。)
對於那些沒有必須的介面, PCI(對於桌面) 和 PCMCIA(對於筆記本型電腦) ,現在火線和USB 2.0擴展卡也並非貴不可及: 舉例來說, 我稍後將在文章中提及PCMCIA火線擴展卡大約為10英鎊.($20 美元以下)
為了達到本文的目的,我已經購買 5-1/4寸外置驅動器的硬碟盒。 這是一件非常靈活的硬碟盒,並沒提供驅動器而且能固定任何的標准 IDE 設備,包括 3-1/2 寸驅動器和像CD-RW/DVD-RW等5-1/4 寸 IDE 設備 。硬碟盒兼有 USB 2.0 和火線介面。
為了把硬碟盒連接到我的IBM Thinkpad T30筆記本電腦,我也購買了一個 PCMCIA 火線轉接卡。 ( 因為內置的USB 介面只支持USB 1.1)
硬碟盒和火線轉接卡相對比較便宜。 (大約分別為50英鎊和10英鎊。)
測試期間, 我把一個手邊閑置的13 GB 3-1/2 寸 IDE 硬碟放進硬碟盒——對於真實情況,我會買一個較大的容量驅動器, 現在另購一個硬碟相當低廉( 大約每個50英鎊!)
Linux 支持
正如你所期待,linux對這些硬碟盒支持的確非常好。任何遵從SBP(串列匯流排協議)標準的大儲存設備在linux中使用非常簡單。
大體上, 使對這些裝置的支持你能夠將會需要在你的核心中支持某些選項( 或直接地編譯或通過模塊。)
對於USB和火線,SBP 裝置通過SCSI模擬來實現-- 也就是說,Linux會把他們當作SCSI硬碟來處理 。 這是在 Linux 世界裡面使用存儲設備的一個常規方法。 ( 舉例來說, IDE CD/DVD設備通常通過SCSI模擬來連接)。基於以上原因,下列的選項需要被內核支持:
* SCSI support
* SCSI emulation
* SCSI disk support
除此之外,不同連接方式需要一下的內核支持:
* 針對火線:
* IEEE1394 support
* OHCI1394 support
* RAW1394 support
* SBP-2 support
* 針對USB:
*(host-side) USB support
* OHCI support
* UHCI support
* USB mass-storage support
明顯地,你還必須為其他的硬體 ( 如顯卡等等)編譯常規的支持, 而且可能需要一些額外的模塊,取決你的具體硬體。
舉例來說,我正在使用 PCMCIA(cardbus) 火線轉接卡,因此,我還需要增加:
* PCMCIA support
* cardbus support
安裝
現在我們有很完美外置驅動器,我們將開始安裝在其安裝Linux美妙之旅。
目前最簡單的安裝linux方法(當然僅個人意見) , 是連接你的所有硬體;(我的情況是,插入火線轉接卡,連上轉接線盒驅動器,然後打開驅動器的電源) 然後從你選擇的發行版安裝CD上啟動你的計算機。
我採用的發行版是Gentoo(資源詳見鏈接),因此,我用了最新的 「通用」x86 LiveCD。 (2004.1) 其他的發行版本必須的步驟大致和此相似。
一旦你使用安裝CD啟動,要藉由一點運氣讓他要辨認出你的驅動器。 磁碟應該出現在/dev/sdX, X 是一個小寫字母從「a」開始。 在我的系統上,外置硬碟被當做 /dev/sda, 但是如果你有其他的 SCSI硬碟,這數字將會改變;( 或模擬了SCSI硬碟) 那種情況下,它可能是 /dev/sdb 或一些其他的字母。 如果你的驅動器不能被自動檢測到, 就需要進一步採取措施 -- 舉例來說,你可能必須打開啟動選項使用火線或者PCMCIA介面, 或你可能必須手動裝載一些內核模塊 , 或其他一類選項。 (資源詳見故障發現與維修指導鏈接)
一旦驅動器被辨認出來,安裝過程種其運作起來就像一個內置的硬碟。然後就你可以對其分區並且用常規方法安裝linux。
有一句話我著重要提醒,小心選擇何處安裝boot loader(通常是GRUB和LILO)--我建議不要裝到主引導記錄(MBR)中( 通常是默認值) 而是裝到外置驅動器的根分區 ( 或/boot分區,如果你單獨分了一個話)。
既然我們已經安裝 Linux 在這個設備上,我們想要從上面啟動它。 事情到此開始變的有點復雜了。
啟動
在我前討論在如何的新驅動器上面啟動,我要講解一些boot loader的小知識。
boot loader程序通常安裝在計算機的第一個硬碟的MBR上。 當boot loader被調用 (BIOS自動地運行MBR里的代碼),它通常顯示一份可啟動操作系統的菜單。以便選擇一個給定的操作系統啟動計算機。
兩件細節在這個章節中應該注意:
* 操作系統選擇菜單(通常)從磁碟中載入。
*為了啟動有關的操作系統, boot loader 需要從磁碟中讀取相關的內核。
在操作系統被裝載之前 ,以上各步驟已經執行,這意味著所有的磁碟讀取在BIOS調用時。 這是一個必須的前提,即,為了直接啟動磁碟,你的 BIOS必須支持通過火線或USB被連接的磁碟。通常能在BIOS中看到關於從這些設備上啟動選項。 火線BIOS支持現在的確非常的少見,但是 USB 支持正在變得相當的平常。 因此,如果你正在使用一部相對比較新的計算機上的USB介面,應該可以直接啟動驅動器進Linux。
當經由 USB 連接,在安裝外部的驅動器的 MBR 的幼蟲之後,我能夠直接地啟動它。 當以被連接的磁碟片啟動的時候,只是進入 BIOS 裝備公用程序。 外部的磁碟片將會出現如一個一般的硬碟: 移動它,如此它在啟動次序中的內在驅動器之前。
我也能夠在一個內置的硬碟的MBR上安裝一個boot loader而且使用其啟動USB硬碟(在GRUB中被成為hd1)。 如果你正在使用火線, 有可能你的 BIOS 將會無法直接地啟動硬碟,而且你需要更多一點步驟。
幸運的是,由於 Linux 的多樣性,這有非常容易解決,如果你不能直接地啟動,( 我就是這樣的情況,使用一個PCMCIA轉接卡!) 你能運行初始啟動步驟,來自一個支持的設備 , 像是一台軟碟機,CD-ROM,USB棒,或在主硬碟上的小分區, 然後使用外部的驅動器繼續其他步驟。
創建一個啟動鏡像
我們有2種方法啟動:
*單階啟動
內核啟動, 掛載根分區文件系統, 接著調用初始化教本繼續初始化( 通常是/sbin/init)
*雙階啟動 (initrd)的啟動
內核啟動,掛載一個初始ram disk (initrd),進一步運行定製的初始化, 然後掛載根分區文件系統繼續初始化(同樣, 通常調用/sbin/init)
每種方法都有它自己的優點和缺點。
單階啟動
為了要使用一個單階的啟動,我們需要建立一個內核包含掛載一個根分區文件系統所需的所有驅動程序。( 任何其他的驅動能作為模塊編譯並在根分區載入時候進行常規初始化。)
如果我們正在從像軟盤這樣的一個非常小的裝置嘗試啟動, 最好的方式是創建的一個正合適內核,編譯進所有掛載根外部分區系統所需驅動 -- 而且編譯其他的作為模塊。 舉例來說,我的內核編譯進了SCSI支持, PCMCIA 支持, IEE1394 , SBP ,和其他相似的支持, 但是其他的(包括顯卡支持,網路設備支持,等等)當做模塊編譯並儲存在根分區上(在外部的驅動器的),而不是存儲在軟盤上。
這種方法的主要問題是需要我們給內核源代碼打補丁-- 那是一種最糟糕的痛苦(當新的內核發布),而真正的問題是如果補丁沒有在維護,這樣就不能跟上內核的變化。
你可能以為如果計算機BIOS支持USB和火線直接啟動,我們能避免發生以上的2個問題。 不幸地,事情不是這樣:這一個方法使用BIOS在啟動時調用磁碟,一旦內核開始初始化, BIOS就失去了作用,而且使用內核驅動來調用磁碟-- 所以你仍然會碰到同樣的問題。
二階啟動
內核2.0.X版本 ,添加了一個有趣的功能到內核 -- 使用「initial RAM disk(初始內存磁碟)」(or initrd)來實現二階啟動。
簡言之,內核一概既往的啟動;掛載一個創建在內存里迷你的根分區文件系統取代掛載「真正」的根分區系統。 無論任何命令都在這個初始環境中執行在「真正」的根分區系統被掛載之前直到我們切換到真正的根分區文件系統並銷毀初始內存磁碟(initial RAM disk)。
這點在各種環境中都非常有用,但是我們的目標僅僅是簡單的利用我們的迷你環境去重新掃描SCSI匯流排,等待外部驅動器識別,然後用它切換到我們真正的根而後繼續啟動。
使用這種方法,我們需要創建2個文件,一個內核和一個初始鏡像文件。
內核僅是一個內建啟動鏡像(initrd)支持常規內核。 initrd 鏡像是一個包涵我們迷你根分區系統的環路(loopback)文件系統鏡像。 (該鏡像可以有選折地使用gzip壓縮來減小它的大小)。
你能在資源章節里找到關於如何創建和定製你自己的初始鏡像的更多信息。
在鏡像文件里,有一個linuxrc的文件。當鏡像給載入時,該文件自動運行,所以請確定其有運行許可權!為了達到我們的目的,linuxrc文件非常的簡單:
列舉 1. initrd linuxrc
#!/bin/sh
REAL_ROOT=/dev/sda1
# mount the /proc filesystem
mount -t proc none /proc
#for scsi-emulation (SCSI模擬)
# modprobe sd_mod
#for pcmcia (PCNCIA卡)
# modprobe pcmcia_core
#for FireWire (火線)
# modprobe ieee1394
# modprobe ohci1394
# modprobe raw1394
# modprobe sbp2
#for USB (USB)
# modprobe usbcore
# modprobe ohci-hcd
# modprobe uhci-hcd
# modprobe usb-storage
# loop rescanning the scsi bus + rerunning devfsd
retries=5
i=1
until [ -e $REAL_ROOT ]
do
if [ $i -gt $retries ]
then
echo "Unable to mount real root ($REAL_ROOT) - Giving up!"
/bin/ash
exit
fi
echo "Real root ($REAL_ROOT) not found, retrying ($i)"
sleep 1
echo "scsi add-single-device 0 0 0" > /proc/scsi/scsi
echo "scsi add-single-device 1 0 0" > /proc/scsi/scsi
echo "scsi add-single-device 2 0 0" > /proc/scsi/scsi
/bin/devfsd /dev -np
i=$((i+1))
done
#umount /proc as it will be remounted by the normal init process
(解除掛載/proc分區當它會給常規的INIT進程重新掛載)
umount /proc
#now we simply exit, and the normal boot process should continue
(現在我們可以退出了,常規的啟動進程將會繼續)
exit 0
我們正在做的是載入適當的模塊去支持外部驅動器: 請按需注視相應行。 (我把所有需要的支持編譯進內核,因此不需要模塊)。 然後循環, 再掃描 SCSI 匯流排 (回應一個命令到/proc虛擬文件系統下一個特別文件並調用devfsd程序) 直到根分區設備出現(我的情況是/dev/sda1 )。在我的情況,被訪問的火線模擬SCSI匯流排是1 0 0,但是並不影響嘗試部分其他的匯流排 -- 如果你知道將會使用哪一個,你可以裁減這個教本。 同時, 如果你有其他的 SCSI 設備 (或模擬 SCSI設備), 驅動器可能有一個不同的字母。(例如,/dev/sdb1) 而且如果你沒有使用外置驅動器上的第一個分區, 你將會需要使用一個不同的數字。( 例如,/dev/sda2)
現在我們需要做的全部是復制相關的文件進initrd鏡像.( 你能夠使用mount -o loop 命令掛載未壓縮的鏡像)尤其,我們需要確定我們有 linuxrc 文件、所有被用到的命令和其依賴的庫。 這個(未掛載的)鏡像可以有選折的壓縮。
復制內核 (bzImage) 和 initrd 鏡像 (initrd.gz)到磁碟。
最後的步是在磁碟上安裝一個boot loader, 而且用下列的選項啟動內核: kernel bzImage root=/dev/sda1 initrd=initrd.gz.
你現在應該可以使用磁碟來啟動了:它會從軟盤中載入內核,載入initrd鏡像入內存,然後從那裡繼續常規啟動。這點以後,磁碟就可以拿開了。
如果磁碟不合適 ( 例如,計算機沒有軟碟機),任何設備在BIOS能用於啟動都可以使用。 個人而言,我就使用一個小小的32MB的USB棒來達到這個目的。
參考資料:
另外,虛機團上產品團購,超級便宜
B. Ubuntu編譯了新的內核,進入新內核時一直顯示載入Linux 5.6.7,載入初始化內存檔咋回事
概述====1)當內核配置了內存檔時, 內核在初始化時可以將軟盤載入到內存檔中作為根盤.當同時配置了初始化內存檔(Initail RAM Disk)時, 內核在初始化時可以在安裝主盤之前,通過引導程序所載入的initrd文件建立一個內存初始化盤, 首先將它安裝成根文件系統, 然後執行其根目錄下的linuxrc 文件,可用於在安裝主盤之前載入一些內核模塊. 等到linuxrc 程序退出後, 再將主盤安裝成根文件系統,並將內存初始化盤轉移安裝到其/initrd目錄下.2)當主盤就是initrd所生成的內存初始化盤時, 不再進行重新安裝,在DOS下用loadlin載入的搶救盤就是這種工作方式.3)引導程序所載入的initrd為文件系統的映象文件, 可以是gzip壓縮的, 也可以是不壓縮的.能夠識別的文件系統有minix,ext2,romfs三種.4)當內核的根盤為軟盤時,內核初始化時會測試軟盤的指定部位是否存在文件系統或壓縮文件映象, 然後將之載入或解壓到內存檔中作為根盤. 這是單張搶救軟盤的工作方式.有關代碼========; init/main.c#ifdef CONFIG_BLK_DEV_INITRDkdev_t real_root_dev; 啟動參數所設定的根盤設備#endifasmlinkage void __init start_kernel(void){ char * command_line; unsigned long mempages; extern char saved_command_line[]; lock_kernel(); printk(linux_banner); setup_arch(&command_line);arch/i386/kernel/setup.c中,初始化initrd_start和initrd_end兩個變數 ...#ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && !initrd_below_start_ok && initrd_start < min_low_pfn << PAGE_SHIFT) { ; min_low_pfn為內核末端_end所開始的物理頁號,initrd_start,initrd_end在rd.c中定義 printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " "disabling it./n",initrd_start,min_low_pfn << PAGE_SHIFT); initrd_start = 0; }#endif ... kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); 創建init進程 unlock_kernel(); current->need_resched = 1; cpu_idle();}static int init(void * unused){ lock_kernel(); do_basic_setup(); /* * Ok, we have completed the initial bootup, and * we're essentially up and running. Get rid of the * initmem segments and start the user-mode stuff.. */ free_initmem(); unlock_kernel(); if (open("/dev/console", O_RDWR, 0) < 0) printk("Warning: unable to open an initial console./n"); (void) p(0); (void) p(0); /* * We try each of these until one succeeds. * * The Bourne shell can be used instead of init if we are * trying to recover a really broken machine. */ if (execute_command) execve(execute_command,argv_init,envp_init); execve("/sbin/init",argv_init,envp_init); execve("/etc/init",argv_init,envp_init); execve("/bin/init",argv_init,envp_init); execve("/bin/sh",argv_init,envp_init); panic("No init found. Try passing init= option to kernel.");}static void __init do_basic_setup(void){#ifdef CONFIG_BLK_DEV_INITRD int real_root_mountflags;#endif ...#ifdef CONFIG_BLK_DEV_INITRD real_root_dev = ROOT_DEV; ROOT_DEV為所請求根文件系統的塊設備 real_root_mountflags = root_mountflags; if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY; else mount_initrd =0; #endif start_context_thread(); do_initcalls(); 會調用partition_setup()中載入內存檔 /* .. filesystems .. */ filesystem_setup(); /* Mount the root filesystem.. */ mount_root(); mount_devfs_fs ();#ifdef CONFIG_BLK_DEV_INITRD root_mountflags = real_root_mountflags; if (mount_initrd && ROOT_DEV != real_root_dev && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) { ; 如果當前根盤為initrd所建立的內存檔 int error; int i, pid; pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); 創建新的任務去執行程序/linuxrc if (pid>0) while (pid != wait(&i)); 等待linuxrc進程退出 if (MAJOR(real_root_dev) != RAMDISK_MAJOR || MINOR(real_root_dev) != 0) { ; 如果原來的根盤不是0號內存檔,則使用原來的根文件系統, ; 並且將內存檔轉移到其/initrd目錄下 error = change_root(real_root_dev,"/initrd"); if (error) printk(KERN_ERR "Change root to /initrd: " "error %d/n",error); } }#endif}#ifdef CONFIG_BLK_DEV_INITRDstatic int do_linuxrc(void * shell){ static char *argv[] = { "linuxrc", NULL, }; close(0);close(1);close(2); setsid(); 設置新的session號 (void) open("/dev/console",O_RDWR,0); (void) p(0); (void) p(0); return execve(shell, argv, envp_init);}#endif; arch/i386/kernel/setup.c#define RAMDISK_IMAGE_START_MASK 0x07FF#define RAMDISK_PROMPT_FLAG 0x8000#define RAMDISK_LOAD_FLAG 0x4000 #define PARAM ((unsigned char *)empty_zero_page)#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8)) 可用rdev設置的參數#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))#define INITRD_START (*(unsigned long *) (PARAM+0x218)) 初始化盤映象起始物理地址#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c)) 初始化盤位元組數void __init setup_arch(char **cmdline_p){ ...#ifdef CONFIG_BLK_DEV_RAM rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; 以塊為單位 rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);#endif ...#ifdef CONFIG_BLK_DEV_INITRD if (LOADER_TYPE && INITRD_START) { if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { ; max_low_pfn表示內核空間1G范圍以下最大允許的物理頁號 reserve_bootmem(INITRD_START, INITRD_SIZE); initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0; 轉變為內核邏輯地址 initrd_end = initrd_start+INITRD_SIZE; } else { printk("initrd extends beyond end of memory " "(0x%08lx > 0x%08lx)/ndisabling initrd/n", INITRD_START + INITRD_SIZE, max_low_pfn << PAGE_SHIFT); initrd_start = 0; } }#endif ...}; fs/partitions/check.c:int __init partition_setup(void){ device_init(); 包含ramdisk設備的初始化#ifdef CONFIG_BLK_DEV_RAM#ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && mount_initrd) initrd_load(); ;如果啟動時載入了initrd文件,則用它去初始化根內存檔 else#endif rd_load(); 如果內核配置了內存檔並且根盤指定為軟盤則試圖將軟盤載入為根內存檔#endif return 0;}__initcall(partition_setup);; drivers/block/rd.c:int rd_doload; /* 1 = load RAM disk, 0 = don't load */int rd_prompt = 1; /* 1 = prompt for RAM disk, 0 = don't prompt */int rd_image_start; /* starting block # of image */#ifdef CONFIG_BLK_DEV_INITRDunsigned long initrd_start, initrd_end;int mount_initrd = 1; /* zero if initrd should not be mounted */int initrd_below_start_ok;void __init rd_load(void){ rd_load_disk(0); 載入到0號內存檔}void __init rd_load_secondary(void){ rd_load_disk(1); 載入到1號內存檔}static void __init rd_load_disk(int n){#ifdef CONFIG_BLK_DEV_INITRD extern kdev_t real_root_dev;#endif if (rd_doload == 0) return; if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR 如果根盤是不軟盤#ifdef CONFIG_BLK_DEV_INITRD && MAJOR(real_root_dev) != FLOPPY_MAJOR#endif ) return; if (rd_prompt) {#ifdef CONFIG_BLK_DEV_FD floppy_eject();#endif#ifdef CONFIG_MAC_FLOPPY if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR) swim3_fd_eject(MINOR(ROOT_DEV)); else if(MAJOR(real_root_dev) == FLOPPY_MAJOR) swim3_fd_eject(MINOR(real_root_dev));#endif printk(KERN_NOTICE "VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER/n"); wait_for_keypress(); } rd_load_image(ROOT_DEV,rd_image_start, n); 將根軟盤載入到n號內存檔}void __init initrd_load(void){ ; 使用initrd設備盤作為源盤去建立內存根盤 rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),rd_image_start,0);}static void __init rd_load_image(kdev_t device, int offset, int unit){ struct inode *inode, *out_inode; struct file infile, outfile; struct dentry in_dentry, out_dentry; mm_segment_t fs; kdev_t ram_device; int nblocks, i; char *buf; unsigned short rotate = 0; unsigned short devblocks = 0; char rotator[4] = { '|' , '/' , '-' , '//' }; ram_device = MKDEV(MAJOR_NR, unit); 建立輸出內存檔設備號 if ((inode = get_empty_inode()) == NULL) return; memset(&infile, 0, sizeof(infile)); memset(&in_dentry, 0, sizeof(in_dentry)); infile.f_mode = 1; /* read only */ infile.f_dentry = &in_dentry; in_dentry.d_inode = inode; infile.f_op = &def_blk_fops; init_special_inode(inode, S_IFBLK | S_IRUSR, kdev_t_to_nr(device)); if ((out_inode = get_empty_inode()) == NULL) goto free_inode; memset(&outfile, 0, sizeof(outfile)); memset(&out_dentry, 0, sizeof(out_dentry)); outfile.f_mode = 3; /* read/write */ outfile.f_dentry = &out_dentry; out_dentry.d_inode = out_inode; outfile.f_op = &def_blk_fops; init_special_inode(out_inode, S_IFBLK | S_IRUSR | S_IWUSR, kdev_t_to_nr(ram_device)); if (blkdev_open(inode, &infile) != 0) 打開輸入盤文件 goto free_inode; if (blkdev_open(out_inode, &outfile) != 0) 打開輸出內存檔文件 goto free_inodes; fs = get_fs(); set_fs(KERNEL_DS); nblocks = identify_ramdisk_image(device, &infile, offset); 鑒定輸入盤的文件類型 if (nblocks < 0) 出錯 goto done; if (nblocks == 0) { 表示輸入盤是gzip文件#ifdef BUILD_CRAMDISK if (crd_load(&infile, &outfile) == 0) 將輸入盤文件解壓到輸出盤文件中去 goto successful_load;#else printk(KERN_NOTICE "RAMDISK: Kernel does not support compressed " "RAM disk images/n");#endif goto done; } /* * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so * rd_load_image will work only with filesystem BLOCK_SIZE wide! * So make sure to use 1k blocksize while generating ext2fs * ramdisk-images. */ if (nblocks > (rd_length[unit] >> BLOCK_SIZE_BITS)) { ; 如果輸入盤的尺寸超過了輸出內存檔的允許尺寸 printk("RAMDISK: image too big! (%d/%ld blocks)/n", nblocks, rd_length[unit] >> BLOCK_SIZE_BITS); goto done; } /* * OK, time to in the data */ buf = kmalloc(BLOCK_SIZE, GFP_KERNEL); if (buf == 0) { printk(KERN_ERR "RAMDISK: could not allocate buffer/n"); goto done; } if (blk_size[MAJOR(device)]) devblocks = blk_size[MAJOR(device)][MINOR(device)]; 取輸入盤的容量#ifdef CONFIG_BLK_DEV_INITRD if (MAJOR(device) == MAJOR_NR && MINOR(device) == INITRD_MINOR) devblocks = nblocks; 如果輸入是初始化內存檔,則盤的容量為它的實際尺寸#endif if (devblocks == 0) { printk(KERN_ERR "RAMDISK: could not determine device size/n"); goto done; } printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%d disk%s] into ram disk... ", nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : ""); for (i=0; i < nblocks; i++) { if (i && (i % devblocks == 0)) { printk("done disk #%d./n", i/devblocks); rotate = 0; invalidate_buffers(device); 使輸入盤設備緩沖區無效 if (infile.f_op->release) infile.f_op->release(inode, &infile); printk("Please insert disk #%d and press ENTER/n", i/devblocks+1); wait_for_keypress(); if (blkdev_open(inode, &infile) != 0) { printk("Error opening disk./n"); goto done; } infile.f_pos = 0; printk("Loading disk #%d... ", i/devblocks+1); } infile.f_op->read(&infile, buf, BLOCK_SIZE, &infile.f_pos); outfile.f_op->write(&outfile, buf, BLOCK_SIZE, &outfile.f_pos);#if !defined(CONFIG_ARCH_S390) if (!(i % 16)) { printk("%c/b", rotator[rotate & 0x3]); rotate++; }#endif } printk("done./n"); kfree(buf);successful_load: invalidate_buffers(device); ROOT_DEV = MKDEV(MAJOR_NR, unit); 將根盤設備設置為當前載入的內存檔 if (ROOT_DEVICE_NAME != NULL) strcpy (ROOT_DEVICE_NAME, "rd/0");done: if (infile.f_op->release) infile.f_op->release(inode, &infile); set_fs(fs); return;free_inodes: /* free inodes on error */ iput(out_inode); blkdev_put(inode->i_bdev, BDEV_FILE);free_inode: iput(inode);}int __init identify_ramdisk_image(kdev_t device, struct file *fp, int start_block){ const int size = 512; struct minix_super_block *minixsb; struct ext2_super_block *ext2sb; struct romfs_super_block *romfsb; int nblocks = -1; unsigned char *buf; buf = kmalloc(size, GFP_KERNEL); if (buf == 0) return -1; minixsb = (struct minix_super_block *) buf; ext2sb = (struct ext2_super_block *) buf; romfsb = (struct romfs_super_block *) buf; memset(buf, 0xe5, size); /* * Read block 0 to test for gzipped kernel */ if (fp->f_op->llseek) fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0); fp->f_pos = start_block * BLOCK_SIZE; fp->f_op->read(fp, buf, size, &fp->f_pos); ; 讀取offset開始的512位元組 /* * If it matches the gzip magic numbers, return -1 */ if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) { printk(KERN_NOTICE "RAMDISK: Compressed image found at block %d/n", start_block); nblocks = 0; goto done; } /* romfs is at block zero too */ if (romfsb->word0 == ROMSB_WORD0 && romfsb->word1 == ROMSB_WORD1) { printk(KERN_NOTICE "RAMDISK: romfs filesystem found at block %d/n", start_block); nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; goto done; } /* * Read block 1 to test for minix and ext2 superblock */ if (fp->f_op->llseek) fp->f_op->llseek(fp, (start_block+1) * BLOCK_SIZE, 0); fp->f_pos = (start_block+1) * BLOCK_SIZE; fp->f_op->read(fp, buf, size, &fp->f_pos); /* Try minix */ if (minixsb->s_magic == MINIX_SUPER_MAGIC || minixsb->s_magic == MINIX_SUPER_MAGIC2) { printk(KERN_NOTICE "RAMDISK: Minix filesystem found at block %d/n", start_block); nblocks = minixsb->s_nzones << minixsb->s_log_zone_size; goto done; } /* Try ext2 */ if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { printk(KERN_NOTICE "RAMDISK: ext2 filesystem found at block %d/n", start_block); nblocks = le32_to_cpu(ext2sb->s_blocks_count); goto done; } printk(KERN_NOTICE "RAMDISK: Couldn't find valid RAM disk image starting at %d./n", start_block);done: if (fp->f_op->llseek) fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0); fp->f_pos = start_block * BLOCK_SIZE; kfree(buf); return nblocks;}; fs/super.cvoid __init mount_root(void){ struct file_system_type * fs_type; struct super_block * sb; struct vfsmount *vfsmnt; struct block_device *bdev = NULL; mode_t mode; int retval; void *handle; char path[64]; int path_start = -1;#ifdef CONFIG_BLK_DEV_FD if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { 當根盤還是軟盤,表示沒有載入過內存檔#ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; extern void rd_load_secondary(void);#endif floppy_eject();#ifndef CONFIG_BLK_DEV_RAM printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)/n");#else /* rd_doload is 2 for a al initrd/ramload setup */ ; 只有當載入了initrd但沒有釋放到內存檔中(mount_inird=0)才有可能到這一步 if(rd_doload==2) rd_load_secondary(); 載入另一張軟盤到1號內存檔作為根盤 else#endif { printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER/n"); wait_for_keypress(); } }#endif devfs_make_root (root_device_name); handle = devfs_find_handle (NULL, ROOT_DEVICE_NAME, MAJOR (ROOT_DEV), MINOR (ROOT_DEV), DEVFS_SPECIAL_BLK, 1); if (handle) /* Sigh: bd*() functions only paper over the cracks */ { unsigned major, minor; devfs_get_maj_min (handle, &major, &minor); ROOT_DEV = MKDEV (major, minor); } /* * Probably pure paranoia, but I'm less than happy about delving into * devfs crap and checking it right now. Later. */ if (!ROOT_DEV) panic("I have no root and I want to scream"); bdev = bdget(kdev_t_to_nr(ROOT_DEV)); if (!bdev) panic(__FUNCTION__ ": unable to allocate root device"); bdev->bd_op = devfs_get_ops (handle); path_start = devfs_generate_path (handle, path + 5, sizeof (path) - 5); mode = FMODE_READ; if (!(root_mountflags & MS_RDONLY)) mode |= FMODE_WRITE; retval = blkdev_get(bdev, mode, 0, BDEV_FS); if (retval == -EROFS) { root_mountflags |= MS_RDONLY; retval = blkdev_get(bdev, FMODE_READ, 0, BDEV_FS); } if (retval) { /* * Allow the user to distinguish between failed open * and bad superblock on root device. */ printk ("VFS: Cannot open root device /"%s/" or %s/n", root_device_name, kdevname (ROOT_DEV)); printk ("Please append a correct /"root=/" boot option/n"); panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV)); } check_disk_change(ROOT_DEV); sb = get_super(ROOT_DEV); 取根盤的超級塊 if (sb) { fs_type = sb->s_type; goto mount_it; } read_lock(&file_systems_lock); for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) { if (!(fs_type->fs_flags & FS_REQUIRES_DEV)) continue; 根文件系統必須依賴於塊設備 if (!try_inc_mod_count(fs_type->owner)) continue; 當文件系統模塊正在刪除過程中 read_unlock(&file_systems_lock); sb = read_super(ROOT_DEV,bdev,fs_type,root_mountflags,NULL,1);建立根盤的超級塊結構 if (sb) goto mount_it; read_lock(&file_systems_lock); put_filesystem(fs_type); 釋放對文件系統模塊的引用 } read_unlock(&file_systems_lock); panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));mount_it: printk ("VFS: Mounted root (%s filesystem)%s./n", fs_type->name, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); if (path_start >= 0) { devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT, path + 5 + path_start, NULL, NULL); memcpy (path + path_start, "/dev/", 5); vfsmnt = add_vfsmnt(NULL, sb->s_root, path + path_start); } else vfsmnt = add_vfsmnt(NULL, sb->s_root, "/dev/root"); 建立根盤的安裝結構 /* FIXME: if something will try to umount us right now... */ if (vfsmnt) { set_fs_root(current->fs, vfsmnt, sb->s_root); 設置當前進程的根盤和根目錄 set_fs_pwd(current->fs, vfsmnt, sb->s_root); 設置當前進程的當前盤和當前目錄 if (bdev) bdput(bdev); /* sb holds a reference */ return; } panic("VFS: add_vfsmnt failed for root fs");}#ifdef CONFIG_BLK_DEV_INITRDint __init change_root(kdev_t new_root_dev,const char *put_old){ 以new_root_dev作為根盤重新安裝根文件系統,原來的根轉移到put_old目錄下 struct vfsmount *old_rootmnt; struct nameidata devfs_nd, nd; int error = 0; read_lock(¤t->fs->lock); old_rootmnt = mntget(current->fs->rootmnt); 取當前進程的根盤安裝結構 read_unlock(¤t->fs->lock); /* First unmount devfs if mounted */ if (path_init("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd)) error = path_walk("/dev", &devfs_nd); if (!error) { if (devfs_nd.mnt->mnt_sb->s_magic == DEVFS_SUPER_MAGIC && devfs_nd.dentry == devfs_nd.mnt->mnt_root) { dput(devfs_nd.dentry); down(&mount_sem); /* puts devfs_nd.mnt */ do_umount(devfs_nd.mnt, 0, 0); up(&mount_sem); } else path_release(&devfs_nd); } ROOT_DEV = new_root_dev; mount_root(); 改變根盤設備重新安裝根文件系統#if 1 shrink_dcache(); 清除目錄項緩沖中所有自由的目錄項 printk("change_root: old root has d_count=%d/n", atomic_read(&old_rootmnt->mnt_root->d_count));#endif mount_devfs_fs (); /* * Get the new mount directory */ error = 0; if (path_init(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd)) error = path_walk(put_old, &nd); 在新的根盤中尋找put_old目錄 if (error) { int blivet; printk(KERN_NOTICE "Trying to unmount old root ... "); blivet = do_umount(old_rootmnt, 1, 0); 卸載原始的根盤 if (!blivet) { printk("okay/n"); return 0; } printk(KERN_ERR "error %d/n", blivet); return error; } /* FIXME: we should hold i_zombie on nd.dentry */ move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old"); mntput(old_rootmnt); path_release(&nd); return 0;}#endifstatic struct vfsmount *add_vfsmnt(struct nameidata *nd, 在虛擬文件系統中的安裝點 struct dentry *root, 安裝盤的根目錄項 const char *dev_name) 安裝盤名稱{ struct vfsmount *mnt;
————————————————
版權聲明:本文為CSDN博主「huanghaibin」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/huanghaibin/java/article/details/478215
C. make moles編譯驅動模塊,只生成.o文件沒有.ko文件...這是怎麼回事
file1.o和file2.o指的是編譯出來的源文件有兩個分別是file1.c和file2.c
D. 如何把自己的驅動編譯進內核或模塊
我們知道若要給Linux內核添加模塊(驅動)有如下兩種方式:
(1)動態方式:採用insmod命令來給運行中的linux載入模塊。
(2)靜態方式:修改linux的配置菜單,添加模塊相關文件到源碼對應目錄,然後把模塊直接編譯進內核。
對於動態方式,比較簡單,下面我們介紹如何採用靜態的方式把模塊添加到內核。
最終到達的效果是:在內核的配置菜單中可以配置我們添加的模塊,並可以對我們添加的模塊進行編譯。
一. 內核的配置系統組成
首先我們要了解Linux 2.6內核的配置系統的原理,比如我們在源碼下運行「make menuconfig 」為神馬會出現一個圖形配置菜單,配置了這個菜單後又是如何改變了內核的編譯策略滴。
內核的配置系統一般由以下幾部分組成:
(1)Makefile:分布在Linux內核源代碼中的Makefile,定義Linux內核的編譯規則。
(2)配置文件(Kconfig):給用戶提供配置選項,修改該文件來改變配置菜單選項。
(3)配置工具:包括配置命令解釋器(對配置腳本中使用的配置命令進行解釋),配置用戶界面(提供字元界面和圖形界面)。這些配置工具都是使用腳本語言編寫的,如Tcl/TK、Perl等。
其原理可以簡述如下:這里有兩條主線,一條為配置線索,一條為編譯線索。配置工具根據kconfig配置腳本產生配置菜單,然後根據配置菜單的配置情況生成頂層目錄下的.config,在.config里定義了配置選擇的配置宏定義,如下所示:
如上所示,這里定義的這些配置宏變數會在Makefile里出現,如下所示:
然後make 工具根據Makefile里這些宏的賦值情況來指導編譯。所以理論上,我們可以直接修改.config和Makefile來添加模塊,但這樣很麻煩,也容易出錯,下面我們將會看到,實際上我們有兩種方法來很容易的實現。
二. 如何添加模塊到內核
實際上,我們需要做的工作可簡述如下:
(1)將編寫的模塊或驅動源代碼(比如是XXOO)復制到Linux內核源代碼的相應目錄。
(2)在該目錄下的Kconfig文件中依葫蘆畫瓢的添加XXOO配置選項。
(3)在該目錄的Makefile文件中依葫蘆畫瓢的添加XXOO編譯選項。
可以看到,我們奉行的原則是「依葫蘆畫瓢」,主要是添加。
一般的按照上面方式又可出現兩種情況,一種為給XXOO驅動添加我們自己的目錄,一種是不添加目錄。兩種情況的處理方式有點兒不一樣哦。
三. 不加自己目錄的情況
(1)把我們的驅動源文件(xxoo.c)放到對應目錄下,具體放到哪裡需要根據驅動的類型和特點。這里假設我們放到./driver/char下。
(2)然後我們修改./driver/char下的Kconfig文件,依葫蘆添加即可,如下所示:
注意這里的LT_XXOO這個名字可以隨便寫,但需要保持這個格式,他並不需要跟驅動源文件保持一致,但最好保持一致,等下我們在修改Makefile時會用到這個名字,他將會變成CONFIG_LT_XXOO,那個名字必須與這個名字對應。如上所示,tristate定義了這個配置選項的可選項有幾個,help定義了這個配置選項的幫助信息,具體更多的規則這里不講了。
(3)然後我們修改./driver/char下的Makefile文件,如下所示:
這里我們可以看到,前面Kconfig里出現的LT_XXOO,在這里我們就需要使用到CONFIG_XXOO,實際上邏輯是醬汁滴:在Kconfig里定義了LT_XXOO,然後配置完成後,在頂層的.config里會產生CONFIG_XXOO,然後這里我們使用這個變數。
到這里第一種情況下的添加方式就完成了。
四. 添加自己目錄的情況
(1)在源碼的對應目錄下建立自己的目錄(xxoo),這里假設為/drivers/char/xxoo 。
(2) 把驅動源碼放到新建的xxoo目錄下,並在此目錄下新建Kconfig和Makefile文件。然後給新建的Kconfig和Makefile添加內容。
Kconfig下添加的內容如下:
這個格式跟之前在Kconfig里添加選項類似。
Makefile里寫入的內容就更少了:
添加這一句就可以了。
(3)第三也不復雜,還是依葫蘆畫瓢就可以了。
我們在/drivers/char目錄下添加了xxoo目錄,我們總得在這個配置系統里進行登記吧,哈哈,不然配置系統怎麼找到們呢。由於整個配置系統是遞歸調用滴,所以我們需要在xxoo的父目錄也即char目錄的Kconfig和Makefile文件里進行登記。具體如下:
a). 在drivers/char/Kconfig中加入:source 「drivers/char/xxoo/Kconfig」
b). 在drivers/char/Makefile中加入:obj-$(CONFIG_LT_XXOO) += xxoo/
添加過程依葫蘆畫瓢就可以了,灰常滴簡單。
E. 如何編譯Linux內核
編譯linux內核步驟:
1、安裝內核
如果內核已經安裝(/usr/src/目錄有linux子目錄),跳過。如果沒有安裝,在光碟機中放入linux安裝光碟,找到kernel-source-2.xx.xx.rpm文件(xx代表數字,表示內核的版本號),比如RedHat linux的RPMS目錄是/RedHat/RPMS/目錄,然後使用命令rpm -ivh kernel-source-2.xx.xx.rpm安裝內核。如果沒有安裝盤,可以去各linux廠家站點或者www.kernel.org下載。
2、清除從前編譯內核時殘留的.o 文件和不必要的關聯
cd /usr/src/linux
make mrproper
3、配置內核,修改相關參數,請參考其他資料
在圖形界面下,make xconfig;字元界面下,make menuconfig。在內核配置菜單中正確設置個內核選項,保存退出
4、正確設置關聯文件
make dep
5、編譯內核
對於大內核(比如需要SCSI支持),make bzImage
對於小內核,make zImage
6、編譯模塊
make moles
7、安裝模塊
make moles_install
8、使用新內核
把/usr/src/linux/arch/i386/boot/目錄內新生成的內核文件bzImage/zImage拷貝到/boot目錄,然後修改/etc/lilo.conf文件,加一個啟動選項,使用新內核bzImage/zImage啟動。格式如下:
boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
linear
default=linux-new ### 告訴lilo預設使用新內核啟動linux ###
append="mem=256M"
image=/boot/vmlinuz-2.2.14-5.0
label=linux
read-only
root=/dev/hda5
image=/boot/bzImage(zImage)
label=linux-new
read-only
root=/dev/hda5
保留舊有的啟動選項可以保證新內核不能引導的情況,還可以進入linux進行其他操作。保存退出後,不要忘記了最重要的一步,運行/sbin/lilo,使修改生效。
9、重新生成ram磁碟
如果您的系統中的/etc/lilo.conf沒有使用了ram磁碟選項initrd,略過。如果您的系統中的/etc/lilo.conf使用了ram磁碟選項initrd,使用mkinitrd initrd-內核版本號,內核版本號命令重新生成ram磁碟文件,例如我的Redhat 6.2:
mkinitrd initrd-2.2.14-5.0 2.2.14-5.0
之後把/etc/lilo.conf中的initrd指向新生成的initrd-2.2.14-5.0文件:
initrd=/boot/initrd-2.2.14-5.0
ram磁碟能使系統性能盡可能的優化,具體參考/usr/src/linux/Documents/initrd.txt文件
10、重新啟動,OK!
F. 如何把新驅動編譯進內核 ubuntu
工具/原料
Ubuntu12.04操作系統和測試驅動程序(beep_arv.c)
方法/步驟
在介紹2種方法前,必須知道的知識點:
1.關聯文件Makefile:
Makefile:分布在Linux內核源代碼中的Makefile用於定義Linux內核的編譯規則;
2.管理文件Kconfig:
給用戶提供配置選擇的功能;
配置工具:
1)包括配置命令解析器;
2)配置用戶界面;menuconfig || xconfig;
3)通過腳本語言編寫的;
3.
---tristate 代表三種狀態:1.[ ]不選擇,2.[*]選擇直接編譯進內核,載入驅動到內核里,3.[m]動態載入驅動;
---bool 代表兩種狀態,1.[ ]不選擇,2.[*]選擇;
---"Mini2440 mole sample"這個是在make menuconfig時刷出的提示字元;
---depends on MACH_MINI2440 這個配置選項出現在make menuconfig菜單欄下,在內核配置中必須選中、MACH_MINI2440;
---default m if MACH_MINI2440 這個如果選中了MACH_MINI2440,默認是手
動載入這個驅動;
help:提示幫助信息;
在了解了基本的知識點,便開始進行第一種添加驅動的方法,本次交流是以beep_arv.c蜂鳴驅動程序為基礎的
方法一:
1)進入內核的驅動目錄;
#cp beep_arv.c /XXX/.../linux-XXXl/drivers/char
2)進入Kconfig添加驅動信息;
#cd /XXX/linux-XXX/.../drivers/char
#vim Kconfig
添加基本信息:
config BEEP_MINI2440
tristate "---HAH--- BEEP"
default
help
this is test makefile!
3)進入Makefile添加驅動編譯信息;
#vim Makefile
添加基本信息:
obj-$(CONFIG-BEEP_MINI2440) +=beep_drv.o
方法一結果:
在--Character devices下就能看到配置信息了;
方法二:
1)進入驅動目錄,創建BEED目錄;
#cd /XXX/.../linux-XXX/drivers/char
#mkdir beep
2)將beep_arv.c驅動程序復制到新建目錄下;
#cp beep_arv.c /XXX/.../linux-XXXl/drivers/char/beep
3)創建Makefile和Kconfig文件
#cd char/beep
#mkdir Makefile Kconfig
#chmod 755 Makefile
#chmod 755 Kconfig
4)進入Kconfig添加驅動信息;
#vim Kconfig
添加基本信息:
config BEEP_MINI2440
tristate "---HAH--- BEEP"
default
help
this is test makefile!
5)進入Makefile添加驅動編譯信息;
#vim Makefile
添加基本信息:
obj-$(CONFIG_BEEP_MINI2440) +=beep_drv.o
6)並且要到上一級目錄的Makefile和Kconfig添加驅動信息;
#cd ../
#vim Makefile
#vim Kconfig
G. 怎樣才能把framebuffer正確編譯進內核
GRUB配置文件 grub.conf 里現在使用的內核的 kernel 一行最後加上vga=ask(前面加空格和別的部分隔開); 重啟linux,會停在一個系統支持解析度列表的界面,選擇想要的解析度進入。 進系統後應該有framebuffer開啟,有設備文件 /dev/fb0 。