无忧启动论坛
标题:
malloc 和 free 的问题,应该抽时间进行完善
[打印本页]
作者:
不点
时间:
2015-6-26 09:08
标题:
malloc 和 free 的问题,应该抽时间进行完善
这个我以前也提到过,我现在也没有时间去研究代码,不知道这个工作有没有进展。如果没做的话,我觉得 chenall 或 yaya 在空闲时可以做一做。
首先我需要把意思说清楚。
malloc 是内存分配函数。可是,grub4dos 是由内核和用户程序两个部分构成的。grub4dos 内核里面所建立的内存分配链表(其实是数组),是用来给应用程序使用的,不是让内核使用的。内核应该严格使用 32M 以内的空间,不可以以任何方式使用到其他内存空间。目前这个问题之所以不太严重,是因为我们的用户进程设计还不完善(而且太简单),还没有出现内核与用户进程内存使用发生冲突的情况。
为了展示其严重性,我试试继续加以解释。
我们知道,DOS 在给 .com 程序分配内存时,是将全部可用内存都分配给了这个 .com 进程。而我当初为 grub4dos 设计进程管理的时候,就是以 dos 的 .com 程序的逻辑框架为参考模型的。
好的,假如我们在 grub4dos 执行某个 32 位程序的时候,分配该程序全部的内存,那么,此时如果这个程序要调用内核的某个功能,而假如碰巧此时的内核又要用 malloc 来分配内存,则此时已经没有内存了,因为内存全部分配给用户的 32 位程序了。因此,此时的功能调用会失败。
所以,内核使用的 malloc 函数应该与用户使用的 malloc 函数隔离开来。内核可以有 kmalloc、kfree 之类的函数,而且它们只能触碰 32M 以内的专门保留给内核所使用的内存,而不可以超限使用内存。
可以参考一下 Linux 的 kernel,它的内核就使用了 kmalloc 之类的函数,与用户进程的 malloc 函数完全隔离。
作者:
2011yaya2007777
时间:
2015-7-10 12:50
本帖最后由 2011yaya2007777 于 2015-7-10 13:02 编辑
这个问题不是太懂。我看到有 grub_malloc,grub_free 函数。这个函数是供内核使用的,还是供用户使用的?
只是登记一下使用内存的位置及尺寸,以便供后续使用者查询?还是直接分配合适的内存?
这还有个是否遵守协定的问题。不使用函数,直接分配和使用内存,也没有办法。
我觉得对于32M内核使用内存,开发者应当在 shared.h 予以登记,至少在 .h 文件登记。
不要在代码中使用 (unsigned char *)0x1000000 这样直接赋值。没有多少人有时间在浩瀚的代码中寻找内存使用位置。
我查询到的内存分布,肯定还有遗漏。
名称 中文 位置 长度 定义
BOOT_PART_TABLE 引导分区表 0x07be 0x200 shared.h
MB_CMDLINE_BUF 多重引导命令行缓冲区地址 0x7000 0x1000 shared.h
BOOTSEC_LOCATION BOOTSEC位置 0x7C00 shared.h
mbr 主文件分配表 0x8000 0x200 disk_io.c
terminfo 0x8000 0x200 builtins.c
LINUX_HEAP_END_OFFSET LINUX堆结束偏移 0x9000 - 0x200 shared.h
LINUX_ZIMAGE_ADDR LINUX Z映像地址 0x10000 shared.h
SCRATCHADDR SCRATCH地址 0x1F000 0x200 shared.h
SCRATCHADDR 0x1F000 builtins.c
GEOMTUNE_SEG 0x20000 0x10000 ams.s geometry_tune
读缓存 0x2F000 0x200 bios.c
读缓存 0x2F000 0x800 builtins.c
GEOMTUNE_BUFFERSEG 0x30000 0x8000 ams.s geometry_tune
BUFFERADDR 缓冲区地址 0x30000 0x10000 shared.h
PXE_BUF PXE缓存地址 0x30000 0xFE00 fsys_pxe.c
ADDR_RET_STR 地址返回字符串 0x4CA00 shared.h
CMD_RUN_ON_EXIT 命令运行在退出 0x4CB08 shared.h
LINUX_OLD_REAL_MODE_ADDR LINUX旧实模式地址 0x90000 shared.h
VIDEOMEM 图形视频内存 0xA0000
HERCULES_VIDEO_ADDR RAW_ADDR hercules视频地址 0xB0000 hercules,h
LINUX_BZIMAGE_ADDR LINUX BZ映像地址 0x100000 shared.h
buf_addr 存放UNIFONT字符 0x100000 0x10000 builtins.c
FB_MENU_ADDR FB菜单地址 0x150000 0x10000 fsys_fb.c
读缓存 0x200000 builtins.c
读缓存 0x2A0000 builtins.c
HMA_ADDR 0x2B0000 builtins.c
HMA_ADDR 高端内存区地址 0x2B0000 shared.h
第二块固定变量区 0x307000~0x308200 0x1200
use_preset_menu 使用预值菜单地址 0x307FF8 shared.h
preset_menu 预设菜单 0x307FFC stage2
cpu 的信息 0x308000 0x20
JPG_FILE jpg文件缓存 0x3A0000 0x8000 graphics.h
MENU_TITLE 菜单总标题缓存 0x3A8000 0x800 shared,h
#define VSHADOW VSHADOW1
/* 8x16 点阵字符,总字符 = 80*30. 平面尺寸 = 80*30*16 = 38400字节 */
/* 8x16 点阵字符,总字符 = 100*37. 平面尺寸= 800*600/8 = 60000字节 */
VSHADOW1 0x3A0000 0xea60 graphics.c
VSHADOW2 0x3AEA60 0xea60 graphics.c
VSHADOW4 0x3BD4C0 0xea60 graphics.c
VSHADOW8 0x3CBF20 0xea60 graphics.c //end at 0x3DA980
text 0x3FC000 100*37*4 = 0x39D0 graphics.c
FSYS_BUF RAW_ADDR 文件系统缓存地址 0x3E0000 0x8000 shared.h
PART_TABLE_BUF 分区表缓存地址 0x3E8000 0x1000 shared.h
PART_TABLE_TMPBUF 分区表临时缓存地址 0x3E9000 0x200 shared.h
CMDLINE_BUF 命令行缓存地址 0x3E9200 0x640 shared.h
COMPLETION_BUF 完成缓冲区地址 0x3E9840 0x640 shared.h
UNIQUE_BUF UNI字符串缓冲区地址 0x3E9E80 0x640 shared.h
HISTORY_BUF 命令行历史缓冲区地址 0x3EA4C0 0x320 shared.h
font8x16 0x580000 0x1000 builtins.c
mem_alloc_array_start 0x800000 ams.s
mem_alloc_array_end 0xA00000 ams.s
page_map_start 0xA00000 ams.s
page_map_end 0xE00000 ams.s
PAGING_TABLES_BUF 分页表缓冲区 0xEFC000 0x4000 shared.h
PAGING_TABLES_BUF 分页表缓存 0xEFC000 0x4000 shared.h
IMAGE_BUFFER vbe图像缓存 0x1000000 0xa8c000 graphics.h (1920*1440*4)
UNIFONT_START UNI字体开始 0x1800000
SYSTEM_RESERVED_MEMORY 系统保留的内存 0x2000000
GRUB_MOD_ADDR 0x2000000-100000 builtins.c
cmd_buffer 命令缓存 0x2000000-0x10000 cmdline.c
PRINTF_BUFFER 打印缓存 0x2000000+0x20000 cmdline.c
LINUX_INITRD_MAX_ADDRESSLINUX 初始化RAM磁盘最大地址 0x38000000 shared.h
graphics.c 使用 0x3A0000 - 0x3DA980 和 0x3FC000 - 0x3FF9D0 切换到实模式扩展chainloader代码地址
VM_RFC1048 0x63825363L pxe.h
linalloc_topaddr 窗口的大小 ((saved_mem_upper << 10) + 0x100000) 0x8000UL gunzip.c
fsys_pxe.c
#define PXE_MIN_BLKSIZE 128
#define PXE_MAX_BLKSIZE 16384
#define DOT_SIZE 1048576
#define CMP_BUF_SIZE 0x8000ULL
addr1 = (char *) RAW_ADDR (0x100000);
addr2 = addr1 + CMP_BUF_SIZE;
作者:
不点
时间:
2015-7-10 16:57
当初这个不良的状况,可以说是我造成的,也可以说不是我,而是原始的 GNU GRUB 开发者造成的。他们并未写一个内存分配函数,而是直接使用内存。而且那时的情况很糟糕,统统只使用 1M 以内的常规内存,所以那时的程序无法增加功能;稍微改动一点,就容易死机崩溃。
chenall 写了一个 malloc 函数,不过,在我看来,应该把这个函数劈成两个,一个是内核使用的 kmalloc,另一个是用户使用的 malloc。内核所使用的 malloc,只能严格使用 32M 以内的可用空闲空间,用过之后应该用 kfree 函数来释放内存。比如说,可以让 kmalloc 只使用从 28M 至 32M 之间的 4M 内存。只要在 32M 以内找一块比较大的空闲内存可供 kmalloc 使用便可。
而用户使用的内存,倒是可以像目前这样,用 mem alloc array 来圈定。所以,需要做的工作其实是增加一个 kmalloc 函数,而保持现在的 malloc 函数不动。增加 kmalloc 函数之后,内核中所有对 malloc 的调用,都应该改为对 kmalloc 的调用。同时,用户的程序不可以使用 kmalloc 函数,而只能使用 malloc 函数。也就是说,不给用户提供 kmalloc 函数的接口,让用户根本就无法使用它。
我好像已经提到了,这个问题并不迫切,可以在自己确实愿意做的时候再做。
再提醒注意一点:位于 15M 至 16M 之间的内存,是 grub4dos 不使用的内存。原因是,这个 1M 空间被某些主板芯片使用,如果我们也使用它,就会与主板 BIOS 发生冲突。所以,迫使我们放弃使用这 1M 内存。在这样的机器上,其主板的 int15/E820/E801 应该会报告这个空间不是用户可用的自由空间,而是被主板保留的空间(甚至也有可能是不可写的 ROM)。
作者:
chenall
时间:
2015-7-10 17:11
我也觉得目前GRUB4DOS的内存使用情况确实是有一些乱。
要整理的话需要有足够的时间,而且我对这些不是很熟悉,不清楚哪一些不能改。
yaya可以尝试整理一下,也方便后来的开发者。我觉得除非有必要否则能够使用自动分配的内存就尽量使用自动分配,可以避免内存冲突。
作者:
不点
时间:
2015-7-10 17:30
另外,你上面列出的那些内存,好像存在冲突的情况。比如说,
#define CMP_BUF_SIZE 0x8000ULL
addr1 = (char *) RAW_ADDR (0x100000);
addr2 = addr1 + CMP_BUF_SIZE;
老天爷,1M 处的 64K 内存已经被 dd 命令使用了。不过 dd 也仅仅是把这块内存作为缓冲区使用。所以,好像并未真正产生冲突。如果你将来写出个 kmalloc 函数,那就可以让 dd 和 cmp 命令都使用 kmalloc 来分配内存,而不是使用固定的内存地址。
那些 VSHADOW 内存,是支持 VGA 图形模式的内存。目前其实 VGA 还被 grub4dos 内核支持,只是不建议使用罢了(而是建议用户使用 VBE 图形模式)。所以,这些 VSHADOW 内存,还得保留着,它们占用的空间也不算是太大。
虽然 VGA 代码基本不使用了,但是也尽量不要删除掉。因为 grub.exe 和 DOS 互通的时候,从 grub4dos 返回到 DOS,需要经过 VGA 的图形模式转换,才能正常进入中文 DOS 环境。否则进入 DOS 后出现屏幕无反应的假死现象。这是因为,当 grub4dos 运行于 VBE 模式,如果此时直接切换到 DOS,则 DOS 的图形模式不对(中文 DOS 基本上都是 VGA 图形模式),调用 VGA BIOS 清屏也没用。必须在进入 DOS 前利用 graphicsmode 0x12 进行中转,才能保证一切正常。 利用模式 0x12 中转,可以适应中英文两种 DOS 环境,非常好,非常可靠。这个工作我在当时就已经做好了,将来如果有需要的时候,只需打上补丁即可(补丁就在论坛上那个相关的帖子里面)。
欢迎光临 无忧启动论坛 (http://wuyou.net/)
Powered by Discuz! X3.3