summaryrefslogtreecommitdiff
path: root/bootblocks/relocate.c
blob: a2cced045a957316fc320d1b4d96961ade001349 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

#include "monitor.h"

static unsigned memseg = 0, memlen = 0;

char buf[1];

/* If newseg == 0x0000 => Lowest address CS=$50
 * If newseg == 0x0001 => DS to 64k position
 * If newseg == 0x0002 => DS to 128k position
 * ...
 * If newseg == 0x0009 => DS to 576k position
 * If newseg == 0xFFFF => Highest address leaving Linux-i386 clear.
 *
 * All others are literal, will fail if would overlap with something important.
 */

void
relocator(newseg)
unsigned newseg;
{
#ifdef __STANDALONE__
   unsigned moved, codelen;
   unsigned es      = __get_es();

   /* If running under DOS don't relocate */
   if (__argr.x.cflag) return;

   /* Where do we start */
   if(memseg == 0)
   {
      extern int _heap_top;
      memseg = __get_cs();
      codelen = __get_ds()-memseg;
      __set_es(memseg-2);

      memlen = (((int)&_heap_top) >> 4);

      /*
      if (__deek_es(0) == 0x0301 ) memlen = (__deek_es(24) >> 4);
      */

      if( memlen == 0 ) memlen = 0x1000;
      memlen += codelen;
      __set_es(es);
   }

   if( newseg == 0 ) newseg = 0x50;
   if( newseg > 0 && newseg < 10 )
   {
      newseg = (newseg<<12) - (__get_ds() - __get_cs());
   }
   if( newseg < 0x50 ) return;

   if( newseg == 0xFFFF )
   {
      newseg = boot_mem_top;
      if( newseg > 0x9000 ) newseg = 0x9000;
      newseg -= memlen;
   }

   /* If the old area overlaps the new then fail */
   if( newseg >= memseg && newseg < memseg+memlen ) return;
   if( memseg >= newseg && memseg < newseg+memlen ) return;

   /* Copy segments, done in 32k chunks */
   for(moved=0; moved < memlen; )
   {
       unsigned int lump;
       if( memlen-moved <= 0x800 ) lump = memlen-moved; else lump = 0x800;

       __movedata(memseg+moved, 0, newseg+moved, 0, (lump<<4));
       moved += lump;
   }

   /* re-link int 0x80, this one is only an example (used by 'standalone.c') */
   /* __set_es(0); __doke_es(0x80*4+2, newseg); __set_es(es); */

   /* The actual jump ... */
   memseg = newseg;

#asm
   mov	ax,ds
   mov	bx,cs
   sub	ax,bx
   mov	bx,[_memseg]
   add	ax,bx
   push bx
   call	L_x
   mov	ds,ax
   mov	ss,ax
   mov	[_memseg],bx
#endasm
}
#asm
L_x:
   retf
#endasm

#else
}
#endif