2 * bootsect.S - boot sector for NEC PC-9800 series
4 * Linux/98 project at Kyoto University Microcomputer Club (KMC)
5 * FUJITA Norimasa, TAKAI Kousuke 1997-1998
6 * rewritten by TAKAI Kousuke (as86 -> gas), Nov 1999
9 * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds
10 * modified by Drew Eckhardt
11 * modified by Bruce Evans (bde)
13 * bootsect.S is loaded at 0x1FC00 or 0x1FE00 by the bios-startup routines,
14 * and moves itself out of the way to address 0x90000, and jumps there.
16 * It then loads 'setup' directly after itself (0x90200), and the system
17 * at 0x10000, using BIOS interrupts.
19 * NOTE! currently system is at most (8*65536-4096) bytes long. This should
20 * be no problem, even in the future. I want to keep it simple. This 508 kB
21 * kernel size should be enough, especially as this doesn't contain the
22 * buffer cache as in minix (and especially now that the kernel is
25 * The loader has been made as simple as possible, and continuous
26 * read errors will result in a unbreakable loop. Reboot by hand. It
27 * loads pretty fast by getting whole tracks at a time whenever possible.
30 #include <linux/config.h> /* for CONFIG_ROOT_RDONLY */
33 SETUPSECTS = 4 /* default nr of setup-sectors */
34 BOOTSEG = 0x1FC0 /* original address of boot-sector */
35 INITSEG = DEF_INITSEG /* we move boot here - out of the way */
36 SETUPSEG = DEF_SETUPSEG /* setup starts here */
37 SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */
38 SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */
40 ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
41 SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */
44 #define SVGA_MODE ASK_VGA
55 /* normal/hireso text VRAM segments */
56 #define NORMAL_TEXT 0xa000
57 #define HIRESO_TEXT 0xe000
59 /* bios work area addresses */
60 #define EXPMMSZ 0x0401
61 #define BIOS_FLAG 0x0501
62 #define DISK_BOOT 0x0584
70 #if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */
77 xorw %di, %di /* %di = 0 */
78 movw %di, %ss /* %ss = 0 */
80 pushw %cx /* for hint */
82 movw $0x0A00, %ax /* normal mode defaults (80x25) */
84 testb $0x08, %ss:BIOS_FLAG /* check hi-reso bit */
87 * Hi-Reso (high-resolution) machine.
89 * Some hi-reso machines have no RAMs on bank 8/A (0x080000 - 0x0BFFFF).
90 * On such machines we get two RAM banks from top of protect menory and
91 * map them on bank 8/A.
92 * These work-around must be done before moving myself on INITSEG (0x090000-).
94 movw $(HIRESO_TEXT >> 8), %cs:(vram + 1) /* text VRAM segment */
96 /* set memory window */
98 outb %al, $0x91 /* map native RAM (if any) */
102 /* check bank ram A */
105 movw (%di), %cx /* %si == 0 from entry */
109 movw $0x43F, %dx /* cache flush for 486 and up. */
117 * Write test failed; we have no native RAM on 080000h - 0BFFFFh.
118 * Take 256KB of RAM from top of protected memory.
120 movb %ss:EXPMMSZ, %al
121 subb $2, %al /* reduce 2 x 128KB */
122 movb %al, %ss:EXPMMSZ
130 movb $0x10, %al /* CRT mode 80x31, %ah still 0Ah */
133 int $0x18 /* set CRT mode */
135 movb $0x0C, %ah /* turn on text displaying */
138 xorw %dx, %dx /* position cursor to home */
142 movb $0x11, %ah /* turn cursor displaying on */
145 /* move 1 kilobytes from [BOOTSEG:0000h] to [INITSEG:0000h] */
150 movw $512, %cx /* %di == 0 from entry */
159 popw %ds /* %ds = %cs */
161 popw %dx /* %dh = saved %ch passed from BIOS */
162 movb %ss:DISK_BOOT, %al
163 andb $0xf0, %al /* %al = Device Address */
164 movb $18, %ch /* 18 secs/track, 512 b/sec (1440 KB) */
167 cmpb $0x90, %al /* 1 MB I/F, 1 MB floppy */
169 cmpb $0xf0, %al /* 640 KB I/F, 1 MB floppy */
171 movb $9, %ch /* 9 secs/track, 512 b/sec ( 720 KB) */
172 cmpb $0x10, %al /* 1 MB I/F, 640 KB floppy */
174 cmpb $0x70, %al /* 640 KB I/F, 640 KB floppy */
175 jne error /* unknown device? */
177 /* XXX: Does it make sense to support 8 secs/track, 512 b/sec
180 try512: movb $2, %cl /* 512 b/sec */
183 * Display error message and halt
185 error: movw $error_msg, %si
189 int $0x18 /* wait keyboard input */
191 outb %al, $0xF0 /* reset CPU */
192 jmp 1b /* just in case... */
196 movw $0x0803, %cx /* 8 secs/track, 1024 b/sec (1232 KB) */
198 movb $15, %ch /* 15 secs/track, 512 b/sec (1200 KB) */
200 try2HC: movw $0x0F02, %cx /* 15 secs/track, 512 b/sec (1200 KB) */
202 movw $0x0803, %cx /* 8 secs/track, 1024 b/sec (1232 KB) */
206 * Try to load SETUP and SYSTEM provided geometry information in %cx.
207 * This routine *will not* return on successful load...
211 movb %ss:DISK_BOOT, %al
212 movb $0x7, %ah /* recalibrate the drive */
214 jc error /* recalibration should succeed */
217 * Load SETUP into memory. It is assumed that SETUP fits into
218 * first cylinder (2 tracks, 9KB on 2DD, 15-18KB on 2HD).
221 movb setup_sects, %bh
223 shlw %bx /* %bx = (setup_sects + 1) * 512 */
225 shlw %cl, %bp /* %bp = <sector size> */
226 subw %bp, %bx /* length to load */
227 movw $0x0002, %dx /* head 0, sector 2 */
228 movb %cl, %ch /* `N' for sector address */
229 movb $0, %cl /* cylinder 0 */
231 popw %es /* %es = %cs (= INITSEG) */
232 movb $0xd6, %ah /* read, multi-track, MFM */
233 int $0x1b /* load it! */
236 movw $loading_msg, %si
240 movw %ax, %es /* %es = SYSSEG */
243 * This routine loads the system at address 0x10000, making sure
244 * no 64kB boundaries are crossed. We try to load it as fast as
245 * possible, loading whole tracks whenever we can.
247 * in: es - starting address segment (normally 0x1000)
250 addb $7, %cl /* %cl = log2 <sector_size> */
251 shrw %cl, %bx /* %bx = # of phys. sectors in SETUP */
252 addb %bl, %dl /* %dl = start sector # of SYSTEM */
253 decb %dl /* %dl is 0-based in below loop */
256 xorw %bp, %bp /* = starting address within segment */
257 #ifdef __BIG_KERNEL__
258 bootsect_kludge = 0x220 /* 0x200 (size of bootsector) + 0x20 (offset */
259 lcall *bootsect_kludge /* of bootsect_kludge in setup.S */
270 movb %al, %ch /* # of sectors on both surface */
271 subb %dl, %al /* # of sectors left on this track */
273 shlw %cl, %ax /* # of bytes left on this track */
274 movw %ax, %bx /* transfer length */
275 addw %bp, %ax /* cross 64K boundary? */
279 * Oops, we are crossing 64K boundary...
280 * Adjust transfer length to make transfer fit in the boundary.
282 * Note: sector size is assumed to be a measure of 65536.
287 movw $dot_msg, %si /* give progress message */
293 xchgw %ax, %dx /* %dh = head # / %dl = sector # */
294 incb %dl /* fix %dl to 1-based */
297 movb $0xd6, %ah /* read, multi-track, seek, MFM */
298 movb %ss:DISK_BOOT, %al
303 movw %bx, %ax /* # of bytes just read */
304 shrw %cl, %ax /* %ax = # of sectors just read */
305 addb %al, %dl /* advance sector # */
306 cmpb %ch, %dl /* %ch = # of sectors/cylinder */
308 incb cylinder /* next cylinder */
309 xorb %dl, %dl /* sector 0 */
310 2: addw %bx, %bp /* advance offset pointer */
312 /* offset pointer wrapped; advance segment pointer. */
321 boot: movw %cs, %ax /* = INITSEG */
324 movw $0x4000, %sp /* 0x4000 is arbitrary value >=
325 * length of bootsect + length of
326 * setup + room for stack;
327 * PC-9800 never have BIOS workareas
331 * After that we check which root-device to use. If the device is
332 * not defined, /dev/fd0 (2, 0) will be used.
340 * After that (everything loaded), we jump to the setup-routine
341 * loaded directly after the bootblock:
346 * Subroutine for print string on console.
347 * %cs:%si - pointer to message
355 lesw curpos, %di /* %es:%di = current text VRAM addr. */
359 jz 2f /* end of string */
360 stosw /* character code */
361 movb $0xE1, %es:0x2000-2(%di) /* character attribute */
365 int $0x18 /* move cursor to current point */
376 .string "Read Error!"
380 curpos: .word 160 /* current cursor position */
381 vram: .word NORMAL_TEXT /* text VRAM segment */
383 cylinder: .byte 0 /* current cylinder (lower byte) */
384 sectlen: .byte 0 /* (log2 of <sector size>) - 7 */
385 sectors: .byte 0x0F /* default is 2HD (15 sector/track) */
387 # XXX: This is a fairly snug fit.
390 setup_sects: .byte SETUPSECTS
391 root_flags: .word ROOT_RDONLY
392 syssize: .word SYSSIZE
393 swap_dev: .word SWAP_DEV
394 ram_size: .word RAMDISK
395 vid_mode: .word SVGA_MODE
396 root_dev: .word ROOT_DEV
397 boot_flag: .word 0xAA55