; segments, but this stuff is painful enough as it is without having to rely
; on everything happening "as it ought to."
;
- section .rodata
+DummyTSS equ 0x580 ; Hopefully safe place in low mmoery
+
+ section .data
; desc base, limit, flags
%macro desc 3
.adj1: dd call32_gdt+CS_BASE ; pointer for LGDT instruction
dw 0
- ; 0008: Code segment, use16, readable, dpl 0, base CS_BASE, 64K
+ ; 0008: Dummy TSS to make Intel VT happy
+ ; Should never be actually accessed...
+ desc DummyTSS, 103, 0x8089
+
+ ; 0010: Code segment, use16, readable, dpl 0, base CS_BASE, 64K
desc CS_BASE, 0xffff, 0x009b
- ; 0010: Data segment, use16, read/write, dpl 0, base CS_BASE, 64K
+ ; 0018: Data segment, use16, read/write, dpl 0, base CS_BASE, 64K
desc CS_BASE, 0xffff, 0x0093
- ; 0018: Data segment, use16, read/write, dpl 0, base 0, 4G
- desc 0, 0xfffff, 0x809b
-
; 0020: Code segment, use32, read/write, dpl 0, base 0, 4G
desc 0, 0xfffff, 0xc09b
A20Tries resb 1
section .data
- alignb 4
+ align 4, db 0
Target dd 0 ; Target address
Target_Seg dw 20h ; Target CS
mov [.pm_jmp+2],eax ; Patch the PM jump
jmp .sync
.sync:
+ mov byte [call32_gdt+8+5],89h ; Mark TSS unbusy
o32 lgdt [call32_gdt] ; Set up GDT
o32 lidt [call32_pmidt] ; Set up IDT
mov eax,cr0
xor eax,eax ; Available for future use...
mov fs,eax
mov gs,eax
+ lldt ax
mov al,28h ; Set up data segments
mov es,eax
mov ds,eax
mov ss,eax
+ mov al,08h
+ ltr ax
+
mov esp,[ebp+PMESP] ; Load protmode %esp if available
jmp ebx ; Go to where we need to go
mov esp, (BOUNCE_SEG << 4) + 0x10000
push dword stack_end ; RM size
+ push dword call32_gdt+CS_BASE
push dword call32_handle_interrupt+CS_BASE
push dword CS_BASE ; Segment base
push dword (BOUNCE_SEG << 4) ; Bounce buffer address
cld
mov [ebp+PMESP],esp ; Save exit %esp
xor esp,esp ; Make sure the high bits are zero
- jmp 08h:.in_pm16 ; Return to 16-bit mode first
+ jmp 10h:.in_pm16 ; Return to 16-bit mode first
bits 16
.in_pm16:
- mov ax,10h ; Real-mode-like segment
+ mov ax,18h ; Real-mode-like segment
mov es,ax
mov ds,ax
mov ss,ax
; encoding smaller
mov eax,[ecx+eax*4] ; Get IVT entry
stosd ; Save in stack frame
- mov eax,call32_sys_rm.return + (MY_CS << 16) ; Return seg:offs
- stosd ; Save in stack frame
+ mov ax,call32_sys_rm.return ; Return offset
+ stosw ; Save in stack frame
+ mov eax,ebp
+ shr eax,4 ; Return segment
+ stosw ; Save in stack frame
mov eax,[edi-12] ; Return flags
and eax,0x200cd7 ; Mask (potentially) unsafe flags
mov [edi-12],eax ; Primary flags entry
uint32_t rm_bounce;
uint32_t rm_base;
uint32_t rm_handle_interrupt;
+ uint32_t rm_gdt;
uint32_t rm_size;
};
struct real_mode_args rm_args;
+__cdecl syscall_t syscall;
+void *sys_bounce;
+
/* Access to high memory */
/* Access to objects in the zero page */
printf("Moving compressed data from 0x%08x to 0x%08x\n",
where, newwhere);
- /* Our memcpy() is OK, because we always move from a higher
- address to a lower one */
- memcpy((void *)newwhere, (void *)where, size);
+ memmove((void *)newwhere, (void *)where, size);
where = newwhere;
}
*/
void __attribute__ ((noreturn)) die(void)
{
- asm volatile ("sti");
+ sti();
for (;;)
- asm volatile ("hlt");
+ asm volatile("hlt");
}
/*
return 0;
}
+static void update_global_vars(void)
+{
+ syscall = (__cdecl syscall_t) rm_args.rm_syscall;
+ sys_bounce = (void *)rm_args.rm_bounce;
+ shdr = (void *)rm_args.rm_base;
+}
+
+/*
+ * Relocate the real-mode code to a new segment
+ */
+struct gdt_ptr {
+ uint16_t limit;
+ uint32_t base;
+} __attribute__((packed));
+
+static void set_seg_base(uint32_t gdt_base, int seg, uint32_t v)
+{
+ *(uint16_t *)(gdt_base + seg + 2) = v;
+ *(uint8_t *)(gdt_base + seg + 4) = v >> 16;
+ *(uint8_t *)(gdt_base + seg + 7) = v >> 24;
+}
+
+static void relocate_rm_code(uint32_t newbase)
+{
+ uint32_t gdt_base;
+ uint32_t oldbase = rm_args.rm_base;
+ uint32_t delta = newbase - oldbase;
+
+ cli();
+ memmove((void *)newbase, (void *)oldbase, rm_args.rm_size);
+
+ rm_args.rm_return += delta;
+ rm_args.rm_syscall += delta;
+ rm_args.rm_bounce += delta;
+ rm_args.rm_base += delta;
+ rm_args.rm_gdt += delta;
+ rm_args.rm_handle_interrupt += delta;
+
+ gdt_base = rm_args.rm_gdt;
+
+ *(uint32_t *)(gdt_base+2) = gdt_base; /* GDT self-pointer */
+
+ /* Segments 0x10 and 0x18 are real-mode-based */
+ set_seg_base(gdt_base, 0x10, rm_args.rm_base);
+ set_seg_base(gdt_base, 0x18, rm_args.rm_base);
+
+ asm volatile("lgdtl %0" : : "m" (*(char *)gdt_base));
+ sti();
+
+ update_global_vars();
+}
+
#define STACK_NEEDED 512 /* Number of bytes of stack */
/*
* Returns the drive number (which is then passed in %dl to the
* called routine.)
*/
-__cdecl syscall_t syscall;
-void *sys_bounce;
-
void setup(const struct real_mode_args *rm_args_ptr)
{
unsigned int bin_size;
int total_size, cmdlinelen;
com32sys_t regs;
uint32_t ramdisk_image, ramdisk_size;
+ uint32_t boot_base, rm_base;
int bios_drives;
int do_edd = 1; /* 0 = no, 1 = yes, default is yes */
int no_bpt; /* No valid BPT presented */
+ uint32_t boot_seg = 0; /* Meaning 0000:7C00 */
+ uint32_t boot_len = 512; /* One sector */
+ uint32_t boot_lba = 0; /* LBA of bootstrap code */
/* We need to copy the rm_args into their proper place */
memcpy(&rm_args, rm_args_ptr, sizeof rm_args);
sti(); /* ... then interrupts are safe */
/* Set up global variables */
- syscall = (__cdecl syscall_t) rm_args.rm_syscall;
- sys_bounce = (void *)rm_args.rm_bounce;
- shdr = (void *)rm_args.rm_base;
+ update_global_vars();
/* Show signs of life */
printf("%s %s\n", memdisk_version, copyright);
wrz_8(BIOS_EQUIP, equip);
/* Install DPT pointer if this was the only floppy */
- if (getcmditem("dpt") != CMD_NOTFOUND || ((nflop == 1 || no_bpt)
- && getcmditem("nodpt") ==
- CMD_NOTFOUND)) {
+ if (getcmditem("dpt") != CMD_NOTFOUND ||
+ ((nflop == 1 || no_bpt) && getcmditem("nodpt") == CMD_NOTFOUND)) {
/* Do install a replacement DPT into INT 1Eh */
pptr->dpt_ptr = hptr->patch_offs + offsetof(struct patch_area, dpt);
}
printf("new: int13 = %08x int15 = %08x int1e = %08x\n",
rdz_32(BIOS_INT13), rdz_32(BIOS_INT15), rdz_32(BIOS_INT1E));
- /* Reboot into the new "disk"; this is also a test for the interrupt hooks */
- puts("Loading boot sector... ");
-
- memset(®s, 0, sizeof regs);
- // regs.es = 0;
- regs.eax.w[0] = 0x0201; /* Read sector */
- regs.ebx.w[0] = 0x7c00; /* 0000:7C00 */
- regs.ecx.w[0] = 1; /* One sector */
- regs.edx.w[0] = geometry->driveno;
- syscall(0x13, ®s, ®s);
+ /* Figure out entry point */
+ if (!boot_seg) {
+ boot_base = 0x7c00;
+ shdr->sssp = 0x7c00;
+ shdr->csip = 0x7c00;
+ } else {
+ boot_base = boot_seg << 4;
+ shdr->sssp = boot_seg << 16;
+ shdr->csip = boot_seg << 16;
+ }
- if (regs.eflags.l & 1) {
- puts("MEMDISK: Failed to load new boot sector\n");
+ /* Relocate the real-mode code to below the stub */
+ rm_base = (driveraddr - rm_args.rm_size) & ~15;
+ if (rm_base < boot_base + boot_len) {
+ puts("MEMDISK: bootstrap too large to load\n");
die();
}
+ relocate_rm_code(rm_base);
+
+ /* Reboot into the new "disk" */
+ puts("Loading boot sector... ");
+
+ memcpy((void *)boot_base, (char *)pptr->diskbuf + boot_lba*512, boot_len);
if (getcmditem("pause") != CMD_NOTFOUND) {
puts("press any key to boot... ");
/* On return the assembly code will jump to the boot vector */
shdr->esdi = pnp_install_check();
shdr->edx = geometry->driveno;
- shdr->sssp = 0x7c00;
- shdr->csip = 0x7c00;
}