grub之loongarch架构调试

一 什么是grub

GNU GRUB 是一个多重操作系统启动管理器。GNU GRUB是由GRUB(GRandUnified Bootloader)派生而来。
GRUB最初由Erich Stefan Boleyn 设计和应用;
主流发行版 Fedora、Redhat、Centos、Kylin 等基于RPM包的系统,在最新版本中都默认GRUB引导;
Slackware目前仍采用LILO;而Debian发行版目前最新的版本也是采用GRUB;Grub在uefi上也是以一个Grub.efi的方式运行的,但是这个efi是放在操作系统下面的boot/EFI/下面的, 
uefi在运行过程的后期加载Grub的时候会去这个目录load这个Grub模块,Load到内存之后,就开始执行。 

二 grub源码环境的安装

笔者以国产Kylin操作系统为例进行安装:
a) 先拿到grub2 对应的rpm包 
https://download.csdn.net/download/qq_33559839/89560518 
b) 下载之后,将rpm报进行安装 
rpm -ivh grub2-2.12-21.se.02.p01.ky11.src.rpm  
c) 将源码展示出来  
cd /root/rpmbuild
rpmbuild -bp SPECS/grub2.spec 
cd BUILD 
grub-2.12 --》 就是grub2的源码 
find -name main.c 
找到grub2的入口点文件 ---》 ./grub-core/kern/main.c 

三 grub源码分析:

3.0 首先是grub的入口点文件:
vi grub-core/kern/loongarch64/efi/startup.S 就是入口点文件
FUNCTION(_start)/** EFI_SYSTEM_TABLE and EFI_HANDLE are passed in $a1/$a0.*/la      $a2, EXT_C(grub_efi_image_handle)st.d        $a0, $a2, 0la      $a2, EXT_C(grub_efi_system_table)st.d        $a1, $a2, 0b       EXT_C(grub_main) //跳转到grub_main函数,所以gruub_main就是grub的入口函数
3.1 我们找到入口点文件之后,就可以分析grub的源码了 
grub_main 是grub执行的main函数,绝大多数grub的主要工作都是在这个函数中完成的
/* The main routine.  */
void __attribute__ ((noreturn))
grub_main (void)
{/* First of all, initialize the machine.  */grub_machine_init ();grub_boot_time ("After machine init.");/* This breaks flicker-free boot on EFI systems, so disable it there. */
#ifndef GRUB_MACHINE_EFI/* Hello.  */grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);grub_printf ("Welcome to GRUB!\n\n");grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
#endif...
}	
3.2 先来分析第一个函数:
初始化grub在本平台上要做的各种操作,这个函数与架构是强相关的,x86架构,arm架构,loongarch架构上
的实现都不一样
笔者就以国产loongarch架构为例进行讲解,该函数位于grub-core/kern/loongarch64/efi/init.c中
(loongson架构的位于./grub-core/kern/mips/loongson/init.c文件中) 
grub_machine_init 函数的主要工作:
a) 先获取grub要加载的各个模块的基地址 问题:grub要加载哪些模块呢?b) 初始化控制台
c) 堆区内存的映射及初始化(初始化内存管理系统、grub中有一套自己的内存管理方式)
d)  初始化frame buffer
e)初始化字体及终端
f)  ftdbus、网卡、系统定时器、串口等设备的初始化
void      
grub_machine_init (void)                                                              
{grub_efi_boot_services_t *b;grub_efi_init ();b = grub_efi_system_table->boot_services;b->create_event (GRUB_EFI_EVT_TIMER | GRUB_EFI_EVT_NOTIFY_SIGNAL,                   GRUB_EFI_TPL_CALLBACK, grub_loongson_increment_timer, NULL, &tmr_evt);     b->set_timer (tmr_evt, GRUB_EFI_TIMER_PERIODIC, EFI_TIMER_PERIOD_MILLISECONDS(10)); grub_install_get_time_ms (grub_efi_get_time_ms);                                    
}
3.2.1 grub_efi_init 
我们先简单的分析一下这个函数(位于grub-core/kern/loongarch64/efi/init.c中):
void
grub_machine_init (void)
{grub_efi_boot_services_t *b; grub_efi_init (); b = grub_efi_system_table->boot_services;b->create_event (GRUB_EFI_EVT_TIMER | GRUB_EFI_EVT_NOTIFY_SIGNAL,GRUB_EFI_TPL_CALLBACK, grub_loongson_increment_timer, NULL, &tmr_evt);b->set_timer (tmr_evt, GRUB_EFI_TIMER_PERIODIC, EFI_TIMER_PERIOD_MILLISECONDS(10));grub_install_get_time_ms (grub_efi_get_time_ms);
}__attribute__ ((__optimize__ ("-fno-stack-protector"))) void
grub_efi_init (void)
{grub_modbase = grub_efi_section_addr ("mods");/* First of all, initialize the console so that GRUB can displaymessages.  */grub_console_init (); stack_protector_init (); /* Initialize the memory management system.  */grub_efi_mm_init (); /*  * Lockdown the GRUB and register the shim_lock verifier* if the UEFI Secure Boot is enabled.*/if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED){   grub_lockdown (); grub_shim_lock_verifier_setup (); }   grub_efi_system_table->boot_services->set_watchdog_timer (0, 0, 0, NULL);grub_efidisk_init (); grub_efi_register_debug_commands (); 
}
别的先不说,我们先来看看grub的内存是怎么管理的:
void
grub_efi_mm_init (void)
{/*#ifdef GRUB_CPU_LOONGARCH64#define DEFAULT_HEAP_SIZE   0x10000000 #else#define DEFAULT_HEAP_SIZE   0x2000000#endif*///如果是loongarch架构,grub会在堆区分配256M的内存空间if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE, GRUB_MM_ADD_REGION_NONE) != GRUB_ERR_NONE)grub_fatal ("%s", grub_errmsg);grub_mm_add_region_fn = grub_efi_mm_add_regions;
}static grub_err_t
grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
{grub_efi_memory_descriptor_t *memory_map;grub_efi_memory_descriptor_t *memory_map_end;grub_efi_memory_descriptor_t *filtered_memory_map;grub_efi_memory_descriptor_t *filtered_memory_map_end;grub_efi_uintn_t map_size;grub_efi_uintn_t desc_size;grub_err_t err;int mm_status;/* Prepare a memory region to store two memory maps.  *//*#define MEMORY_MAP_SIZE 0x3000 void *grub_efi_allocate_any_pages (grub_efi_uintn_t pages){#ifdef GRUB_CPU_LOONGARCH64return grub_efi_allocate_pages_real (grub_efi_max_usable_address(),pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS,GRUB_EFI_LOADER_DATA);#elsereturn grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS,pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS,GRUB_EFI_LOADER_DATA);#endif}//可以看出来loongarch架构grub的最高的可用地址是从csr寄存器中读出来的//而其他架构grub可用的最高地址是0xffffffffstatic inline grub_uint64_t grub_efi_max_usable_address(void){                      grub_uint64_t addr;  asm volatile ("csrrd %0, 0x181" : "=r" (addr));return addr |= 0xffffffffffUL;}所以下面的这个函数,是grub先申请6页的内存保存memory map*/memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));if (! memory_map)return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map");/* Obtain descriptors for available memory.  */map_size = MEMORY_MAP_SIZE;//获取EFI规范中定义的内存映射。如果成功返回1,如果部分返回0,或者如果发生错误返回-1。mm_status = grub_efi_get_memory_map (&map_size, memory_map, 0, &desc_size, 0);if (mm_status == 0){grub_efi_free_pages((grub_efi_physical_address_t) ((grub_addr_t) memory_map),2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));/* Freeing/allocating operations may increase memory map size.  */map_size += desc_size * 32;memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size));if (! memory_map)return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map");mm_status = grub_efi_get_memory_map (&map_size, memory_map, 0,&desc_size, 0);}if (mm_status < 0)return grub_error (GRUB_ERR_OUT_OF_MEMORY, "error fetching memory map from EFI");memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size);filtered_memory_map = memory_map_end;filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,desc_size, memory_map_end);/* Sort the filtered descriptors, so that GRUB can allocate pagesfrom smaller regions.  */sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end);/* Allocate memory regions for GRUB's memory management.  */err = add_memory_regions (filtered_memory_map, desc_size,filtered_memory_map_end,BYTES_TO_PAGES (required_bytes),flags);if (err != GRUB_ERR_NONE)return err;#if 0/* For debug. 该打印可以将grub分配的内存信息打印出来*/map_size = MEMORY_MAP_SIZE;if (grub_efi_get_memory_map (&map_size, memory_map, 0, &desc_size, 0) < 0)grub_fatal ("cannot get memory map");grub_printf ("printing memory map\n");print_memory_map (memory_map, desc_size,NEXT_MEMORY_DESCRIPTOR (memory_map, map_size));grub_fatal ("Debug. ");
#endif/* Release the memory maps.  */grub_efi_free_pages ((grub_addr_t) memory_map,2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));return GRUB_ERR_NONE;
}
...
--------------------------------------------------------
--------------------------------------------------------
...
//接下来我们重点分析一下grub加载vmliux和initrd的逻辑:
vi  grub-core/loader/loongarch64/linux-elf.c 
struct grub_relocator_chunk
{struct grub_relocator_chunk *next;grub_phys_addr_t src;void *srcv;grub_phys_addr_t target;grub_size_t size;struct grub_relocator_subchunk *subchunks;unsigned nsubchunks;
};
typedef const struct grub_relocator_chunk *grub_relocator_chunk_t; grub_err_t
grub_relocator_alloc_chunk_align (struct grub_relocator *rel,grub_relocator_chunk_t *out,grub_phys_addr_t min_addr,grub_phys_addr_t max_addr,grub_size_t size, grub_size_t align,int preference,int avoid_efi_boot_services);//想要申请size个字节的空间,按照align进行对齐,错误信息回填到err中
void*
grub_linux_loongarch_alloc_virtual_mem_align (grub_size_t size,grub_size_t align,grub_err_t *err)
{grub_relocator_chunk_t ch;*err = grub_relocator_alloc_chunk_align (relocator, &ch,0, (0xffffffff - size) + 1,size, align,//从低地址向高地址进行申请GRUB_RELOCATOR_PREFERENCE_LOW, 0);return get_virtual_current_address (ch);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/49999.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

04 ES6中对象的简写

在 ES6 中&#xff0c;对象字面量的书写方式进行了一些简化&#xff0c;使得对象的创建更加简洁。以下是 ES6 中对象简写的几种形式&#xff1a; 属性值缩写&#xff1a; 当对象的属性名和属性值的变量名相同时&#xff0c;可以省略属性值&#xff0c;只写属性名。 // ES5 cons…

如何在Linux上安装配置RabbitMQ消息队列

RabbitMQ是一种开源的消息中间件&#xff0c;基于AMQP协议实现。它可以在分布式系统中传递消息&#xff0c;并提供了可靠的消息传递机制。RabbitMQ使用一种称为"消息队列"的方式来管理消息的发送和接收。它的主要特性包括&#xff1a; 可靠性&#xff1a;RabbitMQ使用…

Zabbix监控案例

文章目录 一、监控linux TCP连接状态TCP端口的十一种连接状态自定义监控项监控示例二、监控模板监控tcp连接监控nginx 一、监控linux TCP连接状态 TCP&#xff0c;全称Transfer Control Protocol&#xff0c;中文名为传输控制协议&#xff0c;它工作在OSI的传输层&#xff0c;…

3.Fabric系统架构、网络拓扑图、交易流程

Hyperledger Fabric系统架构 Fabric网络拓扑图 Fabric交易流程 多通道

面试官视角:Java高级面试中的考察与评判

1. 面试前的准备 1.1 明确岗位需求 在面试前&#xff0c;面试官需要对岗位需求有清晰的认识&#xff0c;明确需要考察的技术点和能力。 1.2 设计面试问题 设计针对性强、覆盖面广的面试问题&#xff0c;确保能够全面考察面试者的能力。 2. 考察技术能力 2.1 基础知识 考…

【数字范围按位与】python刷题记录

run到位运算。 顿悟&#xff1a; 只看第一个二进制位&#xff0c;只存在0,1两种情况&#xff0c;所以如果left<right&#xff0c;区间中必然存在left1,那么最低位&一下一定等于0了&#xff0c;然后不停的右移&#xff0c;一直移到两个相等为止&#xff0c;就这么简单 …

Qt自定义下拉列表-可为选项设置标题、可禁用选项

在Qt中,ComboBox&#xff08;组合框&#xff09;是一种常用的用户界面控件,它提供了一个下拉列表,允许用户从预定义的选项中选择一个。在项目开发中&#xff0c;如果简单的QComboBox无法满足需求&#xff0c;可以通过自定义QComboBox来实现更复杂的功能。本文介绍一个自定义的下…

二级医院LIS系统源码,医学检验系统,支持DB2,Oracle,MS SQLServer等主流数据库

系统概述&#xff1a; LIS系统即实验室信息管理系统。LIS系统能实现临床检验信息化&#xff0c;检验科信息管理自动化。其主要功能是将检验科的实验仪器传出的检验数据经数据分析后&#xff0c;自动生成打印报告&#xff0c;通过网络存储在数据库中&#xff0c;使医生能够通过医…

7.消息应答

消费者完成一个任务可能需要一段时间&#xff0c;如果其中一个消费者处理一个长时间的任务并且只完成了部分突然就挂掉了&#xff0c;会发生什么情况&#xff1f; RabbitMQ一旦向消费者传递了一条消息&#xff0c;便立即将该消息标记为删除。这种情况下&#xff0c;突然有个消…

代码随想录算法训练营day6 | 242.有效的字母异位词、349. 两个数组的交集、202. 快乐数、1.两数之和

文章目录 哈希表键值 哈希函数哈希冲突拉链法线性探测法 常见的三种哈希结构集合映射C实现std::unordered_setstd::map 小结242.有效的字母异位词思路复习 349. 两个数组的交集使用数组实现哈希表的情况思路使用set实现哈希表的情况 202. 快乐数思路 1.两数之和思路 总结 今天是…

C++版OpenCV_03_图像增强

图像增强 3.1 直方图3.2 线性变换3.3 直方图归一化3.4 Gamma变换 3.1 直方图 概念&#xff1a;计算图像单个通道像素的分布。 步骤&#xff1a;把图像灰度级分为n个区间&#xff0c;计算每个区间像素的频数&#xff0c;把频数转化为频率&#xff0c;得到图像的直方图。如果图像…

OpenCV 遍历Mat,像素操作,使用TrackBar 调整图像的亮度和对比度 C++实现

文章目录 1.使用C遍历Mat,完成颜色反转1.1 常规遍历方式1.2 迭代器遍历方式1.3指针访问方式遍历&#xff08;最快&#xff09;1.4不同遍历方式的时间对比 2.图像像素操作&#xff0c;提高图像的亮度3.TrackBar 进度条操作3.1使用TrackBar 调整图像的亮度3.2使用TrackBar 调整图…

Windows波形音频MMEAPI简介

Windows波形音频MMEAPI简介 使用MMEAPI时需要导入头文件&#xff1a;#include<mmeapi.h> mmeapi.h文件的主要内容 mmeapi.h 文件是 Windows 多媒体 API 的一部分&#xff0c;主要用于处理波形音频&#xff08;Waveform Audio&#xff09;的输入和输出。以下是该文件的…

GNU/Linux - Bazaar版本管理工具

GNU Bazaar&#xff08;以前称为Bazaar-NG&#xff0c;命令行中称为bzr&#xff09;是由Canonical赞助开发的分布式和主从式版本控制系统。并用来进行Ubuntu项目的版本控制。 Bazaar 可以由一个开发本地内容的多个分支的开发人员使用&#xff0c;也可以由跨网络协作的团队使用。…

学术研讨 | 区块链网络体系结构研讨会顺利召开

添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 近日&#xff0c;国家区块链技术创新中心组织了“区块链网络体系结构研讨会”&#xff0c;会议面向跨域交互多、计算规模大、数据管理复杂、性能与扩展性要求高等特征的区块链网络的体系结构展开交流研讨&…

docker相关内容学习

一、docker的四部分 二、镜像相关命令 三、容器相关命令

视频生成【文章汇总】SVD, Sora, Latte, VideoCrafter12, DiT...

视频生成【文章汇总】SVD, Sora, Latte, VideoCrafter12, DiT... 数据集指标 【arXiv 2024】MiraData: A Large-Scale Video Dataset with Long Durations and Structured Captions【CVPR 2024】VBench : Comprehensive Benchmark Suite for Video Generative Models【arxiv 20…

学习记录——day15 数据结构 链表

链表的引入 顺序表的优缺点 1、优点:能够直接通过下标进行定位元素&#xff0c;访问效率高&#xff0c;对元素进行查找和修改比较快 2、不足:插入和删除元素需要移动大量的元素&#xff0c;效率较低 3、缺点:存储数据元素有上限&#xff0c;当达到MAX后&#xff0c;就不能再…

[python]数字与字符串

目录 Python 数字类型转换 Python 数字运算 Python字符串操作 修改 查询 Python 数字数据类型用于存储数值。 数据类型是不允许改变的&#xff0c;这就意味着如果改变数字数据类型的值&#xff0c;将重新分配内存空间。 Python 支持三种不同的数值类型&#xff1a; 整型…

javafx的ListView代入项目的使用

目录 1. 创建一个可观察的列表&#xff0c;用于存储ListView中的数据,这里的User是包装了用户的相关信息。 2.通过本人id获取friendid&#xff0c;及好友的id&#xff0c;然后用集合接送&#xff0c;更方便直观一点。 3.用for遍历集合&#xff0c;逐个添加。 4.渲染器&…