无忧启动论坛

 找回密码
 注册
搜索
系统gho:最纯净好用系统下载站广告联系 微信:wuyouceo QQ:184822951
查看: 11779|回复: 54
打印 上一主题 下一主题

[求助] 批处理引导linux内核出错

  [复制链接]
1#
发表于 2017-4-7 22:34:59 | 显示全部楼层
2011yaya2007777 发表于 2017-4-7 22:17
cpu是64位的,操作系统是33位的。不知道是不是仿真器QEMU不支持。

现在哪还有 32 位的 CPU?肯定都是 64 位的了。

我试过,在 32 位的 XP 之下,qemu 可以支持 64 位的 Guest 操作系统。

你需要运行 qemu-system-x86_64 而不是 qemu-system-i386。

点评

说起来奔腾四就有64位的支持了吧 再早些才只有纯32位吧  详情 回复 发表于 2017-4-8 11:19
回复

使用道具 举报

2#
发表于 2017-4-10 11:40:56 | 显示全部楼层
我来说说这个问题。启动 Linux,很可能与批处理互相冲突。

尽量避免这样使用。

我不知道能不能避免在批处理里面启动 Linux,如果能避免的话,就不用折腾了。

就是说,批处理功能与 Linux 的启动,两者存在冲突。

初步想了一下,你可以用一个菜单去启动 Linux,大概用 configfile 命令即可做到吧,我想。

回复

使用道具 举报

3#
发表于 2017-4-10 13:41:37 | 显示全部楼层
yaya 可以考虑优化批处理,也优化 malloc 等函数。主要就是内存冲突引起的。

kernel 固定加载在 32M 处,而此处的内存,却被批处理以及 grub4dos 的外部命令占据。

所以,kernel 执行以后,就不可以再执行任何外部命令以及批处理了,否则,一定是破坏了已经加载的 kernel 代码和数据。

续尾本来就不是一个正儿八经的办法,又碰上 kernel 和 initrd 这个庞然大物,就出问题了。

我不主张对 grub4dos 进行大修。能节约点精力,尽量节约,少做这些不怎么重要的工作。

BIOS 被淘汰之后,这些工作就全部失去意义了。努力是不值得的。



回复

使用道具 举报

4#
发表于 2017-4-10 17:50:11 | 显示全部楼层
2011yaya2007777 发表于 2017-4-10 14:33
请教不点,page_map_start 在 10M 处,原计划是用来作什么的?

grub4dos 要支持访问 4G 以上的内存空间。然而,4G 以上内存空间的访问,需要页映射,而不是像 4G 以内那样,仅仅通过 cpu 指令、地址前缀 0x66,0x67 即可实现。

既然需要页映射,就得有页面空间。这个页面空间所起的作用很简单,不过就是恒等映射而已。page_map_start 开始的几个 M 的空间,就是用于页映射。

然而,我写的 mem64 汇编语言函数,竟然是无效的。我印象当初是测试有效的,怎会后来无效了呢?我至今很疑惑。我也离开开发队伍了,也不感兴趣了,同时也确实没什么精力和能力了,所以,也就不能去排除 bug 了。

既然我写的 mem64 函数无效,那么 page_map_start 开始的那个页空间,也就可能是没用的。karyonix 写了新的函数来处理高于 4G 的内存访问。我不知道 karyonix 是否采用了 page_map_start 开始的页面空间。假如 karyonix 不使用这个页面空间的话,那么这个空间是可以挪作它用的。

最好不要挪作他用。karyonix 的内存处理是用 PAE,我的 mem64 汇编代码是用 64 位指令,两种方法是不一样的。64 位指令的效率应该更高一些。当 PAE 失效时,会尝试采用 mem64,因此,mem64 也是有用的。这个 mem64 目前是有 bug 的,是失效的。但假如将来有人捉住了 mem64 的 bug,那时,还是需要 page_map_start 这个页面空间的。

回复

使用道具 举报

5#
发表于 2017-4-10 18:15:51 | 显示全部楼层

再补充一点。karyonix 的内存函数,我不太清楚究竟能够处理多大内存。我猜有可能是 64G 内存。我的 mem64 函数(如果排除了 bug 的话),可以处理 512G 内存。而且,假如扩大页映射的空间,还可以支持更大内存。因此,如果 grub4dos 还要继续开发下去的话,那就应该找出 bug,让 mem64 真正发挥作用。

回复

使用道具 举报

6#
发表于 2017-4-11 08:50:19 | 显示全部楼层
2011yaya2007777 发表于 2017-4-11 08:16
可惜没有64位环境。不然的话,可以试一试问题定位。

没关系,4G 以内照样可以试验。

mem64 即使是访问 4G 以内的空间,都失败了。连访问 1M 以内的常规内存都失败了。我怀疑是某个补丁造成的。问题出得很早,现在很难知道具体是什么原因。只要能访问常规内存,就成功了。

回复

使用道具 举报

7#
发表于 2017-4-21 12:30:16 | 显示全部楼层
2011yaya2007777 发表于 2017-4-21 08:55
现在可以使用了。4Gb以下内存我测试可以移动及填充。4Gb以上内存我没有测试环境,不知如何。请有条件的网 ...

超级强悍!此问题终于被你俘虏!我没测试环境,但应该是解决了。以下是我的分析、思考。

mem64 函数的开头,是这样的:
  1.         .code32

  2.         pushl        %ebp
  3.         movl        %esp, %ebp

  4.         #; +28        len
  5.         #; +20        src
  6.         #; +12        dest
  7.         #;  +8        func
  8.         #;  +4        EIP
  9.         #; ebp        EBP
  10.         #;  -4        ESI
  11.         #;  -8        EDI
  12.         #; -12        EBX

  13.         pushl        %esi
  14.         pushl        %edi
  15.         pushl        %ebx
复制代码


可以看到,在 ebp 被赋值以后,又执行了三条 push 指令,这就隐含地改变了 esp 的值!这是关键。我的失误就在此处——没能意识到 esp 已经改变了。

再看这个片段:

  1.         ljmp        $32, $ABS(1f)                # ljmp to enter 64-bit mode

  2.         .code64
  3. 1:

  4.         /* 28(%ebp) = len */
  5.         /* 20(%ebp) = src */
  6.         /* 12(%ebp) = dest */
  7.         /*  8(%ebp) = func */

  8.         movl        %esp, %ebp                # clear upper 32-bit of %rbp
复制代码


ljmp 属于跳转指令,而跳转指令是不可能改变 esp 的值的。正是前面的三条 push 指令,改变了 esp 的值。此时,我把错误的 esp 赋值给 ebp,是问题的症结。佩服 yaya 的调试功底,抓住了它。一般来说,调试别人的代码,那是困难的。yaya 功力不凡。

此处,rbp 的高 32 位,是应该被清除的。由于我已经脱离了 intel x86 体系,不再学习,所以,我现在不清楚 x86 的指令细节。确切地说,我不知道 addl $0, %ebp 能否清除 rbp 的高 32 位。

也可以试试 movl %ebp, %ebp,看看它能否清除 rbp 的高 32 位。应该查阅相关资料(查阅 intel 和 amd 的资料),了解这些细节。

程序运行需要万无一失。因此,该清除高32位的时候,就必须清除,不能让它有偶然出错的可能性。


回复

使用道具 举报

8#
发表于 2017-4-21 16:54:01 | 显示全部楼层
本帖最后由 不点 于 2017-4-21 17:32 编辑
2011yaya2007777 发表于 2017-4-21 12:38
ljmp        $32, $ABS(1f)
其中 $32 是什么意思?是段因子?


看这段 “全局描述符表” 的定义:
  1. MyGDT:
  2. //gdt:
  3. /* 0*/        .word        0        /* NULL entry. Can be used at will. */
  4. gdtdesc:                /* 6 bytes used for gdt descriptor. */
  5.         .word        MyGDTEnd - MyGDT - 1        /* GDT limit */
  6.         /* The gdt linear base address will be adjusted by set_int13_handler,
  7.          * but not touched outside int13_handler. */
  8.         .long        ABS(MyGDT)                /* GDT linear address */

  9. /* 8*/        PM_DS16 = (. - MyGDT)        /* adjusted base = int13_handler */
  10.         .long        0x0000FFFF, 0x00009300        /* 16-bit data 64K limit */
  11. /*16*/        PM_DS32 = (. - MyGDT)
  12.         .long        0x0000FFFF, 0x00CF9300        /* 32-bit data 4GB limit */

  13.         /* The 16-bit code segment base will be adjusted by set_int13_handler,
  14.          * but not touched outside int13_handler. */
  15. /*24*/        PM_CS16 = (. - MyGDT)        /* adjusted base = int13_handler */
  16.         .long        0x0000FFFF, 0x00009B00        /* 16-bit code 64K limit */
  17. /*32*/        LM_CS64 = (. - MyGDT)
  18.         .long        0x0000FFFF, 0x00AF9B00        /* 64-bit code 4GB limit */

  19.         /* This gdt entry is not used by int13_handler, but used outside. */
  20. /*40*/        PM_CS32 = (. - MyGDT)
  21.         .long        0x0000FFFF, 0x00CF9B00        /* 32-bit code 4GB limit */
  22. MyGDTEnd:
复制代码


其中的 /*32*/ 处有 LM_CS64 = (. - MyGDT),就是关于 64 位 long_mode 的代码段的描述。此处的 32,就是“段选择器”(segment selector),它就是 CS、DS、ES、SS、FS、或 GS 之类的段寄存器可以取的值。或者说,此处 32 就是“段值”,不过,保护模式的段值,其含义不同于实模式下的段值。

当 ljmp  $32, $ABS(1f) 这条指令执行的时候,CPU 仍旧处于 32 位保护模式。它执行的结果,就是实实在在地切换到 64 位 long mode(长模式)。那么接下来就是 64 位的段了,不能是 32 位了,因此用 .code64 来通知编译器,接下来的汇编语言代码需要按照 64 位的指令格式来编译。

我猜,如果你将 $32 改成 $LM_CS64,可能也行(如果真行的话,那肯定更好,因为可读性更高了)。这些 PM_DS16, PM_CS16, PM_DS32,PM_CS32,LM_CS64 之类的定义,好像都是 karyonix 做的,我之所以没有采用,那是因为我的代码先写好了,karyonix 后来才增加的这几个定义(我先写的 64 位函数,karyonix 后来添加的 PAE 功能)。我对汇编语法并不熟悉,而 karyonix 比较专业。

再看结尾的片段:

  1.         /* XXX: Is this actually needed? */
  2.         ljmp        $40, $ABS(1f)                # ljmp to enter 32-bit protected mode
  3. 1:
  4.         xchgl        %eax, %ebx                # EAX=return value
  5.         popl        %ebx
  6.         popl        %edi
  7.         popl        %esi
  8.         popl        %ebp

  9.         ret
复制代码


这个 $40 不就是 $PM_CS32 嘛(见前面关于 PM_CS32 的定义),即 32 位保护模式代码段。那就是,实实在在地进入常规的 32 位模式。

不知道这是谁注释的:/* XXX: Is this actually needed? */ 有可能是我注释的,也有可能是 karyonix 注释的,也有可能是别的开发者注释的。反正我没什么记性了。

究竟需要不需要这个跳转,我也不能肯定。你也可以试试去掉(或者注释掉)这条 ljmp $40, $ABS(1f),看看有没有什么异常现象发生?

多执行这条指令,肯定是更安全一点(没什么坏处),但会浪费 CPU 执行这么一条指令的时间。       

如果确实能够证明去掉这条指令也行的话,那还是去掉了更好,毕竟少执行一条指令、少让 cpu 走弯路,那是更优化的。如果要证明的话,需要在 AMD 和 Intel 都验证通过,那才算是一个有效的证明。

回复

使用道具 举报

9#
发表于 2017-4-21 17:13:36 | 显示全部楼层
本帖最后由 不点 于 2017-4-21 17:19 编辑
2011yaya2007777 发表于 2017-4-21 15:13
现在只是 mem64 函数可以使用了。引导尾续在批处理后面的内核没有改进。

经测试,movl %ebp, %ebp 或者  ...


搞清楚了就好。其实,还得测试 AMD 和 Intel 两个厂家的 CPU 才行,而不能只测试其中一家。

grub4dos 迄今为止的代码,全都同时适用于 AMD 和 Intel。就连进入 64 位以后的操作,也都有意避免了那些有差异的部分,即,全都采用两个厂家同时都支持的 cpu 特性和指令,避免采用只有其中一家支持的 cpu 指令或特性。

另外,关于清除 rbp 的高 32 位,还可能有如下一些方法:

方法一:orl    %ebp, %ebp

方法二:andl   %ebp, %ebp

如果有时间、有兴趣,可以通过试验验证,来确定是否可行。

回复

使用道具 举报

10#
发表于 2017-4-24 00:27:53 | 显示全部楼层
2011yaya2007777 发表于 2017-4-22 11:19
movl %ebp, %ebp
在 AMD 和 Intel 两个厂家的 CPU 测试,证明可以清除 rep 的高32位.

好的,这就可以放心地使用 movl %ebp, %ebp 了。先前你证明了 add 指令也能够清除寄存器的高 32 位。而 or 和 and 指令,还没有证明过。如果以后有机会,最好都能证明一下,这样将来说不定啥时候就能用上了。甚至还可以试试 test %ebp, %ebp 指令的效果。
回复

使用道具 举报

11#
发表于 2017-4-24 01:01:43 | 显示全部楼层
求道者 发表于 2017-4-23 21:07
现在mem64可用的话 优先用mem64启动大于4G的内存吧
顺便usb --init这几天频繁发生这个检测到USB设备但是 ...

是的,yaya 居然把 mem64 救活了。这是我感觉很震动的一件事情,事先不敢有这样的奢望。我的代码我看过很多遍,一头雾水,找不到问题的根源在那里。当毛病找出来了之后,大家再看这毛病,似乎觉得很显然。但在找出毛病之前,那可不是个简单的事。看代码——理解代码——集中火力——进攻!我想,至少是要耗费不少体力的,需要把自己锻造成子弹头,才能进攻。cpu 模式转换的代码,我自己现在都看不懂了。幸亏 yaya 进入了团队!

在当时, karyonix 可能早就发现 mem64 不能用了。所以,karyonix 编写了 PAE 的代码。真的感谢 karyonix,要不是他,grub4dos 根本就无法读写 4G 之上的内存。

yaya 可以研究一下 karyonix 的代码,看看代码是否支持 512G 的内存。

(1)如果 karyonix 的代码支持 512G 甚至完全不限制内存大小,那就继续采用 karyonix 的代码。
(2)如果 karyonix 的代码所支持的内存不足 512G,那就调整为默认采用 mem64 的代码。
(3)如果可能的话,yaya 也可以考虑进一步改进 mem64,让 mem64 支持无限大的内存(即,不限制内存的大小)。

点评

不能吧 AMD64弄出来的时候不是2^48吗? PAE不是最大64G吗?(linux)  详情 回复 发表于 2017-4-24 12:34
回复

使用道具 举报

12#
发表于 2017-4-24 16:49:58 | 显示全部楼层
印象中,PAE 后来又有新的扩展,似乎 AMD 和 Intel 同时支持,可以处理 64 位内存,与 cpu 64 位模式的内存处理能力相同。

就是说,如果不考虑性能,则 PAE 与 64 位模式的处理能力相同。

64 位模式的字符串拷贝指令每次处理 8 个字节,比 PAE 的 4 字节要多一倍,因此速度会更快一点。

点评

e文维基上Win,linux,MAC 最大支持是64G物理内存…… 但是就算是DDR4 要插满64GB的内存也是有点虚吧(现在内存条贼J8贵) 有猛男试试现在grub4dos pae下最大支持多少内存吗?  详情 回复 发表于 2017-4-24 18:20
回复

使用道具 举报

13#
发表于 2017-4-24 18:47:53 | 显示全部楼层
2011yaya2007777 发表于 2017-4-24 18:27
orl %ebp, %ebp
andl %ebp, %ebp
在 AMD 和 Intel 两个厂家的 CPU 测试,证明可以清除 rep 的高32位.

扩展后的 PAE 支持很大的内存。你可以写个测试程序,看看 karyonix 的代码能否读写 64G 以上的内存。我估计没问题。另外,如果 karyonix 的代码能够处理 64G 以上的内存,(根据你提供的分页方面的信息)那就能够处理任意大的内存了。

如果普通用户不需要 1T 内存的话,目前的 mem64 也就够用了(可以处理 512G 内存)。特殊用户使用若干 T 的内存(估计是服务器虚拟主机的商家),那就让他自己修改 grub4dos 吧(假如他使用 grub4dos 的话;其实,这些商户没有一个是使用 grub4dos 的,至少我没发现;grub4dos 随着 BIOS 一起快要淘汰了,人家都不用)。

回复

使用道具 举报

14#
发表于 2017-4-24 19:45:06 | 显示全部楼层
2011yaya2007777 发表于 2017-4-24 19:42
可惜我的内存只有2Gb

不是你自己测试,你可以让网友测试。你只需要告诉测试步骤即可。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1 )

闽公网安备 35020302032614号

GMT+8, 2024-5-2 21:21

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表