kolibri-process:

v86 works now, at least in VBox

git-svn-id: svn://kolibrios.org@4993 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2014-07-11 10:47:51 +00:00
parent c8deb6df88
commit e72c474426
14 changed files with 1661 additions and 279 deletions

View File

@ -5,7 +5,7 @@
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision: 4273 $
$Revision: 4437 $
; =============================================================================
; ================================= Constants =================================

View File

@ -5,7 +5,7 @@
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision: 4133 $
$Revision: 4465 $
; Read/write functions try to do large operations,
; it is significantly faster than several small operations.

View File

@ -5,7 +5,7 @@
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision: 4273 $
$Revision: 4695 $
;**********************************************************

View File

@ -5,7 +5,7 @@
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision: 4420 $
$Revision: 4839 $
; Low-level driver for HDD access

View File

@ -21,7 +21,7 @@
;
;**************************************************************************
$Revision: 3742 $
$Revision: 4700 $
align 4
find_empty_slot_CD_cache:

View File

@ -94,6 +94,7 @@ __exports:
load_cursor, 'LoadCursor', \ ;stdcall
\
get_curr_task, 'GetCurrentTask', \
change_task, 'ChangeTask', \
load_file, 'LoadFile', \ ;retval eax, ebx
delay_ms, 'Sleep', \
\

View File

@ -0,0 +1,881 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2014. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision: 4619 $
; Initializes MTRRs.
proc init_mtrr
cmp [BOOT_VARS+BOOT_MTRR], byte 2
je .exit
bt [cpu_caps], CAPS_MTRR
jnc .exit
call mtrr_reconfigure
stdcall set_mtrr, [LFBAddress], 0x1000000, MEM_WC
.exit:
ret
endp
; Helper procedure for mtrr_reconfigure and set_mtrr,
; called before changes in MTRRs.
proc mtrr_begin_change
mov eax, cr0
or eax, 0x60000000 ;disable caching
mov cr0, eax
wbinvd ;invalidate cache
ret
endp
; Helper procedure for mtrr_reconfigure and set_mtrr,
; called after changes in MTRRs.
proc mtrr_end_change
wbinvd ;again invalidate
mov eax, cr0
and eax, not 0x60000000
mov cr0, eax ; enable caching
ret
endp
; Some limits to number of structures located in the stack.
MAX_USEFUL_MTRRS = 16
MAX_RANGES = 16
; mtrr_reconfigure keeps a list of MEM_WB ranges.
; This structure describes one item in the list.
struct mtrr_range
next dd ? ; next item
start dq ? ; first byte
length dq ? ; length in bytes
ends
uglobal
align 4
num_variable_mtrrs dd 0 ; number of variable-range MTRRs
endg
; Helper procedure for MTRR initialization.
; Takes MTRR configured by BIOS and tries to recongifure them
; in order to allow non-UC data at top of 4G memory.
; Example: if low part of physical memory is 3.5G = 0xE0000000 bytes wide,
; BIOS can configure two MTRRs so that the first MTRR describes [0, 4G) as WB
; and the second MTRR describes [3.5G, 4G) as UC;
; WB+UC=UC, so the resulting memory map would be as needed,
; but in this configuration our attempts to map LFB at (say) 0xE8000000 as WC
; would be ignored, WB+UC+WC is still UC.
; So we must keep top of 4G memory not covered by MTRRs,
; using three WB MTRRs [0,2G) + [2G,3G) + [3G,3.5G),
; this gives the same memory map, but allows to add further entries.
; See mtrrtest.asm for detailed input/output from real hardware+BIOS.
proc mtrr_reconfigure
push ebp ; we're called from init_LFB, and it feels hurt when ebp is destroyed
; 1. Prepare local variables.
; 1a. Create list of MAX_RANGES free (aka not yet allocated) ranges.
xor eax, eax
lea ecx, [eax+MAX_RANGES]
.init_ranges:
sub esp, sizeof.mtrr_range - 4
push eax
mov eax, esp
dec ecx
jnz .init_ranges
mov eax, esp
; 1b. Fill individual local variables.
xor edx, edx
sub esp, MAX_USEFUL_MTRRS * 16 ; .mtrrs
push edx ; .mtrrs_end
push edx ; .num_used_mtrrs
push eax ; .first_free_range
push edx ; .first_range: no ranges yet
mov cl, [cpu_phys_addr_width]
or eax, -1
shl eax, cl ; note: this uses cl&31 = cl-32, not the entire cl
push eax ; .phys_reserved_mask
virtual at esp
.phys_reserved_mask dd ?
.first_range dd ?
.first_free_range dd ?
.num_used_mtrrs dd ?
.mtrrs_end dd ?
.mtrrs rq MAX_USEFUL_MTRRS * 2
.local_vars_size = $ - esp
end virtual
; 2. Get the number of variable-range MTRRs from MTRRCAP register.
; Abort if zero.
mov ecx, 0xFE
rdmsr
test al, al
jz .abort
mov byte [num_variable_mtrrs], al
; 3. Validate MTRR_DEF_TYPE register.
mov ecx, 0x2FF
rdmsr
; If BIOS has not initialized variable-range MTRRs, fallback to step 7.
test ah, 8
jz .fill_ranges_from_memory_map
; If the default memory type (not covered by MTRRs) is not UC,
; then probably BIOS did something strange, so it is better to exit immediately
; hoping for the best.
cmp al, MEM_UC
jnz .abort
; 4. Validate all variable-range MTRRs
; and copy configured MTRRs to the local array [.mtrrs].
; 4a. Prepare for the loop over existing variable-range MTRRs.
mov ecx, 0x200
lea edi, [.mtrrs]
.get_used_mtrrs_loop:
; 4b. For every MTRR, read PHYSBASEn and PHYSMASKn.
; In PHYSBASEn, clear upper bits and copy to ebp:ebx.
rdmsr
or edx, [.phys_reserved_mask]
xor edx, [.phys_reserved_mask]
mov ebp, edx
mov ebx, eax
inc ecx
; If PHYSMASKn is not active, ignore this MTRR.
rdmsr
inc ecx
test ah, 8
jz .get_used_mtrrs_next
; 4c. For every active MTRR, check that number of local entries is not too large.
inc [.num_used_mtrrs]
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS
ja .abort
; 4d. For every active MTRR, store PHYSBASEn with upper bits cleared.
; This contains the MTRR base and the memory type in low byte.
mov [edi], ebx
mov [edi+4], ebp
; 4e. For every active MTRR, check that the range is continuous:
; PHYSMASKn with upper bits set must be negated power of two, and
; low bits of PHYSBASEn must be zeroes:
; PHYSMASKn = 1...10...0,
; PHYSBASEn = x...x0...0,
; this defines a continuous range from x...x0...0 to x...x1...1,
; length = 10...0 = negated PHYSMASKn.
; Store length in the local array.
and eax, not 0xFFF
or edx, [.phys_reserved_mask]
mov dword [edi+8], 0
mov dword [edi+12], 0
sub [edi+8], eax
sbb [edi+12], edx
; (x and -x) is the maximum power of two that divides x.
; Condition for powers of two: (x and -x) equals x.
and eax, [edi+8]
and edx, [edi+12]
cmp eax, [edi+8]
jnz .abort
cmp edx, [edi+12]
jnz .abort
sub eax, 1
sbb edx, 0
and eax, not 0xFFF
and eax, ebx
jnz .abort
and edx, ebp
jnz .abort
; 4f. For every active MTRR, validate memory type: it must be either WB or UC.
add edi, 16
cmp bl, MEM_UC
jz .get_used_mtrrs_next
cmp bl, MEM_WB
jnz .abort
.get_used_mtrrs_next:
; 4g. Repeat the loop at 4b-4f for all [num_variable_mtrrs] entries.
mov eax, [num_variable_mtrrs]
lea eax, [0x200+eax*2]
cmp ecx, eax
jb .get_used_mtrrs_loop
; 4h. If no active MTRRs were detected, fallback to step 7.
cmp [.num_used_mtrrs], 0
jz .fill_ranges_from_memory_map
mov [.mtrrs_end], edi
; 5. Generate sorted list of ranges marked as WB.
; 5a. Prepare for the loop over configured MTRRs filled at step 4.
lea ecx, [.mtrrs]
.fill_wb_ranges:
; 5b. Ignore non-WB MTRRs.
mov ebx, [ecx]
cmp bl, MEM_WB
jnz .next_wb_range
mov ebp, [ecx+4]
and ebx, not 0xFFF ; clear memory type and reserved bits
; ebp:ebx = start of the range described by the current MTRR.
; 5c. Find the first existing range containing a point greater than ebp:ebx.
lea esi, [.first_range]
.find_range_wb:
; If there is no next range or start of the next range is greater than ebp:ebx,
; exit the loop to 5d.
mov edi, [esi]
test edi, edi
jz .found_place_wb
mov eax, ebx
mov edx, ebp
sub eax, dword [edi+mtrr_range.start]
sbb edx, dword [edi+mtrr_range.start+4]
jb .found_place_wb
; Otherwise, if end of the next range is greater than or equal to ebp:ebx,
; exit the loop to 5e.
mov esi, edi
sub eax, dword [edi+mtrr_range.length]
sbb edx, dword [edi+mtrr_range.length+4]
jb .expand_wb
or eax, edx
jnz .find_range_wb
jmp .expand_wb
.found_place_wb:
; 5d. ebp:ebx is not within any existing range.
; Insert a new range between esi and edi.
; (Later, during 5e, it can be merged with the following ranges.)
mov eax, [.first_free_range]
test eax, eax
jz .abort
mov [esi], eax
mov edx, [eax+mtrr_range.next]
mov [.first_free_range], edx
mov dword [eax+mtrr_range.start], ebx
mov dword [eax+mtrr_range.start+4], ebp
; Don't fill [eax+mtrr_range.next] and [eax+mtrr_range.length] yet,
; they will be calculated including merges at step 5e.
mov esi, edi
mov edi, eax
.expand_wb:
; 5e. The range at edi contains ebp:ebx, and esi points to the first range
; to be checked for merge: esi=edi if ebp:ebx was found in an existing range,
; esi is next after edi if a new range with ebp:ebx was created.
; Merge it with following ranges while start of the next range is not greater
; than the end of the new range.
add ebx, [ecx+8]
adc ebp, [ecx+12]
; ebp:ebx = end of the range described by the current MTRR.
.expand_wb_loop:
; If there is no next range or start of the next range is greater than ebp:ebx,
; exit the loop to 5g.
test esi, esi
jz .expand_wb_done
mov eax, ebx
mov edx, ebp
sub eax, dword [esi+mtrr_range.start]
sbb edx, dword [esi+mtrr_range.start+4]
jb .expand_wb_done
; Otherwise, if end of the next range is greater than or equal to ebp:ebx,
; exit the loop to 5f.
sub eax, dword [esi+mtrr_range.length]
sbb edx, dword [esi+mtrr_range.length+4]
jb .expand_wb_last
; Otherwise, the current range is completely within the new range.
; Free it and continue the loop.
mov edx, [esi+mtrr_range.next]
cmp esi, edi
jz @f
mov eax, [.first_free_range]
mov [esi+mtrr_range.next], eax
mov [.first_free_range], esi
@@:
mov esi, edx
jmp .expand_wb_loop
.expand_wb_last:
; 5f. Start of the new range is inside range described by esi,
; end of the new range is inside range described by edi.
; If esi is equal to edi, the new range is completely within
; an existing range, so proceed to the next range.
cmp esi, edi
jz .next_wb_range
; Otherwise, set end of interval at esi to end of interval at edi
; and free range described by edi.
mov ebx, dword [esi+mtrr_range.start]
mov ebp, dword [esi+mtrr_range.start+4]
add ebx, dword [esi+mtrr_range.length]
adc ebp, dword [esi+mtrr_range.length+4]
mov edx, [esi+mtrr_range.next]
mov eax, [.first_free_range]
mov [esi+mtrr_range.next], eax
mov [.first_free_range], esi
mov esi, edx
.expand_wb_done:
; 5g. We have found the next range (maybe 0) after merging and
; the new end of range (maybe ebp:ebx from the new range
; or end of another existing interval calculated at step 5f).
; Write them to range at edi.
mov [edi+mtrr_range.next], esi
sub ebx, dword [edi+mtrr_range.start]
sbb ebp, dword [edi+mtrr_range.start+4]
mov dword [edi+mtrr_range.length], ebx
mov dword [edi+mtrr_range.length+4], ebp
.next_wb_range:
; 5h. Continue the loop 5b-5g over all configured MTRRs.
add ecx, 16
cmp ecx, [.mtrrs_end]
jb .fill_wb_ranges
; 6. Exclude all ranges marked as UC.
; 6a. Prepare for the loop over configured MTRRs filled at step 4.
lea ecx, [.mtrrs]
.fill_uc_ranges:
; 6b. Ignore non-UC MTRRs.
mov ebx, [ecx]
cmp bl, MEM_UC
jnz .next_uc_range
mov ebp, [ecx+4]
and ebx, not 0xFFF ; clear memory type and reserved bits
; ebp:ebx = start of the range described by the current MTRR.
lea esi, [.first_range]
; 6c. Find the first existing range containing a point greater than ebp:ebx.
.find_range_uc:
; If there is no next range, ignore this MTRR,
; exit the loop and continue to next MTRR.
mov edi, [esi]
test edi, edi
jz .next_uc_range
; If start of the next range is greater than or equal to ebp:ebx,
; exit the loop to 6e.
mov eax, dword [edi+mtrr_range.start]
mov edx, dword [edi+mtrr_range.start+4]
sub eax, ebx
sbb edx, ebp
jnb .truncate_uc
; Otherwise, continue the loop if end of the next range is less than ebp:ebx,
; exit the loop to 6d otherwise.
mov esi, edi
add eax, dword [edi+mtrr_range.length]
adc edx, dword [edi+mtrr_range.length+4]
jnb .find_range_uc
; 6d. ebp:ebx is inside (or at end of) an existing range.
; Split the range. (The second range, maybe containing completely within UC-range,
; maybe of zero length, can be removed at step 6e, if needed.)
mov edi, [.first_free_range]
test edi, edi
jz .abort
mov dword [edi+mtrr_range.start], ebx
mov dword [edi+mtrr_range.start+4], ebp
mov dword [edi+mtrr_range.length], eax
mov dword [edi+mtrr_range.length+4], edx
mov eax, [edi+mtrr_range.next]
mov [.first_free_range], eax
mov eax, [esi+mtrr_range.next]
mov [edi+mtrr_range.next], eax
; don't change [esi+mtrr_range.next] yet, it will be filled at step 6e
mov eax, ebx
mov edx, ebp
sub eax, dword [esi+mtrr_range.start]
sbb edx, dword [esi+mtrr_range.start+4]
mov dword [esi+mtrr_range.length], eax
mov dword [esi+mtrr_range.length+4], edx
.truncate_uc:
; 6e. edi is the first range after ebp:ebx, check it and next ranges
; for intersection with the new range, truncate heads.
add ebx, [ecx+8]
adc ebp, [ecx+12]
; ebp:ebx = end of the range described by the current MTRR.
.truncate_uc_loop:
; If start of the next range is greater than ebp:ebx,
; exit the loop to 6g.
mov eax, ebx
mov edx, ebp
sub eax, dword [edi+mtrr_range.start]
sbb edx, dword [edi+mtrr_range.start+4]
jb .truncate_uc_done
; Otherwise, if end of the next range is greater than ebp:ebx,
; exit the loop to 6f.
sub eax, dword [edi+mtrr_range.length]
sbb edx, dword [edi+mtrr_range.length+4]
jb .truncate_uc_last
; Otherwise, the current range is completely within the new range.
; Free it and continue the loop if there is a next range.
; If that was a last range, exit the loop to 6g.
mov edx, [edi+mtrr_range.next]
mov eax, [.first_free_range]
mov [.first_free_range], edi
mov [edi+mtrr_range.next], eax
mov edi, edx
test edi, edi
jnz .truncate_uc_loop
jmp .truncate_uc_done
.truncate_uc_last:
; 6f. The range at edi partially intersects with the UC-range described by MTRR.
; Truncate it from the head.
mov dword [edi+mtrr_range.start], ebx
mov dword [edi+mtrr_range.start+4], ebp
neg eax
adc edx, 0
neg edx
mov dword [edi+mtrr_range.length], eax
mov dword [edi+mtrr_range.length+4], edx
.truncate_uc_done:
; 6g. We have found the next range (maybe 0) after intersection.
; Write it to [esi+mtrr_range.next].
mov [esi+mtrr_range.next], edi
.next_uc_range:
; 6h. Continue the loop 6b-6g over all configured MTRRs.
add ecx, 16
cmp ecx, [.mtrrs_end]
jb .fill_uc_ranges
; Sanity check: if there are no ranges after steps 5-6,
; fallback to step 7. Otherwise, go to 8.
cmp [.first_range], 0
jnz .ranges_ok
.fill_ranges_from_memory_map:
; 7. BIOS has not configured variable-range MTRRs.
; Create one range from 0 to [MEM_AMOUNT].
mov eax, [.first_free_range]
mov edx, [eax+mtrr_range.next]
mov [.first_free_range], edx
mov [.first_range], eax
xor edx, edx
mov [eax+mtrr_range.next], edx
mov dword [eax+mtrr_range.start], edx
mov dword [eax+mtrr_range.start+4], edx
mov ecx, [MEM_AMOUNT]
mov dword [eax+mtrr_range.length], ecx
mov dword [eax+mtrr_range.length+4], edx
.ranges_ok:
; 8. We have calculated list of WB-ranges.
; Now we should calculate a list of MTRRs so that
; * every MTRR describes a range with length = power of 2 and start that is aligned,
; * every MTRR can be WB or UC
; * (sum of all WB ranges) minus (sum of all UC ranges) equals the calculated list
; * top of 4G memory must not be covered by any ranges
; Example: range [0,0xBC000000) can be converted to
; [0,0x80000000)+[0x80000000,0xC0000000)-[0xBC000000,0xC0000000)
; WB +WB -UC
; but not to [0,0x100000000)-[0xC0000000,0x100000000)-[0xBC000000,0xC0000000).
; 8a. Check that list of ranges is [0,something) plus, optionally, [4G,something).
; This holds in practice (see mtrrtest.asm for real-life examples)
; and significantly simplifies the code: ranges are independent, start of range
; is almost always aligned (the only exception >4G upper memory can be easily covered),
; there is no need to consider adding holes before start of range, only
; append them to end of range.
xor eax, eax
mov edi, [.first_range]
cmp dword [edi+mtrr_range.start], eax
jnz .abort
cmp dword [edi+mtrr_range.start+4], eax
jnz .abort
cmp dword [edi+mtrr_range.length+4], eax
jnz .abort
mov edx, [edi+mtrr_range.next]
test edx, edx
jz @f
cmp dword [edx+mtrr_range.start], eax
jnz .abort
cmp dword [edx+mtrr_range.start+4], 1
jnz .abort
cmp [edx+mtrr_range.next], eax
jnz .abort
@@:
; 8b. Initialize: no MTRRs filled.
mov [.num_used_mtrrs], eax
lea esi, [.mtrrs]
.range2mtrr_loop:
; 8c. If we are dealing with upper-memory range (after 4G)
; with length > start, create one WB MTRR with [start,2*start),
; reset start to 2*start and return to this step.
; Example: [4G,24G) -> [4G,8G) {returning} + [8G,16G) {returning}
; + [16G,24G) {advancing to ?}.
mov eax, dword [edi+mtrr_range.length+4]
test eax, eax
jz .less4G
mov edx, dword [edi+mtrr_range.start+4]
cmp eax, edx
jb .start_aligned
inc [.num_used_mtrrs]
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS
ja .abort
mov dword [esi], MEM_WB
mov dword [esi+4], edx
mov dword [esi+8], 0
mov dword [esi+12], edx
add esi, 16
add dword [edi+mtrr_range.start+4], edx
sub dword [edi+mtrr_range.length+4], edx
jnz .range2mtrr_loop
cmp dword [edi+mtrr_range.length], 0
jz .range2mtrr_next
.less4G:
; 8d. If we are dealing with low-memory range (before 4G)
; and appending a maximal-size hole would create a range covering top of 4G,
; create a maximal-size WB range and return to this step.
; Example: for [0,0xBC000000) the following steps would consider
; variants [0,0x80000000)+(another range to be splitted) and
; [0,0x100000000)-(another range to be splitted); we forbid the last variant,
; so the first variant must be used.
bsr ecx, dword [edi+mtrr_range.length]
xor edx, edx
inc edx
shl edx, cl
lea eax, [edx*2]
add eax, dword [edi+mtrr_range.start]
jnz .start_aligned
inc [.num_used_mtrrs]
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS
ja .abort
mov eax, dword [edi+mtrr_range.start]
mov dword [esi], eax
or dword [esi], MEM_WB
mov dword [esi+4], 0
mov dword [esi+8], edx
mov dword [esi+12], 0
add esi, 16
add dword [edi+mtrr_range.start], edx
sub dword [edi+mtrr_range.length], edx
jnz .less4G
jmp .range2mtrr_next
.start_aligned:
; Start is aligned for any allowed length, maximum-size hole is allowed.
; Select the best MTRR configuration for one range.
; length=...101101
; Without hole at the end, we need one WB MTRR for every 1-bit in length:
; length=...100000 + ...001000 + ...000100 + ...000001
; We can also append one hole at the end so that one 0-bit (selected by us)
; becomes 1 and all lower bits become 0 for WB-range:
; length=...110000 - (...00010 + ...00001)
; In this way, we need one WB MTRR for every 1-bit higher than the selected bit,
; one WB MTRR for the selected bit, one UC MTRR for every 0-bit between
; the selected bit and lowest 1-bit (they become 1-bits after negation)
; and one UC MTRR for lowest 1-bit.
; So we need to select 0-bit with the maximal difference
; (number of 0-bits) - (number of 1-bits) between selected and lowest 1-bit,
; this equals the gain from using a hole. If the difference is negative for
; all 0-bits, don't append hole.
; Note that lowest 1-bit is not included when counting, but selected 0-bit is.
; 8e. Find the optimal bit position for hole.
; eax = current difference, ebx = best difference,
; ecx = hole bit position, edx = current bit position.
xor eax, eax
xor ebx, ebx
xor ecx, ecx
bsf edx, dword [edi+mtrr_range.length]
jnz @f
bsf edx, dword [edi+mtrr_range.length+4]
add edx, 32
@@:
push edx ; save position of lowest 1-bit for step 8f
.calc_stat:
inc edx
cmp edx, 64
jae .stat_done
inc eax ; increment difference in hope for 1-bit
; Note: bt conveniently works with both .length and .length+4,
; depending on whether edx>=32.
bt dword [edi+mtrr_range.length], edx
jc .calc_stat
dec eax ; hope was wrong, decrement difference to correct 'inc'
dec eax ; and again, now getting the real difference
cmp eax, ebx
jle .calc_stat
mov ebx, eax
mov ecx, edx
jmp .calc_stat
.stat_done:
; 8f. If we decided to create a hole, flip all bits between lowest and selected.
pop edx ; restore position of lowest 1-bit saved at step 8e
test ecx, ecx
jz .fill_hi_init
@@:
inc edx
cmp edx, ecx
ja .fill_hi_init
btc dword [edi+mtrr_range.length], edx
jmp @b
.fill_hi_init:
; 8g. Create MTRR ranges corresponding to upper 32 bits.
sub ecx, 32
.fill_hi_loop:
bsr edx, dword [edi+mtrr_range.length+4]
jz .fill_hi_done
inc [.num_used_mtrrs]
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS
ja .abort
mov eax, dword [edi+mtrr_range.start]
mov [esi], eax
mov eax, dword [edi+mtrr_range.start+4]
mov [esi+4], eax
xor eax, eax
mov [esi+8], eax
bts eax, edx
mov [esi+12], eax
cmp edx, ecx
jl .fill_hi_uc
or dword [esi], MEM_WB
add dword [edi+mtrr_range.start+4], eax
jmp @f
.fill_hi_uc:
sub dword [esi+4], eax
sub dword [edi+mtrr_range.start+4], eax
@@:
add esi, 16
sub dword [edi+mtrr_range.length], eax
jmp .fill_hi_loop
.fill_hi_done:
; 8h. Create MTRR ranges corresponding to lower 32 bits.
add ecx, 32
.fill_lo_loop:
bsr edx, dword [edi+mtrr_range.length]
jz .range2mtrr_next
inc [.num_used_mtrrs]
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS
ja .abort
mov eax, dword [edi+mtrr_range.start]
mov [esi], eax
mov eax, dword [edi+mtrr_range.start+4]
mov [esi+4], eax
xor eax, eax
mov [esi+12], eax
bts eax, edx
mov [esi+8], eax
cmp edx, ecx
jl .fill_lo_uc
or dword [esi], MEM_WB
add dword [edi+mtrr_range.start], eax
jmp @f
.fill_lo_uc:
sub dword [esi], eax
sub dword [edi+mtrr_range.start], eax
@@:
add esi, 16
sub dword [edi+mtrr_range.length], eax
jmp .fill_lo_loop
.range2mtrr_next:
; 8i. Repeat the loop at 8c-8h for all ranges.
mov edi, [edi+mtrr_range.next]
test edi, edi
jnz .range2mtrr_loop
; 9. We have calculated needed MTRRs, now setup them in the CPU.
; 9a. Abort if number of MTRRs is too large.
mov eax, [num_variable_mtrrs]
cmp [.num_used_mtrrs], eax
ja .abort
; 9b. Prepare for changes.
call mtrr_begin_change
; 9c. Prepare for loop over MTRRs.
lea esi, [.mtrrs]
mov ecx, 0x200
@@:
; 9d. For every MTRR, copy PHYSBASEn as is: step 8 has configured
; start value and type bits as needed.
mov eax, [esi]
mov edx, [esi+4]
wrmsr
inc ecx
; 9e. For every MTRR, calculate PHYSMASKn = -(length) or 0x800
; with upper bits cleared, 0x800 = MTRR is valid.
xor eax, eax
xor edx, edx
sub eax, [esi+8]
sbb edx, [esi+12]
or eax, 0x800
or edx, [.phys_reserved_mask]
xor edx, [.phys_reserved_mask]
wrmsr
inc ecx
; 9f. Continue steps 9d and 9e for all MTRRs calculated at step 8.
add esi, 16
dec [.num_used_mtrrs]
jnz @b
; 9g. Zero other MTRRs.
xor eax, eax
xor edx, edx
mov ebx, [num_variable_mtrrs]
lea ebx, [0x200+ebx*2]
@@:
cmp ecx, ebx
jae @f
wrmsr
inc ecx
wrmsr
inc ecx
jmp @b
@@:
; 9i. Configure MTRR_DEF_TYPE.
mov ecx, 0x2FF
rdmsr
or ah, 8 ; enable variable-ranges MTRR
and al, 0xF0; default memtype = UC
wrmsr
; 9j. Changes are done.
call mtrr_end_change
.abort:
add esp, .local_vars_size + MAX_RANGES * sizeof.mtrr_range
pop ebp
ret
endp
; Allocate&set one MTRR for given range.
; size must be power of 2 that divides base.
proc set_mtrr stdcall, base:dword,size:dword,mem_type:dword
; find unused register
mov ecx, 0x201
.scan:
rdmsr
dec ecx
test ah, 8
jz .found
rdmsr
test edx, edx
jnz @f
and eax, not 0xFFF ; clear reserved bits
cmp eax, [base]
jz .ret
@@:
add ecx, 3
mov eax, [num_variable_mtrrs]
lea eax, [0x200+eax*2]
cmp ecx, eax
jb .scan
; no free registers, ignore the call
.ret:
ret
.found:
; found, write values
call mtrr_begin_change
xor edx, edx
mov eax, [base]
or eax, [mem_type]
wrmsr
mov al, [cpu_phys_addr_width]
xor edx, edx
bts edx, eax
xor eax, eax
sub eax, [size]
sbb edx, 0
or eax, 0x800
inc ecx
wrmsr
call mtrr_end_change
ret
endp
; Helper procedure for mtrr_validate.
; Calculates memory type for given address according to variable-range MTRRs.
; Assumes that MTRRs are enabled.
; in: ebx = 32-bit physical address
; out: eax = memory type for ebx
proc mtrr_get_real_type
; 1. Initialize: we have not yet found any MTRRs covering ebx.
push 0
mov ecx, 0x201
.mtrr_loop:
; 2. For every MTRR, check whether it is valid; if not, continue to the next MTRR.
rdmsr
dec ecx
test ah, 8
jz .next
; 3. For every valid MTRR, check whether (ebx and PHYSMASKn) == PHYSBASEn,
; excluding low 12 bits.
and eax, ebx
push eax
rdmsr
test edx, edx
pop edx
jnz .next
xor edx, eax
and edx, not 0xFFF
jnz .next
; 4. If so, set the bit corresponding to memory type defined by this MTRR.
and eax, 7
bts [esp], eax
.next:
; 5. Continue loop at 2-4 for all variable-range MTRRs.
add ecx, 3
mov eax, [num_variable_mtrrs]
lea eax, [0x200+eax*2]
cmp ecx, eax
jb .mtrr_loop
; 6. If no MTRRs cover address in ebx, use default MTRR type from MTRR_DEF_CAP.
pop edx
test edx, edx
jz .default
; 7. Find&clear 1-bit in edx.
bsf eax, edx
btr edx, eax
; 8. If there was only one 1-bit, then all MTRRs are consistent, return that bit.
test edx, edx
jz .nothing
; Otherwise, return MEM_UC (e.g. WB+UC is UC).
xor eax, eax
.nothing:
ret
.default:
mov ecx, 0x2FF
rdmsr
movzx eax, al
ret
endp
; If MTRRs are configured improperly, this is not obvious to the user;
; everything works, but the performance can be horrible.
; Try to detect this and let the user know that the low performance
; is caused by some problem and is not a global property of the system.
; Let's hope he would report it to developers...
proc mtrr_validate
; 1. If MTRRs are not supported, they cannot be configured improperly.
; Note: VirtualBox claims MTRR support in cpuid, but emulates MTRRCAP=0,
; which is efficiently equivalent to absent MTRRs.
; So check [num_variable_mtrrs] instead of CAPS_MTRR in [cpu_caps].
cmp [num_variable_mtrrs], 0
jz .exit
; 2. If variable-range MTRRs are not configured, this is a problem.
mov ecx, 0x2FF
rdmsr
test ah, 8
jz .fail
; 3. Get the memory type for address somewhere inside working memory.
; It must be write-back.
mov ebx, 0x27FFFF
call mtrr_get_real_type
cmp al, MEM_WB
jnz .fail
; 4. If we're using a mode with LFB,
; get the memory type for last pixel of the framebuffer.
; It must be write-combined.
test word [SCR_MODE], 0x4000
jz .exit
mov eax, [_display.pitch]
mul [_display.height]
dec eax
; LFB is mapped to virtual address LFB_BASE,
; it uses global pages if supported by CPU.
mov ebx, [sys_proc+PROC.pdt_0+(LFB_BASE shr 20)]
test ebx, PG_LARGE
jnz @f
mov ebx, [page_tabs+(LFB_BASE shr 10)]
@@:
and ebx, not 0xFFF
add ebx, eax
call mtrr_get_real_type
cmp al, MEM_WC
jz .exit
; 5. The check at step 4 fails on Bochs:
; Bochs BIOS configures MTRRs in a strange way not respecting [cpu_phys_addr_width],
; so mtrr_reconfigure avoids to touch anything.
; However, Bochs core ignores MTRRs (keeping them only for rdmsr/wrmsr),
; so we don't care about proper setting for Bochs.
; Use northbridge PCI id to detect Bochs: it emulates either i440fx or i430fx
; depending on configuration file.
mov eax, [pcidev_list.fd]
cmp eax, pcidev_list ; sanity check: fail if no PCI devices
jz .fail
cmp [eax+PCIDEV.vendor_device_id], 0x12378086
jz .exit
cmp [eax+PCIDEV.vendor_device_id], 0x01228086
jnz .fail
.exit:
ret
.fail:
mov ebx, mtrr_user_message
mov ebp, notifyapp
call fs_execute_from_sysdir_param
ret
endp

View File

@ -14,9 +14,7 @@ DEBUG_SHOW_IO = 0
struct V86_machine
; page directory
pagedir dd ?
; translation table: V86 address -> flat linear address
pages dd ?
process dd ?
; mutex to protect all data from writing by multiple threads at one time
mutex dd ?
; i/o permission map
@ -38,91 +36,87 @@ v86_create:
and dword [eax+V86_machine.mutex], 0
; allocate tables
mov ebx, eax
; We allocate 4 pages.
; First is main page directory for V86 mode.
; Second page:
; first half (0x800 bytes) is page table for addresses 0 - 0x100000,
; second half is for V86-to-linear translation.
; Third and fourth are for I/O permission map.
push 8000h ; blocks less than 8 pages are discontinuous
stdcall create_process, 4096, OS_BASE, 4096
test eax, eax
jz .fail2
mov [eax+PROC.mem_used], 4096
mov [ebx+V86_machine.process], eax
push 2000h
call kernel_alloc
test eax, eax
jz .fail2
mov [ebx+V86_machine.pagedir], eax
push edi eax
mov edi, eax
add eax, 1800h
mov [ebx+V86_machine.pages], eax
mov [ebx+V86_machine.iopm], eax
; initialize tables
mov ecx, 2000h/4
xor eax, eax
rep stosd
mov [ebx+V86_machine.iopm], edi
dec eax
mov ecx, 2000h/4
rep stosd
pop eax
; page directory: first entry is page table...
push edi
mov edi, eax
add eax, 1000h
push eax
call get_pg_addr
or al, PG_UW
stosd
; ...and also copy system page tables
; thx to Serge, system is located at high addresses
add edi, (OS_BASE shr 20) - 4
push esi
mov esi, sys_proc+PROC.pdt_0+(OS_BASE shr 20)
mov ecx, 0x80000000 shr 22
rep movsd
mov eax, -1
mov ecx, 2000h/4
rep stosd
mov eax, [ebx+V86_machine.process]
mov eax, [eax+PROC.pdt_0_phys]
pushfd
cli
mov cr3, eax
mov eax, [ebx+V86_machine.pagedir] ;root dir also is
call get_pg_addr ;used as page table
or al, PG_SW
mov [edi-4096+(page_tabs shr 20)], eax
pop esi
; now V86 specific: initialize known addresses in first Mb
pop eax
; first page - BIOS data (shared between all machines!)
; physical address = 0
; linear address = OS_BASE
mov dword [eax], 111b
mov dword [eax+800h], OS_BASE
; page before 0xA0000 - Extended BIOS Data Area (shared between all machines!)
; physical address = 0x9C000
; linear address = 0x8009C000
; (I have seen one computer with EBDA segment = 0x9D80,
; all other computers use less memory)
mov ecx, 4
mov edx, 0x9C000
push eax
lea edi, [eax+0x9C*4]
mov eax, PG_UW
mov [page_tabs], eax
invlpg [eax]
mov byte [0x500], 0xCD
mov byte [0x501], 0x13
mov byte [0x502], 0xF4
mov byte [0x503], 0xCD
mov byte [0x504], 0x10
mov byte [0x505], 0xF4
mov eax, 0x99000+PG_UW
mov edi, page_tabs+0x99*4
mov edx, 0x1000
mov ecx, 7
@@:
lea eax, [edx + OS_BASE]
mov [edi+800h], eax
lea eax, [edx + 111b]
stosd
add edx, 0x1000
add eax, edx
loop @b
pop eax
pop edi
; addresses 0xC0000 - 0xFFFFF - BIOS code (shared between all machines!)
; physical address = 0xC0000
; linear address = 0x800C0000
mov ecx, 0xC0
mov eax, 0xC0000+PG_UW
mov edi, page_tabs+0xC0*4
mov edx, 0x1000
mov ecx, 64
@@:
mov edx, ecx
shl edx, 12
push edx
or edx, 111b
mov [eax+ecx*4], edx
pop edx
add edx, OS_BASE
mov [eax+ecx*4+0x800], edx
inc cl
jnz @b
stosd
add eax, edx
loop @b
mov eax, sys_proc-OS_BASE+PROC.pdt_0
mov cr3, eax
popfd
pop edi
mov eax, ebx
ret
.fail2:
@ -132,15 +126,16 @@ v86_create:
xor eax, eax
ret
;not used
; Destroy V86 machine
; in: eax = handle
; out: nothing
; destroys: eax, ebx, ecx, edx (due to free)
v86_destroy:
push eax
stdcall kernel_free, [eax+V86_machine.pagedir]
pop eax
jmp free
;v86_destroy:
; push eax
; stdcall kernel_free, [eax+V86_machine.pagedir]
; pop eax
; jmp free
; Translate V86-address to linear address
; in: eax=V86 address
@ -150,28 +145,29 @@ v86_destroy:
v86_get_lin_addr:
push ecx edx
mov ecx, eax
mov edx, [esi+V86_machine.pages]
mov edx, page_tabs
shr ecx, 12
and eax, 0xFFF
add eax, [edx+ecx*4] ; atomic operation, no mutex needed
pop edx ecx
ret
;not used
; Sets linear address for V86-page
; in: eax=linear address (must be page-aligned)
; ecx=V86 page (NOT address!)
; esi=handle
; out: nothing
; destroys: nothing
v86_set_page:
push eax ebx
mov ebx, [esi+V86_machine.pagedir]
mov [ebx+ecx*4+0x1800], eax
call get_pg_addr
or al, 111b
mov [ebx+ecx*4+0x1000], eax
pop ebx eax
ret
;v86_set_page:
; push eax ebx
; mov ebx, [esi+V86_machine.pagedir]
; mov [ebx+ecx*4+0x1800], eax
; call get_pg_addr
; or al, 111b
; mov [ebx+ecx*4+0x1000], eax
; pop ebx eax
; ret
; Allocate memory in V86 machine
; in: eax=size (in bytes)
@ -214,21 +210,7 @@ init_sys_v86:
mov [sys_v86_machine], eax
test eax, eax
jz .ret
mov byte [OS_BASE + 0x500], 0xCD
mov byte [OS_BASE + 0x501], 0x13
mov byte [OS_BASE + 0x502], 0xF4
mov byte [OS_BASE + 0x503], 0xCD
mov byte [OS_BASE + 0x504], 0x10
mov byte [OS_BASE + 0x505], 0xF4
mov esi, eax
mov ebx, [eax+V86_machine.pagedir]
; one page for stack, two pages for results (0x2000 bytes = 16 sectors)
mov dword [ebx+0x99*4+0x1000], 0x99000 or 111b
mov dword [ebx+0x99*4+0x1800], OS_BASE + 0x99000
mov dword [ebx+0x9A*4+0x1000], 0x9A000 or 111b
mov dword [ebx+0x9A*4+0x1800], OS_BASE + 0x9A000
mov dword [ebx+0x9B*4+0x1000], 0x9B000 or 111b
mov dword [ebx+0x9B*4+0x1800], OS_BASE + 0x9B000
if ~DEBUG_SHOW_IO
; allow access to all ports
mov ecx, [esi+V86_machine.iopm]
@ -272,6 +254,9 @@ ends
; eax = 3 - IRQ is already hooked by another VM
; destroys: nothing
v86_start:
xchg bx, bx
pushad
cli
@ -296,12 +281,10 @@ v86_start:
mov [ecx+APPDATA.saved_esp0], esp
mov [tss._esp0], esp
mov eax, [esi+V86_machine.pagedir]
call get_pg_addr
mov eax, [esi+V86_machine.process]
mov [ecx+APPDATA.process], eax
; mov cr3, eax
; mov [irq_tab+5*4], my05
mov eax, [eax+PROC.pdt_0_phys]
mov cr3, eax
; We do not enable interrupts, because V86 IRQ redirector assumes that
; machine is running
@ -795,6 +778,7 @@ end if
pop ebx
mov dword [SLOT_BASE+ecx+APPDATA.io_map], ebx
mov dword [page_tabs + (tss._io_map_0 shr 10)], ebx
mov eax, [eax+PROC.pdt_0_phys]
mov cr3, eax
sti
@ -843,8 +827,7 @@ v86_irq:
pop eax
v86_irq2:
mov esi, [v86_irqhooks+edi*8] ; get VM handle
mov eax, [esi+V86_machine.pagedir]
call get_pg_addr
mov eax, [esi+V86_machine.process]
mov ecx, [CURRENT_TASK]
shl ecx, 8
cmp [SLOT_BASE+ecx+APPDATA.process], eax
@ -895,6 +878,7 @@ v86_irq2:
popad
iretd
.found:
mov eax, [eax+PROC.pdt_0_phys]
mov cr3, eax
mov esi, [ebx+APPDATA.saved_esp0]
sub word [esi-sizeof.v86_regs+v86_regs.esp], 6

View File

@ -0,0 +1,459 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2014. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision: 4850 $
;-----------------------------------------------------------------------------
; find the IDE controller in the device list
;-----------------------------------------------------------------------------
mov ecx, IDE_controller_1
mov esi, pcidev_list
;--------------------------------------
align 4
.loop:
mov esi, [esi+PCIDEV.fd]
cmp esi, pcidev_list
jz find_IDE_controller_done
mov eax, [esi+PCIDEV.class]
shr eax, 4
cmp eax, 0x01018
jnz .loop
;--------------------------------------
.found:
mov eax, [esi+PCIDEV.class]
DEBUGF 1, 'K : IDE controller programming interface %x\n', eax
mov [ecx+IDE_DATA.ProgrammingInterface], eax
mov ah, [esi+PCIDEV.bus]
mov al, 2
mov bh, [esi+PCIDEV.devfn]
;--------------------------------------
mov dx, 0x1F0
test byte [esi+PCIDEV.class], 1
jz @f
mov bl, 0x10
push eax
call pci_read_reg
and eax, 0xFFFC
mov edx, eax
pop eax
@@:
DEBUGF 1, 'K : BAR0 IDE base addr %x\n', dx
mov [StandardATABases], dx
mov [ecx+IDE_DATA.BAR0_val], dx
;--------------------------------------
mov dx, 0x3F4
test byte [esi+PCIDEV.class], 1
jz @f
mov bl, 0x14
push eax
call pci_read_reg
and eax, 0xFFFC
mov edx, eax
pop eax
@@:
DEBUGF 1, 'K : BAR1 IDE base addr %x\n', dx
mov [ecx+IDE_DATA.BAR1_val], dx
;--------------------------------------
mov dx, 0x170
test byte [esi+PCIDEV.class], 4
jz @f
mov bl, 0x18
push eax
call pci_read_reg
and eax, 0xFFFC
mov edx, eax
pop eax
@@:
DEBUGF 1, 'K : BAR2 IDE base addr %x\n', dx
mov [StandardATABases+2], dx
mov [ecx+IDE_DATA.BAR2_val], dx
;--------------------------------------
mov dx, 0x374
test byte [esi+PCIDEV.class], 4
jz @f
mov bl, 0x1C
push eax
call pci_read_reg
and eax, 0xFFFC
mov edx, eax
pop eax
@@:
DEBUGF 1, 'K : BAR3 IDE base addr %x\n', dx
mov [ecx+IDE_DATA.BAR3_val], dx
;--------------------------------------
mov bl, 0x20
push eax
call pci_read_reg
and eax, 0xFFFC
DEBUGF 1, 'K : BAR4 IDE controller register base addr %x\n', ax
mov [ecx+IDE_DATA.RegsBaseAddres], ax
pop eax
;--------------------------------------
mov bl, 0x3C
push eax
call pci_read_reg
and eax, 0xFF
DEBUGF 1, 'K : IDE Interrupt %x\n', al
mov [ecx+IDE_DATA.Interrupt], ax
pop eax
add ecx, sizeof.IDE_DATA
;--------------------------------------
jmp .loop
;-----------------------------------------------------------------------------
uglobal
align 4
;--------------------------------------
IDE_controller_pointer dd ?
;--------------------------------------
IDE_controller_1 IDE_DATA
IDE_controller_2 IDE_DATA
IDE_controller_3 IDE_DATA
;--------------------------------------
cache_ide0 IDE_CACHE
cache_ide1 IDE_CACHE
cache_ide2 IDE_CACHE
cache_ide3 IDE_CACHE
cache_ide4 IDE_CACHE
cache_ide5 IDE_CACHE
cache_ide6 IDE_CACHE
cache_ide7 IDE_CACHE
cache_ide8 IDE_CACHE
cache_ide9 IDE_CACHE
cache_ide10 IDE_CACHE
cache_ide11 IDE_CACHE
;--------------------------------------
IDE_device_1 rd 2
IDE_device_2 rd 2
IDE_device_3 rd 2
;--------------------------------------
endg
;-----------------------------------------------------------------------------
; START of initialisation IDE ATA code
;-----------------------------------------------------------------------------
Init_IDE_ATA_controller:
cmp [ecx+IDE_DATA.ProgrammingInterface], 0
jne @f
ret
;--------------------------------------
@@:
mov esi, boot_disabling_ide
call boot_log
;--------------------------------------
; Disable IDE interrupts, because the search
; for IDE partitions is in the PIO mode.
;--------------------------------------
.disable_IDE_interrupt:
; Disable interrupts in IDE controller for PIO
mov al, 2
mov dx, [ecx+IDE_DATA.BAR1_val] ;0x3F4
add dx, 2 ;0x3F6
out dx, al
mov dx, [ecx+IDE_DATA.BAR3_val] ;0x374
add dx, 2 ;0x376
out dx, al
;-----------------------------------------------------------------------------
; set current ata bases
@@:
mov ax, [ecx+IDE_DATA.BAR0_val]
mov [StandardATABases], ax
mov ax, [ecx+IDE_DATA.BAR2_val]
mov [StandardATABases+2], ax
mov esi, boot_detecthdcd
call boot_log
;--------------------------------------
include 'dev_hdcd.inc'
;--------------------------------------
ret
;-----------------------------------------------------------------------------
Init_IDE_ATA_controller_2:
cmp [ecx+IDE_DATA.ProgrammingInterface], 0
jne @f
ret
;--------------------------------------
@@:
mov dx, [ecx+IDE_DATA.RegsBaseAddres]
; test whether it is our interrupt?
add dx, 2
in al, dx
test al, 100b
jz @f
; clear Bus Master IDE Status register
; clear Interrupt bit
out dx, al
;--------------------------------------
@@:
add dx, 8
; test whether it is our interrupt?
in al, dx
test al, 100b
jz @f
; clear Bus Master IDE Status register
; clear Interrupt bit
out dx, al
;--------------------------------------
@@:
; read status register and remove the interrupt request
mov dx, [ecx+IDE_DATA.BAR0_val] ;0x1F0
add dx, 0x7 ;0x1F7
in al, dx
mov dx, [ecx+IDE_DATA.BAR2_val] ;0x170
add dx, 0x7 ;0x177
in al, dx
;-----------------------------------------------------------------------------
; push eax edx
; mov dx, [ecx+IDE_DATA.RegsBaseAddres]
; xor eax, eax
; add dx, 2
; in al, dx
; DEBUGF 1, "K : Primary Bus Master IDE Status Register %x\n", eax
; add dx, 8
; in al, dx
; DEBUGF 1, "K : Secondary Bus Master IDE Status Register %x\n", eax
; pop edx eax
; cmp [ecx+IDE_DATA.RegsBaseAddres], 0
; setnz [ecx+IDE_DATA.dma_hdd]
;-----------------------------------------------------------------------------
; set interrupts for IDE Controller
;-----------------------------------------------------------------------------
pushfd
cli
.enable_IDE_interrupt:
mov esi, boot_enabling_ide
call boot_log
; Enable interrupts in IDE controller for DMA
xor ebx, ebx
cmp ecx, IDE_controller_2
jne @f
add ebx, 5
jmp .check_DRIVE_DATA
;--------------------------------------
@@:
cmp ecx, IDE_controller_3
jne .check_DRIVE_DATA
add ebx, 10
;--------------------------------------
.check_DRIVE_DATA:
mov al, 0
mov ah, [ebx+DRIVE_DATA+1]
test ah, 10100000b ; check for ATAPI devices
jz @f
;--------------------------------------
.ch1_pio_set_ATAPI:
DEBUGF 1, "K : IDE CH1 PIO, because ATAPI drive present\n"
jmp .ch1_pio_set_for_all
;--------------------------------------
.ch1_pio_set_no_devices:
DEBUGF 1, "K : IDE CH1 PIO because no devices\n"
jmp .ch1_pio_set_for_all
;-------------------------------------
.ch1_pio_set:
DEBUGF 1, "K : IDE CH1 PIO because device not support UDMA\n"
;-------------------------------------
.ch1_pio_set_for_all:
mov [ecx+IDE_DATA.dma_hdd_channel_1], al
jmp .ch2_check
;--------------------------------------
@@:
xor ebx, ebx
call calculate_IDE_device_values_storage
test ah, 1010000b
jz .ch1_pio_set_no_devices
test ah, 1000000b
jz @f
cmp [ebx+IDE_DEVICE.UDMA_possible_modes], al
je .ch1_pio_set
cmp [ebx+IDE_DEVICE.UDMA_set_mode], al
je .ch1_pio_set
;--------------------------------------
@@:
test ah, 10000b
jz @f
add ebx, 2
cmp [ebx+IDE_DEVICE.UDMA_possible_modes], al
je .ch1_pio_set
cmp [ebx+IDE_DEVICE.UDMA_set_mode], al
je .ch1_pio_set
;--------------------------------------
@@:
mov dx, [ecx+IDE_DATA.BAR1_val] ;0x3F4
add dx, 2 ;0x3F6
out dx, al
DEBUGF 1, "K : IDE CH1 DMA enabled\n"
mov [ecx+IDE_DATA.dma_hdd_channel_1], byte 1
;--------------------------------------
.ch2_check:
test ah, 1010b ; check for ATAPI devices
jz @f
;--------------------------------------
.ch2_pio_set_ATAPI:
DEBUGF 1, "K : IDE CH2 PIO, because ATAPI drive present\n"
jmp .ch2_pio_set_for_all
;--------------------------------------
.ch2_pio_set_no_devices:
DEBUGF 1, "K : IDE CH2 PIO because no devices\n"
jmp .ch2_pio_set_for_all
;--------------------------------------
.ch2_pio_set:
DEBUGF 1, "K : IDE CH2 PIO because device not support UDMA\n"
;--------------------------------------
.ch2_pio_set_for_all:
mov [ecx+IDE_DATA.dma_hdd_channel_2], al
jmp .set_interrupts_for_IDE_controllers
;--------------------------------------
@@:
mov ebx, 4
call calculate_IDE_device_values_storage
test ah, 101b
jz .ch2_pio_set_no_devices
test ah, 100b
jz @f
cmp [ebx+IDE_DEVICE.UDMA_possible_modes], al
je .ch2_pio_set
cmp [ebx+IDE_DEVICE.UDMA_set_mode], al
je .ch2_pio_set
;--------------------------------------
@@:
test ah, 1b
jz @f
add ebx, 2
cmp [ebx+IDE_DEVICE.UDMA_possible_modes], al
je .ch2_pio_set
cmp [ebx+IDE_DEVICE.UDMA_set_mode], al
je .ch2_pio_set
;--------------------------------------
@@:
mov dx, [ecx+IDE_DATA.BAR3_val] ;0x374
add dx, 2 ;0x376
out dx, al
DEBUGF 1, "K : IDE CH2 DMA enabled\n"
mov [ecx+IDE_DATA.dma_hdd_channel_2], byte 1
;--------------------------------------
.set_interrupts_for_IDE_controllers:
mov esi, boot_set_int_IDE
call boot_log
;--------------------------------------
mov eax, [ecx+IDE_DATA.ProgrammingInterface]
cmp ax, 0x0180
je .pata_ide
cmp ax, 0x018a
jne .sata_ide
;--------------------------------------
.pata_ide:
cmp [ecx+IDE_DATA.RegsBaseAddres], 0
je .end_set_interrupts
push ecx
stdcall attach_int_handler, 14, IDE_irq_14_handler, 0
DEBUGF 1, "K : Set IDE IRQ14 return code %x\n", eax
stdcall attach_int_handler, 15, IDE_irq_15_handler, 0
DEBUGF 1, "K : Set IDE IRQ15 return code %x\n", eax
pop ecx
jmp .end_set_interrupts
;--------------------------------------
.sata_ide:
cmp ax, 0x0185
je .sata_ide_1
cmp ax, 0x018f
jne .end_set_interrupts
;--------------------------------------
.sata_ide_1:
; Some weird controllers generate an interrupt even if IDE interrupts
; are disabled and no IDE devices. For example, notebook ASUS K72F -
; IDE controller 010185 generates false interrupt when we work with
; the IDE controller 01018f. For this reason, the interrupt handler
; does not need to be installed if both channel IDE controller
; running in PIO mode.
cmp [ecx+IDE_DATA.RegsBaseAddres], 0
je .end_set_interrupts
cmp [ecx+IDE_DATA.dma_hdd_channel_1], 0
jne @f
cmp [ecx+IDE_DATA.dma_hdd_channel_2], 0
je .end_set_interrupts
;--------------------------------------
@@:
mov ax, [ecx+IDE_DATA.Interrupt]
movzx eax, al
push ecx
stdcall attach_int_handler, eax, IDE_common_irq_handler, 0
pop ecx
DEBUGF 1, "K : Set IDE IRQ%d return code %x\n", [ecx+IDE_DATA.Interrupt]:1, eax
;--------------------------------------
.end_set_interrupts:
popfd
ret
;-----------------------------------------------------------------------------
; END of initialisation IDE ATA code
;-----------------------------------------------------------------------------
find_IDE_controller_done:
mov ecx, IDE_controller_1
mov [IDE_controller_pointer], ecx
call Init_IDE_ATA_controller
mov ecx, IDE_controller_2
mov [IDE_controller_pointer], ecx
call Init_IDE_ATA_controller
mov ecx, IDE_controller_3
mov [IDE_controller_pointer], ecx
call Init_IDE_ATA_controller
;-----------------------------------------------------------------------------
mov esi, boot_getcache
call boot_log
include 'getcache.inc'
;-----------------------------------------------------------------------------
mov esi, boot_detectpart
call boot_log
include 'sear_par.inc'
;-----------------------------------------------------------------------------
mov esi, boot_init_sys
call boot_log
call Parser_params
if ~ defined extended_primary_loader
; ramdisk image should be loaded by extended primary loader if it exists
; READ RAMDISK IMAGE FROM HD
include '../boot/rdload.inc'
end if
;-----------------------------------------------------------------------------
mov ecx, IDE_controller_1
mov [IDE_controller_pointer], ecx
call Init_IDE_ATA_controller_2
mov ecx, IDE_controller_2
mov [IDE_controller_pointer], ecx
call Init_IDE_ATA_controller_2
mov ecx, IDE_controller_3
mov [IDE_controller_pointer], ecx
call Init_IDE_ATA_controller_2
;-----------------------------------------------------------------------------

View File

@ -39,6 +39,7 @@ syscall_button: ;///// system function 8 //////////////////////////////////////
;> 7 (31) = 0
;> 6 (30) = don't draw button
;> 5 (29) = don't draw button frame when pressed
;> 4 (28) = don't draw button 3d frame
;> esi = button color
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Undefine button:
@ -86,9 +87,11 @@ syscall_button: ;///// system function 8 //////////////////////////////////////
mov ax, dx
stosw ; button id number: bits 0-15
mov eax, ebx
dec eax
rol eax, 16
stosd ; x start | x size
mov eax, ecx
dec eax
rol eax, 16
stosd ; y start | y size
mov eax, edx
@ -100,114 +103,116 @@ syscall_button: ;///// system function 8 //////////////////////////////////////
test edx, 0x40000000
jnz .exit
; draw button body
; DRAW BODY -----------------------------
pushad
; calculate window-relative coordinates
movzx edi, cx
shr ebx, 16
shr ecx, 16
mov eax, [TASK_BASE]
add ebx, [eax - twdw + WDATA.box.left]
add ecx, [eax - twdw + WDATA.box.top]
mov eax, ebx
shl eax, 16
mov ax, bx
add ax, word[esp + 16]
mov ebx, ecx
shl ebx, 16
mov bx, cx
; calculate initial color
call button._.button_calc_relativ
xor edi, edi ; for __sys_draw_line
; set color
mov ecx, esi
; set coordinate
inc edx
; if gradient
cmp [buttontype], 0
je @f
call button._.incecx2
; set button height counter
@@:
mov edx, edi
.next_line:
je .next_line
call button._.incecx
align 4
.next_line:
call button._.button_dececx
push edi
xor edi, edi
; call [draw_line]
call __sys_draw_line
pop edi
add ebx, 0x00010001
dec edx
jnz .next_line
popad
; draw button frame
; DRAW FRAME ----------------------------
pushad
call button._.button_calc_relativ
mov esi, common_colours
push ebx ecx
mov edi, dword [esi+104]
call .top_border
mov edi, dword [esi+104]
call .bottom_border
mov edi, dword [esi+104]
call .right_border
mov edi, dword [esi+104]
call .left_border
popad
; calculate window-relative coordinates
shr ebx, 16
shr ecx, 16
mov eax, [TASK_BASE]
add ebx, [eax - twdw + WDATA.box.left]
add ecx, [eax - twdw + WDATA.box.top]
; DRAW 3D SHADOW ------------------------
test edx, 0x10000000
jnz .exit
; top border
mov eax, ebx
shl eax, 16
mov ax, bx
add ax, [esp + 4]
pushad
mov edi, edx
call button._.button_calc_relativ
; get color address
mov esi, common_colours
test edi, 0x10000000
jnz @f
add eax, 0x10000
dec eax
inc ecx
dec edx
dec edx
align 4
@@:
mov edi, dword [esi+12]
call .top_border
mov edi, dword [esi+8]
call .bottom_border
mov edi, dword [esi+8]
call .right_border
mov edi, dword [esi+12]
call .left_border
popad
ret
align 4
.top_border:
mov ebx, ecx
shl ebx, 16
mov bx, cx
push ebx
mov bx , cx
mov ecx, edi
xor edi, edi
mov ecx, esi
call button._.incecx
; call [draw_line]
call __sys_draw_line
ret
; bottom border
movzx edx, word[esp + 4 + 0]
add ebx, edx
shl edx, 16
add ebx, edx
mov ecx, esi
call button._.dececx
; call [draw_line]
align 4
.bottom_border:
add bx , dx
rol ebx, 16
add bx , dx
mov ecx, edi
xor edi, edi
call __sys_draw_line
ret
; left border
pop ebx
push edx
mov edx, eax
shr edx, 16
mov ax, dx
mov edx, ebx
shr edx, 16
mov bx, dx
add bx, [esp + 4 + 0]
pop edx
mov ecx, esi
call button._.incecx
; call [draw_line]
align 4
.right_border:
push eax
sub bx, dx
mov cx, ax
shl eax, 16
mov ax, cx
mov ecx, edi
xor edi, edi
call __sys_draw_line
pop eax
ret
; right border
mov dx, [esp + 4]
add ax, dx
shl edx, 16
add eax, edx
add ebx, 0x00010000
mov ecx, esi
call button._.dececx
; call [draw_line]
align 4
.left_border:
shr eax, 16
mov cx, ax
shl eax, 16
mov ax, cx
mov ecx, edi
xor edi, edi
call __sys_draw_line
pop ecx ebx
.exit:
ret
align 4
.exit:
ret
; FIXME: mutex needed
@ -269,8 +274,10 @@ sys_button_activate_handler: ;/////////////////////////////////////////////////
jz .exit
mov ebx, dword[eax + SYS_BUTTON.id_hi - 2]
push edi ; spam
xor edi, edi
call button._.negative_button
pop edi
.exit:
ret
@ -289,8 +296,11 @@ sys_button_deactivate_handler: ;///////////////////////////////////////////////
jz .exit
mov ebx, dword[eax + SYS_BUTTON.id_hi - 2]
push edi ; spam
xor edi, edi
inc edi
call button._.negative_button
pop edi
.exit:
ret
@ -373,69 +383,6 @@ button._.find_button: ;////////////////////////////////////////////////////////
pop edi esi edx ecx
ret
;------------------------------------------------------------------------------
button._.dececx: ;/////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
sub cl, 0x20
jnc @f
xor cl, cl
@@:
sub ch, 0x20
jnc @f
xor ch, ch
@@:
rol ecx, 16
sub cl, 0x20
jnc @f
xor cl, cl
@@:
rol ecx, 16
ret
;------------------------------------------------------------------------------
button._.incecx: ;/////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
add cl, 0x20
jnc @f
or cl, -1
@@:
add ch, 0x20
jnc @f
or ch, -1
@@:
rol ecx, 16
add cl, 0x20
jnc @f
or cl, -1
@@:
rol ecx, 16
ret
;------------------------------------------------------------------------------
button._.incecx2: ;////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
add cl, 0x14
jnc @f
or cl, -1
@@:
add ch, 0x14
jnc @f
or ch, -1
@@:
rol ecx, 16
add cl, 0x14
jnc @f
or cl, -1
@@:
rol ecx, 16
ret
;------------------------------------------------------------------------------
button._.button_dececx: ;//////////////////////////////////////////////////////
;------------------------------------------------------------------------------
@ -446,9 +393,9 @@ button._.button_dececx: ;//////////////////////////////////////////////////////
push eax
mov al, 1
cmp edi, 20
jg @f
mov al, 2
;cmp edi, 20
;jg @f
;mov al, 2
@@:
sub cl, al
@ -470,18 +417,60 @@ button._.button_dececx: ;//////////////////////////////////////////////////////
.finish:
ret
;------------------------------------------------------------------------------
button._.incecx: ;////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
add cl, 0x14
jnc @f
or cl, -1
@@:
add ch, 0x14
jnc @f
or ch, -1
@@:
rol ecx, 16
add cl, 0x14
jnc @f
or cl, -1
@@:
rol ecx, 16
ret
;------------------------------------------------------------------------------
button._.button_calc_relativ: ;
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
movzx edx, cx
dec edx ; get height
shr ebx, 16
shr ecx, 16
mov eax, [TASK_BASE]
add ebx, [eax - twdw + WDATA.box.left]
add ecx, [eax - twdw + WDATA.box.top]
mov eax, ebx
shl eax, 16
mov ax, bx
add ax, word[esp + 20]
dec eax
mov bx, cx
shl ebx, 16
mov bx, cx
ret
;------------------------------------------------------------------------------
button._.negative_button: ;////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Invert system button border
; edi - 0 activate, 1 - deactivate
;------------------------------------------------------------------------------
; if requested, do not display button border on press.
test ebx, 0x20000000
jnz .exit
pushad
push ebx
xchg esi, eax
movzx ecx, [esi + SYS_BUTTON.pslot]
@ -499,10 +488,58 @@ button._.negative_button: ;////////////////////////////////////////////////////
add ax, cx
add bx, dx
xor edx, edx
mov dx, [esi + SYS_BUTTON.id_lo]
cmp dx, 1
jne .no_close
sub eax, 0x00010001
dec ebx
mov esi, 0x01000000
call draw_rectangle.forced
jmp .fade
align 4
.no_close:
cmp dx, 65535
jne .no_mini
sub eax, 0x00010001
dec ebx
mov esi, 0x01000000
call draw_rectangle.forced
jmp .fade
align 4
.no_mini:
add eax, 0x00010000
add ebx, 0x00010000
pop edx
test edx, 0x10000000
jnz .only_frame
mov edx, common_colours
mov esi, dword [edx+12]
cmp edi, 0
jne .shadow
mov esi, dword [edx+8]
align 4
.shadow:
call draw_rectangle.forced
align 4
.only_frame:
mov edx, common_colours
sub eax, 0x00010000
sub ebx, 0x00010000
mov esi, dword [edx+104]
cmp edi, 0
jne .draw
mov esi, dword [edx+112]
align 4
.draw:
call draw_rectangle.forced
popad
.exit:
ret
align 4
.fade:
pop ebx
popad
align 4
.exit:
ret

View File

@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2014. All rights reserved. ;;
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;;
;; Distributed under terms of the GNU General Public License ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -457,19 +457,40 @@ send_scancode:
test bl, bl
jz .exit.irq1
cmp cl, 0xE0 ; extended keycode
jne @f
cmp ch, 53
jne .dowrite
mov bl, '/'
jmp .dowrite
@@:
cmp ch, 55
jne @f
mov bl, '*'
jmp .dowrite
@@:
cmp ch, 74
jne @f
mov bl, '-'
jmp .dowrite
@@:
cmp ch, 78
jne @f
mov bl, '+'
jmp .dowrite
@@:
test [kb_state], VKEY_NUMLOCK
jz .dowrite
cmp cl, 0xE0
jz .dowrite
cmp ch, 55
jnz @f
mov bl, 0x2A ;*
jmp .dowrite
;--------------------------------------
@@:
cmp ch, 71
jb .dowrite

View File

@ -685,7 +685,8 @@ no_mode_0x12:
xchg bx, bx
call v86_init
; call v86_init
call init_sys_v86
mov esi, boot_inittimer
call boot_log
@ -1008,7 +1009,6 @@ endg
; Load PS/2 mouse driver
stdcall load_driver, szPS2MDriver
; stdcall load_driver, szCOM_MDriver
mov esi, boot_setmouse
call boot_log

View File

@ -267,10 +267,9 @@ IPv4_input: ; TODO: add IPv4
cmp eax, 224
je .ip_ok
; or a loopback address (127.0.0.0/8)
; maybe we just dont have an IP yet and should accept everything on the IP level
and eax, 0x00ffffff
cmp eax, 127
cmp [IP_LIST + edi], 0
je .ip_ok
; or it's just not meant for us.. :(

View File

@ -110,7 +110,7 @@ SS_MORETOCOME = 0x4000
SS_BLOCKED = 0x8000
SOCKET_MAXDATA = 4096*8 ; must be 4096*(power of 2) where 'power of 2' is at least 8
SOCKET_MAXDATA = 4096*64 ; must be 4096*(power of 2) where 'power of 2' is at least 8
MAX_backlog = 20 ; maximum backlog for stream sockets
; Error Codes