diff options
Diffstat (limited to 'arch/x86/boot/setup.s')
-rw-r--r-- | arch/x86/boot/setup.s | 268 |
1 files changed, 0 insertions, 268 deletions
diff --git a/arch/x86/boot/setup.s b/arch/x86/boot/setup.s deleted file mode 100644 index 2afc974..0000000 --- a/arch/x86/boot/setup.s +++ /dev/null @@ -1,268 +0,0 @@ -/* - setup.s is second stage bootloader loaded at 0x90200 (by - first stage), is responsible for getting the system data - from the BIOS. - - System data puts at special place: 0x90000-0x901FF. -*/ - -.code16 # Tell GAS to generate 16 bit code - -.include "bios.inc" -.include "rm_seg.inc" - -.set ENDSEG, KERNSEG + KERNSIZE # Where to stop loading kernel - -# Define some constants for the GDT segment descriptor offsets -.set CODESEG, gdt_code - gdt_start -.set DATASEG, gdt_data - gdt_start - -# Keyboard Controller commands: -.set READ_OUTP, 0xD0 # Read Output Port -.set WRITE_OUTP, 0xD1 # Write Output Port - -.global _start # Make the symbol visible to ld -_start: - mov $SDATASEG, %ax - mov %ax, %ds - mov %ax, %ss - mov $KERNSEG, %ax - mov %ax, %es - - mov $0xFF00, %bp # Set up the stack at 0x9ff00 - mov %bp, %sp - - BIOS_PRINT $get_data_msg - - # Get current cursor position - mov $0x3, %ah - xor %bh, %bh # Page Number = 0 - int $0x10 - add $3, %dh # Add number of next BIOS_PRINTs - mov %dx, (2) # Save it - - # Get disk drive parameters - xor %ax, %ax - mov %ax, %es # ES:DI = 0x0000:0x0000 to guard - mov %ax, %di # against BIOS bugs - mov (0), %dl # Set drive boot - mov $0x8, %ah - int $0x13 - jc disk_error - - # Interrupt return: - # - CH = low eight bits of maximum cylinder number - # - CL = maximum sector number (bits 5-0) - # high two bits of maximum cylinder number (bits 7-6) - # - DH = maximum head number - xor %ch, %ch - and $0b00111111, %cl - xor %dl, %dl - mov %dx, heads - mov %cx, sectors - - # TODO: get memory size - # TODO: get video infos - -load_kernel: # Load our kernel - BIOS_PRINT $boot_load_kern_msg - - # Load the system at $KERNSEG address: - mov $KERNSEG, %ax - mov %ax, %es # ES - starting address segment - xor %bx, %bx # BX is offset within segment - - # A few words about the algorithm: - # We read 0x10000 bytes (64 kB) and overflow BX (16 bytes register), - # then add 0x1000 to ES reg, after that compare with $ENDSEG - # - # If KERNSIZE != 0x10000 * N we read some unnecessary data, but - # i think it's not a problem -repeat_read: - mov %es, %ax - cmp $ENDSEG, %ax - jae enable_a20 # Jump if AX >= $ENDSEG -get_sects_for_read: - mov sectors, %ax # AX = amount of sectors - current sector - sub csect, %ax # AX has 6 significant bytes - mov %ax, %cx # Calculate how many bytes we get by - # reading AX sectors - shl $9, %cx # One sector = 2^9 = 512 - add %bx, %cx # CX = 0@@@.@@@0.0000.0000 + BX - jnc read_sects # if not overflow, then jump - jz read_sects # if CX = 0, then jump - xor %ax, %ax # AX = 0 - sub %bx, %ax # AX = amount of sectors that we must - shr $9, %ax # read for overflow BX -read_sects: - call read_track # INPUT: AX - mov %ax, %cx # CX = amount of sectors that we read - add csect, %ax - cmp sectors, %ax # Current sector = amount of sectors? - jne check_read # If not equal, jump - mov chead, %ax - cmp heads, %ax # Current head = amount of heads? - jne inc_chead # If not equal, jump - movw $0xffff, chead # Current head will overflow and equal 0 - # after INC instuction in inc_chead - incw ctrack # Go to next cylinder - # We don't check cylinder overflow - # because it makes no sense -inc_chead: - incw chead - xor %ax, %ax -check_read: - mov %ax, csect # Calculate how many bytes we get by - shl $9, %cx # reading AX sectors - add %cx, %bx # Add it to BX - jnc repeat_read # If BX not overflow, jjmp - mov %es, %ax - add $0x1000, %ax # We read 0x10000 = 65536 bytes - mov %ax, %es - xor %bx, %bx - jmp repeat_read - -# INPUT: -# AX - amount of sectors that we want to read -read_track: - push %ax - push %bx - push %cx - push %dx - mov ctrack, %dx - mov csect, %cx # Set sector - inc %cx # Add +1 because sector has a base of 1 - mov %dl, %ch # Set cylinder - mov chead, %dh # Set head - mov %dl, %dh - mov (0), %dl # Set boot - mov $0x02, %ah # Set BIOS read sector routine - int $0x13 - jc . # Error :( - pop %dx - pop %cx - pop %bx - pop %ax - ret - -enable_a20: - BIOS_PRINT $enable_a20_msg - - cli # Switch of interrupt until we have set - # up the protected mode interrupt vector - - call wait_input - mov $READ_OUTP, %al - out %al, $0x64 - call wait_output - - in $0x60, %al # Read input buffer and store on stack - push %ax - call wait_input - - mov $WRITE_OUTP, %al - out %al, $0x64 - call wait_input - - pop %ax # Pop the output port data from stack - or $2, %al # Set bit 1 (A20) to enable - out %al, $0x60 # Write the data to the output port - call wait_input - -switch_to_pm: - BIOS_PRINT $boot_prot_mode_msg - lgdt gdt_descriptor # Load our global descriptor table - - mov %cr0, %eax # Set the first bit of CR0 - or $0x01, %eax # to make the switch to protected mode - mov %eax, %cr0 - - # Make a far jump to our 32-bit code. - # This also forces the CPU to flush its cache of pre-fetched - # and real-mode decoded instructions, which can cause problems - jmp $CODESEG, $KERNADDR - -disk_error: - BIOS_PRINT $disk_error_msg - jmp . - -wait_input: - in $0x64, %al # Read status - test $2, %al # Is input buffer full? - jnz wait_input # yes - continue waiting - ret - -wait_output: - in $0x64, %al - test $1, %al # Is output buffer full? - jz wait_output # no - continue waiting - ret - -# Global Descriptor Table (contains 8-byte entries) -gdt_start: -gdt_null: # The mandatory null descriptor - .quad 0x0 - -gdt_code: # The code segment descriptor - # Base = 0x0, limit = 0xfffff - # 1st flags: (present)1 (privilege)00 (descriptor type)1 -> b1001 - # Type flags: (code)1 (conforming)0 (readable)1 (accessed)0 -> b1010 - # 2nd flags: (granularity)1 (size)1 (64-bit seg)0 (AVL)0 -> b1100 - .word 0xffff # Limit (bits 0-15) - .word 0x0 # Base (bits 0-15) - .byte 0x0 # Base (bits 16-23) - .byte 0b10011010 # 1st flags, type flags - .byte 0b11001111 # 2nd flags, limit (bits 16-19) - .byte 0x0 # Base (bits 24-31) - -gdt_data: # the data segment descriptor - # Same as code segment except for the type flags: - # Type flags: (code)0 (direction)0 (writable)1, (accessed)0 -> b0010 - # P.S: direction bit: 0 the segment grows up - .word 0xffff # Limit (bits 0-15) - .word 0x0 # Base (bits 0-15) - .byte 0x0 # Base (bits 16-23) - .byte 0b10010010 # 1st flags, type flags - .byte 0b11001111 # 2nd flags, limit (bits 16-19) - .byte 0x0 # Base (bits 24-31) -gdt_end: - -# Global variables - -# Total amount of HDD components: -heads: # 8 significant bytes - .word 0x0 -sectors: # 6 significant bytes - .word 0x0 - -# The number of the current component with which we interact: -ctrack: # track/cylinder - .word 0x0 -chead: - .word 0x0 -csect: - .word 1 + SETUPLEN - -gdt_descriptor: - # The 6-byte GDT structure containing: - # - GDT size, 2 bytes (size always less one of the real size): - .word gdt_end - gdt_start - 1 - # - GDT address, 4 bytes: - .word gdt_start, 0x9 - -get_data_msg: - .asciz "Getting the system data from the BIOS\r\n" - -boot_prot_mode_msg: - .asciz "Entering 32-bit protected mode\r\n" - -boot_load_kern_msg: - .asciz "Loading kernel into memory\r\n" - -enable_a20_msg: - .asciz "Enabling A20 line\r\n" - -disk_error_msg: - .asciz "Disk read error!" - -.space (512 * SETUPLEN) - (. - _start), 0 |