relocate.c
Go to the documentation of this file.00001 #include <gpxe/io.h>
00002 #include <registers.h>
00003 #include <gpxe/memmap.h>
00004
00005
00006
00007
00008
00009
00010
00011
00012 FILE_LICENCE ( GPL2_OR_LATER );
00013
00014
00015
00016
00017
00018
00019 extern char _max_align[];
00020 #define max_align ( ( unsigned int ) _max_align )
00021
00022
00023 extern char _textdata[];
00024 extern char _etextdata[];
00025
00026
00027
00028
00029
00030
00031
00032 #define MAX_ADDR (0xfff00000UL)
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 __asmcall void relocate ( struct i386_all_regs *ix86 ) {
00045 struct memory_map memmap;
00046 unsigned long start, end, size, padded_size;
00047 unsigned long new_start, new_end;
00048 unsigned i;
00049
00050
00051 get_memmap ( &memmap );
00052 start = virt_to_phys ( _textdata );
00053 end = virt_to_phys ( _etextdata );
00054 size = ( end - start );
00055 padded_size = ( size + max_align - 1 );
00056
00057 DBG ( "Relocate: currently at [%lx,%lx)\n"
00058 "...need %lx bytes for %d-byte alignment\n",
00059 start, end, padded_size, max_align );
00060
00061
00062
00063
00064
00065
00066
00067
00068 new_end = end;
00069 for ( i = 0 ; i < memmap.count ; i++ ) {
00070 struct memory_region *region = &memmap.regions[i];
00071 unsigned long r_start, r_end;
00072
00073 DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
00074
00075
00076
00077
00078
00079 if ( region->start > MAX_ADDR ) {
00080 DBG ( "...starts after MAX_ADDR=%lx\n", MAX_ADDR );
00081 continue;
00082 }
00083 r_start = region->start;
00084 if ( region->end > MAX_ADDR ) {
00085 DBG ( "...end truncated to MAX_ADDR=%lx\n", MAX_ADDR );
00086 r_end = MAX_ADDR;
00087 } else {
00088 r_end = region->end;
00089 }
00090
00091
00092
00093
00094 if ( ( r_end - 1 ) & 0x100000 ) {
00095
00096
00097
00098
00099
00100
00101
00102 if ( r_end >= 1 ) {
00103 r_end = ( r_end - 1 ) & ~0xfffff;
00104 DBG ( "...end truncated to %lx "
00105 "(avoid ending in odd megabyte)\n",
00106 r_end );
00107 }
00108 } else if ( ( r_end - size ) & 0x100000 ) {
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 if ( r_end >= 0x100000 ) {
00119 r_end = ( r_end - 0x100000 ) & ~0xfffff;
00120 DBG ( "...end truncated to %lx "
00121 "(avoid starting in odd megabyte)\n",
00122 r_end );
00123 }
00124 }
00125
00126 DBG ( "...usable portion is [%lx,%lx)\n", r_start, r_end );
00127
00128
00129
00130
00131 if ( r_end < r_start ) {
00132 DBG ( "...truncated to negative size\n" );
00133 continue;
00134 }
00135
00136
00137 if ( ( r_end - r_start ) < size ) {
00138 DBG ( "...too small (need %lx bytes)\n", size );
00139 continue;
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 if ( ( r_end - size ) > new_end ) {
00151 new_end = r_end;
00152 DBG ( "...new best block found.\n" );
00153 }
00154 }
00155
00156
00157
00158
00159 new_start = new_end - padded_size;
00160 new_start += ( start - new_start ) & ( max_align - 1 );
00161 new_end = new_start + size;
00162
00163 DBG ( "Relocating from [%lx,%lx) to [%lx,%lx)\n",
00164 start, end, new_start, new_end );
00165
00166
00167 ix86->regs.esi = start;
00168 ix86->regs.edi = new_start;
00169 ix86->regs.ecx = size;
00170 }