通过串口的启动信息反推VBIOS的内容

需求:有一台没有PMON源码的龙芯3A5000 7A1000的机器,在不动任何软件的情况下获取到固件传递的VBIOS内容。

从串口打印中找到关键信息
vsp = 0x900000000f00f4c8 ssp = 0x900000000f00f568

一、源码分析

  1 initstack
  2 {
  3     ...
  4 1047     /* build environment vector on stack */
  5 1048     if (ec) {
  6 1049         printf("vsp = 08x%llx, ssp @ 08x%llx\n", (unsigned long long )vsp, (unsigned long l    ong)     ssp);
  7 1050         if (ssp !=  (nsp + vectorlen + stringlen))
  8 1051         {
  9 1052             printf("!!! Error @@@: stack not meet \n");
 10 1053         }
 11 1054         envbuild (vsp, ssp);//这里配置的VBIOS
 12 1055     }
 13 1056     else {
 14 1057         *vsp++ = (char *)0;
 15 1058     }
 16 
 17     ...
 18 }

439 void envbuild(char **vsp, char *ssp)
440 {//vsp没有用到
441     struct boot_params * bp;
442     bp = (struct boot_params *) ssp;//0x900000000f00f568
443 
444     init_boot_param(bp);
445 }


 45 struct boot_params{
 46     u64 sign;   //{'B', 'P', 'I', '0', '1', '0', '0', '0'}
 47     void *efitab;
 48     struct ext_list_hdr *elh;
 49     u64 flags;
 50 } __attribute__((__packed__));


 40 int init_boot_param(struct boot_params *bp)
 41 {
 42     u64 tab_offset = sizeof(struct boot_params);
 43     char sign_bp[8] = {'B', 'P', 'I', '0', '1', '0', '0', '0'};
 44 
 45     init_systab();
 46     memcpy(bp, sign_bp, 8);
 47     bp->efitab = &systab;
 48     bp->elh = NULL;
 49     bp->flags = 0;
 50 
 51 #ifdef MEM_TAB
 52     tab_offset += init_mem(bp, tab_offset);
 53 #endif
 54 #ifdef VBIOS_TAB
 55     tab_offset += init_vbios(bp, tab_offset);
 56 #endif
 57 #ifdef SMBIOS_SUPPORT
 58     loongson_smbios_init();
 59 #endif
 60 #ifdef ACPI_SUPPORT
 61     loongson_acpi_init();
 62 #endif
 63     return bp;
 64 }

 44 u64 init_mem(struct boot_params *bp, u64 offset)
 45 {
 46     struct mem_info *mem_data = (struct mem_info *)((u64)bp + offset);
 47     char data[8] = {'M', 'E', 'M'};
 48     u64 j = 0;
 49 
 50     memcpy(&mem_data->header.sign, data, sizeof(data));
 51     mem_data->header.rev = 0;
 52     mem_data->header.len = sizeof (*mem_data);
 53     mem_data->map_num = 0;
 54     /*
 55      * 1. The lowest 2M region cannot record in MemMap, cause Linux ram region should begin with usable ram.
 56      *    map_entry_init(mem_data, MEM_RESERVED, 0x0, 0x200000);  // 0x0-0x200000
 57      */
 58 
 59     /* 2. Available SYSTEM_RAM area. */
 60     map_entry_init(mem_data, SYSTEM_RAM, 0x200000, 0xf000000 - 0x200000);  // 0x200000~0xf000000
 61 
 62     /* 3. Reserved low memory highest 16M. */
 63     map_entry_init(mem_data, MEM_RESERVED, 0xf000000, 0x1000000);  // 0xf000000~0x10000000
 64 
 65     /* 4. Available SYSTEM_RAM area */
 66     map_entry_init(mem_data, SYSTEM_RAM, HIGH_MEM_WIN_BASE_ADDR + 0x10000000, memorysize_high_n[0] - 0x10000000); // (HIGH    _MEM_WIN_BASE_ADDR + 0x10000000) ~ MAX
 67 
 68     for (j = 1; j < TOT_NODE_NUM; j++) {
 69         if (memorysize_high_n[j])
 70             map_entry_init(mem_data, SYSTEM_RAM, HIGH_MEM_WIN_BASE_ADDR | (j << 44), memorysize_high_n[j]);
 71     }
 72     addlist(bp, &mem_data->header);
 73 #if 0
 74     for (j = 0; j < mem_data->map_num; j++) {
 75         printf("%d: type: %x, start: %llx, size %llx\n", j, mem_data->map[j].type, mem_data->map[j].start, mem_data->map[j    ].size);
 76     }
 77 
 78 #endif
 79     return sizeof(struct mem_info);
 80 }

 15 u64 init_vbios(struct boot_params *bp, u64 offset)
 16 {
 17     struct vbios_info *vbios_data = (struct vbios_info *)((u64)bp + offset);
 18     char data[8] = {'V', 'B', 'I', 'O', 'S'};
 19 
 20     memcpy(&vbios_data->header.sign, data, sizeof(data));
 21     vbios_data->header.rev = 0;
 22     vbios_data->header.len = sizeof (*vbios_data);
 23 
 24     ls7a_spi_read_vgabios(readspi_result, VBIOS_SIZE);
 25     if (!ls7a_vgabios_crc_check(readspi_result, VBIOS_SIZE)) {
 26         vbios_data->VbiosAddr = readspi_result;
 27     } else {
 28         vbios_data->VbiosAddr = Vbios;
 29     } 
 30 
 31     addlist(bp, &vbios_data->header);
 32     return sizeof(struct vbios_info);
 33 }
 从以上代码可以看出数据结构关系如下:
//------------------     <-----0x900000000f00f568
struct boot_params
//------------------
struct mem_info
//------------------
 70 struct vbios_info {
 71   struct ext_list_hdr header;       22字节   // {VBIOS}
 72   u64  VbiosAddr; 
 73 } __attribute__((__packed__));
//..................


确定vbios便宜的方式有三种:
1.通过gdb可以直接获得VbiosAddr的偏移,但是目前LA编译PMON后GDB不好用,
2.另外找一块开发版增加打印信息,输出Vbios便宜
3.直接从ssp开始读足够大的空间然后根据vbios_info->header的 sign确定Vbios的位置

采用第二种方法:
得到vbios_info offse为0xa37
&vbios_data->VbiosAddr = 0x900000000f00ffb5
相对于ssp的偏移为0xa4d

二、总结

ssp开始的数据结构如下:
//------------------     <-----ssp地址
struct boot_params
//------------------
struct mem_info
//------------------    offset:0xa37
 70 struct vbios_info {
 71   struct ext_list_hdr header;       22字节   // {VBIOS}
 72   u64  VbiosAddr; offset:0xa4d
 73 } __attribute__((__packed__));
//..................

1.首先查看串口启动信息找到ssp的地址
2.ssp地址加上偏移0xa4d即为VbiosAddr的地址,里面存储vbios的首地址
3.在PMON命令行下首先执行pcs -1,然虎再执行 d1 VbiosAddr地址 1 获取到Vbios的首地址
4.d1 Vbios的首地址 0x45c6即为整个VBIOS内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值