| /* |
| * Raw bootcode loader (CHRP/Apple %BOOT) |
| * Written by Mark Cave-Ayland 2013 |
| */ |
| |
| #include "config.h" |
| #include "kernel/kernel.h" |
| #include "libopenbios/bindings.h" |
| #include "libopenbios/bootcode_load.h" |
| #include "libopenbios/initprogram.h" |
| #include "libopenbios/sys_info.h" |
| #include "libc/diskio.h" |
| #include "drivers/drivers.h" |
| #define printf printk |
| #define debug printk |
| |
| |
| int |
| bootcode_load(ihandle_t dev) |
| { |
| int retval = -1, count = 0, fd; |
| unsigned long bootcode, loadbase, entry, size, offset; |
| ihandle_t bootcode_info; |
| |
| /* Mark the saved-program-state as invalid */ |
| feval("0 state-valid !"); |
| |
| fd = open_ih(dev); |
| if (fd == -1) { |
| goto out; |
| } |
| |
| /* If we don't have the get-bootcode-info word then we don't support |
| loading bootcode via %BOOT */ |
| bootcode_info = find_ih_method("get-bootcode-info", dev); |
| if (!bootcode_info) { |
| retval = LOADER_NOT_SUPPORT; |
| goto out; |
| } |
| |
| /* Default to loading at load-base */ |
| fword("load-base"); |
| loadbase = POP(); |
| entry = loadbase; |
| size = 0; |
| |
| #ifdef CONFIG_PPC |
| /* |
| * Apple OF does not honor load-base and instead uses pmBootLoad |
| * value from the boot partition descriptor. |
| * |
| * Tested with: |
| * a debian image with QUIK installed |
| * a debian image with iQUIK installed (https://github.com/andreiw/quik) |
| * an IQUIK boot floppy |
| * a NetBSD boot floppy (boots stage 2) |
| */ |
| if (is_apple()) { |
| PUSH(bootcode_info); |
| fword("execute"); |
| |
| loadbase = POP(); |
| entry = POP(); |
| size = POP(); |
| } |
| #endif |
| |
| bootcode = loadbase; |
| offset = 0; |
| |
| while(1) { |
| if (seek_io(fd, offset) == -1) |
| break; |
| count = read_io(fd, (void *)bootcode, 512); |
| offset += count; |
| bootcode += count; |
| } |
| |
| /* If we didn't read anything then exit */ |
| if (!count) { |
| goto out; |
| } |
| |
| /* Use proper file size if we got it from bootcode info */ |
| if (size == 0) { |
| size = offset; |
| } |
| |
| /* Initialise load-state */ |
| PUSH(entry); |
| feval("load-state >ls.entry !"); |
| PUSH(size); |
| feval("load-state >ls.file-size !"); |
| feval("bootcode load-state >ls.file-type !"); |
| |
| out: |
| close_io(fd); |
| return retval; |
| } |
| |
| int |
| is_bootcode(char *addr) |
| { |
| /* Bootcode has no magic, and is executed directly. So we'll |
| * say that something is bootcode if the loader detected the |
| * %BOOT type sucessfully */ |
| ucell filetype; |
| |
| feval("load-state >ls.file-type @"); |
| filetype = POP(); |
| |
| return (filetype == 0x12); |
| } |
| |
| void |
| bootcode_init_program(void) |
| { |
| /* Entry point is already set, just need to setup the context */ |
| arch_init_program(); |
| |
| feval("-1 state-valid !"); |
| } |