Rename MAKE_FARPTR (and similar) to MAKE_FLATPTR.
[seabios.git] / src / util.c
1 // Misc utility functions.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "util.h" // usleep
8 #include "bregs.h" // struct bregs
9 #include "config.h" // SEG_BIOS
10 #include "farptr.h" // GET_FLATPTR
11 #include "biosvar.h" // get_ebda_seg
12
13 // Call a function with a specified register state.  Note that on
14 // return, the interrupt enable/disable flag may be altered.
15 inline void
16 call16(struct bregs *callregs)
17 {
18     asm volatile(
19 #if MODE16 == 1
20         "calll __call16\n"
21 #else
22         "calll __call16_from32\n"
23 #endif
24         : "+a" (callregs), "+m" (*callregs)
25         :
26         : "ebx", "ecx", "edx", "esi", "edi", "ebp", "cc", "memory");
27 }
28
29 inline void
30 call16big(struct bregs *callregs)
31 {
32     extern void __force_link_error__call16big_only_in_32bit_mode();
33     if (MODE16)
34         __force_link_error__call16big_only_in_32bit_mode();
35
36     asm volatile(
37         "calll __call16big_from32\n"
38         : "+a" (callregs), "+m" (*callregs)
39         :
40         : "ebx", "ecx", "edx", "esi", "edi", "ebp", "cc", "memory");
41 }
42
43 inline void
44 __call16_int(struct bregs *callregs, u16 offset)
45 {
46     callregs->cs = SEG_BIOS;
47     callregs->ip = offset;
48     call16(callregs);
49 }
50
51 inline void
52 call16_simpint(int nr, u32 *eax, u32 *flags)
53 {
54     extern void __force_link_error__call16_simpint_only_in_16bit_mode();
55     if (!MODE16)
56         __force_link_error__call16_simpint_only_in_16bit_mode();
57
58     asm volatile(
59         "stc\n"
60         "int %2\n"
61         "pushfl\n"
62         "popl %1\n"
63         "cld\n"
64         "cli\n"
65         : "+a"(*eax), "=r"(*flags)
66         : "i"(nr)
67         : "cc", "memory");
68 }
69
70 // Switch to the extra stack in ebda and call a function.
71 inline u32
72 stack_hop(u32 eax, u32 edx, u32 ecx, void *func)
73 {
74     extern void __force_link_error__stack_hop_only_in_16bit_mode();
75     if (!MODE16)
76         __force_link_error__stack_hop_only_in_16bit_mode();
77
78     u16 ebda_seg = get_ebda_seg(), bkup_ss;
79     u32 bkup_esp;
80     asm volatile(
81         // Backup current %ss/%esp values.
82         "movw %%ss, %w3\n"
83         "movl %%esp, %4\n"
84         // Copy ebda seg to %ds/%ss and set %esp
85         "movw %w6, %%ds\n"
86         "movw %w6, %%ss\n"
87         "movl %5, %%esp\n"
88         // Call func
89         "calll %7\n"
90         // Restore segments and stack
91         "movw %w3, %%ds\n"
92         "movw %w3, %%ss\n"
93         "movl %4, %%esp\n"
94         : "+a" (eax), "+d" (edx), "+c" (ecx), "=&r" (bkup_ss), "=&r" (bkup_esp)
95         : "i" (EBDA_OFFSET_TOP_STACK), "r" (ebda_seg), "m" (*(u8*)func)
96         : "cc", "memory");
97     return eax;
98 }
99
100 // Sum the bytes in the specified area.
101 u8
102 checksum(u8 *buf_fl, u32 len)
103 {
104     u32 i;
105     u8 sum = 0;
106     for (i=0; i<len; i++)
107         sum += GET_FLATPTR(buf_fl[i]);
108     return sum;
109 }
110
111 void *
112 memset(void *s, int c, size_t n)
113 {
114     while (n)
115         ((char *)s)[--n] = c;
116     return s;
117 }
118
119 void *
120 memcpy_fl(void *d_fl, const void *s_fl, size_t len)
121 {
122     u8 *d = d_fl;
123     u8 *s = (u8*)s_fl;
124
125     while (len--) {
126         SET_FLATPTR(*d, GET_FLATPTR(*s));
127         d++;
128         s++;
129     }
130
131     return d_fl;
132 }
133
134 void *
135 memcpy(void *d1, const void *s1, size_t len)
136 {
137     u8 *d = (u8*)d1, *s = (u8*)s1;
138     while (len--)
139         *d++ = *s++;
140     return d1;
141 }
142
143 void *
144 memmove(void *d, const void *s, size_t len)
145 {
146     if (s >= d)
147         return memcpy(d, s, len);
148
149     d += len-1;
150     s += len-1;
151     while (len--) {
152         *(char*)d = *(char*)s;
153         d--;
154         s--;
155     }
156
157     return d;
158 }