Skip to content

Commit 137aca5

Browse files
committed
backported more fixes from 256boss
1 parent 81c11bd commit 137aca5

29 files changed

+3734
-1
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ warn = -pedantic -Wall
1010
#opt = -O2
1111
dbg = -g
1212
inc = -Isrc -Isrc/libc -Isrc/test
13-
gccopt = -fno-pic -ffreestanding -nostdinc -fno-builtin
13+
gccopt = -fno-pic -ffreestanding -nostdinc -fno-builtin -ffast-math
1414

1515
CFLAGS = $(ccarch) -march=i386 $(warn) $(opt) $(dbg) $(gccopt) $(inc) $(def)
1616
ASFLAGS = $(asarch) -march=i386 $(dbg) -nostdinc -fno-builtin $(inc)

src/bootdev.c

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
/*
2+
pcboot - bootable PC demo/game kernel
3+
Copyright (C) 2018-2019 John Tsiombikas <[email protected]>
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY, without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
#include <stdio.h>
19+
#include <string.h>
20+
#include "bootdev.h"
21+
#include "boot.h"
22+
#include "int86.h"
23+
#include "panic.h"
24+
#include "timer.h"
25+
#include "floppy.h"
26+
27+
#define FLOPPY_MOTOR_OFF_TIMEOUT 4000
28+
#define DBG_RESET_ON_FAIL
29+
30+
struct chs {
31+
unsigned int cyl, head, tsect;
32+
};
33+
34+
struct disk_access {
35+
unsigned char pktsize;
36+
unsigned char zero;
37+
uint16_t num_sectors; /* max 127 on some implementations */
38+
uint16_t boffs, bseg;
39+
uint32_t lba_low, lba_high;
40+
} __attribute__((packed));
41+
42+
enum {OP_READ, OP_WRITE};
43+
44+
#ifdef DBG_RESET_ON_FAIL
45+
static int bios_reset_dev(int dev);
46+
#endif
47+
static int bios_rw_sect_lba(int dev, uint64_t lba, int nsect, int op, void *buf);
48+
static int bios_rw_sect_chs(int dev, struct chs *chs, int nsect, int op, void *buf);
49+
static int get_drive_chs(int dev, struct chs *chs);
50+
static void calc_chs(uint64_t lba, struct chs *chs);
51+
52+
static int have_bios_ext;
53+
static int bdev_is_floppy;
54+
static int num_cyl, num_heads, num_track_sect;
55+
56+
void bdev_init(void)
57+
{
58+
struct chs chs;
59+
struct int86regs regs;
60+
61+
memset(&regs, 0, sizeof regs);
62+
regs.eax = 0x4100; /* function 41h: check int 13h extensions */
63+
regs.ebx = 0x55aa;
64+
regs.edx = boot_drive_number;
65+
66+
int86(0x13, &regs);
67+
if((regs.flags & FLAGS_CARRY) || (regs.ecx & 1) == 0) {
68+
printf("BIOS does not support int13h extensions (LBA access)\n");
69+
have_bios_ext = 0;
70+
71+
if(get_drive_chs(boot_drive_number, &chs) == -1) {
72+
panic("drive (%d) parameter query failed\n", boot_drive_number);
73+
}
74+
75+
num_cyl = chs.cyl;
76+
num_heads = chs.head;
77+
num_track_sect = chs.tsect;
78+
79+
printf("Drive params: %d cyl, %d heads, %d sect/track\n", num_cyl,
80+
num_heads, num_track_sect);
81+
} else {
82+
printf("BIOS supports int13h extensions (LBA access)\n");
83+
have_bios_ext = 1;
84+
}
85+
86+
bdev_is_floppy = !(boot_drive_number & 0x80);
87+
}
88+
89+
#define NRETRIES 3
90+
91+
int bdev_read_sect(uint64_t lba, void *buf)
92+
{
93+
int i;
94+
struct chs chs;
95+
96+
if(bdev_is_floppy) {
97+
cancel_alarm(floppy_motors_off);
98+
set_alarm(FLOPPY_MOTOR_OFF_TIMEOUT, floppy_motors_off);
99+
}
100+
101+
if(have_bios_ext) {
102+
return bios_rw_sect_lba(boot_drive_number, lba, 1, OP_READ, buf);
103+
}
104+
105+
calc_chs(lba, &chs);
106+
107+
for(i=0; i<NRETRIES; i++) {
108+
if(bios_rw_sect_chs(boot_drive_number, &chs, 1, OP_READ, buf) != -1) {
109+
return 0;
110+
}
111+
#ifdef DBG_RESET_ON_FAIL
112+
bios_reset_dev(boot_drive_number);
113+
#endif
114+
}
115+
return -1;
116+
}
117+
118+
int bdev_write_sect(uint64_t lba, void *buf)
119+
{
120+
struct chs chs;
121+
122+
if(bdev_is_floppy) {
123+
cancel_alarm(floppy_motors_off);
124+
set_alarm(FLOPPY_MOTOR_OFF_TIMEOUT, floppy_motors_off);
125+
}
126+
127+
if(have_bios_ext) {
128+
return bios_rw_sect_lba(boot_drive_number, lba, 1, OP_WRITE, buf);
129+
}
130+
131+
calc_chs(lba, &chs);
132+
return bios_rw_sect_chs(boot_drive_number, &chs, 1, OP_WRITE, buf);
133+
}
134+
135+
int bdev_read_range(uint64_t lba, int nsect, void *buf)
136+
{
137+
int i;
138+
struct chs chs;
139+
140+
if(bdev_is_floppy) {
141+
cancel_alarm(floppy_motors_off);
142+
set_alarm(FLOPPY_MOTOR_OFF_TIMEOUT, floppy_motors_off);
143+
}
144+
145+
if(have_bios_ext) {
146+
return bios_rw_sect_lba(boot_drive_number, lba, nsect, OP_READ, buf);
147+
}
148+
149+
calc_chs(lba, &chs);
150+
151+
for(i=0; i<NRETRIES; i++) {
152+
int rd;
153+
if((rd = bios_rw_sect_chs(boot_drive_number, &chs, nsect, OP_READ, buf)) == nsect) {
154+
return 0;
155+
}
156+
157+
if(rd > 0) {
158+
nsect -= rd;
159+
buf = (char*)buf + rd * 512;
160+
lba += rd;
161+
calc_chs(lba, &chs);
162+
}
163+
164+
#ifdef DBG_RESET_ON_FAIL
165+
bios_reset_dev(boot_drive_number);
166+
#endif
167+
}
168+
return -1;
169+
}
170+
171+
int bdev_write_range(uint64_t lba, int nsect, void *buf)
172+
{
173+
struct chs chs;
174+
175+
if(bdev_is_floppy) {
176+
cancel_alarm(floppy_motors_off);
177+
set_alarm(FLOPPY_MOTOR_OFF_TIMEOUT, floppy_motors_off);
178+
}
179+
180+
if(have_bios_ext) {
181+
return bios_rw_sect_lba(boot_drive_number, lba, nsect, OP_WRITE, buf);
182+
}
183+
184+
calc_chs(lba, &chs);
185+
return bios_rw_sect_chs(boot_drive_number, &chs, nsect, OP_WRITE, buf);
186+
}
187+
188+
189+
#ifdef DBG_RESET_ON_FAIL
190+
static int bios_reset_dev(int dev)
191+
{
192+
struct int86regs regs;
193+
194+
printf("resetting drive %d ...", dev);
195+
196+
memset(&regs, 0, sizeof regs);
197+
regs.edx = dev;
198+
199+
int86(0x13, &regs);
200+
201+
printf("%s\n", (regs.flags & FLAGS_CARRY) ? "failed" : "done");
202+
203+
return (regs.flags & FLAGS_CARRY) ? -1 : 0;
204+
}
205+
#endif
206+
207+
static int bios_rw_sect_lba(int dev, uint64_t lba, int nsect, int op, void *buf)
208+
{
209+
struct int86regs regs;
210+
struct disk_access *dap = (struct disk_access*)low_mem_buffer;
211+
uint32_t addr = (uint32_t)low_mem_buffer;
212+
uint32_t xaddr = (addr + sizeof *dap + 15) & 0xfffffff0;
213+
void *xbuf = (void*)xaddr;
214+
int func;
215+
216+
if(op == OP_READ) {
217+
func = 0x42; /* function 42h: extended read sector (LBA) */
218+
} else {
219+
func = 0x43; /* function 43h: extended write sector (LBA) */
220+
memcpy(xbuf, buf, nsect * 512);
221+
}
222+
223+
dap->pktsize = sizeof *dap;
224+
dap->zero = 0;
225+
dap->num_sectors = nsect;
226+
dap->boffs = 0;
227+
dap->bseg = xaddr >> 4;
228+
dap->lba_low = (uint32_t)lba;
229+
dap->lba_high = (uint32_t)(lba >> 32);
230+
231+
memset(&regs, 0, sizeof regs);
232+
regs.eax = func << 8;
233+
regs.ds = addr >> 4;
234+
regs.esi = 0;
235+
regs.edx = dev;
236+
237+
int86(0x13, &regs);
238+
239+
if(regs.flags & FLAGS_CARRY) {
240+
return -1;
241+
}
242+
243+
if(op == OP_READ) {
244+
memcpy(buf, xbuf, nsect * 512);
245+
}
246+
return dap->num_sectors;
247+
}
248+
249+
/* TODO: fix: probably can't cross track boundaries, clamp nsect accordingly
250+
* and return a short count
251+
*/
252+
static int bios_rw_sect_chs(int dev, struct chs *chs, int nsect, int op, void *buf)
253+
{
254+
struct int86regs regs;
255+
uint32_t xaddr = (uint32_t)low_mem_buffer;
256+
int func;
257+
258+
if(op == OP_READ) {
259+
func = 2;
260+
} else {
261+
func = 3;
262+
memcpy(low_mem_buffer, buf, nsect * 512);
263+
}
264+
265+
memset(&regs, 0, sizeof regs);
266+
regs.eax = (func << 8) | nsect; /* 1 sector */
267+
regs.es = xaddr >> 4; /* es:bx buffer */
268+
regs.ecx = ((chs->cyl << 8) & 0xff00) | ((chs->cyl >> 10) & 0xc0) | chs->tsect;
269+
regs.edx = dev | (chs->head << 8);
270+
271+
int86(0x13, &regs);
272+
273+
if(regs.flags & FLAGS_CARRY) {
274+
return -1;
275+
}
276+
277+
if(op == OP_READ) {
278+
memcpy(buf, low_mem_buffer, nsect * 512);
279+
}
280+
return nsect;
281+
}
282+
283+
static int get_drive_chs(int dev, struct chs *chs)
284+
{
285+
struct int86regs regs;
286+
287+
memset(&regs, 0, sizeof regs);
288+
regs.eax = 0x800;
289+
regs.edx = dev;
290+
291+
int86(0x13, &regs);
292+
293+
if(regs.flags & FLAGS_CARRY) {
294+
return -1;
295+
}
296+
297+
chs->cyl = (((regs.ecx >> 8) & 0xff) | ((regs.ecx << 2) & 0x300)) + 1;
298+
chs->head = (regs.edx >> 8) + 1;
299+
chs->tsect = regs.ecx & 0x3f;
300+
return 0;
301+
}
302+
303+
static void calc_chs(uint64_t lba, struct chs *chs)
304+
{
305+
uint32_t lba32, trk;
306+
307+
if(lba >> 32) {
308+
/* XXX: 64bit ops require libgcc, and I don't want to link that for
309+
* this. CHS I/O is only going to be for floppies and really old systems
310+
* anyway, so there's no point in supporting anything more than LBA32 in
311+
* the translation.
312+
*/
313+
const char *fmt = "calc_chs only supports 32bit LBA. requested: %llx\n"
314+
"If you see this message, please file a bug report at:\n"
315+
" https://github.com/jtsiomb/256boss/issues\n"
316+
" or by email: [email protected]\n";
317+
panic(fmt, lba);
318+
}
319+
320+
lba32 = (uint32_t)lba;
321+
trk = lba32 / num_track_sect;
322+
chs->tsect = (lba32 % num_track_sect) + 1;
323+
chs->cyl = trk / num_heads;
324+
chs->head = trk % num_heads;
325+
}

src/bootdev.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
pcboot - bootable PC demo/game kernel
3+
Copyright (C) 2018-2019 John Tsiombikas <[email protected]>
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY, without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
#ifndef BOOTDEV_H_
19+
#define BOOTDEV_H_
20+
21+
void bdev_init(void);
22+
23+
int bdev_read_sect(uint64_t lba, void *buf);
24+
int bdev_write_sect(uint64_t lba, void *buf);
25+
26+
int bdev_read_range(uint64_t lba, int nsect, void *buf);
27+
int bdev_write_range(uint64_t lba, int nsect, void *buf);
28+
29+
#endif /* BOOTDEV_H_ */

src/floppy.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
pcboot - bootable PC demo/game kernel
3+
Copyright (C) 2018-2019 John Tsiombikas <[email protected]>
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY, without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
#include <stdio.h>
19+
#include "floppy.h"
20+
#include "asmops.h"
21+
22+
void floppy_motors_off(void)
23+
{
24+
unsigned char dout = inb(FDC_REG_DOUT);
25+
outb(dout & 0xf, FDC_REG_DOUT);
26+
}

0 commit comments

Comments
 (0)