chain module: setbpb changes, bss & bs options, bugfixes
[profile/ivi/syslinux.git] / com32 / chain / utility.c
1 #include <com32.h>
2 #include <stdint.h>
3 #include <stdio.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <syslinux/disk.h>
8 #include "utility.h"
9
10 void error(const char *msg)
11 {
12     fputs(msg, stderr);
13 }
14
15 int guid_is0(const struct guid *guid)
16 {
17     return !*(const uint64_t *)guid && !*((const uint64_t *)guid+1);
18 }
19
20 void wait_key(void)
21 {
22     int cnt;
23     char junk;
24
25     /* drain */
26     do {
27         errno = 0;
28         cnt = read(0, &junk, 1);
29     } while (cnt > 0 || (cnt < 0 && errno == EAGAIN));
30
31     /* wait */
32     do {
33         errno = 0;
34         cnt = read(0, &junk, 1);
35     } while (!cnt || (cnt < 0 && errno == EAGAIN));
36 }
37
38 uint32_t lba2chs(const struct disk_info *di, uint64_t lba)
39 {
40     uint32_t c, h, s, t;
41
42     if (di->cbios) {
43         if (lba >= di->cyl * di->head * di->sect) {
44             s = di->sect;
45             h = di->head - 1;
46             c = di->cyl - 1;
47             goto out;
48         }
49         s = ((uint32_t)lba % di->sect) + 1;
50         t = (uint32_t)lba / di->sect;
51         h = t % di->head;
52         c = t / di->head;
53     } else
54         goto fallback;
55
56 out:
57     return h | (s << 8) | ((c & 0x300) << 6) | ((c & 0xFF) << 16);
58
59 fallback:
60     if (di->disk & 0x80)
61         return 0x00FFFFFE; /* 1023/63/254 */
62     else
63         /*
64          * adjust ?
65          * this is somewhat "useful" with partitioned floppy,
66          * maybe stick to 2.88mb ?
67          */
68         return 0x004F1201; /* 79/18/1 */
69 #if 0
70         return 0x004F2401; /* 79/36/1 */
71 #endif
72 }
73
74 uint32_t get_file_lba(const char *filename)
75 {
76     com32sys_t inregs;
77     uint32_t lba;
78
79     /* Start with clean registers */
80     memset(&inregs, 0, sizeof(com32sys_t));
81
82     /* Put the filename in the bounce buffer */
83     strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size);
84
85     /* Call comapi_open() which returns a structure pointer in SI
86      * to a structure whose first member happens to be the LBA.
87      */
88     inregs.eax.w[0] = 0x0006;
89     inregs.esi.w[0] = OFFS(__com32.cs_bounce);
90     inregs.es = SEG(__com32.cs_bounce);
91     __com32.cs_intcall(0x22, &inregs, &inregs);
92
93     if ((inregs.eflags.l & EFLAGS_CF) || inregs.esi.w[0] == 0) {
94         return 0;               /* Filename not found */
95     }
96
97     /* Since the first member is the LBA, we simply cast */
98     lba = *((uint32_t *) MK_PTR(inregs.ds, inregs.esi.w[0]));
99
100     /* Clean the registers for the next call */
101     memset(&inregs, 0, sizeof(com32sys_t));
102
103     /* Put the filename in the bounce buffer */
104     strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size);
105
106     /* Call comapi_close() to free the structure */
107     inregs.eax.w[0] = 0x0008;
108     inregs.esi.w[0] = OFFS(__com32.cs_bounce);
109     inregs.es = SEG(__com32.cs_bounce);
110     __com32.cs_intcall(0x22, &inregs, &inregs);
111
112     return lba;
113 }
114
115 /* drive offset detection */
116 int drvoff_detect(int type, unsigned int *off)
117 {
118     if (bpbV40 <= type && type <= bpbVNT) {
119         *off = 0x24;
120     } else if (type == bpbV70) {
121         *off = 0x40;
122     } else
123         return 0;
124
125     return -1;
126 }
127
128 /*
129  * heuristics could certainly be improved
130  */
131 int bpb_detect(const uint8_t *sec)
132 {
133     int a, b, c, jmp = -1, rev = -1;
134
135     /* media descriptor check */
136     if ((sec[0x15] & 0xF0) != 0xF0)
137         return -1;
138
139     if (sec[0] == 0xEB) /* jump short */
140         jmp = 2 + *(int8_t *)(sec + 1);
141     else if (sec[0] == 0xE9) /* jump near */
142         jmp = 3 + *(int16_t *)(sec + 1);
143
144     if (jmp < 0)    /* no boot code at all ? */
145         goto nocode;
146
147     /* sanity */
148     if (jmp < 0x18 || jmp > 0x1F0)
149         return -1;
150
151     /* detect by jump */
152     if (jmp >= 0x18 && jmp < 0x1E)
153         rev = bpbV20;
154     else if (jmp >= 0x1E && jmp < 0x20)
155         rev = bpbV30;
156     else if (jmp >= 0x20 && jmp < 0x24)
157         rev = bpbV32;
158     else if (jmp >= 0x24 && jmp < 0x46)
159         rev = bpbV34;
160
161     /* TODO: some better V2 - V3.4 checks ? */
162
163     if (rev >= 0)
164         return rev;
165
166 nocode:
167     a = memcmp(sec + 0x03, "NTFS", 4);
168     b = memcmp(sec + 0x36, "FAT", 3);
169     c = memcmp(sec + 0x52, "FAT", 3);   /* ext. DOS 7+ bs */
170
171     if ((sec[0x26] & 0xFE) == 0x28 && !b) {
172         rev = bpbV40;
173     } else if (sec[0x26] == 0x80 && !a) {
174         rev = bpbVNT;
175     } else if ((sec[0x42] & 0xFE) == 0x28 && !c) {
176         rev = bpbV70;
177     }
178
179     return rev;
180 }
181
182
183 /* vim: set ts=8 sts=4 sw=4 noet: */