| 1 | /* |
| 2 | * sys/i386/stand/asbootblk.c |
| 3 | * |
| 4 | * Boot block for Adaptech 1542 SCSI |
| 5 | * |
| 6 | * April 10, 1992 |
| 7 | * Pace Willisson |
| 8 | * pace@blitz.com |
| 9 | * |
| 10 | * Placed in the public domain with NO WARRANTIES, not even the |
| 11 | * implied warranties for MERCHANTABILITY or FITNESS FOR A |
| 12 | * PARTICULAR PURPOSE. |
| 13 | * |
| 14 | * To compile: |
| 15 | * |
| 16 | * cc -O -c -DRELOC=0x70000 asbootblk.c |
| 17 | * ld -N -T 7c00 asbootblk.o |
| 18 | * |
| 19 | * This should result in a file with 512 bytes of text and no initialized |
| 20 | * data. Strip the 32 bit header and place in block 0. |
| 21 | * |
| 22 | * When run, this program copies at least the first 8 blocks of SCSI |
| 23 | * target 0 to the address specified by RELOC, then jumps to the |
| 24 | * address RELOC+1024 (skipping the boot block and disk label). Usually, |
| 25 | * disks have 512 bytes per block, but I don't think they ever have |
| 26 | * less, and it wont hurt if they are bigger, as long as RELOC + 8*SIZE |
| 27 | * is less than 0xa0000. |
| 28 | * |
| 29 | * This bootblock does not support fdisk partitions, and can only be used |
| 30 | * as the master boot block. |
| 31 | * |
| 32 | * from: 386BSD 0.1 |
| 33 | * $Id$ |
| 34 | */ |
| 35 | |
| 36 | #include "param.h" |
| 37 | #include "disklabel.h" |
| 38 | #include "i386/isa/asreg.h" |
| 39 | |
| 40 | /* RELOC should be defined with a -D flag to cc */ |
| 41 | |
| 42 | #define SECOND_LEVEL_BOOT_START (RELOC + 0x400) |
| 43 | #define READ_SIZE 8192 |
| 44 | |
| 45 | #define as_port 0x330 |
| 46 | #define target 0 |
| 47 | |
| 48 | |
| 49 | #define NBLOCKS (READ_SIZE / 512) /* how many logical blocks to read */ |
| 50 | |
| 51 | |
| 52 | /* These are the parameters to pass to the second level boot */ |
| 53 | #define dev 4 /* major device number of as driver in |
| 54 | i386/stand/conf.c and i386/i386/conf.c */ |
| 55 | #define unit 0 /* partition number of root file system */ |
| 56 | #define off 0 /* block offset of root file system */ |
| 57 | |
| 58 | /* inline i/o borrowed from Roell X server */ |
| 59 | static __inline__ void |
| 60 | outb(port, val) |
| 61 | short port; |
| 62 | char val; |
| 63 | { |
| 64 | __asm__ volatile("outb %%al, %1" : :"a" (val), "d" (port)); |
| 65 | } |
| 66 | |
| 67 | static __inline__ unsigned int |
| 68 | inb(port) |
| 69 | short port; |
| 70 | { |
| 71 | unsigned int ret; |
| 72 | __asm__ volatile("xorl %%eax, %%eax; inb %1, %%al" |
| 73 | : "=a" (ret) : "d" (port)); |
| 74 | return ret; |
| 75 | } |
| 76 | |
| 77 | /* this code is linked at 0x7c00 and is loaded there by the BIOS */ |
| 78 | |
| 79 | asm (" |
| 80 | /* we're running in 16 real mode, so normal assembly doesn't work */ |
| 81 | bootbase: |
| 82 | /* interrupts off */ |
| 83 | cli |
| 84 | |
| 85 | /* load gdt */ |
| 86 | .byte 0x2e,0x0f,0x01,0x16 /* lgdt %cs:$imm */ |
| 87 | .word _gdtarg + 2 |
| 88 | |
| 89 | /* turn on protected mode */ |
| 90 | smsw %ax |
| 91 | orb $1,%al |
| 92 | lmsw %ax |
| 93 | |
| 94 | /* flush prefetch queue and reload %cs */ |
| 95 | .byte 0xea /* ljmp $8, flush */ |
| 96 | .word flush |
| 97 | .word 8 |
| 98 | |
| 99 | flush: |
| 100 | /* now running in 32 bit mode */ |
| 101 | movl $0x10,%eax |
| 102 | movl %ax,%ds |
| 103 | movl %ax,%es |
| 104 | movl %ax,%ss |
| 105 | movl $0x7c00,%esp |
| 106 | call _main |
| 107 | "); /* end of asm */ |
| 108 | |
| 109 | const char gdt[] = { |
| 110 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 111 | 0xff, 0xff, 0, 0, 0, 0x9f, 0xcf, 0, /* code segment */ |
| 112 | 0xff, 0xff, 0, 0, 0, 0x93, 0xcf, 0, /* data segment */ |
| 113 | }; |
| 114 | |
| 115 | const struct { |
| 116 | short filler; |
| 117 | short size; |
| 118 | const char *gdt; |
| 119 | } gdtarg = { 0, sizeof gdt - 1, gdt }; |
| 120 | |
| 121 | #define CRTBASE ((char *)0xb8000) |
| 122 | #define CHECKPOINT(x) (CRTBASE[0] = x) |
| 123 | |
| 124 | volatile struct mailbox_entry mailbox[2]; |
| 125 | const char ccb[] = { |
| 126 | 0, /* opcode: normal read/write */ |
| 127 | (target << 5) | 8, /* target num and read flag */ |
| 128 | 10, /* scsi cmd len */ |
| 129 | 1, /* no automatic request for sense */ |
| 130 | READ_SIZE >> 16, /* data length */ |
| 131 | READ_SIZE >> 8, |
| 132 | READ_SIZE, |
| 133 | RELOC >> 16, /* data pointer */ |
| 134 | RELOC >> 8, |
| 135 | RELOC, |
| 136 | 0, 0, 0, /* link pointer */ |
| 137 | 0, /* link id */ |
| 138 | 0, /* host status */ |
| 139 | 0, /* target status */ |
| 140 | 0, 0, /* reserved */ |
| 141 | |
| 142 | /* scsi cdb */ |
| 143 | 0x28, /* read opcode */ |
| 144 | 0, /* logical unit number */ |
| 145 | 0, 0, 0, 0, /* logical block address */ |
| 146 | 0, /* reserved */ |
| 147 | 0, NBLOCKS, /* transfer length */ |
| 148 | 0, /* link control */ |
| 149 | }; |
| 150 | |
| 151 | int (*f)(); |
| 152 | |
| 153 | main () |
| 154 | { |
| 155 | int i; |
| 156 | extern char edata[], end[]; |
| 157 | char volatile * volatile p, *q; |
| 158 | int physaddr; |
| 159 | |
| 160 | CHECKPOINT ('a'); |
| 161 | |
| 162 | /* clear bss */ |
| 163 | for (p = edata; p < end; p++) |
| 164 | *p = 0; |
| 165 | |
| 166 | f = (int (*)())SECOND_LEVEL_BOOT_START; |
| 167 | |
| 168 | /* dma setup: see page 5-31 in the Adaptech manual */ |
| 169 | /* this knows we are using drq 5 */ |
| 170 | outb (0xd6, 0xc1); |
| 171 | outb (0xd4, 0x01); |
| 172 | |
| 173 | outb (as_port + AS_CONTROL, AS_CONTROL_SRST); |
| 174 | |
| 175 | /* delay a little */ |
| 176 | inb (0x84); |
| 177 | |
| 178 | while (inb (as_port + AS_STATUS) != (AS_STATUS_INIT | AS_STATUS_IDLE)) |
| 179 | ; |
| 180 | |
| 181 | CHECKPOINT ('b'); |
| 182 | |
| 183 | as_put_byte (AS_CMD_MAILBOX_INIT); |
| 184 | as_put_byte (1); /* one mailbox out, one in */ |
| 185 | as_put_byte ((int)mailbox >> 16); |
| 186 | as_put_byte ((int)mailbox >> 8); |
| 187 | as_put_byte ((int)mailbox); |
| 188 | |
| 189 | while (inb (as_port + AS_STATUS) & AS_STATUS_INIT) |
| 190 | ; |
| 191 | |
| 192 | CHECKPOINT ('c'); |
| 193 | |
| 194 | mailbox[0].msb = (int)ccb >> 16; |
| 195 | mailbox[0].mid = (int)ccb >> 8; |
| 196 | mailbox[0].lsb = (int)ccb; |
| 197 | mailbox[0].cmd = 1; |
| 198 | |
| 199 | as_put_byte (AS_CMD_START_SCSI_COMMAND); |
| 200 | |
| 201 | /* wait for done */ |
| 202 | while (mailbox[1].cmd == 0) |
| 203 | ; |
| 204 | |
| 205 | CHECKPOINT ('d'); |
| 206 | |
| 207 | if (mailbox[1].cmd != 1) { |
| 208 | /* some error */ |
| 209 | CHECKPOINT ('X'); |
| 210 | while (1); |
| 211 | } |
| 212 | |
| 213 | CHECKPOINT ('e'); |
| 214 | |
| 215 | /* the optimazation that gcc uses when it knows we are jumpping |
| 216 | * to a constant address is broken, so we have to use a variable |
| 217 | * here |
| 218 | */ |
| 219 | (*f)(dev, unit, off); |
| 220 | } |
| 221 | |
| 222 | int |
| 223 | as_put_byte (val) |
| 224 | int val; |
| 225 | { |
| 226 | while (inb (as_port + AS_STATUS) & AS_STATUS_CDF) |
| 227 | ; |
| 228 | outb (as_port + AS_DATA_OUT, val); |
| 229 | } |
| 230 | |
| 231 | asm (" |
| 232 | ebootblkcode: |
| 233 | . = 510 |
| 234 | .byte 0x55 |
| 235 | .byte 0xaa |
| 236 | ebootblk: /* MUST BE EXACTLY 0x200 BIG FOR SURE */ |
| 237 | "); |