init_heap() 관련해서.

도영주 2013.08.28 15:35 조회 수 : 2050

심심해서 분석해봤는데, 아직 좀 찜찜한 부분이 있네요.


main.c의 init_heap에서 heap_end_ptr에 + 0x200이 이해가 안되던 부분이었죠.

부트 로더는 다음과 같은 코드를 반드시 넣어야 한다고 합니다.


kernel과의 protocol을 맞추기 위한 코드죠.

830         unsigned long base_ptr; /* base address for real-mode segment */
831 
832         if ( setup_sects == 0 ) {
833                 setup_sects = 4;
834         }
835 
836         if ( protocol >= 0x0200 ) {
837                 type_of_loader = <type code>;
838                 if ( loading_initrd ) {
839                         ramdisk_image = <initrd_address>;
840                         ramdisk_size = <initrd_size>;
841                 }
842 
843                 if ( protocol >= 0x0202 && loadflags & 0x01 ) //High memory 
844                         heap_end = 0xe000;
845                 else
846                         heap_end = 0x9800;
847 
848                 if ( protocol >= 0x0201 ) {
849                         heap_end_ptr = heap_end - 0x200;
850                         loadflags |= 0x80; /* CAN_USE_HEAP */
851                 }
852 
853                 if ( protocol >= 0x0202 ) {
854                         cmd_line_ptr = base_ptr + heap_end;
855                         strcpy(cmd_line_ptr, cmdline);
856                 } else {
857                         cmd_line_magic  = 0xA33F;
858                         cmd_line_offset = heap_end;
859                         setup_move_size = heap_end + strlen(cmdline)+1;
860                         strcpy(base_ptr+cmd_line_offset, cmdline);
861                 }
862         } else {
863                 /* Very old kernel */
864 
865                 heap_end = 0x9800;
866 
867                 cmd_line_magic  = 0xA33F;
868                 cmd_line_offset = heap_end;
869 
870                 /* A very old kernel MUST have its real-mode code
871                    loaded at 0x90000 */
872 
873                 if ( base_ptr != 0x90000 ) {
874                         /* Copy the real-mode kernel */
875                         memcpy(0x90000, base_ptr, (setup_sects+1)*512);
876                         base_ptr = 0x90000;              /* Relocated */
877                 }
878 
879                 strcpy(0x90000+cmd_line_offset, cmdline);
880 
881                 /* It is recommended to clear memory up to the 32K mark */
882                 memset(0x90000 + (setup_sects+1)*512, 0,
883                        (64-(setup_sects+1))*512);
884         }



위에서 kernel 2.01 protocol 부터는 무조건 heap을 사용하게 됩니다.

왜 0x200을 더했나, 이게 의문이었는데, 보면 heap_end_ptr = heap_end - 0x200인 것을 확인할 수 있습니다.

bzimage_compress라는 부분에서 보게 될 것 같습니다.


heap_end에서 0x200을 빼준건 heap overrun (overflow) 때문에 그랬다고 하는데, (boot.txt에 protocol 설명이 있습니다.)

정확한 이유는 모르겠네요.


head_end를 단순히 stack_size에 맞추어 heap과 stack의 경계를 잡는 것으로 생각됩니다.

114 
115 static void init_heap(void)
116 {
117         char *stack_end;
118 
119         if (boot_params.hdr.loadflags & CAN_USE_HEAP) {
120                 asm("leal %P1(%%esp),%0"
121                     : "=r" (stack_end) : "i" (-STACK_SIZE));
122 
123                 heap_end = (char *)
124                         ((size_t)boot_params.hdr.heap_end_ptr + 0x200);
125                 if (heap_end > stack_end)
126                         heap_end = stack_end;
127         } else {
128                 /* Boot protocol 2.00 only, no heap available */
129                 puts("WARNING: Ancient bootloader, some functionality "
130                      "may be limited!n");
131         }

header.S에서 fffc로 stack pointer를 설정하는 것과는 별개의 문제인 것 같습니다.

fffc는 그냥 wrap around되는 경우, heap size와 stack size를 더한 값이 0xffff보다 큰 0x10000 이 되었기 때문에

4byte를 뺀 원래의 값인 0xfffc로 stack의 end값을 지정하는 것 같네요.


444         movw    %ss, %dx
445         cmpw    %ax, %dx        # %ds == %ss?
446         movw    %sp, %dx
447         je      2f              # -> assume %sp is reasonably set
448 
449         # Invalid %ss, make up a new stack
450         movw    $_end, %dx
451         testb   $CAN_USE_HEAP, loadflags
452         jz      1f
453         movw    heap_end_ptr, %dx
454 1:      addw    $STACK_SIZE, %dx
455         jnc     2f
456         xorw    %dx, %dx        # Prevent wraparound
457 
458 2:      # Now %dx should point to the end of our stack space
459         andw    $~3, %dx        # dword align (might as well...)
460         jnz     3f
461         movw    $0xfffc, %dx    # Make sure we're not zero
462 3:      movw    %ax, %ss
463         movzwl  %dx, %esp       # Clear upper half of %esp
464         sti                     # Now we should have a working stack


XE Login