summaryrefslogtreecommitdiff
path: root/src/cpu/amd/car/copy_and_run.c
blob: 55068c5511567de0abf49b8b18c41d42adf4ee71 (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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* by yhlu 6.2005 
	moved from nrv2v.c and some lines from crt0.S
*/
#ifndef ENDIAN
#define ENDIAN   0
#endif
#ifndef BITSIZE
#define BITSIZE 32
#endif

#define GETBIT_8(bb, src, ilen) \
    (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1)

#define GETBIT_LE16(bb, src, ilen) \
    (bb*=2,bb&0xffff ? (bb>>16)&1 : (ilen+=2,((bb=(src[ilen-2]+src[ilen-1]*256u)*2+1)>>16)&1))

#define GETBIT_LE32(bb, src, ilen) \
    (bc > 0 ? ((bb>>--bc)&1) : (bc=31,\
    bb=*(const uint32_t *)((src)+ilen),ilen+=4,(bb>>31)&1))

#if ENDIAN == 0 && BITSIZE == 8
#define GETBIT(bb, src, ilen) GETBIT_8(bb, src, ilen)
#endif
#if ENDIAN == 0 && BITSIZE == 16
#define GETBIT(bb, src, ilen) GETBIT_LE16(bb, src, ilen)
#endif
#if ENDIAN == 0 && BITSIZE == 32
#define GETBIT(bb, src, ilen) GETBIT_LE32(bb, src, ilen)
#endif

static inline void print_debug_cp_run(const char *strval, uint32_t val)
{
#if CONFIG_USE_INIT
        printk_debug("%s%08x\r\n", strval, val);
#else
        print_debug(strval); print_debug_hex32(val); print_debug("\r\n");
#endif
}

static void copy_and_run(unsigned cpu_reset)
{
	uint8_t *src, *dst; 
        unsigned long ilen = 0, olen = 0, last_m_off =  1;
        uint32_t bb = 0;
        unsigned bc = 0;

	print_debug("Copying LinuxBIOS to ram.\r\n");

#if !CONFIG_COMPRESS 
	__asm__ volatile (
		"leal _liseg, %0\n\t"
		"leal _iseg, %1\n\t"
		"leal _eiseg, %2\n\t"
		"subl %1, %2\n\t"
		: "=a" (src), "=b" (dst), "=c" (olen)
	);
	memcpy(src, dst, olen);
#else 

        __asm__ volatile (
	        "leal  4+_liseg, %0\n\t"
	        "leal    _iseg,  %1\n\t"
                : "=a" (src) , "=b" (dst)
        );

	print_debug_cp_run("src=",(uint32_t)src); 
	print_debug_cp_run("dst=",(uint32_t)dst);
	
//	dump_mem(src, src+0x100);

        for(;;) {
                unsigned int m_off, m_len;
                while(GETBIT(bb, src, ilen)) {
                        dst[olen++] = src[ilen++];
                }
                m_off = 1;
                do {
                        m_off = m_off*2 + GETBIT(bb, src, ilen);
                } while (!GETBIT(bb, src, ilen));
                if (m_off == 2)
                {
                        m_off = last_m_off;
                }
                else
                {
                        m_off = (m_off - 3)*256 + src[ilen++];
                        if(m_off == 0xffffffffU) 
                                break;
                        last_m_off = ++m_off;
                }
                m_len = GETBIT(bb, src, ilen);
                m_len = m_len*2 + GETBIT(bb, src, ilen);
                if (m_len == 0)
                {
                        m_len++;
                        do {
                                m_len = m_len*2 + GETBIT(bb, src, ilen);
                        } while(!GETBIT(bb, src, ilen));
                        m_len += 2;
                }
                m_len += (m_off > 0xd00);
                {
                        const uint8_t *m_pos;
                        m_pos = dst + olen - m_off;
                        dst[olen++] = *m_pos++;
                        do {
                                dst[olen++] = *m_pos++;
                        } while(--m_len > 0);
                }
        }
#endif
//	dump_mem(dst, dst+0x100);

	print_debug_cp_run("linxbios_ram.bin length = ", olen);

	print_debug("Jumping to LinuxBIOS.\r\n");

	if(cpu_reset == 1 ) {
		__asm__ volatile (
			"movl $0xffffffff, %ebp\n\t"
		);
	}
	else {
                __asm__ volatile (
                        "xorl %ebp, %ebp\n\t"
                );
	}
	
	__asm__ volatile (
		"cli\n\t"
		"leal    _iseg, %edi\n\t"
		"jmp     *%edi\n\t"
	);

}