免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3500 | 回复: 8
打印 上一主题 下一主题

用网络卡从并口上启动Linux(I386) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-02-08 21:04 |只看该作者 |倒序浏览
看到好文章为什么不能拿过来跟这里的朋友分享呢?

出自:http://www.linuxforum.net
作者:raoxianhong


  1. 1、到底想干什么
  2.    了解Linux的启动过程,制作一个自己的Linux启动程序,可以增加对Linux的了解,
  3. 还能学习PC机的启动机制,增进对计算机结构的了解,增强对Linux内核学习的信心。
  4. 也可以在某些专用产品中使用(比如专用的服务器)。为此,我尝试在原来代码的基础
  5. 上修改制作了一个用网络卡从并口上启动Linux的程序,以博一笑,其中有许多问题值得研究。
  6. 2、Linux对启动程序的要求
  7.    Linux(bzImage Kernel)对启动程序的要求比较简单,你只要能够建立一个启动头(setup.S),
  8. 给出一些信息,然后将kernel(/usr/src/linux/arch/i386/boot/compressed/bvmlinux.out)调到
  9. 绝对地址0x100000(1M地址处),如果有initrd,则将它调到内存高端(离0x100000越远越好,比如如果
  10. initrd小于4M,就可以将它调到地址0xB00000,即12M处,相信现在已经很少有少于16M内存的机器了),
  11. 然后执行一些初始化操作,跳到内核处就行了。
  12.    当然,说起来容易做起来还有点麻烦,以下分几个问题解释。
  13. 3、PC机开机流程--启动程序放在何处
  14.    PC机加电后,进入实模式,先进行自检,然后初始化各个总线扩展设备(ISA, EISA,PCI,AGP),
  15. 全部初始化做完后,从当前启动设备中读一个块(512字节)到07C0:0000处,将控制转到该处。
  16.    了解这个过程,我们可以决定将启动程序放在何处:
  17.       1)放在启动设备的MBR(主启动记录中),比如磁盘的启动扇区。这是一般的启动方式。
  18.       2)放在总线扩展设备的扩展rom中,比如网卡的boot rom就行,这里制作的启动程序就是放在网卡中,可以支持
  19.           16K字节。
  20.       3)哪位高手能够修改ROMBIOS,让BIOS在做完初始化后不要马上从启动设备读数据,而是调用一段外面
  21.           加入的程序(2K字节就够了,当然也必须与修改后的BIOS一起烧在BIOS ROM中),就可以从BIOS启动!
  22.       4)先启动一个操作系统,再在此操作系统中写启动程序(比如lodlin16就是从DOS中启动Linux,好象中软
  23.          提供了一个从Windows下启动Linux的启动程序)。
  24. 4、操作系统放在何处
  25.    操作系统(一般内核在500K-1M之间,加上应用程序可以控制在2M以内,当然都经过压缩了)的数据选择余地就大了,
  26. 可以从软盘、硬盘、CDROM、网络、磁带机、并口(软件狗上烧个内核和应用程序?)、串口(外接你的设备)、
  27. USB设备(?)、PCI扩展卡、IC卡等等上面来读;各位还有什么意见,提醒提醒。有位老兄说实在不行可以用键盘启动,
  28. 每次启动时把内核敲进去,还有int 16h支持呢,做起来也不难,应该是最节省的方案了。
  29.    反正一个原则是,在启动程序中能够从该设备上读就行了,这里最简单的就是并口了,简单的端口操作,不需
  30. 要任何驱动程序支持,不需要BIOS支持,比磁盘还简单(磁盘一般使用int 13h,主要是计算柱面啊、磁头啊、磁道啊、
  31. 扇区啊好麻烦,幸好有现成的源代码,可以学习学习)。
  32.    好了,我们挑个简单的方案,将启动代码(bootsect.S+setup.S)放到网络卡的boot rom中,内核数据和应用数据放
  33. 到另外一台计算机上,用并口提供。下面谈谈几个相关的问题。
  34. 5、将数据移动到绝对地址处
  35.    第一个问题,我们得到数据,因为是在实模式下,所以一般是放在1M地址空间内,怎样将它移动到指定的地方去,
  36. 在setup.S 的源代码中,使用了int 15h(87h号功能)。这里将该段代码稍加改动,做了些假设,列到下面:
  37. 流程是:
  38.         if (%cs:move_es==0)/*由于使用前move_es初始化为0,因此这是第一次调用,此时es:bx是要移动的数据
  39.                                 存放处bx=0,es低四为位为零表示es:bx在64K边界上,fs的低8位指定目的地地址,
  40.                                 也以64K字节为单位,用不着那么精确,以简化操作*/
  41.         {
  42.                 将es右移四位,得到64K单位的8位地址(这样一来,最多只能将数据移动到16M以下了),作为源数据
  43.                 描述符中24位地址的高8位,低16位为零。
  44.                 将fs的低8位作为目的地的描述符中24位地址的高8位,同样,它的低16位为零。
  45.                 将es存放在move_es中,es自然不会是零,因此以后再调用该例程时就进行正常的移动操作了。
  46.                 ax清零返回。
  47.         }
  48.         else
  49.         {
  50.                 if (bx==0)/*bx为零,表示数据已经满64K了,应该进行实际的移动*/
  51.                 {       
  52.                         调用int15h 87h号功能,进行实际的数据移动(64K, 0x8000个16字节块)。
  53.                         目的地址(24位)高8位增一,往后走64K
  54.                         ax = 1
  55.                         return;
  56.                 }
  57.                 else
  58.                 {
  59.                         ax = 0;
  60.                         return;
  61.                 }
  62.         }


  63. # we will move %cx bytes from es:bx to %fs(64Kbytes per unit)
  64. # when we first call movetohigh(%cs:move_es is zero),
  65. # the es:bx and %edx is valid
  66. # we configure the param first
  67. # follow calls will move data actually
  68. # %ax return 0 if no data really moved, and return 1 if there is data
  69. # really to be moved
  70. #
  71. movetohigh:
  72.         cmpw        $0, %cs:move_es
  73.         jnz        move_second

  74.         # at this point , es:bx(bx = 0) is the source address
  75.         # %edx is the destination address

  76.         movb        $0x20, %cs:type_of_loader
  77.         movw        %es, %ax
  78.         shrw        $4, %ax
  79.         movb        %ah, %cs:move_src_base+2
  80.         movw        %fs, %ax
  81.         movb        %al, %cs:move_dst_base+2
  82.         movw        %es, %ax
  83.         movw        %ax, %cs:move_es
  84.         xorw        %ax, %ax
  85.         ret                                        # nothing else to do for now

  86. move_second:
  87.         xorw        %ax, %ax
  88.         testw        %bx, %bx
  89.         jne        move_ex
  90.         pushw        %ds       
  91.         pushw        %cx
  92.         pushw        %si
  93.         pushw        %bx

  94.         movw        $0x8000, %cx                        # full 64K, INT15 moves words
  95.         pushw        %cs
  96.         popw        %es
  97.         leaw        %cs:move_gdt, %si
  98.         movw        $0x8700, %ax
  99.         int        $0x15
  100.         jc        move_panic                        # this, if INT15 fails

  101.         movw        %cs:move_es, %es                # we reset %es to always point
  102.         incb        %cs:move_dst_base+2                # to 0x10000
  103.         popw        %bx
  104.         popw        %si
  105.         popw        %cx
  106.         popw        %ds
  107.         movw        $1, %ax
  108. move_ex:
  109.         ret

  110. move_gdt:
  111.         .word        0, 0, 0, 0
  112.         .word        0, 0, 0, 0

  113. move_src:
  114.         .word        0xffff

  115. move_src_base:
  116.         .byte        0x00, 0x00, 0x01                # base = 0x010000
  117.         .byte        0x93                                # typbyte
  118.         .word        0                                # limit16,base24 =0

  119. move_dst:
  120.         .word        0xffff

  121. move_dst_base:
  122.         .byte        0x00, 0x00, 0x10                # base = 0x100000
  123.         .byte        0x93                                # typbyte
  124.         .word        0                                # limit16,base24 =0
  125.         .word        0, 0, 0, 0                        # BIOS CS
  126.         .word        0, 0, 0, 0                        # BIOS DS

  127. move_es:
  128.         .word        0

  129. move_panic:
  130.         pushw        %cs
  131.         popw        %ds
  132.         cld
  133.         leaw        move_panic_mess, %si
  134.         call        prtstr
  135.        
  136. move_panic_loop:
  137.         jmp        move_panic_loop

  138. move_panic_mess:
  139.         .string        "INT15 refuses to access high mem, giving up."


  140. 6、用并口传输数据
  141.    用并口传输数据,可以从/usr/src/linux/driver/net/plip.c中抄一段,我们采用半字节协议,
  142. 并口线连接参考该文件。字节收发过程如下:

  143. #define PORT_BASE                0x378

  144. #define data_write(b) outportb(PORT_BASE, b)
  145. #define data_read() inportb(PORT_BASE+1)

  146. #define OK                        0
  147. #define TIMEOUT                        1
  148. #define FAIL                        2

  149. int sendbyte(unsigned char data)
  150. {
  151.         unsigned char c0;
  152.         unsigned long cx;

  153.         data_write((data & 0x0f));
  154.         data_write((0x10 | (data & 0x0f)));
  155.         cx = 32767l * 1024l;
  156.         while (1) {
  157.                 c0 = data_read();
  158.                 if ((c0 & 0x80) == 0)
  159.                         break;
  160.                 if (--cx == 0)
  161.                         return TIMEOUT;
  162.         }
  163.         data_write(0x10 | (data >;>; 4));
  164.         data_write((data >;>; 4));
  165.         cx = 32767l * 1024l;
  166.         while (1) {
  167.                 c0 = data_read();
  168.                 if (c0 & 0x80)
  169.                         break;
  170.                 if (--cx == 0)
  171.                         return TIMEOUT;
  172.         }
  173.         return OK;
  174. }

  175. int rcvbyte(unsigned char * pByte)
  176. {
  177.         unsigned char c0, c1;
  178.         unsigned long cx;

  179.         cx = 32767l * 1024l;
  180.         while (1) {
  181.                 c0 = data_read();
  182.                 if ((c0 & 0x80) == 0) {
  183.                         c1 = data_read();
  184.                         if (c0 == c1)
  185.                                 break;
  186.                 }
  187.                 if (--cx == 0)
  188.                         return TIMEOUT;
  189.         }
  190.         *pByte = (c0 >;>; 3) & 0x0f;
  191.         data_write(0x10); /* send ACK */
  192.         cx = 32767l * 1024l;
  193.         while (1) {
  194.                 c0 = data_read();
  195.                 if (c0 & 0x80) {
  196.                         c1 = data_read();
  197.                         if (c0 == c1)
  198.                                 break;
  199.                 }
  200.                 if (--cx == 0)
  201.                         return TIMEOUT;
  202.         }
  203.         *pByte |= (c0 << 1) & 0xf0;
  204.         data_write(0x00); /* send ACK */
  205.         return OK;
  206. }

  207. 为了能够在setup.S下收字符,特将字符接收子程序该为AT&T汇编语法
  208. (也没有什么好办法,在DOS下用TURBO C 2.0将上述代码编译成汇编
  209. 代码,然后手工转换成AT&T格式,据说有程序可以自动进行这样的转换,
  210. 有谁用过请指教):

  211. rcvbyte:
  212.         pushw        %bp
  213.         movw        %sp, %bp
  214.         subw        $6, %sp
  215.         movw        $511, -2(%bp)
  216.         movw        $-1024, -4(%bp)
  217.         jmp        .L13
  218. .L15:
  219.         movw        $889, %dx
  220.         inb        %dx, %al
  221.         movb        %al, -6(%bp)
  222.         testb        $128, -6(%bp)
  223.         jne        .L16
  224.         inb        %dx, %al
  225.         movb        %al, -5(%bp)
  226.         movb        -6(%bp), %al
  227.         cmpb        -5(%bp), %al
  228.         jne        .L17
  229.         jmp        .L14
  230. .L17:
  231. .L16:
  232.         subw        $1, -4(%bp)
  233.         sbbw        $0, -2(%bp)
  234.         movw        -2(%bp), %dx
  235.         movw        -4(%bp), %ax
  236.         orw        %ax, %dx
  237.         jne        .L18
  238.         movw        $1, %ax
  239.         jmp        .L12
  240. .L18:
  241. .L13:
  242.         jmp        .L15
  243. .L14:
  244.         movb        -6(%bp), %al
  245.         shrb        $1, %al
  246.         shrb        $1, %al
  247.         shrb        $1, %al
  248.         andb        $15, %al
  249.         movw        4(%bp), %bx
  250.         movb        %al, (%bx)
  251.         movb        $16, %al
  252.         movw        $888, %dx
  253.         outb        %al, %dx
  254.         movw        $511, -2(%bp)
  255.         movw        $-1024, -4(%bp)
  256.         jmp        .L19
  257. .L21:
  258.         movw        $889, %dx
  259.         inb        %dx, %al  
  260.         movb        %al, -6(%bp)
  261.         testb        $128, %al
  262.         je        .L22
  263.         inb        %dx, %al
  264.         movb        %al, -5(%bp)
  265.         movb        -6(%bp), %al
  266.         cmpb        -5(%bp), %al
  267.         jne        .L23
  268.         jmp        .L20
  269. .L23:
  270. .L22:
  271.         subw        $1, -4(%bp)
  272.         sbbw        $0, -2(%bp)
  273.         movw        -2(%bp), %dx
  274.         movw        -4(%bp), %ax
  275.         orw        %ax, %dx
  276.         jne        .L24
  277.         movw        $1, %ax
  278.         jmp        .L12
  279. .L24:
  280. .L19:
  281.         jmp        .L21
  282. .L20:       
  283.         movb        -6(%bp), %al
  284.         shlb        $1, %al
  285.         andb        $240, %al
  286.         movw        4(%bp), %bx
  287.         orb        %al, (%bx)
  288.         xorw        %ax, %ax
  289.         movw        $888, %dx
  290.         outb        %al, %dx
  291.         jmp        .L12
  292. .L12:
  293.         movw        %bp, %sp
  294.         popw        %bp
  295.         ret

  296. 能够收发字符还不行,作为协议,总得知道数据的起始和结束,也应该进行简单的检错。这里采用
  297. 字符填充方式进行数据包编码,用‘\’表示转义字符,数据包头用\H表示,数据包结束用\T表示
  298. 如果数据中有'\',则用\\表示(从printf的格式串中学来的),数据包后面跟一个字节的校验和,
  299. 这样就可以收发数据包了,具体程序如下:

  300. int rcvpack(unsigned char * pData, int * pLength)
  301. {
  302.         int ret;
  303.         int length;
  304.         unsigned char checksum;
  305.         int maxlength;
  306.         int status;
  307.         maxlength = *pLength + 1;
  308.         if (maxlength<=0)
  309.                 return FAIL;
  310.         if (pData == NULL)
  311.                 return FAIL;
  312.         checksum = 0;
  313.         length = 0;
  314.         status = 0;
  315.         while (1)
  316.         {
  317.                 unsigned char ch;
  318.                 int count;
  319.                 count = 10;
  320.                 while (1)
  321.                 {
  322.                 if ((ret = rcvbyte(&ch)) != OK)
  323.                 {
  324.                         count--;
  325.                         if (count==0)
  326.                         {
  327.                                 printf("\nReceive byte timeout\n");
  328.                                 return ret;
  329.                         }
  330.                 }
  331.                         else
  332.                                 break;
  333.                 }
  334.                 switch (status)
  335.                 {
  336.                         case 0:
  337.                         {
  338.                                 if (ch == '\\')
  339.                                 {
  340.                                         status = 1;
  341.                                 }
  342.                         }
  343.                         break;
  344.                         case 1:
  345.                         {
  346.                                 if (ch == 'H')
  347.                                         status = 2;
  348.                                 else
  349.                                         status = 0;
  350.                         }
  351.                         break;
  352.                         case 2:
  353.                         {
  354.                                 if (ch == '\\')
  355.                                 {
  356.                                         status = 3;
  357.                                 }
  358.                                 else
  359.                                 {
  360.                                         length ++;
  361.                                         if (length>;maxlength)
  362.                                         {
  363.                                                 printf("Buffer overflow(%d>;%d)\n", length, maxlength);
  364.                                                 return FAIL;
  365.                                         }
  366.                                         *pData++ = ch;
  367.                                         checksum += ch;
  368.                                 }
  369.                         }
  370.                         break;
  371.                         case 3:
  372.                         {
  373.                                 if (ch == '\\')
  374.                                 {
  375.                                     length++;
  376.                                     if (length>;maxlength)
  377.                                     {
  378.                                         printf("Buffer overflow (%d>;%d)\n", length, maxlength);
  379.                                         return FAIL;
  380.                                     }
  381.                                     checksum += ch;
  382.                                     *pData++ = ch;
  383.                                     status = 2;
  384.                                 }
  385.                                 else
  386.                                 if (ch =='T')
  387.                                 {
  388.                                         unsigned char chk;
  389.                                         *pLength = length;
  390.                                         if (rcvbyte(&chk)!=OK)
  391.                                                 return FAIL;
  392.                                         if (checksum==chk)
  393.                                         {
  394.                                                 return OK;
  395.                                         }
  396.                                         else
  397.                                         {
  398.                                                 printf("ERROR: Checksum is nozero(%d-%d)\n", checksum,chk);
  399.                                                 return FAIL;
  400.                                         }
  401.                                 }
  402.                                 else
  403.                                 {
  404.                                         printf("ERROR: a '\\' or 'T' expected('%c')!\n ", ch);
  405.                                         return FAIL;
  406.                                 }
  407.                         }
  408.                 }
  409.         }
  410. }


  411. int sendpack(unsigned char * pData, int length)
  412. {
  413.         int ret;
  414.         unsigned char checksum;
  415.         checksum = 0;
  416.         if (length<=0)
  417.                 return OK;
  418.         if ((ret = sendbyte('\\')) != OK)
  419.                 return 1;
  420.         if ((ret = sendbyte('H')) != OK)
  421.                 return 2;
  422.         while (length>;0)
  423.         {
  424.                 unsigned char ch;
  425.                 ch = *pData++;
  426.                 checksum += ch;
  427.                 if ((ret = sendbyte(ch)) != OK)
  428.                         return 3;
  429.                 if (ch == '\\')
  430.                 {
  431.                         if ((ret = sendbyte(ch)) != OK)
  432.                                 return 4;
  433.                 }
  434.                 length--;
  435.         }

  436.         if ((ret = sendbyte('\\')) != OK)
  437.                 return 5;
  438.         if ((ret = sendbyte('T')) != OK)
  439.                 return 6;
  440.         if ((ret = sendbyte(checksum)) != OK)
  441.                 return 7;
  442.         return OK;
  443. }

  444. 同样,也将rcvpack改成AT&T汇编(减少了几个printf语句):

  445. chbuffer:
  446.         .byte 0
  447. overflow:
  448.         .string "Buffer overflow..."
  449. rcvpack:
  450.         pushw        %bp
  451.         movw        %sp, %bp
  452.         subw        $12, %sp
  453.         pushw        %si
  454.         movw        4(%bp), %si
  455.         movw        6(%bp), %bx
  456.         movw        (%bx), %ax
  457.         incw         %ax
  458.         movw        %ax, -6(%bp)
  459.         cmpw        $0, -6(%bp)
  460.         jg        .L26
  461.         leaw        overflow, %si
  462.         call        prtstr
  463.         movw        $2, %ax
  464.         jmp        .L25
  465. .L26:
  466.         orw        %si, %si       
  467.         jne        .L27
  468.         movw        $2, %ax
  469.         jmp        .L25
  470. .L27:
  471.         movb        $0,-8(%bp)
  472.         movw        $0, -10(%bp)
  473.         movw        $0, -4(%bp)
  474.         jmp        .L28
  475. .L30:
  476.         movw        $10, -2(%bp)
  477.         jmp        .L31
  478. .L33:
  479. #        movw        -4(%bp), %ax
  480. #        addb        $'0', %al
  481. #        call        prtchr
  482.         leaw        chbuffer, %ax
  483.         pushw        %ax
  484.         call        rcvbyte
  485.         popw        %cx
  486.         movw        %ax, -12(%bp)
  487.         orw         %ax, %ax
  488.         je        .L34
  489.         decw        -2(%bp)
  490.         cmpw        $0, -2(%bp)
  491.         jne        .L35
  492.         movw        -12(%bp), %ax
  493.         jmp        .L25
  494. .L35:
  495.         jmp        .L36
  496. .L34:
  497.         jmp        .L32
  498. .L36:
  499. .L31:
  500.         jmp        .L33
  501. .L32:
  502.         pushw        %si
  503.         leaw        chbuffer, %si
  504.         movb        (%si), %al
  505.         movb        %al, -7(%bp)
  506.         popw        %si
  507. #        call        prtchr
  508.         movw         -4(%bp), %ax
  509.         cmpw        $3, %ax
  510.         jbe        .L58
  511.         jmp        .L56
  512. .L58:
  513.         cmpw        $0, %ax
  514.         je        .L38
  515.         cmpw        $1, %ax
  516.         je        .L40
  517.         cmpw        $2, %ax
  518.         je        .L43
  519.         cmpw        $3, %ax
  520.         je        .L47
  521.         jmp        .L56
  522. .L38:       
  523.         cmpb        $92, -7(%bp)
  524.         jne        .L39
  525.         movw        $1, -4(%bp)
  526. .L39:
  527.         jmp         .L37
  528. .L40:
  529.         cmpb        $72, -7(%bp)
  530.         jne        .L41
  531.         movw        $2, -4(%bp)
  532.         jmp        .L42
  533. .L41:
  534.         movw        $0, -4(%bp)       
  535. .L42:
  536.         jmp        .L37
  537. .L43:
  538.         cmpb        $92, -7(%bp)
  539.         jne        .L44
  540.         movw        $3, -4(%bp)
  541.         jmp         .L45
  542. .L44:
  543.         incw        -10(%bp)
  544.         movw        -10(%bp), %ax
  545.         cmpw        -6(%bp), %ax       
  546.         jle        .L46
  547.         movw        $2, %ax
  548.         jmp        .L25
  549. .L46:
  550.         movb        -7(%bp), %al
  551.         movb        %al, (%si)
  552.         incw        %si       
  553.         movb         -7(%bp), %al
  554.         addb        %al, -8(%bp)
  555. .L45:
  556.         jmp        .L37
  557. .L47:
  558.         cmpb        $92, -7(%bp)  
  559.         jne        .L48
  560.         incw        -10(%bp)
  561.         movw        -10(%bp), %ax       
  562.         cmpw        -6(%bp), %ax
  563.         jle        .L49
  564.         movw        $2, %ax
  565.         jmp        .L25
  566. .L49:
  567.         movb        -7(%bp), %al
  568.         addb        %al, -8(%bp)
  569.         movb        -7(%bp), %al
  570.         movb        %al, (%si)
  571.         incw        %si       
  572.         movw        $2, -4(%bp)
  573.         jmp        .L50
  574. .L48:
  575.         cmpb        $84, -7(%bp)
  576.         jne        .L51
  577.         movw        -10(%bp), %ax
  578.         movw        6(%bp), %bx
  579.         movw        %ax, (%bx)
  580.         leaw        chbuffer, %ax
  581.         pushw        %ax
  582.         call        rcvbyte
  583.         popw        %cx
  584.         orw        %ax, %ax
  585.         je        .L52
  586.         movw        $2, %ax
  587.         jmp        .L25
  588. .L52:
  589.         movb        -8(%bp), %al
  590.         cmpb        chbuffer, %al
  591.         jne        .L53
  592.         xorw        %ax, %ax
  593.         jmp        .L25
  594.         jmp        .L54
  595. sChecksumFailed:
  596.         .string "Checksum error!"
  597. .L53:
  598.         leaw        sChecksumFailed, %si
  599.         call         prtstr
  600.         movw        $2, %ax
  601.         jmp        .L25
  602. .L54:
  603.         jmp        .L55
  604. .L51:
  605.         movw        $2, %ax
  606.         jmp        .L25
  607. .L55:
  608. .L50:
  609. .L56:
  610. .L37:
  611. .L28:
  612.         jmp         .L30
  613. .L29:
  614. .L25:
  615.         popw        %si
  616.         movw        %bp, %sp
  617.         popw        %bp
  618.         ret

  619. 好了,万事具备了,先用上面的c代码写另外一台计算机上的“服务”程序(也用来测试),这台
  620. 计算机运行DOS,用TURBO C 2.0编译运行:
  621. 运行时将initrd.img和内核编译后的/usr/src/linux/arch/i386/boot/compressed/bvmlinux.out
  622. 拷贝到该计算机的c:\下,然后带参数 s c:\bvmlinux.out c:\initrd.img运行即可。
  623. 至于启动程序,还得进行少许修改,才能烧到boot rom 中,见后面的说明。

  624. int main(int argc, char* argv[])
  625. {
  626.         FILE* pFile;
  627.         int count = 2;
  628.         if (argc<3)
  629.         {
  630.                 printf("Usage testspp [s | r] \n");
  631.                 return 1;
  632.         }
  633.         while(count        {
  634.         if (argv[1][0] == 's')
  635.                 pFile = fopen(argv[count], "rb");
  636.         else
  637.                 pFile = fopen(argv[count], "wb");
  638.         if (pFile==NULL)
  639.         {
  640.                 printf("Can't open/create file %s\n", argv[2]);
  641.                 return 2;
  642.         }
  643.         if (argv[1][0]=='r')/*receive*/
  644.         {
  645.                 unsigned long filesize;
  646.                 char buffer[10244];
  647.                 int length;
  648.                 /*get filelength */
  649.                 length = 10244;
  650.                
  651.                 printf("Receiving filesize package\n");
  652.                 while( (rcvpack(buffer, &length)!=OK) && (length!=4))
  653.                         length = 10244;
  654.                 filesize = *(long*)buffer;
  655.                 printf("file size is:%ld\n", filesize);
  656.                
  657.                 while (filesize>;0)
  658.                 {
  659.                         length = 10244;
  660.                         if (rcvpack(buffer, &length) != OK)
  661.                         {
  662.                                 printf("Receive data package failed\n");
  663.                                 return 0;
  664.                         }
  665.                         if (length>;0)
  666.                                 fwrite(buffer, 1, length, pFile);
  667.                         filesize-=length;
  668.                         printf("\r%ld Bytes Left         ", filesize);
  669.                 }
  670.         }
  671.         else/*send*/
  672.         {
  673.                 unsigned long filesize;
  674.                 /*send file length*/
  675.                 unsigned long stemp;
  676.                 int ret;
  677.                 fseek(pFile, 0, 2);
  678.                 filesize = ftell(pFile);
  679.                 fseek(pFile, 0, 0);
  680.                 printf("\nfile size is:%ld\n", filesize);
  681.                 /*
  682.                 while ((ret = sendpack((char *)&filesize, 4)) != OK)
  683.                 {
  684.                         printf("send file size failed(%d)\n", ret);
  685.                 }
  686.                 */
  687.                 while (filesize>;0)
  688.                 {
  689.                         char buffer[10240];
  690.                         long size;
  691.                         int ret;
  692.                         size = fread(buffer, 1, 10240, pFile);
  693.                         if ((ret = sendpack(buffer, size)) != OK)
  694.                         {
  695.                                 printf("Send data package failed(%d)\n", ret);
  696.                                 return 0;
  697.                         }
  698.                         filesize -= size;
  699.                         printf("\r\t%ld Bytes Left", filesize);
  700.                 }
  701.         }
  702.         fclose(pFile);
  703.         count++;
  704.         }/*while*/
  705.         return 0;
  706. }

  707. 5、对bootsect.S的修改
  708.    目前的bootsect.S ,主要的问题是,它是从软盘上读数据,将这些代码换成对rcvpack的调用即可,
  709. 另外,它不支持调入initrd,应该增加相应的代码。问题在于,bootsect.S中没有那么多空间来放rcvpack
  710. 相关的代码(毕竟只有512字节,当然,如果烧在boot rom中,就不存在这个问题了,但是用软盘调试时
  711. 就不行了,因此干脆编制load_kernel和load_initrd放在setup.S中,然后在bootsect.S中进行回调即可。
  712. bootsect.S 修改如下(只给出修改部分):
  713. .....
  714. .....
  715. ok_load_setup:
  716.         call        kill_motor
  717.         call        print_nl
  718. # Now we will load kernel and initrd
  719. loading:
  720. # 先打印Loading字符
  721.         movw        $INITSEG, %ax
  722.         movw        %ax, %es                # set up es
  723.         movb        $0x03, %ah                # read cursor pos
  724.         xorb        %bh, %bh
  725.         int        $0x10
  726.         movw        $22, %cx
  727.         movw        $0x0007, %bx                # page 0, attribute 7 (normal)
  728.         movw    $msg1, %bp
  729.         movw    $0x1301, %ax                # write string, move cursor
  730.         int        $0x10                        # tell the user we're loading..
  731. load_kernel_img:
  732. # 将load_kernel函数的指针放到0x22C处这里进行调用就行了(软盘启动过程中,此前已经将setup.S
  733. # 从磁盘上调到bootsect.S,即0x0200之后,注意setup.S的头部是一张表,这里“提前”消费了)
  734. # 0x22C is the load kernel routine
  735.         bootsect_readimage = 0x22C
  736.         lcall        bootsect_readimage
  737. load_initrd_img:
  738. # 将load_initrd函数的指针放到0x220处
  739. # 0x220 if the load initrd routine
  740.         bootsect_readinitrd = 0x220
  741.         lcall        bootsect_readinitrd

  742. # After that (everything loaded), we jump to the setup-routine
  743. # loaded directly after the bootblock:
  744.         ljmp        $SETUPSEG, $0
  745. ......
  746. ......
  747. 6、对setup.S的修改
  748.    对setup.S进行修改,主要是:修改setup.S头部,增加load_kernel和load_initrd函数等,具体如下。
  749.     修改setup.S头部如下(为好看,这里删除了原来的部分注释):

  750. start:
  751.                         jmp        trampoline
  752.                         .ascii        "HdrS"                # header signature
  753.                         .word        0x0202                # header version number (>;= 0x0105)
  754. realmode_swtch:        .word        0, 0                # default_switch, SETUPSEG
  755. start_sys_seg:        .word        SYSSEG
  756.                         .word        kernel_version        # pointing to kernel version string
  757. type_of_loader:        .byte        0       
  758. loadflags:
  759. LOADED_HIGH        = 1                       
  760.                         .byte        LOADED_HIGH   # 只支持bzImage
  761. setup_move_size:         .word  0x8000       
  762. code32_start:                                # here loaders can put a different
  763.                         .long        0x100000        # 0x100000 = default for big kernel
  764. ramdisk_image:        .long        0xB00000        # ramdisk 调到12M处
  765. ramdisk_size:                .long        0                # 由load_initrd来设置长度
  766. bootsect_kludge:
  767.                         .word  load_initrd, SETUPSEG #0x220, 放置load_initrd函数的指针
  768. heap_end_ptr:                .word        modelist+1024        pad1:                .word        0
  769. cmd_line_ptr:                .long 0               
  770. load_kernel_call:
  771.                         .word  load_kernel, SETUPSEG
  772. trampoline:                call        start_of_setup

  773.                         .space        1024

  774. load_kernel和load_initrd:

  775. load_imsg:
  776.         .byte 13, 10
  777.         .string "Load INITRD from PARPort(378)"
  778. load_kmsg:
  779.         .byte 13, 10
  780.         .string        "Load Kernel From PARPort(378)"
  781. reading_suc:
  782.         .string        "."
  783. reading_failed:
  784.         .string " failed"
  785. read_len:
  786.         .word 0, 0
  787. read_total:
  788.         .word 0, 0
  789. read_buffer:
  790.         # 如何在AT&T语法中完成intel语法中的 db 1280 dup(0),那位请指教
  791.         # AT&T汇编的语法何处寻?
  792.         .string "012345678901234567890123456789012345678901234567890123456789"
  793.         .string "012345678901234567890123456789012345678901234567890123456789"
  794.         .string "012345678901234567890123456789012345678901234567890123456789"
  795.         .string "012345678901234567890123456789012345678901234567890123456789"
  796.         .string "012345678901234567890123456789012345678901234567890123456789"
  797.         .string "012345678901234567890123456789012345678901234567890123456789"
  798.         .string "012345678901234567890123456789012345678901234567890123456789"
  799.         .string "012345678901234567890123456789012345678901234567890123456789"
  800.         .string "012345678901234567890123456789012345678901234567890123456789"
  801.         .string "012345678901234567890123456789012345678901234567890123456789"
  802.         .string "012345678901234567890123456789012345678901234567890123456789"
  803.         .string "012345678901234567890123456789012345678901234567890123456789"
  804.         .string "012345678901234567890123456789012345678901234567890123456789"
  805.         .string "012345678901234567890123456789012345678901234567890123456789"
  806.         .string "012345678901234567890123456789012345678901234567890123456789"
  807.         .string "012345678901234567890123456789012345678901234567890123456789"
  808.         .string "012345678901234567890123456789012345678901234567890123456789"
  809.         .string "012345678901234567890123456789012345678901234567890123456789"
  810.         .string "012345678901234567890123456789012345678901234567890123456789"
  811.         .string "012345678901234567890123456789012345678901234567890123456789"

  812. load_initrd:
  813.         pushw        %ds
  814.         pushw        %es
  815.         pushw        %cs
  816.         popw        %ds
  817.         pushw        %cs
  818.         popw        %es
  819.         cld       
  820.         leaw        load_imsg, %si
  821.         call        prtstr                                # 打印提示
  822.         movw        $0x1000, %ax
  823.         movw        %ax, %es
  824.         xorw        %bx, %bx
  825.         movw        $0x00B0, %ax                        # initrd数据先调到0x1000:0000处,
  826.                                                 # 满64K即移动到12M(0xB00000)处
  827.         movw        %ax, %fs
  828.         movw        $0, %cs:move_es
  829.         movl        $0, %cs:read_total
  830.         call        movetohigh                        # 初始化数据移动部分
  831.         call        .ld_img                        # 从并口上读入一个文件并移动到指定位置
  832.         movl        %cs:read_total, %eax
  833.         movl        %eax, %cs:ramdisk_size        # 设置ramdisk_size和ramdisk_image       
  834.         movl        $0x00B00000, %eax
  835.         movl        %eax, %cs:ramdisk_image
  836.         popw        %es
  837.         popw        %ds
  838.         lret

  839. load_kernel:
  840.         pushw        %ds
  841.         pushw        %es
  842.         pushw        %cs
  843.         popw        %ds
  844.         pushw   %cs
  845.         popw        %es
  846.         cld
  847.         leaw        load_kmsg, %si
  848.         call        prtstr
  849.         movw        $0x1000, %ax
  850.         movw        %ax, %es
  851.         xorw        %bx, %bx
  852.         movw        $0x0010, %ax
  853.         movw        %ax, %fs
  854.         movw        $0, %cs:move_es
  855.         movl        $0, %cs:read_total
  856.         call        movetohigh
  857.         call        .ld_img
  858.         popw        %es
  859.         popw        %ds
  860.         lret

  861. .ld_img:
  862. .ld_nextpack:
  863.         pushw        %bx
  864.         pushw        %es
  865.         leaw         read_len, %si
  866.         movw        $1124, %ax
  867.         movw        %ax, (%si)
  868.         pushw        %si
  869.         leaw        read_buffer, %ax
  870.         pushw        %ax
  871.         movw        %bx, %ax
  872.         call        rcvpack                # 调用rcpack接收一个数据包read_buffer中
  873.         popw        %cx
  874.         popw        %cx
  875.         popw        %es
  876.         popw        %bx
  877.         cmpw        $0, %ax                # 成功?
  878.         je        .ld_suc
  879.         leaw        reading_failed, %si       
  880.         call        prtstr
  881. .ld_panic:
  882.         jmp        .ld_panic                # 失败则死循环
  883. .ld_suc:
  884.         leaw        read_buffer, %si
  885.         movw        %bx, %di
  886.         movw        $256, %cx                # move 1024 bytes
  887.         rep       
  888.         movsl                                # 从read_buffer移动到es:bx处,强制假定一个数据包长度
  889.                                         # 就是1024字节,最后一个数据包除外。
  890.         addw        $1024, %bx                # 更新bx, 如果bx加到零,则表示已经满64K,后面的调用中
  891.         call         movetohigh                # 进行实际的数据移动
  892.         movw        %ax, %dx                #
  893.         cmpw        $0, %ax                # 如果进行了64K数据移动,就打印一个'.'
  894.         je        .ld_1
  895.         leaw        reading_suc, %si
  896.         call         prtstr
  897. .ld_1:
  898.         leaw        read_len, %si               
  899.         xorl        %eax, %eax
  900.         movw        (%si), %ax
  901.         addl        %eax, %cs:read_total
  902.         cmpw        $1024, %ax                 # 更新收到数据总字节数,如果收到的字节数少于1024,则表示
  903.                                         # 收到最后一个数据包,这得冒点风险,万一最后一个数据包刚好
  904.                                         # 是1024字节,怎么办好呢?赌一把吧!
  905.         jb        .ld_lastestpack
  906.         jmp        .ld_nextpack                # 接着接收下一个数据包
  907. .ld_lastestpack:
  908.         # 最后一个数据包收到后,不见得满64K,此时应该强制数据移动
  909.         cmpw        $0, %dx
  910.         jne        .ld_exit
  911.         xorw         %bx, %bx
  912.         call        movetohigh
  913. .ld_exit:
  914.         ret

  915. 7、用软盘进行调试,将启动程序烧到bootrom中
  916.         好了,大功告成,对内核进行配置,然后make bzImage,将bvmlinux.out拷贝到“服务器”上,建立
  917. initrd也放在“服务器”上,然后放张软盘在软驱中,dd if=/usr/src/linux/arch/i386/boot/bzImage of=
  918. /dev/fd0 count=32将bootsect.S+setup.S部分拷贝到软盘上,重新启动(先连接好并口线)。启动后再在
  919. “服务器”上启动文件“服务”程序,终于可以将Linux从并口上启动了!
  920.         做少量调整(主要是去掉读setup.S部分的代码),即可以将此bzImage的前8(16?)K写在一个文件中,
  921. 处理成boot rom映象,烧到boot rom中,插到网络卡上,启动机器即可。这就是用网络卡从并口上启动Linux。
复制代码

论坛徽章:
0
2 [报告]
发表于 2003-02-08 21:06 |只看该作者

用网络卡从并口上启动Linux(I386)

出自:http://www.linuxforum.net
作者:raoxianhong

1.系统自检完毕后在ROM空间中找(好象是2Kbytes为单位),如果某一段的前两表字节是0x55AA,那么第三个字节作为ROM程序的大小(512字节为单位)。然后将该段空间中的所有字节相加(计算校验和),结果为零时表示ROM程序有效。此时BIOS用一个长调用(lcall),调用该块的第四个字节起始处(自然该用lret返回)。
2.有个问题原来一直不明白,如果此时某个启动网卡启动系统,但是后面还有带ROM的卡(比如PCI),那么该段ROM程序岂不是没有机会运行了吗,当然,如果不运行任何设备的扩展ROM,不知道Linux内会不会有问题!后来查资料得知,实际上制作网卡启动程序时还没有这么简单。
3.事实上,系统在自检及运行所有的扩展硬件检测之后,是用int 19h启动操作系统的!因此在扩展ROM中不直接启动操作系统,而是将操作系统启动代码作为int 19h的中断调用(其实也不用返回,操作系统没有必要返回)代码就行了。
明白这一点后,制作一个网卡启动程序就容易多了,具体请看某个网卡的启动源代码即可,附件中有一个,记不住是从哪里抄来的了!

论坛徽章:
0
3 [报告]
发表于 2003-02-08 21:07 |只看该作者

用网络卡从并口上启动Linux(I386)


  1. Bootrom写好后要进行一些处理才能烧到EPROM中去。这里提供一段代码可以完成这个功能,上面讲的用并口启动Linux的程序就是这么处理的。
  2. 基本的想法是,写一个通用的启动代码载入程序(stub),将bootsect.S+setup.S(也就是bzImage的前面一段)设置成0x19号中断的中断向量。在外面写一段代码将该段代码和启动代码进行合并,生成合法的bootrom映象就,可以烧到bootrom中去,在网络卡上启动。

  3. 下面是通用的启动代码载入程序:



  4. .code16
  5. RomHeader:
  6.         .byte 0x55, 0xaa #启动ROM标志
  7. RomPageCount:
  8.         .byte 0x20  #假定bootrom是16K bytes

  9. RomCode:
  10.         pushw %es
  11.         pushw %bx
  12.         pushw %ax

  13.         movb  $0xc1, %al
  14.         call  IntVectAddr
  15.         movw  $0x6a6e, %ax
  16.         cmpw  %es:(%bx), %ax
  17.         jz    RomBootInit_x
  18.         movw  %ax, %es:(%bx)
  19.         movw  $0xc019, %ax
  20.         call  MoveIntVector
  21.         movw  $RomBootVect, %bx
  22.         pushw %cs
  23.         popw  %es
  24.         call  SetIntVector
  25. RomBootInit_x:
  26.         popw  %ax
  27.         popw  %bx
  28.         popw  %es
  29.         lret

  30. IntVectAddr:
  31.         xorw        %bx,%bx       
  32.         movw        %bx,%es       
  33.         movb        %al,%bl
  34.         addw        %bx,%bx
  35.         addw        %bx,%bx
  36.         ret

  37. GetIntVector:       
  38.         call        IntVectAddr
  39. GetIntVect_1:
  40.                      les        %es:(%bx), %bx
  41.         ret                       

  42. SetIntVector:
  43.         pushf                        #; entry AL=vector to set, ES:BX=value
  44.         pushw        %es                #; exit: vector modified
  45.         pushw        %bx                #; all registers preserved
  46.         call        IntVectAddr
  47.         cli
  48.         popw        %es:(%bx)
  49.         addw        $2, %bx
  50.         popw        %es:(%bx)
  51.         subw        $2, %bx
  52.         popf
  53.         jmp        GetIntVect_1

  54. MoveIntVector:
  55.         call        GetIntVector        #; entry AL=vect to get, AH=vect to set
  56.         xchgb        %al,%ah                #; exit: vector set, ES:BX=vector value
  57.         call        SetIntVector        #; other registers preserved
  58.         xchgb        %al,%ah
  59.         ret

  60. RomBootVect:
  61.         pushw   %cs
  62.         popw        %ds
  63.         movw        $0x07c0, %ax
  64.         movw        %ax, %es
  65.         movw        $BootCode, %si
  66.         subw        %di, %di
  67.         movw        $8192, %cx
  68.         cld
  69.         rep
  70.         movsw
  71.         ljmp        $0x07c0, $0
  72.         lret

  73. .org        0x0200
  74. BootCode:




  75. 在Linux下的编译方法与bootsect.S的编译方法一样,编译成可执行文件后,比如放在bootx文件中。
  76. 内核编译后(make bzImage,支持上面所说的启动方式),得到bzImage文件。

  77. 下面是将这两个文件复合在一起得到bootrom映象的程序:


  78. /* mkbtrom.c */

  79. int main(int argc, char* argv[])
  80. {
  81.         char buf[16384];
  82.         char ch;
  83.         int i;
  84.         if (argc<4)
  85.         {
  86.                 printf("Usage: mkbtrom   \n");
  87.                 return 1;
  88.         }
  89.         FILE * pFile;
  90.         pFile = fopen(argv[1], "rb");
  91.         if (pFile==NULL)
  92.         {
  93.                 printf("File %s open failed\n", argv[1]);
  94.                 return 2;
  95.         }
  96.         fread(buf, 1, 512, pFile);
  97.         fclose(pFile);
  98.         pFile = fopen(argv[2], "rb");
  99.         if (pFile==NULL)
  100.         {
  101.                 printf("File %s open failed\n", argv[2]);
  102.                 return 2;
  103.         }
  104.         fread(&buf[512], 1, 16384-512-1, pFile);
  105.         fclose(pFile);
  106.         ch = 0;
  107.         for (i = 0;i<18383;i++)
  108.                 ch += buf[ i ];
  109.         buf[16383] = -ch;
  110.         pFile = fopen(argv[3], "wb");
  111.         fwrite(buf, 1, 16384, pFile);
  112.         fclose(pFile);
  113.         return 0;
  114. }




  115. 编译成执行文件后,运行mkbtrom bootx bzImage boot16k.bin后,boot16k.bin就可以烧到eprom中,从网络卡中启动了。

复制代码

论坛徽章:
0
4 [报告]
发表于 2003-02-10 06:42 |只看该作者

用网络卡从并口上启动Linux(I386)

高人

论坛徽章:
0
5 [报告]
发表于 2003-03-04 14:31 |只看该作者

用网络卡从并口上启动Linux(I386)

牛啊

论坛徽章:
0
6 [报告]
发表于 2004-12-26 11:41 |只看该作者

用网络卡从并口上启动Linux(I386)

走召弓虽!!!!

论坛徽章:
0
7 [报告]
发表于 2004-12-26 22:39 |只看该作者

用网络卡从并口上启动Linux(I386)

好文,这篇文章应该对做无盘系统的兄弟有点助益

论坛徽章:
0
8 [报告]
发表于 2004-12-27 09:43 |只看该作者

用网络卡从并口上启动Linux(I386)

先收下,慢慢消化

招聘 : Linux运维
论坛徽章:
0
9 [报告]
发表于 2005-01-20 00:01 |只看该作者

用网络卡从并口上启动Linux(I386)

根本看不懂,上面的代码是用什么写的?MASM??
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP