ubuntu20.04與win7 UEFI + GPT雙啓動修復

  老筆記本,一直用的ubuntu14.04與win7雙系統。因爲怕折騰,一直沒有升級ubuntu,畢竟裏面有數年常用的數據、軟件,升級的話不折騰幾天是搞不定的。不過ubuntu14.04的支持基本到頭了,趁着ubuntu20.04 LTS新鮮出爐,決定嘗試一下。

  這一嘗試,首先出現的問題就是引導掛了。只進入了grub shell,然後我進入LiveCD用boot-repair一頓操作,把win7的啓動也弄掛了,這。。。只能手動慢慢修了。要修就得先知道UEFI是怎麼工作的,這裏先簡單說下UEFI的啓動過程。

  支持UEFI的主板上都有NVRAM(Non-Volatile Ram即掉電也不丟失數據的存儲空間),安裝操作系統的時候,通常都會在NVRAM寫入引導項,這個列表除了安裝操作系統時寫入的引導項,還有一些固定的硬件引導項,比如硬盤、U盤、網絡啓動)。在開機的時候,進入BIOS應該是能看到這個列表的,不同的主板操作不一樣,我機子上的NVRAM列表看起來是這樣的:

ubuntu是安裝ubuntu時寫入的引導項,IPV4、Boot From EFI File則是一些固定的硬件引導項。

  實現UEFI啓動,硬盤上還需要有一個ESP分區(EFI system partition),然後安裝操作系統時,會在ESP分區寫入引導文件。我機子上的ESP分區大概是這樣的:

~$ sudo tree /boot/efi/EFI -L 3
/boot/efi/EFI
├── Boot
│   ├── BOOTX64.CSV
│   ├── bootx64.efi
│   ├── grub.cfg
│   ├── grubx64.efi
│   ├── mmx64.efi
│   └── shimx64.efi
├── Microsoft
│   └── Boot
│       ├── BCD
│       ├── BCD.LOG
│       ├── BCD.LOG1
│       ├── BCD.LOG2
│       ├── bootmgfw.efi
│       ├── bootmgr.efi
│       ├── BOOTSTAT.DAT
│       ├── cs-CZ
│       ├── da-DK
│       ├── de-DE
│       ├── el-GR
│       ├── en-US
│       ├── es-ES
│       ├── fi-FI
│       ├── Fonts
│       ├── fr-FR
│       ├── hu-HU
│       ├── it-IT
│       ├── ja-JP
│       ├── ko-KR
│       ├── memtest.efi
│       ├── nb-NO
│       ├── nl-NL
│       ├── pl-PL
│       ├── pt-BR
│       ├── pt-PT
│       ├── ru-RU
│       ├── sv-SE
│       ├── tr-TR
│       ├── zh-CN
│       ├── zh-HK
│       └── zh-TW
└── ubuntu
    ├── BOOTX64.CSV
    ├── grub.cfg
    ├── grubx64.efi
    ├── mmx64.efi
    └── shimx64.efi

28 directories, 19 files

其中,Boot目錄是ESP分區的默認目錄,Microsoft是win7的引導目錄,ubuntu則是ubuntu的引導目錄,注意,ESP分區是fat格式,這些目錄及文件名不區分大小寫。

  當開機時,主板加電,會從NVRAM中讀取引導列表,按順序一個個去嘗試引導啓動,如果成功,就會進入對應的操作系統。例如,我的機子在開機時選擇ubuntu的話,則主板會根據NVRAM中ubuntu這個項中的信息,直接加載ESP分區中的ubuntu/shimx64.efi,然後ubuntu/shimx64.efi會啓動grub,接着由grub啓動ubuntu,完成ubuntu的啓動。如果選擇從硬盤啓動(我機子的BIOS中沒顯示這個項,後面會說到),那就會在硬盤中查找ESP分區(ESP分區在同一個硬盤可以有多個,會一個個去試),如果ESP分區中存在/Boot/bootx64.efi,就運行這個文件,完成引導,所以Boot目錄稱爲ESP的默認目錄。

  回到之前的問題,我安裝ubuntu後,沒能引導進系統,而是掛在grub shell了,說明UEFI已經正確加載了ubuntu/shimx64.efi,但在grub那一步,grub沒能成功啓動ubuntu,這可能是配置錯誤,比如grub.conf錯誤。但我的系統是全新安裝的,grub的配置不大可能會出問題,可能是一些環境變量不對,嘗試手動加載。我的硬盤是gpt模式,ubuntu安裝在第7個區分,沒有使用獨立的boot分區,因此boot目錄是在ubuntu分區的boot目錄下,即(hd0,gpt7)/boot/grub。如果不記得安裝在哪個分區,可以用ls (hd0,gpt7)這樣一個個去試,會打印一些分區信息

grub > ls
(hd0), (hd0,gpt8),(hd0,gpt7),(hd0,gpt6),(hd0,gpt5),(hd0,gpt4),(hd0,gpt3),(hd0,gpt2),(hd0,gpt1)
grub > set root=(hd0,gpt7)
grub > set prefix=(hd0,gpt7)/boot/grub
grub > insmod normal
grub > normal

如果成功,會出現後面那個grub菜單,即可進入系統。如果失敗,或者無法引導進入系統,那麼說明grub已經沒救了(至少以我的水平救不了了),你需要一個LiveCD之類的盤了。進入系統後,就需要修復一下grub了

sudo update-grub
Sourcing file `/etc/default/grub'
Sourcing file `/etc/default/grub.d/init-select.cfg'
正在生成 grub 配置文件 ...
找到 Linux 鏡像:/boot/vmlinuz-5.4.0-26-generic
找到 initrd 鏡像:/boot/initrd.img-5.4.0-26-generic
Adding boot menu entry for UEFI Firmware Settings
完成

update-grub會搜索當前系統,查找各種啓動,然後完成修復。按我的理解,update-grub只是修復grub引導,即對應/boot/grub目錄下的東西,並不會修改ESP分區以及NVRAM的東西,但Adding boot menu entry for UEFI Firmwre Settings實在讓人困惑,這個像是往NVRAM添加引導項。

如果進入的是LiveCD,那麼當前系統並不是你想要修復的系統,你想修復的系統還在硬盤上,那麼手動修復就複雜多了,我沒這樣操作過。在LiveCD可以使用boot-repair來修復

sudo add-apt-repository ppa:yannubuntu/boot-repair && sudo apt-get update
sudo apt-get install -y boot-repair && boot-repair

boot-repair是一個帶UI的程序,在菜單裏找到它直接按提示操作就好。我的機子修復好以後,ubuntu能進了,但是win7的導引沒了。而且,出現了新的問題

每次啓動時,都會提示

System BootOrder not found. Initializing defaults.
Creating boot entry "Boot0001" with label "ubuntu" for file "\EFI\ubuntu\shhimx64.efi"

而且這個Boot0001會依次增加爲Boot0001、Boot0002、Boot0003,這樣一直加下去,但是能正常進入ubuntu系統。根據上面UEFI的啓動過程,可以推斷,提示這個的時候,主板還沒加載任何efi文件,而是在嘗試引導某個NVRAM中的啓動項時失敗,然後主板在ESP分區找到了\EFI\ubuntu\shimx64.efi這個文件,並用這個文件引導ubuntu。我的直覺是NVRAM列表有問題,需要修復下。在ubuntu下,可以用efibootmgr來管理NVRAM列表

~$ efibootmgr
BootCurrent: 0002
Timeout: 0 seconds
BootOrder: 0002
Boot0000* ubuntu
Boot0001* ubuntu
Boot0002* ubuntu

$ efibootmgr -v
BootCurrent: 0002
Timeout: 0 seconds
BootOrder: 0002
Boot0000* ubuntu	HD(1,GPT,2b776bfe-665b-4a9a-995f-4c74e11712a4,0x800,0x95800)/File(\EFI\ubuntu\shimx64.efi)
Boot0001* ubuntu	HD(1,GPT,2b776bfe-665b-4a9a-995f-4c74e11712a4,0x800,0x95800)/File(\EFI\ubuntu\shimx64.efi)
Boot0002* ubuntu	HD(1,GPT,2b776bfe-665b-4a9a-995f-4c74e11712a4,0x800,0x95800)/File(\EFI\ubuntu\shimx64.efi)


sudo efibootmgr -b 0001 -B
sudo efibootmgr -b 0002 -B
sudo efibootmgr -o 0000
sudo efibootmgr -b 0000 -a

通過efibootmgr指令可以看到主板已經給NVRAM列表添加了幾個ubuntu,通過efibootmgr -v可以查看他們的參數(當選擇NVRAM的一個啓動項時,主板知道去哪個分區運行哪個efi文件,就是根據這些參數來的)。但是並沒有看出什麼問題,似乎一切正常。於是我把多餘的刪除了

sudo efibootmgr -b 0001 -B # 把啓動項0001刪了
sudo efibootmgr -b 0002 -B # 把0002刪了
sudo efibootmgr -o 0000 # 設置0000爲第一啓動順序
sudo efibootmgr -b 0000 -a #設置0000爲活動啓動項

重啓,結果發現還是一樣,主板又自動加了一個0001回來,參數還是一模一樣。我懷疑是哪裏操作錯誤,沒修改到NVRAM列表,於是把它們又刪了,還故意創建了一個win的引導項

~$ sudo efibootmgr -c -d /dev/sda -p 1 -L "Windows Boot Manager" -l "\EFI\microsoft\bootmgfw.efi"
BootCurrent: 0002
Timeout: 0 seconds
BootOrder: 0001,0000
Boot0000* ubuntu
Boot0001* Windows Boot Manager

重啓,發現NVRAM列表確實有修改到,多了Windows Boot Manager,不過問題依然存在。

至此,NVRAM像是沒有問題的,那麼我就懷疑ESP分區了。於是我直接把ESP分區給格了。然後重新安裝

:~$ sudo update-grub
Sourcing file `/etc/default/grub'
Sourcing file `/etc/default/grub.d/init-select.cfg'
正在生成 grub 配置文件 ...
找到 Linux 鏡像:/boot/vmlinuz-5.4.0-26-generic
找到 initrd 鏡像:/boot/initrd.img-5.4.0-26-generic
Adding boot menu entry for UEFI Firmware Settings
完成

:~$ sudo grub-install /dev/sda
正在爲 x86_64-efi 平臺進行安裝。
安裝完成。沒有報告錯誤。

update-grub是修復/boot/grub的,我這裏並沒修改,其實是不需要運行的,不過爲了保險再修復一次。grub-install是把當前系統的啓動信息安裝到ESP分區,會在ESP分區生成ubuntu目錄和Boot目錄,並且在NVRAM添加引導項。然後檢測ESP分區(在ubuntu20.04裏,已掛載到/boot/efi/EFI目錄,ls就能看到文件)的各個文件,確認Boot和ubuntu目錄確實存在,並且各文件的日期也是剛更新的,然後重啓,問題依然存在。

  到了這裏,我已經技窮了,實在想不出來有啥可以操作的了。甚至還試了下在LiveCD下修復

mkdir /mnt/sda7
mount /dev/sda7 /mnt/sda7
grub-install --boot-directory=/mnt/sda7 /dev/sda

# 由於LiveCD不是要修復的系統,需要把要修復的系統mount到當前系統
# 然後修復的時候指定啓動目錄爲需要修復的系統目錄

然而並沒有什麼區別。瘋狂地google "System BootOrder not found"這些關鍵字,發現有不少例子,都沒能說明白啥原因造成,不過我也嘗試了他們的一些做法:

1. 在BIOS設置中把ubuntu放到第一項,但是我的BIOS沒有這個選項,嘗試失敗

2. 嘗試創建一個啓動項,手動指定到ESP分區的/ubuntu/shimx64.efi。我機子的BIOS確實有一個Customized Boot,不過不管我輸入啥,在NVRAM列表中都不會出現這個選項,只能放棄了

3. 直接使用Boot From EFI File從ESP分區的/boot/bootx64.efi啓動,能進入系統,但問題依舊

4. 直接從NVRAM中選擇ubuntu進入,問題解決,但我機子的BIOS無法設置ubuntu爲第一啓動項,所以這個不是辦法

5. 接使用Boot From EFI File從ESP分區的/ubuntu/shimx64.efi啓動,問題解決,但是這個只能手動啓動

6. 把ESP分區裏的/ubuntu/shimx64.efi覆蓋/Boot/bootx64.efi,問題依然

7. 把ESP分區Boot目錄裏的文件全刪了,複製ubuntu目錄中的所有文件到Boot目錄,然後把shimx64.efi改名bootx64.efi,問題解決

  現在,"System BootOrder not found"這個問題是如何出現的,沒法知道原因。google得到的結果裏,多數也歸爲BIOS固件和UEFI的兼容問題,並且不少都提到hp筆記本的固件,我的剛好就是hp筆記本。沒辦法解決這個問題,只能繞過它。從結果上看,這有幾個問題。第一,grub-install在ESP分區生成的Boot/bootx64.efi,在我的筆記本上無法正常引導ubuntu;第二,hp的BIOS沒有按UEFI標準來引導系統,NVRAM列表上一直有ubuntu,但是沒有硬盤的選項,而啓動的時候,卻直接從硬盤啓動,然後執行/Boot/bootx64.efi,正常應該是先嚐試NVRAM中設定的選項;第三,hp這個BIOS很坑,不僅不能像別的那樣設定NVRAM的啓動順序,它一直有一個OS Boot Manager,這個OS Boot Manager用efibootmgr看不到,改不了,選中的時候主是從硬盤啓動,我懷疑直接從硬盤啓動就是這個隱藏選項的問題

  ubuntu的啓動問題總算解決了,下一步,就是要修復win7的啓動。windows系統啓動時,加載ESP分區的EFI/Microsoft/bootmgfw.efi文件,bootmgfw.efi讀取目錄下的BCD文件(boot configuration data),BCD保存了win的啓動信息,比如在哪個分區。如果是多個win系統,也是在這裏配置。根據BCD,加載對應分區的“\windows\system32\winload.efi”,之後winload.efi加載windows內核,啓動完成。

  win也提供了啓動修復工具:bcdboot.exe。進入PE,確保win系統分區和ESP分區已掛載,我這裏剛好是C和H盤,和bcdboot的幫助文檔一致

執行

bcdboot c:\windows /s h: /f UEFI /l zh-cn

:: 表示c:\windows爲系統目錄
:: h爲ESP分區
:: 啓動方式爲UEFI
:: 啓動語言爲中文簡體

執行完後,檢查ESP分區,正確創建了Microsoft目錄。PS:看網上有些人說bcdboot修復會覆蓋ESP分區裏的Boot目錄,我試了下,在我機子並不會出現這種情況,如果出現了再用ubuntu的啓動文件重新覆蓋一次。

  重啓,我發現在BIOS裏並沒有windows的引導項。但是,我用efibootmgr來檢查,win7引導項是有在NVRAM列表中的,而我的ubuntu反而不見了。。。也不知道是bcdboot給清了,還是主板BIOS的問題,不過反正ubuntu那個引導項從來不會排在第一啓動項,所以我也不糾結這個,直接默認從硬盤啓動就好。

:~$ efibootmgr -v
BootCurrent: 0000
Timeout: 0 seconds
No BootOrder is set; firmware will attempt recovery
Boot0000* Notebook Hard Drive	BBS(HD,,0x0).......................................................................
Boot0001* SD Card	BBS(7,,0xa0).......................................................................
Boot0002* Windows Boot Manager	HD(1,GPT,2b776bfe-665b-4a9a-995f-4c74e11712a4,0x800,0x95800)/File(\EFI\Microsoft\Boot\bootmgfw.efi)WINDOWS.........x...B.C.D.O.B.J.E.C.T.=.{.9.d.e.a.8.6.2.c.-.5.c.d.d.-.4.e.7.0.-.a.c.c.1.-.f.3.2.b.3.4.4.d.4.7.9.5.}....................

在UEFI模式下,Linux + Win雙系統引導只有兩種方式,一是由BIOS引導,在NVRAM列表裏直接選擇啓動哪個系統,不過我這裏在BIOS裏沒有出現win的引導項,而且沒法設置默認ubuntu啓動,所以不考慮;二是由Linux的grub來引導win系統。不存在win引導linux的選項,因爲到目前爲止,一旦加載ESP分區的/Microsoft/Boot/bootmgfw.efi。它就會讀取BCD中的配置,如果有多個系統,就會出現一個選擇菜單,如果這裏加了一個linux系統,它是不認linux系統的數據,引導不成功的,所以它可以引導多個windows,但不能引導linux系統。

  進入ubuntu,用update-grub來更新grub配置

~$ sudo update-grub
Sourcing file `/etc/default/grub'
Sourcing file `/etc/default/grub.d/init-select.cfg'
正在生成 grub 配置文件 ...
找到 Linux 鏡像:/boot/vmlinuz-5.4.0-26-generic
找到 initrd 鏡像:/boot/initrd.img-5.4.0-26-generic
找到 Windows Boot Manager 位於 /dev/sda1@/EFI/Microsoft/Boot/bootmgfw.efi
Adding boot menu entry for UEFI Firmware Settings
完成

如果win的啓動配置正確,update-grub應該是能夠分析到win的引導並加入到grub中,如果不行,那得手動編輯/boot/grub/grub.cfg來手動添加入口。由於grub配置和ESP分區無關,因此不需要grub-install,重啓,應該能在grub選擇菜單中看到win7了。

  關於SecureBoot,安全啓動,是說在整個啓動過程中,所調用的文件都是經過簽名的。比如啓動用的shimx64.efi,還有系統啓動時一些驅動等。ubuntu官方的文件是有簽名的,因此支持安全啓動,但是有一些驅動是私有的,比如AMD、NVIDIA的顯卡驅動,是沒有經過簽名的,如果有用這類的驅動,就得關閉安全啓動。

  關於UEFI CSM(Compatibility Support Module),UEFI的兼容模塊,允許操作系統以舊的BIOS-MBR模式啓動。win7必須得開啓CSM才能正常啓動,部分人以爲是win7需要MBR模式引導,這個是錯誤的。關閉CSM,用UEFI + GPT的方式win7一樣能引導,只是卡在啓動中,一般是在windows那個圖標的位置就花屏了。UEFI不僅僅是從NVRAM讀取引導項,去ESP分區加載引導程序這麼簡單的,這只是它一小部分的功能。它的另一個功能,是定義了UEFI下的一些顯示規則,所以UEFI的主板,啓動過程可以做得很炫酷。UEFI引導win7是沒問題的,但是win7的驅動不支持UEFI的顯示,因此完成引導後,就跑不下去了。有傳聞說,只要願意啓動過程黑屏,win7也是可以純UEFI啓動的(我沒試過,嘗試的話後果自負)

設置啓動過程黑屏
bcdedit.exe /store S:\efi\Microsoft\boot\bcd /set {default} novesa on
然後刪掉vga.sys
C:\Windows\System32\drivers,把vga.sys

而ubuntu20.04是兩者都支持的,但在CSM模式下,明顯驅動沒寫好,OEM logo被拉伸了,正常情況下,hp這個應該是圓的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章