Index: head/sys/boot/pc98/btx/btx/Makefile =================================================================== --- head/sys/boot/pc98/btx/btx/Makefile (revision 235263) +++ head/sys/boot/pc98/btx/btx/Makefile (revision 235264) @@ -1,33 +1,34 @@ # $FreeBSD$ PROG= btx INTERNALPROG= NO_MAN= SRCS= btx.S .if defined(BOOT_BTX_NOHANG) BOOT_BTX_FLAGS=0x1 .else BOOT_BTX_FLAGS=0x0 .endif CFLAGS+=-DBTX_FLAGS=${BOOT_BTX_FLAGS} +CFLAGS+=-I${.CURDIR}/../../../i386/common .if defined(BTX_SERIAL) BOOT_COMCONSOLE_PORT?= 0x238 BOOT_COMCONSOLE_SPEED?= 9600 B2SIOFMT?= 0x3 CFLAGS+=-DBTX_SERIAL -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} -DSIOSPD=${BOOT_COMCONSOLE_SPEED} .endif ORG= 0x9000 LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.btx.S= ${CLANG_NO_IAS} CFLAGS+= ${CFLAGS.${.IMPSRC:T}} Index: head/sys/boot/pc98/btx/btx/btx.S =================================================================== --- head/sys/boot/pc98/btx/btx/btx.S (revision 235263) +++ head/sys/boot/pc98/btx/btx/btx.S (revision 235264) @@ -1,1097 +1,1099 @@ /* * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. * * $FreeBSD$ */ +#include + /* * Memory layout. */ .set MEM_BTX,0x1000 # Start of BTX memory .set MEM_ESP0,0x1800 # Supervisor stack .set MEM_BUF,0x1800 # Scratch buffer .set MEM_ESPR,0x5e00 # Real mode stack .set MEM_IDT,0x5e00 # IDT .set MEM_TSS,0x5f98 # TSS .set MEM_MAP,0x6000 # I/O bit map .set MEM_TSS_END,0x7fff # End of TSS .set MEM_ORG,0x9000 # BTX code .set MEM_USR,0xa000 # Start of user memory /* * Paging control. */ .set PAG_SIZ,0x1000 # Page size .set PAG_CNT,0x1000 # Pages to map /* * Fields in %eflags. */ .set PSL_RESERVED_DEFAULT,0x00000002 .set PSL_T,0x00000100 # Trap flag .set PSL_I,0x00000200 # Interrupt enable flag .set PSL_VM,0x00020000 # Virtual 8086 mode flag .set PSL_AC,0x00040000 # Alignment check flag /* * Segment selectors. */ .set SEL_SCODE,0x8 # Supervisor code .set SEL_SDATA,0x10 # Supervisor data .set SEL_RCODE,0x18 # Real mode code .set SEL_RDATA,0x20 # Real mode data .set SEL_UCODE,0x28|3 # User code .set SEL_UDATA,0x30|3 # User data .set SEL_TSS,0x38 # TSS /* * Task state segment fields. */ .set TSS_ESP0,0x4 # PL 0 ESP .set TSS_SS0,0x8 # PL 0 SS .set TSS_MAP,0x66 # I/O bit map base /* * System calls. */ .set SYS_EXIT,0x0 # Exit .set SYS_EXEC,0x1 # Exec /* * Fields in V86 interface structure. */ .set V86_CTL,0x0 # Control flags .set V86_ADDR,0x4 # Int number/address .set V86_ES,0x8 # V86 ES .set V86_DS,0xc # V86 DS .set V86_FS,0x10 # V86 FS .set V86_GS,0x14 # V86 GS /* * V86 control flags. */ .set V86F_ADDR,0x10000 # Segment:offset address .set V86F_CALLF,0x20000 # Emulate far call .set V86F_FLAGS,0x40000 # Return flags /* * Dump format control bytes. */ .set DMP_X16,0x1 # Word .set DMP_X32,0x2 # Long .set DMP_MEM,0x4 # Memory .set DMP_EOL,0x8 # End of line /* * Screen defaults and assumptions. */ .set SCR_MAT,0xe1 # Mode/attribute .set SCR_COL,0x50 # Columns per row .set SCR_ROW,0x19 # Rows per screen /* * BIOS Data Area locations. */ .set BDA_MEM,0x501 # Free memory .set BDA_POS,0x53e # Cursor position /* * Derivations, for brevity. */ .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0 .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base .set _TSSLM,MEM_TSS_END-MEM_TSS # TSS limit .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit /* * Code segment. */ .globl start .code16 start: # Start of code /* * BTX header. */ btx_hdr: .byte 0xeb # Machine ID .byte 0xe # Header size .ascii "BTX" # Magic .byte 0x1 # Major version .byte 0x2 # Minor version .byte BTX_FLAGS # Flags .word PAG_CNT-MEM_ORG>>0xc # Paging control .word break-start # Text size .long 0x0 # Entry address /* * Initialization routine. */ init: cli # Disable interrupts xor %ax,%ax # Zero/segment mov %ax,%ss # Set up mov $MEM_ESP0,%sp # stack mov %ax,%es # Address mov %ax,%ds # data pushl $0x2 # Clear popfl # flags /* * Initialize memory. */ mov $MEM_IDT,%di # Memory to initialize mov $(MEM_ORG-MEM_IDT)/2,%cx # Words to zero rep # Zero-fill stosw # memory /* * Update real mode IDT for reflecting hardware interrupts. */ mov $intr20,%bx # Address first handler mov $0x10,%cx # Number of handlers mov $0x20*4,%di # First real mode IDT entry init.0: mov %bx,(%di) # Store IP inc %di # Address next inc %di # entry stosw # Store CS add $4,%bx # Next handler loop init.0 # Next IRQ /* * Create IDT. */ mov $MEM_IDT,%di mov $idtctl,%si # Control string init.1: lodsb # Get entry cbw # count xchg %ax,%cx # as word jcxz init.4 # If done lodsb # Get segment xchg %ax,%dx # P:DPL:type lodsw # Get control xchg %ax,%bx # set lodsw # Get handler offset mov $SEL_SCODE,%dh # Segment selector init.2: shr %bx # Handle this int? jnc init.3 # No mov %ax,(%di) # Set handler offset mov %dh,0x2(%di) # and selector mov %dl,0x5(%di) # Set P:DPL:type add $0x4,%ax # Next handler init.3: lea 0x8(%di),%di # Next entry loop init.2 # Till set done jmp init.1 # Continue /* * Initialize TSS. */ init.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0 movb $SEL_SDATA,TSS_SS0(%di) # Set SS0 movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base /* * Bring up the system. */ mov $0x2820,%bx # Set protected mode callw setpic # IRQ offsets lidt idtdesc # Set IDT lgdt gdtdesc # Set GDT mov %cr0,%eax # Switch to protected inc %ax # mode mov %eax,%cr0 # ljmp $SEL_SCODE,$init.8 # To 32-bit code .code32 init.8: xorl %ecx,%ecx # Zero movb $SEL_SDATA,%cl # To 32-bit movw %cx,%ss # stack /* * Launch user task. */ movb $SEL_TSS,%cl # Set task ltr %cx # register movl $MEM_USR,%edx # User base address movzwl %ss:BDA_MEM,%eax # Get free memory andl $0x7,%eax incl %eax shll $0x11,%eax # To bytes - subl $0x1000,%eax # Less arg space + subl $ARGSPACE,%eax # Less arg space subl %edx,%eax # Less base movb $SEL_UDATA,%cl # User data selector pushl %ecx # Set SS pushl %eax # Set ESP push $0x202 # Set flags (IF set) push $SEL_UCODE # Set CS pushl btx_hdr+0xc # Set EIP pushl %ecx # Set GS pushl %ecx # Set FS pushl %ecx # Set DS pushl %ecx # Set ES pushl %edx # Set EAX movb $0x7,%cl # Set remaining init.9: push $0x0 # general loop init.9 # registers #ifdef BTX_SERIAL call sio_init # setup the serial console #endif popa # and initialize popl %es # Initialize popl %ds # user popl %fs # segment popl %gs # registers iret # To user mode /* * Exit routine. */ exit: cli # Disable interrupts movl $MEM_ESP0,%esp # Clear stack /* * Turn off paging. */ movl %cr0,%eax # Get CR0 andl $~0x80000000,%eax # Disable movl %eax,%cr0 # paging xorl %ecx,%ecx # Zero movl %ecx,%cr3 # Flush TLB /* * Restore the GDT in case we caught a kernel trap. */ lgdt gdtdesc # Set GDT /* * To 16 bits. */ ljmpw $SEL_RCODE,$exit.1 # Reload CS .code16 exit.1: mov $SEL_RDATA,%cl # 16-bit selector mov %cx,%ss # Reload SS mov %cx,%ds # Load mov %cx,%es # remaining mov %cx,%fs # segment mov %cx,%gs # registers /* * To real-address mode. */ dec %ax # Switch to mov %eax,%cr0 # real mode ljmp $0x0,$exit.2 # Reload CS exit.2: xor %ax,%ax # Real mode segment mov %ax,%ss # Reload SS mov %ax,%ds # Address data mov $0x1008,%bx # Set real mode callw setpic # IRQ offsets lidt ivtdesc # Set IVT /* * Reboot or await reset. */ sti # Enable interrupts testb $0x1,btx_hdr+0x7 # Reboot? exit.3: jz exit.3 # No movb $0xa0,%al outb %al,$0x35 movb $0x00,%al outb %al,$0xf0 # reboot the machine exit.4: jmp exit.4 /* * Set IRQ offsets by reprogramming 8259A PICs. */ setpic: in $0x02,%al # Save master push %ax # IMR in $0x0a,%al # Save slave push %ax # IMR movb $0x11,%al # ICW1 to outb %al,$0x00 # master, outb %al,$0x08 # slave movb %bl,%al # ICW2 to outb %al,$0x02 # master movb %bh,%al # ICW2 to outb %al,$0x0a # slave movb $0x80,%al # ICW3 to outb %al,$0x02 # master movb $0x7,%al # ICW3 to outb %al,$0x0a # slave movb $0x1d,%al # ICW4 to outb %al,$0x02 # master, movb $0x9,%al # ICW4 to outb %al,$0x0a # slave pop %ax # Restore slave outb %al,$0x0a # IMR pop %ax # Restore master outb %al,$0x02 # IMR retw # To caller .code32 /* * Exception jump table. */ intx00: push $0x0 # Int 0x0: #DE jmp ex_noc # Divide error push $0x1 # Int 0x1: #DB jmp ex_noc # Debug push $0x3 # Int 0x3: #BP jmp ex_noc # Breakpoint push $0x4 # Int 0x4: #OF jmp ex_noc # Overflow push $0x5 # Int 0x5: #BR jmp ex_noc # BOUND range exceeded push $0x6 # Int 0x6: #UD jmp ex_noc # Invalid opcode push $0x7 # Int 0x7: #NM jmp ex_noc # Device not available push $0x8 # Int 0x8: #DF jmp except # Double fault push $0xa # Int 0xa: #TS jmp except # Invalid TSS push $0xb # Int 0xb: #NP jmp except # Segment not present push $0xc # Int 0xc: #SS jmp except # Stack segment fault push $0xd # Int 0xd: #GP jmp except # General protection push $0xe # Int 0xe: #PF jmp except # Page fault intx10: push $0x10 # Int 0x10: #MF jmp ex_noc # Floating-point error /* * Save a zero error code. */ ex_noc: pushl (%esp,1) # Duplicate int no movb $0x0,0x4(%esp,1) # Fake error code /* * Handle exception. */ except: cld # String ops inc pushl %ds # Save pushl %es # most pusha # registers pushl %gs # Set GS pushl %fs # Set FS pushl %ds # Set DS pushl %es # Set ES cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode? jne except.1 # No pushl %ss # Set SS jmp except.2 # Join common code except.1: pushl 0x50(%esp,1) # Set SS except.2: pushl 0x50(%esp,1) # Set ESP push $SEL_SDATA # Set up popl %ds # to pushl %ds # address popl %es # data movl %esp,%ebx # Stack frame movl $dmpfmt,%esi # Dump format string movl $MEM_BUF,%edi # Buffer pushl %eax pushl %edx wait.1: inb $0x60,%al testb $0x04,%al jz wait.1 movb $0xe0,%al outb %al,$0x62 wait.2: inb $0x60,%al testb $0x01,%al jz wait.2 xorl %edx,%edx inb $0x62,%al movb %al,%dl inb $0x62,%al movb %al,%dh inb $0x62,%al inb $0x62,%al inb $0x62,%al movl %edx,%eax shlw $1,%ax movl $BDA_POS,%edx movw %ax,(%edx) popl %edx popl %eax pushl %edi # Dump to call dump # buffer popl %esi # and call putstr # display leal 0x18(%esp,1),%esp # Discard frame popa # Restore popl %es # registers popl %ds # saved cmpb $0x3,(%esp,1) # Breakpoint? je except.3 # Yes cmpb $0x1,(%esp,1) # Debug? jne except.2a # No testl $PSL_T,0x10(%esp,1) # Trap flag set? jnz except.3 # Yes except.2a: jmp exit # Exit except.3: leal 0x8(%esp,1),%esp # Discard err, int no iret # From interrupt /* * Reboot the machine by setting the reboot flag and exiting */ reboot: orb $0x1,btx_hdr+0x7 # Set the reboot flag jmp exit # Terminate BTX and reboot /* * Protected Mode Hardware interrupt jump table. */ intx20: push $0x8 # Int 0x20: IRQ0 jmp int_hw # V86 int 0x8 push $0x9 # Int 0x21: IRQ1 jmp int_hw # V86 int 0x9 push $0xa # Int 0x22: IRQ2 jmp int_hw # V86 int 0xa push $0xb # Int 0x23: IRQ3 jmp int_hw # V86 int 0xb push $0xc # Int 0x24: IRQ4 jmp int_hw # V86 int 0xc push $0xd # Int 0x25: IRQ5 jmp int_hw # V86 int 0xd push $0xe # Int 0x26: IRQ6 jmp int_hw # V86 int 0xe push $0xf # Int 0x27: IRQ7 jmp int_hw # V86 int 0xf push $0x10 # Int 0x28: IRQ8 jmp int_hw # V86 int 0x10 push $0x11 # Int 0x29: IRQ9 jmp int_hw # V86 int 0x11 push $0x12 # Int 0x2a: IRQ10 jmp int_hw # V86 int 0x12 push $0x13 # Int 0x2b: IRQ11 jmp int_hw # V86 int 0x13 push $0x14 # Int 0x2c: IRQ12 jmp int_hw # V86 int 0x14 push $0x15 # Int 0x2d: IRQ13 jmp int_hw # V86 int 0x15 push $0x16 # Int 0x2e: IRQ14 jmp int_hw # V86 int 0x16 push $0x17 # Int 0x2f: IRQ15 jmp int_hw # V86 int 0x17 /* * Invoke real mode interrupt/function call from user mode with arguments. */ intx31: pushl $-1 # Dummy int no for btx_v86 /* * Invoke real mode interrupt/function call from protected mode. * * We place a trampoline on the user stack that will return to rret_tramp * which will reenter protected mode and then finally return to the user * client. * * Kernel frame %esi points to: Real mode stack frame at MEM_ESPR: * * -0x00 user %ss -0x04 kernel %esp (with full frame) * -0x04 user %esp -0x08 btx_v86 pointer * -0x08 user %eflags -0x0c flags (only used if interrupt) * -0x0c user %cs -0x10 real mode CS:IP return trampoline * -0x10 user %eip -0x12 real mode flags * -0x14 int no -0x16 real mode CS:IP (target) * -0x18 %eax * -0x1c %ecx * -0x20 %edx * -0x24 %ebx * -0x28 %esp * -0x2c %ebp * -0x30 %esi * -0x34 %edi * -0x38 %gs * -0x3c %fs * -0x40 %ds * -0x44 %es * -0x48 zero %eax (hardware int only) * -0x4c zero %ecx (hardware int only) * -0x50 zero %edx (hardware int only) * -0x54 zero %ebx (hardware int only) * -0x58 zero %esp (hardware int only) * -0x5c zero %ebp (hardware int only) * -0x60 zero %esi (hardware int only) * -0x64 zero %edi (hardware int only) * -0x68 zero %gs (hardware int only) * -0x6c zero %fs (hardware int only) * -0x70 zero %ds (hardware int only) * -0x74 zero %es (hardware int only) */ int_hw: cld # String ops inc pusha # Save gp regs pushl %gs # Save pushl %fs # seg pushl %ds # regs pushl %es push $SEL_SDATA # Set up popl %ds # to pushl %ds # address popl %es # data leal 0x44(%esp,1),%esi # Base of frame movl %esp,MEM_ESPR-0x04 # Save kernel stack pointer movl -0x14(%esi),%eax # Get Int no cmpl $-1,%eax # Hardware interrupt? jne intusr.1 # Yes /* * v86 calls save the btx_v86 pointer on the real mode stack and read * the address and flags from the btx_v86 structure. For interrupt * handler invocations (VM86 INTx requests), disable interrupts, * tracing, and alignment checking while the handler runs. */ movl $MEM_USR,%ebx # User base movl %ebx,%edx # address addl -0x4(%esi),%ebx # User ESP movl (%ebx),%ebp # btx_v86 pointer addl %ebp,%edx # Flatten btx_v86 ptr movl %edx,MEM_ESPR-0x08 # Save btx_v86 ptr movl V86_ADDR(%edx),%eax # Get int no/address movl V86_CTL(%edx),%edx # Get control flags movl -0x08(%esi),%ebx # Save user flags in %ebx testl $V86F_ADDR,%edx # Segment:offset? jnz intusr.4 # Yes andl $~(PSL_I|PSL_T|PSL_AC),%ebx # Disable interrupts, tracing, # and alignment checking for # interrupt handler jmp intusr.3 # Skip hardware interrupt /* * Hardware interrupts store a NULL btx_v86 pointer and use the * address (interrupt number) from the stack with empty flags. Also, * push a dummy frame of zeros onto the stack for all the general * purpose and segment registers and clear %eflags. This gives the * hardware interrupt handler a clean slate. */ intusr.1: xorl %edx,%edx # Control flags movl %edx,MEM_ESPR-0x08 # NULL btx_v86 ptr movl $12,%ecx # Frame is 12 dwords intusr.2: pushl $0x0 # Fill frame loop intusr.2 # with zeros movl $PSL_RESERVED_DEFAULT,%ebx # Set clean %eflags /* * Look up real mode IDT entry for hardware interrupts and VM86 INTx * requests. */ intusr.3: shll $0x2,%eax # Scale movl (%eax),%eax # Load int vector jmp intusr.5 # Skip CALLF test /* * Panic if V86F_CALLF isn't set with V86F_ADDR. */ intusr.4: testl $V86F_CALLF,%edx # Far call? jnz intusr.5 # Ok movl %edx,0x30(%esp,1) # Place VM86 flags in int no movl $badvm86,%esi # Display bad call putstr # VM86 call popl %es # Restore popl %ds # seg popl %fs # regs popl %gs popal # Restore gp regs jmp ex_noc # Panic /* * %eax now holds the segment:offset of the function. * %ebx now holds the %eflags to pass to real mode. * %edx now holds the V86F_* flags. */ intusr.5: movw %bx,MEM_ESPR-0x12 # Pass user flags to real mode # target /* * If this is a v86 call, copy the seg regs out of the btx_v86 structure. */ movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr jecxz intusr.6 # Skip for hardware ints leal -0x44(%esi),%edi # %edi => kernel stack seg regs pushl %esi # Save leal V86_ES(%ecx),%esi # %esi => btx_v86 seg regs movl $4,%ecx # Copy seg regs rep # from btx_v86 movsl # to kernel stack popl %esi # Restore intusr.6: movl -0x08(%esi),%ebx # Copy user flags to real movl %ebx,MEM_ESPR-0x0c # mode return trampoline movl $rret_tramp,%ebx # Set return trampoline movl %ebx,MEM_ESPR-0x10 # CS:IP movl %eax,MEM_ESPR-0x16 # Real mode target CS:IP ljmpw $SEL_RCODE,$intusr.7 # Change to 16-bit segment .code16 intusr.7: movl %cr0,%eax # Leave dec %al # protected movl %eax,%cr0 # mode ljmpw $0x0,$intusr.8 intusr.8: xorw %ax,%ax # Reset %ds movw %ax,%ds # and movw %ax,%ss # %ss lidt ivtdesc # Set IVT popl %es # Restore popl %ds # seg popl %fs # regs popl %gs popal # Restore gp regs movw $MEM_ESPR-0x16,%sp # Switch to real mode stack iret # Call target routine /* * For the return to real mode we setup a stack frame like this on the real * mode stack. Note that callf calls won't pop off the flags, but we just * ignore that by repositioning %sp to be just above the btx_v86 pointer * so it is aligned. The stack is relative to MEM_ESPR. * * -0x04 kernel %esp * -0x08 btx_v86 * -0x0c %eax * -0x10 %ecx * -0x14 %edx * -0x18 %ebx * -0x1c %esp * -0x20 %ebp * -0x24 %esi * -0x28 %edi * -0x2c %gs * -0x30 %fs * -0x34 %ds * -0x38 %es * -0x3c %eflags */ rret_tramp: movw $MEM_ESPR-0x08,%sp # Reset stack pointer pushal # Save gp regs pushl %gs # Save pushl %fs # seg pushl %ds # regs pushl %es pushfl # Save %eflags cli # Disable interrupts std # String ops dec xorw %ax,%ax # Reset seg movw %ax,%ds # regs movw %ax,%es # (%ss is already 0) lidt idtdesc # Set IDT lgdt gdtdesc # Set GDT mov %cr0,%eax # Switch to protected inc %ax # mode mov %eax,%cr0 # ljmp $SEL_SCODE,$rret_tramp.1 # To 32-bit code .code32 rret_tramp.1: xorl %ecx,%ecx # Zero movb $SEL_SDATA,%cl # Setup movw %cx,%ss # 32-bit movw %cx,%ds # seg movw %cx,%es # regs movl MEM_ESPR-0x04,%esp # Switch to kernel stack leal 0x44(%esp,1),%esi # Base of frame andb $~0x2,tss_desc+0x5 # Clear TSS busy movb $SEL_TSS,%cl # Set task ltr %cx # register /* * Now we are back in protected mode. The kernel stack frame set up * before entering real mode is still intact. For hardware interrupts, * leave the frame unchanged. */ cmpl $0,MEM_ESPR-0x08 # Leave saved regs unchanged jz rret_tramp.3 # for hardware ints /* * For V86 calls, copy the registers off of the real mode stack onto * the kernel stack as we want their updated values. Also, initialize * the segment registers on the kernel stack. * * Note that the %esp in the kernel stack after this is garbage, but popa * ignores it, so we don't have to fix it up. */ leal -0x18(%esi),%edi # Kernel stack GP regs pushl %esi # Save movl $MEM_ESPR-0x0c,%esi # Real mode stack GP regs movl $8,%ecx # Copy GP regs from rep # real mode stack movsl # to kernel stack movl $SEL_UDATA,%eax # Selector for data seg regs movl $4,%ecx # Initialize %ds, rep # %es, %fs, and stosl # %gs /* * For V86 calls, copy the saved seg regs on the real mode stack back * over to the btx_v86 structure. Also, conditionally update the * saved eflags on the kernel stack based on the flags from the user. */ movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr leal V86_GS(%ecx),%edi # %edi => btx_v86 seg regs leal MEM_ESPR-0x2c,%esi # %esi => real mode seg regs xchgl %ecx,%edx # Save btx_v86 ptr movl $4,%ecx # Copy seg regs rep # from real mode stack movsl # to btx_v86 popl %esi # Restore movl V86_CTL(%edx),%edx # Read V86 control flags testl $V86F_FLAGS,%edx # User wants flags? jz rret_tramp.3 # No movl MEM_ESPR-0x3c,%eax # Read real mode flags movw %ax,-0x08(%esi) # Update user flags (low 16) /* * Return to the user task */ rret_tramp.3: popl %es # Restore popl %ds # seg popl %fs # regs popl %gs popal # Restore gp regs addl $4,%esp # Discard int no iret # Return to user mode /* * System Call. */ intx30: cmpl $SYS_EXEC,%eax # Exec system call? jne intx30.1 # No pushl %ss # Set up popl %es # all pushl %es # segment popl %ds # registers pushl %ds # for the popl %fs # program pushl %fs # we're popl %gs # invoking movl $MEM_USR,%eax # User base address addl 0xc(%esp,1),%eax # Change to user leal 0x4(%eax),%esp # stack popl %eax # Call call *%eax # program intx30.1: orb $0x1,%ss:btx_hdr+0x7 # Flag reboot jmp exit # Exit /* * Dump structure [EBX] to [EDI], using format string [ESI]. */ dump.0: stosb # Save char dump: lodsb # Load char testb %al,%al # End of string? jz dump.10 # Yes testb $0x80,%al # Control? jz dump.0 # No movb %al,%ch # Save control movb $'=',%al # Append stosb # '=' lodsb # Get offset pushl %esi # Save movsbl %al,%esi # To addl %ebx,%esi # pointer testb $DMP_X16,%ch # Dump word? jz dump.1 # No lodsw # Get and call hex16 # dump it dump.1: testb $DMP_X32,%ch # Dump long? jz dump.2 # No lodsl # Get and call hex32 # dump it dump.2: testb $DMP_MEM,%ch # Dump memory? jz dump.8 # No pushl %ds # Save testl $PSL_VM,0x50(%ebx) # V86 mode? jnz dump.3 # Yes verr 0x4(%esi) # Readable selector? jnz dump.3 # No ldsl (%esi),%esi # Load pointer jmp dump.4 # Join common code dump.3: lodsl # Set offset xchgl %eax,%edx # Save lodsl # Get segment shll $0x4,%eax # * 0x10 addl %edx,%eax # + offset xchgl %eax,%esi # Set pointer dump.4: movb $2,%dl # Num lines dump.4a: movb $0x10,%cl # Bytes to dump dump.5: lodsb # Get byte and call hex8 # dump it decb %cl # Keep count jz dump.6a # If done movb $'-',%al # Separator cmpb $0x8,%cl # Half way? je dump.6 # Yes movb $' ',%al # Use space dump.6: stosb # Save separator jmp dump.5 # Continue dump.6a: decb %dl # Keep count jz dump.7 # If done movb $0xa,%al # Line feed stosb # Save one movb $7,%cl # Leading movb $' ',%al # spaces dump.6b: stosb # Dump decb %cl # spaces jnz dump.6b jmp dump.4a # Next line dump.7: popl %ds # Restore dump.8: popl %esi # Restore movb $0xa,%al # Line feed testb $DMP_EOL,%ch # End of line? jnz dump.9 # Yes movb $' ',%al # Use spaces stosb # Save one dump.9: jmp dump.0 # Continue dump.10: stosb # Terminate string ret # To caller /* * Convert EAX, AX, or AL to hex, saving the result to [EDI]. */ hex32: pushl %eax # Save shrl $0x10,%eax # Do upper call hex16 # 16 popl %eax # Restore hex16: call hex16.1 # Do upper 8 hex16.1: xchgb %ah,%al # Save/restore hex8: pushl %eax # Save shrb $0x4,%al # Do upper call hex8.1 # 4 popl %eax # Restore hex8.1: andb $0xf,%al # Get lower 4 cmpb $0xa,%al # Convert sbbb $0x69,%al # to hex das # digit orb $0x20,%al # To lower case stosb # Save char ret # (Recursive) /* * Output zero-terminated string [ESI] to the console. */ putstr.0: call putchr # Output char putstr: lodsb # Load char testb %al,%al # End of string? jnz putstr.0 # No ret # To caller #ifdef BTX_SERIAL .set SIO_PRT,SIOPRT # Base port .set SIO_FMT,SIOFMT # 8N1 .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD /* * void sio_init(void) */ sio_init: movw $SIO_PRT+0x3,%dx # Data format reg movb $SIO_FMT|0x80,%al # Set format outb %al,(%dx) # and DLAB pushl %edx # Save subb $0x3,%dl # Divisor latch reg movw $SIO_DIV,%ax # Set outw %ax,(%dx) # BPS popl %edx # Restore movb $SIO_FMT,%al # Clear outb %al,(%dx) # DLAB incl %edx # Modem control reg movb $0x3,%al # Set RTS, outb %al,(%dx) # DTR incl %edx # Line status reg /* * void sio_flush(void) */ sio_flush.0: call sio_getc.1 # Get character sio_flush: call sio_ischar # Check for character jnz sio_flush.0 # Till none ret # To caller /* * void sio_putc(int c) */ sio_putc: movw $SIO_PRT+0x5,%dx # Line status reg xor %ecx,%ecx # Timeout movb $0x40,%ch # counter sio_putc.1: inb (%dx),%al # Transmitter testb $0x20,%al # buffer empty? loopz sio_putc.1 # No jz sio_putc.2 # If timeout movb 0x4(%esp,1),%al # Get character subb $0x5,%dl # Transmitter hold reg outb %al,(%dx) # Write character sio_putc.2: ret $0x4 # To caller /* * int sio_getc(void) */ sio_getc: call sio_ischar # Character available? jz sio_getc # No sio_getc.1: subb $0x5,%dl # Receiver buffer reg inb (%dx),%al # Read character ret # To caller /* * int sio_ischar(void) */ sio_ischar: movw $SIO_PRT+0x5,%dx # Line status register xorl %eax,%eax # Zero inb (%dx),%al # Received data andb $0x1,%al # ready? ret # To caller /* * Output character AL to the serial console. */ putchr: pusha # Save cmpb $10, %al # is it a newline? jne putchr.1 # no?, then leave push $13 # output a carriage call sio_putc # return first movb $10, %al # restore %al putchr.1: pushl %eax # Push the character # onto the stack call sio_putc # Output the character popa # Restore ret # To caller #else /* * Output character AL to the console. */ putchr: pusha # Save xorl %ecx,%ecx # Zero for loops movb $SCR_MAT,%ah # Mode/attribute movl $BDA_POS,%ebx # BDA pointer movw (%ebx),%dx # Cursor position movl $0xa0000,%edi putchr.1: cmpb $0xa,%al # New line? je putchr.2 # Yes movw %dx,%cx movb %al,(%edi,%ecx,1) # Write char addl $0x2000,%ecx movb %ah,(%edi,%ecx,1) # Write attr addw $0x02,%dx jmp putchr.3 putchr.2: movw %dx,%ax movb $SCR_COL*2,%dl div %dl incb %al mul %dl movw %ax,%dx putchr.3: cmpw $SCR_ROW*SCR_COL*2,%dx jb putchr.4 # No leal 2*SCR_COL(%edi),%esi # New top line movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move rep # Scroll movsl # screen movb $0x20,%al # Space xorb %ah,%ah movb $SCR_COL,%cl # Columns to clear rep # Clear stosw # line movw $(SCR_ROW-1)*SCR_COL*2,%dx putchr.4: movw %dx,(%ebx) # Update position popa # Restore ret # To caller #endif .code16 /* * Real Mode Hardware interrupt jump table. */ intr20: push $0x8 # Int 0x20: IRQ0 jmp int_hwr # V86 int 0x8 push $0x9 # Int 0x21: IRQ1 jmp int_hwr # V86 int 0x9 push $0xa # Int 0x22: IRQ2 jmp int_hwr # V86 int 0xa push $0xb # Int 0x23: IRQ3 jmp int_hwr # V86 int 0xb push $0xc # Int 0x24: IRQ4 jmp int_hwr # V86 int 0xc push $0xd # Int 0x25: IRQ5 jmp int_hwr # V86 int 0xd push $0xe # Int 0x26: IRQ6 jmp int_hwr # V86 int 0xe push $0xf # Int 0x27: IRQ7 jmp int_hwr # V86 int 0xf push $0x10 # Int 0x28: IRQ8 jmp int_hwr # V86 int 0x10 push $0x11 # Int 0x29: IRQ9 jmp int_hwr # V86 int 0x11 push $0x12 # Int 0x2a: IRQ10 jmp int_hwr # V86 int 0x12 push $0x13 # Int 0x2b: IRQ11 jmp int_hwr # V86 int 0x13 push $0x14 # Int 0x2c: IRQ12 jmp int_hwr # V86 int 0x14 push $0x15 # Int 0x2d: IRQ13 jmp int_hwr # V86 int 0x15 push $0x16 # Int 0x2e: IRQ14 jmp int_hwr # V86 int 0x16 push $0x17 # Int 0x2f: IRQ15 jmp int_hwr # V86 int 0x17 /* * Reflect hardware interrupts in real mode. */ int_hwr: push %ax # Save push %ds # Save push %bp # Save mov %sp,%bp # Address stack frame xchg %bx,6(%bp) # Swap BX, int no xor %ax,%ax # Set %ds:%bx to shl $2,%bx # point to mov %ax,%ds # IDT entry mov (%bx),%ax # Load IP mov 2(%bx),%bx # Load CS xchg %ax,4(%bp) # Swap saved %ax,%bx with xchg %bx,6(%bp) # CS:IP of handler pop %bp # Restore pop %ds # Restore lret # Jump to handler .p2align 4 /* * Global descriptor table. */ gdt: .word 0x0,0x0,0x0,0x0 # Null entry .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA tss_desc: .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS gdt.1: /* * Pseudo-descriptors. */ gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT /* * IDT construction control string. */ idtctl: .byte 0x10, 0x8e # Int 0x0-0xf .word 0x7dfb,intx00 # (exceptions) .byte 0x10, 0x8e # Int 0x10 .word 0x1, intx10 # (exception) .byte 0x10, 0x8e # Int 0x20-0x2f .word 0xffff,intx20 # (hardware) .byte 0x1, 0xee # int 0x30 .word 0x1, intx30 # (system call) .byte 0x2, 0xee # Int 0x31-0x32 .word 0x1, intx31 # (V86, null) .byte 0x0 # End of string /* * Dump format string. */ dmpfmt: .byte '\n' # "\n" .ascii "int" # "int=" .byte 0x80|DMP_X32, 0x40 # "00000000 " .ascii "err" # "err=" .byte 0x80|DMP_X32, 0x44 # "00000000 " .ascii "efl" # "efl=" .byte 0x80|DMP_X32, 0x50 # "00000000 " .ascii "eip" # "eip=" .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n" .ascii "eax" # "eax=" .byte 0x80|DMP_X32, 0x34 # "00000000 " .ascii "ebx" # "ebx=" .byte 0x80|DMP_X32, 0x28 # "00000000 " .ascii "ecx" # "ecx=" .byte 0x80|DMP_X32, 0x30 # "00000000 " .ascii "edx" # "edx=" .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n" .ascii "esi" # "esi=" .byte 0x80|DMP_X32, 0x1c # "00000000 " .ascii "edi" # "edi=" .byte 0x80|DMP_X32, 0x18 # "00000000 " .ascii "ebp" # "ebp=" .byte 0x80|DMP_X32, 0x20 # "00000000 " .ascii "esp" # "esp=" .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n" .ascii "cs" # "cs=" .byte 0x80|DMP_X16, 0x4c # "0000 " .ascii "ds" # "ds=" .byte 0x80|DMP_X16, 0xc # "0000 " .ascii "es" # "es=" .byte 0x80|DMP_X16, 0x8 # "0000 " .ascii " " # " " .ascii "fs" # "fs=" .byte 0x80|DMP_X16, 0x10 # "0000 " .ascii "gs" # "gs=" .byte 0x80|DMP_X16, 0x14 # "0000 " .ascii "ss" # "ss=" .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n" .ascii "cs:eip" # "cs:eip=" .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n" .ascii "ss:esp" # "ss:esp=" .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n" .asciz "BTX halted\n" # End /* * Bad VM86 call panic */ badvm86: .asciz "Invalid VM86 Request\n" /* * End of BTX memory. */ .p2align 4 break: Index: head/sys/boot/pc98/btx/btxldr/Makefile =================================================================== --- head/sys/boot/pc98/btx/btxldr/Makefile (revision 235263) +++ head/sys/boot/pc98/btx/btxldr/Makefile (revision 235264) @@ -1,20 +1,21 @@ # $FreeBSD$ PROG= btxldr INTERNALPROG= NO_MAN= SRCS= btxldr.S CFLAGS+=-DLOADER_ADDRESS=${LOADER_ADDRESS} +CFLAGS+=-I${.CURDIR}/../../../i386/common .if defined(BTXLDR_VERBOSE) CFLAGS+=-DBTXLDR_VERBOSE .endif LDFLAGS=-e start -Ttext ${LOADER_ADDRESS} -Wl,-N,-S,--oformat,binary .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.btxldr.S= ${CLANG_NO_IAS} CFLAGS+= ${CFLAGS.${.IMPSRC:T}} Index: head/sys/boot/pc98/btx/btxldr/btxldr.S =================================================================== --- head/sys/boot/pc98/btx/btxldr/btxldr.S (revision 235263) +++ head/sys/boot/pc98/btx/btxldr/btxldr.S (revision 235264) @@ -1,424 +1,430 @@ /* * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. * * $FreeBSD$ */ /* * Prototype BTX loader program, written in a couple of hours. The * real thing should probably be more flexible, and in C. */ +#include + /* * Memory locations. */ .set MEM_STUB,0x600 # Real mode stub .set MEM_ESP,0x1000 # New stack pointer .set MEM_TBL,0x5000 # BTX page tables .set MEM_ENTRY,0x9010 # BTX entry point .set MEM_DATA,start+0x1000 # Data segment /* * Segment selectors. */ .set SEL_SCODE,0x8 # 4GB code .set SEL_SDATA,0x10 # 4GB data .set SEL_RCODE,0x18 # 64K code .set SEL_RDATA,0x20 # 64K data /* * Paging constants. */ .set PAG_SIZ,0x1000 # Page size .set PAG_ENT,0x4 # Page entry size /* * Screen constants. */ .set SCR_MAT,0xe1 # Mode/attribute .set SCR_COL,0x50 # Columns per row .set SCR_ROW,0x19 # Rows per screen /* * BIOS Data Area locations. */ .set BDA_MEM,0xa1501 # Free memory .set BDA_POS,0xa153e # Cursor position /* * Required by aout gas inadequacy. */ .set SIZ_STUB,0x1a # Size of stub /* * We expect to be loaded by boot2 at the origin defined in ./Makefile. */ .globl start /* * BTX program loader for ELF clients. */ start: cld # String ops inc cli gdcwait.1: inb $0x60,%al testb $0x04,%al jz gdcwait.1 movb $0xe0,%al outb %al,$0x62 nop gdcwait.2: inb $0x60,%al testb $0x01,%al jz gdcwait.2 inb $0x62,%al movb %al,%dl inb $0x62,%al movb %al,%dh inb $0x62,%al inb $0x62,%al inb $0x62,%al shlw $1,%dx movl $BDA_POS,%ebx movw %dx,(%ebx) movl $m_logo,%esi # Identify call putstr # ourselves movzwl BDA_MEM,%eax # Get base memory andl $0x7,%eax incl %eax shll $0x11,%eax # in bytes movl %eax,%ebp # Base of user stack #ifdef BTXLDR_VERBOSE movl $m_mem,%esi # Display call hexout # amount of call putstr # base memory #endif lgdt gdtdesc # Load new GDT /* * Relocate caller's arguments. */ #ifdef BTXLDR_VERBOSE movl $m_esp,%esi # Display movl %esp,%eax # caller call hexout # stack call putstr # pointer movl $m_args,%esi # Format string - leal 0x4(%esp,1),%ebx # First argument + leal 0x4(%esp),%ebx # First argument movl $0x6,%ecx # Count start.1: movl (%ebx),%eax # Get argument and addl $0x4,%ebx # bump pointer call hexout # Display it loop start.1 # Till done call putstr # End message #endif - movl $0x48,%ecx # Allocate space - subl %ecx,%ebp # for bootinfo - movl 0x18(%esp,1),%esi # Source: bootinfo + movl BA_BOOTINFO+4(%esp),%esi # Source: bootinfo cmpl $0x0, %esi # If the bootinfo pointer je start_null_bi # is null, don't copy it + movl BI_SIZE(%esi),%ecx # Allocate space + subl %ecx,%ebp # for bootinfo movl %ebp,%edi # Destination rep # Copy movsb # it - movl %ebp,0x18(%esp,1) # Update pointer + movl %ebp,BA_BOOTINFO+4(%esp) # Update pointer + movl %edi,%ebp # Restore base pointer #ifdef BTXLDR_VERBOSE movl $m_rel_bi,%esi # Display movl %ebp,%eax # bootinfo call hexout # relocation call putstr # message #endif -start_null_bi: movl $0x18,%ecx # Allocate space - subl %ecx,%ebp # for arguments - leal 0x4(%esp,1),%esi # Source +start_null_bi: movl $BOOTARGS_SIZE,%ecx # Fixed size of arguments + testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data + jz start_fixed # Skip if the flag is not set + addl BOOTARGS_SIZE+4(%esp),%ecx # Add size of variable args +start_fixed: subl $ARGOFF,%ebp # Place args at fixed offset + leal 0x4(%esp),%esi # Source movl %ebp,%edi # Destination rep # Copy movsb # them #ifdef BTXLDR_VERBOSE movl $m_rel_args,%esi # Display movl %ebp,%eax # argument call hexout # relocation call putstr # message #endif /* * Set up BTX kernel. */ movl $MEM_ESP,%esp # Set up new stack movl $MEM_DATA,%ebx # Data segment movl $m_vers,%esi # Display BTX call putstr # version message movb 0x5(%ebx),%al # Get major version addb $'0',%al # Display call putchr # it movb $'.',%al # And a call putchr # dot movb 0x6(%ebx),%al # Get minor xorb %ah,%ah # version movb $0xa,%dl # Divide divb %dl,%al # by 10 addb $'0',%al # Display call putchr # tens movb %ah,%al # Get units addb $'0',%al # Display call putchr # units call putstr # End message movl %ebx,%esi # BTX image movzwl 0x8(%ebx),%edi # Compute orl $PAG_SIZ/PAG_ENT-1,%edi # the incl %edi # BTX shll $0x2,%edi # load addl $MEM_TBL,%edi # address pushl %edi # Save load address movzwl 0xa(%ebx),%ecx # Image size #ifdef BTXLDR_VERBOSE pushl %ecx # Save image size #endif rep # Relocate movsb # BTX movl %esi,%ebx # Keep place #ifdef BTXLDR_VERBOSE movl $m_rel_btx,%esi # Restore popl %eax # parameters call hexout # and #endif popl %ebp # display #ifdef BTXLDR_VERBOSE movl %ebp,%eax # the call hexout # relocation call putstr # message #endif addl $PAG_SIZ,%ebp # Display #ifdef BTXLDR_VERBOSE movl $m_base,%esi # the movl %ebp,%eax # user call hexout # base call putstr # address #endif /* * Set up ELF-format client program. */ cmpl $0x464c457f,(%ebx) # ELF magic number? je start.3 # Yes movl $e_fmt,%esi # Display error call putstr # message start.2: jmp start.2 # Hang start.3: #ifdef BTXLDR_VERBOSE movl $m_elf,%esi # Display ELF call putstr # message movl $m_segs,%esi # Format string #endif movl $0x2,%edi # Segment count movl 0x1c(%ebx),%edx # Get e_phoff addl %ebx,%edx # To pointer movzwl 0x2c(%ebx),%ecx # Get e_phnum start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD? jne start.6 # No #ifdef BTXLDR_VERBOSE movl 0x4(%edx),%eax # Display call hexout # p_offset movl 0x8(%edx),%eax # Display call hexout # p_vaddr movl 0x10(%edx),%eax # Display call hexout # p_filesz movl 0x14(%edx),%eax # Display call hexout # p_memsz call putstr # End message #endif pushl %esi # Save pushl %edi # working pushl %ecx # registers movl 0x4(%edx),%esi # Get p_offset addl %ebx,%esi # as pointer movl 0x8(%edx),%edi # Get p_vaddr addl %ebp,%edi # as pointer movl 0x10(%edx),%ecx # Get p_filesz rep # Set up movsb # segment movl 0x14(%edx),%ecx # Any bytes subl 0x10(%edx),%ecx # to zero? jz start.5 # No xorb %al,%al # Then rep # zero stosb # them start.5: popl %ecx # Restore popl %edi # working popl %esi # registers decl %edi # Segments to do je start.7 # If none start.6: addl $0x20,%edx # To next entry loop start.4 # Till done start.7: #ifdef BTXLDR_VERBOSE movl $m_done,%esi # Display done call putstr # message #endif movl $start.8,%esi # Real mode stub movl $MEM_STUB,%edi # Destination movl $start.9-start.8,%ecx # Size rep # Relocate movsb # it ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code .code16 start.8: xorw %ax,%ax # Data movb $SEL_RDATA,%al # selector movw %ax,%ss # Reload SS movw %ax,%ds # Reset movw %ax,%es # other movw %ax,%fs # segment movw %ax,%gs # limits movl %cr0,%eax # Switch to decw %ax # real movl %eax,%cr0 # mode ljmp $0,$MEM_ENTRY # Jump to BTX entry point start.9: .code32 /* * Output message [ESI] followed by EAX in hex. */ hexout: pushl %eax # Save call putstr # Display message popl %eax # Restore pushl %esi # Save pushl %edi # caller's movl $buf,%edi # Buffer pushl %edi # Save call hex32 # To hex xorb %al,%al # Terminate stosb # string popl %esi # Restore hexout.1: lodsb # Get a char cmpb $'0',%al # Leading zero? je hexout.1 # Yes testb %al,%al # End of string? jne hexout.2 # No decl %esi # Undo hexout.2: decl %esi # Adjust for inc call putstr # Display hex popl %edi # Restore popl %esi # caller's ret # To caller /* * Output zero-terminated string [ESI] to the console. */ putstr.0: call putchr # Output char putstr: lodsb # Load char testb %al,%al # End of string? jne putstr.0 # No ret # To caller /* * Output character AL to the console. */ putchr: pusha # Save xorl %ecx,%ecx # Zero for loops movb $SCR_MAT,%ah # Mode/attribute movl $BDA_POS,%ebx # BDA pointer movw (%ebx),%dx # Cursor position movl $0xa0000,%edi # Regen buffer (color) putchr.1: cmpb $0xa,%al # New line? je putchr.2 # Yes movw %dx,%cx movb %al,(%edi,%ecx,1) # Write char addl $0x2000,%ecx movb %ah,(%edi,%ecx,1) # Write attr addw $0x2,%dx jmp putchr.3 putchr.2: movw %dx,%ax movb $SCR_COL*2,%dl div %dl incb %al mul %dl movw %ax,%dx putchr.3: cmpw $SCR_COL*SCR_ROW*2,%dx jb putchr.4 # No leal 2*SCR_COL(%edi),%esi # New top line movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move rep # Scroll movsl # screen movb $' ',%al # Space xorb %ah,%ah movb $SCR_COL,%cl # Columns to clear rep # Clear stosw # line movw $(SCR_ROW-1)*SCR_COL*2,%dx putchr.4: movw %dx,(%ebx) # Update position shrw $1,%dx gdcwait.3: inb $0x60,%al testb $0x04,%al jz gdcwait.3 movb $0x49,%al outb %al,$0x62 movb %dl,%al outb %al,$0x60 movb %dh,%al outb %al,$0x60 popa # Restore ret # To caller /* * Convert EAX, AX, or AL to hex, saving the result to [EDI]. */ hex32: pushl %eax # Save shrl $0x10,%eax # Do upper call hex16 # 16 popl %eax # Restore hex16: call hex16.1 # Do upper 8 hex16.1: xchgb %ah,%al # Save/restore hex8: pushl %eax # Save shrb $0x4,%al # Do upper call hex8.1 # 4 popl %eax # Restore hex8.1: andb $0xf,%al # Get lower 4 cmpb $0xa,%al # Convert sbbb $0x69,%al # to hex das # digit orb $0x20,%al # To lower case stosb # Save char ret # (Recursive) .data .p2align 4 /* * Global descriptor table. */ gdt: .word 0x0,0x0,0x0,0x0 # Null entry .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA gdt.1: gdtdesc: .word gdt.1-gdt-1 # Limit .long gdt # Base /* * Messages. */ m_logo: .asciz " \nBTX loader 1.00 " m_vers: .asciz "BTX version is \0\n" e_fmt: .asciz "Error: Client format not supported\n" #ifdef BTXLDR_VERBOSE m_mem: .asciz "Starting in protected mode (base mem=\0)\n" m_esp: .asciz "Arguments passed (esp=\0):\n" m_args: .asciz"\n" m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n" m_rel_args: .asciz "Relocated arguments (size=18) to \0\n" m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n" m_base: .asciz "Client base address is \0\n" m_elf: .asciz "Client format is ELF\n" m_segs: .asciz "text segment: offset=" .asciz " vaddr=" .asciz " filesz=" .asciz " memsz=\0\n" .asciz "data segment: offset=" .asciz " vaddr=" .asciz " filesz=" .asciz " memsz=\0\n" m_done: .asciz "Loading complete\n" #endif /* * Uninitialized data area. */ buf: # Scratch buffer Index: head/sys/boot/pc98/btx/lib/btxcsu.s =================================================================== --- head/sys/boot/pc98/btx/lib/btxcsu.s (revision 235263) +++ head/sys/boot/pc98/btx/lib/btxcsu.s (nonexistent) @@ -1,51 +0,0 @@ -# -# Copyright (c) 1998 Robert Nordier -# All rights reserved. -# -# Redistribution and use in source and binary forms are freely -# permitted provided that the above copyright notice and this -# paragraph and the following disclaimer are duplicated in all -# such forms. -# -# This software is provided "AS IS" and without any express or -# implied warranties, including, without limitation, the implied -# warranties of merchantability and fitness for a particular -# purpose. -# - -# $FreeBSD$ - -# -# BTX C startup code (ELF). -# - -# -# Globals. -# - .global _start -# -# Constants. -# - .set ARGADJ,0xfa0 # Argument adjustment -# -# Client entry point. -# -_start: cld - pushl %eax - movl $_edata,%edi - movl $_end,%ecx - subl %edi, %ecx - xorb %al, %al - rep - stosb - popl __base - movl %esp,%eax # Set - addl $ARGADJ,%eax # argument - movl %eax,__args # pointer - call main # Invoke client main() - call exit # Invoke client exit() -# -# Data. -# - .comm __base,4 # Client base address - .comm __args,4 # Client arguments Property changes on: head/sys/boot/pc98/btx/lib/btxcsu.s ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/sys/boot/pc98/btx/lib/Makefile =================================================================== --- head/sys/boot/pc98/btx/lib/Makefile (revision 235263) +++ head/sys/boot/pc98/btx/lib/Makefile (revision 235264) @@ -1,9 +1,10 @@ # $FreeBSD$ PROG= crt0.o INTERNALPROG= NO_MAN= -SRCS= btxcsu.s btxsys.s btxv86.s +SRCS= btxcsu.S btxsys.s btxv86.s +CFLAGS+=-I${.CURDIR}/../../../i386/common LDFLAGS=-Wl,-r .include Index: head/sys/boot/pc98/btx/lib/btxcsu.S =================================================================== --- head/sys/boot/pc98/btx/lib/btxcsu.S (nonexistent) +++ head/sys/boot/pc98/btx/lib/btxcsu.S (revision 235264) @@ -0,0 +1,49 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD$ + +# +# BTX C startup code (ELF). +# + +#include + +# +# Globals. +# + .global _start +# +# Client entry point. +# +_start: cld + pushl %eax + movl $_edata,%edi + movl $_end,%ecx + subl %edi, %ecx + xorb %al, %al + rep + stosb + popl __base + movl %esp,%eax # Set + addl $ARGADJ,%eax # argument + movl %eax,__args # pointer + call main # Invoke client main() + call exit # Invoke client exit() +# +# Data. +# + .comm __base,4 # Client base address + .comm __args,4 # Client arguments Property changes on: head/sys/boot/pc98/btx/lib/btxcsu.S ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/sys/boot/pc98/cdboot/cdboot.s =================================================================== --- head/sys/boot/pc98/cdboot/cdboot.s (revision 235263) +++ head/sys/boot/pc98/cdboot/cdboot.s (nonexistent) @@ -1,811 +0,0 @@ -# -# Copyright (c) 2006 TAKAHASHI Yoshihiro -# Copyright (c) 2001 John Baldwin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the author nor the names of any co-contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# - -# $FreeBSD$ - -# -# Basically, we first create a set of boot arguments to pass to the loaded -# binary. Then we attempt to load /boot/loader from the CD we were booted -# off of. -# - -# -# Memory locations. -# - .set STACK_OFF,0x6000 # Stack offset - .set LOAD_SEG,0x0700 # Load segment - .set LOAD_SIZE,2048 # Load size - .set DAUA,0x0584 # DA/UA - - .set MEM_PAGE_SIZE,0x1000 # memory page size, 4k - .set MEM_ARG,0x900 # Arguments at start - .set MEM_ARG_BTX,0xa100 # Where we move them to so the - # BTX client can see them - .set MEM_ARG_SIZE,0x18 # Size of the arguments - .set MEM_BTX_ADDRESS,0x9000 # where BTX lives - .set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute - .set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader - .set MEM_BTX_CLIENT,0xa000 # where BTX clients live -# -# PC98 machine type from sys/pc98/pc98/pc98_machdep.h -# - .set MEM_SYS, 0xa100 # System common area segment - .set PC98_MACHINE_TYPE, 0x0620 # PC98 machine type - .set EPSON_ID, 0x0624 # EPSON machine id - - .set M_NEC_PC98, 0x0001 - .set M_EPSON_PC98, 0x0002 - .set M_NOT_H98, 0x0010 - .set M_H98, 0x0020 - .set M_NOTE, 0x0040 - .set M_NORMAL, 0x1000 - .set M_8M, 0x8000 -# -# Signature Constants -# - .set SIG1_OFF,0x1fe # Signature offset - .set SIG2_OFF,0x7fe # Signature offset -# -# a.out header fields -# - .set AOUT_TEXT,0x04 # text segment size - .set AOUT_DATA,0x08 # data segment size - .set AOUT_BSS,0x0c # zero'd BSS size - .set AOUT_SYMBOLS,0x10 # symbol table - .set AOUT_ENTRY,0x14 # entry point - .set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header -# -# Flags for kargs->bootflags -# - .set KARGS_FLAGS_CD,0x1 # flag to indicate booting from - # CD loader -# -# Segment selectors. -# - .set SEL_SDATA,0x8 # Supervisor data - .set SEL_RDATA,0x10 # Real mode data - .set SEL_SCODE,0x18 # PM-32 code - .set SEL_SCODE16,0x20 # PM-16 code -# -# BTX constants -# - .set INT_SYS,0x30 # BTX syscall interrupt -# -# Constants for reading from the CD. -# - .set ERROR_TIMEOUT,0x90 # BIOS timeout on read - .set NUM_RETRIES,3 # Num times to retry - .set SECTOR_SIZE,0x800 # size of a sector - .set SECTOR_SHIFT,11 # number of place to shift - .set BUFFER_LEN,0x100 # number of sectors in buffer - .set MAX_READ,0xf800 # max we can read at a time - .set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT - .set MEM_READ_BUFFER,0x9000 # buffer to read from CD - .set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor - .set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer - .set VOLDESC_LBA,0x10 # LBA of vol descriptor - .set VD_PRIMARY,1 # Primary VD - .set VD_END,255 # VD Terminator - .set VD_ROOTDIR,156 # Offset of Root Dir Record - .set DIR_LEN,0 # Offset of Dir Record length - .set DIR_EA_LEN,1 # Offset of EA length - .set DIR_EXTENT,2 # Offset of 64-bit LBA - .set DIR_SIZE,10 # Offset of 64-bit length - .set DIR_NAMELEN,32 # Offset of 8-bit name len - .set DIR_NAME,33 # Offset of dir name - -# -# Program start. -# - .code16 - .globl start - -start: jmp main - - .org 4 - .ascii "IPL1 " - -main: cld - - /* Setup the stack */ - xor %ax,%ax - mov %ax,%ss - mov $STACK_OFF,%sp - - push %ecx - - /* Setup graphic screen */ - mov $0x42,%ah # 640x400 - mov $0xc0,%ch - int $0x18 - mov $0x40,%ah # graph on - int $0x18 - - /* Setup text screen */ - mov $0x0a00,%ax # 80x25 - int $0x18 - mov $0x0c,%ah # text on - int $0x18 - mov $0x13,%ah # cursor home - xor %dx,%dx - int $0x18 - mov $0x11,%ah # cursor on - int $0x18 - - /* Setup keyboard */ - mov $0x03,%ah - int $0x18 - - /* Transfer PC-9801 system common area */ - xor %ax,%ax - mov %ax,%si - mov %ax,%ds - mov %ax,%di - mov $MEM_SYS,%ax - mov %ax,%es - mov $0x0600,%cx - rep - movsb - - /* Transfer EPSON machine type */ - mov $0xfd00,%ax - mov %ax,%ds - mov (0x804),%eax - and $0x00ffffff,%eax - mov %eax,%es:(EPSON_ID) - - /* Set machine type to PC98_SYSTEM_PARAMETER */ - call machine_check - - /* Load cdboot */ - xor %ax,%ax - mov %ax,%ds - mov $0x06,%ah /* Read data */ - mov (DAUA),%al /* Read drive */ - pop %ecx /* cylinder */ - xor %dx,%dx /* head / sector */ - mov $LOAD_SEG,%bx /* Load address */ - mov %bx,%es - xor %bp,%bp - mov $LOAD_SIZE,%bx /* Load size */ - int $0x1b - mov $msg_readerr,%si - jc error - - /* Jump to cdboot */ - ljmp $LOAD_SEG,$cdboot - -# -# Set machine type to PC98_SYSTEM_PARAMETER. -# -machine_check: xor %edx,%edx - mov %dx,%ds - mov $MEM_SYS,%ax - mov %ax,%es - - /* Wait V-SYNC */ -vsync.1: inb $0x60,%al - test $0x20,%al - jnz vsync.1 -vsync.2: inb $0x60,%al - test $0x20,%al - jz vsync.2 - - /* ANK 'A' font */ - xor %al,%al - outb %al,$0xa1 - mov $0x41,%al - outb %al,$0xa3 - - /* Get 'A' font from CG window */ - push %ds - mov $0xa400,%ax - mov %ax,%ds - xor %eax,%eax - xor %bx,%bx - mov $4,%cx -font.1: add (%bx),%eax - add $4,%bx - loop font.1 - pop %ds - cmp $0x6efc58fc,%eax - jnz m_epson - -m_pc98: or $M_NEC_PC98,%edx - mov $0x0458,%bx - mov (%bx),%al - test $0x80,%al - jz m_not_h98 - or $M_H98,%edx - jmp 1f -m_epson: or $M_EPSON_PC98,%edx -m_not_h98: or $M_NOT_H98,%edx - -1: inb $0x42,%al - test $0x20,%al - jz 1f - or $M_8M,%edx - -1: mov $0x0400,%bx - mov (%bx),%al - test $0x80,%al - jz 1f - or $M_NOTE,%edx - -1: mov $PC98_MACHINE_TYPE,%bx - mov %edx,%es:(%bx) - ret - -# -# Print out the error message at [SI], wait for a keypress, and then -# reboot the machine. -# -error: call putstr - mov $msg_keypress,%si - call putstr - xor %ax,%ax # Get keypress - int $0x18 - xor %ax,%ax # CPU reset - outb %al,$0xf0 -halt: hlt - jmp halt # Spin - -# -# Display a null-terminated string at [SI]. -# -# Trashes: AX, BX, CX, DX, SI, DI -# -putstr: push %ds - push %es - mov %cs,%ax - mov %ax,%ds - mov $0xa000,%ax - mov %ax,%es - mov cursor,%di - mov $0x00e1,%bx # Attribute - mov $160,%cx -putstr.0: lodsb - testb %al,%al - jz putstr.done - cmp $0x0d,%al - jz putstr.cr - cmp $0x0a,%al - jz putstr.lf - mov %bl,%es:0x2000(%di) - stosb - inc %di - jmp putstr.move -putstr.cr: xor %dx,%dx - mov %di,%ax - div %cx - sub %dx,%di - jmp putstr.move -putstr.lf: add %cx,%di -putstr.move: mov %di,%dx - mov $0x13,%ah # Move cursor - int $0x18 - jmp putstr.0 -putstr.done: mov %di,cursor - pop %es - pop %ds - ret - -# -# Display a single char at [AL], but don't move a cursor. -# -putc: push %es - push %di - push %bx - mov $0xa000,%bx - mov %bx,%es - mov cursor,%di - mov $0xe1,%bl # Attribute - mov %bl,%es:0x2000(%di) - stosb - pop %bx - pop %di - pop %es - ret - -msg_readerr: .asciz "Read Error\r\n" -msg_keypress: .asciz "\r\nPress any key to reboot\r\n" - -/* Boot signature */ - - .org SIG1_OFF,0x90 - - .word 0xaa55 # Magic number - -# -# cdboot -# -cdboot: mov %cs,%ax - mov %ax,%ds - xor %ax,%ax - mov %ax,%es - mov %es:(DAUA),%al # Save BIOS boot device - mov %al,drive - mov %cx,cylinder # Save BIOS boot cylinder - - mov $msg_welcome,%si # %ds:(%si) -> welcome message - call putstr # display the welcome message -# -# Setup the arguments that the loader is expecting from boot[12] -# - mov $msg_bootinfo,%si # %ds:(%si) -> boot args message - call putstr # display the message - mov $MEM_ARG,%bx # %ds:(%bx) -> boot args - mov %bx,%di # %es:(%di) -> boot args - xor %eax,%eax # zero %eax - mov $(MEM_ARG_SIZE/4),%cx # Size of arguments in 32-bit - # dwords - rep # Clear the arguments - stosl # to zero - mov drive,%dl # Store BIOS boot device - mov %dl,%es:0x4(%bx) # in kargs->bootdev - or $KARGS_FLAGS_CD,%es:0x8(%bx) # kargs->bootflags |= - # KARGS_FLAGS_CD -# -# Load Volume Descriptor -# - mov $VOLDESC_LBA,%eax # Set LBA of first VD -load_vd: push %eax # Save %eax - mov $1,%dh # One sector - mov $MEM_VOLDESC,%ebx # Destination - call read # Read it in - cmpb $VD_PRIMARY,%es:(%bx) # Primary VD? - je have_vd # Yes - pop %eax # Prepare to - inc %eax # try next - cmpb $VD_END,%es:(%bx) # Last VD? - jne load_vd # No, read next - mov $msg_novd,%si # No VD - jmp error # Halt -have_vd: # Have Primary VD -# -# Try to look up the loader binary using the paths in the loader_paths -# array. -# - mov $loader_paths,%si # Point to start of array -lookup_path: push %si # Save file name pointer - call lookup # Try to find file - pop %di # Restore file name pointer - jnc lookup_found # Found this file - push %es - mov %cs,%ax - mov %ax,%es - xor %al,%al # Look for next - mov $0xffff,%cx # path name by - repnz # scanning for - scasb # nul char - pop %es - mov %di,%si # Point %si at next path - mov (%si),%al # Get first char of next path - or %al,%al # Is it double nul? - jnz lookup_path # No, try it. - mov $msg_failed,%si # Failed message - jmp error # Halt -lookup_found: # Found a loader file -# -# Load the binary into the buffer. Due to real mode addressing limitations -# we have to read it in 64k chunks. -# - mov %es:DIR_SIZE(%bx),%eax # Read file length - add $SECTOR_SIZE-1,%eax # Convert length to sectors - shr $SECTOR_SHIFT,%eax - cmp $BUFFER_LEN,%eax - jbe load_sizeok - mov $msg_load2big,%si # Error message - jmp error -load_sizeok: movzbw %al,%cx # Num sectors to read - mov %es:DIR_EXTENT(%bx),%eax # Load extent - xor %edx,%edx - mov %es:DIR_EA_LEN(%bx),%dl - add %edx,%eax # Skip extended - mov $MEM_READ_BUFFER,%ebx # Read into the buffer -load_loop: mov %cl,%dh - cmp $MAX_READ_SEC,%cl # Truncate to max read size - jbe load_notrunc - mov $MAX_READ_SEC,%dh -load_notrunc: sub %dh,%cl # Update count - push %eax # Save - call read # Read it in - pop %eax # Restore - add $MAX_READ_SEC,%eax # Update LBA - add $MAX_READ,%ebx # Update dest addr - jcxz load_done # Done? - jmp load_loop # Keep going -load_done: -# -# Turn on the A20 address line -# - xor %ax,%ax # Turn A20 on - outb %al,$0xf2 - mov $0x02,%al - outb %al,$0xf6 -# -# Relocate the loader and BTX using a very lazy protected mode -# - mov $msg_relocate,%si # Display the - call putstr # relocation message - mov %es:(MEM_READ_BUFFER+AOUT_ENTRY),%edi # %edi is the destination - mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi # %esi is - # the start of the text - # segment - mov %es:(MEM_READ_BUFFER+AOUT_TEXT),%ecx # %ecx = length of the text - # segment - push %edi # Save entry point for later - lgdt gdtdesc # setup our own gdt - cli # turn off interrupts - mov %cr0,%eax # Turn on - or $0x1,%al # protected - mov %eax,%cr0 # mode - ljmp $SEL_SCODE,$pm_start # long jump to clear the - # instruction pre-fetch queue - .code32 -pm_start: mov $SEL_SDATA,%ax # Initialize - mov %ax,%ds # %ds and - mov %ax,%es # %es to a flat selector - rep # Relocate the - movsb # text segment - add $(MEM_PAGE_SIZE - 1),%edi # pad %edi out to a new page - and $~(MEM_PAGE_SIZE - 1),%edi # for the data segment - mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment - rep # Relocate the - movsb # data segment - mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss - xor %eax,%eax # zero %eax - add $3,%cl # round %ecx up to - shr $2,%ecx # a multiple of 4 - rep # zero the - stosl # bss - mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader - add $MEM_BTX_OFFSET,%esi # %esi -> BTX in the loader - mov $MEM_BTX_ADDRESS,%edi # %edi -> where BTX needs to go - movzwl 0xa(%esi),%ecx # %ecx -> length of BTX - rep # Relocate - movsb # BTX - ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM - .code16 -pm_16: mov $SEL_RDATA,%ax # Initialize - mov %ax,%ds # %ds and - mov %ax,%es # %es to a real mode selector - mov %cr0,%eax # Turn off - and $~0x1,%al # protected - mov %eax,%cr0 # mode - ljmp $LOAD_SEG,$pm_end # Long jump to clear the - # instruction pre-fetch queue -pm_end: sti # Turn interrupts back on now -# -# Copy the BTX client to MEM_BTX_CLIENT -# - mov %cs,%ax - mov %ax,%ds - xor %ax,%ax - mov %ax,%es - mov $MEM_BTX_CLIENT,%di # Prepare to relocate - mov $btx_client,%si # the simple btx client - mov $(btx_client_end-btx_client),%cx # length of btx client - rep # Relocate the - movsb # simple BTX client -# -# Copy the boot[12] args to where the BTX client can see them -# - xor %ax,%ax - mov %ax,%ds - mov $MEM_ARG,%si # where the args are at now - mov $MEM_ARG_BTX,%di # where the args are moving to - mov $(MEM_ARG_SIZE/4),%cx # size of the arguments in longs - rep # Relocate - movsl # the words -# -# Save the entry point so the client can get to it later on -# - pop %eax # Restore saved entry point - stosl # and add it to the end of - # the arguments -# -# Now we just start up BTX and let it do the rest -# - mov $msg_jump,%si # Display the - call putstr # jump message - ljmp $0,$MEM_BTX_ENTRY # Jump to the BTX entry point - -# -# Lookup the file in the path at [SI] from the root directory. -# -# Trashes: All but BX -# Returns: CF = 0 (success), BX = pointer to record -# CF = 1 (not found) -# -lookup: mov $VD_ROOTDIR+MEM_VOLDESC,%bx # Root directory record - push %bx - push %si - mov $msg_lookup,%si # Display lookup message - call putstr - pop %si - push %si - call putstr - mov $msg_lookup2,%si - call putstr - pop %si - pop %bx -lookup_dir: lodsb # Get first char of path - cmp $0,%al # Are we done? - je lookup_done # Yes - cmp $'/',%al # Skip path separator. - je lookup_dir - dec %si # Undo lodsb side effect - call find_file # Lookup first path item - jnc lookup_dir # Try next component - mov $msg_lookupfail,%si # Not found message - push %bx - call putstr - pop %bx - stc # Set carry - ret -lookup_done: mov $msg_lookupok,%si # Success message - push %bx - call putstr - pop %bx - clc # Clear carry - ret - -# -# Lookup file at [SI] in directory whose record is at [BX]. -# -# Trashes: All but returns -# Returns: CF = 0 (success), BX = pointer to record, SI = next path item -# CF = 1 (not found), SI = preserved -# -find_file: mov %es:DIR_EXTENT(%bx),%eax # Load extent - xor %edx,%edx - mov %es:DIR_EA_LEN(%bx),%dl - add %edx,%eax # Skip extended attributes - mov %eax,rec_lba # Save LBA - mov %es:DIR_SIZE(%bx),%eax # Save size - mov %eax,rec_size - xor %cl,%cl # Zero length - push %si # Save -ff.namelen: inc %cl # Update length - lodsb # Read char - cmp $0,%al # Nul? - je ff.namedone # Yes - cmp $'/',%al # Path separator? - jnz ff.namelen # No, keep going -ff.namedone: dec %cl # Adjust length and save - mov %cl,name_len - pop %si # Restore -ff.load: mov rec_lba,%eax # Load LBA - mov $MEM_DIR,%ebx # Address buffer - mov $1,%dh # One sector - call read # Read directory block - incl rec_lba # Update LBA to next block -ff.scan: mov %ebx,%edx # Check for EOF - sub $MEM_DIR,%edx - cmp %edx,rec_size - ja ff.scan.1 - stc # EOF reached - ret -ff.scan.1: cmpb $0,%es:DIR_LEN(%bx) # Last record in block? - je ff.nextblock - push %si # Save - movzbw %es:DIR_NAMELEN(%bx),%si # Find end of string -ff.checkver: cmpb $'0',%es:DIR_NAME-1(%bx,%si) # Less than '0'? - jb ff.checkver.1 - cmpb $'9',%es:DIR_NAME-1(%bx,%si) # Greater than '9'? - ja ff.checkver.1 - dec %si # Next char - jnz ff.checkver - jmp ff.checklen # All numbers in name, so - # no version -ff.checkver.1: movzbw %es:DIR_NAMELEN(%bx),%cx - cmp %cx,%si # Did we find any digits? - je ff.checkdot # No - cmpb $';',%es:DIR_NAME-1(%bx,%si) # Check for semicolon - jne ff.checkver.2 - dec %si # Skip semicolon - mov %si,%cx - mov %cl,%es:DIR_NAMELEN(%bx) # Adjust length - jmp ff.checkdot -ff.checkver.2: mov %cx,%si # Restore %si to end of string -ff.checkdot: cmpb $'.',%es:DIR_NAME-1(%bx,%si) # Trailing dot? - jne ff.checklen # No - decb %es:DIR_NAMELEN(%bx) # Adjust length -ff.checklen: pop %si # Restore - movzbw name_len,%cx # Load length of name - cmp %cl,%es:DIR_NAMELEN(%bx) # Does length match? - je ff.checkname # Yes, check name -ff.nextrec: add %es:DIR_LEN(%bx),%bl # Next record - adc $0,%bh - jmp ff.scan -ff.nextblock: subl $SECTOR_SIZE,rec_size # Adjust size - jnc ff.load # If subtract ok, keep going - ret # End of file, so not found -ff.checkname: lea DIR_NAME(%bx),%di # Address name in record - push %si # Save - repe cmpsb # Compare name - je ff.match # We have a winner! - pop %si # Restore - jmp ff.nextrec # Keep looking. -ff.match: add $2,%sp # Discard saved %si - clc # Clear carry - ret - -# -# Load DH sectors starting at LBA EAX into [EBX]. -# -# Trashes: EAX -# -read: push %es # Save - push %bp - push %dx - push %cx - push %ebx - mov %bx,%bp # Set destination address - and $0x000f,%bp - shr $4,%ebx - mov %bx,%es - xor %bx,%bx # Set read bytes - mov %dh,%bl - shl $SECTOR_SHIFT,%bx # 2048 bytes/sec - mov %ax,%cx # Set LBA - shr $16,%eax - mov %ax,%dx -read.retry: mov $0x06,%ah # BIOS device read - mov drive,%al - and $0x7f,%al - call twiddle # Entertain the user - int $0x1b # Call BIOS - jc read.fail # Worked? - pop %ebx # Restore - pop %cx - pop %dx - pop %bp - pop %es - ret # Return -read.fail: cmp $ERROR_TIMEOUT,%ah # Timeout? - je read.retry # Yes, Retry. -read.error: mov %ah,%al # Save error - mov $hex_error,%di # Format it - call hex8 # as hex - mov $msg_badread,%si # Display Read error message - jmp error - -# -# Output the "twiddle" -# -twiddle: push %ax # Save - push %bx # Save - mov twiddle_index,%al # Load index - mov $twiddle_chars,%bx # Address table - inc %al # Next - and $3,%al # char - mov %al,twiddle_index # Save index for next call - xlat # Get char - call putc # Output it - pop %bx # Restore - pop %ax # Restore - ret - -# -# Convert AL to hex, saving the result to [EDI]. -# -hex8: pushl %eax # Save - shrb $0x4,%al # Do upper - call hex8.1 # 4 - popl %eax # Restore -hex8.1: andb $0xf,%al # Get lower 4 - cmpb $0xa,%al # Convert - sbbb $0x69,%al # to hex - das # digit - orb $0x20,%al # To lower case - mov %al,(%di) # Save char - inc %di - ret # (Recursive) - -# -# BTX client to start btxldr -# - .code32 -btx_client: mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi - # %ds:(%esi) -> end - # of boot[12] args - mov $(MEM_ARG_SIZE/4),%ecx # Number of words to push - std # Go backwards -push_arg: lodsl # Read argument - push %eax # Push it onto the stack - loop push_arg # Push all of the arguments - cld # In case anyone depends on this - pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of - # the loader - push %eax # Emulate a near call - mov $0x1,%eax # 'exec' system call - int $INT_SYS # BTX system call -btx_client_end: - .code16 - - .p2align 4 -# -# Global descriptor table. -# -gdt: .word 0x0,0x0,0x0,0x0 # Null entry - .word 0xffff,0x0000,0x9200,0x00cf # SEL_SDATA - .word 0xffff,0x0000,0x9200,0x0000 # SEL_RDATA - .word 0xffff,LOAD_SEG<<4,0x9a00,0x00cf # SEL_SCODE (32-bit) - .word 0xffff,LOAD_SEG<<4,0x9a00,0x008f # SEL_SCODE16 (16-bit) -gdt.1: -# -# Pseudo-descriptors. -# -gdtdesc: .word gdt.1-gdt-1 # Limit - .long LOAD_SEG<<4 + gdt # Base - -# -# BOOT device -# -drive: .byte 0 -cylinder: .word 0 - -# -# State for searching dir -# -rec_lba: .long 0x0 # LBA (adjusted for EA) -rec_size: .long 0x0 # File size -name_len: .byte 0x0 # Length of current name - -cursor: .word 0 -twiddle_index: .byte 0x0 - -msg_welcome: .asciz "CD Loader 1.2\r\n\n" -msg_bootinfo: .asciz "Building the boot loader arguments\r\n" -msg_relocate: .asciz "Relocating the loader and the BTX\r\n" -msg_jump: .asciz "Starting the BTX loader\r\n" -msg_badread: .ascii "Read Error: 0x" -hex_error: .asciz "00\r\n" -msg_novd: .asciz "Could not find Primary Volume Descriptor\r\n" -msg_lookup: .asciz "Looking up " -msg_lookup2: .asciz "... " -msg_lookupok: .asciz "Found\r\n" -msg_lookupfail: .asciz "File not found\r\n" -msg_load2big: .asciz "File too big\r\n" -msg_failed: .asciz "Boot failed\r\n" -twiddle_chars: .ascii "|/-\\" -loader_paths: .asciz "/BOOT.PC98/LOADER" - .asciz "/boot.pc98/loader" - .asciz "/BOOT/LOADER" - .asciz "/boot/loader" - .byte 0 - -/* Boot signature */ - - .org SIG2_OFF,0x90 - - .word 0xaa55 # Magic number Property changes on: head/sys/boot/pc98/cdboot/cdboot.s ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/sys/boot/pc98/cdboot/Makefile =================================================================== --- head/sys/boot/pc98/cdboot/Makefile (revision 235263) +++ head/sys/boot/pc98/cdboot/Makefile (revision 235264) @@ -1,13 +1,15 @@ # $FreeBSD$ PROG= cdboot STRIP= BINMODE=${NOBINMODE} NO_MAN= -SRCS= ${PROG}.s +SRCS= ${PROG}.S + +CFLAGS+=-I${.CURDIR}/../../i386/common ORG= 0x0000 LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary .include Index: head/sys/boot/pc98/cdboot/cdboot.S =================================================================== --- head/sys/boot/pc98/cdboot/cdboot.S (nonexistent) +++ head/sys/boot/pc98/cdboot/cdboot.S (revision 235264) @@ -0,0 +1,808 @@ +# +# Copyright (c) 2006 TAKAHASHI Yoshihiro +# Copyright (c) 2001 John Baldwin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the author nor the names of any co-contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# $FreeBSD$ + +#include + +# +# Basically, we first create a set of boot arguments to pass to the loaded +# binary. Then we attempt to load /boot/loader from the CD we were booted +# off of. +# + +# +# Memory locations. +# + .set STACK_OFF,0x6000 # Stack offset + .set LOAD_SEG,0x0700 # Load segment + .set LOAD_SIZE,2048 # Load size + .set DAUA,0x0584 # DA/UA + + .set MEM_PAGE_SIZE,0x1000 # memory page size, 4k + .set MEM_ARG,0x900 # Arguments at start + .set MEM_ARG_BTX,0xa100 # Where we move them to so the + # BTX client can see them + .set MEM_ARG_SIZE,0x18 # Size of the arguments + .set MEM_BTX_ADDRESS,0x9000 # where BTX lives + .set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute + .set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader + .set MEM_BTX_CLIENT,0xa000 # where BTX clients live +# +# PC98 machine type from sys/pc98/pc98/pc98_machdep.h +# + .set MEM_SYS, 0xa100 # System common area segment + .set PC98_MACHINE_TYPE, 0x0620 # PC98 machine type + .set EPSON_ID, 0x0624 # EPSON machine id + + .set M_NEC_PC98, 0x0001 + .set M_EPSON_PC98, 0x0002 + .set M_NOT_H98, 0x0010 + .set M_H98, 0x0020 + .set M_NOTE, 0x0040 + .set M_NORMAL, 0x1000 + .set M_8M, 0x8000 +# +# Signature Constants +# + .set SIG1_OFF,0x1fe # Signature offset + .set SIG2_OFF,0x7fe # Signature offset +# +# a.out header fields +# + .set AOUT_TEXT,0x04 # text segment size + .set AOUT_DATA,0x08 # data segment size + .set AOUT_BSS,0x0c # zero'd BSS size + .set AOUT_SYMBOLS,0x10 # symbol table + .set AOUT_ENTRY,0x14 # entry point + .set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header +# +# Segment selectors. +# + .set SEL_SDATA,0x8 # Supervisor data + .set SEL_RDATA,0x10 # Real mode data + .set SEL_SCODE,0x18 # PM-32 code + .set SEL_SCODE16,0x20 # PM-16 code +# +# BTX constants +# + .set INT_SYS,0x30 # BTX syscall interrupt +# +# Constants for reading from the CD. +# + .set ERROR_TIMEOUT,0x90 # BIOS timeout on read + .set NUM_RETRIES,3 # Num times to retry + .set SECTOR_SIZE,0x800 # size of a sector + .set SECTOR_SHIFT,11 # number of place to shift + .set BUFFER_LEN,0x100 # number of sectors in buffer + .set MAX_READ,0xf800 # max we can read at a time + .set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT + .set MEM_READ_BUFFER,0x9000 # buffer to read from CD + .set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor + .set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer + .set VOLDESC_LBA,0x10 # LBA of vol descriptor + .set VD_PRIMARY,1 # Primary VD + .set VD_END,255 # VD Terminator + .set VD_ROOTDIR,156 # Offset of Root Dir Record + .set DIR_LEN,0 # Offset of Dir Record length + .set DIR_EA_LEN,1 # Offset of EA length + .set DIR_EXTENT,2 # Offset of 64-bit LBA + .set DIR_SIZE,10 # Offset of 64-bit length + .set DIR_NAMELEN,32 # Offset of 8-bit name len + .set DIR_NAME,33 # Offset of dir name + +# +# Program start. +# + .code16 + .globl start + +start: jmp main + + .org 4 + .ascii "IPL1 " + +main: cld + + /* Setup the stack */ + xor %ax,%ax + mov %ax,%ss + mov $STACK_OFF,%sp + + push %ecx + + /* Setup graphic screen */ + mov $0x42,%ah # 640x400 + mov $0xc0,%ch + int $0x18 + mov $0x40,%ah # graph on + int $0x18 + + /* Setup text screen */ + mov $0x0a00,%ax # 80x25 + int $0x18 + mov $0x0c,%ah # text on + int $0x18 + mov $0x13,%ah # cursor home + xor %dx,%dx + int $0x18 + mov $0x11,%ah # cursor on + int $0x18 + + /* Setup keyboard */ + mov $0x03,%ah + int $0x18 + + /* Transfer PC-9801 system common area */ + xor %ax,%ax + mov %ax,%si + mov %ax,%ds + mov %ax,%di + mov $MEM_SYS,%ax + mov %ax,%es + mov $0x0600,%cx + rep + movsb + + /* Transfer EPSON machine type */ + mov $0xfd00,%ax + mov %ax,%ds + mov (0x804),%eax + and $0x00ffffff,%eax + mov %eax,%es:(EPSON_ID) + + /* Set machine type to PC98_SYSTEM_PARAMETER */ + call machine_check + + /* Load cdboot */ + xor %ax,%ax + mov %ax,%ds + mov $0x06,%ah /* Read data */ + mov (DAUA),%al /* Read drive */ + pop %ecx /* cylinder */ + xor %dx,%dx /* head / sector */ + mov $LOAD_SEG,%bx /* Load address */ + mov %bx,%es + xor %bp,%bp + mov $LOAD_SIZE,%bx /* Load size */ + int $0x1b + mov $msg_readerr,%si + jc error + + /* Jump to cdboot */ + ljmp $LOAD_SEG,$cdboot + +# +# Set machine type to PC98_SYSTEM_PARAMETER. +# +machine_check: xor %edx,%edx + mov %dx,%ds + mov $MEM_SYS,%ax + mov %ax,%es + + /* Wait V-SYNC */ +vsync.1: inb $0x60,%al + test $0x20,%al + jnz vsync.1 +vsync.2: inb $0x60,%al + test $0x20,%al + jz vsync.2 + + /* ANK 'A' font */ + xor %al,%al + outb %al,$0xa1 + mov $0x41,%al + outb %al,$0xa3 + + /* Get 'A' font from CG window */ + push %ds + mov $0xa400,%ax + mov %ax,%ds + xor %eax,%eax + xor %bx,%bx + mov $4,%cx +font.1: add (%bx),%eax + add $4,%bx + loop font.1 + pop %ds + cmp $0x6efc58fc,%eax + jnz m_epson + +m_pc98: or $M_NEC_PC98,%edx + mov $0x0458,%bx + mov (%bx),%al + test $0x80,%al + jz m_not_h98 + or $M_H98,%edx + jmp 1f +m_epson: or $M_EPSON_PC98,%edx +m_not_h98: or $M_NOT_H98,%edx + +1: inb $0x42,%al + test $0x20,%al + jz 1f + or $M_8M,%edx + +1: mov $0x0400,%bx + mov (%bx),%al + test $0x80,%al + jz 1f + or $M_NOTE,%edx + +1: mov $PC98_MACHINE_TYPE,%bx + mov %edx,%es:(%bx) + ret + +# +# Print out the error message at [SI], wait for a keypress, and then +# reboot the machine. +# +error: call putstr + mov $msg_keypress,%si + call putstr + xor %ax,%ax # Get keypress + int $0x18 + xor %ax,%ax # CPU reset + outb %al,$0xf0 +halt: hlt + jmp halt # Spin + +# +# Display a null-terminated string at [SI]. +# +# Trashes: AX, BX, CX, DX, SI, DI +# +putstr: push %ds + push %es + mov %cs,%ax + mov %ax,%ds + mov $0xa000,%ax + mov %ax,%es + mov cursor,%di + mov $0x00e1,%bx # Attribute + mov $160,%cx +putstr.0: lodsb + testb %al,%al + jz putstr.done + cmp $0x0d,%al + jz putstr.cr + cmp $0x0a,%al + jz putstr.lf + mov %bl,%es:0x2000(%di) + stosb + inc %di + jmp putstr.move +putstr.cr: xor %dx,%dx + mov %di,%ax + div %cx + sub %dx,%di + jmp putstr.move +putstr.lf: add %cx,%di +putstr.move: mov %di,%dx + mov $0x13,%ah # Move cursor + int $0x18 + jmp putstr.0 +putstr.done: mov %di,cursor + pop %es + pop %ds + ret + +# +# Display a single char at [AL], but don't move a cursor. +# +putc: push %es + push %di + push %bx + mov $0xa000,%bx + mov %bx,%es + mov cursor,%di + mov $0xe1,%bl # Attribute + mov %bl,%es:0x2000(%di) + stosb + pop %bx + pop %di + pop %es + ret + +msg_readerr: .asciz "Read Error\r\n" +msg_keypress: .asciz "\r\nPress any key to reboot\r\n" + +/* Boot signature */ + + .org SIG1_OFF,0x90 + + .word 0xaa55 # Magic number + +# +# cdboot +# +cdboot: mov %cs,%ax + mov %ax,%ds + xor %ax,%ax + mov %ax,%es + mov %es:(DAUA),%al # Save BIOS boot device + mov %al,drive + mov %cx,cylinder # Save BIOS boot cylinder + + mov $msg_welcome,%si # %ds:(%si) -> welcome message + call putstr # display the welcome message +# +# Setup the arguments that the loader is expecting from boot[12] +# + mov $msg_bootinfo,%si # %ds:(%si) -> boot args message + call putstr # display the message + mov $MEM_ARG,%bx # %ds:(%bx) -> boot args + mov %bx,%di # %es:(%di) -> boot args + xor %eax,%eax # zero %eax + mov $(MEM_ARG_SIZE/4),%cx # Size of arguments in 32-bit + # dwords + rep # Clear the arguments + stosl # to zero + mov drive,%dl # Store BIOS boot device + mov %dl,%es:0x4(%bx) # in kargs->bootdev + or $KARGS_FLAGS_CD,%es:0x8(%bx) # kargs->bootflags |= + # KARGS_FLAGS_CD +# +# Load Volume Descriptor +# + mov $VOLDESC_LBA,%eax # Set LBA of first VD +load_vd: push %eax # Save %eax + mov $1,%dh # One sector + mov $MEM_VOLDESC,%ebx # Destination + call read # Read it in + cmpb $VD_PRIMARY,%es:(%bx) # Primary VD? + je have_vd # Yes + pop %eax # Prepare to + inc %eax # try next + cmpb $VD_END,%es:(%bx) # Last VD? + jne load_vd # No, read next + mov $msg_novd,%si # No VD + jmp error # Halt +have_vd: # Have Primary VD +# +# Try to look up the loader binary using the paths in the loader_paths +# array. +# + mov $loader_paths,%si # Point to start of array +lookup_path: push %si # Save file name pointer + call lookup # Try to find file + pop %di # Restore file name pointer + jnc lookup_found # Found this file + push %es + mov %cs,%ax + mov %ax,%es + xor %al,%al # Look for next + mov $0xffff,%cx # path name by + repnz # scanning for + scasb # nul char + pop %es + mov %di,%si # Point %si at next path + mov (%si),%al # Get first char of next path + or %al,%al # Is it double nul? + jnz lookup_path # No, try it. + mov $msg_failed,%si # Failed message + jmp error # Halt +lookup_found: # Found a loader file +# +# Load the binary into the buffer. Due to real mode addressing limitations +# we have to read it in 64k chunks. +# + mov %es:DIR_SIZE(%bx),%eax # Read file length + add $SECTOR_SIZE-1,%eax # Convert length to sectors + shr $SECTOR_SHIFT,%eax + cmp $BUFFER_LEN,%eax + jbe load_sizeok + mov $msg_load2big,%si # Error message + jmp error +load_sizeok: movzbw %al,%cx # Num sectors to read + mov %es:DIR_EXTENT(%bx),%eax # Load extent + xor %edx,%edx + mov %es:DIR_EA_LEN(%bx),%dl + add %edx,%eax # Skip extended + mov $MEM_READ_BUFFER,%ebx # Read into the buffer +load_loop: mov %cl,%dh + cmp $MAX_READ_SEC,%cl # Truncate to max read size + jbe load_notrunc + mov $MAX_READ_SEC,%dh +load_notrunc: sub %dh,%cl # Update count + push %eax # Save + call read # Read it in + pop %eax # Restore + add $MAX_READ_SEC,%eax # Update LBA + add $MAX_READ,%ebx # Update dest addr + jcxz load_done # Done? + jmp load_loop # Keep going +load_done: +# +# Turn on the A20 address line +# + xor %ax,%ax # Turn A20 on + outb %al,$0xf2 + mov $0x02,%al + outb %al,$0xf6 +# +# Relocate the loader and BTX using a very lazy protected mode +# + mov $msg_relocate,%si # Display the + call putstr # relocation message + mov %es:(MEM_READ_BUFFER+AOUT_ENTRY),%edi # %edi is the destination + mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi # %esi is + # the start of the text + # segment + mov %es:(MEM_READ_BUFFER+AOUT_TEXT),%ecx # %ecx = length of the text + # segment + push %edi # Save entry point for later + lgdt gdtdesc # setup our own gdt + cli # turn off interrupts + mov %cr0,%eax # Turn on + or $0x1,%al # protected + mov %eax,%cr0 # mode + ljmp $SEL_SCODE,$pm_start # long jump to clear the + # instruction pre-fetch queue + .code32 +pm_start: mov $SEL_SDATA,%ax # Initialize + mov %ax,%ds # %ds and + mov %ax,%es # %es to a flat selector + rep # Relocate the + movsb # text segment + add $(MEM_PAGE_SIZE - 1),%edi # pad %edi out to a new page + and $~(MEM_PAGE_SIZE - 1),%edi # for the data segment + mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment + rep # Relocate the + movsb # data segment + mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss + xor %eax,%eax # zero %eax + add $3,%cl # round %ecx up to + shr $2,%ecx # a multiple of 4 + rep # zero the + stosl # bss + mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader + add $MEM_BTX_OFFSET,%esi # %esi -> BTX in the loader + mov $MEM_BTX_ADDRESS,%edi # %edi -> where BTX needs to go + movzwl 0xa(%esi),%ecx # %ecx -> length of BTX + rep # Relocate + movsb # BTX + ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM + .code16 +pm_16: mov $SEL_RDATA,%ax # Initialize + mov %ax,%ds # %ds and + mov %ax,%es # %es to a real mode selector + mov %cr0,%eax # Turn off + and $~0x1,%al # protected + mov %eax,%cr0 # mode + ljmp $LOAD_SEG,$pm_end # Long jump to clear the + # instruction pre-fetch queue +pm_end: sti # Turn interrupts back on now +# +# Copy the BTX client to MEM_BTX_CLIENT +# + mov %cs,%ax + mov %ax,%ds + xor %ax,%ax + mov %ax,%es + mov $MEM_BTX_CLIENT,%di # Prepare to relocate + mov $btx_client,%si # the simple btx client + mov $(btx_client_end-btx_client),%cx # length of btx client + rep # Relocate the + movsb # simple BTX client +# +# Copy the boot[12] args to where the BTX client can see them +# + xor %ax,%ax + mov %ax,%ds + mov $MEM_ARG,%si # where the args are at now + mov $MEM_ARG_BTX,%di # where the args are moving to + mov $(MEM_ARG_SIZE/4),%cx # size of the arguments in longs + rep # Relocate + movsl # the words +# +# Save the entry point so the client can get to it later on +# + pop %eax # Restore saved entry point + stosl # and add it to the end of + # the arguments +# +# Now we just start up BTX and let it do the rest +# + mov $msg_jump,%si # Display the + call putstr # jump message + ljmp $0,$MEM_BTX_ENTRY # Jump to the BTX entry point + +# +# Lookup the file in the path at [SI] from the root directory. +# +# Trashes: All but BX +# Returns: CF = 0 (success), BX = pointer to record +# CF = 1 (not found) +# +lookup: mov $VD_ROOTDIR+MEM_VOLDESC,%bx # Root directory record + push %bx + push %si + mov $msg_lookup,%si # Display lookup message + call putstr + pop %si + push %si + call putstr + mov $msg_lookup2,%si + call putstr + pop %si + pop %bx +lookup_dir: lodsb # Get first char of path + cmp $0,%al # Are we done? + je lookup_done # Yes + cmp $'/',%al # Skip path separator. + je lookup_dir + dec %si # Undo lodsb side effect + call find_file # Lookup first path item + jnc lookup_dir # Try next component + mov $msg_lookupfail,%si # Not found message + push %bx + call putstr + pop %bx + stc # Set carry + ret +lookup_done: mov $msg_lookupok,%si # Success message + push %bx + call putstr + pop %bx + clc # Clear carry + ret + +# +# Lookup file at [SI] in directory whose record is at [BX]. +# +# Trashes: All but returns +# Returns: CF = 0 (success), BX = pointer to record, SI = next path item +# CF = 1 (not found), SI = preserved +# +find_file: mov %es:DIR_EXTENT(%bx),%eax # Load extent + xor %edx,%edx + mov %es:DIR_EA_LEN(%bx),%dl + add %edx,%eax # Skip extended attributes + mov %eax,rec_lba # Save LBA + mov %es:DIR_SIZE(%bx),%eax # Save size + mov %eax,rec_size + xor %cl,%cl # Zero length + push %si # Save +ff.namelen: inc %cl # Update length + lodsb # Read char + cmp $0,%al # Nul? + je ff.namedone # Yes + cmp $'/',%al # Path separator? + jnz ff.namelen # No, keep going +ff.namedone: dec %cl # Adjust length and save + mov %cl,name_len + pop %si # Restore +ff.load: mov rec_lba,%eax # Load LBA + mov $MEM_DIR,%ebx # Address buffer + mov $1,%dh # One sector + call read # Read directory block + incl rec_lba # Update LBA to next block +ff.scan: mov %ebx,%edx # Check for EOF + sub $MEM_DIR,%edx + cmp %edx,rec_size + ja ff.scan.1 + stc # EOF reached + ret +ff.scan.1: cmpb $0,%es:DIR_LEN(%bx) # Last record in block? + je ff.nextblock + push %si # Save + movzbw %es:DIR_NAMELEN(%bx),%si # Find end of string +ff.checkver: cmpb $'0',%es:DIR_NAME-1(%bx,%si) # Less than '0'? + jb ff.checkver.1 + cmpb $'9',%es:DIR_NAME-1(%bx,%si) # Greater than '9'? + ja ff.checkver.1 + dec %si # Next char + jnz ff.checkver + jmp ff.checklen # All numbers in name, so + # no version +ff.checkver.1: movzbw %es:DIR_NAMELEN(%bx),%cx + cmp %cx,%si # Did we find any digits? + je ff.checkdot # No + cmpb $';',%es:DIR_NAME-1(%bx,%si) # Check for semicolon + jne ff.checkver.2 + dec %si # Skip semicolon + mov %si,%cx + mov %cl,%es:DIR_NAMELEN(%bx) # Adjust length + jmp ff.checkdot +ff.checkver.2: mov %cx,%si # Restore %si to end of string +ff.checkdot: cmpb $'.',%es:DIR_NAME-1(%bx,%si) # Trailing dot? + jne ff.checklen # No + decb %es:DIR_NAMELEN(%bx) # Adjust length +ff.checklen: pop %si # Restore + movzbw name_len,%cx # Load length of name + cmp %cl,%es:DIR_NAMELEN(%bx) # Does length match? + je ff.checkname # Yes, check name +ff.nextrec: add %es:DIR_LEN(%bx),%bl # Next record + adc $0,%bh + jmp ff.scan +ff.nextblock: subl $SECTOR_SIZE,rec_size # Adjust size + jnc ff.load # If subtract ok, keep going + ret # End of file, so not found +ff.checkname: lea DIR_NAME(%bx),%di # Address name in record + push %si # Save + repe cmpsb # Compare name + je ff.match # We have a winner! + pop %si # Restore + jmp ff.nextrec # Keep looking. +ff.match: add $2,%sp # Discard saved %si + clc # Clear carry + ret + +# +# Load DH sectors starting at LBA EAX into [EBX]. +# +# Trashes: EAX +# +read: push %es # Save + push %bp + push %dx + push %cx + push %ebx + mov %bx,%bp # Set destination address + and $0x000f,%bp + shr $4,%ebx + mov %bx,%es + xor %bx,%bx # Set read bytes + mov %dh,%bl + shl $SECTOR_SHIFT,%bx # 2048 bytes/sec + mov %ax,%cx # Set LBA + shr $16,%eax + mov %ax,%dx +read.retry: mov $0x06,%ah # BIOS device read + mov drive,%al + and $0x7f,%al + call twiddle # Entertain the user + int $0x1b # Call BIOS + jc read.fail # Worked? + pop %ebx # Restore + pop %cx + pop %dx + pop %bp + pop %es + ret # Return +read.fail: cmp $ERROR_TIMEOUT,%ah # Timeout? + je read.retry # Yes, Retry. +read.error: mov %ah,%al # Save error + mov $hex_error,%di # Format it + call hex8 # as hex + mov $msg_badread,%si # Display Read error message + jmp error + +# +# Output the "twiddle" +# +twiddle: push %ax # Save + push %bx # Save + mov twiddle_index,%al # Load index + mov $twiddle_chars,%bx # Address table + inc %al # Next + and $3,%al # char + mov %al,twiddle_index # Save index for next call + xlat # Get char + call putc # Output it + pop %bx # Restore + pop %ax # Restore + ret + +# +# Convert AL to hex, saving the result to [EDI]. +# +hex8: pushl %eax # Save + shrb $0x4,%al # Do upper + call hex8.1 # 4 + popl %eax # Restore +hex8.1: andb $0xf,%al # Get lower 4 + cmpb $0xa,%al # Convert + sbbb $0x69,%al # to hex + das # digit + orb $0x20,%al # To lower case + mov %al,(%di) # Save char + inc %di + ret # (Recursive) + +# +# BTX client to start btxldr +# + .code32 +btx_client: mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi + # %ds:(%esi) -> end + # of boot[12] args + mov $(MEM_ARG_SIZE/4),%ecx # Number of words to push + std # Go backwards +push_arg: lodsl # Read argument + push %eax # Push it onto the stack + loop push_arg # Push all of the arguments + cld # In case anyone depends on this + pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of + # the loader + push %eax # Emulate a near call + mov $0x1,%eax # 'exec' system call + int $INT_SYS # BTX system call +btx_client_end: + .code16 + + .p2align 4 +# +# Global descriptor table. +# +gdt: .word 0x0,0x0,0x0,0x0 # Null entry + .word 0xffff,0x0000,0x9200,0x00cf # SEL_SDATA + .word 0xffff,0x0000,0x9200,0x0000 # SEL_RDATA + .word 0xffff,LOAD_SEG<<4,0x9a00,0x00cf # SEL_SCODE (32-bit) + .word 0xffff,LOAD_SEG<<4,0x9a00,0x008f # SEL_SCODE16 (16-bit) +gdt.1: +# +# Pseudo-descriptors. +# +gdtdesc: .word gdt.1-gdt-1 # Limit + .long LOAD_SEG<<4 + gdt # Base + +# +# BOOT device +# +drive: .byte 0 +cylinder: .word 0 + +# +# State for searching dir +# +rec_lba: .long 0x0 # LBA (adjusted for EA) +rec_size: .long 0x0 # File size +name_len: .byte 0x0 # Length of current name + +cursor: .word 0 +twiddle_index: .byte 0x0 + +msg_welcome: .asciz "CD Loader 1.2\r\n\n" +msg_bootinfo: .asciz "Building the boot loader arguments\r\n" +msg_relocate: .asciz "Relocating the loader and the BTX\r\n" +msg_jump: .asciz "Starting the BTX loader\r\n" +msg_badread: .ascii "Read Error: 0x" +hex_error: .asciz "00\r\n" +msg_novd: .asciz "Could not find Primary Volume Descriptor\r\n" +msg_lookup: .asciz "Looking up " +msg_lookup2: .asciz "... " +msg_lookupok: .asciz "Found\r\n" +msg_lookupfail: .asciz "File not found\r\n" +msg_load2big: .asciz "File too big\r\n" +msg_failed: .asciz "Boot failed\r\n" +twiddle_chars: .ascii "|/-\\" +loader_paths: .asciz "/BOOT.PC98/LOADER" + .asciz "/boot.pc98/loader" + .asciz "/BOOT/LOADER" + .asciz "/boot/loader" + .byte 0 + +/* Boot signature */ + + .org SIG2_OFF,0x90 + + .word 0xaa55 # Magic number Property changes on: head/sys/boot/pc98/cdboot/cdboot.S ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/sys/boot/pc98/loader/main.c =================================================================== --- head/sys/boot/pc98/loader/main.c (revision 235263) +++ head/sys/boot/pc98/loader/main.c (revision 235264) @@ -1,342 +1,338 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * MD bootstrap main() and assorted miscellaneous * commands. */ #include +#include #include #include #include #include #include "bootstrap.h" +#include "common/bootargs.h" #include "libi386/libi386.h" #include "libpc98/libpc98.h" #include "btxv86.h" -#define KARGS_FLAGS_CD 0x1 -#define KARGS_FLAGS_PXE 0x2 +CTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE); +CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO); +CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS); +CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE); /* Arguments passed in from the boot1/boot2 loader */ -static struct -{ - u_int32_t howto; - u_int32_t bootdev; - u_int32_t bootflags; - u_int32_t pxeinfo; - u_int32_t res2; - u_int32_t bootinfo; -} *kargs; +static struct bootargs *kargs; static u_int32_t initial_howto; static u_int32_t initial_bootdev; static struct bootinfo *initial_bootinfo; struct arch_switch archsw; /* MI/MD interface boundary */ static void extract_currdev(void); static int isa_inb(int port); static void isa_outb(int port, int value); void exit(int code); /* from vers.c */ extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; /* XXX debugging */ extern char end[]; static void *heap_top; static void *heap_bottom; static uint64_t pc98_loadaddr(u_int type, void *data, uint64_t addr) { struct stat st; if (type == LOAD_ELF) return (roundup(addr, PAGE_SIZE)); /* We cannot use 15M-16M area on pc98. */ if (type == LOAD_RAW && addr < 0x1000000 && stat(data, &st) == 0 && (st.st_size == -1 || addr + st.st_size > 0xf00000)) addr = 0x1000000; return (addr); } int main(void) { int i; /* Set machine type to PC98_SYSTEM_PARAMETER. */ set_machine_type(); /* Pick up arguments */ kargs = (void *)__args; initial_howto = kargs->howto; initial_bootdev = kargs->bootdev; initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; /* Initialize the v86 register set to a known-good state. */ bzero(&v86, sizeof(v86)); v86.efl = PSL_RESERVED_DEFAULT | PSL_I; /* * Initialise the heap as early as possible. Once this is done, malloc() is usable. */ bios_getmem(); #if defined(LOADER_BZIP2_SUPPORT) if (high_heap_size > 0) { heap_top = PTOV(high_heap_base + high_heap_size); heap_bottom = PTOV(high_heap_base); if (high_heap_base < memtop_copyin) memtop_copyin = high_heap_base; } else #endif { heap_top = (void *)PTOV(bios_basemem); heap_bottom = (void *)end; } setheap(heap_bottom, heap_top); /* * XXX Chicken-and-egg problem; we want to have console output early, but some * console attributes may depend on reading from eg. the boot device, which we * can't do yet. * * We can use printf() etc. once this is done. * If the previous boot stage has requested a serial console, prefer that. */ bi_setboothowto(initial_howto); if (initial_howto & RB_MULTIPLE) { if (initial_howto & RB_SERIAL) setenv("console", "comconsole vidconsole", 1); else setenv("console", "vidconsole comconsole", 1); } else if (initial_howto & RB_SERIAL) setenv("console", "comconsole", 1); else if (initial_howto & RB_MUTE) setenv("console", "nullconsole", 1); cons_probe(); /* * Initialise the block cache */ bcache_init(32, 512); /* 16k cache XXX tune this */ /* * Special handling for PXE and CD booting. */ if (kargs->bootinfo == 0) { /* * We only want the PXE disk to try to init itself in the below * walk through devsw if we actually booted off of PXE. */ if (kargs->bootflags & KARGS_FLAGS_PXE) pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); else if (kargs->bootflags & KARGS_FLAGS_CD) bc_add(initial_bootdev); } archsw.arch_autoload = i386_autoload; archsw.arch_getdev = i386_getdev; archsw.arch_copyin = i386_copyin; archsw.arch_copyout = i386_copyout; archsw.arch_readin = i386_readin; archsw.arch_isainb = isa_inb; archsw.arch_isaoutb = isa_outb; archsw.arch_loadaddr = pc98_loadaddr; /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024); if (initial_bootinfo != NULL) { initial_bootinfo->bi_basemem = bios_basemem / 1024; initial_bootinfo->bi_extmem = bios_extmem / 1024; } printf("\n"); printf("%s, Revision %s\n", bootprog_name, bootprog_rev); printf("(%s, %s)\n", bootprog_maker, bootprog_date); extract_currdev(); /* set $currdev and $loaddev */ setenv("LINES", "24", 1); /* optional */ interact(); /* doesn't return */ /* if we ever get here, it is an error */ return (1); } /* * Set the 'current device' by (if possible) recovering the boot device as * supplied by the initial bootstrap. * * XXX should be extended for netbooting. */ static void extract_currdev(void) { struct i386_devdesc new_currdev; int major; int biosdev = -1; /* Assume we are booting from a BIOS disk by default */ new_currdev.d_dev = &biosdisk; /* new-style boot loaders such as pxeldr and cdldr */ if (kargs->bootinfo == 0) { if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { /* we are booting from a CD with cdboot */ new_currdev.d_dev = &bioscd; new_currdev.d_unit = bc_bios2unit(initial_bootdev); } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { /* we are booting from pxeldr */ new_currdev.d_dev = &pxedisk; new_currdev.d_unit = 0; } else { /* we don't know what our boot device is */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { /* The passed-in boot device is bad */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } else { new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1; new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); biosdev = initial_bootinfo->bi_bios_dev; major = B_TYPE(initial_bootdev); /* * If we are booted by an old bootstrap, we have to guess at the BIOS * unit number. We will lose if there is more than one disk type * and we are not booting from the lowest-numbered disk type * (ie. SCSI when IDE also exists). */ if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) { /* biosdev doesn't match major */ if (B_TYPE(initial_bootdev) == 6) biosdev = 0x30 + B_UNIT(initial_bootdev); else biosdev = (major << 3) + 0x80 + B_UNIT(initial_bootdev); } } new_currdev.d_type = new_currdev.d_dev->dv_type; /* * If we are booting off of a BIOS disk and we didn't succeed in determining * which one we booted off of, just use disk0: as a reasonable default. */ if ((new_currdev.d_type == biosdisk.dv_type) && ((new_currdev.d_unit = bd_bios2unit(biosdev)) == -1)) { printf("Can't work out which disk we are booting from.\n" "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); new_currdev.d_unit = 0; } env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), i386_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, env_nounset); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { int i; for (i = 0; devsw[i] != NULL; ++i) if (devsw[i]->dv_cleanup != NULL) (devsw[i]->dv_cleanup)(); printf("Rebooting...\n"); delay(1000000); __exit(0); } /* provide this for panic, as it's not in the startup code */ void exit(int code) { __exit(code); } COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { mallocstats(); printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, sbrk(0), heap_top); return(CMD_OK); } /* ISA bus access functions for PnP, derived from */ static int isa_inb(int port) { u_char data; if (__builtin_constant_p(port) && (((port) & 0xffff) < 0x100) && ((port) < 0x10000)) { __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port))); } else { __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); } return(data); } static void isa_outb(int port, int value) { u_char al = value; if (__builtin_constant_p(port) && (((port) & 0xffff) < 0x100) && ((port) < 0x10000)) { __asm __volatile("outb %0,%1" : : "a" (al), "id" ((u_short)(port))); } else { __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); } }