App Icon

Stardue128

More

리눅스 부팅 멈춤 증상 해결법 한 가지

First Published at

8/10/2023 5:33:04 AM

Last Edited at

8/29/2023 4:22:52 AM

nomodeset 옵션으로 리눅스 부팅이 멈추는 증상을 해결해봅니다.

본 글은 리눅스 커널 6.1 기준으로 작성되었습니다.

리눅스를 처음 설치, 혹은 업데이트했을 때 부팅이 멈춰버리는 경우를 경험해보셨을 것입니다. 이번 글에서는 이를 해결할 수 있는 방법 중 한가지를 소개해드리려 합니다.

#

nomodeset이란?

The newest kernels have moved the video mode setting into the kernel. So all the programming of the hardware specific clock rates and registers on the video card happen in the kernel rather than in the X driver when the X server starts.. This makes it possible to have high resolution nice looking splash (boot) screens and flicker free transitions from boot splash to login screen. Unfortunately, on some cards this doesnt work properly and you end up with a black screen. Adding the nomodeset parameter instructs the kernel to not load video drivers and use BIOS modes instead until X is loaded.

https://ubuntuforums.org/showthread.php?t=1613132

txt
linux/Documentation/admin-guide/kernel-parameters.txt
nomodeset Disable kernel modesetting. Most systems' firmware
sets up a display mode and provides framebuffer memory
for output. With nomodeset, DRM and fbdev drivers will
not load if they could possibly displace the pre-
initialized output. Only the system framebuffer will
be available for use. The respective drivers will not
perform display-mode changes or accelerated rendering.

리눅스에서는 비디오 모드 세팅 역할을 커널이 가지고 있습니다. 그래서 그래픽 드라이버 대신 커널이 그래픽카드 제어를 담당합니다. 이렇게 하면 고해상도 부팅 스크린(splash)을 구현할 수 있고, 부팅 스크린에서 로그온 화면으로 넘어가는 과정을 깜빡임 없이 부드럽게 진행할 수 있습니다. 하지만 일부 그래픽카드에서는 제대로 작동하지 않는 문제가 있는데, 부팅이 도중에 멈춰버리기도 합니다.

grub

1

cat /etc/default/grub

···

3

# info -f grub -n 'Simple configuration'

4

5

GRUB_DEFAULT="nomodeset"

6

···

nomodeset 옵션을 grub 부트로더에 옵션으로 주면 이 역할을 X가 완전히 로드될 때까지 그래픽 드라이버가 로드되지 않도록 커널에 지시합니다.

#

nomodeset의 전달 경로

C
linux/drivers/gpu/drm/drm_nomodeset.c

1

// SPDX-License-Identifier: GPL-2.0

2

3

#include <linux/module.h>

4

#include <linux/types.h>

5

6

static bool drm_nomodeset;

7

8

bool drm_firmware_drivers_only(void)

9

{

10

return drm_nomodeset;

11

}

12

EXPORT_SYMBOL(drm_firmware_drivers_only);

13

14

static int __init disable_modeset(char *str)

15

{

16

drm_nomodeset = true;

17

18

pr_warn("Booted with the nomodeset parameter. Only the system framebuffer will be available\n");

19

20

return 1;

21

}

22

23

/* Disable kernel modesetting */

24

__setup("nomodeset", disable_modeset);
nomodeset 설정 값이 어떻게 실제로 적용되는지를 간단히 살펴보겠습니다.
drm_nomoeset.c를 보면 6라인static bool 타입 변수 drm_nomodeset이 존재합니다. 그리고 24라인__setup("nomodeset", disable_modeset) 매크로는 부트로더가 넘겨준 부팅 parameter 중 nomodeset가 존재할 경우 14라인disable_modeset() 함수를 실행하도록 지시합니다. disable_nomodeset() 함수는 앞선 static 변수 drm_nomodeset의 값을 true로 설정합니다.

DRM이란 Direct Rendering Manager의 약자로 GPU와의 인터페이스 역할을 하며 리눅스 서브시스템(subsystem) 중 하나입니다.
그래픽 드라이버는 이 drm_nomodeset의 값을 8라인drm_firmware_drivers_only() 함수를 통해 참조합니다.
C
linux/drivers/gpu/drm/radeon/radeon_drv.c

···

147

int radeon_modeset = -1;

···

630

static int __init radeon_module_init(void)

631

{

632

if (drm_firmware_drivers_only() && radeon_modeset == -1)

633

radeon_modeset = 0;

634

635

if (radeon_modeset == 0)

636

return -EINVAL;

637

638

DRM_INFO("radeon kernel modesetting enabled.\n");

639

radeon_register_atpx_handler();

640

641

return pci_register_driver(&radeon_kms_pci_driver);

642

}

···

651

module_init(radeon_module_init);

···

이번 글에서는 라데온 드라이버를 예로 들어보겠습니다. 147라인에서 radeon_modeset의 값은 -1로 지정되어 있는 상태입니다. 632라인에서 drm_firmware_drivers_only() 함수를 호출합니다. 만약 nomodeset 옵션이 붙여져 있었다면, 이 함수가 true를 반환할 것입니다. 이때 radeon_nomodeset의 값이 0이 되므로, 635라인에 의해 651라인이 지시했던 드라이버 로드 과정을 종료시켜버립니다. 651라인module_init() 매크로는 커널 모듈을 등록하는 역할이었습니다.

#

nomodeset 옵션을 이용해 리눅스 설치하기

nomodeset 옵션을 붙이면 부팅 과정이 끝날 때까지 그래픽 드라이버 사용이 중지됩니다. 따라서 호환성 문제가 있을 때 유용하게 사용할 수 있습니다. 이번에는 실제로 nomodeset 옵션을 사용해보겠습니다.

#

설치 미디어로 부팅

설치 미디어로 부팅을 시도하면 위와 같이 GRUB 부트로더가 나타날 것입니다. 여기서 Try or Install Ubuntu (Server) 옵션에 커서를 위치시킨 뒤, e 키를 누릅니다.

그러면 위와 같이 부팅 파라미터를 세팅할 수 있는 화면이 나타납니다.

여기서 linux가 적혀있는 라인으로 간 뒤, ---을 없애고 nomodeset으로 대체합니다. 그 후 Ctrl + xF10을 눌러 해당 설정으로 부팅합니다.

이제 자유롭게 리눅스 설치를 진행합니다.

#

설치 완료 후 첫 부팅

이제 시스템에 따라 재부팅 후 먹통이 되는 경우가 있을 것입니다.

메인보드 로고, 혹은 POST가 뜬 직후 Esc를 누르거나 Shift를 누르고 있으세요.

시스템에 따라 Esc를 누르면 UEFI Setup으로 진입할 수 있습니다. 이 때는 UEFI Setup에서 Boot Override 기능을 이용해 재부팅하여 다시 시도하거나, Shift를 사용하세요.
이제 시스템에 정식으로 설치된 GRUB이 나타납니다. 여기서 Ubuntu에 커서를 맞춘 뒤 마찬가지로 e키를 누르세요.
여기서도 마찬가지로 linux가 있는 라인을 찾습니다.
이제 마지막 파라미터 뒤에 nomodeset 파라미터를 붙입니다. 마찬가지로 Ctrl + xF10을 눌러 부팅을 진행합니다.

정상적으로 부팅이 진행되는 모습입니다.

이제 GRUB 세팅을 바꿀 차례입니다.

Bash
$ sudo nano /etc/default/grub
여기서 손 볼 것은 GRUB_CMDLINE_LINUX_DEFAULT 부분입니다.
GRUB_CMDLINE_LINUX_DEFAULT의 맨 마지막에 nomodeset을 붙여주세요.

이후 저장하고 빠져나옵니다.

Bash
$ sudo update-grub

이제 GRUB 설정을 업데이트합니다.

여기까지입니다. 이제 기본적으로 부팅 시에 아무 것도 건들지 않아도 nomodeset 옵션이 붙은 채로 부팅이 진행될 것입니다.