7d532375134844612dcbdb308cb2b5294c1c54e8
[people/lynusvaz/gpxe.git] / src / arch / i386 / prefix / romprefix.S
1 /* At entry, the processor is in 16 bit real mode and the code is being
2  * executed from an address it was not linked to. Code must be pic and
3  * 32 bit sensitive until things are fixed up.
4  *
5  * Also be very careful as the stack is at the rear end of the interrupt
6  * table so using a noticeable amount of stack space is a no-no.
7  */
8
9 #include <config/general.h>
10
11 #define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
12 #define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
13 #define PCI_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( ' ' << 24 ) )
14 #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
15 #define PNP_GET_BBS_VERSION 0x60
16 #define PMM_ALLOCATE 0x0000
17 #define PMM_DEALLOCATE 0x0002
18
19 /* ROM banner timeout.  Based on the configurable BANNER_TIMEOUT in
20  * config.h, but converted to a number of (18Hz) timer ticks, and
21  * doubled to allow for BIOSes that switch video modes immediately
22  * beforehand, so rendering the message almost invisible to the user.
23  */
24 #define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 )
25
26         .text
27         .code16
28         .arch i386
29         .section ".prefix", "ax", @progbits
30         
31         .org    0x00
32 romheader:
33         .word   0xAA55                  /* BIOS extension signature */
34 romheader_size: .byte _filesz_sect      /* Size in 512-byte blocks */
35         jmp     init                    /* Initialisation vector */
36 checksum:
37         .byte   0
38         .org    0x16
39         .word   undiheader
40         .org    0x18
41         .word   pciheader
42         .org    0x1a
43         .word   pnpheader
44         .size romheader, . - romheader
45         
46         .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
47         .ascii  "SUBB"
48         .long   romheader_size
49         .long   512
50         .long   0
51         .previous
52
53 pciheader:
54         .ascii  "PCIR"                  /* Signature */
55         .word   pci_vendor_id           /* Vendor identification */ 
56         .word   pci_device_id           /* Device identification */
57         .word   0x0000                  /* Device list pointer */
58         .word   pciheader_len           /* PCI data structure length */
59         .byte   0x03                    /* PCI data structure revision */
60         .byte   0x02, 0x00, 0x00        /* Class code */
61 pciheader_image_length:
62         .word   _filesz_sect            /* Image length */
63         .word   0x0001                  /* Revision level */
64         .byte   0x00                    /* Code type */
65         .byte   0x80                    /* Last image indicator */
66 pciheader_runtime_length:
67         .word   _filesz_sect            /* Maximum run-time image length */
68         .word   0x0000                  /* Configuration utility code header */
69         .word   0x0000                  /* DMTF CLP entry point */
70         .equ pciheader_len, . - pciheader
71         .size pciheader, . - pciheader
72         
73         .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
74         .ascii  "SUBW"
75         .long   pciheader_image_length
76         .long   512
77         .long   0
78         .ascii  "SUBW"
79         .long   pciheader_runtime_length
80         .long   512
81         .long   0
82         .previous
83
84 pnpheader:
85         .ascii  "$PnP"                  /* Signature */
86         .byte   0x01                    /* Structure revision */
87         .byte   ( pnpheader_len / 16 )  /* Length (in 16 byte increments) */
88         .word   0x0000                  /* Offset of next header */
89         .byte   0x00                    /* Reserved */
90         .byte   0x00                    /* Checksum */
91         .long   0x00000000              /* Device identifier */
92         .word   mfgstr                  /* Manufacturer string */
93         .word   prodstr                 /* Product name */
94         .byte   0x02                    /* Device base type code */
95         .byte   0x00                    /* Device sub-type code */
96         .byte   0x00                    /* Device interface type code */
97         .byte   0xf4                    /* Device indicator */
98         .word   0x0000                  /* Boot connection vector */
99         .word   0x0000                  /* Disconnect vector */
100         .word   bev_entry               /* Boot execution vector */
101         .word   0x0000                  /* Reserved */
102         .word   0x0000                  /* Static resource information vector*/
103         .equ pnpheader_len, . - pnpheader
104         .size pnpheader, . - pnpheader
105
106 /* Manufacturer string */
107 mfgstr:
108         .asciz  "http://etherboot.org"
109         .size mfgstr, . - mfgstr
110
111 /* Product string
112  *
113  * Defaults to PRODUCT_SHORT_NAME.  If the ROM image is writable at
114  * initialisation time, it will be filled in to include the PCI
115  * bus:dev.fn number of the card as well.
116  */
117 prodstr:
118         .ascii  PRODUCT_SHORT_NAME
119 prodstr_separator:
120         .byte   0
121         .ascii  "(PCI "
122 prodstr_pci_id:
123         .asciz  "xx:xx.x)"              /* Filled in by init code */
124         .size prodstr, . - prodstr
125
126         .globl  undiheader      
127 undiheader:
128         .ascii  "UNDI"                  /* Signature */
129         .byte   undiheader_len          /* Length of structure */
130         .byte   0                       /* Checksum */
131         .byte   0                       /* Structure revision */
132         .byte   0,1,2                   /* PXE version: 2.1.0 */
133         .word   undiloader              /* Offset to loader routine */
134         .word   _data16_memsz           /* Stack segment size */
135         .word   _data16_memsz           /* Data segment size */
136         .word   _text16_memsz           /* Code segment size */
137         .ascii  "PCIR"                  /* Bus type */
138         .equ undiheader_len, . - undiheader
139         .size undiheader, . - undiheader
140
141 /* Initialisation (called once during POST)
142  *
143  * Determine whether or not this is a PnP system via a signature
144  * check.  If it is PnP, return to the PnP BIOS indicating that we are
145  * a boot-capable device; the BIOS will call our boot execution vector
146  * if it wants to boot us.  If it is not PnP, hook INT 19.
147  */
148 init:
149         /* Preserve registers, clear direction flag, set %ds=%cs */
150         pushaw
151         pushw   %ds
152         pushw   %es
153         pushw   %fs
154         pushw   %gs
155         cld
156         pushw   %cs
157         popw    %ds
158
159         /* Shuffle some registers around.  We need %di available for
160          * the print_xxx functions, and in a register that's
161          * addressable from %es, so shuffle as follows:
162          *
163          *    %di (pointer to PnP structure) => %bx
164          *    %bx (runtime segment address, for PCI 3.0) => %gs
165          */
166         movw    %bx, %gs
167         movw    %di, %bx
168
169         /* Print message as early as possible */
170         movw    $init_message, %si
171         xorw    %di, %di
172         call    print_message
173         call    print_pci_busdevfn
174
175         /* Fill in product name string, if possible */
176         movw    $prodstr_pci_id, %di
177         call    print_pci_busdevfn
178         movb    $( ' ' ), prodstr_separator
179
180         /* Print segment address */
181         movb    $( ' ' ), %al
182         xorw    %di, %di
183         call    print_character
184         movw    %cs, %ax
185         call    print_hex_word
186
187         /* Check for PCI BIOS version */
188         pushl   %ebx
189         pushl   %edx
190         pushl   %edi
191         stc
192         movw    $0xb101, %ax
193         int     $0x1a
194         jc      no_pci3
195         cmpl    $PCI_SIGNATURE, %edx
196         jne     no_pci3
197         testb   %ah, %ah
198         jnz     no_pci3
199         movw    $init_message_pci, %si
200         xorw    %di, %di
201         call    print_message
202         movb    %bh, %al
203         call    print_hex_nibble
204         movb    $( '.' ), %al
205         call    print_character
206         movb    %bl, %al
207         call    print_hex_byte
208         cmpb    $3, %bh
209         jb      no_pci3
210         /* PCI >=3.0: leave %gs as-is if sane */
211         movw    %gs, %ax
212         cmpw    $0xa000, %ax    /* Insane if %gs < 0xa000 */
213         jb      pci3_insane
214         movw    %cs, %bx        /* Sane if %cs == %gs */
215         cmpw    %bx, %ax
216         je      1f
217         movzbw  romheader_size, %cx /* Sane if %cs+len <= %gs */
218         shlw    $5, %cx
219         addw    %cx, %bx
220         cmpw    %bx, %ax
221         jae     1f
222         movw    %cs, %bx        /* Sane if %gs+len <= %cs */
223         addw    %cx, %ax
224         cmpw    %bx, %ax
225         jbe     1f
226 pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
227         movb    $( '!' ), %al
228         call    print_character
229         movw    %gs, %ax
230         call    print_hex_word
231 no_pci3:
232         /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
233         pushw   %cs
234         popw    %gs
235 1:      popl    %edi
236         popl    %edx
237         popl    %ebx
238
239         /* Check for PnP BIOS */
240         testw   $0x0f, %bx      /* PnP signature must be aligned - bochs    */
241         jnz     no_bbs          /* uses unalignment to indicate 'fake' PnP. */
242         cmpl    $PNP_SIGNATURE, %es:0(%bx)
243         jne     no_bbs
244         /* Is PnP: print PnP message */
245         movw    $init_message_pnp, %si
246         xorw    %di, %di
247         call    print_message
248         /* Check for BBS */
249         pushw   %es:0x1b(%bx)   /* Real-mode data segment */
250         pushw   %ds             /* &(bbs_version) */
251         pushw   $bbs_version
252         pushw   $PNP_GET_BBS_VERSION
253         lcall   *%es:0xd(%bx)
254         addw    $8, %sp
255         testw   %ax, %ax
256         je      got_bbs
257 no_bbs: /* Not BBS-compliant - must hook INT 19 */
258         movw    $init_message_int19, %si
259         xorw    %di, %di
260         call    print_message
261         xorw    %ax, %ax
262         movw    %ax, %es
263         pushl   %es:( 0x19 * 4 )
264         popl    orig_int19
265         pushw   %gs /* %gs contains runtime %cs */
266         pushw   $int19_entry
267         popl    %es:( 0x19 * 4 )
268         jmp     bbs_done
269 got_bbs: /* BBS compliant - no need to hook INT 19 */
270         movw    $init_message_bbs, %si
271         xorw    %di, %di
272         call    print_message
273 bbs_done:
274
275         /* Check for PMM */
276         movw    $( 0xe000 - 1 ), %bx
277 pmm_scan:
278         incw    %bx
279         jz      no_pmm
280         movw    %bx, %es
281         cmpl    $PMM_SIGNATURE, %es:0
282         jne     pmm_scan
283         xorw    %dx, %dx
284         xorw    %si, %si
285         movzbw  %es:5, %cx
286 1:      es lodsb
287         addb    %al, %dl
288         loop    1b
289         jnz     pmm_scan
290         /* PMM found: print PMM message */
291         movw    $init_message_pmm, %si
292         xorw    %di, %di
293         call    print_message
294         /* We have PMM and so a 1kB stack: preserve upper register halves */
295         pushal
296         /* Calculate required allocation size in %esi */
297         movzbl  romheader_size, %eax
298         shll    $9, %eax
299         addl    $_textdata_memsz, %eax
300         orw     $0xffff, %ax    /* Ensure allocation size is at least 64kB */
301         bsrl    %eax, %ecx
302         subw    $15, %cx        /* Round up and convert to 64kB count */
303         movw    $1, %si
304         shlw    %cl, %si
305 pmm_loop:
306         /* Try to allocate block via PMM */
307         pushw   $0x0006         /* Aligned, extended memory */
308         pushl   $0xffffffff     /* No handle */
309         movzwl  %si, %eax
310         shll    $12, %eax
311         pushl   %eax            /* Allocation size in paragraphs */
312         pushw   $PMM_ALLOCATE
313         lcall   *%es:7
314         addw    $12, %sp
315         /* Abort if allocation fails */
316         testw   %dx, %dx        /* %ax==0 even on success, since align>=64kB */
317         jz      pmm_fail
318         /* If block has A20==1, free block and try again with twice
319          * the allocation size (and hence alignment).
320          */
321         testw   $0x0010, %dx
322         jz      got_pmm
323         pushw   %dx
324         pushw   $0
325         pushw   $PMM_DEALLOCATE
326         lcall   *%es:7
327         addw    $6, %sp
328         addw    %si, %si
329         jmp     pmm_loop
330 got_pmm: /* PMM allocation succeeded */
331         movw    %dx, ( image_source + 2 )
332         movw    %dx, %ax
333         xorw    %di, %di
334         call    print_hex_word
335         movb    $( '@' ), %al
336         call    print_character
337         movw    %si, %ax
338         call    print_hex_byte
339         /* Copy ROM to PMM block */
340         xorw    %ax, %ax
341         movw    %ax, %es
342         movl    image_source, %edi
343         xorl    %esi, %esi
344         movzbl  romheader_size, %ecx
345         shll    $9, %ecx
346         addr32 rep movsb        /* PMM presence implies flat real mode */
347         movl    %edi, decompress_to
348         /* Shrink ROM */
349         movb    $_prefix_memsz_sect, romheader_size
350 pmm_fail:
351         /* Restore upper register halves */
352         popal
353 no_pmm:
354
355         /* Update checksum */
356         xorw    %bx, %bx
357         xorw    %si, %si
358         movzbw  romheader_size, %cx
359         shlw    $9, %cx
360 1:      lodsb
361         addb    %al, %bl
362         loop    1b
363         subb    %bl, checksum
364
365         /* Copy self to option ROM space.  Required for PCI3.0, which
366          * loads us to a temporary location in low memory.  Will be a
367          * no-op for lower PCI versions.
368          */
369         movb    $( ' ' ), %al
370         xorw    %di, %di
371         call    print_character
372         movw    %gs, %ax
373         call    print_hex_word
374         movzbw  romheader_size, %cx
375         shlw    $9, %cx
376         movw    %ax, %es
377         xorw    %si, %si
378         xorw    %di, %di
379         cs rep  movsb
380
381         /* Prompt for POST-time shell */
382         movw    $init_message_prompt, %si
383         xorw    %di, %di
384         call    print_message
385         movw    $prodstr, %si
386         call    print_message
387         movw    $init_message_dots, %si
388         call    print_message
389         /* Wait for Ctrl-B */
390         movw    $0xff02, %bx
391         call    wait_for_key
392         /* Clear prompt */
393         pushf
394         xorw    %di, %di
395         call    print_kill_line
396         movw    $init_message_done, %si
397         call    print_message
398         popf
399         jnz     2f
400         /* Ctrl-B was pressed: invoke gPXE.  The keypress will be
401          * picked up by the initial shell prompt, and we will drop
402          * into a shell.
403          */
404         pushw   %cs
405         call    exec
406 2:
407         /* Restore registers */
408         popw    %gs
409         popw    %fs
410         popw    %es
411         popw    %ds
412         popaw
413
414         /* Indicate boot capability to PnP BIOS, if present */
415         movw    $0x20, %ax
416         lret
417         .size init, . - init
418
419 /*
420  * Note to hardware vendors:
421  *
422  * If you wish to brand this boot ROM, please do so by defining the
423  * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h.
424  *
425  * While nothing in the GPL prevents you from removing all references
426  * to gPXE or http://etherboot.org, we prefer you not to do so.
427  *
428  * If you have an OEM-mandated branding requirement that cannot be
429  * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
430  * please contact us.
431  *
432  * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
433  *   bypassing the spirit of this request! ]
434  */
435 init_message:
436         .ascii  "\n"
437         .ascii  PRODUCT_NAME
438         .ascii  "\n"
439         .asciz  "gPXE (http://etherboot.org) - "
440         .size   init_message, . - init_message
441 init_message_pci:
442         .asciz  " PCI"
443         .size   init_message_pci, . - init_message_pci
444 init_message_pnp:
445         .asciz  " PnP"
446         .size   init_message_pnp, . - init_message_pnp
447 init_message_bbs:
448         .asciz  " BBS"
449         .size   init_message_bbs, . - init_message_bbs
450 init_message_pmm:
451         .asciz  " PMM"
452         .size   init_message_pmm, . - init_message_pmm
453 init_message_int19:
454         .asciz  " INT19"
455         .size   init_message_int19, . - init_message_int19
456 init_message_prompt:
457         .asciz  "\nPress Ctrl-B to configure "
458         .size   init_message_prompt, . - init_message_prompt
459 init_message_dots:
460         .asciz  "..."
461         .size   init_message_dots, . - init_message_dots
462 init_message_done:
463         .asciz  "\n\n"
464         .size   init_message_done, . - init_message_done
465
466 /* ROM image location
467  *
468  * May be either within option ROM space, or within PMM-allocated block.
469  */
470 image_source:
471         .long   0
472         .size   image_source, . - image_source
473
474 /* Temporary decompression area
475  *
476  * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
477  */
478 decompress_to:
479         .long   HIGHMEM_LOADPOINT
480         .size   decompress_to, . - decompress_to
481
482 /* BBS version
483  *
484  * Filled in by BBS BIOS.  We ignore the value.
485  */
486 bbs_version:
487         .word   0
488         .size   bbs_version, . - bbs_version
489
490 /* Boot Execution Vector entry point
491  *
492  * Called by the PnP BIOS when it wants to boot us.
493  */
494 bev_entry:
495         pushw   %cs
496         call    exec
497         lret
498         .size   bev_entry, . - bev_entry
499
500 /* INT19 entry point
501  *
502  * Called via the hooked INT 19 if we detected a non-PnP BIOS.  We
503  * attempt to return via the original INT 19 vector (if we were able
504  * to store it).
505  */
506 int19_entry:
507         pushw   %cs
508         popw    %ds
509         /* Prompt user to press B to boot */
510         movw    $int19_message_prompt, %si
511         xorw    %di, %di
512         call    print_message
513         movw    $prodstr, %si
514         call    print_message
515         movw    $int19_message_dots, %si
516         call    print_message
517         movw    $0xdf4e, %bx
518         call    wait_for_key
519         pushf
520         xorw    %di, %di
521         call    print_kill_line
522         movw    $int19_message_done, %si
523         call    print_message
524         popf
525         jz      1f
526         /* Leave keypress in buffer and start gPXE.  The keypress will
527          * cause the usual initial Ctrl-B prompt to be skipped.
528          */
529         pushw   %cs
530         call    exec
531 1:      /* Try to call original INT 19 vector */
532         movl    %cs:orig_int19, %eax
533         testl   %eax, %eax
534         je      2f
535         ljmp    *%cs:orig_int19
536 2:      /* No chained vector: issue INT 18 as a last resort */
537         int     $0x18
538         .size   int19_entry, . - int19_entry
539 orig_int19:
540         .long   0
541         .size   orig_int19, . - orig_int19
542
543 int19_message_prompt:
544         .asciz  "Press N to skip booting from "
545         .size   int19_message_prompt, . - int19_message_prompt
546 int19_message_dots:
547         .asciz  "..."
548         .size   int19_message_dots, . - int19_message_dots
549 int19_message_done:
550         .asciz  "\n\n"
551         .size   int19_message_done, . - int19_message_done
552         
553 /* Execute as a boot device
554  *
555  */
556 exec:   /* Set %ds = %cs */
557         pushw   %cs
558         popw    %ds
559
560         /* Print message as soon as possible */
561         movw    $prodstr, %si
562         xorw    %di, %di
563         call    print_message
564         movw    $exec_message, %si
565         call    print_message
566
567         /* Store magic word on BIOS stack and remember BIOS %ss:sp */
568         pushl   $STACK_MAGIC
569         movw    %ss, %dx
570         movw    %sp, %bp
571
572         /* Obtain a reasonably-sized temporary stack */
573         xorw    %ax, %ax
574         movw    %ax, %ss
575         movw    $0x7c00, %sp
576
577         /* Install gPXE */
578         movl    image_source, %esi
579         movl    decompress_to, %edi
580         call    alloc_basemem
581         call    install_prealloc
582
583         /* Set up real-mode stack */
584         movw    %bx, %ss
585         movw    $_estack16, %sp
586
587         /* Jump to .text16 segment */
588         pushw   %ax
589         pushw   $1f
590         lret
591         .section ".text16", "awx", @progbits
592 1:      /* Call main() */
593         pushl   $main
594         pushw   %cs
595         call    prot_call
596         popl    %ecx /* discard */
597
598         /* Uninstall gPXE */
599         call    uninstall
600
601         /* Restore BIOS stack */
602         movw    %dx, %ss
603         movw    %bp, %sp
604
605         /* Check magic word on BIOS stack */
606         popl    %eax
607         cmpl    $STACK_MAGIC, %eax
608         jne     1f
609         /* BIOS stack OK: return to caller */
610         lret
611 1:      /* BIOS stack corrupt: use INT 18 */
612         int     $0x18
613         .previous
614
615 exec_message:
616         .asciz  " starting execution\n"
617         .size exec_message, . - exec_message
618
619 /* UNDI loader
620  *
621  * Called by an external program to load our PXE stack.
622  */
623 undiloader:
624         /* Save registers */
625         pushl   %esi
626         pushl   %edi
627         pushw   %ds
628         pushw   %es
629         pushw   %bx
630         /* ROM segment address to %ds */
631         pushw   %cs
632         popw    %ds
633         /* UNDI loader parameter structure address into %es:%di */
634         movw    %sp, %bx
635         movw    %ss:18(%bx), %di
636         movw    %ss:20(%bx), %es
637         /* Install to specified real-mode addresses */
638         pushw   %di
639         movw    %es:12(%di), %bx
640         movw    %es:14(%di), %ax
641         movl    image_source, %esi
642         movl    decompress_to, %edi
643         call    install_prealloc
644         popw    %di
645         /* Call UNDI loader C code */
646         pushl   $pxe_loader_call
647         pushw   %cs
648         pushw   $1f
649         pushw   %ax
650         pushw   $prot_call
651         lret
652 1:      popw    %bx     /* discard */
653         popw    %bx     /* discard */
654         /* Restore registers and return */
655         popw    %bx
656         popw    %es
657         popw    %ds
658         popl    %edi
659         popl    %esi
660         lret
661         .size undiloader, . - undiloader
662
663 /* Wait for key press specified by %bl (masked by %bh)
664  *
665  * Used by init and INT19 code when prompting user.  If the specified
666  * key is pressed, it is left in the keyboard buffer.
667  *
668  * Returns with ZF set iff specified key is pressed.
669  */
670 wait_for_key:
671         /* Preserve registers */
672         pushw   %cx
673         pushw   %ax
674 1:      /* Empty the keyboard buffer before waiting for input */
675         movb    $0x01, %ah
676         int     $0x16
677         jz      2f
678         xorw    %ax, %ax
679         int     $0x16
680         jmp     1b
681 2:      /* Wait for a key press */
682         movw    $ROM_BANNER_TIMEOUT, %cx
683 3:      decw    %cx
684         js      99f             /* Exit with ZF clear */
685         /* Wait for timer tick to be updated */
686         call    wait_for_tick
687         /* Check to see if a key was pressed */
688         movb    $0x01, %ah
689         int     $0x16
690         jz      3b
691         /* Check to see if key was the specified key */
692         andb    %bh, %al
693         cmpb    %al, %bl
694         je      99f             /* Exit with ZF set */
695         /* Not the specified key: remove from buffer and stop waiting */
696         pushfw
697         xorw    %ax, %ax
698         int     $0x16
699         popfw                   /* Exit with ZF clear */
700 99:     /* Restore registers and return */
701         popw    %ax
702         popw    %cx
703         ret
704         .size wait_for_key, . - wait_for_key
705
706 /* Wait for timer tick
707  *
708  * Used by wait_for_key
709  */
710 wait_for_tick:
711         pushl   %eax
712         pushw   %fs
713         movw    $0x40, %ax
714         movw    %ax, %fs
715         movl    %fs:(0x6c), %eax
716 1:      pushf
717         sti
718         hlt
719         popf
720         cmpl    %fs:(0x6c), %eax
721         je      1b
722         popw    %fs
723         popl    %eax
724         ret
725         .size wait_for_tick, . - wait_for_tick