grub2配置關鍵(三個核心變量prefix、root、cmdpath)和幾點疑問


前置知識:你必須知道grub的啟動過程以及bios和uefi的相關基礎知識,可以參考:《Unified Extensible Firmware Interface Wikipedia》《linux啟動過程簡介》

先說說三個變量是干嘛的:

cmdpath

當前被加載的"core.img"(bios的core.img,uefi的BOOTX64.EFI或grubx64.efi等鏡像)所在目錄的絕對路徑。例如:UEFI啟動可能是'(hd0,gpt1)/EFI/GRUB或'(cd0)/EFI/BOOT',BIOS啟動可能是'(hd0)'

prefix

這個變量是指GRUB2的安裝目錄,即絕對路徑形式的'/boot/grub'目錄位置,如例如'(hd0,gpt1)/grub'或'(hd0,msdos2)/boot/grub'。初始值由GRUB在啟動時根據"grub-install"在安裝時提供的信息自動設置,這些信息是由grub-install腳本直接寫入到grub鏡像(bios的core.img,uefi的BOOTX64.EFI或grubx64.efi等鏡像)的,當然,也可以在grub的rescue模式下用grub的命令直接修改,如:set prefix=(hd1,gpt2)/grub。

GRUB2的安裝目錄中存在着這么幾個文件夾和文件

文件夾:

fonts:存在着一些字體

locale:區域化相關

x86_64-efi:模塊的二進制文件,以.mod為后綴。你insmod所操作的模塊,都在這里面有,比如ext4.mod、fat.mod這些文件系統模塊,gzio等解壓支持的模塊。

themes:一些主題,就是你grub界面的背景啥的。

文件:

grub.cfg:這是grub的啟動shell腳本,對於用戶來說,是最重要的文件,幾乎是用戶配置grub的唯一的配置文件。通過這個文件用戶可以控制grub加載操作系統的行為,比如添加一個menuentry就是添加一個操作系統啟動選項,每個選項中可以指定操作系統內核盡享和initramfs鏡像等等。下面是一個grub.cfg的實例:

  1 #由於"$prefix"的值是在"grub-install"安裝時確定的,並且嵌入'core.img'中的模塊也是隨硬件變化的,
  2 #所以不要只是簡單的復制'grub'目錄到處使用,而應該在每一個介質上都使用"grub-install"進行安裝。
  3 ###############################################################################
  4 #(1)本配置文件要求"grub"目錄所在分區的卷標必須是"GRUB2"  5 #(2)為了保持最大程度的BIOS兼容性,"GRUB2"分區必須位於磁盤的前 137GB 范圍。
  6 ###############################################################################
  7 # 如果要在windows上安裝GRUB2的話,必須首先以管理員身份打開命令提示符,然后運行
  8 # wmic diskdrive list brief
  9 # 命令查看安裝目標,最后再使用例如下面這樣的命令進行安裝:
 10 # grub-install.exe --boot-directory=g: --recheck --target=x86_64-efi --efi-directory=g: --no-nvram --removable \\.\PHYSICALDRIVE5
 11 # grub-install.exe --boot-directory=g: --recheck --target=i386-pc \\.\PHYSICALDRIVE5
 12 ###############################################################################
 13 
 14 #################
 15 ## (1)特殊變量 ##
 16 #################
 17 #禁止驗證簽名
 18 set check_signatures=no
 19 #默認啟動第一個菜單項
 20 set default=0
 21 #如果第一個菜單項啟動失敗,轉而啟動第二個菜單項
 22 set fallback=1
 23 #優先使用最常規的1024x768分辨率,以保證在不同的屏幕上擁有一致的菜單效果,如果失敗再自動匹配分辨率
 24 set gfxmode=1024x768,auto
 25 #使用自己制作的24px的大號字體以避免默認字體太小看不清
 26 set gfxterm_font=WenQuanYiMicroHeiMono24px
 27 #將GRUB2設置為簡體中文界面
 28 set lang=zh_CN
 29 #指定翻譯文件(*.mo)的目錄,若未明確設置此目錄,則無法顯示中文界面。
 30 set locale_dir=$prefix/locale
 31 #每一滿屏后暫停輸出,以免信息太多一閃而過看不清
 32 set pager=1
 33 #開啟密碼驗證功能,並設置一個名為'root'的超級用戶
 34 set superusers=root
 35 #設置菜單的超時時間為5秒
 36 set timeout=5
 37 
 38 #################
 39 ## (2)公共模塊 ##
 40 #################
 41 #兩種最流行的磁盤分區格式(partmap.lst)
 42 insmod part_gpt
 43 insmod part_msdos
 44 #常見文件系統驅動(fs.lst)
 45 insmod fat
 46 insmod exfat
 47 insmod ntfs
 48 insmod iso9660
 49 insmod ext2
 50 insmod xfs
 51 #一次性加載所有可用的視頻驅動
 52 insmod all_video
 53 #圖形模式終端
 54 insmod gfxterm
 55 #背景圖片支持
 56 insmod png
 57 
 58 #########################################
 59 ## (3)公共命令(必須放在模塊和變量之后) ##
 60 #########################################
 61 #激活圖形模式的輸出終端,以允許使用中文和背景圖
 62 terminal_output  gfxterm
 63 #設置背景圖片
 64 background_image $prefix/themes/1024x768.png
 65 #加載自己制作的24px的大號字體文件($prefix/fonts/WenQuanYiMicroHeiMono24px.pf2)
 66 loadfont WenQuanYiMicroHeiMono24px
 67 #設置'root'用戶的哈希密碼[通過"grub-mkpasswd-pbkdf2"工具生成]
 68 password_pbkdf2 root grub.pbkdf2.sha512.69.7DBCA469F80EA1C0A8A1E2FEBC4F8463.B073C1C89EC1E85309C3D6A1BAFF4356
 69 
 70 #################
 71 ## (4)菜單項   ##
 72 #################
 73 
 74 menuentry '正常啟動(Windows)' --unrestricted {
 75     if [ 'pc' == $grub_platform ] ; then
 76         if search --file --set /bootmgr ; then
 77             chainloader +1
 78         elif search --file --set /ntldr ; then
 79             chainloader +1
 80         fi
 81     elif [ 'efi' == $grub_platform ] ; then
 82         if search --file --set /EFI/Microsoft/Boot/bootmgfw.efi ; then
 83             chainloader /EFI/Microsoft/Boot/bootmgfw.efi
 84         fi
 85     fi
 86 }
 87 
 88 #http://www.wepe.com.cn/download.html
 89 menuentry '系統救援(WinPE)' --users=root {
 90     if [ 'pc' == $grub_platform -a -f $prefix/winpe/memdisk ] ; then
 91         if [ -f $prefix/winpe/WinPE.iso ] ; then
 92             linux16  $prefix/winpe/memdisk iso raw
 93             initrd16 $prefix/winpe/WinPE.iso
 94         fi
 95     elif [ 'efi' == $grub_platform -a -f $prefix/winpe/bootmgfw.efi -a -f $prefix/winpe/BCD ] ; then
 96         if [ -f $prefix/winpe/WinPE.wim -a -f $prefix/winpe/boot.sdi ] ; then
 97             chainloader $prefix/winpe/bootmgfw.efi
 98         fi
 99     fi
100 }
101 
102 #https://mirrors.tuna.tsinghua.edu.cn/archlinux/iso/latest/
103 if [ -f $prefix/linux/archlinux.iso ] ; then
104     menuentry 'Arch Linux LiveCD [root/空]' --unrestricted {
105         loopback loop0 $prefix/linux/archlinux.iso
106         linux  (loop0)/arch/boot/x86_64/vmlinuz img_label=GRUB2 img_loop=/grub/linux/archlinux.iso   systemd.wants=sshd.service
107         initrd (loop0)/arch/boot/x86_64/archiso.img
108     }
109 fi
110 
111 #https://mirrors.163.com/gentoo/releases/amd64/autobuilds/current-install-amd64-minimal/
112 #因為Gentoo官方的最小安裝CD不支持UEFI啟動,所以不可用於在UEFI環境中安裝Gentoo
113 if [ -f $prefix/linux/install-amd64-minimal.iso ] ; then
114     menuentry 'Mini Gentoo LiveCD [root/123]' --unrestricted {
115         loopback loop0 $prefix/linux/install-amd64-minimal.iso
116         linux  (loop0)/isolinux/gentoo cdroot isoboot=/grub/linux/install-amd64-minimal.iso  dosshd nokeymap passwd=123
117         initrd (loop0)/isolinux/gentoo.igz
118     }
119 fi
120 
121 #https://mirror.umd.edu/calculate/release/
122 #https://www.calculate-linux.org/main/en/download
123 # Calculate Linux Scratch 是基於Gentoo制作的 LiveCD ,
124 #包含編譯工具(GCC,Binutils,...)、支持UEFI、支持WiFi,
125 #既可用作LFS(Linux From Scratch)的宿主系統、也可用於在UEFI環境中安裝 Gentoo
126 if [ -f $prefix/linux/cls.iso ] ; then
127     menuentry 'Live GCC x64 [root/root]' --unrestricted {
128         loopback loop0 $prefix/linux/cls.iso
129         linux  (loop0)/boot/vmlinuz root=live iso-scan/filename=/grub/linux/cls.iso   vga=current nodevfs noresume nodmraid
130         initrd (loop0)/boot/initrd
131     }
132 fi
133 
134 #https://mirrors.huaweicloud.com/centos/7/isos/x86_64/
135 if [ -f $prefix/linux/CentOS-LiveGNOME.iso ] ; then
136     menuentry 'CentOS 7.6 GNOME LiveCD [root/空](可退出liveuser后再用root登錄)' --unrestricted {
137         loopback loop0 $prefix/linux/CentOS-LiveGNOME.iso
138         linux  (loop0)/isolinux/vmlinuz0 rd.live.image root=live:CDLABEL=CentOS-7-x86_64-LiveGNOME-1810 iso-scan/filename=/grub/linux/CentOS-LiveGNOME.iso   systemd.wants=sshd.service inst.lang=zh_CN
139         initrd (loop0)/isolinux/initrd0.img
140     }
141 fi
142 
143 #https://mirrors.ustc.edu.cn/debian-cd/current-live/amd64/iso-hybrid/
144 #也適用於'Kali LiveCD [root/toor]' https://cdimage.kali.org/current/
145 if [ -f $prefix/linux/debian-live-kde.iso ] ; then
146     menuentry 'Debian 9.6 KDE LiveCD (NO SSH)' --unrestricted {
147         loopback loop0 $prefix/linux/debian-live-kde.iso
148         linux  (loop0)/live/vmlinuz-4.9.0-8-amd64 boot=live findiso=/grub/linux/debian-live-kde.iso   components username=root locales=zh_CN.UTF-8
149         initrd (loop0)/live/initrd.img-4.9.0-8-amd64
150     }
151 fi
152 
153 #https://mirrors.aliyun.com/fedora/releases/29/Spins/x86_64/iso/
154 #只有 Xfce LiveCD 可以設置中文界面
155 if [ -f $prefix/linux/Fedora-Xfce-Live.iso ] ; then
156     menuentry 'Fedora 29 Xfce LiveCD [root/空](可退出liveuser后再用root登錄)' --unrestricted {
157         loopback loop0 $prefix/linux/Fedora-Xfce-Live.iso
158         linux  (loop0)/isolinux/vmlinuz rd.live.image root=live:CDLABEL=Fedora-Xfce-Live-29-20181029-1 iso-scan/filename=/grub/linux/Fedora-Xfce-Live.iso   systemd.wants=sshd.service locale.LANG=zh_CN.utf8 inst.lang=zh_CN
159         initrd (loop0)/isolinux/initrd.img
160     }
161 fi
162 
163 #https://ftp.sjtu.edu.cn/opensuse/distribution/openSUSE-stable/live/
164 if [ -f $prefix/linux/openSUSE-Leap-KDE-Live.iso ] ; then
165     menuentry 'openSUSE Leap 15.0 KDE LiveCD [root/空]' --unrestricted {
166         loopback loop0 $prefix/linux/openSUSE-Leap-KDE-Live.iso
167         linux  (loop0)/boot/x86_64/loader/linux root=live:CDLABEL=openSUSE_Leap_15.0_KDE_Live iso-scan/filename=/grub/linux/openSUSE-Leap-KDE-Live.iso   systemd.wants=sshd.service lang=zh_CN
168         initrd (loop0)/boot/x86_64/loader/initrd
169     }
170 fi
171 
172 #https://mirrors.shu.edu.cn/ubuntu-cdimage/lubuntu/releases/
173 #也適用於 KDE neon LiveCD https://files.kde.org/neon/images/neon-userltsedition/current/neon-userltsedition-current.iso
174 if [ -f $prefix/linux/lubuntu.iso ] ; then
175     menuentry 'Ubuntu LXQt LiveCD (NO SSH)' --unrestricted {
176         loopback loop0 $prefix/linux/lubuntu.iso
177         linux  (loop0)/casper/vmlinuz boot=casper iso-scan/filename=/grub/linux/lubuntu.iso   username=root locale=zh_CN keyboard-configuration/layoutcode=us
178         initrd (loop0)/casper/initrd
179     }
180 fi
181 
182 menuentry '關機' --unrestricted { halt ; }
183 menuentry '重新啟動' --unrestricted { reboot ; }
184 
185 #https://rhinstaller.github.io/anaconda/boot-options.html
186 #硬盤安裝通用於所有包含"Packages"目錄的 CentOS/Fedora ISO映像(Minimal,DVD,Everything)
187 #網絡安裝通用於所有包含"images"目錄的 CentOS/Fedora ISO映像(Minimal,DVD,Everything,NetInstall)
188 #https://mirrors.zju.edu.cn/centos/7/isos/x86_64/
189 if [ -f $prefix/linux/CentOS-Minimal.iso ] ; then
190     menuentry '硬盤安裝 CentOS [最小安裝]' --unrestricted {
191         loopback loop0 $prefix/linux/CentOS-Minimal.iso
192         linux  (loop0)/isolinux/vmlinuz inst.repo=hd:LABEL=GRUB2:/grub/linux/CentOS-Minimal.iso   inst.lang=zh_CN
193         initrd (loop0)/isolinux/initrd.img
194     }
195     menuentry '網絡安裝 CentOS 7.x [不支持WiFi]' --unrestricted {
196         loopback loop0 $prefix/linux/CentOS-Minimal.iso
197         linux  (loop0)/images/pxeboot/vmlinuz inst.repo=https://mirrors.aliyun.com/centos/7/os/x86_64/   inst.lang=zh_CN ip=dhcp nameserver=223.6.6.6
198         initrd (loop0)/images/pxeboot/initrd.img
199     }
200 fi
201 
202 #https://www.debian.org/releases/stable/amd64/ch05s03.html.zh-cn
203 #https://www.debian.org/releases/stable/amd64/ch06s03.html.zh-cn
204 #最好將用於硬盤安裝的ISO映像放在文件系統的根目錄或第一層子目錄中(可簡化ISO映像的搜索)
205 #https://mirrors.163.com/debian/dists/stable/main/installer-amd64/current/images/hd-media/
206 #https://mirrors.163.com/ubuntu/dists/bionic/main/installer-amd64/current/images/hd-media/
207 #硬盤安裝也適用於 Alternative Ubuntu Server ISO [ http://cdimage.ubuntu.com/releases/18.04/release/ubuntu-18.04.1-server-amd64.iso ]
208 if [ -f $prefix/linux/debian/vmlinuz -a -f $prefix/linux/debian/initrd.gz ] ; then
209     menuentry '硬盤安裝 Debian [自動搜索ISO映像(最好放在根目錄)]' --unrestricted {
210         linux  $prefix/linux/debian/vmlinuz   priority=low vga=791 locale=zh_CN
211         initrd $prefix/linux/debian/initrd.gz
212     }
213 fi
214 #https://mirrors.163.com/debian/dists/stable/main/installer-amd64/current/images/netboot/
215 #https://mirrors.163.com/ubuntu/dists/bionic/main/installer-amd64/current/images/netboot/
216 #網絡安裝也適用於 Ubuntu 的 mini.iso 映像(支持WiFi網絡)
217 if [ -f $prefix/linux/debian/mini.iso ] ; then
218     menuentry '網絡安裝 Debian [不支持WiFi]' --unrestricted {
219         loopback loop0 $prefix/linux/debian/mini.iso
220         linux  (loop0)/linux   priority=low vga=791 locale=zh_CN
221         initrd (loop0)/initrd.gz
222     }
223 fi
224 
225 #https://doc.opensuse.org/documentation/leap/startup/html/book.opensuse.startup/cha.boot_parameters.html
226 #https://ftp.sjtu.edu.cn/opensuse/distribution/openSUSE-stable/iso/
227 if [ -f $prefix/linux/openSUSE-Leap-DVD.iso ] ; then
228     menuentry '硬盤安裝 openSUSE Leap' --unrestricted {
229         loopback loop0 $prefix/linux/openSUSE-Leap-DVD.iso
230         linux  (loop0)/boot/x86_64/loader/linux install=hd:/grub/linux/openSUSE-Leap-DVD.iso   lang=zh_CN
231         initrd (loop0)/boot/x86_64/loader/initrd
232     }
233 fi
234 #https://mirrors.nju.edu.cn/opensuse/distribution/openSUSE-stable/iso/
235 if [ -f $prefix/linux/openSUSE-Leap-NET.iso ] ; then
236     menuentry '網絡安裝 openSUSE Leap [支持WiFi]' --unrestricted {
237         loopback loop0 $prefix/linux/openSUSE-Leap-NET.iso
238         linux  (loop0)/boot/x86_64/loader/linux install=https://mirrors.aliyun.com/opensuse/distribution/openSUSE-stable/repo/oss/   lang=zh_CN netsetup=dhcp nameserver=223.6.6.6
239         initrd (loop0)/boot/x86_64/loader/initrd
240     }
241 fi

不過,grub.cfg一般都不會手動編輯的,而是用過grub-mkconfig -o /boot/grub/grub.cfg去生成。

grubenv:預設的一些環境變量可以放到這,是一個文本文件

root

root變量一般在grub.cfg執行的過程中設定的,指定了后續腳本中所有文件的其實位置,比如root=(hd0,gpt3),那么/boot/xxx.img 就是在第一塊硬盤的第三個分區的boot目錄下,如果boot是單獨的分區,比如是第2塊硬盤的第2個分區,那么就是 set root=(hd1,gpt2); linux vmlinuz-linux; 這兩行代碼來啟動一個linux內核了。

 

幾點疑問:

1.grub是如何確定鏡像的安裝位置的?

  如果是bios/mbr啟動,那么鏡像的安裝位置是固定的,boot.img在mbr上,core.img在post-MBR gap上。你只需要在安裝時指定哪個盤就可以了,比如:

grub-install /dev/sda,

它就會安裝到第一塊盤上。

  如果是bios/gpt方式,那么必須要分一個bootable partition(或者叫bios boot,不同分區工具,叫法不一樣),這個分區不要格式化任何文件格式,留着就好了,一般1-2M大就可以,鏡像就安裝在上面。

  如果是uefi/gpt方式,那么必須要有一個efi system partition(叫做esp)的專門分區,分區格式是esp,文件系統是flat32。在安裝的時候,先把這個分區掛載上,然后用--efi-directory指定一下他的位置,如果它是掛載到/boot/efi上,那么不用指定,grub-install會默認esp在那。uefi安裝的示例如下:
  

# grub-install --target=x86_64-efi --efi-directory=esp --bootloader-id=GRUB
--target指定了系統架構,--bootloader-id指定了grub的efi啟動點的名字,到時候你可以在主板設置上看到它。

   至於uefi/mbr方式,那種太奇怪了,你不會碰到的。

 

2.grub-install是在安裝grub時,是如何確定prefix的?

你在哪個操作系統上運行它,這個操作系統的/boot/grub所對應的路徑就是prefix。比如你的操作系統的boot分區在第1塊盤的第3個分區上,那么prefix就是(hd0,gpt3)/grub。這就是網上經常說的默默操作系統去引導啥,比如說Ubuntu系統引導windows,其實就是說啟動點是grub,prefix是Ubuntu的/boot/grub。

說句題外話,一個操作系統是不可能引導另一個操作系統的,只有引導器(BootLoader)如grub才能引導操作系統啟動,或者uefi可以直接引導操作系統啟動。並且,grub還不能直接應道dos(windows)啟動,而是先引導windows系統的引導器(如EasyBCD),再讓這個引導器去引導windows,這種方式成為鏈式引導(chainload),比如:

menuentry 'Windows'{
insmod part_msdos
insmod ntfs
set root='(hd0,msdos1)'
chainloader +1
}

3.是不是一定要掛載esp分區?

如果你確定不會在去動grub了,那么可以不掛載,efi分區只在你操作引導器的時候才有用,平常它是沒有用的。所以看到有些教程說把它掛載到/efi上,有的則是/boot/efi上,甚至有的直接說掛到/boot上這樣方便直接啟動。其實都可以,掛載到不同位置,只影響你grub-install的操作結果,操作過后,他就沒用了。

 

4.linux內核是如何確定文件掛載樹的?我能不能把/etc也搞到一個單獨的分區上?

有人會說有/etc/fstab,對,沒錯,但是,內核啟動的時候,它首先得知道/etc在那個盤對吧?不然它怎么知道到fstab呀。看來這就是個先有雞還是先有蛋的問題,怎么解決呢?

如果你仔細看上面的grub.cfg,你就會發現,在啟動Linux內核的語句中有許多參數,比如這句: linux (loop0)/boot/x86_64/loader/linux root=live:CDLABEL=openSUSE_Leap_15.0_KDE_Live iso-scan/filename=/grub/linux/openSUSE-Leap-KDE-Live.iso systemd.wants=sshd.service lang=zh_CN ,有一個root=xxx,這就是指定了root參數,所以就能知道/在哪,也就知道了/etc在哪。所以,一般來說你的/etc是不能掛載到單獨的盤的,除非你自己編譯一下內核,加入一個etc=xxx之內的參數,在運行linux命令的適合指定這個etc的盤,這樣你就可以把etc單獨搞到別的盤了,但一般沒有人有這么蛋疼的需求。如果你一定要這么做,可以參考一下這個老哥《Moving /etc to separate partition》。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM