commit
						924c061d64
					
				@ -1 +1 @@
 | 
				
			||||
Subproject commit 48dffe3f9aa6404a1bfe53de6645b53401d7499e
 | 
				
			||||
Subproject commit 50d2008d7579e24fc4f29889b73831acdd9aa830
 | 
				
			||||
@ -1 +0,0 @@
 | 
				
			||||
PS1="\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[1;35m\]<$IMAGE_NAME>\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ "
 | 
				
			||||
@ -1,40 +0,0 @@
 | 
				
			||||
FROM rustlang/rust:nightly
 | 
				
			||||
 | 
				
			||||
ENV IMAGE_NAME=blog_os-docker
 | 
				
			||||
 | 
				
			||||
RUN apt-get update && \
 | 
				
			||||
    apt-get install -q -y --no-install-recommends \
 | 
				
			||||
    nasm \
 | 
				
			||||
    binutils \
 | 
				
			||||
    grub-common \
 | 
				
			||||
    xorriso \
 | 
				
			||||
    grub-pc-bin && \
 | 
				
			||||
    apt-get autoremove -q -y && \
 | 
				
			||||
    apt-get clean -q -y && \
 | 
				
			||||
    rm -rf /var/lib/apt/lists/* && \
 | 
				
			||||
    cargo install xargo && \
 | 
				
			||||
    rustup component add rust-src
 | 
				
			||||
 | 
				
			||||
ENV GOSU_VERSION 1.10
 | 
				
			||||
 | 
				
			||||
RUN set -ex; \
 | 
				
			||||
	\
 | 
				
			||||
	fetchDeps=' \
 | 
				
			||||
		ca-certificates \
 | 
				
			||||
		wget \
 | 
				
			||||
	'; \
 | 
				
			||||
	apt-get update; \
 | 
				
			||||
	apt-get install -y --no-install-recommends $fetchDeps; \
 | 
				
			||||
	rm -rf /var/lib/apt/lists/*; \
 | 
				
			||||
	\
 | 
				
			||||
	dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
 | 
				
			||||
	wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \
 | 
				
			||||
	chmod +x /usr/local/bin/gosu; \
 | 
				
			||||
# verify that the binary works
 | 
				
			||||
	gosu nobody true; 
 | 
				
			||||
 | 
				
			||||
COPY entrypoint.sh /usr/local/bin/
 | 
				
			||||
COPY .bash_aliases /etc/skel/
 | 
				
			||||
 | 
				
			||||
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
 | 
				
			||||
CMD ["/bin/bash"]
 | 
				
			||||
@ -1,18 +0,0 @@
 | 
				
			||||
# Building Blog OS using Docker
 | 
				
			||||
Inspired by [redox].
 | 
				
			||||
You just need `git`, `make`, and `docker`.
 | 
				
			||||
It is beter to use a non-privileged user to run the `docker` command, which is usually achieved by adding the user to the `docker` group.
 | 
				
			||||
 | 
				
			||||
## Run the container to build Blog OS
 | 
				
			||||
You can build the docker image using `make docker_build` and run it using `make docker_run`.
 | 
				
			||||
 | 
				
			||||
## Run the container interactively
 | 
				
			||||
You can use the `make` target `docker_interactive` to get a shell in the container.
 | 
				
			||||
 | 
				
			||||
## Clear the toolchain caches (Cargo & Rustup)
 | 
				
			||||
To clean the docker volumes used by the toolchain, you just need to run `make docker_clean`.
 | 
				
			||||
 | 
				
			||||
[redox]: https://github.com/redox-os/redox
 | 
				
			||||
 | 
				
			||||
## License
 | 
				
			||||
The source code is dual-licensed under MIT or the Apache License (Version 2.0). This excludes the `blog` directory.
 | 
				
			||||
@ -1,19 +0,0 @@
 | 
				
			||||
#!/bin/sh
 | 
				
			||||
USER_NAME=blogos
 | 
				
			||||
USER_UID=${LOCAL_UID:-9001}
 | 
				
			||||
USER_GID=${LOCAL_GID:-9001}
 | 
				
			||||
 | 
				
			||||
groupadd --non-unique --gid $USER_GID $USER_NAME
 | 
				
			||||
useradd --non-unique --create-home --uid $USER_UID --gid $USER_GID $USER_NAME
 | 
				
			||||
 | 
				
			||||
export HOME=/home/$USER_NAME
 | 
				
			||||
 | 
				
			||||
TESTFILE=$RUSTUP_HOME/settings.toml
 | 
				
			||||
CACHED_UID=$(stat -c "%u" $TESTFILE)
 | 
				
			||||
CACHED_GID=$(stat -c "%g" $TESTFILE)
 | 
				
			||||
 | 
				
			||||
if [ $CACHED_UID != $USER_UID  ] || [ $USER_GID != $CACHED_GID  ]; then
 | 
				
			||||
    chown $USER_UID:$USER_GID -R $CARGO_HOME $RUSTUP_HOME
 | 
				
			||||
fi
 | 
				
			||||
 | 
				
			||||
exec gosu $USER_NAME "$@"
 | 
				
			||||
@ -1,173 +0,0 @@
 | 
				
			||||
global start
 | 
				
			||||
global stack_bottom
 | 
				
			||||
global stack_top
 | 
				
			||||
extern long_mode_start
 | 
				
			||||
 | 
				
			||||
section .text
 | 
				
			||||
bits 32
 | 
				
			||||
start:
 | 
				
			||||
    mov esp, stack_top
 | 
				
			||||
    push ebx    ; push Multiboot info pointer to stack_top
 | 
				
			||||
 | 
				
			||||
    call check_multiboot
 | 
				
			||||
    call check_cpuid
 | 
				
			||||
    call check_long_mode
 | 
				
			||||
 | 
				
			||||
    call set_up_page_tables
 | 
				
			||||
    call enable_paging
 | 
				
			||||
 | 
				
			||||
    ; load the 64-bit GDT
 | 
				
			||||
    lgdt [gdt64.pointer]
 | 
				
			||||
 | 
				
			||||
    jmp gdt64.code:long_mode_start
 | 
				
			||||
 | 
				
			||||
    ; print `OK` to screen
 | 
				
			||||
    mov dword [0xb8000], 0x2f4b2f4f
 | 
				
			||||
    hlt
 | 
				
			||||
 | 
				
			||||
check_multiboot:
 | 
				
			||||
    cmp eax, 0x36d76289
 | 
				
			||||
    jne .no_multiboot
 | 
				
			||||
    ret
 | 
				
			||||
.no_multiboot:
 | 
				
			||||
    mov al, "0"
 | 
				
			||||
    jmp error
 | 
				
			||||
 | 
				
			||||
check_cpuid:
 | 
				
			||||
    ; Check if CPUID is supported by attempting to flip the ID bit (bit 21)
 | 
				
			||||
    ; in the FLAGS register. If we can flip it, CPUID is available.
 | 
				
			||||
 | 
				
			||||
    ; Copy FLAGS in to EAX via stack
 | 
				
			||||
    pushfd
 | 
				
			||||
    pop eax
 | 
				
			||||
 | 
				
			||||
    ; Copy to ECX as well for comparing later on
 | 
				
			||||
    mov ecx, eax
 | 
				
			||||
 | 
				
			||||
    ; Flip the ID bit
 | 
				
			||||
    xor eax, 1 << 21
 | 
				
			||||
 | 
				
			||||
    ; Copy EAX to FLAGS via the stack
 | 
				
			||||
    push eax
 | 
				
			||||
    popfd
 | 
				
			||||
 | 
				
			||||
    ; Copy FLAGS back to EAX (with the flipped bit if CPUID is supported)
 | 
				
			||||
    pushfd
 | 
				
			||||
    pop eax
 | 
				
			||||
 | 
				
			||||
    ; Restore FLAGS from the old version stored in ECX (i.e. flipping the
 | 
				
			||||
    ; ID bit back if it was ever flipped).
 | 
				
			||||
    push ecx
 | 
				
			||||
    popfd
 | 
				
			||||
 | 
				
			||||
    ; Compare EAX and ECX. If they are equal then that means the bit
 | 
				
			||||
    ; wasn't flipped, and CPUID isn't supported.
 | 
				
			||||
    cmp eax, ecx
 | 
				
			||||
    je .no_cpuid
 | 
				
			||||
    ret
 | 
				
			||||
.no_cpuid:
 | 
				
			||||
    mov al, "1"
 | 
				
			||||
    jmp error
 | 
				
			||||
 | 
				
			||||
check_long_mode:
 | 
				
			||||
    ; test if extended processor info in available
 | 
				
			||||
    mov eax, 0x80000000    ; implicit argument for cpuid
 | 
				
			||||
    cpuid                  ; get highest supported argument
 | 
				
			||||
    cmp eax, 0x80000001    ; it needs to be at least 0x80000001
 | 
				
			||||
    jb .no_long_mode       ; if it's less, the CPU is too old for long mode
 | 
				
			||||
 | 
				
			||||
    ; use extended info to test if long mode is available
 | 
				
			||||
    mov eax, 0x80000001    ; argument for extended processor info
 | 
				
			||||
    cpuid                  ; returns various feature bits in ecx and edx
 | 
				
			||||
    test edx, 1 << 29      ; test if the LM-bit is set in the D-register
 | 
				
			||||
    jz .no_long_mode       ; If it's not set, there is no long mode
 | 
				
			||||
    ret
 | 
				
			||||
.no_long_mode:
 | 
				
			||||
    mov al, "2"
 | 
				
			||||
    jmp error
 | 
				
			||||
 | 
				
			||||
set_up_page_tables:
 | 
				
			||||
    ; map P4 table recursively
 | 
				
			||||
    mov eax, p4_table
 | 
				
			||||
    or eax, 0b11 ; present + writable
 | 
				
			||||
    mov [p4_table + 511 * 8], eax
 | 
				
			||||
 | 
				
			||||
    ; map first & 510th P4 entry to P3 table
 | 
				
			||||
    mov eax, p3_table
 | 
				
			||||
    or eax, 0b11 ; present + writable
 | 
				
			||||
    mov [p4_table], eax
 | 
				
			||||
    mov [p4_table + 510 * 8], eax
 | 
				
			||||
 | 
				
			||||
    ; map first P3 entry to P2 table
 | 
				
			||||
    mov eax, p2_table
 | 
				
			||||
    or eax, 0b11 ; present + writable
 | 
				
			||||
    mov [p3_table], eax
 | 
				
			||||
 | 
				
			||||
    ; map each P2 entry to a huge 2MiB page
 | 
				
			||||
    mov ecx, 0         ; counter variable
 | 
				
			||||
 | 
				
			||||
.map_p2_table:
 | 
				
			||||
    ; map ecx-th P2 entry to a huge page that starts at address 2MiB*ecx
 | 
				
			||||
    mov eax, 0x200000  ; 2MiB
 | 
				
			||||
    mul ecx            ; start address of ecx-th page
 | 
				
			||||
    or eax, 0b10000011 ; present + writable + huge
 | 
				
			||||
    mov [p2_table + ecx * 8], eax ; map ecx-th entry
 | 
				
			||||
 | 
				
			||||
    inc ecx            ; increase counter
 | 
				
			||||
    cmp ecx, 512       ; if counter == 512, the whole P2 table is mapped
 | 
				
			||||
    jne .map_p2_table  ; else map the next entry
 | 
				
			||||
 | 
				
			||||
    ret
 | 
				
			||||
 | 
				
			||||
enable_paging:
 | 
				
			||||
    ; load P4 to cr3 register (cpu uses this to access the P4 table)
 | 
				
			||||
    mov eax, p4_table
 | 
				
			||||
    mov cr3, eax
 | 
				
			||||
 | 
				
			||||
    ; enable PAE-flag in cr4 (Physical Address Extension)
 | 
				
			||||
    mov eax, cr4
 | 
				
			||||
    or eax, 1 << 5
 | 
				
			||||
    mov cr4, eax
 | 
				
			||||
 | 
				
			||||
    ; set the long mode bit & no execute bit in the EFER MSR (model specific register)
 | 
				
			||||
    mov ecx, 0xC0000080
 | 
				
			||||
    rdmsr
 | 
				
			||||
    or eax, 1 << 8 | 1 << 11
 | 
				
			||||
    wrmsr
 | 
				
			||||
 | 
				
			||||
    ; enable paging & write protect in the cr0 register
 | 
				
			||||
    mov eax, cr0
 | 
				
			||||
    or eax, 1 << 31 | 1 << 16
 | 
				
			||||
    mov cr0, eax
 | 
				
			||||
 | 
				
			||||
    ret
 | 
				
			||||
 | 
				
			||||
; Prints `ERR: ` and the given error code to screen and hangs.
 | 
				
			||||
; parameter: error code (in ascii) in al
 | 
				
			||||
error:
 | 
				
			||||
    mov dword [0xb8000], 0x4f524f45
 | 
				
			||||
    mov dword [0xb8004], 0x4f3a4f52
 | 
				
			||||
    mov dword [0xb8008], 0x4f204f20
 | 
				
			||||
    mov byte  [0xb800a], al
 | 
				
			||||
    hlt
 | 
				
			||||
 | 
				
			||||
section .bss
 | 
				
			||||
align 4096
 | 
				
			||||
p4_table:
 | 
				
			||||
    resb 4096
 | 
				
			||||
p3_table:
 | 
				
			||||
    resb 4096
 | 
				
			||||
p2_table:
 | 
				
			||||
    resb 4096
 | 
				
			||||
stack_bottom:
 | 
				
			||||
    resb 4096 * 8
 | 
				
			||||
stack_top:
 | 
				
			||||
 | 
				
			||||
section .rodata
 | 
				
			||||
gdt64:
 | 
				
			||||
    dq 0 ; zero entry
 | 
				
			||||
.code: equ $ - gdt64 ; new
 | 
				
			||||
    dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
 | 
				
			||||
.pointer:
 | 
				
			||||
    dw $ - gdt64 - 1
 | 
				
			||||
    dq gdt64
 | 
				
			||||
@ -1,141 +0,0 @@
 | 
				
			||||
; xv6 x86_64 entryother.S
 | 
				
			||||
 | 
				
			||||
; Each non-boot CPU ("AP") is started up in response to a STARTUP
 | 
				
			||||
; IPI from the boot CPU.  Section B.4.2 of the Multi-Processor
 | 
				
			||||
; Specification says that the AP will start in real mode with CS:IP
 | 
				
			||||
; set to XY00:0000, where XY is an 8-bit value sent with the
 | 
				
			||||
; STARTUP. Thus this code must start at a 4096-byte boundary.
 | 
				
			||||
;
 | 
				
			||||
; Because this code sets DS to zero, it must sit
 | 
				
			||||
; at an address in the low 2^16 bytes.
 | 
				
			||||
;
 | 
				
			||||
; Startothers (in main.c) sends the STARTUPs one at a time.
 | 
				
			||||
; It copies this code (start) at 0x7000.  It puts the address of
 | 
				
			||||
; a newly allocated per-core stack in start-4,the address of the
 | 
				
			||||
; place to jump to (mpenter) in start-8, and the physical address
 | 
				
			||||
; of entrypgdir in start-12.
 | 
				
			||||
;
 | 
				
			||||
; This code is identical to bootasm.S except:
 | 
				
			||||
;   - it does not need to enable A20
 | 
				
			||||
;   - it uses the address at start-4, start-8, and start-12
 | 
				
			||||
 | 
				
			||||
%define CR0_PE 1
 | 
				
			||||
%define STA_X       0x8     ; Executable segment
 | 
				
			||||
%define STA_E       0x4     ; Expand down (non-executable segments)
 | 
				
			||||
%define STA_C       0x4     ; Conforming code segment (executable only)
 | 
				
			||||
%define STA_W       0x2     ; Writeable (non-executable segments)
 | 
				
			||||
%define STA_R       0x2     ; Readable (executable segments)
 | 
				
			||||
%define STA_A       0x1     ; Accessed
 | 
				
			||||
 | 
				
			||||
extern other_main
 | 
				
			||||
 | 
				
			||||
section .text
 | 
				
			||||
bits 16
 | 
				
			||||
start:
 | 
				
			||||
    cli
 | 
				
			||||
 | 
				
			||||
    xor     ax, ax
 | 
				
			||||
    mov     ds, ax
 | 
				
			||||
    mov     es, ax
 | 
				
			||||
    mov     ss, ax
 | 
				
			||||
 | 
				
			||||
    lgdt    [gdt.desc]
 | 
				
			||||
    mov     eax, cr0
 | 
				
			||||
    or      eax, CR0_PE
 | 
				
			||||
    mov     cr0, eax
 | 
				
			||||
 | 
				
			||||
    jmp     gdt.code: start32
 | 
				
			||||
 | 
				
			||||
bits 32
 | 
				
			||||
start32:
 | 
				
			||||
    mov     ax, gdt.data
 | 
				
			||||
    mov     ds, ax
 | 
				
			||||
    mov     es, ax
 | 
				
			||||
    mov     ss, ax
 | 
				
			||||
    mov     ax, 0
 | 
				
			||||
    mov     fs, ax
 | 
				
			||||
    mov     gs, ax
 | 
				
			||||
 | 
				
			||||
    ; Switch to the stack allocated by startothers()
 | 
				
			||||
    mov     esp, [top - 4]
 | 
				
			||||
 | 
				
			||||
    call    enable_paging
 | 
				
			||||
 | 
				
			||||
    ; load the 64-bit GDT
 | 
				
			||||
    lgdt    [gdt64.pointer]
 | 
				
			||||
 | 
				
			||||
    jmp     gdt64.code: start64
 | 
				
			||||
 | 
				
			||||
error:
 | 
				
			||||
    mov     ax, 0x8a00
 | 
				
			||||
    mov     dx, ax
 | 
				
			||||
    out     dx, ax
 | 
				
			||||
    mov     ax, 0x8ae0
 | 
				
			||||
    out     dx, ax
 | 
				
			||||
spin:
 | 
				
			||||
    jmp     spin
 | 
				
			||||
 | 
				
			||||
enable_paging:
 | 
				
			||||
    ; load P4 to cr3 register (cpu uses this to access the P4 table)
 | 
				
			||||
    mov     eax, [top - 8]
 | 
				
			||||
    mov     cr3, eax
 | 
				
			||||
 | 
				
			||||
    ; enable PAE-flag in cr4 (Physical Address Extension)
 | 
				
			||||
    mov     eax, cr4
 | 
				
			||||
    or      eax, 1 << 5
 | 
				
			||||
    mov     cr4, eax
 | 
				
			||||
 | 
				
			||||
    ; set the long mode bit & no execute bit in the EFER MSR (model specific register)
 | 
				
			||||
    mov     ecx, 0xC0000080
 | 
				
			||||
    rdmsr
 | 
				
			||||
    or      eax, 1 << 8 | 1 << 11
 | 
				
			||||
    wrmsr
 | 
				
			||||
 | 
				
			||||
    ; enable paging & write protect in the cr0 register
 | 
				
			||||
    mov     eax, cr0
 | 
				
			||||
    or      eax, 1 << 31 | 1 << 16
 | 
				
			||||
    mov     cr0, eax
 | 
				
			||||
 | 
				
			||||
    ret
 | 
				
			||||
 | 
				
			||||
bits 64
 | 
				
			||||
start64:
 | 
				
			||||
    ; load 0 into all data segment registers
 | 
				
			||||
    mov     ax, 0
 | 
				
			||||
    mov     ss, ax
 | 
				
			||||
    mov     ds, ax
 | 
				
			||||
    mov     es, ax
 | 
				
			||||
    mov     fs, ax
 | 
				
			||||
    mov     gs, ax
 | 
				
			||||
 | 
				
			||||
    ; obtain kstack from data block before entryother
 | 
				
			||||
    mov     rsp, [top - 16]
 | 
				
			||||
 | 
				
			||||
    mov     rax, other_main
 | 
				
			||||
    call    rax
 | 
				
			||||
 | 
				
			||||
; section .rodata
 | 
				
			||||
align 4
 | 
				
			||||
gdt:
 | 
				
			||||
    ; NULL
 | 
				
			||||
    dw  0, 0
 | 
				
			||||
    db  0, 0, 0, 0
 | 
				
			||||
.code: equ $ - gdt
 | 
				
			||||
    dw  0xffff, 0
 | 
				
			||||
    db  0, (0x90 | STA_X | STA_R), 0xcf, 0
 | 
				
			||||
.data: equ $ - gdt
 | 
				
			||||
    dw  0xffff, 0
 | 
				
			||||
    db  0, (0x90 | STA_W), 0xcf, 0
 | 
				
			||||
.desc:
 | 
				
			||||
    dw  $ - gdt - 1
 | 
				
			||||
    dq  gdt
 | 
				
			||||
 | 
				
			||||
gdt64:
 | 
				
			||||
    dq  0 ; zero entry
 | 
				
			||||
.code: equ $ - gdt64 ; new
 | 
				
			||||
    dq  (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
 | 
				
			||||
.pointer:
 | 
				
			||||
    dw  $ - gdt64 - 1
 | 
				
			||||
    dq  gdt64
 | 
				
			||||
 | 
				
			||||
top: equ start + 0x1000
 | 
				
			||||
@ -1,7 +0,0 @@
 | 
				
			||||
set timeout=0
 | 
				
			||||
set default=0
 | 
				
			||||
 | 
				
			||||
menuentry "my os" {
 | 
				
			||||
    multiboot2 /boot/kernel.bin
 | 
				
			||||
    boot
 | 
				
			||||
}
 | 
				
			||||
@ -1,104 +0,0 @@
 | 
				
			||||
ENTRY(start)
 | 
				
			||||
 | 
				
			||||
OTHER_OFFSET = 0x7000;
 | 
				
			||||
BOOT_OFFSET = 0x100000;
 | 
				
			||||
KERNEL_OFFSET = 0xffffff0000000000;
 | 
				
			||||
 | 
				
			||||
SECTIONS {
 | 
				
			||||
 | 
				
			||||
  /* ensure that the multiboot header is at the beginning */
 | 
				
			||||
 | 
				
			||||
  .multiboot_header :
 | 
				
			||||
  {
 | 
				
			||||
      KEEP(*(.multiboot_header))
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  /* bootloader for other processors */
 | 
				
			||||
 | 
				
			||||
  . = OTHER_OFFSET;
 | 
				
			||||
 | 
				
			||||
  .text.other : AT(OTHER_OFFSET)
 | 
				
			||||
  {
 | 
				
			||||
    KEEP(*/entryother.o (.text))
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  /* bootloader for first processor */
 | 
				
			||||
 | 
				
			||||
  . = BOOT_OFFSET;
 | 
				
			||||
 | 
				
			||||
  .rodata.32 :
 | 
				
			||||
  {
 | 
				
			||||
    */boot.o (.rodata)
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
  .text.32 :
 | 
				
			||||
  {
 | 
				
			||||
    */boot.o (.text)
 | 
				
			||||
    */long_mode_init.o (.text)
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
  .bss.32 :
 | 
				
			||||
  {
 | 
				
			||||
    */boot.o (.bss)
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  /* kernel */
 | 
				
			||||
 | 
				
			||||
  . += KERNEL_OFFSET;
 | 
				
			||||
 | 
				
			||||
  .user ALIGN(4K): AT(ADDR(.user) - KERNEL_OFFSET)
 | 
				
			||||
  {
 | 
				
			||||
    KEEP(user/*.o (.data))
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  .rodata : AT(ADDR(.rodata) - KERNEL_OFFSET)
 | 
				
			||||
  {
 | 
				
			||||
    *(.rodata .rodata.*)
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  .text : AT(ADDR(.text) - KERNEL_OFFSET)
 | 
				
			||||
  {
 | 
				
			||||
    *(.text .text.*)
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  .data : AT(ADDR(.data) - KERNEL_OFFSET)
 | 
				
			||||
  {
 | 
				
			||||
    *(.data .data.*)
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  .bss ALIGN(4K): AT(ADDR(.bss) - KERNEL_OFFSET)
 | 
				
			||||
  {
 | 
				
			||||
    *(.bss .bss.*)
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  .got ALIGN(4K): AT(ADDR(.got) - KERNEL_OFFSET)
 | 
				
			||||
  {
 | 
				
			||||
    *(.got)
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  .got.plt : AT(ADDR(.got.plt) - KERNEL_OFFSET)
 | 
				
			||||
  {
 | 
				
			||||
    *(.got.plt)
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  .data.rel.ro : AT(ADDR(.data.rel.ro) - KERNEL_OFFSET) 
 | 
				
			||||
  {
 | 
				
			||||
    *(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*)
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  .gcc_except_table : AT(ADDR(.gcc_except_table) - KERNEL_OFFSET)
 | 
				
			||||
  {
 | 
				
			||||
    *(.gcc_except_table)
 | 
				
			||||
    . = ALIGN(4K);
 | 
				
			||||
  }
 | 
				
			||||
}
 | 
				
			||||
@ -1,29 +0,0 @@
 | 
				
			||||
global long_mode_start
 | 
				
			||||
extern rust_main
 | 
				
			||||
 | 
				
			||||
KERNEL_OFFSET equ 0xffff_ff00_0000_0000
 | 
				
			||||
 | 
				
			||||
section .text
 | 
				
			||||
bits 64
 | 
				
			||||
long_mode_start:
 | 
				
			||||
    ; load 0 into all data segment registers
 | 
				
			||||
    mov ax, 0
 | 
				
			||||
    mov ss, ax
 | 
				
			||||
    mov ds, ax
 | 
				
			||||
    mov es, ax
 | 
				
			||||
    mov fs, ax
 | 
				
			||||
    mov gs, ax
 | 
				
			||||
 | 
				
			||||
    ; translate rsp to virtual address
 | 
				
			||||
    mov rax, KERNEL_OFFSET
 | 
				
			||||
    add rsp, rax
 | 
				
			||||
 | 
				
			||||
    ; call the rust main
 | 
				
			||||
    extern rust_main
 | 
				
			||||
    mov rax, rust_main
 | 
				
			||||
    call rax
 | 
				
			||||
 | 
				
			||||
    ; print `OKAY` to screen
 | 
				
			||||
    mov rax, 0x2f592f412f4b2f4f
 | 
				
			||||
    mov qword [0xb8000], rax
 | 
				
			||||
    hlt
 | 
				
			||||
@ -1,15 +0,0 @@
 | 
				
			||||
section .multiboot_header
 | 
				
			||||
header_start:
 | 
				
			||||
    dd 0xe85250d6                ; magic number (multiboot 2)
 | 
				
			||||
    dd 0                         ; architecture 0 (protected mode i386)
 | 
				
			||||
    dd header_end - header_start ; header length
 | 
				
			||||
    ; checksum
 | 
				
			||||
    dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start))
 | 
				
			||||
 | 
				
			||||
    ; insert optional multiboot tags here
 | 
				
			||||
 | 
				
			||||
    ; required end tag
 | 
				
			||||
    dw 0    ; type
 | 
				
			||||
    dw 0    ; flags
 | 
				
			||||
    dd 8    ; size
 | 
				
			||||
header_end:
 | 
				
			||||
@ -1,61 +0,0 @@
 | 
				
			||||
// Migrate from xv6-x86_64 acpi.c
 | 
				
			||||
 | 
				
			||||
mod structs;
 | 
				
			||||
use self::structs::*;
 | 
				
			||||
use consts::*;
 | 
				
			||||
 | 
				
			||||
pub fn init(rsdt_addr: usize) -> Result<AcpiResult, AcpiError> {
 | 
				
			||||
	let rsdt = unsafe { &*(rsdt_addr as *const Rsdt) };
 | 
				
			||||
	let mut madt: Option<&'static Madt> = None;
 | 
				
			||||
	for i in 0 .. rsdt.entry_count() {
 | 
				
			||||
		let entry = rsdt.entry_at(i);
 | 
				
			||||
		let header = unsafe{ &*(entry as *const Header) };
 | 
				
			||||
        trace!("{:?}", header);
 | 
				
			||||
		if &header.signature == b"APIC" {
 | 
				
			||||
			madt = Some(unsafe{ &*(entry as *const Madt) });
 | 
				
			||||
		}
 | 
				
			||||
	}
 | 
				
			||||
    trace!("{:?}", madt);
 | 
				
			||||
	config_smp(madt.expect("acpi: madt not found."))
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
#[derive(Debug)]
 | 
				
			||||
pub struct AcpiResult {
 | 
				
			||||
	pub cpu_num: u8,
 | 
				
			||||
	pub cpu_acpi_ids: [u8; MAX_CPU_NUM],
 | 
				
			||||
	pub ioapic_id: u8,
 | 
				
			||||
	pub lapic_addr: *const (),
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
#[derive(Debug)]
 | 
				
			||||
pub enum AcpiError {
 | 
				
			||||
	NotMapped,
 | 
				
			||||
	IoacpiNotFound,
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
fn config_smp(madt: &'static Madt) -> Result<AcpiResult, AcpiError> {
 | 
				
			||||
	let lapic_addr = madt.lapic_address as *const ();
 | 
				
			||||
 | 
				
			||||
	let mut cpu_num = 0u8;
 | 
				
			||||
	let mut cpu_acpi_ids: [u8; MAX_CPU_NUM] = [0; MAX_CPU_NUM];
 | 
				
			||||
	let mut ioapic_id: Option<u8> = None;
 | 
				
			||||
	for entry in madt.entry_iter() {
 | 
				
			||||
        trace!("{:?}", entry);
 | 
				
			||||
		match &entry {
 | 
				
			||||
			&MadtEntry::LocalApic(ref lapic) => {
 | 
				
			||||
				cpu_acpi_ids[cpu_num as usize] = lapic.id;
 | 
				
			||||
				cpu_num += 1;
 | 
				
			||||
			},
 | 
				
			||||
			&MadtEntry::IoApic(ref ioapic) => {
 | 
				
			||||
				ioapic_id = Some(ioapic.id);
 | 
				
			||||
			},
 | 
				
			||||
			_ => {},
 | 
				
			||||
		}
 | 
				
			||||
	}
 | 
				
			||||
 | 
				
			||||
	if ioapic_id.is_none() {
 | 
				
			||||
		return Err(AcpiError::IoacpiNotFound);
 | 
				
			||||
	}
 | 
				
			||||
	let ioapic_id = ioapic_id.unwrap();
 | 
				
			||||
	Ok(AcpiResult { cpu_num, cpu_acpi_ids, ioapic_id, lapic_addr })
 | 
				
			||||
}
 | 
				
			||||
@ -1,141 +0,0 @@
 | 
				
			||||
// Reference: xv6-x86_64 acpi.h
 | 
				
			||||
// Copy from crate 'acpica-sys'
 | 
				
			||||
 | 
				
			||||
use util::{Checkable, bytes_sum};
 | 
				
			||||
use core::mem::size_of;
 | 
				
			||||
 | 
				
			||||
#[repr(C)]
 | 
				
			||||
#[derive(Debug)]
 | 
				
			||||
pub struct Rsdp {
 | 
				
			||||
    pub signature: [u8; 8],
 | 
				
			||||
    pub checksum: u8,
 | 
				
			||||
    pub oem_id: [i8; 6],
 | 
				
			||||
    pub revision: u8,
 | 
				
			||||
    pub rsdt_physical_address: u32,
 | 
				
			||||
    pub length: u32,
 | 
				
			||||
    pub xsdt_physical_address: u64,
 | 
				
			||||
    pub extended_checksum: u8,
 | 
				
			||||
    pub reserved: [u8; 3],
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
impl Checkable for Rsdp {
 | 
				
			||||
    fn check(&self) -> bool {
 | 
				
			||||
        &self.signature == b"RSD PTR " && bytes_sum(self) == 0
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
#[repr(C)]
 | 
				
			||||
#[derive(Debug)]
 | 
				
			||||
pub struct Header {
 | 
				
			||||
    pub signature: [u8; 4],
 | 
				
			||||
    pub length: u32,
 | 
				
			||||
    pub revision: u8,
 | 
				
			||||
    pub checksum: u8,
 | 
				
			||||
    pub oem_id: [i8; 6],
 | 
				
			||||
    pub oem_table_id: [i8; 8],
 | 
				
			||||
    pub oem_revision: u32,
 | 
				
			||||
    pub asl_compiler_id: [i8; 4],
 | 
				
			||||
    pub asl_compiler_revision: u32,
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
#[repr(C)]
 | 
				
			||||
#[derive(Debug)]
 | 
				
			||||
pub struct Rsdt {
 | 
				
			||||
    pub header: Header,
 | 
				
			||||
    table_offset_entry: [u32; 0],
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
impl Rsdt {
 | 
				
			||||
    pub fn entry_count(&self) -> usize {
 | 
				
			||||
        (self.header.length as usize - size_of::<Self>()) / 4
 | 
				
			||||
    }
 | 
				
			||||
    pub fn entry_at(&self, id: usize) -> u32 {
 | 
				
			||||
        assert!(id < self.entry_count());
 | 
				
			||||
        unsafe {
 | 
				
			||||
            let p = (self as *const Self).offset(1) as *const u32;
 | 
				
			||||
            *(p.offset(id as isize))
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
#[repr(C)]
 | 
				
			||||
#[derive(Debug)]
 | 
				
			||||
pub struct Madt {
 | 
				
			||||
    pub header: Header,
 | 
				
			||||
    pub lapic_address: u32,
 | 
				
			||||
    pub flags: u32,
 | 
				
			||||
    table: [u32; 0],
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
impl Checkable for Madt {
 | 
				
			||||
    fn check(&self) -> bool {
 | 
				
			||||
        &self.header.signature == b"APIC" && self.header.length >= size_of::<Self>() as u32
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
#[derive(Debug)]
 | 
				
			||||
pub enum MadtEntry {
 | 
				
			||||
    Unknown(MadtEntryUnknown),
 | 
				
			||||
    LocalApic(MadtEntryLocalApic),
 | 
				
			||||
    IoApic(MadtEntryIoApic),
 | 
				
			||||
}
 | 
				
			||||
#[repr(C)]
 | 
				
			||||
#[derive(Debug, Clone)]
 | 
				
			||||
pub struct MadtEntryUnknown {
 | 
				
			||||
    pub type_: u8,
 | 
				
			||||
    pub length: u8,
 | 
				
			||||
}
 | 
				
			||||
#[repr(C)]
 | 
				
			||||
#[derive(Debug, Clone)]
 | 
				
			||||
pub struct MadtEntryLocalApic {
 | 
				
			||||
    pub type_: u8,   // 0
 | 
				
			||||
    pub length: u8,
 | 
				
			||||
    pub processor_id: u8,
 | 
				
			||||
    pub id: u8,
 | 
				
			||||
    pub lapic_flags: u32,
 | 
				
			||||
}
 | 
				
			||||
#[repr(C)]
 | 
				
			||||
#[derive(Debug, Clone)]
 | 
				
			||||
pub struct MadtEntryIoApic {
 | 
				
			||||
    pub type_: u8,   // 1
 | 
				
			||||
    pub length: u8,
 | 
				
			||||
    pub id: u8,
 | 
				
			||||
    pub reserved: u8,
 | 
				
			||||
    pub address: u32,
 | 
				
			||||
    pub global_irq_base: u32,
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
#[derive(Debug)]
 | 
				
			||||
pub struct MadtEntryIter<'a> {
 | 
				
			||||
    madt: &'a Madt,
 | 
				
			||||
    ptr: *const u8,
 | 
				
			||||
    end_ptr: *const u8,
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
impl Madt {
 | 
				
			||||
    pub fn entry_iter(&self) -> MadtEntryIter {
 | 
				
			||||
        let ptr = unsafe{ (self as *const Self).offset(1) } as *const u8;
 | 
				
			||||
        let end_ptr = unsafe{ ptr.offset(self.header.length as isize) };
 | 
				
			||||
        MadtEntryIter { madt: self, ptr, end_ptr }
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
impl<'a> Iterator for MadtEntryIter<'a> {
 | 
				
			||||
    type Item = MadtEntry;
 | 
				
			||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
				
			||||
        if self.ptr >= self.end_ptr {
 | 
				
			||||
            return None;
 | 
				
			||||
        }
 | 
				
			||||
        unsafe {
 | 
				
			||||
            let type_id = *self.ptr.offset(0);
 | 
				
			||||
            let len = *self.ptr.offset(1);
 | 
				
			||||
            let ret = Some(match type_id {
 | 
				
			||||
                0 => MadtEntry::LocalApic( (&*(self.ptr as *const MadtEntryLocalApic)).clone() ),
 | 
				
			||||
                1 => MadtEntry::IoApic( (&*(self.ptr as *const MadtEntryIoApic)).clone() ),
 | 
				
			||||
                _ => MadtEntry::Unknown( (&*(self.ptr as *const MadtEntryUnknown)).clone() ),
 | 
				
			||||
            });        
 | 
				
			||||
            self.ptr = self.ptr.offset(len as isize);
 | 
				
			||||
            ret       
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
@ -1,31 +1,23 @@
 | 
				
			||||
extern crate syscall as redox_syscall;
 | 
				
			||||
 | 
				
			||||
pub mod vga;
 | 
				
			||||
pub mod acpi;
 | 
				
			||||
pub mod apic;
 | 
				
			||||
pub mod mp;
 | 
				
			||||
pub mod serial;
 | 
				
			||||
pub mod pic;
 | 
				
			||||
pub mod keyboard;
 | 
				
			||||
pub mod pit;
 | 
				
			||||
pub mod ide;
 | 
				
			||||
 | 
				
			||||
pub fn init(rsdt_addr: usize) -> acpi::AcpiResult {
 | 
				
			||||
pub fn init() {
 | 
				
			||||
    assert_has_not_been_called!();
 | 
				
			||||
 | 
				
			||||
    let acpi = acpi::init(rsdt_addr).expect("Failed to init ACPI");
 | 
				
			||||
    assert_eq!(acpi.lapic_addr as usize, 0xfee00000);
 | 
				
			||||
    trace!("acpi = {:?}", acpi);
 | 
				
			||||
 | 
				
			||||
    if cfg!(feature = "use_apic") {
 | 
				
			||||
        pic::disable();
 | 
				
			||||
        use consts::KERNEL_OFFSET;
 | 
				
			||||
        apic::init((KERNEL_OFFSET + 0xfee00000) as *const (), acpi.ioapic_id);
 | 
				
			||||
        apic::init();
 | 
				
			||||
    } else {
 | 
				
			||||
        pic::init();
 | 
				
			||||
    }
 | 
				
			||||
    pit::init();
 | 
				
			||||
    serial::init();
 | 
				
			||||
    keyboard::init();
 | 
				
			||||
    acpi
 | 
				
			||||
}
 | 
				
			||||
@ -1,113 +0,0 @@
 | 
				
			||||
// Migrate from xv6 mp.c
 | 
				
			||||
 | 
				
			||||
// Multiprocessor support
 | 
				
			||||
// Search memory for MP description structures.
 | 
				
			||||
// http://developer.intel.com/design/pentium/datashts/24201606.pdf
 | 
				
			||||
 | 
				
			||||
mod structs;
 | 
				
			||||
use self::structs::*;
 | 
				
			||||
 | 
				
			||||
/// Search for the MP Floating Pointer Structure, which according to the
 | 
				
			||||
/// spec is in one of the following three locations:
 | 
				
			||||
/// 1) in the first KB of the EBDA;
 | 
				
			||||
/// 2) in the last KB of system base memory;
 | 
				
			||||
/// 3) in the BIOS ROM address space between 0F0000h and 0FFFFFh.
 | 
				
			||||
pub fn find_mp() -> Option<*const MP>
 | 
				
			||||
{
 | 
				
			||||
	use core::mem::size_of;
 | 
				
			||||
	use util::find_in_memory;
 | 
				
			||||
	let ebda = unsafe { *(0x40E as *const u16) as usize } << 4;
 | 
				
			||||
	if ebda != 0 {
 | 
				
			||||
		let res = unsafe{ find_in_memory::<MP>(ebda, 1024, size_of::<MP>()) };
 | 
				
			||||
		if let Some(addr) = res {
 | 
				
			||||
			return Some(addr as *const MP);
 | 
				
			||||
		}
 | 
				
			||||
	}
 | 
				
			||||
	let p = unsafe { *(0x413 as *const u16) as usize } << 10;
 | 
				
			||||
	let res = unsafe{ find_in_memory::<MP>(p-1024, 1024, size_of::<MP>()) };
 | 
				
			||||
    if let Some(addr) = res {
 | 
				
			||||
		return Some(addr as *const MP);
 | 
				
			||||
	}
 | 
				
			||||
	let res = unsafe{ find_in_memory::<MP>(0xF0000, 0x10000, size_of::<MP>()) };
 | 
				
			||||
	res.map(|addr| addr as *const MP)
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
struct cpu cpus[NCPU];
 | 
				
			||||
int ncpu;
 | 
				
			||||
uchar ioapicid;
 | 
				
			||||
 | 
				
			||||
// Search for an MP configuration table.  For now,
 | 
				
			||||
// don't accept the default configurations (physaddr == 0).
 | 
				
			||||
// Check for correct signature, calculate the checksum and,
 | 
				
			||||
// if correct, check the version.
 | 
				
			||||
// To do: check extended table checksum.
 | 
				
			||||
static struct mpconf*
 | 
				
			||||
mpconfig(struct mp **pmp)
 | 
				
			||||
{
 | 
				
			||||
	struct mpconf *conf;
 | 
				
			||||
	struct mp *mp;
 | 
				
			||||
 | 
				
			||||
	if((mp = mpsearch()) == 0 || mp->physaddr == 0)
 | 
				
			||||
		return 0;
 | 
				
			||||
	conf = (struct mpconf*) P2V((uint) mp->physaddr);
 | 
				
			||||
	if(memcmp(conf, "PCMP", 4) != 0)
 | 
				
			||||
		return 0;
 | 
				
			||||
	if(conf->version != 1 && conf->version != 4)
 | 
				
			||||
		return 0;
 | 
				
			||||
	if(sum((uchar*)conf, conf->length) != 0)
 | 
				
			||||
		return 0;
 | 
				
			||||
	*pmp = mp;
 | 
				
			||||
	return conf;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void
 | 
				
			||||
mpinit(void)
 | 
				
			||||
{
 | 
				
			||||
	uchar *p, *e;
 | 
				
			||||
	int ismp;
 | 
				
			||||
	struct mp *mp;
 | 
				
			||||
	struct mpconf *conf;
 | 
				
			||||
	struct mpproc *proc;
 | 
				
			||||
	struct mpioapic *ioapic;
 | 
				
			||||
 | 
				
			||||
	if((conf = mpconfig(&mp)) == 0)
 | 
				
			||||
		panic("Expect to run on an SMP");
 | 
				
			||||
	ismp = 1;
 | 
				
			||||
	lapic = (uint*)conf->lapicaddr;
 | 
				
			||||
	for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
 | 
				
			||||
		switch(*p){
 | 
				
			||||
		case MPPROC:
 | 
				
			||||
			proc = (struct mpproc*)p;
 | 
				
			||||
			if(ncpu < NCPU) {
 | 
				
			||||
				cpus[ncpu].apicid = proc->apicid;  // apicid may differ from ncpu
 | 
				
			||||
				ncpu++;
 | 
				
			||||
			}
 | 
				
			||||
			p += sizeof(struct mpproc);
 | 
				
			||||
			continue;
 | 
				
			||||
		case MPIOAPIC:
 | 
				
			||||
			ioapic = (struct mpioapic*)p;
 | 
				
			||||
			ioapicid = ioapic->apicno;
 | 
				
			||||
			p += sizeof(struct mpioapic);
 | 
				
			||||
			continue;
 | 
				
			||||
		case MPBUS:
 | 
				
			||||
		case MPIOINTR:
 | 
				
			||||
		case MPLINTR:
 | 
				
			||||
			p += 8;
 | 
				
			||||
			continue;
 | 
				
			||||
		default:
 | 
				
			||||
			ismp = 0;
 | 
				
			||||
			break;
 | 
				
			||||
		}
 | 
				
			||||
	}
 | 
				
			||||
	if(!ismp)
 | 
				
			||||
		panic("Didn't find a suitable machine");
 | 
				
			||||
 | 
				
			||||
	if(mp->imcrp){
 | 
				
			||||
		// Bochs doesn't support IMCR, so this doesn't run on Bochs.
 | 
				
			||||
		// But it would on real hardware.
 | 
				
			||||
		outb(0x22, 0x70);   // Select IMCR
 | 
				
			||||
		outb(0x23, inb(0x23) | 1);  // Mask external interrupts.
 | 
				
			||||
	}
 | 
				
			||||
}
 | 
				
			||||
*/
 | 
				
			||||
@ -1,74 +0,0 @@
 | 
				
			||||
// Migrate from xv6 mp.h
 | 
				
			||||
 | 
				
			||||
// See MultiProcessor Specification Version 1.[14]
 | 
				
			||||
 | 
				
			||||
use util::{Checkable, bytes_sum};
 | 
				
			||||
 | 
				
			||||
#[repr(C)]
 | 
				
			||||
#[derive(Debug)]
 | 
				
			||||
pub struct MP {             // floating pointer
 | 
				
			||||
	signature: [u8; 4],         // "_MP_"
 | 
				
			||||
	physaddr: u32,               // phys addr of MP config table
 | 
				
			||||
	length: u8,                 // 1
 | 
				
			||||
	specrev: u8,                // [14]
 | 
				
			||||
	checksum: u8,               // all bytes must add up to 0
 | 
				
			||||
	type_: u8,                   // MP system config type
 | 
				
			||||
	imcrp: u8,
 | 
				
			||||
	reserved: [u8; 3],
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
impl Checkable for MP {
 | 
				
			||||
	fn check(&self) -> bool {
 | 
				
			||||
		&self.signature == b"_MP_" && bytes_sum(self) == 0
 | 
				
			||||
	}
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 | 
				
			||||
#[repr(C)]
 | 
				
			||||
struct mpconf {         // configuration table header
 | 
				
			||||
	signature: [byte; 4];           // "PCMP"
 | 
				
			||||
	length: u16,                // total table length
 | 
				
			||||
	version: u8,                // [14]
 | 
				
			||||
	checksum: u8,               // all bytes must add up to 0
 | 
				
			||||
	product: [u8; 20],            // product id
 | 
				
			||||
	uint *oemtable,               // OEM table pointer
 | 
				
			||||
	ushort oemlength,             // OEM table length
 | 
				
			||||
	ushort entry,                 // entry count
 | 
				
			||||
	uint *lapicaddr,              // address of local APIC
 | 
				
			||||
	ushort xlength,               // extended table length
 | 
				
			||||
	u8 xchecksum,              // extended table checksum
 | 
				
			||||
	u8 reserved,
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
#[repr(C)]
 | 
				
			||||
struct mpproc {         // processor table entry
 | 
				
			||||
	u8 type;                   // entry type (0)
 | 
				
			||||
	u8 apicid;                 // local APIC id
 | 
				
			||||
	u8 version;                // local APIC verison
 | 
				
			||||
	u8 flags;                  // CPU flags
 | 
				
			||||
		#define MPBOOT 0x02           // This proc is the bootstrap processor.
 | 
				
			||||
	u8 signature[4];           // CPU signature
 | 
				
			||||
	uint feature;                 // feature flags from CPUID instruction
 | 
				
			||||
	u8 reserved[8];
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
struct mpioapic {       // I/O APIC table entry
 | 
				
			||||
	u8 type;                   // entry type (2)
 | 
				
			||||
	u8 apicno;                 // I/O APIC id
 | 
				
			||||
	u8 version;                // I/O APIC version
 | 
				
			||||
	u8 flags;                  // I/O APIC flags
 | 
				
			||||
	uint *addr;                  // I/O APIC address
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
// Table entry types
 | 
				
			||||
const MPPROC    : u8 = 0x00;  // One per processor
 | 
				
			||||
const MPBUS     : u8 = 0x01;  // One per bus
 | 
				
			||||
const MPIOAPIC  : u8 = 0x02;  // One per I/O APIC
 | 
				
			||||
const MPIOINTR  : u8 = 0x03;  // One per bus interrupt source
 | 
				
			||||
const MPLINTR   : u8 = 0x04;  // One per system interrupt source
 | 
				
			||||
 | 
				
			||||
//PAGEBREAK!
 | 
				
			||||
// Blank page.
 | 
				
			||||
 | 
				
			||||
*/
 | 
				
			||||
@ -0,0 +1,33 @@
 | 
				
			||||
ENTRY(_start)
 | 
				
			||||
 | 
				
			||||
KERNEL_BEGIN = 0xffffff0000000000;
 | 
				
			||||
 | 
				
			||||
SECTIONS {
 | 
				
			||||
 | 
				
			||||
  . = KERNEL_BEGIN;
 | 
				
			||||
 | 
				
			||||
  .rodata ALIGN(4K):
 | 
				
			||||
  {
 | 
				
			||||
    *(.rodata .rodata.*)
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  .text ALIGN(4K):
 | 
				
			||||
  {
 | 
				
			||||
    *(.text .text.*)
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  .data ALIGN(4K):
 | 
				
			||||
  {
 | 
				
			||||
    *(.data .data.*)
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  .got ALIGN(4K):
 | 
				
			||||
  {
 | 
				
			||||
    *(.got .got.*)
 | 
				
			||||
  }
 | 
				
			||||
 | 
				
			||||
  .bss ALIGN(4K):
 | 
				
			||||
  {
 | 
				
			||||
    *(.bss .bss.*)
 | 
				
			||||
  }
 | 
				
			||||
}
 | 
				
			||||
@ -1,112 +1,24 @@
 | 
				
			||||
use bit_allocator::{BitAlloc, BitAlloc64K};
 | 
				
			||||
use bit_allocator::BitAlloc;
 | 
				
			||||
use consts::KERNEL_OFFSET;
 | 
				
			||||
// Depends on kernel
 | 
				
			||||
use memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, Stack};
 | 
				
			||||
use super::multiboot2::{ElfSection, ElfSectionFlags, ElfSectionsTag};
 | 
				
			||||
use super::multiboot2::BootInformation;
 | 
				
			||||
use memory::{FRAME_ALLOCATOR, init_heap};
 | 
				
			||||
use super::{BootInfo, MemoryRegionType};
 | 
				
			||||
use ucore_memory::PAGE_SIZE;
 | 
				
			||||
use ucore_memory::paging::PageTable;
 | 
				
			||||
 | 
				
			||||
// BootInformation may trigger page fault after kernel remap
 | 
				
			||||
// So just take its ownership
 | 
				
			||||
pub fn init(boot_info: BootInformation) {
 | 
				
			||||
pub fn init(boot_info: &BootInfo) {
 | 
				
			||||
    assert_has_not_been_called!("memory::init must be called only once");
 | 
				
			||||
    info!("{:?}", boot_info);
 | 
				
			||||
    init_frame_allocator(&boot_info);
 | 
				
			||||
    remap_the_kernel(&boot_info);
 | 
				
			||||
    init_frame_allocator(boot_info);
 | 
				
			||||
    init_heap();
 | 
				
			||||
    info!("memory: init end");
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
fn init_frame_allocator(boot_info: &BootInformation) {
 | 
				
			||||
    let memory_areas = boot_info.memory_map_tag().expect("Memory map tag required")
 | 
				
			||||
        .memory_areas();
 | 
				
			||||
    let elf_sections = boot_info.elf_sections_tag().expect("Elf sections tag required")
 | 
				
			||||
        .sections().filter(|s| s.is_allocated());
 | 
				
			||||
 | 
				
			||||
/// Init FrameAllocator and insert all 'Usable' regions from BootInfo.
 | 
				
			||||
fn init_frame_allocator(boot_info: &BootInfo) {
 | 
				
			||||
    let mut ba = FRAME_ALLOCATOR.lock();
 | 
				
			||||
    for area in memory_areas {
 | 
				
			||||
        ba.insert(to_range(area.start_address() as usize, area.end_address() as usize));
 | 
				
			||||
    }
 | 
				
			||||
    for section in elf_sections {
 | 
				
			||||
        ba.remove(to_range(section.start_address() as usize, section.end_address() as usize));
 | 
				
			||||
    }
 | 
				
			||||
    ba.remove(to_range(boot_info.start_address(), boot_info.end_address()));
 | 
				
			||||
 | 
				
			||||
    use core::ops::Range;
 | 
				
			||||
    fn to_range(mut start_addr: usize, mut end_addr: usize) -> Range<usize> {
 | 
				
			||||
        use consts::KERNEL_OFFSET;
 | 
				
			||||
        if start_addr >= KERNEL_OFFSET {
 | 
				
			||||
            start_addr -= KERNEL_OFFSET;
 | 
				
			||||
        }
 | 
				
			||||
        if end_addr >= KERNEL_OFFSET {
 | 
				
			||||
            end_addr -= KERNEL_OFFSET;
 | 
				
			||||
    for region in boot_info.memory_map.iter() {
 | 
				
			||||
        if region.region_type == MemoryRegionType::Usable {
 | 
				
			||||
            ba.insert(region.range.start_frame_number as usize..region.range.end_frame_number as usize);
 | 
				
			||||
        }
 | 
				
			||||
        let page_start = start_addr / PAGE_SIZE;
 | 
				
			||||
        let mut page_end = (end_addr - 1) / PAGE_SIZE + 1;
 | 
				
			||||
        if page_end >= BitAlloc64K::CAP {
 | 
				
			||||
            warn!("page num {:#x} out of range {:#x}", page_end, BitAlloc64K::CAP);
 | 
				
			||||
            page_end = BitAlloc64K::CAP;
 | 
				
			||||
        }
 | 
				
			||||
        page_start..page_end
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
fn remap_the_kernel(boot_info: &BootInformation) {
 | 
				
			||||
    extern { fn stack_bottom(); }
 | 
				
			||||
    extern { fn stack_top(); }
 | 
				
			||||
    let kstack = Stack {
 | 
				
			||||
        top: stack_top as usize + KERNEL_OFFSET,
 | 
				
			||||
        bottom: stack_bottom as usize + PAGE_SIZE + KERNEL_OFFSET,
 | 
				
			||||
    };
 | 
				
			||||
 | 
				
			||||
    let mut memory_set = memory_set_from(boot_info.elf_sections_tag().unwrap(), kstack);
 | 
				
			||||
 | 
				
			||||
    use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE};
 | 
				
			||||
    use super::smp::ENTRYOTHER_ADDR;
 | 
				
			||||
    memory_set.push(MemoryArea::new_physical(0xb8000, 0xb9000, KERNEL_OFFSET, MemoryAttr::default(), "VGA"));
 | 
				
			||||
    memory_set.push(MemoryArea::new_physical(0xfee00000, 0xfee01000, KERNEL_OFFSET, MemoryAttr::default(), "LAPIC"));
 | 
				
			||||
    memory_set.push(MemoryArea::new_identity(0x07fe1000, 0x07fe1000 + PAGE_SIZE, MemoryAttr::default(), "RSDT"));
 | 
				
			||||
    memory_set.push(MemoryArea::new_identity(0xfec00000, 0xfec00000 + PAGE_SIZE, MemoryAttr::default(), "IOAPIC"));
 | 
				
			||||
    memory_set.push(MemoryArea::new(KERNEL_HEAP_OFFSET, KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, MemoryAttr::default(), "kernel_heap"));
 | 
				
			||||
    memory_set.push(MemoryArea::new_identity(ENTRYOTHER_ADDR, ENTRYOTHER_ADDR + PAGE_SIZE, MemoryAttr::default().execute(), "entry_other.text"));
 | 
				
			||||
    memory_set.push(MemoryArea::new_physical(0, 4096, KERNEL_OFFSET, MemoryAttr::default(), "entry_other.ctrl"));
 | 
				
			||||
    debug!("{:#x?}", memory_set);
 | 
				
			||||
 | 
				
			||||
    unsafe { memory_set.activate(); }
 | 
				
			||||
    info!("NEW TABLE!!!");
 | 
				
			||||
 | 
				
			||||
    use core::mem::forget;
 | 
				
			||||
    forget(memory_set);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
fn memory_set_from(sections: ElfSectionsTag, kstack: Stack) -> MemorySet {
 | 
				
			||||
    assert_has_not_been_called!();
 | 
				
			||||
    // WARNING: must ensure it's large enough
 | 
				
			||||
    static mut SPACE: [u8; 0x1000] = [0; 0x1000];
 | 
				
			||||
    let mut set = unsafe { MemorySet::new_from_raw_space(&mut SPACE, kstack) };
 | 
				
			||||
    for section in sections.sections().filter(|s| s.is_allocated()) {
 | 
				
			||||
        set.push(memory_area_from(section));
 | 
				
			||||
    }
 | 
				
			||||
    set
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
fn memory_area_from(section: ElfSection) -> MemoryArea {
 | 
				
			||||
    let mut start_addr = section.start_address() as usize;
 | 
				
			||||
    let mut end_addr = section.end_address() as usize;
 | 
				
			||||
    assert_eq!(start_addr % PAGE_SIZE, 0, "sections need to be page aligned");
 | 
				
			||||
    let name = unsafe { &*(section.name() as *const str) };
 | 
				
			||||
    if start_addr >= KERNEL_OFFSET {
 | 
				
			||||
        start_addr -= KERNEL_OFFSET;
 | 
				
			||||
        end_addr -= KERNEL_OFFSET;
 | 
				
			||||
    }
 | 
				
			||||
    MemoryArea::new_physical(start_addr, end_addr, KERNEL_OFFSET, memory_attr_from(section.flags()), name)
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
fn memory_attr_from(elf_flags: ElfSectionFlags) -> MemoryAttr {
 | 
				
			||||
    let mut flags = MemoryAttr::default();
 | 
				
			||||
 | 
				
			||||
    if !elf_flags.contains(ElfSectionFlags::ALLOCATED) { flags = flags.hide(); }
 | 
				
			||||
    if !elf_flags.contains(ElfSectionFlags::WRITABLE) { flags = flags.readonly(); }
 | 
				
			||||
    if elf_flags.contains(ElfSectionFlags::EXECUTABLE) { flags = flags.execute(); }
 | 
				
			||||
    flags
 | 
				
			||||
}
 | 
				
			||||
@ -1,11 +0,0 @@
 | 
				
			||||
# MacOS environment
 | 
				
			||||
 | 
				
			||||
* x86_64_elf_*:
 | 
				
			||||
    <https://github.com/altkatz/homebrew-gcc_cross_compilers>
 | 
				
			||||
 | 
				
			||||
* grub.rb:
 | 
				
			||||
    <https://github.com/nativeos/homebrew-i386-elf-toolchain/blob/master/Formula/i386-elf-grub.rb>
 | 
				
			||||
 | 
				
			||||
* objconv.rb:
 | 
				
			||||
    <https://github.com/hawkw/homebrew-grub/blob/master/Formula/objconv.rb>
 | 
				
			||||
    Change SHA256
 | 
				
			||||
@ -1,31 +0,0 @@
 | 
				
			||||
class Grub < Formula
 | 
				
			||||
  desc "GNU GRUB 2 targetting i386-elf"
 | 
				
			||||
  homepage "https://www.gnu.org/software/grub/"
 | 
				
			||||
  url "https://ftp.gnu.org/gnu/grub/grub-2.02.tar.xz"
 | 
				
			||||
  version "2.02"
 | 
				
			||||
  sha256 "810b3798d316394f94096ec2797909dbf23c858e48f7b3830826b8daa06b7b0f"
 | 
				
			||||
 | 
				
			||||
  depends_on "i386-elf-gcc"
 | 
				
			||||
 | 
				
			||||
  def install
 | 
				
			||||
    mkdir "grub-build" do
 | 
				
			||||
      system "../configure",
 | 
				
			||||
        "--disable-nls",
 | 
				
			||||
        "--disable-werror",
 | 
				
			||||
        "--disable-efiemu",
 | 
				
			||||
        "--target=i386-elf",
 | 
				
			||||
        "--prefix=#{prefix}",
 | 
				
			||||
        "TARGET_CC=i386-elf-gcc",
 | 
				
			||||
        "TARGET_NM=i386-elf-nm",
 | 
				
			||||
        "TARGET_OBJCOPY=i386-elf-objcopy",
 | 
				
			||||
        "TARGET_RANLIB=i386-elf-ranlib",
 | 
				
			||||
        "TARGET_STRIP=i386-elf-strip"
 | 
				
			||||
 | 
				
			||||
      system "make", "install"
 | 
				
			||||
    end
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  test do
 | 
				
			||||
    system "grub-shell", "--version"
 | 
				
			||||
  end
 | 
				
			||||
end
 | 
				
			||||
@ -1,23 +0,0 @@
 | 
				
			||||
class Objconv < Formula
 | 
				
			||||
  desc "Object file converter and disassembler"
 | 
				
			||||
  homepage "http://www.agner.org/optimize/#objconv"
 | 
				
			||||
  url "http://www.agner.org/optimize/objconv.zip"
 | 
				
			||||
  version "2.44"
 | 
				
			||||
  sha256 "f2c0c4cd6ff227e76ffed5796953cd9ae9eb228847ca9a14dba6392c573bb7a4"
 | 
				
			||||
  def install
 | 
				
			||||
    system "unzip", "source.zip",
 | 
				
			||||
                    "-dsrc"
 | 
				
			||||
    # objconv doesn't have a Makefile, so we have to call
 | 
				
			||||
    # the C++ compiler ourselves
 | 
				
			||||
    system ENV.cxx, "-o", "objconv",
 | 
				
			||||
                    "-O2",
 | 
				
			||||
                    *Dir["src/*.cpp"],
 | 
				
			||||
                    "--prefix=#{prefix}"
 | 
				
			||||
    bin.install "objconv"
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  test do
 | 
				
			||||
    system "#{bin}/objconv", "-h"
 | 
				
			||||
    # TODO: write better tests
 | 
				
			||||
  end
 | 
				
			||||
end
 | 
				
			||||
@ -1,38 +0,0 @@
 | 
				
			||||
# Environment for RustOS-RISCV
 | 
				
			||||
 | 
				
			||||
# NOT ubuntu 18.04: libmpfr.so.4 error
 | 
				
			||||
FROM ubuntu:17.10
 | 
				
			||||
 | 
				
			||||
WORKDIR /rust
 | 
				
			||||
 | 
				
			||||
# Rust toolchain bins
 | 
				
			||||
# https://github.com/riscv-rust/rust/releases/download/riscv-rust-1.26.0-1-dev/rust-1.26.0-dev-x86_64-unknown-linux-gnu.tar.xz
 | 
				
			||||
ADD rust-1.26.0-dev-x86_64-unknown-linux-gnu.tar.xz .
 | 
				
			||||
 | 
				
			||||
# Rust src
 | 
				
			||||
# https://github.com/riscv-rust/rust/archive/riscv-rust-1.26.0-1-dev.zip
 | 
				
			||||
# with submodule: libcompiler_builtins, stdsimd
 | 
				
			||||
ADD rust-riscv-rust-1.26.0-1-dev.tar.gz .
 | 
				
			||||
 | 
				
			||||
# RISCV32 toolchain
 | 
				
			||||
# From tencent cloud for OS2018: ssh 2015011279@140.143.187.14
 | 
				
			||||
ADD rv32-toolchains-prebuild.tar.bz2 .
 | 
				
			||||
 | 
				
			||||
# Dependencies
 | 
				
			||||
RUN apt-get update && apt-get install -q -y --no-install-recommends libssl1.0.0 libssh2-1 gcc make git libc6-dev \
 | 
				
			||||
    autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev
 | 
				
			||||
# Rust bins need this
 | 
				
			||||
RUN mkdir -p /gnu/store/n6acaivs0jwiwpidjr551dhdni5kgpcr-glibc-2.26.105-g0890d5379c/lib \
 | 
				
			||||
	&& ln -s /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /gnu/store/n6acaivs0jwiwpidjr551dhdni5kgpcr-glibc-2.26.105-g0890d5379c/lib/ld-linux-x86-64.so.2
 | 
				
			||||
# Install Rust toolchains
 | 
				
			||||
RUN ./rust-1.26.0-dev-x86_64-unknown-linux-gnu/install.sh && rm -rf ./rust-1.26.0-dev-x86_64-unknown-linux-gnu
 | 
				
			||||
# Install xargo
 | 
				
			||||
RUN apt-get install -q -y ca-certificates
 | 
				
			||||
RUN cargo install xargo
 | 
				
			||||
# Dependencies for qemu-system-riscv32
 | 
				
			||||
RUN apt-get install -q -y libglib2.0-0 libjpeg8 libpng16-16 libnuma1 libpixman-1-0 libaio1
 | 
				
			||||
# Env
 | 
				
			||||
ENV RISCV=/rust/install-rv32
 | 
				
			||||
ENV PATH=~/.cargo/bin:$RISCV/bin:$PATH
 | 
				
			||||
ENV XARGO_RUST_SRC=/rust/rust-riscv-rust-1.26.0-1-dev/src
 | 
				
			||||
RUN ln -s ~/.cargo/bin/xargo /usr/local/bin/xargo
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue