diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..95819c2 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,29 @@ +stboot 0.2.1 (2012/25/10) +------------ +- Added support for systems with more than one HDD +- Fixed typos in source files and READMEs + +stboot 0.2 (2011/29/11) +---------- +- Implemented a simple bootloader as a separate program, which loads the + the VBR of an active partition +- GRUB4DOS is not included anymore, since it became useless (but it can + still be used as an alternative bootsect.bin) +- Set the correct video mode for text mode programs +- Added a procedure to display some messages +- Introduced a function-like macro to calculate real mode addresses +- Changes in the README in order to reflect the latest changes + +stboot 0.1.1 (2011/08/26) +------------ +- Code clean-up: + - removal of unneeded instructions + - optimization of the copy instructions, by moving double-words + instead of bytes + - improve code readability with macro definition of constants + - correction of some comments +- Minor corrections in the README + +stboot 0.1 (2011/08/21) +---------- +- Initial release diff --git a/README b/README new file mode 100644 index 0000000..484c2ed --- /dev/null +++ b/README @@ -0,0 +1,113 @@ +-------------------------------------------------- +stboot - A CEFULL replacement +and a boot loader for Splashtop-compatible systems +-------------------------------------------------- +by trya - tryagainprod@gmail.com + +DISCLAIMER: +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE +LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER +PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO +THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM +PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + +Overview +-------- +This program enables the use of the Splashtop (and related) start button in +order to launch an OS other than Splashtop OS, quickly and without having to +install Splashtop OS itself. + +Splashtop OS boot process +------------------------- +When the Splashtop button is pressed: +- After POST, the BIOS loads the option ROM (containing the DeviceVM ROM +Loader and a CE program) at 0x7c00 and jumps there. +- The ROM Loader switches the computer to protected mode and transfers control +to the CE program, looking for splash.idx at the root of a FAT32 or NTFS +partition in the HDD. +- If the file is found, then the program will look for CEFULL in the directory +(except the root) as mentioned in the second line of splash.idx. +- If CEFULL is present, it is copied to 0x100000 [1] and execution is +transfered to this address. +- CEFULL looks for kernel.bin in one of the FAT32 or NTFS partitions, in the +given directory from splash.idx. kernel.bin is the combination of a vmlinuz and +an initrd.img. +- Once kernel.bin is loaded, the rest of Splashtop OS initialization is left +to the Linux kernel. + +[1] as for the Linux kernel bzImages. The CE_BZ files used with systems with +no Splashtop button or starting Splashtop OS from a USB stick are also bzImages +(CE_BZ = linux_head.S + CEFULL), which allows starting Splashtop OS from a +classic boot loader (Splashtop usually uses a custom version of GRUB). + +Solutions +--------- +1. Patch the option ROM, but on the one hand, this solution doesn't come +without risk and on the other hand, it would be difficult to find a universal +method, as the integration of Splashtop by manufacturers may vary. + +2. Integrate kexec in Splashtop OS, in order to run another kernel from +Splashtop Linux kernel, but on the one hand, this method required to have +Splashtop OS installed and on the other hand, you can lose up to 15 seconds +between booting and kexec call, the time Splashtop OS takes to be initialized. + +3. Build a custom kernel.bin, except that the format of kernel.bin remains +unknown and only Splashtop developers have access to the tools that would +allow us to build this file. + +4. Execute our own boot loader from CEFULL, so we need to write a program that +reproduces the CEFULL format and switches the computer back to real mode with +our boot loader copied to 0x7c00, simulating the 19h interrupt without having +to load specific drivers to access our boot loader from the HDD. stboot is an +implementation of this method. + +Usage +----- +- Assembly: +The generated CEFULL from stboot.asm consists of a header, the code preparing +bootstrap and the boot sector "bootsect.bin" of your choice. You can build +your own CEFULL by assembling stboot.asm with yasm: + + $ cp -f [custom_bootsector] bootsect.bin + $ yasm -o CEFULL stboot.asm + +- Installation: +A Splashtop OS installation is not required. On the other hand, a FAT32 or +NTFS partition is necessary. In our example, the file tree of the partition +containing CEFULL should look like this : + +─┬─stboot/ + │ │ + │ └CEFULL (our own boot loader) + │ + └─splash.idx (shows CEFULL location) + +This ready-for-use file tree is available in the root-example directory. At this +point, the boot loader configuration is entirely up to you. In the default +installation, the bootsect.bin included in CEFULL is a minimal bootloader which +looks for and loads the boot sector of the first active partition found. + +However, you are free to integrate your own boot sector into CEFULL. +Typically, extraction of a boot sector in Linux (or any Unix-like) is performed +with the dd utility like this: + + # dd if=/dev/[disk|partition] of=1st_sect.bin bs=512 count=1 + +Please refer to the "Assembly" section above for the boot sector integration +into CEFULL. + +Known limitations +----------------- +- Memory mapping only occurs in a 32-bit address space, the BIOS apparently +doesn't do memory hole remapping when booting Splashtop, since Splashtop OS is +supposed to be 32-bit only. This shouldn't prevent you from loading a 64-bit +kernel but it will never access more than 4 GB of RAM (and around 3 GB in +practice because of MMIO). +- SATA controllers are limited to Compatible (IDE) mode, even if the BIOS +supports AHCI mode under normal conditions. + +--- +END OF README diff --git a/README-fr b/README-fr new file mode 100644 index 0000000..1c74d17 --- /dev/null +++ b/README-fr @@ -0,0 +1,119 @@ +----------------------------------------------------------------- +stboot - un remplacement de CEFULL +et un chargeur d'amorçage pour les systèmes compatibles Splashtop +----------------------------------------------------------------- +par trya - tryagainprod@gmail.com + +DISCLAMER : +IL N’Y A AUCUNE GARANTIE POUR LE PROGRAMME, DANS LES LIMITES PERMISES PAR LA +LOI APPLICABLE. À MOINS QUE CELA NE SOIT ÉTABLI DIFFÉREMMENT PAR ÉCRIT, LES +PROPRIÉTAIRES DE DROITS ET/OU LES AUTRES PARTIES FOURNISSENT LE PROGRAMME « EN +L’ÉTAT » SANS GARANTIE D’AUCUNE SORTE, QU’ELLE SOIT EXPRIMÉE OU IMPLICITE, CECI +COMPRENANT, SANS SE LIMITER À CELLES-CI, LES GARANTIES IMPLICITES DE +COMMERCIALISABILITÉ ET D’ADÉQUATION À UN OBJECTIF PARTICULIER. VOUS ASSUMEZ LE +RISQUE ENTIER CONCERNANT LA QUALITÉ ET LES PERFORMANCES DU PROGRAMME. DANS +L’ÉVENTUALITÉ OÙ LE PROGRAMME S’AVÉRERAIT DÉFECTUEUX, VOUS ASSUMEZ LES COÛTS +DE TOUS LES SERVICES, RÉPARATIONS OU CORRECTIONS NÉCESSAIRES. + +Objectif +-------- +Ce programme permet d'utiliser le bouton de démarrage de Splashtop (et +apparentés) afin de lancer un OS autre que Splashtop OS, de manière rapide et +sans avoir à installer Splashtop OS lui-même. + +Procédure de démarrage de Splashtop OS +-------------------------------------- +Quand le bouton Splashtop est pressé : +- Après le POST, le BIOS charge la ROM option (contenant le DeviceVM ROM Loader +et un programme CE) à l'adresse 0x7c00 et saute à cet endroit. +- Le DeviceVM Rom Loader fait passer l'ordinateur en mode protégé et transfère +le contrôle au programme CE, chargé de rechercher un fichier splash.idx à la +racine d'une partition FAT32 ou NTFS du disque dur. +- Si ce fichier est trouvé, alors le programme CE va chercher un fichier CEFULL +dans le dossier (sauf la racine) indiqué dans la deuxième ligne de splash.idx. +- Si CEFULL est présent, il est copié à l'adresse 0x100000 [1] et le contrôle +est passé à cette adresse. +- CEFULL recherche un fichier kernel.bin dans une des partitions FAT32 ou NTFS +à l'endroit indiqué par splash.idx. kernel.bin est la combinaison d'un vmlinuz +et d'un initrd.img. +- Une fois kernel.bin chargé, le reste de l'initialisation de Splashtop OS est +laissé au noyau Linux. + +[1] comme pour les bzImages du noyau Linux. Les fichiers CE_BZ utilisés avec +les systèmes n'ayant pas de bouton Splashtop ou démarrant Splashtop OS à partir +d'une clé USB sont aussi des bzImages (CE_BZ = linux_head.S + CEFULL), +permettant ainsi le démarrage de Splashtop OS à partir d'un chargeur de +démarrage classique (Splashtop OS utilise habituellement une version modifiée +de GRUB). + +Solutions +--------- +1. Patcher la ROM option, mais d'une part, cette solution n'est pas sans risque +et d'autre part, il serait difficile d'en faire une méthode universelle sachant +que l'intégration de Splashtop par les constructeurs peut varier. + +2. Intégrer kexec dans Splashtop OS, afin de lancer un autre noyau +à partir du noyau Linux de Splashtop, mais d'une part cette méthode nécessite +d'avoir installé Splashtop OS et d'autre part, on peut perdre jusqu'à 15 +secondes entre le démarrage de l'ordinateur et l'appel à kexec, le temps +que Splashtop OS soit initialisé. + +3. Construire un kernel.bin personnalisé, sauf que le format de kernel.bin +reste inconnu et seuls les développeurs de Splashtop ont accès aux outils +permettant de construire ce fichier. + +4. Exécuter notre propre chargeur d'amorçage à partir de CEFULL, ce qui +nécessite d'écrire un programme reproduisant le format d'un CEFULL et faisant +repasser l'ordinateur en mode réel avec notre chargeur d'amorçage copié à +l'adresse 0x7c00, simulant ainsi l'interruption 19h sans avoir à charger des +pilotes spécifiques pour accéder à notre chargeur d'amorçage sur le disque dur. +stboot est une implémentation de cette méthode. + +Utilisation de stboot +--------------------- +- Assemblage : +Le CEFULL généré à partir de stboot.asm est composé d'un en-tête, du code +préparant l'amorçage et du secteur de boot "bootsect.bin" de votre choix. +Vous pouvez construire votre propre CEFULL en assemblant stboot.asm avec yasm : + + $ cp -f [custom_bootsector] bootsect.bin + $ yasm -o CEFULL stboot.asm + +- Installation : +Une installation de Splashtop OS n'est pas nécessaire, une partition FAT32 ou +NTFS est par contre obligatoire. L'arborescence de la partition contenant CEFULL +doit être la suivante : + +─┬─stboot/ + │ │ + │ └CEFULL (notre propre chargeur d'amorçage) + │ + └─splash.idx (indique l'emplacement de CEFULL) + +Cette arborescence prête à l'emploi est disponible dans le dossier root-example. +À ce moment-là, la configuration du chargeur d'amorçage dépend entièrement de +vous. Dans l'installation par défaut, le bootsect.bin inclus dans CEFULL est un +chargeur d'amorçage minimal qui recherche et charge le secteur de boot de la +première partition active trouvée. + +Cependant, vous êtes libre d'intégrer votre propre secteur de boot dans CEFULL, +Typiquement, l'extraction d'un secteur de boot sous Linux (ou Unix-like) +s'effectue avec le programme dd de cette manière : + + # dd if=/dev/[disque|partition] of=1st_sect.bin bs=512 count=1 + +Référez-vous au paragraphe "Assemblage" au-dessus pour l'intégration du secteur +de boot dans CEFULL. + +Limitations connues +------------------- +- Le "memory mapping" ne se produit que dans un espace mémoire 32 bits, le BIOS +ne fait pas apparemment de "memory hole remapping" quand Splashtop est démarré, +puisque Splashtop OS est censé être uniquement un système 32 bits. Cela ne +devrait pas vous empêcher de charger un noyau 64 bits mais il ne pourra jamais +accéder à plus de 4 Go de RAM (et environ 3 Go en pratique à cause du MMIO). +- Les contrôleurs SATA sont limités au mode Compatible (IDE), même si le BIOS +supporte le mode AHCI en temps normal. + +--- +FIN DU README diff --git a/bootsect.asm b/bootsect.asm new file mode 100644 index 0000000..e8fdb8e --- /dev/null +++ b/bootsect.asm @@ -0,0 +1,220 @@ +;; bootsect.asm - simple bootloader for stboot +;; by trya - tryagainprod@gmail.com + +%define mbr_address 0x7C00 +%define code_address 0x2000 + +[ORG code_address] ; assuming we're working at the new location +[BITS 16] + +%macro print_msg 1 + mov si, %1 + call write_msg +%endmacro + +bootsect: +;; First things first, move this bootloader to another address + cli + mov sp, mbr_address + cld + mov si, sp + mov di, code_address + mov cx, 512/4 + rep movsd + + jmp far 0x0:main + +main: + sti + +;; Welcome message + print_msg msg1 + +;; Retrieve number of HDDs + mov ax, 0x8 + mov dl, 0x80 + mov di, 0 + int 0x13 + mov [last_hdd], dl + +read_mbr: + mov esi, 0 + call read_disk + +;; Read the partition table + mov bx, mbr_address+0x1BE +read_table: + cmp bx, mbr_address+0x1FE + jnb read_ebr ; no more primary partitions, + ; let's take a look at logical partitions + + call copy_entry + add bx, 0x10 ; move to the next partition table entry + +;; Is the partition extended? +extended: + mov al, [pt_type] + cmp al, 0x05 + je is_extended + cmp al, 0x0F + jne active +is_extended: + mov al, 1 + mov [ebr_exists], al + mov eax, [pt_start] + mov [ebr_start], eax + +;; Is the partition active? +active: + call is_active + test al, al + jz read_table + +;; Copy the VBR of the selected partition and boot +goodbye: + print_msg msg2 ; chainloading message + mov esi, [pt_start] + call read_disk + jmp far 0x0:mbr_address + +;; Probe the logical partitions +read_ebr: + mov al, [ebr_exists] + test al, al + jz hdd_end + mov eax, [ebr_start] + mov [curr_ebr], eax +next_ebr: + mov esi, [curr_ebr] + call read_disk ; copy the EBR + mov bx, mbr_address+0x1BE + call copy_entry ; copy first entry + add bx, 0x10 + call is_active + test al, al + jz not_active +;; Prepare booting + mov eax, [curr_ebr] + add eax, [pt_start] + mov [pt_start], eax + jmp goodbye +not_active: + call copy_entry + mov al, [pt_type] + test al, al + jz hdd_end + mov eax, [ebr_start] + add eax, [pt_start] + mov [curr_ebr], eax + jmp next_ebr + +hdd_end: + mov al, [curr_hdd] + mov bl, [last_hdd] + cmp al, bl + je fail + inc al + mov [curr_hdd], al + jmp read_mbr + +fail: + print_msg msg3 + jmp $ +;; Main code ends here + +;; Procedures +;; Method for loading first sector with modern BIOS extensions +read_disk: + mov eax, esi ; sector number + mov [dap_sect], eax + mov ax, mbr_address ; destination address + mov [dap_dest], ax + mov ah, 0x42 ; read extended sectors + mov dl, [curr_hdd] ; current hard drive +;; We assume that the 'ds' register has been set to 0x0 by stboot + mov si, dap + int 0x13 + ret + +;; Copy an entry from the partition table +copy_entry: + cld + mov si, bx + mov di, pt_entry + mov cx, 16/4 + rep movsd + ret + +;; Is the partition active? +is_active: + mov al, [pt_active] + cmp al, 0x80 + je true + jmp false +true: + mov al, 1 + ret +false: + mov al, 0 + ret + +;; Writes string from DS:SI until null character is met +write_msg: + mov ah, 0xE ; write a TTY character + xor bh, bh + mov bl, 0x7 ; color attribute +.nextchar: + lodsb + or al, al + jz .return + int 0x10 + jmp .nextchar +.return: + ret +;; End of procedures + +;; Data +messages: + msg1 db 'Welcome to the VBR loader!',10,13,0 + msg2 db 'Chainloading from partition...',10,13,0 + msg3 db 'No stboot partition. Aborting.',10,13,0 + +hdd_indexes: + last_hdd db 0 ; index of the last HDD + curr_hdd db 0x80 ; currently probed HDD + +pt_entry: + pt_active db 0 + times 3 db 0 ; CHS address, useless here + pt_type db 0 + times 3 db 0 ; same here + pt_start dd 0 + pt_size dd 0 + +ebr: + ebr_exists db 0 + ebr_start dd 0 + curr_ebr dd 0 + +;; Disk address packet, required by int 13h extensions +dap: + db 16 ; size of DAP + db 0 ; unused + dw 1 ; number of sectors to be read + dap_dest dw 0 ; offset of the destination + dw 0 ; segment of the destination + dap_sect dd 0 ; low 4 bytes of the first sector to read + dd 0 ; high 4 bytes + +;; Pad to the 446-bytes code limit, just before the partition table + times 446-($-$$) db 0 + +pt_table: + first: times 16 db 0 + second: times 16 db 0 + third: times 16 db 0 + fourth: times 16 db 0 +pt_table_end: + dw 0xAA55 +bootsect_end: +;; End of data diff --git a/stboot.asm b/stboot.asm new file mode 100644 index 0000000..7d55062 --- /dev/null +++ b/stboot.asm @@ -0,0 +1,185 @@ +;; stboot.asm +;; by trya - tryagainprod@gmail.com + +;; CEFULL is loaded at 0x100000 in 32-bit protected mode, hence... +[ORG 0x100000] +[BITS 32] + +%define cefull_size (cefull_end-cefull) +%define stage2_size (stage2_end-stage2) +%define mbr_size (mbr_end-mbr) +%define gdt_size (gdt_end-gdt-1) + +%define mbr_address 0x7C00 +%define stage2_address 0x1000 +%define rm_address(x) (stage2_address+(x-stage2)) + +%macro print_msg 1 + mov si, %1 + call write_msg +%endmacro + +cefull: +header: +;; Reproducing the CE header (0xc0 length) + jmp short header+0x40 ; EB3E + db 0x45,0x54 + dd cefull_size ; executable size (checked by DeviceVM rom loader) + times 0x38 db 0 + jmp short header+0xC0 ; EB7E + db 0x43,0x45 + times 0x7C db 0 +header_end: + +stage1: +;; Our code starts here +;; NB: I let the stack setup to the chainloaded bootsector + cli + +;; Load our GDT + lgdt [stage1_gdtr] + +;; Jump to our 32-bit code segment + jmp far 0x8:pm_code + +pm_code: +;; Assign the new 32-bit data segment selector to the other segment registers + mov eax, 0x10 + mov ds, eax + mov ss, eax + mov es, eax + mov fs, eax + mov gs, eax + +;; Copy the included boot sector to 0x7c00 + cld + mov esi, mbr + mov edi, mbr_address + mov ecx, mbr_size/4 ; double-word blocks for faster copy + rep movsd + +;; Copy the 2nd stage code and data to 0x1000 + mov esi, stage2 + mov edi, stage2_address + mov ecx, stage2_size/4 ; double-word blocks + rep movsd + +;; Load the GDT from real mode address space + lgdt [rm_address(stage2_gdtr)] + +;; Jump to our new code in 16-bit protected mode (16-bit GDT code selector) + jmp far 0x18:stage2_address +stage1_end: + +[BITS 16] + +stage2: +;; Disable protected mode by clearing its flag in CR0 + mov eax, cr0 + and al, 11111110b + mov cr0, eax + +;; Reinitialize the other segment registers with a real mode compatible value + mov ax, 0x0 + mov ds, ax + mov ss, ax + mov es, ax + mov fs, ax + mov gs, ax + +;; Disable A20, assuming it was enabled by the rom loader + in al, 0x92 + and al, 11111101b + out 0x92, al + +;; Load real mode IDT + lidt [rm_address(idtr)] + +;; Jump to real mode code address + jmp far 0x0:rm_address(rm_code) + +rm_code: +;; Back into serious business, enable interrupts + sti + +;; Set video mode + mov ah, 0x00 + mov al, 0x03 ; 80x25 text mode (16 colors) + int 0x10 + +;; Welcome message + print_msg rm_address(msg1) + print_msg rm_address(msg2) + +;; We're in real mode and the CPU is in a sane state, +;; so we let the boot sector take control + jmp far 0x0:0x7C00 + +;; Main code ends here + +;; Writes string from DS:SI until null character is met +write_msg: + mov ah, 0xE + xor bh, bh + mov bl, 0x7 +.nextchar: + lodsb + or al,al + jz .return + int 0x10 + jmp .nextchar +.return: + ret + +messages: + msg1 db 'stboot has escaped from protected mode!',10,13,0 + msg2 db 'Now passing control to the boot sector...',10,13,0 + +;; GDT: table of 64-bit entries, first element of the table is NULL +;; Usual descriptor structure (rather complicated): +;; |___db___|___db___|___db___|___db___|___db___|___db___|____db_____|___db___| +;; |0______________15|16______________________39|40____47|48_51|52_55|56____63| +;; | Limit | | |Limit| | Base | +;; | first | Base first 24 bits | Flags |last |Flags| last | +;; |_____16 bits_____|__________________________|________|4bits|_____|_8_bits_| + +;; The only differences between 32 and 16-bit entries +;; are the granularity and the 16/32-bit flags + +gdt: + db 0,0,0,0,0,0,0,0 +gdt_pm_cs: + db 0xFF,0xFF,0x0,0x0,0x0,10011010b,11001111b,0x0 +gdt_pm_ds: + db 0xFF,0xFF,0x0,0x0,0x0,10010010b,11001111b,0x0 +gdt_rm_cs: + db 0xFF,0xFF,0x0,0x0,0x0,10011010b,00000000b,0x0 +gdt_end: + +;; GDT register: 48-bit (16+32) register +;; |_____dw_____|__________dd__________| +;; |0_________15|16__________________47| +;; | | | +;; | GDT size | GDT pointer | +;; |____________|______________________| + +stage1_gdtr: + dw gdt_size + dd gdt + +stage2_gdtr: + dw gdt_size + dd rm_address(gdt) + +;; IDT register: same structure as GDTR + +idtr: + dw 0x3FF ; 256 entries + dd 0 ; real mode IVT at 0x0 +stage2_end: + +;; Included boot sector, to be copied to 0x7c00 +mbr: + INCBIN "bootsect.bin" +mbr_end: +cefull_end: