/*! @file loseg_utils.c @created 2009-03-22 David Elliott @copyright David Elliott @abstract Provides functions to be used during the real-mode entry. @discussion Used by the real-mode (non-Multiboot) entry code. We want the code here to be located early enough in the binary that if the later portions of it did not load for one reason or another at least we can fail gracefully. Note that despite being used by the real-mode entrypoint, this code still runs after entering protected mode. */ #include #include "memory.h" // libsa #define SECTION_ATTR_FOR_LOTEXT __attribute__((section("__LOSEG,__text"))) extern struct {} _LOSEG__text__begin ASM_MACHO_SECTION_BEGIN(__LOSEG,__text); extern struct {} _DATA__bss__begin ASM_MACHO_SECTION_BEGIN(__DATA,__bss); extern uint32_t save_ss asm("save_ss"); extern uint32_t save_sp asm("save_sp"); /*! @function checksum_booter @abstract Checksums the in-memory booter @returns 0, if you're lucky @discussion The Apple-supplied HFS+ bootsector loaded exactly 126 512-byte sectors and the CD bootsector loaded exactly 31 2048-byte sectors. It's not so much an issue for CD boot where the build process is responsible for concatenating the CD boot sector and this booter but in the HFS+ case it is impossible to know whether or not someone is using the old or the new HFS+ bootsector. It's also impossible to know whether the HFS+ startupfile somehow used more than the first extent which is the only one that the HFS+ boot1h loads. Therefore, we assume that the bootsector or other previous stage loader loaded enough of the binary such that if we keep the entrypoint and this code low enough we can do a self-exam to make sure we were fully loaded. To make this happen, machOconv was modified slightly to append a 32-bit checksum to the end of flat binary it generates. The checksum is calculated by summing all DWORD in the output file then writing out 0-sum. When that value is added to the rest of them, the sum should always be zero. The small caveat is that this function must therefore be called before the BSS is zeroed and before any globals are modified. Since __switch_stack must be called before entering protected mode and since it must use two of the globals we cheat and take that into account when calculating the checksum. Note that the bios() function uses a few more globals. We don't account for these as we plan to be run before that function is used. */ uint32_t checksum_booter() SECTION_ATTR_FOR_LOTEXT; uint32_t checksum_booter() { uint32_t *p; uint32_t csum = 0; // Checksum the entire binary from _LOSEG__text__begin to _DATA__bss__begin plus 4 bytes. for(p = (uint32_t*)&_LOSEG__text__begin; p < (uint32_t*)((char*)&_DATA__bss__begin + sizeof(uint32_t)); ++p) csum += *p; // Take the save_ss and save_sp changes into account. csum -= save_ss; csum += STACK_SEG; csum -= save_sp; csum += STACK_OFS; return csum; } #include "libsaio.h" /*! @function loseg_puts @abstract A basic puts function @discussion The libsaio routines don't include puts because printf is generally used. We don't want to pull all of the printf machinery into the low segment so instead we provide this. Note that for this to work as intended (i.e. you could chop the booter at the end of __LOSEG and it would fail its checksum and return) the putc function from libsaio must have been compiled into __LOSEG,__text as well. */ void loseg_puts(char const *s) SECTION_ATTR_FOR_LOTEXT; void loseg_puts(char const *s) { for(;*s != '\0'; ++s) putc(*s); }